Imported Upstream version 1.7.6p1 upstream/1.7.6p1
authorBdale Garbee <bdale@gag.com>
Tue, 26 Apr 2011 19:58:18 +0000 (13:58 -0600)
committerBdale Garbee <bdale@gag.com>
Tue, 26 Apr 2011 19:58:18 +0000 (13:58 -0600)
157 files changed:
ChangeLog
INSTALL
LICENSE
Makefile.in
NEWS
README
README.LDAP
TROUBLESHOOTING
UPGRADE
aclocal.m4
aix.c
alias.c
alloc.c
audit.c
auth/afs.c
auth/aix_auth.c
auth/bsdauth.c
auth/dce.c
auth/fwtk.c
auth/kerb4.c
auth/kerb5.c
auth/pam.c
auth/passwd.c
auth/rfc1938.c
auth/secureware.c
auth/securid.c
auth/securid5.c
auth/sia.c
auth/sudo_auth.c
auth/sudo_auth.h
boottime.c
bsm_audit.c
check.c
closefrom.c
compat.h [deleted file]
config.h.in
configure
configure.in
def_data.c
def_data.h
def_data.in
defaults.c
env.c
error.c
exec.c
exec_pty.c
fileops.c
find_path.c
fnmatch.c
get_pty.c
getcwd.c
getdate.c
getdate.y
getline.c
getprogname.c
getspwuid.c
gettime.c
glob.c
goodpath.c
gram.c
gram.y
iolog.c
isblank.c
lbuf.c
ldap.c
linux_audit.c
list.c
list.h
logging.c
match.c
memrchr.c
missing.h
mkpkg
mksiglist.c
mkstemps.c
nanosleep.c
parse.c
parse_args.c
pp
pwutil.c
redblack.c
schema.ActiveDirectory
schema.OpenLDAP
schema.iPlanet
sesh.c
set_perms.c
setsid.c
sigaction.c
snprintf.c
strcasecmp.c
strerror.c
strlcat.c
strlcpy.c
strsignal.c
sudo.c
sudo.cat
sudo.h
sudo.man.in
sudo.pod
sudo.pp
sudo_exec.h
sudo_noexec.c
sudo_nss.c
sudo_usage.h.in
sudoers.cat
sudoers.ldap.cat
sudoers.ldap.man.in
sudoers.ldap.pod
sudoers.man.in
sudoers.pod
sudoers2ldif [changed mode: 0644->0755]
sudoreplay.c
sudoreplay.cat
sudoreplay.man.in
sudoreplay.pod
term.c
testsudoers.c
tgetpass.c
timestr.c
toke.c
toke.h [new file with mode: 0644]
toke.l
toke_util.c [new file with mode: 0644]
tsgetgrpw.c
utimes.c
vasgroups.c
visudo.c
visudo.cat
visudo.man.in
visudo.pod
zero_bytes.c
zlib/adler32.c [new file with mode: 0644]
zlib/compress.c [new file with mode: 0644]
zlib/crc32.c [new file with mode: 0644]
zlib/crc32.h [new file with mode: 0644]
zlib/deflate.c [new file with mode: 0644]
zlib/deflate.h [new file with mode: 0644]
zlib/gzclose.c [new file with mode: 0644]
zlib/gzguts.h [new file with mode: 0644]
zlib/gzlib.c [new file with mode: 0644]
zlib/gzread.c [new file with mode: 0644]
zlib/gzwrite.c [new file with mode: 0644]
zlib/infback.c [new file with mode: 0644]
zlib/inffast.c [new file with mode: 0644]
zlib/inffast.h [new file with mode: 0644]
zlib/inffixed.h [new file with mode: 0644]
zlib/inflate.c [new file with mode: 0644]
zlib/inflate.h [new file with mode: 0644]
zlib/inftrees.c [new file with mode: 0644]
zlib/inftrees.h [new file with mode: 0644]
zlib/trees.c [new file with mode: 0644]
zlib/trees.h [new file with mode: 0644]
zlib/uncompr.c [new file with mode: 0644]
zlib/zconf.h.in [new file with mode: 0644]
zlib/zlib.h [new file with mode: 0644]
zlib/zutil.c [new file with mode: 0644]
zlib/zutil.h [new file with mode: 0644]

index b0e2b30ad0422f90c937d1d0094b872e1f895a13..5efe57dfce809921f4ec34e60cffa2312f221074 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
+2011-04-14  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudo.pp:
+       update copyright year
+       [edf691539a65] [tip] <1.7>
+
+       * toke.c, toke.l:
+       Treat a missing includedir like an empty one and do not return an
+       error.
+       [9c770ff2d0bc] <1.7>
+
+2011-04-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * pp:
+       Fix ARCH setting in cross-compile Solaris packages.
+       [057d743bd1a2] <1.7>
+
+       * sudo.pp:
+       Fix aix version setting.
+       [1a2621321f5c] <1.7>
+
+       * ldap.c:
+       Remove extraneous parens in LDAP filter when sudoers_search_filter
+       is enabled that causes a search error. From Matthew Thomas.
+       [7a5a2d021d32] <1.7>
+
+2011-04-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * .hgtags:
+       Added tag SUDO_1_7_6 for changeset fafbb7b0aea2
+       [6f5c74a8a6ac] <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:
+       regen for 1.7.6
+       [fafbb7b0aea2] [SUDO_1_7_6] <1.7>
+
+       * sudo.cat, sudo.man.in:
+       regen man pages for 1.7.6
+       [94d851285f31] <1.7>
+
+2011-04-06  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in:
+       Fix warnings when -without-skey, --without-opie, --without-kerb4,
+       --without-kerb5 or --without-SecurID were specified.
+       [83a99d369286] <1.7>
+
+2011-04-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS:
+       Mention %#gid support in User_List and Runas_List
+       [8ff14765d7df] <1.7>
+
+       * sudoers.pod:
+       Merge SETENV and NOSETENV description from 1.8
+       [dd44e79b53a0] <1.7>
+
+2011-04-01  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * testsudoers.c:
+       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>
+
+2011-03-31  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * testsudoers.c:
+       Fix setting of user_args
+       [0669612feeb1] <1.7>
+
+       * toke.c, toke.l:
+       Add '!' token to lex tracing
+       [7738d002a8d0] <1.7>
+
+       * toke.c, toke.l:
+       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>
+
+2011-03-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudo.pp:
+       Strip off the beta or release candidate version when building AIX
+       packages.
+       [246ebb79e64f] <1.7>
+
+       * aix.c:
+       getuserattr(user, ...) will fall back to the "default" entry
+       automatically, there's no need to check "default" manually.
+       [dd233ca1092a] <1.7>
+
+2011-03-29  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * UPGRADE:
+       Document parser changes.
+       [f767c045e6c0] <1.7>
+
+       * testsudoers.c:
+       Add runasgroup support to testsudoers
+       [23f060665d23] <1.7>
+
+       * testsudoers.c:
+       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>
+
+       * sudoers.pod:
+       Document %#gid, and %:#nonunix_gid syntax.
+       [59e7df4c91e4] <1.7>
+
+       * pwutil.c:
+       Add support to user_in_group() for treating group names that begin
+       with a '#' as gids.
+       [3926017fbf95] <1.7>
+
+2011-03-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * aclocal.m4:
+       Quote first argument to AC_DEFUN(); from Elan Ruusamae
+       [a245e4891bab] <1.7>
+
+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
+       continuation character is used.
+       [37a7f1fc54b7] <1.7>
+
+       * gram.c, toke.c:
+       Add missing include of config.h
+       [b13da7baee1e] <1.7>
+
+       * gram.c, gram.y, toke.c, toke.l:
+       Move lexer globals initialization into init_lexer.
+       [b7c124212d05] <1.7>
+
+       * toke.c, toke.l:
+       Fix a potential crash when a non-regular file is present in an
+       includedir. Fixes bz #452
+       [f1209a710607] <1.7>
+
+       * pp:
+       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>
+
+       * toke.c, toke.l:
+       Make an empty group or netgroup a syntax error.
+       [e88aa7b31a43] <1.7>
+
+       * toke.c, toke.l:
+       Allow a group ID in the User_Spec.
+       [3e58bc732e33] <1.7>
+
+       * toke.c, toke.l:
+       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>
+
+2011-03-23  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * testsudoers.c:
+       Fix printing "User_Alias FOO = ALL"
+       [8e6e810e89ce] <1.7>
+
+2011-03-22  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * parse_args.c:
+       Better error message about invalid -C argument
+       [fc14f8dc03d2] <1.7>
+
+       * NEWS:
+       fix typo
+       [f789649fdeaf] <1.7>
+
+       * sudoers.pod:
+       Fix placement of equal size ('=') in user specification summary.
+       [51861d678ac1] <1.7>
+
+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
+       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>
+
+       * toke.c, toke.l:
+       Allow whitespace after the modifier in a Defaults entry. E.g.
+       "Defaults: username set_home"
+       [57c09139d10c] <1.7>
+
+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>
+
+       * NEWS:
+       Credit Matthew Thomas for the sudoers_search_filter changes.
+       [4b3f239e114d] <1.7>
+
+       * NEWS:
+       Update for sudo 1.7.6 beta
+       [26cdd6578c23] <1.7>
+
+       * exec_pty.c:
+       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>
+
+       * ldap.c, sudoers.ldap.pod:
+       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>
+
+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>
+
+       * sudoers.pod:
+       The '@' character does not normally need to be quoted.
+       [7e96569aed54] <1.7>
+
+       * toke.c, toke.l:
+       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>
+
+       * Makefile.in:
+       toke_util.c lives in $(srcdir) not $(devdir)
+       [b1b59d72f026] <1.7>
+
+       * toke.c, toke.l:
+       Fix parsing of double-quoted names in Defaults and Aliases which was
+       broken in c2b486b12951.
+       [30b2fdbafdc2] <1.7>
+
+2011-03-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS:
+       Document major changes for sudo 1.7.6
+       [d474a2aeb411] <1.7>
+
+       * configure, configure.in:
+       Update version to 1.7.6
+       [c1c80b99ed82] <1.7>
+
+       * match.c:
+       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>
+
+       * mkpkg:
+       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>
+
+       * sudoers.pod:
+       Warn about the dangers of log_input and mention iolog_dir in the
+       log_input and log_output descriptions.
+       [68c3615f7487] <1.7>
+
+       * pp:
+       Back out 2b81d57de4a4 and sync with git version
+       [5a2443567b9c] <1.7>
+
+       * exec.c:
+       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>
+
+       * exec.c:
+       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>
+
+       * lbuf.c:
+       Fix printing of the remainder after a newline. Fixes "sudo -l"
+       output corruption that could occur in some cases.
+       [41e5595f0559] <1.7>
+
+2011-03-08  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * mkpkg:
+       Fix default setting of osversion variable.
+       [c67d9d3bfa2b] <1.7>
+
+2011-03-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * mkpkg:
+       Add --osversion flag to specify OS instead of running "pp
+       --probeonly"
+       [550104604d4b] <1.7>
+
+       * sudo.pp:
+       Fix expr usage w/ GNU expr
+       [c2161988dec9] <1.7>
+
+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>
+
+2011-02-25  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * .hgtags:
+       Added tag SUDO_1_7_5 for changeset 9314212577c3
+       [75f9d661ea03] <1.7>
+
+       * configure, configure.in:
+       version 1.7.5
+       [9314212577c3] [SUDO_1_7_5] <1.7>
+
+2011-02-21  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.5rc1
+       [216ab95b5de0] <1.7>
+
+       * parse_args.c, sudo.c, sudo.pod, sudo_usage.h.in, sudoreplay.c,
+       sudoreplay.pod, visudo.c, visudo.pod:
+       add help text to sudo, visudo and sudoreplay for the -h option
+       [141d348c660b] <1.7>
+
+2011-02-19  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * snprintf.c:
+       avoid using "howmany" for a parameter name since it is a select-
+       related macro
+       [6b6c2d504103] <1.7>
+
+       * Makefile.in:
+       add localstatedir; closes bug 471
+       [a4778228ae54] <1.7>
+
+       * config.h.in, configure, configure.in, exec.c, exec_pty.c,
+       sudoreplay.c:
+       The howmany macro lives in sys/sysmacros.h on SVR5 systems Closes
+       Bug 470
+       [be5dff63ff5d] <1.7>
+
+       * exec.c:
+       SVR5 systems return non-zero for success on socketpair(), check for
+       -1 instead. Closes Bug 469
+       [13ac9d0e0934] <1.7>
+
+2011-02-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * auth/afs.c:
+       Move afs includes to be before sudo ones
+       [fbe0bdcf5798] <1.7>
+
+       * config.h.in, configure, configure.in:
+       No longer use vhangup
+       [9fce94512df9] <1.7>
+
+2011-02-14  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudo_nss.c:
+       Avoid printing empty "Runas and Command-specific defaults for user"
+       line.
+       [3df2925f9982] <1.7>
+
+       * lbuf.c:
+       Truncate the buffer at buf.len before printing in the non-wordwrap
+       case.
+       [23a31b8d95b8] <1.7>
+
+       * 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>
+
+2011-02-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * alias.c:
+       Remove unneeded variable.
+       [23329353f964] <1.7>
+
+2011-02-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in:
+       Prefer getutxid over getutid
+       [e89811f0e4da] <1.7>
+
+       * 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>
+
+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>
+
+       * exec.c, missing.h, sudo.c, toke.h:
+       fix K&R compilation
+       [23ebea9c2183] <1.7>
+
+       * 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>
+
+       * 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>
+
+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>
+
+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>
+
+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>
+
+       * aclocal.m4, configure:
+       fix typo that broke --with-iologdir
+       [fca175fdfd81] <1.7>
+
+2011-02-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS:
+       sync for 1.7.5b3
+       [744e2e78ef5a] <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:
+       1.7.5b3
+       [7a24576e35ac] <1.7>
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       Attempt to clarify how users and groups interact in Runas_Specs
+       [9e8c2fb328d0] <1.7>
+
+       * exec.c, exec_pty.c:
+       Do not handle SIGARLM specially, just pass it through.
+       [944978b640b5] <1.7>
+
+       * exec.c, exec_pty.c:
+       Pass SIGUSR1/SIGUSR2 through to the child.
+       [774506c977df] <1.7>
+
+       * exec.c:
+       Made tcsetpgrp() bits conditional on HAVE_TCSETPGRP
+       [386f69132ad4] <1.7>
+
+       * exec.c:
+       Use pid_t not int and check the return value of kill()
+       [5f15c3304a1d] <1.7>
+
+2011-02-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * exec.c:
+       In non-pty mode before continuing the child, make it the foreground
+       pgrp if possible. Fixes resuming a shell.
+       [dfaadefcc6c6] <1.7>
+
+       * exec_pty.c:
+       If we get a signal other than SIGCHLD in the monitor, pass it
+       directly to the child.
+       [7e638105bfaf] <1.7>
+
+       * exec.c, exec_pty.c, sudo.h:
+       Save signal state before changing handlers and restore before we
+       execute the command.
+       [83278957e630] <1.7>
+
+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:
+       Use a char array to map a number to a base36 digit.
+       [d626ded3312d] <1.7>
+
+       * sudoers.ldap.cat, sudoers.ldap.man.in, 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>
+
+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>
+
+2011-01-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * UPGRADE:
+       Mention LDAP attribute compatibility status.
+       [adb74ad2331b] <1.7>
+
+2011-01-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * README.LDAP:
+       Mention phpQLAdmin
+       [5d80d6291142] <1.7>
+
+       * INSTALL, NEWS, config.h.in, configure, configure.in, defaults.c,
+       sudoers.man.in, sudoers.pod:
+       Add --disable-env-reset configure option.
+       [803ce2f4d85c] <1.7>
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       Document that sudoers_locale also affects logging and email.
+       [080dd4338374] <1.7>
+
+       * NEWS, config.h.in, configure, configure.in, 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>
+
+2011-01-25  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS, 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>
+
+2011-01-24  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * 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>
+
+       * 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:
+       standardize on "return foo;" rather than "return(foo);" or "return
+       (foo);"
+       [e05dd17dcec4] <1.7>
+
+       * NEWS:
+       sync
+       [bedc1e1bc7f8] <1.7>
+
+       * sudo.c:
+       Do not reject sudoers file just because it is root-writable.
+       [26634f322b04] <1.7>
+
+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>
+
+       * sudo_nss.c:
+       For "sudo -U user -l" if user is not authorized on the host, say so.
+       [9eb5673f2f22] <1.7>
+
+       * 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>
+
+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:
+       Update copyright year to 2011
+       [8959c05dc270] <1.7>
+
+       * 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>
+
+       * 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>
+
+       * 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:
+       Check initgroups() return value.
+       [973a67304e3b] <1.7>
+
+2011-01-19  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS:
+       sync
+       [deb822cce3dd] <1.7>
+
 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]
+       [eacd774c37c0] <1.7>
+
+2011-01-15  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudo.c:
+       delref list_pw before exit
+       [0df5a53f3484] <1.7>
+
+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>
+
+       * pp:
+       sync with git version
+       [eb187023bb73] <1.7>
+
+2011-01-13  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudoers.cat, sudoers.man.in, sudoers.pod:
+       fix typo
+       [075e92a756a1] <1.7>
+
+2011-01-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS:
+       Update for sudo 1.7.4p5
+       [11cb87598478] <1.7>
+
+       * schema.OpenLDAP, schema.iPlanet:
+       Add sudoNotBefore and sudoNotAfter attributes as optional attributes
+       to the sudoRole object class. From Andreas Mueller
+       [73357eb1b269] <1.7>
 
 2011-01-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * NEWS:
+       Mention "sudo -g group" password check fix.
+       [8299a2d939e8] <1.7>
+
        * check.c:
        If the user is running sudo as himself but as a different group we
        need to prompt for a password.
-       [fe8a94f96542]
+       [fe8a94f96542] <1.7>
 
 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:
+       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>
+
+       * sudoers.cat, sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.man.in:
+       regen
+       [d56ad7169e67] <1.7>
+
+       * NEWS, ldap.c, sudoers.ldap.pod:
+       Add NETWORK_TIMEOUT as an alias for BIND_TIMELIMIT for compatibility
+       with OpenLDAP ldap.conf files.
+       [85e33e42c008] <1.7>
+
        * pwutil.c:
        If user has no supplementary groups, fall back on checking the group
        file explicitly.
-       [c536ddb16bb6]
+       [c536ddb16bb6] <1.7>
 
 2011-01-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * NEWS:
+       update
+       [9f6e0ec3142a] <1.7>
+
+       * Makefile.in:
+       Use "mv -f" when regenerating ChangeLog
+       [b322b5995e7f] <1.7>
+
        * 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]
+       [c51e2be737b2] <1.7>
 
 2010-12-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * term.c:
        Clear OPOST from c_oflag like we used to. Fixes screen-based
        editors such as vi.
-       [e26055d17b72]
+       [e26055d17b72] <1.7>
 
        * sudoers.pod:
        Clarify umask option description. From Reuben Thomas.
-       [fb8bdcb54feb]
+       [fb8bdcb54feb] <1.7>
+
+2010-12-18  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * ldap.c, sudoers.ldap.pod:
+       Pick last match in LDAP sudoers too
+       [607801b83e25] <1.7>
+
+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>
+
+2010-12-07  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * pp:
+       Add missing '*' that prevented the generic ELF case from matching.
+       [b35bbb42736f] <1.7>
+
+       * pp:
+       If file(1) can't identify the ELF binary type, try readelf(1).
+       [8a73092d8898] <1.7>
+
+2010-11-30  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * auth/kerb4.c, check.c, env.c, pwutil.c, 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>
+
+       * sudoers.ldap.pod:
+       Clarify ordering of entries and attributes
+       [598748ec3804] <1.7>
+
+       * sudoers.ldap.pod:
+       Fix typo and editing goof.
+       [197a2fe65be5] <1.7>
+
+       * ldap.c:
+       Make sure we don't dereference a NULL handle.
+       [b0026541de1e] <1.7>
 
 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]
+       [fcc1daaf4df0] <1.7>
 
 2010-11-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudoers.pod:
        fix typo; from Michael T Hunter
-       [46e70e2063af]
+       [46e70e2063af] <1.7>
+
+       * match.c:
+       In sudoedit mode, assume command line arguments are paths and pass
+       FNM_PATHNAME to fnmatch().
+       [6087ba0064ff] <1.7>
+
+2010-11-20  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * configure, configure.in:
+       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>
+
+       * 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>
+
+       * sudo.pp:
+       For Tru64, strip off beta version.
+       [a16213ec9c27] <1.7>
+
+       * zlib/gzguts.h:
+       Include stdio.h after zlib.h, not before. We need the large file
+       defines to come first.
+       [389ea592d6c2] <1.7>
+
+2010-11-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * ldap.c:
+       Enlarge the array of entry wrappers int blocks of 100 entries to
+       save on allocation time. From Andreas Mueller
+       [db8da143e803] <1.7>
+
+       * ldap.c:
+       Add back call to sudo_ldap_timefilter() in sudo_ldap_build_pass2()
+       that was mistakenly dropped.
+       [f6f1103f9971] <1.7>
+
+2010-11-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * TROUBLESHOOTING:
+       Mention that sudo needs "ar" to build.
+       [eef95d0abfbe] <1.7>
+
+       * configure, configure.in:
+       Fail with a more useful error if "ar" is not found.
+       [1ef3c8501bf5] <1.7>
+
+2010-11-14  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * ldap.c:
+       Reorder things to avoid most of the extra prototypes.
+       [0541a55deb86] <1.7>
+
+       * ldap.c:
+       Inline sudo_ldap_result_get_entry(), it is always called in
+       situations where the bounds are already checked.
+       [fa65cf4eaf5e] <1.7>
+
+       * 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>
+
+2010-11-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * ldap.c, schema.ActiveDirectory, schema.OpenLDAP, schema.iPlanet,
+       sudoers.ldap.pod:
+       Add timed entry support from Andreas Mueller.
+       [10b121c46a1c] <1.7>
+
+       * ldap.c:
+       Use efree() not free() and remove malloc.h include since we never
+       directly call malloc() or free().
+       [f2184b2a0646] <1.7>
+
+2010-11-10  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>
+
+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>
+
+       * pp:
+       sync with git repo
+       [e052d78dde35] <1.7>
+
+2010-11-03  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Makefile.in:
+       remove zlib/zconf.h for distclean
+       [5cf14594d014] <1.7>
+
+       * 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>
+
+       * configure:
+       regen
+       [5b09c0dd9279] <1.7>
+
+       * NEWS:
+       Update 1.7.5 entries.
+       [73a7b2c01db4] <1.7>
+
+2010-11-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Makefile.in:
+       Include zlib in the tar file.
+       [3b7900c3f2af] <1.7>
+
+2010-10-28  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * INSTALL:
+       Better --enable-zlib description
+       [0ca9936a7271] <1.7>
+
+       * mkpkg:
+       Use system zlib on Linux Let configure decide on Solaris For all
+       others, use builtin zlib
+       [58e1b4383b58] <1.7>
+
+       * LICENSE, Makefile.in, config.h.in, configure, configure.in,
+       license.pod, 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:
+       Add local copy of zlib for systems that lack it.
+       [060627a4a413] <1.7>
+
+2010-10-12  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * Makefile.in:
+       Don't overwrite ChangeLog if we can't run hg
+       [8cad8bfce9ee] <1.7>
+
+       * configure, configure.in:
+       HP-UX 10.20 libc has an incompatible getline()
+       [6ae1631c6993] <1.7>
+
+       * visudo.c:
+       Quiet an HP-UX compiler warning.
+       [b8eb3006d68b] <1.7>
+
+2010-10-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * pp:
+       Don't use run_as_superuser=false on HP-UX
+       [2a9ec2750082] <1.7>
+
+       * 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>
+
+       * configure, configure.in:
+       Fix syntax error
+       [96048f77d772] <1.7>
+
+       * 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>
 
 2010-10-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * exec_pty.c:
+       don't need ws_col here
+       [049b4ef9c9ce] <1.7>
+
        * check.c:
        Having a timestamp file defined is no longer indicative of tty
        tickets being enabled. Check def_tty_tickets directly.
-       [6c3803c239d9]
+       [6c3803c239d9] <1.7>
+
+       * exec_pty.c, lbuf.c:
+       Fix TCGETWINSZ compat.
+       [62233ba46ec7] <1.7>
+
+2010-10-02  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * exec_pty.c, lbuf.c:
+       Prefer newer TIOCGWINSZ ioctl to old TIOCGSIZE
+       [0813e3030b1a] <1.7>
 
 2010-10-01  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * set_perms.c:
        Sync set_project() with trunk.
-       [646fd9bc0537]
+       [646fd9bc0537] <1.7>
+
+       * 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>
+
+       * 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]
+       [6ffd892243ab] <1.7>
+
+       * exec.c:
+       Add missing signal_pipe[0] to fdsr for the non-pty case.
+       [3398af88db51] <1.7>
+
+       * mkpkg:
+       Add --with-project for Solaris
+       [25bd2aa83884] <1.7>
+
+       * README:
+       Need ar and ranlib too
+       [d09e632d0a93] <1.7>
+
+2010-09-27  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * env.c:
+       Preserve ODMDIR environment variable by default on AIX.
+       [75266d18e4a7] <1.7>
 
 2010-09-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * linux_audit.c:
        Ignore ECONNREFUSED from audit_log_user_command() which will occur
        if auditd is not running.
-       [a686884684ca]
+       [a686884684ca] <1.7>
+
+2010-09-17  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * pp:
+       Sync with git version
+       [9a328aa25c53] <1.7>
+
+2010-09-16  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * defaults.c, fileops.c:
+       Cast isblank argument to unsigned char.
+       [64b9f3bed954] <1.7>
+
+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:
+       Implement --with-umask-override configure flag.
+       [5065008079df] <1.7>
+
+       * env.c:
+       Take MODE_LOGIN_SHELL into account when initially setting reset_home
+       instead of special-casing it later.
+       [25e6b8419dea] <1.7>
+
+       * sudo.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>
+
+       * env.c:
+       Reset HOME for "sudo -i" even if HOME was listed in env_keep.
+       [8dc31006a428] <1.7>
+
+       * sudo.c:
+       Use SIG_SETMASK when resetting signal mask instead of SIG_UNBLOCK.
+       [8751ef94b18d] <1.7>
+
+       * 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>
 
 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]
+       [16372da8a286] <1.7>
+
+       * lbuf.c:
+       Back out rev e165f67d3127
+       [e9b70079698d] <1.7>
+
+       * lbuf.c:
+       Include sys/time.h for utimes() and struct timeval.
+       [e165f67d3127] <1.7>
+
+       * snprintf.c:
+       Quiet bogus compiler warnings.
+       [176fceb8db3c] <1.7>
+
+       * 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>
+
+       * bsm_audit.c:
+       Use __sun for consistency with the rest of the sources.
+       [8f0db6350b3a] <1.7>
+
+       * pwutil.c:
+       Don't try to delref a NULL group.
+       [57e94fc5df3e] <1.7>
+
+       * alloc.c, lbuf.c:
+       Include memory.h on systems that need it.
+       [e43d8d8a0008] <1.7>
+
+2010-09-11  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * exec.c:
+       Quiet gcc warnings on glibc systems that use warn_unused_result for
+       write(2).
+       [f22696affc78] <1.7>
+
+2010-09-10  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * NEWS, README, configure, configure.in:
+       Update for sudo 1.7.5
+       [62ed8c6cb7c2] <1.7>
+
+       * exec.c, exec_pty.c, list.c, list.h, 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>
+
+2010-09-09  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * visudo.c, visudo.pod:
+       Make "visudo -c -f -" check the standard input.
+       [8ed46ff3141a] <1.7>
+
+       * sudoers.pod:
+       set_home and always_set_home have an effect if HOME is present in
+       the env_keep list.
+       [a2b26d62176d] <1.7>
+
+       * 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>
 
 2010-09-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * bsm_audit.c:
        Solaris BSM audit return EINVAL when auditing is not enabled,
        whereas OpenBSM returns ENOSYS.
-       [bb9c94a8fa7d]
+       [bb9c94a8fa7d] <1.7>
 
 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]
+       [0a5519756bf1] <1.7>
 
        * 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]
+       [694ed1a75a4a] <1.7>
+
+       * sudo.c:
+       Update comment to reality.
+       [de302f39566b] <1.7>
+
+       * missing.h:
+       Need stdio.h for FILE *, not just NULL.
+       [77cf303f5696] <1.7>
 
 2010-09-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [68d30216c13a] <1.7>
 
 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]
+       [e50e6ae4d06d] <1.7>
 
        * ldap.c:
        display_bound_defaults now returns a count so make the stub return
        0, not 1.
-       [97293ced4908]
+       [97293ced4908] <1.7>
+
+       * 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>
 
 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]
+       [62c281fcd4ad] <1.7>
 
 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:
+       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>
+
        * Makefile.in:
        Install sudoers file from the build dir not hte src dir.
-       [a26afd8db531]
+       [a26afd8db531] <1.7>
 
 2010-08-26  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [24a695707b67] <1.7>
 
        * Makefile.in:
        Add target to generate sudoers file Remove generated sudoers file as
        part of distclean
-       [448627fc35b6]
+       [448627fc35b6] <1.7>
 
 2010-08-23  millert  <millert@rh4-x86.home.courtesan.com>
 
        * exec.c:
        When not logging I/O install a handler for SIGCONT and deliver it to
        the command upon resume. Fixes bugzilla #431
-       [e84690aa67bd]
+       [e84690aa67bd] <1.7>
 
 2010-08-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * sudo.c, sudo.h:
+       g/c unused auth_pw global
+       [e30778d73c0b] <1.7>
+
+       * check.c, sudo.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]
+       [2ae1bbe4437a] <1.7>
 
 2010-08-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * lbuf.c:
        Convert a remaining puts() and putchar() to use the output function.
-       [d68c213feb0f]
+       [d68c213feb0f] <1.7>
 
 2010-08-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * Makefile.in:
        Replace sudoers with sudoers.in in DISTFILES
-       [616509f85d6c]
+       [616509f85d6c] <1.7>
 
        * 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]
+       [2672ae047984] <1.7>
 
        * configure, configure.in, sudoers, sudoers.in:
        Substitute sysconfdir in the installed sudoers file to get the
        correct path for sudoers.d.
-       [ab14a68e546f]
+       [ab14a68e546f] <1.7>
 
 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]
+       [a3e6c5a66890] <1.7>
+
+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:
+       Merge compat.h and missing.h into missing.h
+       [905905c7a8f0] <1.7>
 
 2010-08-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [c8f6bc58fd86] <1.7>
 
 2010-08-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * exec.c:
        Fix waitpid() loop termination condition.
-       [97719b3259f2]
+       [97719b3259f2] <1.7>
 
        * exec_pty.c:
        Use sudo_waitpid() instead of bare waitpid()
-       [624a40269189]
+       [624a40269189] <1.7>
 
 2010-08-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Set pp_kit_version and strip off patchlevel
-       [814c87778567]
+       [814c87778567] <1.7>
 
        * 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]
+       [d18ef30f0a72] <1.7>
 
 2010-08-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * auth/sudo_auth.c:
        For non-standalone auth methods, stop reading the password if the
        user enters ^C at the prompt.
-       [59d2b1328d1e]
+       [59d2b1328d1e] <1.7>
+
+       * configure, configure.in:
+       Don't print getspwuid as an auth method.
+       [d35cf4628d9a] <1.7>
+
+       * Makefile.in, auth/passwd.c, auth/secureware.c, auth/sudo_auth.c,
+       auth/sudo_auth.h, configure, configure.in, 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>
 
        * check.c:
        When removing/resetting the timestamp file ignore the tty ticket
        contents.
-       [8b285f601ec0]
+       [8b285f601ec0] <1.7>
+
+2010-08-05  Todd C. Miller  <Todd.Miller@courtesan.com>
+
+       * sudo.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>
 
 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:
+       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>
+
        * UPGRADE:
        Fix typo
-       [0f443aa22e96]
+       [0f443aa22e96] <1.7>
 
 2010-08-03  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * check.c:
        Do not produce a warning for "sudo -k" if the ticket file does not
        exist.
-       [eeaaa73d7f5b]
+       [eeaaa73d7f5b] <1.7>
+
+       * 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
+       the key instead of the contents of struct passwd or struct group.
+       This matters because the name in the database may not match what we
+       looked up, due either to case folding or truncation (historically at
+       8 characters). Also mark the disabled calls to sudo_freepwcache()
+       and sudo_freegrcache() as broken since we use cached data for things
+       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>
+
+       * check.c, exec_pty.c, get_pty.c, logging.c, sudoreplay.c, tgetpass.c,
+       visudo.c:
+       Quiet gcc warnings on glibc systems that use warn_unused_result for
+       write(2) and others.
+       [5faf88695c66] <1.7>
 
 2010-08-02  Todd C. Miller  <Todd.Miller@courtesan.com>
 
+       * toke.c, toke.l:
+       Add %option noinput
+       [8a5e05d6f71f] <1.7>
+
        * aclocal.m4, configure:
        Add cross-compile defaults for remaining AC_TRY_RUN usage.
-       [fb88d22eabc6]
+       [fb88d22eabc6] <1.7>
 
 2010-07-31  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * aclocal.m4, config.h.in, configure, configure.in, snprintf.c:
        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]
+       [5e7cc557a46e] <1.7>
 
 2010-07-30  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * .hgtags:
        Added tag SUDO_1_7_4 for changeset 2920a3b9d568
-       [e929004d5102]
+       [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]
+       [2920a3b9d568] [SUDO_1_7_4] <1.7>
 
        * .hgtags:
        Added tag SUDO_1_7_4 for changeset 0d844aa34c1d
-       [cf65ddcec602]
+       [cf65ddcec602] <1.7>
 
 2010-07-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * exec_pty.c:
        exec_monitor is static
-       [0d844aa34c1d]
+       [0d844aa34c1d] <1.7>
 
        * pp:
        Update to latest version
-       [7b8a00defbd6]
+       [7b8a00defbd6] <1.7>
 
 2010-07-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Let pp determine pp_aix_version itself.
-       [c5ee7944af03]
+       [c5ee7944af03] <1.7>
 
        * INSTALL, config.h.in, configure, configure.in, mkpkg, sudo.c:
        Add support for Ubuntu admin flag file and enable it when building
        Ubuntu packages.
-       [2d97501cda0c]
+       [2d97501cda0c] <1.7>
 
        * sudo.pp, sudoers:
        Add commented out SuSE-like targetpw settings
-       [f4ad331ace46]
+       [f4ad331ace46] <1.7>
 
        * 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]
+       [654da0091c16] <1.7>
 
        * configure, configure.in:
        Prevent configure from adding the -g flag unless in devel mode
-       [e3c11f228c56]
+       [e3c11f228c56] <1.7>
 
 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]
+       [1f78ecf3b990] <1.7>
 
        * sudo.pp:
        Use sudo_$flavor instead of sudo-$flavor since that causes the least
        amount of trouble for the various package managers.
-       [7e1e07115788]
+       [7e1e07115788] <1.7>
 
        * 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]
+       [2bde3925346d] <1.7>
 
        * configure, configure.in:
        Back out version change in 5baf2187a138
-       [bbc3a81afbba]
+       [bbc3a81afbba] <1.7>
 
        * 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]
+       [87201c7f1116] <1.7>
 
        * configure, configure.in, mkpkg:
        Use the HP ANSI C compiler on HP-UX if possible
-       [5baf2187a138]
+       [5baf2187a138] <1.7>
 
        * sudoreplay.c:
        Some getline() implementations (FreeBSD 8.0) do not ignore the
        length pointer when the line pointer is NULL as they should.
-       [8652300785ed]
+       [8652300785ed] <1.7>
 
        * sudoreplay.c:
        Don't need to check for *cp being non-zero, isdigit() will do that.
-       [107301a99b6a]
+       [107301a99b6a] <1.7>
 
        * sudoreplay.c:
        Add setlocale() so the command line arguments that use floating
        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]
+       [2b8ed181e37c] <1.7>
 
        * exec.c:
        Do I/O logging in the C locale so the floating point numbers in the
        timing file are not locale-dependent.
-       [18abbca14078]
+       [18abbca14078] <1.7>
 
        * sudoreplay.c:
        Use errorx() not error() for thingsthat don't set errno.
-       [a2e7c6793d26]
+       [a2e7c6793d26] <1.7>
 
 2010-07-26  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Add Tru64 kit support
-       [40e2d21aa17f]
+       [40e2d21aa17f] <1.7>
 
        * pp:
        Better support for 1.2.3 style versions in Tru64 kits
-       [f7133199a711]
+       [f7133199a711] <1.7>
 
        * pp:
        Remove apparently unnecessary use of sudo
-       [a667a69eeab0]
+       [a667a69eeab0] <1.7>
 
        * Makefile.in:
        Create timedir as part of install-dirs target.
-       [a2e394d694dd]
+       [a2e394d694dd] <1.7>
 
        * exec_pty.c:
        Handle ENXIO from read/write which can occur when reading/writing a
        pty that has gone away. Fixes bugzilla 422
-       [142f4c2efa17]
+       [142f4c2efa17] <1.7>
 
        * pwutil.c:
        sudo_pwdup() was not expanding an empty pw_shell to _PATH_BSHELL
-       [82e5e46bf458]
+       [82e5e46bf458] <1.7>
 
        * mkpkg:
        platform is a pp flag not a variable
-       [9d0ab9b9bf0c]
+       [9d0ab9b9bf0c] <1.7>
 
        * Makefile.in, mkpkg, sudo.pp:
        Add simple arg parsing for mkpkg so we can set debug, flavor or
        platform.
-       [8142ab01ccd9]
+       [8142ab01ccd9] <1.7>
 
        * pp:
        Make rpm backend work on AIX 5.x
-       [2467a79d0b4d]
+       [2467a79d0b4d] <1.7>
 
 2010-07-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudoers:
        Add commented out Defaults entry for log_output
-       [b3fe97e59ae0]
+       [b3fe97e59ae0] <1.7>
 
 2010-07-23  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * Makefile.in:
        Install binary files with -b~ to make a backup. Fixes "text file
        busy" error on HP-UX during install.
-       [3563e3e0163a]
+       [3563e3e0163a] <1.7>
 
        * 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]
+       [3994af813c88] <1.7>
 
        * configure, configure.in:
        Some more ${foo} -> $(foo) conversion for consistent Makefiles.
-       [c214d50c32ec]
+       [c214d50c32ec] <1.7>
 
 2010-07-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pathnames.h.in:
        Add missing include of maillock.h for Solaris
-       [343f04b7a581]
+       [343f04b7a581] <1.7>
 
        * NEWS, TROUBLESHOOTING, UPGRADE, configure, configure.in,
        sample.syslog.conf, sudoers.cat:
        Change the default syslog facility from local2 to authpriv (or auth
        if the operating system doesn't support authpriv).
-       [949f39cf4a59]
+       [949f39cf4a59] <1.7>
 
        * Makefile.in, configure, configure.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]
+       [74c7ff01e880] <1.7>
 
        * 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]
+       [166133a4fb9e] <1.7>
 
 2010-07-21  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * boottime.c, mkstemps.c:
        Include time.h for struct timeval.
-       [50446e0b8398]
+       [50446e0b8398] <1.7>
 
        * exec_pty.c:
        The return value of strsignal() may be const and should be treated
        as const regardless.
-       [c035b17b50e3]
+       [c035b17b50e3] <1.7>
 
        * sudoers.cat, sudoers.man.in, sudoers.pod:
        Mention that 127.0.0.1 will not match, nor will localhost unless
        that is the actual host name.
-       [e9977ec7ac4f]
+       [e9977ec7ac4f] <1.7>
 
        * Makefile.in:
        fix typo
-       [f216d653404d]
+       [f216d653404d] <1.7>
 
        * Makefile.in, NEWS, README, UPGRADE, WHATSNEW:
        Rename WHATSNEW -> NEWS
-       [f3ce0a462ca0]
+       [f3ce0a462ca0] <1.7>
 
        * pp:
        Updated pp with latest patches
-       [cded68af5ba0]
+       [cded68af5ba0] <1.7>
 
        * 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]
+       [fb3d7de50a05] <1.7>
 
        * sudoers.cat, sudoers.man.in:
        regen sudoers manual
-       [7498a058eeb1]
+       [7498a058eeb1] <1.7>
 
        * UPGRADE, sudoers, sudoers.pod:
        Add commented out line to add HOME to env_keep and add a warning to
        the note about the HOME change in UPGRADE.
-       [0f7e08f09b9f]
+       [0f7e08f09b9f] <1.7>
 
 2010-07-20  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudoreplay.c:
        Add LINE_MAX define for those without it.
-       [6248dd44573c]
+       [6248dd44573c] <1.7>
 
        * WHATSNEW:
        Mention that tty_tickets is now the default.
-       [4cf26eaee5ba]
+       [4cf26eaee5ba] <1.7>
 
        * INSTALL, UPGRADE, config.h.in, configure, configure.in, defaults.c,
        sudoers.cat, sudoers.man.in, sudoers.pod:
        The tty_tickets option is now on by default.
-       [73dd2b82a3a9]
+       [73dd2b82a3a9] <1.7>
 
        * WHATSNEW:
        Mention that AIX authdb support has been fixed.
-       [9331829dc276]
+       [9331829dc276] <1.7>
 
        * 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]
+       [d956fd763521] <1.7>
 
 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]
+       [a69c9bed3164] <1.7>
 
        * sudo.cat, sudo.man.in, sudo.pod:
        fix typo
-       [9b90bb3e9187]
+       [9b90bb3e9187] <1.7>
 
        * UPGRADE, WHATSNEW, env.c, sudo.cat, sudo.man.in, sudo.pod:
        Reset HOME when env_reset is enabled unless it is in env_keep
-       [18223dfd1ac3]
+       [18223dfd1ac3] <1.7>
 
        * sudoers.cat, sudoers.man.in, sudoers.pod:
        The default for set_logname has been "true" for some time now.
-       [9f97e4b43a4b]
+       [9f97e4b43a4b] <1.7>
 
        * sudoers.cat, sudoers.man.in, sudoers.pod:
        Document that MAIL it set in env_reset mode.
-       [dcf9ad98079e]
+       [dcf9ad98079e] <1.7>
 
        * boottime.c:
        Add missing include of time.h
-       [57bee414982d]
+       [57bee414982d] <1.7>
 
        * defaults.c, sudo.c:
        Check return value of setdefs() but don't stop setting defaults if
        we hit an unknown one.
-       [a42cb2d6b7ed]
+       [a42cb2d6b7ed] <1.7>
 
        * logging.c:
        Fix check for dup2() return value.
-       [916cd7fdeba7]
+       [916cd7fdeba7] <1.7>
 
        * visudo.c:
        Treat an unknown defaults entry as a parse error.
-       [1f94675835d9]
+       [1f94675835d9] <1.7>
 
        * env.c:
        Check KEPT_MAIL not DID_MAIL when determining whether to set MAIL in
        -i and env_reset mode.
-       [aa6657ccfe01]
+       [aa6657ccfe01] <1.7>
 
        * env.c:
        Add PYTHONUSERBASE to initial_badenv_table
-       [93058374f0d9]
+       [93058374f0d9] <1.7>
 
        * WHATSNEW, aclocal.m4, config.h.in, configure, configure.in, env.c,
        pathnames.h.in, sudo.cat, sudo.man.in, sudo.pod:
        If env_reset is enabled, set the MAIL environment variable based on
        the target user unless MAIL is explicitly preserved in sudoers.
-       [d903c904dcd4]
+       [d903c904dcd4] <1.7>
 
 2010-07-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * pp:
        decode debian code names
-       [2df0ecbc23b4]
+       [2df0ecbc23b4] <1.7>
 
        * WHATSNEW:
        fix typo
-       [b66a95fa1869]
+       [b66a95fa1869] <1.7>
 
 2010-07-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
        Add entry about SuSE bash script fix.
-       [04af78fa281c]
+       [04af78fa281c] <1.7>
 
        * 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]
+       [bb14802d48b1] <1.7>
 
 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]
+       [83c7870130fe] <1.7>
 
 2010-07-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
        Mention polypkg
-       [c5f6e40bbb58]
+       [c5f6e40bbb58] <1.7>
 
        * README, WHATSNEW:
        Update for sudo 1.7.4
-       [0c688f1f8160]
+       [0c688f1f8160] <1.7>
 
        * INSTALL:
        document --with-pam-login
-       [33ca3f6308ae]
+       [33ca3f6308ae] <1.7>
 
        * sudoers.cat, sudoers.man.in, sudoers.pod:
        The tag is NOSETENV, not UNSETENV. From Petr Uzel.
-       [95f37e63ca15]
+       [95f37e63ca15] <1.7>
 
 2010-07-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.pp:
        Include flavor in solaris package name
-       [b6d56ccf367e]
+       [b6d56ccf367e] <1.7>
 
        * mkpkg:
        Older shells don't support IFS= so set explictly to space, tab,
        newline.
-       [336925525e17]
+       [336925525e17] <1.7>
 
        * mkpkg:
        Use '=' not '==' in test
-       [98c692271cfd]
+       [98c692271cfd] <1.7>
 
        * mkpkg:
        Fix typo that prevented debian from matching
-       [af4deec35e37]
+       [af4deec35e37] <1.7>
 
        * mkpkg:
        Add missing prefix setting for debian
-       [d0c1941cb6ec]
+       [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]
+       [74ba26566cdc] <1.7>
 
        * 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
        debian for ldap flavor
-       [f15ff41b5afd]
+       [f15ff41b5afd] <1.7>
 
        * sudoers:
        Add commented out env_keep entries, sample Aliases and a %sudo line
        for debian.
-       [8264e4ed42dc]
+       [8264e4ed42dc] <1.7>
 
        * configure, configure.in:
        Remove check for egrep; configure has its own
-       [27b3d85ebf4f]
+       [27b3d85ebf4f] <1.7>
 
        * configure.in:
        Use enable_zlib instead of enableval for consistency
-       [4a15cfd43d3e]
+       [4a15cfd43d3e] <1.7>
 
 2010-07-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * mkpkg:
        Enable zlib for linux distros
-       [fcab91448bb0]
+       [fcab91448bb0] <1.7>
 
        * mkpkg:
        Add ldap flavor to default build
-       [e35a577c8994]
+       [e35a577c8994] <1.7>
 
        * mkpkg, sudo.pp:
        Simplify rpm linux distro settings
-       [f30547765636]
+       [f30547765636] <1.7>
 
        * UPGRADE, aclocal.m4, configure, configure.in, sudo.cat, sudo.man.in,
        sudoers.cat:
        Move time stamp files from /var/run/sudo to /var/{db,lib,adm}/sudo.
-       [8c9440423d98]
+       [8c9440423d98] <1.7>
 
        * Makefile.in, mkpkg, sudo.pp:
        Add ldap "flavor" for debian, controlled by the SUDO_FLAVOR
        environment variable.
-       [9f418defc08a]
+       [9f418defc08a] <1.7>
 
        * sudo.pp:
        Create sudo group on debian
-       [4b0cc7b8b0b5]
+       [4b0cc7b8b0b5] <1.7>
 
        * mkpkg, sudo.pp:
        Add debian 4/5/6 and use the dot when doing version matches
-       [d5184f0a1efc]
+       [d5184f0a1efc] <1.7>
 
        * sudoers.cat, sudoers.man.in, sudoers.pod:
        Remove spurious "and"; from debian
-       [8b9f2a5937bc]
+       [8b9f2a5937bc] <1.7>
 
        * aclocal.m4, configure:
        Use a loop when searching for mv, sendmail and sh
-       [a1c7d19721a4]
+       [a1c7d19721a4] <1.7>
 
        * aclocal.m4, configure, configure.in, sudoers.cat, sudoers.man.in,
        sudoers.pod, visudo.cat, visudo.man.in, visudo.pod:
        Substitute the value of EDITOR into the sudoers and visudo manuals.
-       [f00dc9343f94]
+       [f00dc9343f94] <1.7>
 
 2010-07-13  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * mkpkg, pp, sudo.pp:
        Initial debian 4.0 support
-       [6d73c000723f]
+       [6d73c000723f] <1.7>
 
        * mkpkg:
        Some platforms need -fPIE instead of -fpie
-       [8533a29633e8]
+       [8533a29633e8] <1.7>
 
        * Makefile.in:
        Add packaging bits to DISTFILES
-       [dea9f374f28b]
+       [dea9f374f28b] <1.7>
 
        * 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]
+       [22e04d2f5f0f] <1.7>
 
        * sudo.psf:
        We now use pp to generate HP-UX packages
-       [6c9f8ae6bc11]
+       [6c9f8ae6bc11] <1.7>
 
 2010-07-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * auth/pam.c:
        Fix indentation
-       [e52e9e6338d5]
+       [e52e9e6338d5] <1.7>
 
        * INSTALL, Makefile.in:
        isntall-man -> install-doc
-       [02cc8198ea7a]
+       [02cc8198ea7a] <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.4
-       [df6ce4ea908a]
+       [df6ce4ea908a] <1.7>
 
        * INSTALL.binary, Makefile.binary.in, Makefile.in:
        Remove remaining bits of the old binary package
-       [8d4f82c23c22]
+       [8d4f82c23c22] <1.7>
 
        * sudo.pp:
        Use http://rc.quest.com/topics/polypkg/ for packaging
-       [d71793085629]
+       [d71793085629] <1.7>
 
        * Makefile.in, mkpkg, pp:
        Use http://rc.quest.com/topics/polypkg/ for packaging
-       [675e505758c5]
+       [675e505758c5] <1.7>
 
        * install-sh:
        Just ignore the -c option, it is the default Add support for -d
        option
-       [2adfb3a63231]
+       [2adfb3a63231] <1.7>
 
        * env.c, logging.c, pathnames.h.in:
        Use _PATH_STDPATH instead of _PATH_DEFPATH
-       [2c22d54a1f02]
+       [2c22d54a1f02] <1.7>
 
        * Makefile.in:
        Do not strip binaries.
-       [bc84682b372c]
+       [bc84682b372c] <1.7>
 
        * 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]
+       [6d9f40db9cca] <1.7>
 
 2010-07-10  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * env.c, sudoreplay.c:
        Fix K&R compilation
-       [e44d3be7ab85]
+       [e44d3be7ab85] <1.7>
 
 2010-07-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        sudo.h:
        Add support for a sudo-i pam.d file to be used for "sudo -i".
        Adapted from a RedHat patch.
-       [2984c3831d88]
+       [2984c3831d88] <1.7>
 
        * Makefile.in:
        Fix installation of sudo_noexec.so
-       [d1f7ca8331b6]
+       [d1f7ca8331b6] <1.7>
 
        * Makefile.in, config.h.in, configure, configure.in, missing.h,
        mkstemp.c, mkstemps.c, 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]
+       [46399679d9ae] <1.7>
 
 2010-07-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [1d626a5cf8c0] <1.7>
 
 2010-07-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * toke.c, toke.l:
        Add suport for negated user/host/command lists in a Defaults entry.
        E.g. Defaults:!baduser noexec
-       [24f07a805dce]
+       [24f07a805dce] <1.7>
 
 2010-07-01  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudoers.ldap.pod:
        fix typo.
-       [d5f2922cecf2]
+       [d5f2922cecf2] <1.7>
 
 2010-06-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * .hgtags:
        Added tag SUDO_1_7_3 for changeset 72fd1f510a08
-       [cc8b2277e17e]
+       [cc8b2277e17e] <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:
        Sudo 1.7.3 GA
-       [72fd1f510a08] [SUDO_1_7_3]
+       [72fd1f510a08] [SUDO_1_7_3] <1.7>
 
        * 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,
        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]
+       [7c6de7fb5dba] <1.7>
 
        * env.c:
        Do not rely on env.env_len when unsetting a variable, just use the
        NULL terminator.
-       [faf088613ce5]
+       [faf088613ce5] <1.7>
 
        * env.c:
        In unsetenv() check for NULL or empty name as per POSIX 1003.1-2008
-       [47f8dfcc7a48]
+       [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]
+       [1dc0ac5929bf] <1.7>
 
        * WHATSNEW:
        Document AIX fixes
-       [be36e8a6dddd]
+       [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]
+       [d4f3e374caeb] <1.7>
 
 2010-06-25  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [fe43fe79070d] <1.7>
 
        * TODO:
        fqdn issue is resolved
-       [f35cb63eb74b]
+       [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]
+       [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]
+       [d3109706ec85] <1.7>
 
        * 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]
+       [0174e89f983b] <1.7>
 
        * sudo.c:
        Defer call to sudo_nonunix_groupcheck_cleanup() until after we have
        closed the sudoers sources. From Quest sudo.
-       [c1b33e3e0f9e]
+       [c1b33e3e0f9e] <1.7>
 
        * pwutil.c:
        Ignore case when matching user/group names in the cache. From Quest
        sudo.
-       [72df368a8a0e]
+       [72df368a8a0e] <1.7>
 
 2010-06-24  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * config.h.in, configure, configure.in, selinux.c:
        Add check for setkeycreatecon() when --with-selinux is specified.
-       [24144c52c0cc]
+       [24144c52c0cc] <1.7>
 
        * 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]
+       [215c7653d9bc] <1.7>
 
        * aix.c:
        K&R function declaration for aix_setauthdb()
-       [82da12d222a6]
+       [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]
+       [8e82ce63f774] <1.7>
 
        * ldap.c:
        Add support for multiple URI lines by joining the contents and
        passing the result to ldap_initialize.
-       [b4e10b2ffdb1]
+       [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]
+       [363dbe449f1c] <1.7>
 
        * aix.c:
        Include compat.h before alloc.h to get __P
-       [819a2667ffd7]
+       [819a2667ffd7] <1.7>
 
        * auth/aix_auth.c:
        Include usersec.h for authenticate() prototype
-       [2b8dd2b67131]
+       [2b8dd2b67131] <1.7>
 
        * aix.c:
        Add missing includes Add missing trailing NUL in userinfo string
-       [8deaedf44943]
+       [8deaedf44943] <1.7>
 
 2010-06-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * HISTORY, history.pod:
        Mention when LDAP was incorporated.
-       [4e6c8ec4f67c]
+       [4e6c8ec4f67c] <1.7>
 
 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]
+       [3657f1b181b9] <1.7>
 
        * pwutil.c:
        Include usersec.h on AIX to get IDtouser() prototype.
-       [11483bbe15c7]
+       [11483bbe15c7] <1.7>
 
        * configure.in:
        Define _LINUX_SOURCE_COMPAT on AIX for strsignal() prototype, it is
        not covered by _ALL_SOURCE.
-       [fd48e6e2136b]
+       [fd48e6e2136b] <1.7>
 
 2010-06-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * iolog.c:
        Add a cast to quiet a compiler warning.
-       [51e9d419bd83]
+       [51e9d419bd83] <1.7>
 
        * boottime.c:
        Use memset() instead of zero_bytes() since we don't include sudo.h
-       [f310b2123ba9]
+       [f310b2123ba9] <1.7>
 
        * Makefile.in:
        getline.o is already in LIB_OBJS, do not need it in COMMON_OBJS
-       [c8750c2d75ab]
+       [c8750c2d75ab] <1.7>
 
        * getdate.c, getdate.y:
        Quiet a compiler warning.
-       [9f231be15958]
+       [9f231be15958] <1.7>
 
        * defaults.c, sudo.c:
        Call set_fqdn() after sudoers has parsed instead of inline as a
        callback.
-       [26d413ddb6dd]
+       [26d413ddb6dd] <1.7>
 
        * WHATSNEW:
        Do not call set_fqdn() until sudoers parses (where is gets run as a
        callback).
-       [582453a993a1]
+       [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]
+       [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]
+       [c1c5a73766b6] <1.7>
 
        * WHATSNEW:
        mention the change in tty ticket behavior when there is no tty
-       [93ddde63e453]
+       [93ddde63e453] <1.7>
 
        * TODO:
        remove done items
-       [9601b2e8dcef]
+       [9601b2e8dcef] <1.7>
 
        * aix.c:
        Remove comment; NAME in usrinfo should be user name.
-       [eb46f1e8ea08]
+       [eb46f1e8ea08] <1.7>
 
        * check.c:
        Do not update tty ticket if there is no tty.
-       [e64e8c8f2286]
+       [e64e8c8f2286] <1.7>
 
        * sudo.cat, sudo.man.in, sudo.pod:
        No longer need to use -- with the -s flag
-       [e45c18dd79dc]
+       [e45c18dd79dc] <1.7>
 
        * Makefile.in:
        Add missing $(srcdir) to sudo.man.in target
-       [2bd89f6ca9f3]
+       [2bd89f6ca9f3] <1.7>
 
        * Makefile.in:
        Do not rely on BSD make's $>
-       [cb328b82cb92]
+       [cb328b82cb92] <1.7>
 
        * configure, configure.in:
        Set timedir to /var/db/sudo for darwin to match Apple sudo's
        location
-       [860c7f1b001f]
+       [860c7f1b001f] <1.7>
 
 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]
+       [f8a9bdf346c1] <1.7>
 
        * config.h.in, configure, configure.in, defaults.c, iolog.c,
        sudoreplay.c:
        Check for zlib.h in addition to libz.
-       [fb77e44d5196]
+       [fb77e44d5196] <1.7>
 
        * Makefile.in, exec.c, exec_pty.c, sudo.h, sudo_exec.h:
        Move functions and symbols shared between exec.c and exec_pty.c into
        sudo_exec.h.
-       [e798d945424e]
+       [e798d945424e] <1.7>
 
        * sudo.h:
        Add missing prototypes for aix_setauthdb and aix_restoreauthdb
-       [8bc2af6d4e17]
+       [8bc2af6d4e17] <1.7>
 
        * Makefile.in:
        Comment out rules to build .man.in and .cat files unless --with-
        devel
-       [81d6726a19ab]
+       [81d6726a19ab] <1.7>
 
        * aix.c, pwutil.c, set_perms.c, sudo.h:
        Fix AIX compilation problems.
-       [7d95f73eca42]
+       [7d95f73eca42] <1.7>
 
        * sudo.c:
        Cast isalnum() arg to unsigned char.
-       [5fff9a81af00]
+       [5fff9a81af00] <1.7>
 
        * WHATSNEW:
        Add Linux audit support.
-       [e59e0670ba79]
+       [e59e0670ba79] <1.7>
 
        * sudo.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]
+       [d35a3f4cb3c0] <1.7>
 
        * sudo.c:
        Add missing braces that broke -i mode.
-       [7fe124b078ec]
+       [7fe124b078ec] <1.7>
 
        * linux_audit.c:
        Fix linux_audit_command() return value
-       [0c582476181c]
+       [0c582476181c] <1.7>
 
 2010-06-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * Makefile.in, linux_audit.c, linux_audit.h:
        Add Linux audit support.
-       [b207dc9960de]
+       [b207dc9960de] <1.7>
 
 2010-06-16  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * INSTALL, audit.c, bsm_audit.c, config.h.in, configure, configure.in,
        logging.h, selinux.c:
        Add Linux audit support.
-       [26ae31d7ff93]
+       [26ae31d7ff93] <1.7>
 
 2010-06-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudoreplay.c, sudoreplay.cat, sudoreplay.man.in, sudoreplay.pod:
        Sync sudoreplay with trunk
-       [65b780cccfa5]
+       [65b780cccfa5] <1.7>
 
        * exec_pty.c:
        Remove an XXX
-       [8304ac649241]
+       [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]
+       [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]
+       [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]
+       [3c0b59fce7b4] <1.7>
 
        * configure, configure.in:
        Remove duplicate setsid check
-       [7712d6d52da1]
+       [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]
+       [f24743c9e4e9] <1.7>
 
        * exec_pty.c, logging.c, selinux.c, sudo.c, tgetpass.c:
        Check for dup2() failure.
-       [b1b6ba761b61]
+       [b1b6ba761b61] <1.7>
 
        * config.h.in, configure, configure.in:
        Remove dup2 check, it is not optional.
-       [cfbe5f3b5956]
+       [cfbe5f3b5956] <1.7>
 
 2010-06-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
        Add mbr_check_membership support and SELinux fixes
-       [af1936a7cf2f]
+       [af1936a7cf2f] <1.7>
 
        * Makefile.in:
        Sync SRCS and DISTFILES with reality
-       [0971b5dcb1be]
+       [0971b5dcb1be] <1.7>
 
        * INSTALL:
        Update OS specific notes. Delete some really ancient ones and move
        older ones to the end of the list.
-       [872dd8b437a8]
+       [872dd8b437a8] <1.7>
 
        * README:
        Bump for sudo 1.7.3 Merge some changes from trunk
-       [a3088c75bf22]
+       [a3088c75bf22] <1.7>
 
        * selinux.c, sudo.c:
        Call selinux_restore_tty() as part of cleanup() so it gets called
        from error()/errorx()
-       [0197c07d4c1e]
+       [0197c07d4c1e] <1.7>
 
        * compat.h:
        No longer use SA_NOCLDSTOP
-       [73ca654cd3f8]
+       [73ca654cd3f8] <1.7>
 
        * interfaces.h, match.c:
        Move union sudo_in_addr_un into interfaces.h
-       [c84bda7c332a]
+       [c84bda7c332a] <1.7>
 
        * pathnames.h.in:
        Update copyright year
-       [94871f44206b]
+       [94871f44206b] <1.7>
 
        * 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,
        sudoreplay.c, term.c, tgetpass.c, toke.l, visudo.c, visudo.cat,
        visudo.man.in, visudo.pod:
        Update copyright year
-       [4cfb47c799b8]
+       [4cfb47c799b8] <1.7>
 
        * Makefile.in:
        Remove varsub as part of clean
-       [61f04a21b0bb]
+       [61f04a21b0bb] <1.7>
 
        * match.c:
        Quiet a compiler warning.
-       [06d8cfe916c8]
+       [06d8cfe916c8] <1.7>
 
        * getdate.c, getdate.y:
        Quiet a compiler warning.
-       [473d2b7d44a1]
+       [473d2b7d44a1] <1.7>
 
        * ldap.c, sudo.h:
        Make the remaining functions in ldap.c static
-       [ba555565b30a]
+       [ba555565b30a] <1.7>
 
        * ldap.c:
        Make private functions static. Diff from Joachim Henke
-       [1603035b1863]
+       [1603035b1863] <1.7>
 
        * 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]
+       [83f11ae00f19] <1.7>
 
 2010-06-12  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]
+       [0a92b41c5ce5] <1.7>
 
 2010-06-11  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * configure, configure.in, sudo.c, sudo_usage.h.in:
        Print configure args with verbose version information.
-       [ca4a5fcf0af8]
+       [ca4a5fcf0af8] <1.7>
 
        * 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]
+       [344c631d0d43] <1.7>
 
 2010-06-10  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * WHATSNEW:
        Describe tty timestamp improvements
-       [136b0f832903]
+       [136b0f832903] <1.7>
 
        * toke.c, 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]
+       [2a0c82ffedde] <1.7>
 
        * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in:
        regen
-       [c9fddd23c7e1]
+       [c9fddd23c7e1] <1.7>
 
        * sudoers.pod:
        Make this read a little bit better when passwd_timeout is 0.
-       [51644950823f]
+       [51644950823f] <1.7>
 
        * Makefile.in:
        Use the --file argument to config.status instead of setting
        CONFIG_FILES
-       [fc2b42c60b5d]
+       [fc2b42c60b5d] <1.7>
 
        * sudo.man.pl, sudo.pod:
        Attempt to handle a default password prompt timeout of zero more
        gracefully.
-       [478b8e720993]
+       [478b8e720993] <1.7>
 
        * toke.c, toke.l:
        Do not override value of keepopen global, instead restore it to the
        value we pushed onto the stack when popping.
-       [dc370d57a668]
+       [dc370d57a668] <1.7>
 
        * exec.c, exec_pty.c, logging.c, mon_systrace.c, tgetpass.c:
        Use SA_INTERRUPT in sa_flags
-       [3845c6637361]
+       [3845c6637361] <1.7>
 
        * getdate.c, getdate.y, ldap.c, sudoreplay.c:
        Silence some compiler warnings
-       [112ac65afd0c]
+       [112ac65afd0c] <1.7>
 
 2010-06-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * exec.c, exec_pty.c, sudo.c, sudo.h:
        Implement background mode. If I/O logging we use pipes instead of a
        pty.
-       [8d448eaf2aaa]
+       [8d448eaf2aaa] <1.7>
 
        * compat.h, exec.c, exec_pty.c, mksiglist.c, strsignal.c, tgetpass.c:
        Move compat definition of NSIG to compat.h
-       [cae72a4c9dec]
+       [cae72a4c9dec] <1.7>
 
        * tgetpass.c:
        Ignore SIGPIPE for "sudo -S"
-       [c6595c8527c4]
+       [c6595c8527c4] <1.7>
 
        * tgetpass.c:
        Properly handle TGP_ECHO again. Print a newline if the user
        interrupted password input.
-       [15acbe4fb535]
+       [15acbe4fb535] <1.7>
 
        * exec_pty.c:
        Use POSIX tcgetpgrp() instead of BSD TIOCGPGRP ioctl
-       [dd041fc9554c]
+       [dd041fc9554c] <1.7>
 
 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]
+       [b518225cafba] <1.7>
 
        * 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]
+       [365e56db7cd5] <1.7>
 
        * check.c, compat.h, config.h.in, configure, configure.in, iolog.c,
        nanosleep.c, sudo_edit.c, visudo.c:
        Replace timerfoo macros with timevalfoo since the timer macros are
        known to be busted on some systems.
-       [4bb5228606c5]
+       [4bb5228606c5] <1.7>
 
        * toke.c, 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]
+       [b7fb75eddb77] <1.7>
 
        * 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]
+       [0a39c8e6a81b] <1.7>
 
        * WHATSNEW, def_data.c, def_data.h, def_data.in, exec.c, sudoers.cat,
        sudoers.man.in, sudoers.pod:
        Add use_pty sudoers option to force use of a pty even when not
        logging I/O.
-       [aea971f1456a]
+       [aea971f1456a] <1.7>
 
        * 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]
+       [58c85c5695dc] <1.7>
 
        * set_perms.c:
        Fix typo
-       [0f677fcdde04]
+       [0f677fcdde04] <1.7>
 
 2010-06-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudo.h:
        Rename pty.c -> get_pty.c
-       [39137dcc4420]
+       [39137dcc4420] <1.7>
 
        * iolog.c:
        Add #define for maximum session id
-       [2a487437f013]
+       [2a487437f013] <1.7>
 
        * 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]
+       [b197515585db] <1.7>
 
        * Makefile.in, configure, configure.in, get_pty.c, pty.c:
        Rename pty.c -> get_pty.c
-       [c0e5270bb28a]
+       [c0e5270bb28a] <1.7>
 
        * aclocal.m4, configure, configure.in:
        Fix --without-iologdir
-       [dcd6c5907b10]
+       [dcd6c5907b10] <1.7>
 
 2010-06-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * 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]
+       [96cdd49be996] <1.7>
 
 2010-06-05  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]
+       [c67b77f8d6b1] <1.7>
 
 2010-06-04  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [de356064ea01] <1.7>
 
        * defaults.h, lbuf.h, sudo.h:
        Reorg function prototypes a bit
-       [5c40f58bb28e]
+       [5c40f58bb28e] <1.7>
 
        * Makefile.in, parse_args.c, sudo.c, sudo.h, sudo_usage.h.in:
        Move argument parsing into parse_args.c
-       [fad7b8737c12]
+       [fad7b8737c12] <1.7>
 
        * 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]
+       [3b5f671936dc] <1.7>
 
        * exec.c, iolog.c, missing.h, sudo_edit.c:
        K&R fixes
-       [dad62986f2fe]
+       [dad62986f2fe] <1.7>
 
        * exec.c, pty.c, sudo.c, sudo.h, sudo_edit.c:
        Log sudoedit sessions as well; adapted from trunk
-       [2c5d9695022b]
+       [2c5d9695022b] <1.7>
 
        * configure:
        regen
-       [9b319e89a6c4]
+       [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,
        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]
+       [968c2c74c69b] <1.7>
 
 2010-06-03  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * INSTALL, configure, configure.in:
        Add --enable-warnings configure option
-       [19cf967c36d1]
+       [19cf967c36d1] <1.7>
 
        * check.c, lbuf.h, script.c, sudo.c, sudo_nss.c:
        Fix K&R compilation issues on HP-UX.
-       [c01a547cdcf8]
+       [c01a547cdcf8] <1.7>
 
        * 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]
+       [596a427ff873] <1.7>
 
        * configure, configure.in, sudo.man.pl, sudoers.man.pl:
        Use numeric registers to handle conditionals instead of trying to do
        it all with text processing.
-       [31570c372e0e]
+       [31570c372e0e] <1.7>
 
        * sudoers.pod:
        Document per-command SELinux settings
-       [bbce5acad1be]
+       [bbce5acad1be] <1.7>
 
        * sudo.pod:
        timestamp -> time stamp
-       [d7335ce6286f]
+       [d7335ce6286f] <1.7>
 
        * tsgetgrpw.c:
        Set close on exec flag in private versions of setpwent() and
        setgrent().
-       [954814bdbd56]
+       [954814bdbd56] <1.7>
 
        * logging.c:
        Make send_mail() take a printf-style argument list
-       [0783ad585062]
+       [0783ad585062] <1.7>
 
        * 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]
+       [3544dd2f1a94] <1.7>
 
        * boottime.c:
        Don't use TRUE/FALSE which may not be defined.
-       [8649bf22b3b2]
+       [8649bf22b3b2] <1.7>
 
        * sudo.cat, sudo.man.in, sudo.pod:
        Document new tty_ticket behavior
-       [0663e0390338]
+       [0663e0390338] <1.7>
 
        * find_path.c, sudo.c, sudo.h, 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]
+       [16c3f27cd9b9] <1.7>
 
        * check.c:
        Store info from stat(2)ing the tty in the tty ticket when tty
        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]
+       [f9aec9ab9054] <1.7>
 
        * boottime.c, check.c, sudo.h:
        get_boottime() now fills in a timeval struct
-       [dbd2003659c0]
+       [dbd2003659c0] <1.7>
 
 2010-06-02  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [c85bf3e41839] <1.7>
 
        * auth/pam.c:
        Fix OpenPAM detection for newer versions.
-       [67f29a0703d0]
+       [67f29a0703d0] <1.7>
 
        * vasgroups.c:
        Sync with Quest sudo git repo
-       [2680ad9762c2]
+       [2680ad9762c2] <1.7>
 
        * 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]
+       [6c886eb9070a] <1.7>
 
        * README.LDAP:
        Fix typos; from Quest Sudo
-       [cf258fc69f1a]
+       [cf258fc69f1a] <1.7>
 
        * Makefile.in, configure.in:
        Use value of SHELL from configure in Makefile
-       [08aaf12221d6]
+       [08aaf12221d6] <1.7>
 
 2010-05-28  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [086c6397d8cd] <1.7>
 
 2010-04-29  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * visudo.c:
        Fix a crash when checking a sudoers file that has aliases that
        reference themselves. Based on a diff from David Wood.
-       [5efc702a3b35]
+       [5efc702a3b35] <1.7>
 
 2010-04-15  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * alias.c:
        Fix use after free in error message when a duplicate alias exists.
-       [9eaac49bd22b]
+       [9eaac49bd22b] <1.7>
 
 2010-04-14  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [b4eed2f0615d] <1.7>
 
 2010-04-12  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * TODO, sudoers.cat, sudoers.man.in, sudoers.pod:
        Fix typo
-       [57198cae9cf5]
+       [57198cae9cf5] <1.7>
 
 2010-04-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        e.g. "./foo" instead of just returning "foo". This removes an
        ambiguity between real commands and possible pseudo-commands in
        command matching.
-       [fb4d571495fa]
+       [fb4d571495fa] <1.7>
 
 2010-04-07  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * sudoers.cat, sudoers.man.in, sudoers.pod:
        Add a note about the security implications of the fast_glob option.
-       [84f8097553d9]
+       [84f8097553d9] <1.7>
 
        * memrchr.c:
        Remove duplicate includes
-       [3e8d90f4c30f]
+       [3e8d90f4c30f] <1.7>
 
 2010-03-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * 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]
+       [5177a284b9ff] <1.7>
 
 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]
+       [549f8f7c2463] <1.7>
 
 2010-03-08  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [eac86126e335] <1.7>
 
        * env.c:
        In setenv(), if the var is empty, return 1 and set errno to EINVAL
        instead of returning EINVAL directly.
-       [d202091ec15e]
+       [d202091ec15e] <1.7>
 
 2010-02-22  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        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]
+       [88f3181692fe] <1.7>
 
 2010-02-09  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * toke.l:
        Avoid a duplicate fclose() of the sudoers file.
-       [164d39108dde]
+       [164d39108dde] <1.7>
 
        * toke.l:
        Fix size arg when realloc()ing include stack. From Daniel Kopecek
-       [8900bccef219]
+       [8900bccef219] <1.7>
 
 2010-02-06  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * aix.c, config.h.in, configure, configure.in:
        Use setrlimit64(), if available, instead of setrlimit() when setting
        AIX resource limits since rlim_t is 32bits.
-       [2cbb14d98fc1]
+       [2cbb14d98fc1] <1.7>
 
        * logging.c:
        Fix use after free when sending error messages. From Timo Juhani
        Lindfors
-       [caf183fd9d94]
+       [caf183fd9d94] <1.7>
 
 2010-01-18  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * ChangeLog, Makefile.in:
        Generate the ChangeLog as part of "make dist" instead of having it
        in the repo.
-       [836c31615859]
+       [836c31615859] <1.7>
 
 2010-01-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
        * Makefile.in:
        Generate correct ChangeLog for 1.7 branch.
-       [586dd90b8878]
+       [586dd90b8878] <1.7>
 
 2010-01-17  Todd C. Miller  <Todd.Miller@courtesan.com>
 
diff --git a/INSTALL b/INSTALL
index 8d92b4cbfd7eb5659a1cc23cd08ec19ba20fbee3..d9568d3ff270afe68a776cb9e573731438bf9efb 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -463,6 +463,11 @@ The following options are also configurable at runtime:
   --without-umask
        Preserves the umask of the user invoking sudo.
 
+  --with-umask-override
+        Use the umask specified in sudoers even if it is less restrictive
+       than the user's.  The default is to use the intersection of the
+       user's umask and the umask specified in sudoers.
+
   --with-runas-default=USER
        The default user to run commands as if the -u flag is not specified
        on the command line.  This defaults to "root".
@@ -562,6 +567,16 @@ 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.
+
   --disable-authentication
        By default, sudo requires the user to authenticate via a
        password or similar means.  This options causes sudo to
@@ -603,22 +618,16 @@ The following options are also configurable at runtime:
        if the executable is simply not in the user's path, sudo will tell
        the user that they are not allowed to run it, which can be confusing.
 
-  --disable-iologdir
-       Disable sudo's I/O logging support.  This can be used to allow sudo
-       to be compiled on systems without pseudo-tty support.
-
-  --enable-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.
-
-  --enable-zlib[=DIR]
-       Enable the use of the zlib compress library when storing
-       I/O log files.  If specified, DIR is the base directory
-       containing the zlib include and lib directories.  By default
-       zlib is used if it is found on the system and I/O logging
-       support is not disabled.
+  --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.
 
   --disable-zlib
         Disable the use of the zlib compress library when storing
@@ -631,6 +640,10 @@ The following options are also configurable at runtime:
        Enable the creation of an Ubuntu-style admin flag file
        the first time sudo is run.
 
+  --disable-env-reset
+        Disable environment resetting.  This sets the default value
+        of the "env_reset" Defaults option in sudoers to false.
+
 Shadow password and C2 support
 ==============================
 
diff --git a/LICENSE b/LICENSE
index 6e9a547ab4583b30b07b6e8559efa9615edbb53c..2af4e0fca870bc427e2ece97337ff48237d22576 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 Sudo is distributed under the following ISC-style license:
 
-   Copyright (c) 1994-1996, 1998-2010
+   Copyright (c) 1994-1996, 1998-2011
         Todd C. Miller <Todd.Miller@courtesan.com>
 
    Permission to use, copy, modify, and distribute this software for any
@@ -19,7 +19,7 @@ Sudo is distributed under the following ISC-style license:
    Agency (DARPA) and Air Force Research Laboratory, Air Force
    Materiel Command, USAF, under agreement number F39502-99-1-0512.
 
-Additionally, fnmatch.c, fnmatch.h, getcwd.c, glob.c, glob.h and snprintf.c
+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
@@ -49,7 +49,7 @@ bear the following UCB license:
    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    SUCH DAMAGE.
 
-nonunix.h and vasgroups.c bear the following license:
+The files nonunix.h and vasgroups.c bear the following license:
 
    Copyright (c) 2006 Quest Software, Inc.  All rights reserved.
 
@@ -76,3 +76,26 @@ nonunix.h and vasgroups.c bear the following license:
    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
index 0114ca7c697386e5d944c92de2eb1959573a861a..b16338b12a3a2ae6a6b4260506067a9c5e7e0441 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 1996, 1998-2005, 2007-2010
+# 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
@@ -64,6 +64,7 @@ sbindir = @sbindir@
 sysconfdir = @sysconfdir@
 libexecdir = @libexecdir@
 datarootdir = @datarootdir@
+localstatedir = @localstatedir@
 docdir = @docdir@
 mandir = @mandir@
 timedir = @timedir@
@@ -113,8 +114,8 @@ SRCS = aix.c alias.c alloc.c audit.c boottime.c bsm_audit.c check.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 \
-       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 \
+       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 \
@@ -122,21 +123,21 @@ AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \
            auth/secureware.c auth/securid.c auth/securid5.c auth/sia.c \
            auth/sudo_auth.c
 
-HDRS = alloc.h bsm_audit.h compat.h def_data.h defaults.h error.h ins_2001.h \
+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 \
+       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 redblack.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 getspwuid.o gettime.o goodpath.o fileops.o find_path.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
 
@@ -148,6 +149,10 @@ 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
+
 VERSION = @PACKAGE_VERSION@
 PACKAGE_TARNAME = @PACKAGE_TARNAME@
 
@@ -163,12 +168,20 @@ DISTFILES = $(SRCS) $(HDRS) ChangeLog HISTORY INSTALL INSTALL.configure \
            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
+           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)/compat.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
+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
 
@@ -189,13 +202,17 @@ libsudo.a: $(LIB_OBJS) $(COMMON_OBJS)
        $(AR) rv $@ $(LIB_OBJS) $(COMMON_OBJS)
        $(RANLIB) $@
 
-sudo: libsudo.a $(SUDO_OBJS)
+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 $(REPLAY_OBJS)
+sudoreplay: libsudo.a @ZLIB_DEP@ $(REPLAY_OBJS)
        $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) -lsudo $(LIBS) @ZLIB@
 
 testsudoers: $(TEST_OBJS)
@@ -213,21 +230,27 @@ libsudo_noexec.la: sudo_noexec.lo
 # 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@  mv -f y.tab.c gram.c
-@DEV@  if cmp -s y.tab.h gram.h; then rm -f y.tab.h; else mv -f y.tab.h gram.h; fi
+@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@  mv -f lex.yy.c toke.c
+@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@  mv -f y.tab.c getdate.c
+@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
@@ -237,7 +260,7 @@ $(devdir)/getdate.c: $(srcdir)/getdate.y
 siglist.c: mksiglist
        ./mksiglist > $@
 
-mksiglist: $(srcdir)/mksiglist.c $(srcdir)/mksiglist.h $(srcdir)/compat.h $(top_builddir)/config.h
+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
@@ -264,7 +287,7 @@ defaults.o: $(srcdir)/defaults.c $(SUDODEP) $(srcdir)/def_data.c $(authdir)/sudo
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/defaults.c
 env.o: $(srcdir)/env.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/env.c
-error.o: $(srcdir)/error.c $(srcdir)/compat.h $(srcdir)/error.h config.h
+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
@@ -274,13 +297,13 @@ fileops.o: $(srcdir)/fileops.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/fileops.c
 find_path.o: $(srcdir)/find_path.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/find_path.c
-fnmatch.o: $(srcdir)/fnmatch.c $(srcdir)/emul/fnmatch.h $(srcdir)/compat.h config.h
+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)/compat.h config.h
+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)/compat.h config.h
+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
@@ -290,7 +313,7 @@ getspwuid.o: $(srcdir)/getspwuid.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getspwuid.c
 gettime.o: $(srcdir)/gettime.c $(SUDODEP)
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/gettime.c
-glob.o: $(srcdir)/glob.c $(srcdir)/emul/glob.h $(srcdir)/compat.h config.h
+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
@@ -300,7 +323,7 @@ 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)/compat.h config.h
+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
@@ -318,7 +341,7 @@ 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)/compat.h config.h
+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
@@ -330,33 +353,33 @@ 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)/compat.h config.h
+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)/compat.h
+sigaction.o: $(srcdir)/sigaction.c $(srcdir)/missing.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sigaction.c
-siglist.o: siglist.c $(srcdir)/compat.h config.h
+siglist.o: siglist.c $(srcdir)/missing.h config.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/siglist.c
-snprintf.o: $(srcdir)/snprintf.c $(srcdir)/compat.h config.h
+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)/compat.h  config.h
+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)/compat.h config.h
+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)/compat.h config.h
+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)/compat.h config.h
+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)/compat.h config.h
+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)/compat.h $(srcdir)/error.h $(srcdir)/missing.h config.h
+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)/compat.h config.h
+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
@@ -366,19 +389,21 @@ testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/li
        $(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)/compat.h config.h
+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 $(devdir)/gram.h
+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)/compat.h $(srcdir)/emul/utime.h config.h
+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)/compat.h config.h
+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
@@ -411,6 +436,38 @@ securid5.o: $(authdir)/securid5.c $(AUTHDEP)
 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/' >> $@
 
@@ -470,12 +527,21 @@ sudoers: $(srcdir)/sudoers.in
 
 # The 1.7 branch started Jan 18, 2010
 ChangeLog:
-       if test -d $(srcdir)/.hg; then \
-           hg log --style=changelog -b 1.7 > $@; \
-           hg log --style=changelog -b default --date '<2010-01-18 00:00:00' >> $@; \
+       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 \
+               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; \
        fi
 
-install: install-dirs install-binaries @INSTALL_NOEXEC@ install-sudoers install-doc
+install: pre-install install-dirs install-binaries @INSTALL_NOEXEC@ install-sudoers install-doc
 
 install-dirs:
        $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(sudodir) \
@@ -526,7 +592,7 @@ 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
+               visudo.man sudo_usage.h Makefile.binary zlib/zconf.h
 
 clobber: distclean
 
diff --git a/NEWS b/NEWS
index 71be281c3210fefcd38ae6eac430eb05d9de7c85..87bac52e1748ba18fc019ec587d8b15bfa580d82 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,124 @@
+What's new in Sudo 1.7.6p1
+
+ * A non-existent includedir is now treated the same as an empty
+   directory and not reported as an error.
+
+ * 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?
+
+ * A new LDAP setting, sudoers_search_filter, has been added to
+   ldap.conf.  This setting can be used to restrict the set of
+   records returned by the LDAP query.  Based on changes from Matthew
+   Thomas.
+
+ * White space is now permitted within a User_List when used in
+   conjunction with a per-user Defaults definition.
+
+ * A group ID (%#gid) may now be specified in a User_List or Runas_List.
+   Likewise, for non-Unix groups the syntax is %:#gid.
+
+ * Support for double-quoted words in the sudoers file has been fixed.
+   The change in 1.7.5 for escaping the double quote character
+   caused the double quoting to only be available at the beginning
+   of an entry.
+
+ * The fix for resuming a suspended shell in 1.7.5 caused problems
+   with resuming non-shells on Linux.  Sudo will now save the process
+   group ID of the program it is running on suspend and restore it
+   when resuming, which fixes both problems.
+
+ * A bug that could result in corrupted output in "sudo -l" has been
+   fixed.
+
+What's new in Sudo 1.7.5?
+
+ * When using visudo in check mode, a file named "-" may be used to
+   check sudoers data on the standard input.
+
+ * Sudo now only fetches shadow password entries when using the
+   password database directly for authentication.
+
+ * Password and group entries are now cached using the same key
+   that was used to look them up.  This fixes a problem when looking
+   up entries by name if the name in the retrieved entry does not
+   match the name used to look it up.  This may happen on some systems
+   that do case insensitive lookups or that truncate long names.
+
+ * GCC will no longer display warnings on glibc systems that use
+   the warn_unused_result attribute for write(2) and other system calls.
+
+ * If a PAM account management module denies access, sudo now prints
+   a more useful error message and stops trying to validate the user.
+
+ * Fixed a potential hang on idle systems when the sudo-run process
+   exits immediately.
+
+ * Sudo now includes a copy of zlib that will be used on systems
+   that do not have zlib installed.
+
+ * The --with-umask-override configure flag has been added to enable
+   the "umask_override" sudoers Defaults option at build time.
+
+ * Sudo now unblocks all signals on startup to avoid problems caused
+   by the parent process changing the default signal mask.
+
+ * LDAP Sudoers entries may now specify a time period for which
+   the entry is valid.  This requires an updated sudoers schema
+   that includes the sudoNotBefore and sudoNotAfter attributes.
+   Support for timed entries must be explicitly enabled in the
+   ldap.conf file.  Based on changes from Andreas Mueller.
+
+ * LDAP Sudoers entries may now specify a sudoOrder attribute that
+   determines the order in which matching entries are applied.  The
+   last matching entry is used, just like file-based sudoers.  This
+   requires an updated sudoers schema that includes the sudoOrder
+   attribute.  Based on changes from Andreas Mueller.
+
+ * When run as sudoedit, or when given the -e flag, sudo now treats
+   command line arguments as pathnames.  This means that slashes
+   in the sudoers file entry must explicitly match slashes in
+   the command line arguments.  As a result, and entry such as:
+       user ALL = sudoedit /etc/*
+   will allow editing of /etc/motd but not /etc/security/default.
+
+ * NETWORK_TIMEOUT is now an alias for BIND_TIMELIMIT in ldap.conf for
+   compatibility with OpenLDAP configuration files.
+
+ * The LDAP API TIMEOUT parameter is now honored in ldap.conf.
+
+ * The I/O log directory may now be specified in the sudoers file.
+
+ * Sudo will no longer refuse to run if the sudoers file is writable
+   by root.
+
+ * Sudo now performs command line escaping for "sudo -s" and "sudo -i"
+   after validating the command so the sudoers entries do not need
+   to include the backslashes.
+
+ * Logging and email sending are now done in the locale specified
+   by the "sudoers_locale" setting ("C" by default).  Email send by
+   sudo now includes MIME headers when "sudoers_locale" is not "C".
+
+ * The configure script has a new option, --disable-env-reset, to
+   allow one to change the default for the sudoers Default setting
+   "env_reset" at compile time.
+
+ * When logging "sudo -l command", sudo will now prepend "list "
+   to the command in the log line to distinguish between an
+   actual command invocation in the logs.
+
+ * Double-quoted group and user names may now include escaped double
+   quotes as part of the name.  Previously this was a parse error.
+
+ * Sudo once again restores the state of the signal handlers it
+   modifies before executing the command.  This allows sudo to be
+   used with the nohup command.
+
+ * Resuming a suspended shell now works properly when I/O logging
+   is not enabled (the I/O logging case was already correct).
+
 What's new in Sudo 1.7.4p6?
 
  * A bug has been fixed in the I/O logging support that could cause
diff --git a/README b/README
index 4f6f454f7c4ebc8a9ceaee1c88294b395413526c..387734f3841793c9786f43f38f732ecce29cdcbb 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is Sudo version 1.7.4
+This is Sudo version 1.7.5
 
 The sudo philosophy
 ===================
@@ -35,7 +35,7 @@ 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 make utility.
+compiler, 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
index 5b7f6d835856914747e83a646dbfa3f654481249..84ac231d662c9002411f1680a361185ce049c384 100644 (file)
@@ -133,6 +133,11 @@ I recommend using any of the following LDAP browsers to administer your SUDOers.
     and since it is Schema aware, I don't need to create a sudoRole template.
        http://biot.com/gq/
 
+  * phpQLAdmin - Open Source - phpQLAdmin is an administration tool,
+    originally for QmailLDAP, that supports editing sudoRole objects
+    in version 2.3.2 and higher.
+       http://phpqladmin.com/
+
   * LDAP Browser/Editor - by Jarek Gawor - I use this a lot on Windows
     and Solaris.  It runs anywhere in a Java Virtual Machine including
     web pages.  You have to make a template from an existing sudoRole entry.
index 57e20127b4cb84bbf766c9eaa1ec85bc065fb94e..9ed181772f0322fbd58d752c3560b1901b853401 100644 (file)
@@ -8,6 +8,14 @@ A) This usually means you either don't have a working compiler.  This
    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
diff --git a/UPGRADE b/UPGRADE
index fb271199135bb980b472cc250896ca2a0afab4d4..8b7da22fbd78817444c9f322ad28295599df261b 100644 (file)
--- a/UPGRADE
+++ b/UPGRADE
@@ -1,6 +1,57 @@
 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
index 1276746a6d2a2ce742bc4cd13998aa014d80a2ca..255b91fb6a64563a0a3d2ec9261a9b1fcd0cadda 100644 (file)
@@ -1,6 +1,6 @@
 dnl Local m4 macros for autoconf (used by sudo)
 dnl
-dnl Copyright (c) 1994-1996, 1998-2005, 2007-2009
+dnl Copyright (c) 1994-1996, 1998-2005, 2007-2011
 dnl    Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
 dnl XXX - should cache values in all cases!!!
@@ -10,7 +10,7 @@ dnl checks for programs
 dnl
 dnl check for sendmail in well-known locations
 dnl
-AC_DEFUN(SUDO_PROG_SENDMAIL, [AC_MSG_CHECKING([for sendmail])
+AC_DEFUN([SUDO_PROG_SENDMAIL], [AC_MSG_CHECKING([for sendmail])
 found=no
 for p in "/usr/sbin/sendmail" "/usr/lib/sendmail" "/usr/etc/sendmail" "/usr/ucblib/sendmail" "/usr/local/lib/sendmail" "/usr/local/bin/sendmail"; do
     if test -f "$p"; then
@@ -28,7 +28,7 @@ fi
 dnl
 dnl check for vi in well-known locations
 dnl
-AC_DEFUN(SUDO_PROG_VI, [AC_MSG_CHECKING([for vi])
+AC_DEFUN([SUDO_PROG_VI], [AC_MSG_CHECKING([for vi])
 found=no
 for editor in "/usr/bin/vi" "/bin/vi" "/usr/ucb/vi" "/usr/bsd/vi" "/usr/local/bin/vi"; do
     if test -f "$editor"; then
@@ -46,7 +46,7 @@ fi
 dnl
 dnl check for mv in well-known locations
 dnl
-AC_DEFUN(SUDO_PROG_MV, [AC_MSG_CHECKING([for mv])
+AC_DEFUN([SUDO_PROG_MV], [AC_MSG_CHECKING([for mv])
 found=no
 for p in "/usr/bin/mv" "/bin/mv" "/usr/ucb/mv" "/usr/sbin/mv"; do
     if test -f "$p"; then
@@ -64,7 +64,7 @@ fi
 dnl
 dnl check for bourne shell in well-known locations
 dnl
-AC_DEFUN(SUDO_PROG_BSHELL, [AC_MSG_CHECKING([for bourne shell])
+AC_DEFUN([SUDO_PROG_BSHELL], [AC_MSG_CHECKING([for bourne shell])
 found=no
 for p in "/bin/sh" "/usr/bin/sh" "/sbin/sh" "/usr/sbin/sh" "/bin/ksh" "/usr/bin/ksh" "/bin/bash" "/usr/bin/bash"; do
     if test -f "$p"; then
@@ -82,7 +82,7 @@ fi
 dnl
 dnl Where the log file goes, use /var/log if it exists, else /{var,usr}/adm
 dnl
-AC_DEFUN(SUDO_LOGFILE, [AC_MSG_CHECKING(for log file location)
+AC_DEFUN([SUDO_LOGFILE], [AC_MSG_CHECKING(for log file location)
 if test -n "$with_logpath"; then
     AC_MSG_RESULT($with_logpath)
     SUDO_DEFINE_UNQUOTED(_PATH_SUDO_LOGFILE, "$with_logpath")
@@ -103,7 +103,7 @@ fi
 dnl
 dnl Where the timestamp files go.
 dnl
-AC_DEFUN(SUDO_TIMEDIR, [AC_MSG_CHECKING(for timestamp file location)
+AC_DEFUN([SUDO_TIMEDIR], [AC_MSG_CHECKING(for timestamp file location)
 timedir="$with_timedir"
 if test -z "$timedir"; then
     for d in /var/db /var/lib /var/adm /usr/adm; do
@@ -121,28 +121,28 @@ dnl
 dnl Where the I/O log files go, use /var/log/sudo-io if
 dnl /var/log exists, else /{var,usr}/adm/sudo-io
 dnl
-AC_DEFUN(SUDO_IO_LOGDIR, [
+AC_DEFUN([SUDO_IO_LOGDIR], [
     AC_MSG_CHECKING(for I/O log dir location)
     if test "${with_iologdir-yes}" != "yes"; then
-       :
+       iolog_dir="$with_iologdir"
     elif test -d "/var/log"; then
-       with_iologdir="/var/log/sudo-io"
+       iolog_dir="/var/log/sudo-io"
     elif test -d "/var/adm"; then
-       with_iologdir="/var/adm/sudo-io"
+       iolog_dir="/var/adm/sudo-io"
     else
-       with_iologdir="/usr/adm/sudo-io"
+       iolog_dir="/usr/adm/sudo-io"
     fi
-    if test "${with_iologdir-yes}" != "no"; then
-       SUDO_DEFINE_UNQUOTED(_PATH_SUDO_IO_LOGDIR, "$with_iologdir")
+    if test "${with_iologdir}" != "no"; then
+       SUDO_DEFINE_UNQUOTED(_PATH_SUDO_IO_LOGDIR, "$iolog_dir")
     fi
-    AC_MSG_RESULT($with_iologdir)
+    AC_MSG_RESULT($iolog_dir)
 ])dnl
 
 dnl
 dnl SUDO_CHECK_TYPE(TYPE, DEFAULT)
 dnl XXX - should require the check for unistd.h...
 dnl
-AC_DEFUN(SUDO_CHECK_TYPE,
+AC_DEFUN([SUDO_CHECK_TYPE],
 [AC_REQUIRE([AC_HEADER_STDC])dnl
 AC_MSG_CHECKING(for $1)
 AC_CACHE_VAL(sudo_cv_type_$1,
@@ -163,31 +163,31 @@ fi
 dnl
 dnl Check for size_t declation
 dnl
-AC_DEFUN(SUDO_TYPE_SIZE_T,
+AC_DEFUN([SUDO_TYPE_SIZE_T],
 [SUDO_CHECK_TYPE(size_t, int)])
 
 dnl
 dnl Check for ssize_t declation
 dnl
-AC_DEFUN(SUDO_TYPE_SSIZE_T,
+AC_DEFUN([SUDO_TYPE_SSIZE_T],
 [SUDO_CHECK_TYPE(ssize_t, int)])
 
 dnl
 dnl Check for dev_t declation
 dnl
-AC_DEFUN(SUDO_TYPE_DEV_T,
+AC_DEFUN([SUDO_TYPE_DEV_T],
 [SUDO_CHECK_TYPE(dev_t, int)])
 
 dnl
 dnl Check for ino_t declation
 dnl
-AC_DEFUN(SUDO_TYPE_INO_T,
+AC_DEFUN([SUDO_TYPE_INO_T],
 [SUDO_CHECK_TYPE(ino_t, unsigned int)])
 
 dnl
 dnl check for working fnmatch(3)
 dnl
-AC_DEFUN(SUDO_FUNC_FNMATCH,
+AC_DEFUN([SUDO_FUNC_FNMATCH],
 [AC_MSG_CHECKING([for working fnmatch with FNM_CASEFOLD])
 AC_CACHE_VAL(sudo_cv_func_fnmatch,
 [rm -f conftestdata; > conftestdata
@@ -253,7 +253,7 @@ int putenv(const char *string) {return 0;}], [])],
 dnl
 dnl check for sa_len field in struct sockaddr
 dnl
-AC_DEFUN(SUDO_SOCK_SA_LEN, [
+AC_DEFUN([SUDO_SOCK_SA_LEN], [
     AC_CHECK_MEMBER([struct sockaddr.sa_len], 
        [AC_DEFINE(HAVE_SA_LEN, 1, [Define if your struct sockadr has an sa_len field.])],    
        [],
@@ -266,7 +266,7 @@ dnl check for max length of uid_t in string representation.
 dnl we can't really trust UID_MAX or MAXUID since they may exist
 dnl only for backwards compatibility.
 dnl
-AC_DEFUN(SUDO_UID_T_LEN,
+AC_DEFUN([SUDO_UID_T_LEN],
 [AC_REQUIRE([AC_TYPE_UID_T])
 AC_MSG_CHECKING(max length of uid_t)
 AC_CACHE_VAL(sudo_cv_uid_t_len,
@@ -299,7 +299,7 @@ AC_DEFINE_UNQUOTED(MAX_UID_T_LEN, $sudo_cv_uid_t_len, [Define to the max length
 dnl
 dnl append a libpath to an LDFLAGS style variable
 dnl
-AC_DEFUN(SUDO_APPEND_LIBPATH, [
+AC_DEFUN([SUDO_APPEND_LIBPATH], [
     if test X"$with_rpath" = X"yes"; then
        case "$host" in
            *-*-hpux*)  $1="${$1} -L$2 -Wl,+b,$2"
@@ -319,12 +319,12 @@ dnl
 dnl Determine the mail spool location
 dnl NOTE: must be run *after* check for paths.h
 dnl
-AC_DEFUN(SUDO_MAILDIR, [
+AC_DEFUN([SUDO_MAILDIR], [
 maildir=no
 if test X"$ac_cv_header_paths_h" = X"yes"; then
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
-#include <paths.h>
-int main() {char *p = _PATH_MAILDIR;}], [])], [maildir=yes], [])
+#include <paths.h>],
+[char *p = _PATH_MAILDIR;])], [maildir=yes], [])
 fi
 if test $maildir = no; then
     # Solaris has maillock.h which defines MAILDIR
diff --git a/aix.c b/aix.c
index 5735ec97a0eb2f35b7b4e9c522b869cd6282d457..873896e22c77f5b6e19b0cd535245d3cf3c2bbee 100644 (file)
--- a/aix.c
+++ b/aix.c
@@ -31,7 +31,7 @@
 #include <usersec.h>
 #include <uinfo.h>
 
-#include "compat.h"
+#include "missing.h"
 #include "alloc.h"
 #include "error.h"
 
@@ -73,12 +73,10 @@ aix_getlimit(user, lim, valp)
 {
     int val;
 
-    if (getuserattr(user, lim, &val, SEC_INT) != 0 &&
-       getuserattr("default", lim, &val, SEC_INT) != 0) {
-       return(-1);
-    }
+    if (getuserattr(user, lim, &val, SEC_INT) != 0)
+       return -1;
     *valp = val;
-    return(0);
+    return 0;
 }
 
 static void
diff --git a/alias.c b/alias.c
index b1f57e7ecafb45a12ec1ff119dd3643e9c5f0d45..238830c7bbd948d72a6d953d45cf09d9244df64c 100644 (file)
--- a/alias.c
+++ b/alias.c
@@ -69,7 +69,7 @@ alias_compare(v1, v2)
        res = 1;
     else if ((res = strcmp(a1->name, a2->name)) == 0)
        res = a1->type - a2->type;
-    return(res);
+    return res;
 }
 
 /*
@@ -95,10 +95,10 @@ alias_find(name, type)
             */
            a = node->data;
            if (a->seqno == alias_seqno)
-               return(NULL);
+               return NULL;
            a->seqno = alias_seqno;
     }
-    return(a);
+    return a;
 }
 
 /*
@@ -122,9 +122,9 @@ alias_add(name, type, members)
     if (rbinsert(aliases, a)) {
        snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name);
        alias_free(a);
-       return(errbuf);
+       return errbuf;
     }
-    return(NULL);
+    return NULL;
 }
 
 /*
@@ -144,7 +144,7 @@ alias_apply(func, cookie)
 int
 no_aliases()
 {
-    return(rbisempty(aliases));
+    return rbisempty(aliases);
 }
 
 /*
@@ -182,14 +182,13 @@ alias_remove(name, type)
     int type;
 {
     struct rbnode *node;
-    struct alias key, *a;
+    struct alias key;
 
     key.name = name;
     key.type = type;
     if ((node = rbfind(aliases, &key)) == NULL)
-       return(NULL);
-    a = rbdelete(aliases, node);
-    return(a);
+       return NULL;
+    return rbdelete(aliases, node);
 }
 
 void
diff --git a/alloc.c b/alloc.c
index 8e6a7e2623af006a7d6e8d7ca226934d130777cc..535465c4aeb86a7295e858cd186ec89caafa934f 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -33,6 +33,9 @@
 # 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
@@ -45,7 +48,9 @@
 # include <inttypes.h>
 #endif
 
-#include "sudo.h"
+#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
@@ -76,7 +81,7 @@ emalloc(size)
 
     if ((ptr = malloc(size)) == NULL)
        errorx(1, "unable to allocate memory");
-    return(ptr);
+    return ptr;
 }
 
 /*
@@ -98,7 +103,7 @@ emalloc2(nmemb, size)
     size *= nmemb;
     if ((ptr = malloc(size)) == NULL)
        errorx(1, "unable to allocate memory");
-    return(ptr);
+    return ptr;
 }
 
 /*
@@ -118,7 +123,7 @@ erealloc(ptr, size)
     ptr = ptr ? realloc(ptr, size) : malloc(size);
     if (ptr == NULL)
        errorx(1, "unable to allocate memory");
-    return(ptr);
+    return ptr;
 }
 
 /*
@@ -143,7 +148,7 @@ erealloc3(ptr, nmemb, size)
     ptr = ptr ? realloc(ptr, size) : malloc(size);
     if (ptr == NULL)
        errorx(1, "unable to allocate memory");
-    return(ptr);
+    return ptr;
 }
 
 /*
@@ -155,14 +160,15 @@ estrdup(src)
     const char *src;
 {
     char *dst = NULL;
-    size_t size;
+    size_t len;
 
     if (src != NULL) {
-       size = strlen(src) + 1;
-       dst = (char *) emalloc(size);
-       (void) memcpy(dst, src, size);
+       len = strlen(src);
+       dst = (char *) emalloc(len + 1);
+       (void) memcpy(dst, src, len);
+       dst[len] = '\0';
     }
-    return(dst);
+    return dst;
 }
 
 /*
@@ -191,7 +197,7 @@ easprintf(ret, fmt, va_alist)
 
     if (len == -1)
        errorx(1, "unable to allocate memory");
-    return(len);
+    return len;
 }
 
 /*
@@ -208,7 +214,7 @@ evasprintf(ret, format, args)
 
     if ((len = vasprintf(ret, format, args)) == -1)
        errorx(1, "unable to allocate memory");
-    return(len);
+    return len;
 }
 
 /*
diff --git a/audit.c b/audit.c
index 9226d301d3d000c360ec5a2b25278450566503b0..15ac8eea7e2b2b8d9159b6e780cc7377744a58e0 100644 (file)
--- a/audit.c
+++ b/audit.c
@@ -32,7 +32,7 @@
 # include <varargs.h>
 #endif
 
-#include "compat.h"
+#include "missing.h"
 #include "logging.h"
 
 #ifdef HAVE_BSM_AUDIT
index 2b9d7b9bf4a0dc61ccfc763cc505cc8c62c8ec97..393605a900d99222b4bacfc0f9a40e7ba7796e96 100644 (file)
 #endif /* HAVE_UNISTD_H */
 #include <pwd.h>
 
-#include "sudo.h"
-#include "sudo_auth.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;
@@ -67,7 +67,7 @@ afs_verify(pw, pass, auth)
                         0,                     /* lifetime */
                         &afs_token,            /* token */
                         0) == 0)               /* new */
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 
     /* Fall back on old method XXX - needed? */
     setpag();
@@ -80,7 +80,7 @@ afs_verify(pw, pass, auth)
                                   NULL,        /* expiration ptr (unused) */
                                   0,           /* spare */
                                   NULL) == 0)  /* reason */
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 
-    return(AUTH_FAILURE);
+    return AUTH_FAILURE;
 }
index 7a776be0fe1fb66c34895ecbab9b73304fd127a2..fe65b0b66d3c04c5c73ff9234ba88ff3ffe3e1c8 100644 (file)
@@ -69,7 +69,7 @@ aixauth_verify(pw, prompt, auth)
        free(message);
        zero_bytes(pass, strlen(pass));
     }
-    return(rval);
+    return rval;
 }
 
 int
@@ -80,5 +80,5 @@ aixauth_cleanup(pw, auth)
     /* Unset AUTHSTATE as it may not be correct for the runas user. */
     unsetenv("AUTHSTATE");
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
index 2539713acf23726aa27cc09bb107f29b947b5eb0..727df13b08fab31533f4665ae5fa9037ee27bfab 100644 (file)
@@ -65,7 +65,7 @@ bsdauth_init(pw, promptp, auth)
     if ((as = auth_open()) == NULL) {
        log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
            "unable to begin bsd authentication");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     /* XXX - maybe sanity check the auth style earlier? */
@@ -73,7 +73,7 @@ bsdauth_init(pw, promptp, auth)
     if (login_style == NULL) {
        log_error(NO_EXIT|NO_MAIL, "invalid authentication type");
        auth_close(as);
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
      if (auth_setitem(as, AUTHV_STYLE, login_style) < 0 ||
@@ -81,11 +81,11 @@ bsdauth_init(pw, promptp, auth)
        auth_setitem(as, AUTHV_CLASS, login_class) < 0) {
        log_error(NO_EXIT|NO_MAIL, "unable to setup authentication");
        auth_close(as);
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     auth->data = (void *) as;
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -146,14 +146,14 @@ bsdauth_verify(pw, prompt, auth)
     (void) sigaction(SIGCHLD, &osa, NULL);
 
     if (authok)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 
     if (!pass)
-       return(AUTH_INTR);
+       return AUTH_INTR;
 
     if ((s = auth_getvalue(as, "errormsg")) != NULL)
        log_error(NO_EXIT|NO_MAIL, "%s", s);
-    return(AUTH_FAILURE);
+    return AUTH_FAILURE;
 }
 
 int
@@ -165,5 +165,5 @@ bsdauth_cleanup(pw, auth)
 
     auth_close(as);
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
index 76b43b3f8fa4995513bc8afcbc03836b635df6a9..3333a72036d2abcee68645c6de2960b4a55a49a1 100644 (file)
@@ -89,7 +89,7 @@ dce_verify(pw, plain_pw, auth)
        sec_login_no_flags, &login_context, &status)) {
 
        if (check_dce_status(status, "sec_login_setup_identity(1):"))
-           return(AUTH_FAILURE);
+           return AUTH_FAILURE;
 
        password_rec.key.key_type = sec_passwd_plain;
        password_rec.key.tagged_union.plain = (idl_char *) plain_pw;
@@ -101,7 +101,7 @@ dce_verify(pw, plain_pw, auth)
            &reset_passwd, &auth_src, &status)) {
 
            if (check_dce_status(status, "sec_login_validate_identity(1):"))
-               return(AUTH_FAILURE);
+               return AUTH_FAILURE;
 
            /*
             * Certify that the DCE Security Server used to set
@@ -111,10 +111,10 @@ dce_verify(pw, plain_pw, auth)
            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);
+               return AUTH_FAILURE;
            }
            if (check_dce_status(status, "sec_login_certify_identity(2):"))
-               return(AUTH_FAILURE);
+               return AUTH_FAILURE;
 
            /*
             * Sets the network credentials to those specified
@@ -122,7 +122,7 @@ dce_verify(pw, plain_pw, auth)
             */
            sec_login_set_context(login_context, &status);
            if (check_dce_status(status, "sec_login_set_context:"))
-               return(AUTH_FAILURE);
+               return AUTH_FAILURE;
 
            /*
             * Oops, your credentials were no good. Possibly
@@ -132,13 +132,13 @@ dce_verify(pw, plain_pw, auth)
            if (auth_src != sec_login_auth_src_network) {
                    (void) fprintf(stderr,
                        "You have no network credentials.\n");
-                   return(AUTH_FAILURE);
+                   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);
+                   return AUTH_FAILURE;
            }
 
            /*
@@ -150,7 +150,7 @@ dce_verify(pw, plain_pw, auth)
            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);
+               return AUTH_FAILURE;
 
            /*
             * If we get to here, then the pwent above properly fetched
@@ -172,17 +172,17 @@ dce_verify(pw, plain_pw, auth)
             * somewhere later in the program.
             */
            sec_login_purge_context(&login_context, &status);
-           return(AUTH_SUCCESS);
+           return AUTH_SUCCESS;
        } else {
            if(check_dce_status(status, "sec_login_validate_identity(2):"))
-               return(AUTH_FAILURE);
+               return AUTH_FAILURE;
            sec_login_purge_context(&login_context, &status);
            if(check_dce_status(status, "sec_login_purge_context:"))
-               return(AUTH_FAILURE);
+               return AUTH_FAILURE;
        }
     }
     (void) check_dce_status(status, "sec_login_setup_identity(2):");
-    return(AUTH_FAILURE);
+    return AUTH_FAILURE;
 }
 
 /* Returns 0 for DCE "ok" status, 1 otherwise */
@@ -195,8 +195,8 @@ check_dce_status(input_status, comment)
     unsigned char error_string[dce_c_error_string_len];
 
     if (input_status == rpc_s_ok)
-       return(0);
+       return 0;
     dce_error_inq_text(input_status, error_string, &error_stat);
     (void) fprintf(stderr, "%s %s\n", comment, error_string);
-    return(1);
+    return 1;
 }
index fba99e8095e993ca5f9bfdce771e9071909f5b3b..f1c164e976aee026a9cc66b7d8cedd4a42d88cad 100644 (file)
@@ -60,25 +60,25 @@ fwtk_init(pw, promptp, auth)
 
     if ((confp = cfg_read("sudo")) == (Cfg *)-1) {
        warningx("cannot read fwtk config");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     if (auth_open(confp)) {
        warningx("cannot connect to authentication server");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     /* Get welcome message from auth server */
     if (auth_recv(resp, sizeof(resp))) {
        warningx("lost connection to authentication server");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
     if (strncmp(resp, "Authsrv ready", 13) != 0) {
        warningx("authentication server error:\n%s", resp);
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -97,7 +97,7 @@ fwtk_verify(pw, prompt, auth)
 restart:
     if (auth_send(buf) || auth_recv(resp, sizeof(resp))) {
        warningx("lost connection to authentication server");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     /* Get the password/response from the user. */
@@ -119,10 +119,10 @@ restart:
        goto restart;
     } else {
        warningx("%s", resp);
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
     if (!pass) {                       /* ^C or error */
-       return(AUTH_INTR);
+       return AUTH_INTR;
     }
 
     /* Send the user's response to the server */
@@ -145,7 +145,7 @@ restart:
 done:
     zero_bytes(pass, strlen(pass));
     zero_bytes(buf, strlen(buf));
-    return(error);
+    return error;
 }
 
 int
@@ -155,5 +155,5 @@ fwtk_cleanup(pw, auth)
 {
 
     auth_close();
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
index f3107a063536834d30ea0b6468352c8d403294ef..883035d95dbbd74626e73a4cf184794bb4a73ed2 100644 (file)
@@ -57,16 +57,16 @@ kerb4_init(pw, promptp, auth)
 
     /* Don't try to verify root */
     if (pw->pw_uid == 0)
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
 
     /* Get the local realm, or retrun failure (no krb.conf) */
     if (krb_get_lrealm(realm, 1) != KSUCCESS)
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
 
     /* Stash a pointer to the realm (used in kerb4_verify) */
     auth->data = (void *) realm;
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -83,8 +83,8 @@ kerb4_verify(pw, pass, auth)
      * 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%lu",
-       _PATH_SUDO_TIMEDIR, (unsigned long) pw->pw_uid);
+    (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. */
@@ -94,7 +94,7 @@ kerb4_verify(pw, pass, auth)
     switch (error) {
        case INTK_OK:
            dest_tkt();                 /* we are done with the temp ticket */
-           return(AUTH_SUCCESS);
+           return AUTH_SUCCESS;
            break;
        case INTK_BADPW:
        case KDC_PR_UNKNOWN:
@@ -104,5 +104,5 @@ kerb4_verify(pw, pass, auth)
                krb_err_txt[error]);
     }
 
-    return(AUTH_FAILURE);
+    return AUTH_FAILURE;
 }
index 230898f7f0e02f2299f7162df821b298532ad995..4ce04aa1287de9e0bf0fa5e796ddbc052a87661b 100644 (file)
@@ -110,7 +110,7 @@ kerb5_init(pw, promptp, auth)
     error = krb5_init_context(&(sudo_krb5_data.sudo_context));
 #endif
     if (error)
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
     sudo_context = sudo_krb5_data.sudo_context;
 
     if ((error = krb5_parse_name(sudo_context, pw->pw_name,
@@ -118,7 +118,7 @@ kerb5_init(pw, promptp, auth)
        log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to parse '%s': %s", auth->name, pw->pw_name,
                  error_message(error));
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
     }
     princ = sudo_krb5_data.princ;
 
@@ -131,7 +131,7 @@ kerb5_init(pw, promptp, auth)
        log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to unparse princ ('%s'): %s", auth->name,
                  pw->pw_name, error_message(error));
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
     }
 
     /* Only rewrite prompt if user didn't specify their own. */
@@ -148,11 +148,11 @@ kerb5_init(pw, promptp, auth)
        log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to resolve ccache: %s", auth->name,
                  error_message(error));
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
     }
     ccache = sudo_krb5_data.ccache;
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 #ifdef HAVE_KRB5_VERIFY_USER
@@ -172,7 +172,7 @@ kerb5_verify(pw, pass, auth)
     ccache = ((sudo_krb5_datap) auth->data)->ccache;
 
     error = krb5_verify_user(sudo_context, princ, ccache, pass, 1, NULL);
-    return (error ? AUTH_FAILURE : AUTH_SUCCESS);
+    return error ? AUTH_FAILURE : AUTH_SUCCESS;
 }
 #else
 int
@@ -243,7 +243,7 @@ done:
     }
     if (creds)
        krb5_free_cred_contents(sudo_context, creds);
-    return (error ? AUTH_FAILURE : AUTH_SUCCESS);
+    return error ? AUTH_FAILURE : AUTH_SUCCESS;
 }
 #endif
 
@@ -268,7 +268,7 @@ kerb5_cleanup(pw, auth)
        krb5_free_context(sudo_context);
     }
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 #ifndef HAVE_KRB5_VERIFY_USER
@@ -299,7 +299,7 @@ verify_krb_v5_tgt(sudo_context, cred, auth_name)
        log_error(NO_EXIT|NO_MAIL,
                  "%s: unable to get host principal: %s", auth_name,
                  error_message(error));
-       return(-1);
+       return -1;
     }
 
     /* Initialize verify opts and set secure mode */
@@ -314,6 +314,6 @@ verify_krb_v5_tgt(sudo_context, cred, auth_name)
        log_error(NO_EXIT|NO_MAIL,
                  "%s: Cannot verify TGT! Possible attack!: %s", auth_name,
                  error_message(error));
-    return(error);
+    return error;
 }
 #endif
index ca2ef10695754e0c49c4610ed2f67567b6b92e0e..265de36e3ca47838f0e8270fea716eb6ae2cb01d 100644 (file)
@@ -102,7 +102,7 @@ pam_init(pw, promptp, auth)
 
     if (pam_status != PAM_SUCCESS) {
        log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     /*
@@ -124,7 +124,7 @@ pam_init(pw, promptp, auth)
     else
        (void) pam_set_item(pamh, PAM_TTY, user_ttypath);
 
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -145,11 +145,11 @@ pam_verify(pw, prompt, auth)
            *pam_status = pam_acct_mgmt(pamh, PAM_SILENT);
            switch (*pam_status) {
                case PAM_SUCCESS:
-                   return(AUTH_SUCCESS);
+                   return AUTH_SUCCESS;
                case PAM_AUTH_ERR:
-                   log_error(NO_EXIT|NO_MAIL, "pam_acct_mgmt: %d",
-                       *pam_status);
-                   return(AUTH_FAILURE);
+                   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",
@@ -157,33 +157,33 @@ pam_verify(pw, prompt, auth)
                    *pam_status = pam_chauthtok(pamh,
                        PAM_CHANGE_EXPIRED_AUTHTOK);
                    if (*pam_status == PAM_SUCCESS)
-                       return(AUTH_SUCCESS);
+                       return AUTH_SUCCESS;
                    if ((s = pam_strerror(pamh, *pam_status)))
                        log_error(NO_EXIT|NO_MAIL, "pam_chauthtok: %s", s);
-                   return(AUTH_FAILURE);
+                   return AUTH_FAILURE;
                case PAM_AUTHTOK_EXPIRED:
                    log_error(NO_EXIT|NO_MAIL,
                        "Password expired, contact your system administrator");
-                   return(AUTH_FATAL);
+                   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);
+                   return AUTH_FATAL;
            }
            /* FALLTHROUGH */
        case PAM_AUTH_ERR:
            if (gotintr) {
                /* error or ^C from tgetpass() */
-               return(AUTH_INTR);
+               return AUTH_INTR;
            }
        case PAM_MAXTRIES:
        case PAM_PERM_DENIED:
-           return(AUTH_FAILURE);
+           return AUTH_FAILURE;
        default:
            if ((s = pam_strerror(pamh, *pam_status)))
                log_error(NO_EXIT|NO_MAIL, "pam_authenticate: %s", s);
-           return(AUTH_FATAL);
+           return AUTH_FATAL;
     }
 }
 
@@ -196,10 +196,10 @@ pam_cleanup(pw, auth)
 
     /* If successful, we can't close the session until pam_prep_user() */
     if (auth->status == AUTH_SUCCESS)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 
     *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
-    return(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
+    return *pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
 }
 
 int
@@ -235,7 +235,7 @@ pam_begin_session(pw)
        pamh = NULL;
     }
 #endif
-    return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
+    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
 }
 
 int
@@ -249,7 +249,7 @@ pam_end_session()
 #endif
        status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
     }
-    return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
+    return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
 }
 
 /*
@@ -270,7 +270,7 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
     int n, flags, std_prompt;
 
     if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL)
-       return(PAM_SYSTEM_ERR);
+       return PAM_SYSTEM_ERR;
     zero_bytes(*response, num_msg * sizeof(struct pam_response));
 
     for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) {
@@ -332,7 +332,7 @@ sudo_conv(num_msg, msg, response, appdata_ptr)
        }
     }
 
-    return(PAM_SUCCESS);
+    return PAM_SUCCESS;
 
 err:
     /* Zero and free allocated memory and return an error. */
@@ -346,5 +346,5 @@ err:
     zero_bytes(*response, num_msg * sizeof(struct pam_response));
     free(*response);
     *response = NULL;
-    return(gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR);
+    return gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR;
 }
index 4f9efb8a28d0170350e5eee12b7be91e4a137df6..8835c0363c96529c1a24fec428186218b8912b92 100644 (file)
@@ -57,9 +57,12 @@ passwd_init(pw, promptp, auth)
 {
 #ifdef HAVE_SKEYACCESS
     if (skeyaccess(pw, user_tty, NULL, NULL) == 0)
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
 #endif
-    return(AUTH_SUCCESS);
+    sudo_setspent();
+    auth->data = sudo_getepw(pw);
+    sudo_endspent();
+    return AUTH_SUCCESS;
 }
 
 int
@@ -69,16 +72,17 @@ passwd_verify(pw, pass, auth)
     sudo_auth *auth;
 {
     char sav, *epass;
+    char *pw_epasswd = auth->data;
     size_t pw_len;
     int error;
 
-    pw_len = strlen(pw->pw_passwd);
+    pw_len = strlen(pw_epasswd);
 
 #ifdef HAVE_GETAUTHUID
     /* Ultrix shadow passwords may use crypt16() */
-    error = strcmp(pw->pw_passwd, (char *) crypt16(pass, pw->pw_passwd));
+    error = strcmp(pw_epasswd, (char *) crypt16(pass, pw_epasswd));
     if (!error)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 #endif /* HAVE_GETAUTHUID */
 
     /*
@@ -86,7 +90,7 @@ passwd_verify(pw, pass, auth)
      * 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->pw_passwd, pw_len))
+    if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len))
        pass[8] = '\0';
 
     /*
@@ -94,12 +98,26 @@ passwd_verify(pw, pass, auth)
      * 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->pw_passwd);
+    epass = (char *) crypt(pass, pw_epasswd);
     pass[8] = sav;
-    if (HAS_AGEINFO(pw->pw_passwd, pw_len) && strlen(epass) == DESLEN)
-       error = strncmp(pw->pw_passwd, epass, DESLEN);
+    if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN)
+       error = strncmp(pw_epasswd, epass, DESLEN);
     else
-       error = strcmp(pw->pw_passwd, epass);
+       error = strcmp(pw_epasswd, epass);
 
-    return(error ? AUTH_FAILURE : AUTH_SUCCESS);
+    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;
 }
index 3bc39c302142fd4cd04ef215d66134e3b311e6d5..b0640e567b8a1e661cb70ca28a34cab56af2eca4 100644 (file)
@@ -104,9 +104,9 @@ rfc1938_setup(pw, promptp, auth)
     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);
+           return AUTH_FATAL;
        } else {
-           return(AUTH_FAILURE);
+           return AUTH_FAILURE;
        }
     }
 
@@ -123,7 +123,7 @@ rfc1938_setup(pw, promptp, auth)
            orig_prompt, challenge);
 
     *promptp = new_prompt;
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -134,7 +134,7 @@ rfc1938_verify(pw, pass, auth)
 {
 
     if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
     else
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
 }
index e7148d3f7e51f4087848fc06e85d044d83e69e0f..c1c43d04cf8cfd331df7032b83a5ee21701e12c1 100644 (file)
@@ -62,9 +62,12 @@ secureware_init(pw, promptp, auth)
     extern int crypt_type;
 
     if (crypt_type == INT_MAX)
-       return(AUTH_FAILURE);                   /* no shadow */
+       return AUTH_FAILURE;                    /* no shadow */
 #endif
-    return(AUTH_SUCCESS);
+    sudo_setspent();
+    auth->data = sudo_getepw(pw);
+    sudo_endspent();
+    return AUTH_SUCCESS;
 }
 
 int
@@ -73,25 +76,40 @@ secureware_verify(pw, pass, auth)
     char *pass;
     sudo_auth *auth;
 {
+    char *pw_epasswd = auth->data;
 #ifdef __alpha
     extern int crypt_type;
 
 #  ifdef HAVE_DISPCRYPT
-    if (strcmp(user_passwd, dispcrypt(pass, user_passwd, crypt_type)) == 0)
-       return(AUTH_SUCCESS);
+    if (strcmp(pw_epasswd, dispcrypt(pass, pw_epasswd, crypt_type)) == 0)
+       return AUTH_SUCCESS;
 #  else
     if (crypt_type == AUTH_CRYPT_BIGCRYPT) {
-       if (strcmp(user_passwd, bigcrypt(pass, user_passwd)) == 0)
-           return(AUTH_SUCCESS);
+       if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0)
+           return AUTH_SUCCESS;
     } else if (crypt_type == AUTH_CRYPT_CRYPT16) {
-       if (strcmp(user_passwd, crypt(pass, user_passwd)) == 0)
-           return(AUTH_SUCCESS);
+       if (strcmp(pw_epasswd, crypt(pass, pw_epasswd)) == 0)
+           return AUTH_SUCCESS;
     }
 #  endif /* HAVE_DISPCRYPT */
 #elif defined(HAVE_BIGCRYPT)
-    if (strcmp(user_passwd, bigcrypt(pass, user_passwd)) == 0)
-       return(AUTH_SUCCESS);
+    if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0)
+       return AUTH_SUCCESS;
 #endif /* __alpha */
 
-       return(AUTH_FAILURE);
+       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;
 }
index 6aec1098f40844323432c5a9d82ab72e61740532..83ff94c139aa2dd8615e76579081171f90920dad 100644 (file)
@@ -66,9 +66,9 @@ securid_init(pw, promptp, auth)
     auth->data = (void *) &sd_dat;             /* For method-specific data */
 
     if (creadcfg() == 0)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
     else
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
 }
 
 int
@@ -83,10 +83,10 @@ securid_setup(pw, promptp, auth)
     if (sd_init(sd) == 0) {
        /* The programmer's guide says username is 32 bytes */
        strlcpy(sd->username, pw->pw_name, 32);
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
     } else {
        warningx("unable to contact the SecurID server");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 }
 
@@ -102,7 +102,7 @@ securid_verify(pw, pass, auth)
     rval = sd_auth(sd);
     sd_close();
     if (rval == ACM_OK)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
     else
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
 }
index ef9e2283fd811a123a7d3f082933da79fbc15d84..6880c1a1d79b90df833401767897da50ad3b55a4 100644 (file)
@@ -79,10 +79,10 @@ securid_init(pw, promptp, auth)
 
     /* Start communications */
     if (AceInitialize() != SD_FALSE)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
 
     warningx("failed to initialise the ACE API library");
-    return(AUTH_FATAL);
+    return AUTH_FATAL;
 }
 
 /*
@@ -110,7 +110,7 @@ securid_setup(pw, promptp, auth)
     /* Re-initialize SecurID every time. */
     if (SD_Init(sd) != ACM_OK) {
        warningx("unable to contact the SecurID server");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     /* Lock new PIN code */
@@ -119,23 +119,23 @@ securid_setup(pw, promptp, auth)
     switch (retval) {
        case ACM_OK:
                warningx("User ID locked for SecurID Authentication");
-               return(AUTH_SUCCESS);
+               return AUTH_SUCCESS;
 
         case ACE_UNDEFINED_USERNAME:
                warningx("invalid username length for SecurID");
-               return(AUTH_FATAL);
+               return AUTH_FATAL;
 
        case ACE_ERR_INVALID_HANDLE:
                warningx("invalid Authentication Handle for SecurID");
-               return(AUTH_FATAL);
+               return AUTH_FATAL;
 
        case ACM_ACCESS_DENIED:
                warningx("SecurID communication failed");
-               return(AUTH_FATAL);
+               return AUTH_FATAL;
 
        default:
                warningx("unknown SecurID error");
-               return(AUTH_FATAL);
+               return AUTH_FATAL;
        }
 }
 
@@ -228,5 +228,5 @@ then enter the new token code.\n", \
     SD_Close(*sd);
 
     /* Return stored state to calling process */
-    return(rval);
+    return rval;
 }
index 188676a7abe15d9e04b7cfc29d67d488cfca37f1..6c972c635fcc9234b287bb2aaba04d97951d3b1c 100644 (file)
@@ -101,11 +101,11 @@ sia_setup(pw, promptp, auth)
 
        log_error(USE_ERRNO|NO_EXIT|NO_MAIL,
            "unable to initialize SIA session");
-       return(AUTH_FATAL);
+       return AUTH_FATAL;
     }
 
     auth->data = (void *) siah;
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
 
 int
@@ -120,9 +120,9 @@ sia_verify(pw, prompt, auth)
 
     /* XXX - need a way to detect user hitting return or EOF at prompt */
     if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS)
-       return(AUTH_SUCCESS);
+       return AUTH_SUCCESS;
     else
-       return(AUTH_FAILURE);
+       return AUTH_FAILURE;
 }
 
 int
@@ -133,5 +133,5 @@ sia_cleanup(pw, auth)
     SIAENTITY *siah = (SIAENTITY *) auth->data;
 
     (void) sia_ses_release(&siah);
-    return(AUTH_SUCCESS);
+    return AUTH_SUCCESS;
 }
index 69b0a3a661e54d8ff5210019713973888d5a6c6d..42455ee31640ae8343e9d3f32594b1d29b3548a1 100644 (file)
@@ -53,10 +53,10 @@ sudo_auth auth_switch[] = {
     AUTH_STANDALONE
 #else
 #  ifndef WITHOUT_PASSWD
-    AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL)
+    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, NULL)
+    AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, secureware_cleanup)
 #  endif
 #  ifdef HAVE_AFS
     AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
index a4efe1412376347f0ce9095ec4c87cb274c988fd..50249552b597be3fa75e5330e3ed47fbb52abfbd 100644 (file)
@@ -64,8 +64,10 @@ 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));
index f75af3ecaaae1707a191e202033fa0604ab5759b..bdcd1f2d26a2ee3081efd4df83573456599d671b 100644 (file)
 #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 "compat.h"
 #include "missing.h"
 
 /*
@@ -102,7 +106,6 @@ get_boottime(tv)
 
 #elif defined(HAVE_GETUTXID)
 
-#include <utmpx.h>
 int
 get_boottime(tv)
     struct timeval *tv;
@@ -121,7 +124,6 @@ get_boottime(tv)
 
 #elif defined(HAVE_GETUTID)
 
-#include <utmp.h>
 int
 get_boottime(tv)
     struct timeval *tv;
index a673d281e3c1a7f0456d3635adcdd6dfe98f51aa..94ed4a8bf5152434c5cd50ae018e21f54125d0c5 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * 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
@@ -35,7 +36,7 @@
  * Solaris auditon() returns EINVAL if BSM audit not configured.
  * OpenBSM returns ENOSYS for unimplemented options.
  */
-#ifdef __sun__
+#ifdef __sun
 # define AUDIT_NOT_CONFIGURED  EINVAL
 #else
 # define AUDIT_NOT_CONFIGURED  ENOSYS
@@ -62,7 +63,7 @@ audit_sudo_selected(int sf)
                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);
+        return rc;
 }
 
 void
diff --git a/check.c b/check.c
index badf3e4007735df5ec8ad5e454bd3cefc811cf9b..df44bfca73934706d724cdc61a8b94d8e3f44280 100644 (file)
--- a/check.c
+++ b/check.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1993-1996,1998-2005, 2007-2010
+ * 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
@@ -90,6 +90,7 @@ 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
@@ -134,6 +135,8 @@ check_user(validated, mode)
        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());
@@ -162,7 +165,9 @@ check_user(validated, mode)
        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)
@@ -225,7 +230,8 @@ update_timestamp(timestampdir, timestampfile)
            log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile);
        else {
            lock_file(fd, SUDO_LOCK);
-           write(fd, &tty_info, sizeof(tty_info));
+           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 {
@@ -299,7 +305,7 @@ expand_prompt(old_prompt, user, host)
     }
 
     if (subst) {
-       new_prompt = (char *) emalloc(++len);
+       new_prompt = emalloc(++len);
        endp = new_prompt + len;
        for (p = old_prompt, np = new_prompt; *p; p++) {
            if (p[0] =='%') {
@@ -361,7 +367,7 @@ expand_prompt(old_prompt, user, host)
     } else
        new_prompt = old_prompt;
 
-    return(new_prompt);
+    return new_prompt;
 
 oflow:
     /* We pre-allocate enough space, so this should never happen. */
@@ -375,8 +381,8 @@ int
 user_is_exempt()
 {
     if (!def_exempt_group)
-       return(FALSE);
-    return(user_in_group(sudo_user.pw, def_exempt_group));
+       return FALSE;
+    return user_in_group(sudo_user.pw, def_exempt_group);
 }
 
 /*
@@ -453,9 +459,9 @@ timestamp_status(timestampdir, timestampfile, user, flags)
            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 %lu, should be uid %lu",
-               dirparent, (unsigned long) sb.st_uid,
-               (unsigned long) 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",
@@ -480,7 +486,7 @@ timestamp_status(timestampdir, timestampfile, user, flags)
     if (status == TS_ERROR) {
        if (timestamp_uid != 0)
            set_perms(PERM_ROOT);
-       return(status);
+       return status;
     }
 
     /*
@@ -500,9 +506,9 @@ timestamp_status(timestampdir, timestampfile, user, flags)
                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 %lu, should be uid %lu",
-               timestampdir, (unsigned long) sb.st_uid,
-               (unsigned long) 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",
@@ -545,9 +551,9 @@ timestamp_status(timestampdir, timestampfile, user, flags)
                /* 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 %lu, should be uid %lu",
-                       timestampfile, (unsigned long) sb.st_uid,
-                       (unsigned long) timestamp_uid);
+                       "%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,
@@ -624,7 +630,7 @@ timestamp_status(timestampdir, timestampfile, user, flags)
 done:
     if (timestamp_uid != 0)
        set_perms(PERM_ROOT);
-    return(status);
+    return status;
 }
 
 /*
@@ -698,3 +704,33 @@ tty_is_devpts(tty)
 #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;
+}
index fb9958ebc2f3e559e5160dc2beaa5f58fe2ff37c..68da392d746f30b97ab2da4dea4a2764f9e3333e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2005, 2007
+ * Copyright (c) 2004-2005, 2007, 2010
  *     Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * Permission to use, copy, modify, and distribute this software for any
@@ -47,7 +47,7 @@
 # endif
 #endif
 
-#include "sudo.h"
+#include "missing.h"
 
 #ifndef HAVE_FCNTL_CLOSEM
 # ifndef HAVE_DIRFD
diff --git a/compat.h b/compat.h
deleted file mode 100644 (file)
index c01924d..0000000
--- a/compat.h
+++ /dev/null
@@ -1,312 +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_COMPAT_H
-#define _SUDO_COMPAT_H
-
-/*
- * 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
-
-#endif /* _SUDO_COMPAT_H */
index af5653b6da84e662786b4d19a18d489830209d50..a4b000db0a3e1f9fbd4db5b12d8d2f22e1cc1811 100644 (file)
@@ -27,6 +27,9 @@
    variables. */
 #undef ENV_EDITOR
 
+/* Define to 1 to enable environment resetting by default. */
+#undef ENV_RESET
+
 /* If defined, users in this group need not enter a passwd (ie "sudo"). */
 #undef EXEMPTGROUP
 
 /* Define to 1 if you have the `ldap_search_ext_s' function. */
 #undef HAVE_LDAP_SEARCH_EXT_S
 
+/* Define to 1 if you have the `ldap_search_st' function. */
+#undef HAVE_LDAP_SEARCH_ST
+
 /* Define to 1 if you have the `ldap_ssl_client_init' function. */
 #undef HAVE_LDAP_SSL_CLIENT_INIT
 
 /* Define to 1 if you have the <netgroup.h> header file. */
 #undef HAVE_NETGROUP_H
 
+/* Define to 1 if you have the `nl_langinfo' function. */
+#undef HAVE_NL_LANGINFO
+
 /* Define to 1 if you have the `openpty' function. */
 #undef HAVE_OPENPTY
 
 /* Define to 1 if you have the <sys/stropts.h> header file. */
 #undef HAVE_SYS_STROPTS_H
 
+/* Define to 1 if you have the <sys/sysmacros.h> header file. */
+#undef HAVE_SYS_SYSMACROS_H
+
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
 /* Define to 1 if you have the `vasprintf' function. */
 #undef HAVE_VASPRINTF
 
-/* Define to 1 if you have the `vhangup' function. */
-#undef HAVE_VHANGUP
-
 /* Define to 1 if you have the `vsnprintf' function. */
 #undef HAVE_VSNPRINTF
 
 /* Define to 1 if the code in interfaces.c does not compile for you. */
 #undef STUB_LOAD_INTERFACES
 
-/* The umask that the root-run prog should use. */
+/* The umask that the sudo-run prog should use. */
 #undef SUDO_UMASK
 
 /* The number of minutes before sudo asks for a password again. */
 /* The number of tries a user gets to enter their password. */
 #undef TRIES_FOR_PASSWORD
 
+/* Define to 1 to use the umask specified in sudoers even when it is less
+   restrictive than the invoking user's. */
+#undef UMASK_OVERRIDE
+
 /* Define to 1 if the `unsetenv' function returns void instead of `int'. */
 #undef UNSETENV_VOID
 
 /* Define to avoid using the passwd/shadow file for authentication. */
 #undef WITHOUT_PASSWD
 
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
 /* Define to `signed' or nothing if compiler does not support a signed type
    qualifier. */
 #undef __signed
index f7c4838c0780cc49bac5e4e7dae4b5b26f5a8a46..4ac04df652acd93f7a370c99aeae1d806a09851e 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.4p6.
+# Generated by GNU Autoconf 2.65 for sudo 1.7.6p1.
 #
 # Report bugs to <http://www.sudo.ws/bugs/>.
 #
@@ -701,8 +701,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='sudo'
 PACKAGE_TARNAME='sudo'
-PACKAGE_VERSION='1.7.4p6'
-PACKAGE_STRING='sudo 1.7.4p6'
+PACKAGE_VERSION='1.7.6p1'
+PACKAGE_STRING='sudo 1.7.6p1'
 PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/'
 PACKAGE_URL=''
 
@@ -794,6 +794,7 @@ root_sudo
 insults
 tty_tickets
 passwd_tries
+env_reset
 env_editor
 runas_default
 fqdn
@@ -811,11 +812,14 @@ logfac
 lecture
 long_otp_prompt
 passprompt
+umask_override
 sudo_umask
 password_timeout
 timeout
 timedir
+iolog_dir
 CONFIGURE_ARGS
+ZLIB_DEP
 ZLIB
 LOGINCAP_USAGE
 REPLAY
@@ -947,6 +951,7 @@ with_sudoers_mode
 with_sudoers_uid
 with_sudoers_gid
 with_umask
+with_umask_override
 with_runas_default
 with_exempt
 with_editor
@@ -983,6 +988,7 @@ enable_noargs_shell
 enable_shell_sets_home
 enable_path_info
 enable_env_debug
+enable_env_reset
 enable_warnings
 enable_admin_flag
 with_selinux
@@ -996,6 +1002,7 @@ enable_libtool_lock
 with_noexec
 with_netsvc
 enable_sia
+enable_largefile
 with_pam_login
 enable_pam_session
 enable_zlib
@@ -1552,7 +1559,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.4p6 to adapt to many kinds of systems.
+\`configure' configures sudo 1.7.6p1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1617,7 +1624,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of sudo 1.7.4p6:";;
+     short | recursive ) echo "Configuration of sudo 1.7.6p1:";;
    esac
   cat <<\_ACEOF
 
@@ -1638,6 +1645,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-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
   --enable-gss-krb5-ccache-name
@@ -1648,6 +1656,7 @@ Optional Features:
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
   --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
 
@@ -1709,6 +1718,8 @@ Optional Packages:
   --with-umask            umask with which the prog should run (default is
                           022)
   --without-umask         Preserves the umask of the user invoking sudo.
+  --with-umask-override   Use the umask specified in sudoers even if it is
+                          less restrictive than the user's.
   --with-runas-default    User to run commands as (default is "root")
   --with-exempt=group     no passwd needed for users in this group
   --with-editor=path      Default editor for visudo (defaults to vi)
@@ -1828,7 +1839,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-sudo configure 1.7.4p6
+sudo configure 1.7.6p1
 generated by GNU Autoconf 2.65
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -2527,7 +2538,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.4p6, which was
+It was created by sudo $as_me 1.7.6p1, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   $ $0 $@
@@ -2874,7 +2885,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"
+ac_config_headers="$ac_config_headers config.h pathnames.h zlib/zconf.h"
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: Configuring Sudo version $PACKAGE_VERSION" >&5
 $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
@@ -2947,6 +2958,9 @@ $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
 
 
 
+
+
+
 
 
 
@@ -2954,10 +2968,12 @@ $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;}
 #
 # Begin initial values for man page substitution
 #
+iolog_dir=/var/log/sudo-io
 timedir=/var/adm/sudo
 timeout=5
 password_timeout=5
 sudo_umask=0022
+umask_override=off
 passprompt="Password:"
 long_otp_prompt=off
 lecture=once
@@ -2975,6 +2991,7 @@ badpass_message="Sorry, try again."
 fqdn=off
 runas_default=root
 env_editor=off
+env_reset=on
 editor=vi
 passwd_tries=3
 tty_tickets=on
@@ -3005,6 +3022,7 @@ BAMAN=0
 LCMAN=0
 SEMAN=0
 ZLIB=
+ZLIB_DEP=
 AUTH_OBJS=
 AUTH_REG=
 AUTH_EXCL=
@@ -3063,9 +3081,6 @@ $as_echo "$as_me: WARNING: Ignoring unknown argument to --with-devel: $with_deve
 esac
 fi
 
-if test X"$with_devel" != X"yes"; then
-    ac_cv_prog_cc_g=no
-fi
 
 
 # Check whether --with-CC was given.
@@ -3916,8 +3931,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 # Check whether --with-linux-audit was given.
 if test "${with_linux_audit+set}" = set; then :
   withval=$with_linux_audit; case $with_linux_audit in
-    yes)
-               cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+    yes)       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <libaudit.h>
 int
@@ -4060,8 +4074,7 @@ fi
 # Check whether --with-skey was given.
 if test "${with_skey+set}" = set; then :
   withval=$with_skey; case $with_skey in
-    no)                with_skey=""
-               ;;
+    no)                ;;
     *)         $as_echo "#define HAVE_SKEY 1" >>confdefs.h
 
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to try S/Key authentication" >&5
@@ -4078,8 +4091,7 @@ fi
 # Check whether --with-opie was given.
 if test "${with_opie+set}" = set; then :
   withval=$with_opie; case $with_opie in
-    no)                with_opie=""
-               ;;
+    no)                ;;
     *)         $as_echo "#define HAVE_OPIE 1" >>confdefs.h
 
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to try NRL OPIE authentication" >&5
@@ -4116,7 +4128,7 @@ fi
 # Check whether --with-SecurID was given.
 if test "${with_SecurID+set}" = set; then :
   withval=$with_SecurID; case $with_SecurID in
-    no)                with_SecurID="";;
+    no)                ;;
     *)         $as_echo "#define HAVE_SECURID 1" >>confdefs.h
 
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use SecurID for authentication" >&5
@@ -4133,7 +4145,7 @@ fi
 # Check whether --with-fwtk was given.
 if test "${with_fwtk+set}" = set; then :
   withval=$with_fwtk; case $with_fwtk in
-    no)                with_fwtk="";;
+    no)                ;;
     *)         $as_echo "#define HAVE_FWTK 1" >>confdefs.h
 
                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use FWTK AuthSRV for authentication" >&5
@@ -4150,7 +4162,7 @@ fi
 # Check whether --with-kerb4 was given.
 if test "${with_kerb4+set}" = set; then :
   withval=$with_kerb4; case $with_kerb4 in
-    no)                with_kerb4="";;
+    no)                ;;
     *)         { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to try kerberos IV authentication" >&5
 $as_echo_n "checking whether to try kerberos IV authentication... " >&6; }
                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
@@ -4165,7 +4177,7 @@ fi
 # Check whether --with-kerb5 was given.
 if test "${with_kerb5+set}" = set; then :
   withval=$with_kerb5; case $with_kerb5 in
-    no)                with_kerb5="";;
+    no)                ;;
     *)         { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to try Kerberos V authentication" >&5
 $as_echo_n "checking whether to try Kerberos V authentication... " >&6; }
                { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
@@ -4775,6 +4787,22 @@ else
 $as_echo "$sudo_umask" >&6; }
 fi
 
+
+# Check whether --with-umask-override was given.
+if test "${with_umask_override+set}" = set; then :
+  withval=$with_umask_override; case $with_umask_override in
+    yes)       $as_echo "#define UMASK_OVERRIDE 1" >>confdefs.h
+
+               umask_override=on
+               ;;
+    no)                umask_override=off
+               ;;
+    *)         as_fn_error "\"--with-umask-override does not take an argument.\"" "$LINENO" 5
+               ;;
+esac
+fi
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for default user to run commands as" >&5
 $as_echo_n "checking for default user to run commands as... " >&6; }
 
@@ -5580,6 +5608,35 @@ $as_echo "no" >&6; }
 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.
+if test "${enable_env_reset+set}" = set; then :
+  enableval=$enable_env_reset;  case "$enableval" in
+    yes)       env_reset=on
+               ;;
+    no)                env_reset=off
+               ;;
+    *)         env_reset=on
+               { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unknown argument to --enable-env-reset: $enableval" >&5
+$as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-env-reset: $enableval" >&2;}
+               ;;
+  esac
+
+fi
+
+if test "$env_reset" = "on"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    $as_echo "#define ENV_RESET TRUE" >>confdefs.h
+
+else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    $as_echo "#define ENV_RESET FALSE" >>confdefs.h
+
+fi
+
 # Check whether --enable-warnings was given.
 if test "${enable_warnings+set}" = set; then :
   enableval=$enable_warnings;  case "$enableval" in
@@ -6056,6 +6113,9 @@ else
   RANLIB="$ac_cv_prog_RANLIB"
 fi
 
+if test X"$AR" = X"false"; then
+    as_fn_error "the \"ar\" utility is required to build sudo" "$LINENO" 5
+fi
 
 ac_aux_dir=
 for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
@@ -6762,13 +6822,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:6765: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:6825: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:6768: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:6828: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:6771: output\"" >&5)
+  (eval echo "\"\$as_me:6831: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -7973,7 +8033,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 7976 "configure"' > conftest.$ac_ext
+  echo '#line 8036 "configure"' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -9366,11 +9426,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9369: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9429: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9373: \$? = $ac_status" >&5
+   echo "$as_me:9433: \$? = $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.
@@ -9705,11 +9765,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9708: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9768: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:9712: \$? = $ac_status" >&5
+   echo "$as_me:9772: \$? = $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.
@@ -9810,11 +9870,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9813: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9873: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9817: \$? = $ac_status" >&5
+   echo "$as_me:9877: \$? = $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
@@ -9865,11 +9925,11 @@ else
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:9868: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:9928: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:9872: \$? = $ac_status" >&5
+   echo "$as_me:9932: \$? = $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
@@ -12232,7 +12292,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12235 "configure"
+#line 12295 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12328,7 +12388,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12331 "configure"
+#line 12391 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12867,7 +12927,7 @@ done
 
                if test -z "$GCC"; then
                    # HP-UX bundled compiler can't generate shared objects
-                   if -z "$pic_flag"; then
+                   if test "x$ac_cv_prog_cc_c89" = "xno"; then
                        with_noexec=no
                    fi
 
@@ -12941,6 +13001,8 @@ $as_echo "$sudo_cv_var_daportable" >&6; }
                        *-*-hpux10.*)
                            shadow_funcs="getprpwnam iscomsec"
                            shadow_libs="-lsec"
+                           # HP-UX 10.20 libc has an incompatible getline
+                           ac_cv_func_getline="no"
                        ;;
                        *)
                            shadow_funcs="getspnam iscomsec"
@@ -13240,7 +13302,7 @@ done
                    SKIP_SETREUID=yes
                    ;;
                esac
-               if test "$with_skey" = "yes"; then
+               if test "${with_skey-'no'}" = "yes"; then
                     SUDO_LIBS="${SUDO_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
@@ -13276,7 +13338,7 @@ done
                : ${with_logincap='maybe'}
                ;;
     *-*-dragonfly*)
-               if test "$with_skey" = "yes"; then
+               if test "${with_skey-'no'}" = "yes"; then
                     SUDO_LIBS="${SUDO_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
@@ -14019,7 +14081,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
+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
 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"
 
 done
 
+# Check whether --enable-largefile was given.
+if test "${enable_largefile+set}" = set; then :
+  enableval=$enable_largefile;
+fi
+
+if test "$enable_largefile" != no; then
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5
+$as_echo_n "checking for special C compiler options needed for large files... " >&6; }
+if test "${ac_cv_sys_largefile_CC+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_sys_largefile_CC=no
+     if test "$GCC" != yes; then
+       ac_save_CC=$CC
+       while :; do
+        # IRIX 6.2 and later do not support large files by default,
+        # so use the C compiler's -n32 option if that helps.
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+        if ac_fn_c_try_compile "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext
+        CC="$CC -n32"
+        if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_largefile_CC=' -n32'; break
+fi
+rm -f core conftest.err conftest.$ac_objext
+        break
+       done
+       CC=$ac_save_CC
+       rm -f conftest.$ac_ext
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5
+$as_echo "$ac_cv_sys_largefile_CC" >&6; }
+  if test "$ac_cv_sys_largefile_CC" != no; then
+    CC=$CC$ac_cv_sys_largefile_CC
+  fi
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5
+$as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; }
+if test "${ac_cv_sys_file_offset_bits+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_file_offset_bits=64; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_file_offset_bits=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5
+$as_echo "$ac_cv_sys_file_offset_bits" >&6; }
+case $ac_cv_sys_file_offset_bits in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  if test $ac_cv_sys_file_offset_bits = unknown; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5
+$as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; }
+if test "${ac_cv_sys_large_files+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  while :; do
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=no; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _LARGE_FILES 1
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                      && LARGE_OFF_T % 2147483647 == 1)
+                     ? 1 : -1];
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_sys_large_files=1; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_cv_sys_large_files=unknown
+  break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5
+$as_echo "$ac_cv_sys_large_files" >&6; }
+case $ac_cv_sys_large_files in #(
+  no | unknown) ;;
+  *)
+cat >>confdefs.h <<_ACEOF
+#define _LARGE_FILES $ac_cv_sys_large_files
+_ACEOF
+;;
+esac
+rm -rf conftest*
+  fi
+fi
+
+case "$host" in
+    *-*-hpux11.*)
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h needs _XOPEN_SOURCE_EXTENDED" >&5
+$as_echo_n "checking whether sys/types.h needs _XOPEN_SOURCE_EXTENDED... " >&6; }
+if test "${sudo_cv_xopen_source_extended+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+       #include <sys/socket.h>
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  sudo_cv_xopen_source_extended=no
+else
+
+           cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#define _XOPEN_SOURCE_EXTENDED
+           $ac_includes_default
+           #include <sys/socket.h>
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  sudo_cv_xopen_source_extended=yes
+else
+  sudo_cv_xopen_source_extended=error
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_xopen_source_extended" >&5
+$as_echo "$sudo_cv_xopen_source_extended" >&6; }
+       if test "$sudo_cv_xopen_source_extended" = "yes"; then
+           OSDEFS="${OSDEFS} -D_XOPEN_SOURCE_EXTENDED"
+           cat >>confdefs.h <<\EOF
+#define _XOPEN_SOURCE_EXTENDED 1
+EOF
+
+       fi
+       ;;
+esac
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking POSIX termios" >&5
 $as_echo_n "checking POSIX termios... " >&6; }
 if test "${ac_cv_sys_posix_termios+set}" = set; then :
@@ -14088,11 +14405,10 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $ac_includes_default
 #include <paths.h>
-int main() {char *p = _PATH_MAILDIR;}
 int
 main ()
 {
-
+char *p = _PATH_MAILDIR;
   ;
   return 0;
 }
@@ -14812,7 +15128,7 @@ LIBS=$ac_save_LIBS
 
 for ac_func in strchr strrchr memchr memcpy memset sysconf tzset \
               strftime setrlimit initgroups getgroups fstat gettimeofday \
-              regcomp setlocale getaddrinfo setenv vhangup \
+              regcomp setlocale nl_langinfo getaddrinfo setenv \
               mbr_check_membership setrlimit64
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -14918,7 +15234,7 @@ fi
 done
 
 
-for ac_func in sysctl getutid getutxid
+for ac_func in sysctl getutxid getutid
 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"
@@ -17254,7 +17570,7 @@ if test ${with_DCE-'no'} = "yes"; then
     AUTH_OBJS="$AUTH_OBJS dce.o"
 fi
 
-if test ${with_skey-'no'} = "yes"; then
+if test "${with_skey-'no'}" = "yes"; then
     O_LDFLAGS="$LDFLAGS"
     if test "$with_skey" != "yes"; then
        CPPFLAGS="${CPPFLAGS} -I${with_skey}/include"
@@ -17434,7 +17750,7 @@ fi
     AUTH_OBJS="$AUTH_OBJS rfc1938.o"
 fi
 
-if test ${with_opie-'no'} = "yes"; then
+if test "${with_opie-'no'}" = "yes"; then
     O_LDFLAGS="$LDFLAGS"
     if test "$with_opie" != "yes"; then
        CPPFLAGS="${CPPFLAGS} -I${with_opie}/include"
@@ -17574,7 +17890,7 @@ fi
 fi
 
 if test ${with_passwd-'no'} != "no"; then
-                if test -z "$LIB_CRYPT" -a "$with_passwd" != "no"; then
+                if test -z "$LIB_CRYPT"; then
        { $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 :
@@ -18022,7 +18338,7 @@ fi
 
 done
 
-    for ac_func in ldap_initialize ldap_start_tls_s ldapssl_init ldapssl_set_strength ldap_search_ext_s ldap_unbind_ext_s ldap_str2dn ldap_create ldap_sasl_bind_s ldap_ssl_client_init ldap_start_tls_s_np
+    for ac_func in ldap_initialize ldap_start_tls_s ldapssl_init ldapssl_set_strength ldap_unbind_ext_s ldap_str2dn ldap_create ldap_sasl_bind_s ldap_ssl_client_init ldap_start_tls_s_np
 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"
@@ -18032,6 +18348,19 @@ eval as_val=\$$as_ac_var
 #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
 _ACEOF
 
+fi
+done
+
+    for ac_func in ldap_search_ext_s ldap_search_st
+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
 
@@ -18266,22 +18595,22 @@ EOF
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for I/O log dir location" >&5
 $as_echo_n "checking for I/O log dir location... " >&6; }
     if test "${with_iologdir-yes}" != "yes"; then
-       :
+       iolog_dir="$with_iologdir"
     elif test -d "/var/log"; then
-       with_iologdir="/var/log/sudo-io"
+       iolog_dir="/var/log/sudo-io"
     elif test -d "/var/adm"; then
-       with_iologdir="/var/adm/sudo-io"
+       iolog_dir="/var/adm/sudo-io"
     else
-       with_iologdir="/usr/adm/sudo-io"
+       iolog_dir="/usr/adm/sudo-io"
     fi
-    if test "${with_iologdir-yes}" != "no"; then
+    if test "${with_iologdir}" != "no"; then
        cat >>confdefs.h <<EOF
-#define _PATH_SUDO_IO_LOGDIR "$with_iologdir"
+#define _PATH_SUDO_IO_LOGDIR "$iolog_dir"
 EOF
 
     fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_iologdir" >&5
-$as_echo "$with_iologdir" >&6; }
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $iolog_dir" >&5
+$as_echo "$iolog_dir" >&6; }
 
 
 if test "${with_iologdir-yes}" != "no"; then
@@ -18300,38 +18629,12 @@ _ACEOF
 
        # Check whether --enable-zlib was given.
 if test "${enable_zlib+set}" = set; then :
-  enableval=$enable_zlib;  case "$enable_zlib" in
-           yes)    $as_echo "#define HAVE_ZLIB_H 1" >>confdefs.h
-
-                   ZLIB="-lz"
-                   ;;
-           no)     ;;
-           *)      $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
-
+  enableval=$enable_zlib;
 fi
 
-       if test X"$enable_zlib" = X""; then
-           { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzdopen in -lz" >&5
+       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
@@ -18369,7 +18672,7 @@ fi
 $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
+                   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 :
@@ -18377,6 +18680,8 @@ if test "x$ac_cv_header_zlib_h" = x""yes; then :
 #define HAVE_ZLIB_H 1
 _ACEOF
  ZLIB="-lz"
+else
+  enable_zlib=builtin
 fi
 
 done
@@ -18384,6 +18689,45 @@ 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
@@ -18399,7 +18743,7 @@ fi
 
 case "$with_passwd" in
 yes|maybe)
-    AUTH_OBJS="$AUTH_OBJS passwd.o"
+    AUTH_OBJS="$AUTH_OBJS getspwuid.o passwd.o"
     ;;
 *)
     $as_echo "#define WITHOUT_PASSWD 1" >>confdefs.h
@@ -18410,7 +18754,7 @@ yes|maybe)
     ;;
 esac
 AUTH_OBJS=${AUTH_OBJS# }
-_AUTH=`echo "$AUTH_OBJS" | sed 's/\.o//g'`
+_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.o//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;}
 
@@ -18977,7 +19321,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.4p6, which was
+This file was extended by sudo $as_me 1.7.6p1, which was
 generated by GNU Autoconf 2.65.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -19043,7 +19387,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.4p6
+sudo config.status 1.7.6p1
 configured by $0, generated by GNU Autoconf 2.65,
   with options \\"\$ac_cs_config\\"
 
@@ -19419,6 +19763,7 @@ do
   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" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "sudo.man") CONFIG_FILES="$CONFIG_FILES sudo.man" ;;
@@ -20733,6 +21078,8 @@ fi
 
 
 
+
+
 
 
 
index 04ae0741585e67c02cc9bed616a182e70dbd8ed7..29d7f28b223e77c29a765100496d46eb38fc3900 100644 (file)
@@ -1,12 +1,12 @@
 dnl
 dnl Process this file with GNU autoconf to produce a configure script.
 dnl
-dnl Copyright (c) 1994-1996,1998-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+dnl Copyright (c) 1994-1996,1998-2011 Todd C. Miller <Todd.Miller@courtesan.com>
 dnl
-AC_INIT([sudo], [1.7.4p6], [http://www.sudo.ws/bugs/], [sudo])
-AC_CONFIG_HEADER(config.h pathnames.h)
+AC_INIT([sudo], [1.7.6p1], [http://www.sudo.ws/bugs/], [sudo])
+AC_CONFIG_HEADER(config.h pathnames.h zlib/zconf.h)
 dnl
-dnl This won't work before AC_INIT
+dnl Note: this must come after AC_INIT
 dnl
 AC_MSG_NOTICE([Configuring Sudo version $PACKAGE_VERSION])
 dnl
@@ -53,14 +53,17 @@ AC_SUBST([LDAP])
 AC_SUBST([REPLAY])
 AC_SUBST([LOGINCAP_USAGE])
 AC_SUBST([ZLIB])
+AC_SUBST([ZLIB_DEP])
 AC_SUBST([CONFIGURE_ARGS])
 dnl
 dnl Variables that get substituted in docs (not overridden by environment)
 dnl
+AC_SUBST([iolog_dir])dnl real initial value from SUDO_IO_LOGDIR
 AC_SUBST([timedir])dnl real initial value from SUDO_TIMEDIR
 AC_SUBST([timeout])
 AC_SUBST([password_timeout])
 AC_SUBST([sudo_umask])
+AC_SUBST([umask_override])
 AC_SUBST([passprompt])
 AC_SUBST([long_otp_prompt])
 AC_SUBST([lecture])
@@ -78,6 +81,7 @@ AC_SUBST([badpass_message])
 AC_SUBST([fqdn])
 AC_SUBST([runas_default])
 AC_SUBST([env_editor])
+AC_SUBST([env_reset])
 AC_SUBST([passwd_tries])
 AC_SUBST([tty_tickets])
 AC_SUBST([insults])
@@ -92,10 +96,12 @@ AC_SUBST([editor])
 #
 # Begin initial values for man page substitution
 #
+iolog_dir=/var/log/sudo-io
 timedir=/var/adm/sudo
 timeout=5
 password_timeout=5
 sudo_umask=0022
+umask_override=off
 passprompt="Password:"
 long_otp_prompt=off
 lecture=once
@@ -113,6 +119,7 @@ badpass_message="Sorry, try again."
 fqdn=off
 runas_default=root
 env_editor=off
+env_reset=on
 editor=vi
 passwd_tries=3
 tty_tickets=on
@@ -147,6 +154,7 @@ BAMAN=0
 LCMAN=0
 SEMAN=0
 ZLIB=
+ZLIB_DEP=
 AUTH_OBJS=
 AUTH_REG=
 AUTH_EXCL=
@@ -198,9 +206,6 @@ AC_ARG_WITH(devel, [AS_HELP_STRING([--with-devel], [add development options])],
     *)         AC_MSG_WARN([Ignoring unknown argument to --with-devel: $with_devel])
                ;;
 esac])
-if test X"$with_devel" != X"yes"; then
-    ac_cv_prog_cc_g=no
-fi
 
 AC_ARG_WITH(CC, [AS_HELP_STRING([--with-CC], [C compiler to use])],
 [case $with_CC in
@@ -245,8 +250,7 @@ dnl Handle Linux auditing support.
 dnl
 AC_ARG_WITH(linux-audit, [AS_HELP_STRING([--with-linux-audit], [enable Linux audit support])],
 [case $with_linux_audit in
-    yes)       
-               AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <libaudit.h>]], [[int i = AUDIT_USER_CMD; (void)i;]])], [
+    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"
@@ -335,8 +339,7 @@ esac])
 
 AC_ARG_WITH(skey, [AS_HELP_STRING([--with-skey[=DIR]], [enable S/Key support ])],
 [case $with_skey in
-    no)                with_skey=""
-               ;;
+    no)                ;;
     *)         AC_DEFINE(HAVE_SKEY)
                AC_MSG_CHECKING(whether to try S/Key authentication)
                AC_MSG_RESULT(yes)
@@ -346,8 +349,7 @@ esac])
 
 AC_ARG_WITH(opie, [AS_HELP_STRING([--with-opie[=DIR]], [enable OPIE support ])],
 [case $with_opie in
-    no)                with_opie=""
-               ;;
+    no)                ;;
     *)         AC_DEFINE(HAVE_OPIE)
                AC_MSG_CHECKING(whether to try NRL OPIE authentication)
                AC_MSG_RESULT(yes)
@@ -370,7 +372,7 @@ esac])
 
 AC_ARG_WITH(SecurID, [AS_HELP_STRING([--with-SecurID[[=DIR]]], [enable SecurID support])],
 [case $with_SecurID in
-    no)                with_SecurID="";;
+    no)                ;;
     *)         AC_DEFINE(HAVE_SECURID)
                AC_MSG_CHECKING(whether to use SecurID for authentication)
                AC_MSG_RESULT(yes)
@@ -380,7 +382,7 @@ esac])
 
 AC_ARG_WITH(fwtk, [AS_HELP_STRING([--with-fwtk[[=DIR]]], [enable FWTK AuthSRV support])],
 [case $with_fwtk in
-    no)                with_fwtk="";;
+    no)                ;;
     *)         AC_DEFINE(HAVE_FWTK)
                AC_MSG_CHECKING(whether to use FWTK AuthSRV for authentication)
                AC_MSG_RESULT(yes)
@@ -390,7 +392,7 @@ esac])
 
 AC_ARG_WITH(kerb4, [AS_HELP_STRING([--with-kerb4[[=DIR]]], [enable Kerberos IV support])],
 [case $with_kerb4 in
-    no)                with_kerb4="";;
+    no)                ;;
     *)         AC_MSG_CHECKING(whether to try kerberos IV authentication)
                AC_MSG_RESULT(yes)
                AUTH_REG="$AUTH_REG kerb4"
@@ -399,7 +401,7 @@ esac])
 
 AC_ARG_WITH(kerb5, [AS_HELP_STRING([--with-kerb5[[=DIR]]], [enable Kerberos V support])],
 [case $with_kerb5 in
-    no)                with_kerb5="";;
+    no)                ;;
     *)         AC_MSG_CHECKING(whether to try Kerberos V authentication)
                AC_MSG_RESULT(yes)
                AUTH_REG="$AUTH_REG kerb5"
@@ -784,13 +786,24 @@ AS_HELP_STRING([--without-umask], [Preserves the umask of the user invoking sudo
     *)         AC_MSG_ERROR(["you must enter a numeric mask."])
                ;;
 esac])
-AC_DEFINE_UNQUOTED(SUDO_UMASK, $sudo_umask, [The umask that the root-run prog should use.])
+AC_DEFINE_UNQUOTED(SUDO_UMASK, $sudo_umask, [The umask that the sudo-run prog should use.])
 if test "$sudo_umask" = "0777"; then
     AC_MSG_RESULT(user)
 else
     AC_MSG_RESULT($sudo_umask)
 fi
 
+AC_ARG_WITH(umask-override, [AS_HELP_STRING([--with-umask-override], [Use the umask specified in sudoers even if it is less restrictive than the user's.])],
+[case $with_umask_override in
+    yes)       AC_DEFINE(UMASK_OVERRIDE)
+               umask_override=on
+               ;;
+    no)                umask_override=off
+               ;;
+    *)         AC_MSG_ERROR(["--with-umask-override does not take an argument."])
+               ;;
+esac])
+
 AC_MSG_CHECKING(for default user to run commands as)
 AC_ARG_WITH(runas-default, [AS_HELP_STRING([--with-runas-default], [User to run commands as (default is "root")])],
 [case $with_runas_default in
@@ -1256,6 +1269,27 @@ AC_ARG_ENABLE(env_debug,
   esac
 ], AC_MSG_RESULT(no))
 
+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.])],
+[ case "$enableval" in
+    yes)       env_reset=on
+               ;;
+    no)                env_reset=off
+               ;;
+    *)         env_reset=on
+               AC_MSG_WARN([Ignoring unknown argument to --enable-env-reset: $enableval])
+               ;;
+  esac
+])
+if test "$env_reset" = "on"; then
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(ENV_RESET, TRUE)
+else
+    AC_MSG_RESULT(no)
+    AC_DEFINE(ENV_RESET, FALSE)
+fi
+
 AC_ARG_ENABLE(warnings,
 [AS_HELP_STRING([--enable-warnings], [Whether to enable compiler warnings])],
 [ case "$enableval" in
@@ -1310,6 +1344,9 @@ AC_SEARCH_LIBS([strerror], [cposix])
 AC_PROG_CPP
 AC_CHECK_TOOL(AR, ar, false)
 AC_CHECK_TOOL(RANLIB, ranlib, :)
+if test X"$AR" = X"false"; then
+    AC_MSG_ERROR([the "ar" utility is required to build sudo])
+fi
 
 dnl
 dnl Libtool setup, we require libtool 2.2.6b or higher
@@ -1467,7 +1504,7 @@ case "$host" in
 
                if test -z "$GCC"; then
                    # HP-UX bundled compiler can't generate shared objects
-                   if -z "$pic_flag"; then
+                   if test "x$ac_cv_prog_cc_c89" = "xno"; then
                        with_noexec=no
                    fi
 
@@ -1519,6 +1556,8 @@ case "$host" in
                        *-*-hpux10.*)
                            shadow_funcs="getprpwnam iscomsec"
                            shadow_libs="-lsec"
+                           # HP-UX 10.20 libc has an incompatible getline
+                           ac_cv_func_getline="no"
                        ;;
                        *)
                            shadow_funcs="getspnam iscomsec"
@@ -1699,7 +1738,7 @@ case "$host" in
                    SKIP_SETREUID=yes
                    ;;
                esac
-               if test "$with_skey" = "yes"; then
+               if test "${with_skey-'no'}" = "yes"; then
                     SUDO_LIBS="${SUDO_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
@@ -1735,7 +1774,7 @@ case "$host" in
                : ${with_logincap='maybe'}
                ;;
     *-*-dragonfly*)
-               if test "$with_skey" = "yes"; then
+               if test "${with_skey-'no'}" = "yes"; then
                     SUDO_LIBS="${SUDO_LIBS} -lmd"
                fi
                CHECKSHADOW="false"
@@ -1854,7 +1893,28 @@ 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)
+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)
+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.
+dnl
+AC_SYS_LARGEFILE
+case "$host" in
+    *-*-hpux11.*)
+       AC_CACHE_CHECK([whether sys/types.h needs _XOPEN_SOURCE_EXTENDED], [sudo_cv_xopen_source_extended],
+       [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
+       #include <sys/socket.h>], [])], [sudo_cv_xopen_source_extended=no], [
+           AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#define _XOPEN_SOURCE_EXTENDED
+           AC_INCLUDES_DEFAULT
+           #include <sys/socket.h>], [])], [sudo_cv_xopen_source_extended=yes],
+           [sudo_cv_xopen_source_extended=error])
+       ])])
+       if test "$sudo_cv_xopen_source_extended" = "yes"; then
+           OSDEFS="${OSDEFS} -D_XOPEN_SOURCE_EXTENDED"
+           SUDO_DEFINE(_XOPEN_SOURCE_EXTENDED)
+       fi
+       ;;
+esac
 AC_SYS_POSIX_TERMIOS
 if test "$ac_cv_sys_posix_termios" = "yes"; then
     AC_DEFINE(HAVE_TERMIOS_H)
@@ -1912,7 +1972,7 @@ dnl
 AC_FUNC_GETGROUPS
 AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \
               strftime setrlimit initgroups getgroups fstat gettimeofday \
-              regcomp setlocale getaddrinfo setenv vhangup \
+              regcomp setlocale nl_langinfo getaddrinfo setenv \
               mbr_check_membership setrlimit64)
 AC_CHECK_FUNCS(getline, [], [
     AC_LIBOBJ(getline)
@@ -1923,7 +1983,7 @@ AC_CHECK_FUNCS(setsid, [], [
     AC_FUNC_SETPGRP
 ])
 
-AC_CHECK_FUNCS(sysctl getutid getutxid, [break])
+AC_CHECK_FUNCS(sysctl getutxid getutid, [break])
 
 AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(util.h pty.h, [break])], [
     AC_CHECK_LIB(util, openpty, [
@@ -2453,7 +2513,7 @@ fi
 dnl
 dnl extra S/Key lib and includes
 dnl
-if test ${with_skey-'no'} = "yes"; then
+if test "${with_skey-'no'}" = "yes"; then
     O_LDFLAGS="$LDFLAGS"
     if test "$with_skey" != "yes"; then
        CPPFLAGS="${CPPFLAGS} -I${with_skey}/include"
@@ -2487,7 +2547,7 @@ fi
 dnl
 dnl extra OPIE lib and includes
 dnl
-if test ${with_opie-'no'} = "yes"; then
+if test "${with_opie-'no'}" = "yes"; then
     O_LDFLAGS="$LDFLAGS"
     if test "$with_opie" != "yes"; then
        CPPFLAGS="${CPPFLAGS} -I${with_opie}/include"
@@ -2526,7 +2586,7 @@ if test ${with_passwd-'no'} != "no"; then
     dnl
     dnl if crypt(3) not in libc, look elsewhere
     dnl
-    if test -z "$LIB_CRYPT" -a "$with_passwd" != "no"; then
+    if test -z "$LIB_CRYPT"; then
        AC_SEARCH_LIBS([crypt], [crypt crypt_d ufc], [test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"])
     fi
 
@@ -2614,7 +2674,8 @@ if test ${with_ldap-'no'} != "no"; then
 
     AC_CHECK_HEADERS([sasl/sasl.h] [sasl.h], [AC_CHECK_FUNCS(ldap_sasl_interactive_bind_s)], [break])
     AC_CHECK_HEADERS([ldap_ssl.h] [mps/ldap_ssl.h], [break], [], [#include <ldap.h>])
-    AC_CHECK_FUNCS(ldap_initialize ldap_start_tls_s ldapssl_init ldapssl_set_strength ldap_search_ext_s ldap_unbind_ext_s ldap_str2dn ldap_create ldap_sasl_bind_s ldap_ssl_client_init ldap_start_tls_s_np)
+    AC_CHECK_FUNCS(ldap_initialize ldap_start_tls_s ldapssl_init ldapssl_set_strength ldap_unbind_ext_s ldap_str2dn ldap_create ldap_sasl_bind_s ldap_ssl_client_init ldap_start_tls_s_np)
+    AC_CHECK_FUNCS(ldap_search_ext_s ldap_search_st, [break])
 
     if test X"$check_gss_krb5_ccache_name" = X"yes"; then
        AC_CHECK_LIB(gssapi, gss_krb5_ccache_name,
@@ -2695,23 +2756,34 @@ if test "${with_iologdir-yes}" != "no"; then
        REPLAY=""
 
        AC_ARG_ENABLE(zlib,
-       [AS_HELP_STRING([--enable-zlib[[=PATH]]], [Whether to enable or disable zlib])],
-       [ case "$enable_zlib" in
-           yes)    AC_DEFINE(HAVE_ZLIB_H)
-                   ZLIB="-lz"
-                   ;;
-           no)     ;;
-           *)      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""; then
-           AC_CHECK_LIB(z, gzdopen, [
-               AC_CHECK_HEADERS(zlib.h, [ZLIB="-lz"])
-           ])
+       [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])
@@ -2720,11 +2792,11 @@ if test "${with_iologdir-yes}" != "no"; then
 fi
 
 dnl
-dnl Use passwd (and secureware) auth modules?
+dnl Use passwd auth module?
 dnl
 case "$with_passwd" in
 yes|maybe)
-    AUTH_OBJS="$AUTH_OBJS passwd.o"
+    AUTH_OBJS="$AUTH_OBJS getspwuid.o passwd.o"
     ;;
 *)
     AC_DEFINE(WITHOUT_PASSWD)
@@ -2734,7 +2806,7 @@ yes|maybe)
     ;;
 esac
 AUTH_OBJS=${AUTH_OBJS# }
-_AUTH=`echo "$AUTH_OBJS" | sed 's/\.o//g'`
+_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.o//g' -e 's/getspwuid *//'`
 AC_MSG_NOTICE([using the following authentication methods: $_AUTH])
 
 dnl
@@ -2826,6 +2898,7 @@ AH_TEMPLATE(CSOPS_INSULTS, [Define to 1 if you want insults culled from the twis
 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(FQDN, [Define to 1 if you want to require fully qualified hosts in sudoers.])
 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.])
@@ -2895,6 +2968,7 @@ AH_TEMPLATE(SEND_MAIL_WHEN_NO_USER, [Define to 1 to send mail when the user is n
 AH_TEMPLATE(SHELL_IF_NO_ARGS, [Define to 1 if you want sudo to start a shell if given no arguments.])
 AH_TEMPLATE(SHELL_SETS_HOME, [Define to 1 if you want sudo to set $HOME in shell mode.])
 AH_TEMPLATE(STUB_LOAD_INTERFACES, [Define to 1 if the code in interfaces.c does not compile for you.])
+AH_TEMPLATE(UMASK_OVERRIDE, [Define to 1 to use the umask specified in sudoers even when it is less restrictive than the invoking user's.])
 AH_TEMPLATE(USE_ADMIN_FLAG, [Define to 1 if you want to create ~/.sudo_as_admin_successful if the user is in the admin group the first time they run sudo.])
 AH_TEMPLATE(USE_INSULTS, [Define to 1 if you want to insult the user for entering an incorrect password.])
 AH_TEMPLATE(USE_STOW, [Define to 1 if you use GNU stow packaging.])
index fbdc0c791fca4b879ac3d7ad8d3e76c3f8aba82a..c63d59588dd10f1a67b58385f58295b7829aaca4 100644 (file)
@@ -330,6 +330,10 @@ struct sudo_defs_types sudo_defs_table[] = {
        "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
     }
index e868d3226fda1bc9423fdd527213599a7962d36d..0996ec8f59d971c35bff435af7a9b3ae4f87de79 100644 (file)
 #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,
index d903cfaee9105ec275e7d32e48de90481d4d6623..4a7ae9672bf3e642724bde10fe62d88841eeb235 100644 (file)
@@ -244,3 +244,6 @@ compress_io
 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"
index 10757eefce46e9637f4a596d58e4d99e70b3e653..c1f0afa76d66bc753467d8913ebddbb52154f321 100644 (file)
@@ -229,7 +229,7 @@ set_default(var, val, op)
     }
     if (!cur->name) {
        warningx("unknown defaults entry `%s'", var);
-       return(FALSE);
+       return FALSE;
     }
 
     switch (cur->type & T_MASK) {
@@ -239,7 +239,7 @@ set_default(var, val, op)
                    warningx("value `%s' is invalid for option `%s'", val, var);
                else
                    warningx("no value specified for `%s'", var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_LOGPRI:
@@ -248,7 +248,7 @@ set_default(var, val, op)
                    warningx("value `%s' is invalid for option `%s'", val, var);
                else
                    warningx("no value specified for `%s'", var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_STR:
@@ -256,16 +256,16 @@ set_default(var, val, op)
                /* 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);
+                   return FALSE;
                }
            }
            if (ISSET(cur->type, T_PATH) && val && *val != '/') {
                warningx("values for `%s' must start with a '/'", var);
-               return(FALSE);
+               return FALSE;
            }
            if (!store_str(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_INT:
@@ -273,12 +273,12 @@ set_default(var, val, op)
                /* 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);
+                   return FALSE;
                }
            }
            if (!store_int(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_UINT:
@@ -286,12 +286,12 @@ set_default(var, val, op)
                /* 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);
+                   return FALSE;
                }
            }
            if (!store_uint(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_FLOAT:
@@ -299,12 +299,12 @@ set_default(var, val, op)
                /* 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);
+                   return FALSE;
                }
            }
            if (!store_float(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_MODE:
@@ -312,18 +312,18 @@ set_default(var, val, op)
                /* 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);
+                   return FALSE;
                }
            }
            if (!store_mode(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_FLAG:
            if (val) {
                warningx("option `%s' does not take a value", var);
-               return(FALSE);
+               return FALSE;
            }
            cur->sd_un.flag = op;
            break;
@@ -332,27 +332,27 @@ set_default(var, val, op)
                /* 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);
+                   return FALSE;
                }
            }
            if (!store_list(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
        case T_TUPLE:
            if (!val && !ISSET(cur->type, T_BOOL)) {
                warningx("no value specified for `%s'", var);
-               return(FALSE);
+               return FALSE;
            }
            if (!store_tuple(val, cur, op)) {
                warningx("value `%s' is invalid for option `%s'", val, var);
-               return(FALSE);
+               return FALSE;
            }
            break;
     }
 
-    return(TRUE);
+    return TRUE;
 }
 
 /*
@@ -433,11 +433,15 @@ init_defaults()
 #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 = TRUE;
+    def_env_reset = ENV_RESET;
     def_set_logname = TRUE;
     def_closefrom = STDERR_FILENO + 1;
 
@@ -543,7 +547,7 @@ update_defaults(what)
                break;
        }
     }
-    return(rc);
+    return rc;
 }
 
 static int
@@ -560,13 +564,13 @@ store_int(val, def, op)
     } else {
        l = strtol(val, &endp, 10);
        if (*endp != '\0')
-           return(FALSE);
+           return FALSE;
        /* XXX - should check against INT_MAX */
        def->sd_un.ival = (int)l;
     }
     if (def->callback)
-       return(def->callback(val));
-    return(TRUE);
+       return def->callback(val);
+    return TRUE;
 }
 
 static int
@@ -583,13 +587,13 @@ store_uint(val, def, op)
     } else {
        l = strtol(val, &endp, 10);
        if (*endp != '\0' || l < 0)
-           return(FALSE);
+           return FALSE;
        /* XXX - should check against INT_MAX */
        def->sd_un.ival = (unsigned int)l;
     }
     if (def->callback)
-       return(def->callback(val));
-    return(TRUE);
+       return def->callback(val);
+    return TRUE;
 }
 
 static int
@@ -606,13 +610,13 @@ store_float(val, def, op)
     } else {
        d = strtod(val, &endp);
        if (*endp != '\0')
-           return(FALSE);
+           return FALSE;
        /* XXX - should check against HUGE_VAL */
        def->sd_un.fval = d;
     }
     if (def->callback)
-       return(def->callback(val));
-    return(TRUE);
+       return def->callback(val);
+    return TRUE;
 }
 
 static int
@@ -640,11 +644,11 @@ store_tuple(val, def, op)
            }
        }
        if (v->sval == NULL)
-           return(FALSE);
+           return FALSE;
     }
     if (def->callback)
-       return(def->callback(val));
-    return(TRUE);
+       return def->callback(val);
+    return TRUE;
 }
 
 static int
@@ -660,8 +664,8 @@ store_str(val, def, op)
     else
        def->sd_un.str = estrdup(val);
     if (def->callback)
-       return(def->callback(val));
-    return(TRUE);
+       return def->callback(val);
+    return TRUE;
 }
 
 static int
@@ -681,18 +685,18 @@ store_list(str, def, op)
        end = str;
        do {
            /* Remove leading blanks, if nothing but blanks we are done. */
-           for (start = end; isblank(*start); start++)
+           for (start = end; isblank((unsigned char)*start); start++)
                ;
            if (*start == '\0')
                break;
 
            /* Find end position and perform operation. */
-           for (end = start; *end && !isblank(*end); end++)
+           for (end = start; *end && !isblank((unsigned char)*end); end++)
                ;
            list_op(start, end - start, def, op == '-' ? delete : add);
        } while (*end++ != '\0');
     }
-    return(TRUE);
+    return TRUE;
 }
 
 static int
@@ -705,21 +709,21 @@ store_syslogfac(val, def, op)
 
     if (op == FALSE) {
        def->sd_un.ival = FALSE;
-       return(TRUE);
+       return TRUE;
     }
 #ifdef LOG_NFACILITIES
     if (!val)
-       return(FALSE);
+       return FALSE;
     for (fac = facilities; fac->name && strcmp(val, fac->name); fac++)
        ;
     if (fac->name == NULL)
-       return(FALSE);                          /* not found */
+       return FALSE;                           /* not found */
 
     def->sd_un.ival = fac->num;
 #else
     def->sd_un.ival = -1;
 #endif /* LOG_NFACILITIES */
-    return(TRUE);
+    return TRUE;
 }
 
 static const char *
@@ -731,9 +735,9 @@ logfac2str(n)
 
     for (fac = facilities; fac->name && fac->num != n; fac++)
        ;
-    return(fac->name);
+    return fac->name;
 #else
-    return("default");
+    return "default";
 #endif /* LOG_NFACILITIES */
 }
 
@@ -746,15 +750,15 @@ store_syslogpri(val, def, op)
     struct strmap *pri;
 
     if (op == FALSE || !val)
-       return(FALSE);
+       return FALSE;
 
     for (pri = priorities; pri->name && strcmp(val, pri->name); pri++)
        ;
     if (pri->name == NULL)
-       return(FALSE);                          /* not found */
+       return FALSE;                           /* not found */
 
     def->sd_un.ival = pri->num;
-    return(TRUE);
+    return TRUE;
 }
 
 static const char *
@@ -765,7 +769,7 @@ logpri2str(n)
 
     for (pri = priorities; pri->name && pri->num != n; pri++)
        ;
-    return(pri->name);
+    return pri->name;
 }
 
 static int
@@ -782,12 +786,12 @@ store_mode(val, def, op)
     } else {
        l = strtol(val, &endp, 8);
        if (*endp != '\0' || l < 0 || l > 0777)
-           return(FALSE);
+           return FALSE;
        def->sd_un.mode = (mode_t)l;
     }
     if (def->callback)
-       return(def->callback(val));
-    return(TRUE);
+       return def->callback(val);
+    return TRUE;
 }
 
 static void
diff --git a/env.c b/env.c
index 739631fd736bed8aac91c80b34ed4afb0978f44b..654565edc36d5da2ebb7ebc53d953f1d27dd4e83 100644 (file)
--- a/env.c
+++ b/env.c
@@ -205,6 +205,9 @@ static const char *initial_keepenv_table[] = {
     "TZ",
     "XAUTHORITY",
     "XAUTHORIZATION",
+#ifdef _AIX
+    "ODMDIR",
+#endif
     NULL
 };
 
@@ -311,7 +314,7 @@ setenv(var, val, overwrite)
 
     if (!var || *var == '\0') {
        errno = EINVAL;
-       return(-1);
+       return -1;
     }
 
     if (env.envp == NULL)
@@ -344,7 +347,7 @@ setenv(var, val, overwrite)
        errorx(1, "setenv: corrupted envp, len mismatch");
 #endif
     sudo_putenv(estring, TRUE, overwrite);
-    return(0);
+    return 0;
 }
 
 /*
@@ -366,7 +369,7 @@ unsetenv(var)
 #ifdef UNSETENV_VOID
        return;
 #else
-       return(-1);
+       return -1;
 #endif
     }
 
@@ -392,7 +395,7 @@ unsetenv(var)
     }
     env.env_len = ep - env.envp;
 #ifndef UNSETENV_VOID
-    return(0);
+    return 0;
 #endif
 }
 
@@ -412,14 +415,14 @@ putenv(string)
 
     if (strchr(string, '=') == NULL) {
        errno = EINVAL;
-       return(-1);
+       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);
+    return 0;
 }
 
 /*
@@ -520,7 +523,7 @@ matches_env_delete(var)
            break;
        }
     }
-    return(match);
+    return match;
 }
 
 /*
@@ -550,7 +553,7 @@ matches_env_check(var)
            break;
        }
     }
-    return(keepit);
+    return keepit;
 }
 
 /*
@@ -579,7 +582,7 @@ matches_env_keep(var)
            break;
        }
     }
-    return(keepit);
+    return keepit;
 }
 
 /*
@@ -608,10 +611,16 @@ rebuild_env(noexec)
 #ifdef ENV_DEBUG
     memset(env.envp, 0, env.env_size * sizeof(char *));
 #endif
-    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
-       /* Reset HOME based on target user unless keeping old value. */
-       reset_home = TRUE;
 
+    /* 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;
@@ -696,6 +705,11 @@ rebuild_env(noexec)
            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.
@@ -709,13 +723,6 @@ rebuild_env(noexec)
            sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
        }
     } else {
-       /* 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) || 
-               (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
-               reset_home = TRUE;
-       }
-
        /*
         * Copy environ entries as long as they don't match env_delete or
         * env_check.
@@ -765,7 +772,7 @@ rebuild_env(noexec)
     }
 
     /* Set $HOME to target user if not preserving user's value. */
-    if (reset_home && !ISSET(didvar, KEPT_HOME))
+    if (reset_home)
        sudo_setenv("HOME", runas_pw->pw_dir, TRUE);
 
     /* Provide default values for $TERM and $PATH if they are not set. */
@@ -813,9 +820,9 @@ rebuild_env(noexec)
 
     /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
     sudo_setenv("SUDO_USER", user_name, TRUE);
-    snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid);
+    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
     sudo_setenv("SUDO_UID", idbuf, TRUE);
-    snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid);
+    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
     sudo_setenv("SUDO_GID", idbuf, TRUE);
 
     /* Free old environment. */
diff --git a/error.c b/error.c
index 317f10561cbecfba55bfd6c2eee842a3ae688da9..e5cb959713b76e149c3580d7a01faa3ae20fe450 100644 (file)
--- a/error.c
+++ b/error.c
  * 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 <config.h>
-#include <compat.h>
+#include "missing.h"
 #include "error.h"
 
 static void _warning   __P((int, const char *, va_list));
diff --git a/exec.c b/exec.c
index 784f90ab40ff80020dc18f2ea12105076042b5c9..19dbad2e4dca52f116c0a32406a9b37e11505af6 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -18,6 +18,9 @@
 
 #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 "sudo.h"
 #include "sudo_exec.h"
 
-/* shared with exec_pty.c */
-sig_atomic_t recvsig[NSIG];
-void handler __P((int s));
+/* 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
@@ -102,7 +120,7 @@ static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
 {
     struct command_status cstat;
     sigaction_t sa;
-    int pid;
+    pid_t child;
 
     zero_bytes(&sa, sizeof(sa));
     sigemptyset(&sa.sa_mask);
@@ -110,15 +128,18 @@ static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
     sa.sa_handler = handler;
     sigaction(SIGCONT, &sa, NULL);
 
-    pid = fork();
-    switch (pid) {
+    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);
@@ -134,7 +155,51 @@ static int fork_cmnd(path, argv, envp, sv, rbac_enabled)
        send(sv[1], &cstat, sizeof(cstat), 0);
        _exit(1);
     }
-    return pid;
+    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);
 }
 
 /*
@@ -152,11 +217,10 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
     int dowait;
     int bgmode;
 {
-    sigaction_t sa;
-    fd_set *fdsr, *fdsw;
-    int maxfd, n, nready, status, sv[2];
+    int maxfd, n, nready, sv[2];
     int rbac_enabled = 0;
-    int log_io;
+    fd_set *fdsr, *fdsw;
+    sigaction_t sa;
     pid_t child;
 
     /* If running in background mode, fork and exit. */
@@ -200,31 +264,44 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
        my_execve(path, argv, envp);
        cstat->type = CMD_ERRNO;
        cstat->val = errno;
-       return(127);
+       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) != 0)
+    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);
 
-    /* Note: HP-UX select() will not be interrupted if SA_RESTART set */
+    /*
+     * 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 = sv[0];
+    maxfd = MAX(sv[0], signal_pipe[0]);
 
     /*
      * Child will run the command in the pty, parent will pass data
@@ -253,72 +330,48 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
     fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
     fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
     for (;;) {
-       if (recvsig[SIGCHLD]) {
-           pid_t pid;
-
-           /*
-            * If logging I/O, child is the intermediate process,
-            * otherwise it is the command itself.
-            */
-           recvsig[SIGCHLD] = FALSE;
-           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. */
-               if (!log_io) {
-                   if (WIFSTOPPED(status)) {
-                       /* Child may not have privs to suspend us itself. */
-                       kill(getpid(), WSTOPSIG(status));
-                   } 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. */
-           }
-       }
-
        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
-       for (n = 0; n < NSIG; n++) {
-           if (recvsig[n] && n != SIGCHLD) {
-               if (log_io) {
-                   FD_SET(sv[0], fdsw);
-                   break;
-               } else {
-                   /* nothing listening on sv[0], send directly */
-                   kill(child, n);
-               }
-           }
-       }
-
-       if (recvsig[SIGCHLD])
-           continue;
        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.
@@ -328,13 +381,14 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
                    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));
-                   recvsig[n] = TRUE;
+                   schedule_signal(n);
                    continue;
                } else {
                    /* Child exited or was killed, either way we are done. */
@@ -349,25 +403,12 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
        }
 
 #ifdef _PATH_SUDO_IO_LOGDIR
-       /* XXX - move this too */
-       if (FD_ISSET(sv[0], fdsw)) {
-           for (n = 0; n < NSIG; n++) {
-               if (!recvsig[n])
-                   continue;
-               recvsig[n] = FALSE;
-               cstat->type = CMD_SIGNO;
-               cstat->val = n;
-               do {
-                   n = send(sv[0], cstat, sizeof(*cstat), 0);
-               } while (n == -1 && errno == EINTR);
-               if (n != sizeof(*cstat)) {
-                   recvsig[n] = TRUE;
-                   break;
-               }
-           }
-       }
-       if (perform_io(fdsr, fdsw, cstat) != 0)
+       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 */
     }
 
@@ -386,19 +427,211 @@ sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode)
     }
 #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 recvsig[] array is checked in the main event loop.
+ * The other end of signal_pipe is checked in the main event loop.
  */
-void
+RETSIGTYPE
 handler(s)
     int s;
 {
-    recvsig[s] = TRUE;
+    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;
 }
index 2d6b0e83de8e3b428601007975a78794b5e08349..ec54a1f45deba16c5b157376df90d95bdbc1409c 100644 (file)
@@ -18,6 +18,9 @@
 
 #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>
 #define TERM_RAW       1
 
 /* Compatibility with older tty systems. */
-#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
-# define TIOCGSIZE     TIOCGWINSZ
-# define TIOCSSIZE     TIOCSWINSZ
-# define ttysize       winsize
-# define ts_cols       ws_col
+#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
+# define TIOCGWINSZ    TIOCGSIZE
+# define TIOCSWINSZ    TIOCSSIZE
+# define winsize       ttysize
 #endif
 
 struct io_buffer {
@@ -95,7 +97,7 @@ 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;
+static pid_t ppgrp, child, child_pgrp;
 static struct io_buffer *iobufs;
 
 static void flush_output __P((void));
@@ -103,7 +105,7 @@ 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 void sigwinch __P((int s));
+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));
@@ -146,7 +148,8 @@ check_foreground()
 
 /*
  * Suspend sudo if the underlying command is suspended.
- * Returns SIGUSR1 if the child should be resume in foreground else SIGUSR2.
+ * 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)
@@ -171,7 +174,7 @@ suspend_parent(signo)
                } while (!n && errno == EINTR);
                ttymode = TERM_RAW;
            }
-           rval = SIGUSR1; /* resume child in foreground */
+           rval = SIGCONT_FG; /* resume child in foreground */
            break;
        }
        ttymode = TERM_RAW;
@@ -214,11 +217,11 @@ suspend_parent(signo)
        }
 
        sigaction(signo, &osa, NULL);
-       rval = ttymode == TERM_RAW ? SIGUSR1 : SIGUSR2;
+       rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG;
        break;
     }
 
-    return(rval);
+    return rval;
 }
 
 /*
@@ -448,6 +451,8 @@ fork_pty(path, argv, envp, sv, rbac_enabled, maxfd)
     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. */
@@ -525,10 +530,14 @@ pty_close(cstat)
            const char *reason = strsignal(signo);
            n = io_fds[SFD_USERTTY] != -1 ?
                io_fds[SFD_USERTTY] : STDOUT_FILENO;
-           write(n, reason, strlen(reason));
-           if (WCOREDUMP(cstat->val))
-               write(n, " (core dumped)", 14);
-           write(n, "\n", 1);
+           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 */;
+           }
        }
     }
 }
@@ -582,37 +591,26 @@ deliver_signal(pid, signo)
 
     /* Handle signal from parent. */
     switch (signo) {
-    case SIGKILL:
-       _exit(1); /* XXX */
-       /* NOTREACHED */
-    case SIGPIPE:
-    case SIGHUP:
-    case SIGTERM:
-    case SIGINT:
-    case SIGQUIT:
-    case SIGTSTP:
-       /* relay signal to child */
-       killpg(pid, signo);
-       break;
-    case SIGALRM:
-       terminate_child(pid, TRUE);
-       break;
-    case SIGUSR1:
-       /* foreground process, grant it controlling tty. */
+    case SIGCONT_FG:
+       /* Continue in foreground, grant it controlling tty. */
        do {
-           status = tcsetpgrp(io_fds[SFD_SLAVE], pid);
+           status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp);
        } while (status == -1 && errno == EINTR);
        killpg(pid, SIGCONT);
        break;
-    case SIGUSR2:
-       /* background process, I take controlling tty. */
+    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:
-       warningx("unexpected signal from child: %d", signo);
+       /* Relay signal to child. */
+       killpg(pid, signo);
        break;
     }
 }
@@ -664,6 +662,9 @@ handle_sigchld(backchannel, cstat)
            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 */
            }
@@ -695,6 +696,7 @@ exec_monitor(path, argv, envp, backchannel, rbac)
     sigaction_t sa;
     int errpipe[2], maxfd, n, status;
     int alive = TRUE;
+    unsigned char signo;
 
     /* Close unused fds. */
     if (io_fds[SFD_MASTER] != -1)
@@ -702,13 +704,19 @@ exec_monitor(path, argv, envp, backchannel, rbac)
     if (io_fds[SFD_USERTTY] != -1)
        close(io_fds[SFD_USERTTY]);
 
-    /* Reset SIGWINCH and SIGALRM. */
+    /*
+     * 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);
-    sigaction(SIGALRM, &sa, NULL);
 
     /* Ignore any SIGTTIN or SIGTTOU we get. */
     sa.sa_handler = SIG_IGN;
@@ -760,14 +768,18 @@ exec_monitor(path, argv, envp, backchannel, rbac)
     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;
-       write(errpipe[1], &cstat, sizeof(cstat));
+       if (write(errpipe[1], &cstat, sizeof(cstat)) == -1)
+           /* shut up glibc */;
        _exit(1);
     }
     close(errpipe[1]);
@@ -784,35 +796,29 @@ exec_monitor(path, argv, envp, backchannel, rbac)
      * Put child in its own process group.  If we are starting the command
      * in the foreground, assign its pgrp to the tty.
      */
-    setpgid(child, child);
+    child_pgrp = child;
+    setpgid(child, child_pgrp);
     if (foreground) {
        do {
-           status = tcsetpgrp(io_fds[SFD_SLAVE], child);
+           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(errpipe[0], backchannel);
+    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 (;;) {
-       /* Read child status. */
-       if (recvsig[SIGCHLD]) {
-           recvsig[SIGCHLD] = FALSE;
-           alive = handle_sigchld(backchannel, &cstat);
-       }
-
        /* 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(errpipe[0], backchannel);
+       maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel);
 
-       if (recvsig[SIGCHLD])
-           continue;
        /* 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) {
@@ -823,6 +829,24 @@ exec_monitor(path, argv, envp, backchannel, rbac)
            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));
@@ -954,25 +978,8 @@ exec_pty(path, argv, envp, rbac_enabled)
     char *envp[];
     int rbac_enabled;
 {
-    sigaction_t sa;
     pid_t self = getpid();
 
-    /* Reset signal handlers. */
-    zero_bytes(&sa, sizeof(sa));
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_RESTART;
-    sa.sa_handler = SIG_DFL;
-    sigaction(SIGHUP, &sa, NULL);
-    sigaction(SIGTERM, &sa, NULL);
-    sigaction(SIGINT, &sa, NULL);
-    sigaction(SIGQUIT, &sa, NULL);
-    sigaction(SIGTSTP, &sa, NULL);
-    sigaction(SIGTTIN, &sa, NULL);
-    sigaction(SIGTTOU, &sa, NULL);
-    sigaction(SIGUSR1, &sa, NULL);
-    sigaction(SIGUSR2, &sa, NULL);
-    sigaction(SIGCHLD, &sa, NULL);
-
     /* Set child process group here too to avoid a race. */
     setpgid(0, self);
 
@@ -1015,12 +1022,12 @@ sync_ttysize(src, dst)
     int src;
     int dst;
 {
-#ifdef TIOCGSIZE
-    struct ttysize tsize;
+#ifdef TIOCGWINSZ
+    struct winsize wsize;
     pid_t pgrp;
 
-    if (ioctl(src, TIOCGSIZE, &tsize) == 0) {
-           ioctl(dst, TIOCSSIZE, &tsize);
+    if (ioctl(src, TIOCGWINSZ, &wsize) == 0) {
+           ioctl(dst, TIOCSWINSZ, &wsize);
            if ((pgrp = tcgetpgrp(dst)) != -1)
                killpg(pgrp, SIGWINCH);
     }
index ca4903fe0987aef66da165e446573ebbcd0c67d3..ae9a7df135c6d48da8b0ebc0b96722f425f57466 100644 (file)
--- a/fileops.c
+++ b/fileops.c
@@ -44,7 +44,7 @@
 # include <time.h>
 #endif
 #ifndef HAVE_TIMESPEC
-# include <emul/timespec.h>
+# include "emul/timespec.h"
 #endif
 
 #include "sudo.h"
@@ -71,13 +71,13 @@ touch(fd, path, tvp)
 
 #if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES)
     if (fd != -1)
-       return(futimes(fd, tvp ? times : NULL));
+       return futimes(fd, tvp ? times : NULL);
     else
 #endif
     if (path != NULL)
-       return(utimes(path, tvp ? times : NULL));
+       return utimes(path, tvp ? times : NULL);
     else
-       return(-1);
+       return -1;
 }
 
 /*
@@ -102,7 +102,7 @@ lock_file(fd, lockit)
            op = F_ULOCK;
            break;
     }
-    return(lockf(fd, op, 0) == 0);
+    return lockf(fd, op, 0) == 0;
 }
 #elif HAVE_FLOCK
 int
@@ -123,7 +123,7 @@ lock_file(fd, lockit)
            op = LOCK_UN;
            break;
     }
-    return(flock(fd, op) == 0);
+    return flock(fd, op) == 0;
 }
 #else
 int
@@ -142,9 +142,9 @@ lock_file(fd, lockit)
     lock.l_whence = SEEK_SET;
     func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK;
 
-    return(fcntl(fd, func, &lock) == 0);
+    return fcntl(fd, func, &lock) == 0;
 #else
-    return(TRUE);
+    return TRUE;
 #endif
 }
 #endif
@@ -170,8 +170,8 @@ sudo_parseln(fp)
        len = strlen(buf);
        while (len > 0 && isspace((unsigned char)buf[len - 1]))
            buf[--len] = '\0';
-       for (cp = buf; isblank(*cp); cp++)
+       for (cp = buf; isblank((unsigned char)*cp); cp++)
            continue;
     }
-    return(cp);
+    return cp;
 }
index 78c96eaa72ec532c7327bb85abab54bd85c806a4..fb7fb5f86cb23f88935fabc9328a1438144899cd 100644 (file)
@@ -78,13 +78,13 @@ find_path(infile, outfile, sbp, path, ignore_dot)
        strlcpy(command, infile, sizeof(command));      /* paranoia */
        if (sudo_goodpath(command, sbp)) {
            *outfile = command;
-           return(FOUND);
+           return FOUND;
        } else
-           return(NOT_FOUND);
+           return NOT_FOUND;
     }
 
     if (path == NULL)
-       return(NOT_FOUND);
+       return NOT_FOUND;
     path = estrdup(path);
     origpath = path;
 
@@ -125,12 +125,12 @@ find_path(infile, outfile, sbp, path, ignore_dot)
            errorx(1, "%s: File name too long", infile);
        result = sudo_goodpath(command, sbp);
        if (result && ignore_dot)
-           return(NOT_FOUND_DOT);
+           return NOT_FOUND_DOT;
     }
 
     if (result) {
        *outfile = result;
-       return(FOUND);
+       return FOUND;
     } else
-       return(NOT_FOUND);
+       return NOT_FOUND;
 }
index 2255e521444a4bddb561bd3e162133296cae5ac0..723e53d7d706b17402f46e1330e497d60cca55b1 100644 (file)
--- a/fnmatch.c
+++ b/fnmatch.c
@@ -38,6 +38,8 @@
 
 #include <config.h>
 
+#include <sys/types.h>
+
 #include <stdio.h>
 #include <ctype.h>
 #ifdef HAVE_STRING_H
@@ -47,7 +49,7 @@
 # include <strings.h>
 #endif /* HAVE_STRINGS_H */
 
-#include <compat.h>
+#include "missing.h"
 #include "emul/fnmatch.h"
 #include "emul/charclass.h"
 
@@ -78,17 +80,17 @@ fnmatch(pattern, string, flags)
                switch (c = *pattern++) {
                case EOS:
                        if (ISSET(flags, FNM_LEADING_DIR) && *string == '/')
-                               return (0);
-                       return (*string == EOS ? 0 : FNM_NOMATCH);
+                               return 0;
+                       return *string == EOS ? 0 : FNM_NOMATCH;
                case '?':
                        if (*string == EOS)
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        if (*string == '/' && ISSET(flags, FNM_PATHNAME))
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
                            (string == stringstart ||
                            (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        ++string;
                        break;
                case '*':
@@ -100,40 +102,40 @@ fnmatch(pattern, string, flags)
                        if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
                            (string == stringstart ||
                            (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
-                               return (FNM_NOMATCH);
+                               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) ||
+                                       return ISSET(flags, FNM_LEADING_DIR) ||
                                            strchr(string, '/') == NULL ?
-                                           0 : FNM_NOMATCH);
+                                           0 : FNM_NOMATCH;
                                else
-                                       return (0);
+                                       return 0;
                        } else if (c == '/' && ISSET(flags, FNM_PATHNAME)) {
                                if ((string = strchr(string, '/')) == NULL)
-                                       return (FNM_NOMATCH);
+                                       return FNM_NOMATCH;
                                break;
                        }
 
                        /* General case, use recursion. */
                        while ((test = *string) != EOS) {
                                if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
-                                       return (0);
+                                       return 0;
                                if (test == '/' && ISSET(flags, FNM_PATHNAME))
                                        break;
                                ++string;
                        }
-                       return (FNM_NOMATCH);
+                       return FNM_NOMATCH;
                case '[':
                        if (*string == EOS)
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        if (*string == '/' && ISSET(flags, FNM_PATHNAME))
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
                            (string == stringstart ||
                            (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
 
                        switch (rangematch(pattern, *string, flags, &newp)) {
                        case RANGE_ERROR:
@@ -143,7 +145,7 @@ fnmatch(pattern, string, flags)
                                pattern = newp;
                                break;
                        case RANGE_NOMATCH:
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        }
                        ++string;
                        break;
@@ -160,7 +162,7 @@ fnmatch(pattern, string, flags)
                        if (c != *string && !(ISSET(flags, FNM_CASEFOLD) &&
                                 (tolower((unsigned char)c) ==
                                 tolower((unsigned char)*string))))
-                               return (FNM_NOMATCH);
+                               return FNM_NOMATCH;
                        ++string;
                        break;
                }
@@ -216,9 +218,9 @@ rangematch(pattern, test, flags, newp)
                if (c == '\\' && !ISSET(flags, FNM_NOESCAPE))
                        c = *pattern++;
                if (c == EOS)
-                       return (RANGE_ERROR);
+                       return RANGE_ERROR;
                if (c == '/' && ISSET(flags, FNM_PATHNAME))
-                       return (RANGE_NOMATCH);
+                       return RANGE_NOMATCH;
                if (ISSET(flags, FNM_CASEFOLD))
                        c = tolower((unsigned char)c);
                if (*pattern == '-'
@@ -227,7 +229,7 @@ rangematch(pattern, test, flags, newp)
                        if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE))
                                c2 = *pattern++;
                        if (c2 == EOS)
-                               return (RANGE_ERROR);
+                               return RANGE_ERROR;
                        if (ISSET(flags, FNM_CASEFOLD))
                                c2 = tolower((unsigned char)c2);
                        if (c <= test && test <= c2)
@@ -237,7 +239,7 @@ rangematch(pattern, test, flags, newp)
        } while ((c = *pattern++) != ']');
 
        *newp = (char *)pattern;
-       return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
+       return ok == negate ? RANGE_NOMATCH : RANGE_MATCH;
 }
 
 static int
@@ -258,7 +260,7 @@ classmatch(pattern, test, foldcase, ep)
 
        if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') {
                *ep = pattern - 2;
-               return(RANGE_ERROR);
+               return RANGE_ERROR;
        }
        *ep = colon + 2;
        len = (size_t)(colon - pattern);
@@ -277,5 +279,5 @@ classmatch(pattern, test, foldcase, ep)
                *ep = colon + strlen(colon);
                rval = RANGE_ERROR;
        }
-       return(rval);
+       return rval;
 }
index 7b35108234256b35972978c42a86cc4fdbb59aca..854979428b8bb10f30a6e4f48820ddc82264251e 100644 (file)
--- a/get_pty.c
+++ b/get_pty.c
@@ -67,13 +67,16 @@ get_pty(master, slave, name, namesz, ttyuid)
     struct group *gr;
     gid_t ttygid = -1;
 
-    if ((gr = sudo_getgrnam("tty")) != NULL)
+    if ((gr = sudo_getgrnam("tty")) != NULL) {
        ttygid = gr->gr_gid;
+       gr_delref(gr);
+    }
 
     if (openpty(master, slave, name, NULL, NULL) != 0)
-       return(0);
-    (void) chown(name, ttyuid, ttygid);
-    return(1);
+       return 0;
+    if (chown(name, ttyuid, ttygid) != 0)
+       return 0;
+    return 1;
 }
 
 #elif defined(HAVE__GETPTY)
@@ -90,15 +93,15 @@ get_pty(master, slave, name, namesz, ttyuid)
     /* IRIX-style dynamic ptys (may fork) */
     line = _getpty(master, O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP, 0);
     if (line == NULL)
-       return (0);
+       return 0;
     *slave = open(line, O_RDWR|O_NOCTTY, 0);
     if (*slave == -1) {
        close(*master);
-       return(0);
+       return 0;
     }
     (void) chown(line, ttyuid, -1);
     strlcpy(name, line, namesz);
-    return(1);
+    return 1;
 }
 #elif defined(HAVE_GRANTPT)
 # ifndef HAVE_POSIX_OPENPT
@@ -113,7 +116,7 @@ posix_openpt(oflag)
 #  else
     fd = open("/dev/ptmx", oflag);
 #  endif
-    return(fd);
+    return fd;
 }
 # endif /* HAVE_POSIX_OPENPT */
 
@@ -129,22 +132,22 @@ get_pty(master, slave, name, namesz, ttyuid)
 
     *master = posix_openpt(O_RDWR|O_NOCTTY);
     if (*master == -1)
-       return(0);
+       return 0;
 
     (void) grantpt(*master); /* may fork */
     if (unlockpt(*master) != 0) {
        close(*master);
-       return(0);
+       return 0;
     }
     line = ptsname(*master);
     if (line == NULL) {
        close(*master);
-       return(0);
+       return 0;
     }
     *slave = open(line, O_RDWR|O_NOCTTY, 0);
     if (*slave == -1) {
        close(*master);
-       return(0);
+       return 0;
     }
 # if defined(I_PUSH) && !defined(_AIX)
     ioctl(*slave, I_PUSH, "ptem");     /* pseudo tty emulation module */
@@ -152,7 +155,7 @@ get_pty(master, slave, name, namesz, ttyuid)
 # endif
     (void) chown(line, ttyuid, -1);
     strlcpy(name, line, namesz);
-    return(1);
+    return 1;
 }
 
 #else /* Old-style BSD ptys */
@@ -181,7 +184,7 @@ get_pty(master, slave, name, namesz, ttyuid)
            *master = open(line, O_RDWR|O_NOCTTY, 0);
            if (*master == -1) {
                if (errno == ENOENT)
-                   return(0); /* out of ptys */
+                   return 0; /* out of ptys */
                continue; /* already in use */
            }
            line[sizeof("/dev/p") - 2] = 't';
@@ -193,11 +196,11 @@ get_pty(master, slave, name, namesz, ttyuid)
            *slave = open(line, O_RDWR|O_NOCTTY, 0);
            if (*slave != -1) {
                    strlcpy(name, line, namesz);
-                   return(1); /* success */
+                   return 1; /* success */
            }
            (void) close(*master);
        }
     }
-    return(0);
+    return 0;
 }
 #endif /* HAVE_OPENPTY */
index 109794ae8174cba1462435c729a7d1bd2defbc3d..1260ad46f14678d5faf4ac31eec2471b2a2b3765 100644 (file)
--- a/getcwd.c
+++ b/getcwd.c
@@ -71,7 +71,7 @@
 # endif
 #endif
 
-#include <compat.h>
+#include "missing.h"
 
 #define        ISDOT(dp) \
        (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
@@ -104,12 +104,12 @@ getcwd(pt, size)
                ptsize = 0;
                if (!size) {
                        errno = EINVAL;
-                       return (NULL);
+                       return NULL;
                }
                ept = pt + size;
        } else {
                if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
-                       return (NULL);
+                       return NULL;
                ept = pt + ptsize;
        }
        bpt = ept - 1;
@@ -154,7 +154,7 @@ getcwd(pt, size)
                         */
                        bcopy(bpt, pt, ept - bpt);
                        free(up);
-                       return (pt);
+                       return pt;
                }
 
                /*
@@ -262,5 +262,5 @@ err:
                free(up);
        if (dir)
                (void)closedir(dir);
-       return (NULL);
+       return NULL;
 }
index 928246b883fa285770ea18e98ddb8f53032e6ca2..7544c3f712d440d18709b23a3c5c3f1640e711ad 100644 (file)
--- a/getdate.c
+++ b/getdate.c
@@ -1,3 +1,4 @@
+#include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #define YYBYACC 1
@@ -50,7 +51,7 @@
 #endif
 #include <ctype.h>
 
-#include "compat.h"
+#include "missing.h"
 
 
 #define EPOCH          1970
index 2b2e3c9b365edaff8f2c4cfef44f10a93bcb67dc..709408319f5c32298022e0033b5c47d9c4596ed8 100644 (file)
--- a/getdate.y
+++ b/getdate.y
@@ -39,7 +39,7 @@
 #endif
 #include <ctype.h>
 
-#include "compat.h"
+#include "missing.h"
 
 
 #define EPOCH          1970
index b7db37973d59cb7a18ef9ca4465f519d35574b8a..2b3d32464f5925fec9b3e9433f9a235629a1528f 100644 (file)
--- a/getline.c
+++ b/getline.c
@@ -35,7 +35,7 @@
 #endif /* HAVE_STRINGS_H */
 #include <limits.h>
 
-#include "compat.h"
+#include "missing.h"
 #include "alloc.h"
 
 #ifndef LINE_MAX
@@ -64,7 +64,7 @@ getline(bufp, bufsizep, fp)
        memcpy(*bufp, buf, len);
        (*bufp)[len] = '\0';
     }
-    return(buf ? len : -1);
+    return buf ? len : -1;
 }
 #else
 ssize_t
@@ -97,6 +97,6 @@ getline(bufp, bufsizep, fp)
     }
     *bufp = buf;
     *bufsizep = bufsize;
-    return(len);
+    return len;
 }
 #endif
index f269405d0cdb271031de0e5e4565d29ea39b2e3f..0790222d7ea7d7951460c97d6a69f763454346b1 100644 (file)
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
+#include <config.h>
+
+#include <sys/types.h>
+
 #include <stdio.h>
 #include <string.h>
 
-#include <config.h>
-#include <compat.h>
+#include "missing.h"
 
 const char *
 getprogname()
@@ -39,5 +42,5 @@ getprogname()
        else
            progname = Argv[0];
     }
-    return(progname);
+    return progname;
 }
index 7ee5ebaf8a8c2e0d5cd3753e49055f494628724a..7a7ffb854ea0ad25a33dd05e9f60248f917fc533 100644 (file)
@@ -82,19 +82,18 @@ char *
 sudo_getepw(pw)
     const struct passwd *pw;
 {
-    char *epw;
+    char *epw = NULL;
 
     /* If there is a function to check for shadow enabled, use it... */
 #ifdef HAVE_ISCOMSEC
     if (!iscomsec())
-       return(estrdup(pw->pw_passwd));
+       goto done;
 #endif /* HAVE_ISCOMSEC */
 #ifdef HAVE_ISSECURE
     if (!issecure())
-       return(estrdup(pw->pw_passwd));
+       goto done;
 #endif /* HAVE_ISSECURE */
 
-    epw = NULL;
 #ifdef HAVE_GETPRPWNAM
     {
        struct pr_passwd *spw;
@@ -103,10 +102,8 @@ sudo_getepw(pw)
 # ifdef __alpha
            crypt_type = spw->ufld.fd_oldcrypt;
 # endif /* __alpha */
-           epw = estrdup(spw->ufld.fd_encrypt);
+           epw = spw->ufld.fd_encrypt;
        }
-       if (epw)
-           return(epw);
     }
 #endif /* HAVE_GETPRPWNAM */
 #ifdef HAVE_GETSPNAM
@@ -114,9 +111,7 @@ sudo_getepw(pw)
        struct spwd *spw;
 
        if ((spw = getspnam(pw->pw_name)) && spw->sp_pwdp)
-           epw = estrdup(spw->sp_pwdp);
-       if (epw)
-           return(epw);
+           epw = spw->sp_pwdp;
     }
 #endif /* HAVE_GETSPNAM */
 #ifdef HAVE_GETSPWUID
@@ -124,9 +119,7 @@ sudo_getepw(pw)
        struct s_passwd *spw;
 
        if ((spw = getspwuid(pw->pw_uid)) && spw->pw_passwd)
-           epw = estrdup(spw->pw_passwd);
-       if (epw)
-           return(epw);
+           epw = spw->pw_passwd;
     }
 #endif /* HAVE_GETSPWUID */
 #ifdef HAVE_GETPWANAM
@@ -134,9 +127,7 @@ sudo_getepw(pw)
        struct passwd_adjunct *spw;
 
        if ((spw = getpwanam(pw->pw_name)) && spw->pwa_passwd)
-           epw = estrdup(spw->pwa_passwd);
-       if (epw)
-           return(epw);
+           epw = spw->pwa_passwd;
     }
 #endif /* HAVE_GETPWANAM */
 #ifdef HAVE_GETAUTHUID
@@ -144,14 +135,15 @@ sudo_getepw(pw)
        AUTHORIZATION *spw;
 
        if ((spw = getauthuid(pw->pw_uid)) && spw->a_password)
-           epw = estrdup(spw->a_password);
-       if (epw)
-           return(epw);
+           epw = spw->a_password;
     }
 #endif /* HAVE_GETAUTHUID */
 
-    /* Fall back on normal password. */
-    return(estrdup(pw->pw_passwd));
+#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
index 9a13003c4f9eb85984322ba9c2b8293511438071..6cb15d7843dcd9c7a6154cef9ac0392f7b694340 100644 (file)
--- a/gettime.c
+++ b/gettime.c
@@ -24,7 +24,7 @@
 # include <time.h>
 #endif
 
-#include <compat.h>
+#include "missing.h"
 
 /*
  * Get the current time via gettimeofday() for systems with
@@ -41,5 +41,5 @@ gettime(tv)
     rval = (int)time(&tv->tv_sec);
     tv->tv_usec = 0;
 #endif
-    return (rval);
+    return rval;
 }
diff --git a/glob.c b/glob.c
index 9673626531776c465f47e40f3efd9cb33d099e96..66dcadcb74e93675707b0ac2c4c6f96ec0a8dcdc 100644 (file)
--- a/glob.c
+++ b/glob.c
@@ -95,7 +95,7 @@
 #include <limits.h>
 #include <pwd.h>
 
-#include <compat.h>
+#include "missing.h"
 #include "emul/glob.h"
 #include "emul/charclass.h"
 
@@ -175,6 +175,7 @@ static void  qprintf __P((const char *, Char *));
 
 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)
@@ -367,7 +368,7 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
        size_t patbuf_len;
        glob_t *pglob;
 {
-       struct passwd *pwd;
+       struct passwd *pwd = NULL;
        char *h;
        const Char *p;
        Char *b, *eb;
@@ -413,6 +414,9 @@ globtilde(pattern, patbuf, patbuf_len, pglob)
                continue;
        *b = EOS;
 
+       if (pwd)
+           pw_delref(pwd);
+
        return patbuf;
 }
 
@@ -550,7 +554,7 @@ glob0(pattern, pglob)
 #endif
 
        if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0)
-               return(err);
+               return err;
 
        /*
         * If there was no match we are going to append the pattern
@@ -558,21 +562,21 @@ glob0(pattern, pglob)
         */
        if (pglob->gl_pathc == oldpathc) {
                if (pglob->gl_flags & GLOB_NOCHECK)
-                       return(globextend(pattern, pglob));
+                       return globextend(pattern, pglob);
                else
-                       return(GLOB_NOMATCH);
+                       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);
+       return 0;
 }
 
 static int
 compare(p, q)
        const void *p, *q;
 {
-       return(strcmp(*(char **)p, *(char **)q));
+       return strcmp(*(char **)p, *(char **)q);
 }
 
 static int
@@ -584,10 +588,10 @@ glob1(pattern, pattern_last,  pglob)
 
        /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
        if (*pattern == EOS)
-               return(0);
-       return(glob2(pathbuf, pathbuf + PATH_MAX - 1,
+               return 0;
+       return glob2(pathbuf, pathbuf + PATH_MAX - 1,
            pathbuf, pathbuf + PATH_MAX - 1,
-           pattern, pattern_last, pglob));
+           pattern, pattern_last, pglob);
 }
 
 /*
@@ -614,7 +618,7 @@ glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob
                if (*pattern == EOS) {          /* End of pattern? */
                        *pathend = EOS;
                        if (g_lstat(pathbuf, &sb, pglob))
-                               return(0);
+                               return 0;
 
                        if (((pglob->gl_flags & GLOB_MARK) &&
                            pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
@@ -622,12 +626,12 @@ glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob
                            (g_stat(pathbuf, &sb, pglob) == 0) &&
                            S_ISDIR(sb.st_mode)))) {
                                if (pathend+1 > pathend_last)
-                                       return (1);
+                                       return 1;
                                *pathend++ = SEP;
                                *pathend = EOS;
                        }
                        ++pglob->gl_matchc;
-                       return(globextend(pathbuf, pglob));
+                       return globextend(pathbuf, pglob);
                }
 
                /* Find end of next segment, copy tentatively to pathend. */
@@ -637,7 +641,7 @@ glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob
                        if (ismeta(*p))
                                anymeta = 1;
                        if (q+1 > pathend_last)
-                               return (1);
+                               return 1;
                        *q++ = *p++;
                }
 
@@ -646,14 +650,14 @@ glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob
                        pattern = p;
                        while (*pattern == SEP) {
                                if (pathend+1 > pathend_last)
-                                       return (1);
+                                       return 1;
                                *pathend++ = *pattern++;
                        }
                } else
                        /* Need expansion, recurse. */
-                       return(glob3(pathbuf, pathbuf_last, pathend,
+                       return glob3(pathbuf, pathbuf_last, pathend,
                            pathend_last, pattern, pattern_last,
-                           p, pattern_last, pglob));
+                           p, pattern_last, pglob);
        }
        /* NOTREACHED */
 }
@@ -671,7 +675,7 @@ glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
        char buf[PATH_MAX];
 
        if (pathend > pathend_last)
-               return (1);
+               return 1;
        *pathend = EOS;
        errno = 0;
 
@@ -679,12 +683,12 @@ glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
                /* TODO: don't call for ENOENT or ENOTDIR? */
                if (pglob->gl_errfunc) {
                        if (g_Ctoc(pathbuf, buf, sizeof(buf)))
-                               return(GLOB_ABORTED);
+                               return GLOB_ABORTED;
                        if (pglob->gl_errfunc(buf, errno) ||
                            pglob->gl_flags & GLOB_ERR)
-                               return(GLOB_ABORTED);
+                               return GLOB_ABORTED;
                }
-               return(0);
+               return 0;
        }
 
        err = 0;
@@ -718,7 +722,7 @@ glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
        }
 
        closedir(dirp);
-       return(err);
+       return err;
 }
 
 /*
@@ -755,7 +759,7 @@ globextend(path, pglob)
                        free(pglob->gl_pathv);
                        pglob->gl_pathv = NULL;
                }
-               return(GLOB_NOSPACE);
+               return GLOB_NOSPACE;
        }
 
        if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
@@ -772,13 +776,13 @@ globextend(path, pglob)
        if ((copy = malloc(len)) != NULL) {
                if (g_Ctoc(path, copy, len)) {
                        free(copy);
-                       return(GLOB_NOSPACE);
+                       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);
+       return copy == NULL ? GLOB_NOSPACE : 0;
 }
 
 /*
@@ -797,20 +801,20 @@ match(name, pat, patend)
                switch (c & M_MASK) {
                case M_ALL:
                        if (pat == patend)
-                               return(1);
+                               return 1;
                        do {
                            if (match(name, pat, patend))
-                                   return(1);
+                                   return 1;
                        } while (*name++ != EOS);
-                       return(0);
+                       return 0;
                case M_ONE:
                        if (*name++ == EOS)
-                               return(0);
+                               return 0;
                        break;
                case M_SET:
                        ok = 0;
                        if ((k = *name++) == EOS)
-                               return(0);
+                               return 0;
                        if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
                                ++pat;
                        while (((c = *pat++) & M_MASK) != M_END) {
@@ -829,15 +833,15 @@ match(name, pat, patend)
                                        ok = 1;
                        }
                        if (ok == negate_range)
-                               return(0);
+                               return 0;
                        break;
                default:
                        if (*name++ != c)
-                               return(0);
+                               return 0;
                        break;
                }
        }
-       return(*name == EOS);
+       return *name == EOS;
 }
 
 /* Free allocated data belonging to a glob_t structure. */
@@ -870,9 +874,9 @@ g_opendir(str, pglob)
                buf[1] = '\0';
        } else {
                if (g_Ctoc(str, buf, sizeof(buf)))
-                       return(NULL);
+                       return NULL;
        }
-       return(opendir(buf));
+       return opendir(buf);
 }
 
 static int
@@ -884,8 +888,8 @@ g_lstat(fn, sb, pglob)
        char buf[PATH_MAX];
 
        if (g_Ctoc(fn, buf, sizeof(buf)))
-               return(-1);
-       return(lstat(buf, sb));
+               return -1;
+       return lstat(buf, sb);
 }
 
 static int
@@ -897,8 +901,8 @@ g_stat(fn, sb, pglob)
        char buf[PATH_MAX];
 
        if (g_Ctoc(fn, buf, sizeof(buf)))
-               return(-1);
-       return(stat(buf, sb));
+               return -1;
+       return stat(buf, sb);
 }
 
 static Char *
@@ -908,9 +912,9 @@ g_strchr(str, ch)
 {
        do {
                if (*str == ch)
-                       return ((Char *)str);
+                       return (Char *)str;
        } while (*str++);
-       return (NULL);
+       return NULL;
 }
 
 static int
@@ -922,9 +926,9 @@ g_Ctoc(str, buf, len)
 
        while (len--) {
                if ((*buf++ = *str++) == EOS)
-                       return (0);
+                       return 0;
        }
-       return (1);
+       return 1;
 }
 
 #ifdef DEBUG
index 197131427373c4af33155d3e4d7dabe2c727e0ef..45066d3c66f569191c1a35e45d251592dd589606 100644 (file)
@@ -50,18 +50,18 @@ sudo_goodpath(path, sbp)
 
     /* Check for brain damage */
     if (path == NULL || path[0] == '\0')
-       return(NULL);
+       return NULL;
 
     if (stat(path, &sb))
-       return(NULL);
+       return NULL;
 
     /* Make sure path describes an executable regular file. */
     if (!S_ISREG(sb.st_mode) || !(sb.st_mode & 0000111)) {
        errno = EACCES;
-       return(NULL);
+       return NULL;
     }
 
     if (sbp != NULL)
        (void) memcpy(sbp, &sb, sizeof(struct stat));
-    return((char *)path);
+    return (char *)path;
 }
diff --git a/gram.c b/gram.c
index d2e8b46ae895c4bd0f8204fa8afb9064aeeeb4b2..ed7e21ba0ef3cea17de4b6d254e0c633b1ee5b24 100644 (file)
--- a/gram.c
+++ b/gram.c
@@ -1,3 +1,4 @@
+#include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #define YYBYACC 1
@@ -650,7 +651,7 @@ new_default(var, val, op)
     d->prev = d;
     d->next = NULL;
 
-    return(d);
+    return d;
 }
 
 static struct member *
@@ -666,7 +667,7 @@ new_member(name, type)
     m->prev = m;
     m->next = NULL;
 
-    return(m);
+    return m;
 }
 
 /*
@@ -820,10 +821,9 @@ init_parser(path, quiet)
     parse_error = FALSE;
     errorlineno = -1;
     errorfile = NULL;
-    sudolineno = 1;
     verbose = !quiet;
 }
-#line 775 "y.tab.c"
+#line 774 "y.tab.c"
 /* allocate initial stack or double stack size, up to YYMAXDEPTH */
 #if defined(__cplusplus) || defined(__STDC__)
 static int yygrowstack(void)
@@ -1592,7 +1592,7 @@ case 96:
                            yyval.member = new_member(yyvsp[0].string, WORD);
                        }
 break;
-#line 1544 "y.tab.c"
+#line 1543 "y.tab.c"
     }
     yyssp -= yym;
     yystate = *yyssp;
diff --git a/gram.y b/gram.y
index f319eea4f102d5e1189be20b558ce28493ef0566..9a07ee74d7e12b7d496413e4a6f1cb89912d16d3 100644 (file)
--- a/gram.y
+++ b/gram.y
@@ -620,7 +620,7 @@ new_default(var, val, op)
     d->prev = d;
     d->next = NULL;
 
-    return(d);
+    return d;
 }
 
 static struct member *
@@ -636,7 +636,7 @@ new_member(name, type)
     m->prev = m;
     m->next = NULL;
 
-    return(m);
+    return m;
 }
 
 /*
@@ -790,6 +790,5 @@ init_parser(path, quiet)
     parse_error = FALSE;
     errorlineno = -1;
     errorfile = NULL;
-    sudolineno = 1;
     verbose = !quiet;
 }
diff --git a/iolog.c b/iolog.c
index 4e492b6017cbd91164876bd32982ee2e04eb53e0..131770ec3f6e151d3ff67a7ade77b2599a325891 100644 (file)
--- a/iolog.c
+++ b/iolog.c
@@ -89,27 +89,28 @@ io_nextid()
 {
     struct stat sb;
     char buf[32], *ep;
-    int fd, i, ch;
+    int fd, i;
     unsigned long id = 0;
     int len;
     ssize_t nread;
     char pathbuf[PATH_MAX];
+    static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
     /*
-     * Create _PATH_SUDO_IO_LOGDIR if it doesn't already exist.
+     * Create I/O log directory if it doesn't already exist.
      */
-    if (stat(_PATH_SUDO_IO_LOGDIR, &sb) != 0) {
-       if (mkdir(_PATH_SUDO_IO_LOGDIR, S_IRWXU) != 0)
-           log_error(USE_ERRNO, "Can't mkdir %s", _PATH_SUDO_IO_LOGDIR);
+    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)",
-           _PATH_SUDO_IO_LOGDIR, (unsigned int) sb.st_mode);
+           def_iolog_dir, (unsigned int) sb.st_mode);
     }
 
     /*
      * Open sequence file
      */
-    len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", _PATH_SUDO_IO_LOGDIR);
+    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);
@@ -135,9 +136,8 @@ io_nextid()
      * Note that that least significant digits go at the end of the string.
      */
     for (i = 5; i >= 0; i--) {
-       ch = id % 36;
+       buf[i] = b36char[id % 36];
        id /= 36;
-       buf[i] = ch < 10 ? ch + '0' : ch - 10 + 'A';
     }
     buf[6] = '\n';
 
@@ -163,14 +163,14 @@ build_idpath(pathbuf, pathsize)
        log_error(0, "tried to build a session id path without a session id");
 
     /*
-     * Path is of the form /var/log/sudo-session/00/00/01.
+     * Path is of the form /var/log/sudo-io/00/00/01.
      */
-    len = snprintf(pathbuf, pathsize, "%s/%c%c/%c%c/%c%c", _PATH_SUDO_IO_LOGDIR,
+    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", _PATH_SUDO_IO_LOGDIR, sudo_user.sessid);
+       log_error(USE_ERRNO, "%s/%s", def_iolog_dir, sudo_user.sessid);
     }
 
     /*
@@ -187,7 +187,7 @@ build_idpath(pathbuf, pathsize)
        pathbuf[len - i] = '/';
     }
 
-    return(len);
+    return len;
 }
 
 static void *
@@ -227,7 +227,7 @@ io_log_open()
 
     /*
      * Build a path containing the session id split into two-digit subdirs,
-     * so ID 000001 becomes /var/log/sudo-session/00/00/01.
+     * so ID 000001 becomes /var/log/sudo-io/00/00/01.
      */
     len = build_idpath(pathbuf, sizeof(pathbuf));
     if (len == -1)
index e6ad58d4951c86fe39ce640e834c706507af7c20..a7f01e2a61a972d2b81b8f0cac0d260b0a0f1d67 100644 (file)
--- a/isblank.c
+++ b/isblank.c
  */
 
 #include <config.h>
-#include <compat.h>
+
+#include <sys/types.h>
+
+#include "missing.h"
 
 #undef isblank
 int
 isblank(ch)
     int ch;
 {
-    return(ch == ' ' || ch == '\t');
+    return ch == ' ' || ch == '\t';
 }
diff --git a/lbuf.c b/lbuf.c
index bd218da873b32cc7ef68cce0245cf230659cff14..bafea18f8c65be2f9f4b564e11ae37ff61def04f 100644 (file)
--- a/lbuf.c
+++ b/lbuf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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
@@ -31,6 +31,9 @@
 # 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 "sudo.h"
 #include "lbuf.h"
 
-#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ)
-# define TIOCGSIZE     TIOCGWINSZ
-# define ttysize       winsize
-# define ts_cols       ws_col
+/* Compatibility with older tty systems. */
+#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE)
+# define TIOCGWINSZ    TIOCGSIZE
+# define winsize       ttysize
+# define ws_col                ts_cols
 #endif
 
 int
@@ -62,17 +66,17 @@ get_ttycols()
 {
     char *p;
     int cols;
-#ifdef TIOCGSIZE
-    struct ttysize win;
+#ifdef TIOCGWINSZ
+    struct winsize wsize;
 
-    if (ioctl(STDERR_FILENO, TIOCGSIZE, &win) == 0 && win.ts_cols != 0)
-       return((int)win.ts_cols);
+    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);
+    return cols;
 }
 
 void
@@ -276,14 +280,16 @@ lbuf_print(lbuf)
     struct lbuf *lbuf;
 {
     char *cp, *ep;
-    int len, contlen;
+    int len;
 
-    contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0;
+    if (lbuf->buf == NULL || lbuf->len == 0)
+       goto done;
 
     /* For very small widths just give up... */
-    if (lbuf->cols <= lbuf->indent + contlen + 20) {
+    len = lbuf->continuation ? strlen(lbuf->continuation) : 0;
+    if (lbuf->cols <= lbuf->indent + len + 20) {
+       lbuf->buf[lbuf->len] = '\0';
        lbuf->output(lbuf->buf);
-       lbuf->output("\n");
        goto done;
     }
 
@@ -293,9 +299,11 @@ lbuf_print(lbuf)
            lbuf->output("\n");
            cp++;
        } else {
-           ep = memchr(cp, '\n', lbuf->len - (cp - lbuf->buf));
-           len = ep ? (int)(ep - cp) : lbuf->len;
-           lbuf_println(lbuf, cp, len);
+           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;
        }
     }
diff --git a/ldap.c b/ldap.c
index 81d3c408cbfe0173f5e4b4bab9fba3002e2cc090..3097af7dabe1b298fc2ee9ce3a17d69cf4f5865f 100644 (file)
--- a/ldap.c
+++ b/ldap.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * Copyright (c) 2003-2011 Todd C. Miller <Todd.Miller@courtesan.com>
  *
  * This code is derived from software contributed by Aaron Spangler.
  *
 #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 */
+#if TIME_WITH_SYS_TIME
+# include <time.h>
+#endif
 #include <ctype.h>
 #include <pwd.h>
 #include <grp.h>
 #endif
 
 #ifndef HAVE_LDAP_SEARCH_EXT_S
-#define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k)             \
+# 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)                                     \
 #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 */
@@ -129,7 +181,7 @@ struct ldap_config_list_str {
     char val[1];
 };
 
-/* ldap configuration structure */
+/* LDAP configuration structure */
 static struct ldap_config {
     int port;
     int version;
@@ -137,16 +189,19 @@ static struct ldap_config {
     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;
@@ -213,15 +268,25 @@ static struct ldap_config_table ldap_conf_table[] = {
 #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 },
@@ -250,6 +315,22 @@ 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,
@@ -298,7 +379,7 @@ sudo_ldap_conf_add_ports()
        }
     }
 
-    free(ldap_conf.host);
+    efree(ldap_conf.host);
     ldap_conf.host = estrdup(hostbuf);
     return;
 
@@ -378,7 +459,7 @@ sudo_ldap_parse_uri(uri_list)
            ldap_conf.ssl_mode = SUDO_LDAP_SSL;
        }
 
-       free(ldap_conf.host);
+       efree(ldap_conf.host);
        ldap_conf.host = estrdup(hostbuf);
        efree(buf);
     } while ((uri_list = uri_list->next));
@@ -388,7 +469,7 @@ sudo_ldap_parse_uri(uri_list)
 
 done:
     efree(buf);
-    return(rc);
+    return rc;
 
 toobig:
     errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf");
@@ -404,7 +485,7 @@ sudo_ldap_join_uri(uri_list)
 
     /* Usually just a single entry. */
     if (uri_list->next == NULL)
-       return(estrdup(uri_list->val));
+       return estrdup(uri_list->val);
 
     for (uri = uri_list; uri != NULL; uri = uri->next) {
        len += strlen(uri->val) + 1;
@@ -416,7 +497,7 @@ sudo_ldap_join_uri(uri_list)
        *cp++ = ' ';
     }
     cp[-1] = '\0';
-    return(buf);
+    return buf;
 }
 #endif /* HAVE_LDAP_INITIALIZE */
 
@@ -485,7 +566,7 @@ sudo_ldap_init(ldp, host, port)
 
 done:
     *ldp = ld;
-    return(rc);
+    return rc;
 }
 
 /*
@@ -503,12 +584,12 @@ sudo_ldap_check_user_netgroup(ld, entry, user)
     int ret = FALSE;
 
     if (!entry)
-       return(ret);
+       return ret;
 
     /* get the values from the entry */
     bv = ldap_get_values_len(ld, entry, "sudoUser");
     if (bv == NULL)
-       return(ret);
+       return ret;
 
     /* walk through values */
     for (p = bv; *p != NULL && !ret; p++) {
@@ -517,12 +598,12 @@ sudo_ldap_check_user_netgroup(ld, entry, user)
        if (netgr_matches(val, NULL, NULL, user))
            ret = TRUE;
        DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val,
-           ret ? "MATCH!" : "not"), 2);
+           ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1));
     }
 
     ldap_value_free_len(bv);   /* cleanup */
 
-    return(ret);
+    return ret;
 }
 
 /*
@@ -539,12 +620,12 @@ sudo_ldap_check_host(ld, entry)
     int ret = FALSE;
 
     if (!entry)
-       return(ret);
+       return ret;
 
     /* get the values from the entry */
     bv = ldap_get_values_len(ld, entry, "sudoHost");
     if (bv == NULL)
-       return(ret);
+       return ret;
 
     /* walk through values */
     for (p = bv; *p != NULL && !ret; p++) {
@@ -560,7 +641,7 @@ sudo_ldap_check_host(ld, entry)
 
     ldap_value_free_len(bv);   /* cleanup */
 
-    return(ret);
+    return ret;
 }
 
 static int
@@ -573,7 +654,7 @@ sudo_ldap_check_runas_user(ld, entry)
     int ret = FALSE;
 
     if (!runas_pw)
-       return(UNSPEC);
+       return UNSPEC;
 
     /* get the runas user from the entry */
     bv = ldap_get_values_len(ld, entry, "sudoRunAsUser");
@@ -602,7 +683,7 @@ sudo_ldap_check_runas_user(ld, entry)
      * what the user specified on the command line.
      */
     if (bv == NULL)
-       return(!strcasecmp(runas_pw->pw_name, def_runas_default));
+       return !strcasecmp(runas_pw->pw_name, def_runas_default);
 
     /* walk through values returned, looking for a match */
     for (p = bv; *p != NULL && !ret; p++) {
@@ -633,7 +714,7 @@ sudo_ldap_check_runas_user(ld, entry)
 
     ldap_value_free_len(bv);   /* cleanup */
 
-    return(ret);
+    return ret;
 }
 
 static int
@@ -647,12 +728,12 @@ sudo_ldap_check_runas_group(ld, entry)
 
     /* runas_gr is only set if the user specified the -g flag */
     if (!runas_gr)
-       return(UNSPEC);
+       return UNSPEC;
 
     /* get the values from the entry */
     bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup");
     if (bv == NULL)
-       return(ret);
+       return ret;
 
     /* walk through values returned, looking for a match */
     for (p = bv; *p != NULL && !ret; p++) {
@@ -665,7 +746,7 @@ sudo_ldap_check_runas_group(ld, entry)
 
     ldap_value_free_len(bv);   /* cleanup */
 
-    return(ret);
+    return ret;
 }
 
 /*
@@ -680,12 +761,12 @@ sudo_ldap_check_runas(ld, entry)
     int ret;
 
     if (!entry)
-       return(FALSE);
+       return FALSE;
 
     ret = sudo_ldap_check_runas_user(ld, entry) != FALSE &&
        sudo_ldap_check_runas_group(ld, entry) != FALSE;
 
-    return(ret);
+    return ret;
 }
 
 /*
@@ -703,11 +784,11 @@ sudo_ldap_check_command(ld, entry, setenv_implied)
     int foundbang, ret = UNSPEC;
 
     if (!entry)
-       return(ret);
+       return ret;
 
     bv = ldap_get_values_len(ld, entry, "sudoCommand");
     if (bv == NULL)
-       return(ret);
+       return ret;
 
     for (p = bv; *p != NULL && ret != FALSE; p++) {
        val = (*p)->bv_val;
@@ -750,7 +831,7 @@ sudo_ldap_check_command(ld, entry, setenv_implied)
 
     ldap_value_free_len(bv);   /* more cleanup */
 
-    return(ret);
+    return ret;
 }
 
 /*
@@ -768,11 +849,11 @@ sudo_ldap_check_bool(ld, entry, option)
     int ret = UNSPEC;
 
     if (entry == NULL)
-       return(UNSPEC);
+       return UNSPEC;
 
     bv = ldap_get_values_len(ld, entry, "sudoOption");
     if (bv == NULL)
-       return(ret);
+       return ret;
 
     /* walk through options */
     for (p = bv; *p != NULL; p++) {
@@ -787,7 +868,7 @@ sudo_ldap_check_bool(ld, entry, option)
 
     ldap_value_free_len(bv);
 
-    return(ret);
+    return ret;
 }
 
 /*
@@ -841,33 +922,128 @@ sudo_ldap_parse_options(ld, entry)
 }
 
 /*
- * builds together a filter to check against ldap
+ * 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;
-    size_t sz;
-    char *buf;
+    char *buf, timebuffer[TIMEFILTER_LENGTH];
+    size_t sz = 0;
     int i;
 
-    /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */
-    sz = 29 + strlen(pw->pw_name);
+    /* 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)
+    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)
+       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) strlcpy(buf, "(|(sudoUser=", sz);
+    (void) strlcat(buf, "(|(sudoUser=", sz);
     (void) strlcat(buf, pw->pw_name, sz);
     (void) strlcat(buf, ")", sz);
 
@@ -876,6 +1052,7 @@ sudo_ldap_build_pass1(pw)
        (void) strlcat(buf, "(sudoUser=%", sz);
        (void) strlcat(buf, grp->gr_name, sz);
        (void) strlcat(buf, ")", sz);
+       gr_delref(grp);
     }
 
     /* Append supplementary groups */
@@ -886,14 +1063,50 @@ sudo_ldap_build_pass1(pw)
            (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)
+    if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz)
        errorx(1, "sudo_ldap_build_pass1 allocation mismatch");
 
-    return(buf);
+    /* 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;
 }
 
 /*
@@ -907,32 +1120,32 @@ _atobool(s)
        case 'y':
        case 'Y':
            if (strcasecmp(s, "yes") == 0)
-               return(TRUE);
+               return TRUE;
            break;
        case 't':
        case 'T':
            if (strcasecmp(s, "true") == 0)
-               return(TRUE);
+               return TRUE;
            break;
        case 'o':
        case 'O':
            if (strcasecmp(s, "on") == 0)
-               return(TRUE);
+               return TRUE;
            if (strcasecmp(s, "off") == 0)
-               return(FALSE);
+               return FALSE;
            break;
        case 'n':
        case 'N':
            if (strcasecmp(s, "no") == 0)
-               return(FALSE);
+               return FALSE;
            break;
        case 'f':
        case 'F':
            if (strcasecmp(s, "false") == 0)
-               return(FALSE);
+               return FALSE;
            break;
     }
-    return(-1);
+    return -1;
 }
 
 static void
@@ -969,12 +1182,13 @@ sudo_ldap_read_config()
     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);
+       return FALSE;
 
     while ((cp = sudo_parseln(fp)) != NULL) {
        if (*cp == '\0')
@@ -1031,9 +1245,6 @@ sudo_ldap_read_config()
     if (!ldap_conf.host)
        ldap_conf.host = estrdup("localhost");
 
-    if (ldap_conf.bind_timelimit > 0)
-       ldap_conf.bind_timelimit *= 1000;       /* convert to ms */
-
     if (ldap_conf.debug > 1) {
        fprintf(stderr, "LDAP Config Summary\n");
        fprintf(stderr, "===================\n");
@@ -1059,6 +1270,8 @@ sudo_ldap_read_config()
            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 ?
@@ -1067,6 +1280,8 @@ sudo_ldap_read_config()
            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)
@@ -1102,7 +1317,10 @@ sudo_ldap_read_config()
        fprintf(stderr, "===================\n");
     }
     if (!ldap_conf.base)
-       return(FALSE);          /* if no base is defined, ignore LDAP */
+       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
@@ -1126,7 +1344,7 @@ sudo_ldap_read_config()
     if (ldap_conf.uri) {
        struct ldap_config_list_str *uri = ldap_conf.uri;
        if (sudo_ldap_parse_uri(uri) != 0)
-           return(FALSE);
+           return FALSE;
        do {
            ldap_conf.uri = uri->next;
            efree(uri);
@@ -1151,6 +1369,18 @@ sudo_ldap_read_config()
 #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);
@@ -1176,7 +1406,7 @@ sudo_ldap_read_config()
        }
     }
 #endif
-    return(TRUE);
+    return TRUE;
 }
 
 /*
@@ -1192,21 +1422,21 @@ sudo_ldap_get_first_rdn(ld, entry)
     LDAPDN tmpDN;
 
     if ((dn = ldap_get_dn(ld, entry)) == NULL)
-       return(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);
+    return rdn;
 #else
     char *dn, **edn;
 
     if ((dn = ldap_get_dn(ld, entry)) == NULL)
-       return(NULL);
+       return NULL;
     edn = ldap_explode_dn(dn, 1);
     ldap_memfree(dn);
-    return(edn ? edn[0] : NULL);
+    return edn ? edn[0] : NULL;
 #endif
 }
 
@@ -1220,19 +1450,28 @@ sudo_ldap_display_defaults(nss, pw, lbuf)
     struct lbuf *lbuf;
 {
     struct berval **bv, **p;
+    struct timeval tv, *tvp = NULL;
     struct ldap_config_list_str *base;
-    LDAP *ld = (LDAP *) nss->handle;
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
     LDAPMessage *entry, *result;
-    char *prefix;
+    char *prefix, *filt;
     int rc, count = 0;
 
-    if (ld == NULL)
+    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,
-           "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result);
+           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) {
@@ -1251,8 +1490,9 @@ sudo_ldap_display_defaults(nss, pw, lbuf)
        if (result)
            ldap_msgfree(result);
     }
+    efree(filt);
 done:
-    return(count);
+    return count;
 }
 
 /*
@@ -1264,7 +1504,7 @@ sudo_ldap_display_bound_defaults(nss, pw, lbuf)
     struct passwd *pw;
     struct lbuf *lbuf;
 {
-    return(0);
+    return 0;
 }
 
 /*
@@ -1329,7 +1569,6 @@ sudo_ldap_display_entry_short(ld, entry, lbuf)
                    "NOSETENV: " : "SETENV: ";
            if (tag != NULL)
                lbuf_append(lbuf, tag, NULL);
-           /* XXX - ignores other options */
        }
        ldap_value_free_len(bv);
     }
@@ -1347,7 +1586,7 @@ sudo_ldap_display_entry_short(ld, entry, lbuf)
     }
     lbuf_append(lbuf, "\n", NULL);
 
-    return(count);
+    return count;
 }
 
 /*
@@ -1411,7 +1650,19 @@ sudo_ldap_display_entry_long(ld, entry, lbuf)
        lbuf_append(lbuf, "\n", NULL);
     }
 
-    /* get the Command Values from the entry */
+    /*
+     * 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);
@@ -1422,7 +1673,7 @@ sudo_ldap_display_entry_long(ld, entry, lbuf)
        ldap_value_free_len(bv);
     }
 
-    return(count);
+    return count;
 }
 
 /*
@@ -1434,57 +1685,30 @@ sudo_ldap_display_privs(nss, pw, lbuf)
     struct passwd *pw;
     struct lbuf *lbuf;
 {
-    struct ldap_config_list_str *base;
-    LDAP *ld = (LDAP *) nss->handle;
-    LDAPMessage *entry, *result;
-    char *filt;
-    int rc, do_netgr, count = 0;
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
+    struct ldap_result *lres;
+    LDAPMessage *entry;
+    int i, count = 0;
 
-    if (ld == NULL)
+    if (handle == NULL || handle->ld == NULL)
        goto done;
+    ld = handle->ld;
 
-    /*
-     * Okay - time to search for anything that matches this user
-     * Lets limit it to only two queries of the LDAP server
-     *
-     * The first pass will look by the username, groups, and
-     * the keyword ALL.  We will then inspect the results that
-     * came back from the query.  We don't need to inspect the
-     * sudoUser in this pass since the LDAP server already scanned
-     * it for us.
-     *
-     * The second pass will return all the entries that contain
-     * user netgroups.  Then we take the netgroups returned and
-     * try to match them against the username.
-     */
-    for (do_netgr = 0; do_netgr < 2; do_netgr++) {
-       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
-       DPRINTF(("ldap search '%s'", filt), 1);
-       for (base = ldap_conf.base; base != NULL; base = base->next) {
-           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)
-               continue;       /* no entries for this pass */
-
-           /* print each matching entry */
-           LDAP_FOREACH(entry, ld, result) {
-               if ((!do_netgr ||
-                   sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
-                   sudo_ldap_check_host(ld, entry)) {
+    DPRINTF(("ldap search for command list"), 1);
+    lres = sudo_ldap_result_get(nss, pw);
 
-                   if (long_list)
-                       count += sudo_ldap_display_entry_long(ld, entry, lbuf);
-                   else
-                       count += sudo_ldap_display_entry_short(ld, entry, lbuf);
-               }
-           }
-           ldap_msgfree(result);
-       }
-       efree(filt);
+    /* 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);
+    return count;
 }
 
 static int
@@ -1492,59 +1716,36 @@ sudo_ldap_display_cmnd(nss, pw)
     struct sudo_nss *nss;
     struct passwd *pw;
 {
-    struct ldap_config_list_str *base;
-    LDAP *ld = (LDAP *) nss->handle;
-    LDAPMessage *entry, *result;               /* used for searches */
-    char *filt;                                        /* used to parse attributes */
-    int rc, found, do_netgr;                   /* temp/final return values */
+    struct sudo_ldap_handle *handle = nss->handle;
+    LDAP *ld;
+    struct ldap_result *lres;
+    LDAPMessage *entry;
+    int i, found = FALSE;
 
-    if (ld == NULL)
-       return(1);
+    if (handle == NULL || handle->ld == NULL)
+       goto done;
+    ld = handle->ld;
 
     /*
-     * 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.
+     * The sudo_ldap_result_get() function returns all nodes that match
+     * the user and the host.
      */
-    for (found = FALSE, do_netgr = 0; !found && do_netgr < 2; do_netgr++) {
-       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
-       DPRINTF(("ldap search '%s'", filt), 1);
-       for (base = ldap_conf.base; base != NULL; base = base->next) {
-           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)
-               continue;       /* no entries for this pass */
-
-           LDAP_FOREACH(entry, ld, result) {
-               if ((!do_netgr ||
-                   sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
-                   sudo_ldap_check_host(ld, entry) &&
-                   sudo_ldap_check_command(ld, entry, NULL) &&
-                   sudo_ldap_check_runas(ld, entry)) {
-
-                   found = TRUE;
-                   break;
-               }
-           }
-           ldap_msgfree(result);
+    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;
        }
-       efree(filt);
     }
 
+done:
     if (found)
        printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd,
            user_args ? " " : "", user_args ? user_args : "");
-   return(!found);
+   return !found;
 }
 
 #ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S
@@ -1560,7 +1761,7 @@ sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact)
 
     for (; interact->id != SASL_CB_LIST_END; interact++) {
        if (interact->id != SASL_CB_USER)
-           return(LDAP_PARAM_ERROR);
+           return LDAP_PARAM_ERROR;
 
        if (auth_id != NULL)
            interact->result = auth_id;
@@ -1574,7 +1775,7 @@ sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact)
        interact->result = estrdup(interact->result);
 #endif /* SASL_VERSION_MAJOR < 2 */
     }
-    return(LDAP_SUCCESS);
+    return LDAP_SUCCESS;
 }
 #endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */
 
@@ -1613,7 +1814,7 @@ sudo_ldap_set_options(ld)
                if (rc != LDAP_OPT_SUCCESS) {
                    warningx("ldap_set_option: %s -> %d: %s",
                        cur->conf_str, ival, ldap_err2string(rc));
-                   return(-1);
+                   return -1;
                }
                DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1);
            }
@@ -1625,7 +1826,7 @@ sudo_ldap_set_options(ld)
                if (rc != LDAP_OPT_SUCCESS) {
                    warningx("ldap_set_option: %s -> %s: %s",
                        cur->conf_str, sval, ldap_err2string(rc));
-                   return(-1);
+                   return -1;
                }
                DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1);
            }
@@ -1633,6 +1834,22 @@ sudo_ldap_set_options(ld)
        }
     }
 
+#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) {
@@ -1643,7 +1860,7 @@ sudo_ldap_set_options(ld)
        if (rc != LDAP_OPT_SUCCESS) {
            warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s",
                (long)tv.tv_sec, ldap_err2string(rc));
-           return(-1);
+           return -1;
        }
        DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)",
            (long)tv.tv_sec), 1);
@@ -1657,12 +1874,82 @@ sudo_ldap_set_options(ld)
        if (rc != LDAP_SUCCESS) {
            warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s",
                ldap_err2string(rc));
-           return(-1);
+           return -1;
        }
        DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1);
     }
 #endif
-    return(0);
+    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;
 }
 
 /*
@@ -1712,7 +1999,7 @@ sudo_ldap_bind_s(ld)
        }
        if (rc != LDAP_SUCCESS) {
            warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc));
-           return(-1);
+           return -1;
        }
        DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1);
     } else
@@ -1728,7 +2015,7 @@ sudo_ldap_bind_s(ld)
            NULL, NULL, NULL);
        if (rc != LDAP_SUCCESS) {
            warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc));
-           return(-1);
+           return -1;
        }
        DPRINTF(("ldap_sasl_bind_s() ok"), 1);
     }
@@ -1737,12 +2024,12 @@ sudo_ldap_bind_s(ld)
        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);
+           return -1;
        }
        DPRINTF(("ldap_simple_bind_s() ok"), 1);
     }
 #endif
-    return(0);
+    return 0;
 }
 
 /*
@@ -1755,9 +2042,10 @@ sudo_ldap_open(nss)
 {
     LDAP *ld;
     int rc, ldapnoinit = FALSE;
+    struct sudo_ldap_handle    *handle;
 
     if (!sudo_ldap_read_config())
-       return(-1);
+       return -1;
 
     /* Prevent reading of user ldaprc and system defaults. */
     if (getenv("LDAPNOINIT") == NULL) {
@@ -1777,7 +2065,7 @@ sudo_ldap_open(nss)
        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);
+       return -1;
     }
 
     if (ldapnoinit)
@@ -1785,25 +2073,25 @@ sudo_ldap_open(nss)
 
     /* Set LDAP options */
     if (sudo_ldap_set_options(ld) < 0)
-       return(-1);
+       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);
+           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);
+           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);
+           return -1;
        }
        DPRINTF(("ldap_start_tls_s_np() ok"), 1);
 #else
@@ -1813,10 +2101,17 @@ sudo_ldap_open(nss)
 
     /* Actually connect */
     if (sudo_ldap_bind_s(ld) != 0)
-       return(-1);
+       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;
 
-    nss->handle = ld;
-    return(0);
+    return 0;
 }
 
 static int
@@ -1824,17 +2119,29 @@ sudo_ldap_setdefs(nss)
     struct sudo_nss *nss;
 {
     struct ldap_config_list_str *base;
-    LDAP *ld = (LDAP *) nss->handle;
-    LDAPMessage *entry, *result;                /* used for searches */
-    int rc;                                     /* temp return value */
+    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;
 
-    if (ld == NULL)
-       return(-1);
+    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,
-           "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result);
+           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);
@@ -1844,8 +2151,9 @@ sudo_ldap_setdefs(nss)
        if (result)
            ldap_msgfree(result);
     }
+    efree(filt);
 
-    return(0);
+    return 0;
 }
 
 /*
@@ -1857,55 +2165,42 @@ sudo_ldap_lookup(nss, ret, pwflag)
     int ret;
     int pwflag;
 {
-    struct ldap_config_list_str *base;
-    LDAP *ld = (LDAP *) nss->handle;
-    LDAPMessage *entry, *result;
-    char *filt;
-    int do_netgr, rc, matched;
-    int setenv_implied;
-    int ldap_user_matches = FALSE, ldap_host_matches = FALSE;
-    struct passwd *pw = list_pw ? list_pw : sudo_user.pw;
+    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;
 
-    if (ld == NULL)
-       return(ret);
+    /* 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 (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
-           filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
-           for (base = ldap_conf.base; base != NULL; base = base->next) {
-               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)
-                   continue;
-
-               LDAP_FOREACH(entry, ld, result) {
-                   /* only verify netgroup matches in pass 2 */
-                   if (do_netgr && !sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name))
-                       continue;
-
-                   ldap_user_matches = TRUE;
-                   if (sudo_ldap_check_host(ld, entry)) {
-                       ldap_host_matches = TRUE;
-                       if ((pwcheck == any && doauth != FALSE) ||
-                           (pwcheck == all && doauth == FALSE))
-                           doauth = sudo_ldap_check_bool(ld, entry, "authenticate");
-                       /* Only check the command when listing another user. */
-                       if (user_uid == 0 || list_pw == NULL ||
-                           user_uid == list_pw->pw_uid ||
-                           sudo_ldap_check_command(ld, entry, NULL)) {
-                           matched = 1;
-                           break;      /* end foreach */
-                       }
-                   }
-               }
-               ldap_msgfree(result);
+       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;
            }
-           efree(filt);
        }
        if (matched || user_uid == 0) {
            SET(ret, VALIDATE_OK);
@@ -1931,6 +2226,196 @@ sudo_ldap_lookup(nss, ret, pwflag)
        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
@@ -1944,12 +2429,22 @@ sudo_ldap_lookup(nss, ret, pwflag)
      * 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.
      */
-    setenv_implied = FALSE;
-    for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) {
-       filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw);
+    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);
@@ -1957,85 +2452,61 @@ sudo_ldap_lookup(nss, ret, pwflag)
                DPRINTF(("nothing found for '%s'", filt), 1);
                continue;
            }
+           lres->user_matches = TRUE;
 
-           /* parse each entry returned from this most recent search */
+           /* 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) {
-               DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1);
-               if (
-               /* first verify user netgroup matches - only if in pass 2 */
-                   (!do_netgr || sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) &&
-               /* remember that user matched */
-                   (ldap_user_matches = TRUE) &&
-               /* verify host match */
-                   sudo_ldap_check_host(ld, entry) &&
-               /* remember that host matched */
-                   (ldap_host_matches = TRUE) &&
-               /* verify runas match */
-                   sudo_ldap_check_runas(ld, entry) &&
-               /* verify command match */
-                   (rc = sudo_ldap_check_command(ld, entry, &setenv_implied)) != UNSPEC
-                   ) {
-                   /* We have a match! */
-                   DPRINTF(("Command %sallowed", rc == TRUE ? "" : "NOT "), 1);
-                   matched = TRUE;
-                   if (rc == TRUE) {
-                       /* pick up any options */
-                       if (setenv_implied)
-                           def_setenv = TRUE;
-                       sudo_ldap_parse_options(ld, entry);
-#ifdef HAVE_SELINUX
-                       /* Set role and type if not specified on command line. */
-                       if (user_role == NULL)
-                           user_role = def_role;
-                       if (user_type == NULL)
-                           user_type = def_type;
-#endif /* HAVE_SELINUX */
-                       /* make sure we don't reenter loop */
-                       SET(ret, VALIDATE_OK);
-                       CLR(ret, VALIDATE_NOT_OK);
-                   } else {
-                       SET(ret, VALIDATE_NOT_OK);
-                       CLR(ret, VALIDATE_OK);
-                   }
-                   /* break from inside for loop */
-                   break;
+               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);
                }
            }
-           ldap_msgfree(result);
+           DPRINTF(("result now has %d entries", lres->nentries), 1);
        }
        efree(filt);
     }
 
-done:
-    DPRINTF(("user_matches=%d", ldap_user_matches), 1);
-    DPRINTF(("host_matches=%d", ldap_host_matches), 1);
+    /* 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);
 
-    if (!ISSET(ret, VALIDATE_OK)) {
-       /* we do not have a match */
-       if (pwflag && list_pw == NULL)
-           SET(ret, FLAG_NO_CHECK);
-    }
-    if (ldap_user_matches)
-       CLR(ret, FLAG_NO_USER);
-    if (ldap_host_matches)
-       CLR(ret, FLAG_NO_HOST);
-    DPRINTF(("sudo_ldap_lookup(%d)=0x%02x", pwflag, ret), 1);
+    /* Store everything in the sudo_nss handle. */
+    handle->result = lres;
+    handle->username = estrdup(pw->pw_name);
+    handle->groups = user_groups;
 
-    return(ret);
+    return lres;
 }
 
 /*
- * shut down LDAP connection
+ * Shut down the LDAP connection.
  */
 static int
 sudo_ldap_close(nss)
     struct sudo_nss *nss;
 {
-    if (nss->handle != NULL) {
-       ldap_unbind_ext_s((LDAP *) nss->handle, NULL, NULL);
+    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);
+    return 0;
 }
 
 /*
@@ -2045,5 +2516,46 @@ static int
 sudo_ldap_parse(nss)
     struct sudo_nss *nss;
 {
-    return(0);
+    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
index b4160c99cd8ff66ad19f3bbfaeecf53d4084c890..16e21af1bf72327ba0128fdb47abc6c9edca269a 100644 (file)
 #include <string.h>
 #include <libaudit.h>
 
-#include "compat.h"
+#include "missing.h"
 #include "error.h"
 #include "alloc.h"
-#include "missing.h"
 #include "linux_audit.h"
 
 /*
diff --git a/list.c b/list.c
index 60c1138026ac7ad0c84858cbd4ad959820abc385..2fb4967a2335b558708e2e6dfccf5c489c397f58 100644 (file)
--- a/list.c
+++ b/list.c
@@ -62,7 +62,7 @@ tq_pop(vh)
            h->last->next = NULL;
        }
     }
-    return (last);
+    return last;
 }
 
 /*
@@ -131,3 +131,33 @@ tq_append(vh, vl)
     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
index 17aab415b1cc19189260f20e73fe6a1c4b546be9..719afa2f3275b44b397cda5f3473e78bd0c081d8 100644 (file)
--- a/list.h
+++ b/list.h
@@ -77,6 +77,7 @@ struct n/**/_list {                                   \
  */
 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 *));
 
index 2b329683f187c73c59073c17efa4be9673d51ad1..d0aeab9906f3836f972a55b23a1e2608171e0e06 100644 (file)
--- a/logging.c
+++ b/logging.c
 #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>
@@ -132,6 +138,12 @@ do_syslog(pri, msg)
     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
      */
@@ -166,6 +178,11 @@ do_syslog(pri, msg)
        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
@@ -189,6 +206,12 @@ do_logfile(msg)
     } 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) */
@@ -258,6 +281,11 @@ do_logfile(msg)
        (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 */
     }
 }
 
@@ -437,7 +465,7 @@ send_mail(fmt, va_alist)
        "USER=root",
        NULL
     };
-#endif
+#endif /* NO_ROOT_MAILER */
 
     /* Just return if mailer is disabled. */
     if (!def_mailerpath || !def_mailto)
@@ -479,13 +507,22 @@ send_mail(fmt, va_alist)
     /* Daemonize - disassociate from session/tty. */
     if (setsid() == -1)
       warning("setsid");
-    (void) chdir("/");
+    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();
@@ -582,6 +619,11 @@ send_mail(fmt, va_alist)
            (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__
@@ -612,10 +654,10 @@ should_mail(status)
     int status;
 {
 
-    return(def_mail_always || ISSET(status, VALIDATE_ERROR) ||
+    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)));
+       (def_mail_no_perms && !ISSET(status, VALIDATE_OK));
 }
 
 #define        LL_TTY_STR      "TTY="
@@ -669,7 +711,10 @@ new_logline(message, serrno)
        }
        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;
 
@@ -722,8 +767,11 @@ new_logline(message, serrno)
            goto toobig;
        efree(evstr);
     }
-    if (strlcat(line, LL_CMND_STR, len) >= len ||
-       strlcat(line, user_cmnd, len) >= len)
+    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 ||
@@ -731,7 +779,7 @@ new_logline(message, serrno)
            goto toobig;
     }
 
-    return (line);
+    return line;
 toobig:
     errorx(1, "internal error: insufficient space for log line");
 }
diff --git a/match.c b/match.c
index 6431425df3fdde0c64f686f00d5e8b5a464b3460..ba299e19d94c7bf4d97573530250ad15844310fd 100644 (file)
--- a/match.c
+++ b/match.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2010
+ * 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
@@ -146,7 +146,7 @@ _userlist_matches(pw, list)
        if (matched != UNSPEC)
            break;
     }
-    return(matched);
+    return matched;
 }
 
 int
@@ -155,7 +155,7 @@ userlist_matches(pw, list)
     struct member_list *list;
 {
     alias_seqno++;
-    return(_userlist_matches(pw, list));
+    return _userlist_matches(pw, list);
 }
 
 /*
@@ -177,7 +177,7 @@ _runaslist_matches(user_list, group_list)
     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));
+           return userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw);
 
        tq_foreach_rev(user_list, m) {
            switch (m->type) {
@@ -239,10 +239,10 @@ _runaslist_matches(user_list, group_list)
     }
 
     if (user_matched == DENY || group_matched == DENY)
-       return(DENY);
+       return DENY;
     if (user_matched == group_matched || runas_gr == NULL)
-       return(user_matched);
-    return(UNSPEC);
+       return user_matched;
+    return UNSPEC;
 }
 
 int
@@ -251,8 +251,8 @@ runaslist_matches(user_list, group_list)
     struct member_list *group_list;
 {
     alias_seqno++;
-    return(_runaslist_matches(user_list ? user_list : &empty,
-       group_list ? group_list : &empty));
+    return _runaslist_matches(user_list ? user_list : &empty,
+       group_list ? group_list : &empty);
 }
 
 /*
@@ -296,7 +296,7 @@ _hostlist_matches(list)
        if (matched != UNSPEC)
            break;
     }
-    return(matched);
+    return matched;
 }
 
 int
@@ -304,7 +304,7 @@ hostlist_matches(list)
     struct member_list *list;
 {
     alias_seqno++;
-    return(_hostlist_matches(list));
+    return _hostlist_matches(list);
 }
 
 /*
@@ -323,7 +323,7 @@ _cmndlist_matches(list)
        if (matched != UNSPEC)
            break;
     }
-    return(matched);
+    return matched;
 }
 
 int
@@ -331,7 +331,7 @@ cmndlist_matches(list)
     struct member_list *list;
 {
     alias_seqno++;
-    return(_cmndlist_matches(list));
+    return _cmndlist_matches(list);
 }
 
 /*
@@ -364,7 +364,35 @@ cmnd_matches(m)
                matched = !m->negated;
            break;
     }
-    return(matched);
+    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;
 }
 
 /*
@@ -386,16 +414,13 @@ command_matches(sudoers_cmnd, sudoers_args)
         */
        if (strcmp(sudoers_cmnd, "sudoedit") != 0 ||
            strcmp(user_cmnd, "sudoedit") != 0)
-           return(FALSE);
-       if (!sudoers_args ||
-           (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-           (sudoers_args &&
-            fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+           return FALSE;
+       if (command_args_match(sudoers_cmnd, sudoers_args)) {
            efree(safe_cmnd);
            safe_cmnd = estrdup(sudoers_cmnd);
-           return(TRUE);
+           return TRUE;
        } else
-           return(FALSE);
+           return FALSE;
     }
 
     if (has_meta(sudoers_cmnd)) {
@@ -404,10 +429,10 @@ command_matches(sudoers_cmnd, sudoers_args)
         * 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_fnmatch(sudoers_cmnd, sudoers_args);
+       return command_matches_glob(sudoers_cmnd, sudoers_args);
     }
-    return(command_matches_normal(sudoers_cmnd, sudoers_args));
+    return command_matches_normal(sudoers_cmnd, sudoers_args);
 }
 
 static int
@@ -423,17 +448,14 @@ command_matches_fnmatch(sudoers_cmnd, sudoers_args)
      * else return false.
      */
     if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0)
-       return(FALSE);
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-       (sudoers_args &&
-        fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+       return FALSE;
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
        if (safe_cmnd)
            free(safe_cmnd);
        safe_cmnd = estrdup(user_cmnd);
-       return(TRUE);
+       return TRUE;
     } else
-       return(FALSE);
+       return FALSE;
 }
 
 static int
@@ -456,7 +478,7 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
        if ((base = strrchr(sudoers_cmnd, '/')) != NULL) {
            base++;
            if (!has_meta(base) && strcmp(user_base, base) != 0)
-               return(FALSE);
+               return FALSE;
        }
     }
     /*
@@ -469,7 +491,7 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
 #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);
+       return FALSE;
     }
     /* For each glob match, compare basename, st_dev and st_ino. */
     for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) {
@@ -477,7 +499,7 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
        dlen = strlen(cp);
        if (cp[dlen - 1] == '/') {
            if (command_matches_dir(cp, dlen))
-               return(TRUE);
+               return TRUE;
            continue;
        }
 
@@ -499,17 +521,14 @@ command_matches_glob(sudoers_cmnd, sudoers_args)
     }
     globfree(&gl);
     if (cp == NULL)
-       return(FALSE);
+       return FALSE;
 
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-       (sudoers_args &&
-        fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
        efree(safe_cmnd);
        safe_cmnd = estrdup(user_cmnd);
-       return(TRUE);
+       return TRUE;
     }
-    return(FALSE);
+    return FALSE;
 }
 
 static int
@@ -524,7 +543,7 @@ command_matches_normal(sudoers_cmnd, sudoers_args)
     /* 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));
+       return command_matches_dir(sudoers_cmnd, dlen);
 
     /* Only proceed if user_base and basename(sudoers_cmnd) match */
     if ((base = strrchr(sudoers_cmnd, '/')) == NULL)
@@ -533,7 +552,7 @@ command_matches_normal(sudoers_cmnd, sudoers_args)
        base++;
     if (strcmp(user_base, base) != 0 ||
        stat(sudoers_cmnd, &sudoers_stat) == -1)
-       return(FALSE);
+       return FALSE;
 
     /*
      * Return true if inode/device matches AND
@@ -544,16 +563,13 @@ command_matches_normal(sudoers_cmnd, sudoers_args)
     if (user_stat != NULL &&
        (user_stat->st_dev != sudoers_stat.st_dev ||
        user_stat->st_ino != sudoers_stat.st_ino))
-       return(FALSE);
-    if (!sudoers_args ||
-       (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) ||
-       (sudoers_args &&
-        fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) {
+       return FALSE;
+    if (command_args_match(sudoers_cmnd, sudoers_args)) {
        efree(safe_cmnd);
        safe_cmnd = estrdup(sudoers_cmnd);
-       return(TRUE);
+       return TRUE;
     }
-    return(FALSE);
+    return FALSE;
 }
 
 /*
@@ -574,11 +590,11 @@ command_matches_dir(sudoers_dir, dlen)
      */
     dirp = opendir(sudoers_dir);
     if (dirp == NULL)
-       return(FALSE);
+       return FALSE;
 
     if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) {
        closedir(dirp);
-       return(FALSE);
+       return FALSE;
     }
     while ((dent = readdir(dirp)) != NULL) {
        /* ignore paths > PATH_MAX (XXX - log) */
@@ -590,8 +606,9 @@ command_matches_dir(sudoers_dir, dlen)
        if (strcmp(user_base, dent->d_name) != 0 ||
            stat(buf, &sudoers_stat) == -1)
            continue;
-       if (user_stat->st_dev == sudoers_stat.st_dev &&
-           user_stat->st_ino == sudoers_stat.st_ino) {
+       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;
@@ -599,7 +616,7 @@ command_matches_dir(sudoers_dir, dlen)
     }
 
     closedir(dirp);
-    return(dent != NULL);
+    return dent != NULL;
 }
 
 static int
@@ -633,24 +650,24 @@ addr_matches_if(n)
                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);
+                   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);
+                   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);
+                   return TRUE;
 #endif
        }
     }
 
-    return(FALSE);
+    return FALSE;
 }
 
 static int
@@ -710,7 +727,7 @@ addr_matches_if_netmask(n, m)
        switch(family) {
            case AF_INET:
                if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr)
-                   return(TRUE);
+                   return TRUE;
 #ifdef HAVE_IN6_ADDR
            case AF_INET6:
                for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) {
@@ -718,12 +735,12 @@ addr_matches_if_netmask(n, m)
                        break;
                }
                if (j == sizeof(addr.ip6.s6_addr))
-                   return(TRUE);
+                   return TRUE;
 #endif /* HAVE_IN6_ADDR */
        }
     }
 
-    return(FALSE);
+    return FALSE;
 }
 
 /*
@@ -745,7 +762,7 @@ addr_matches(n)
     } else
        retval = addr_matches_if(n);
 
-    return(retval);
+    return retval;
 }
 
 /*
@@ -759,14 +776,14 @@ hostname_matches(shost, lhost, pattern)
 {
     if (has_meta(pattern)) {
        if (strchr(pattern, '.'))
-           return(!fnmatch(pattern, lhost, FNM_CASEFOLD));
+           return !fnmatch(pattern, lhost, FNM_CASEFOLD);
        else
-           return(!fnmatch(pattern, shost, FNM_CASEFOLD));
+           return !fnmatch(pattern, shost, FNM_CASEFOLD);
     } else {
        if (strchr(pattern, '.'))
-           return(!strcasecmp(lhost, pattern));
+           return !strcasecmp(lhost, pattern);
        else
-           return(!strcasecmp(shost, pattern));
+           return !strcasecmp(shost, pattern);
     }
 }
 
@@ -783,9 +800,9 @@ userpw_matches(sudoers_user, user, pw)
     if (pw != NULL && *sudoers_user == '#') {
        uid_t uid = (uid_t) atoi(sudoers_user + 1);
        if (uid == pw->pw_uid)
-           return(TRUE);
+           return TRUE;
     }
-    return(strcmp(sudoers_user, user) == 0);
+    return strcmp(sudoers_user, user) == 0;
 }
 
 /*
@@ -800,9 +817,9 @@ group_matches(sudoers_group, gr)
     if (*sudoers_group == '#') {
        gid_t gid = (gid_t) atoi(sudoers_group + 1);
        if (gid == gr->gr_gid)
-           return(TRUE);
+           return TRUE;
     }
-    return(strcmp(gr->gr_name, sudoers_group) == 0);
+    return strcmp(gr->gr_name, sudoers_group) == 0;
 }
 
 /*
@@ -815,30 +832,46 @@ usergr_matches(group, user, pw)
     char *user;
     struct passwd *pw;
 {
+    int matched = FALSE;
+    struct passwd *pw0 = NULL;
+
     /* make sure we have a valid usergroup, sudo style */
     if (*group++ != '%')
-       return(FALSE);
+       goto done;
 
 #ifdef USING_NONUNIX_GROUPS
-    if (*group == ':')
-       return(sudo_nonunix_groupcheck(++group, user, pw));   
+    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 && (pw = sudo_getpwnam(user)) == NULL)
-       return(FALSE);
+    if (pw == NULL) {
+       if ((pw0 = sudo_getpwnam(user)) == NULL)
+           goto done;
+       pw = pw0;
+    }
 
-    if (user_in_group(pw, group))
-       return(TRUE);
+    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))
-       return(TRUE);
+       sudo_nonunix_groupcheck(group, user, pw)) {
+       matched = TRUE;
+       goto done;
+    }
 #endif /* USING_NONUNIX_GROUPS */
 
-    return(FALSE);
+done:
+    if (pw0 != NULL)
+       pw_delref(pw0);
+
+    return matched;
 }
 
 /*
@@ -862,7 +895,7 @@ netgr_matches(netgr, lhost, shost, user)
 
     /* make sure we have a valid netgroup, sudo style */
     if (*netgr++ != '+')
-       return(FALSE);
+       return FALSE;
 
 #ifdef HAVE_GETDOMAINNAME
     /* get the domain name (if any) */
@@ -878,10 +911,10 @@ netgr_matches(netgr, lhost, shost, user)
 
 #ifdef HAVE_INNETGR
     if (innetgr(netgr, lhost, user, domain))
-       return(TRUE);
+       return TRUE;
     else if (lhost != shost && innetgr(netgr, shost, user, domain))
-       return(TRUE);
+       return TRUE;
 #endif /* HAVE_INNETGR */
 
-    return(FALSE);
+    return FALSE;
 }
index 35e07de5f0464ffeefbba7532359067112e5eb40..425fcb47d04b2b1d8d7eeae10dd1c16f0985be7e 100644 (file)
--- a/memrchr.c
+++ b/memrchr.c
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
 #include <config.h>
-#include <compat.h>
+
+#include <sys/types.h>
+
+#include "missing.h"
 
 /*
  * Reverse memchr()
@@ -34,8 +36,8 @@ memrchr(s, c, n)
        cp = (unsigned char *)s + n;
        do {
            if (*(--cp) == (unsigned char)c)
-               return((void *)cp);
+               return (void *)cp;
        } while (--n != 0);
     }
-    return((void *)0);
+    return (void *)0;
 }
index 749323a94ce725097294e034529b8491219d3b5b..7b2d29d1bd78d43c1faef1c2073187daa727d9cb 100644 (file)
--- a/missing.h
+++ b/missing.h
@@ -1,5 +1,6 @@
 /*
- * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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
  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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;
diff --git a/mkpkg b/mkpkg
index ae4135681715b832d0c8a481995a134ac14229a1..12c1d849c443ae1452e54362fcf2bc4d0b6bce23 100755 (executable)
--- a/mkpkg
+++ b/mkpkg
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
 # Build a binary package using polypkg
-# Usage: mkpkg [--debug] [--flavor flavor] [--platform platform]
+# Usage: mkpkg [--debug] [--flavor flavor] [--platform platform] [--osversion ver]
 #
 
 # Make sure IFS is set to space, tab, newline in that order.
@@ -12,9 +12,10 @@ nl='
 IFS="  $nl"
 
 # Parse arguments
-usage="usage: mkpkg [--debug] [--flavor flavor] [--platform platform]"
+usage="usage: mkpkg [--debug] [--flavor flavor] [--platform platform] [--osversion ver]"
 debug=0
 flavor=vanilla
+crossbuild=false
 while test $# -gt 0; do
     case "$1" in
        --debug)
@@ -47,6 +48,22 @@ while test $# -gt 0; do
            PPFLAGS="${PPFLAGS}${PPFLAGS+$space}--platform $2"
            shift
            ;;
+       --osversion=?*)
+           arg=`echo "$1" | sed -n 's/^--osversion=\(.*\)/\1/p'`
+           osversion="$arg"
+           ;;
+       --osversion)
+           if [ $# -lt 2 ]; then
+               echo "$usage" 1>&2
+               exit 1
+           fi
+           osversion="$2"
+           shift
+           ;;
+       --build|--host)
+           crossbuild=true
+           configure_opts="${configure_opts}${configure_opts+$tab}$1"
+           ;;
        *)
            # Pass unknown options to configure
            configure_opts="${configure_opts}${configure_opts+$tab}$1"
@@ -57,15 +74,16 @@ done
 
 top_srcdir=`dirname $0`
 
-platform=`$top_srcdir/pp --probe` || exit 1
-osrelease=`echo "$platform" | sed -e 's/^[^0-9]*//' -e 's/-.*$//'`
+: ${osversion="`$top_srcdir/pp --probe`"}
+test -n "$osversion" || exit 1
+osrelease=`echo "$osversion" | sed -e 's/^[^0-9]*//' -e 's/-.*$//'`
 
 # Default paths
 prefix=/usr/local
 
 # Linux distros may build binaries as pie files.
 # This is really something libtool should figure out, but it does not.
-case "$platform" in
+case "$osversion" in
     *-s390*|*-sparc*|*-alpha*)
        F_PIE=-fPIE
        ;;
@@ -74,30 +92,40 @@ case "$platform" in
        ;;
 esac
 
-# Choose compiler options by platform.
-case "$platform" in
-    hpux*)
-       # Use the HP ANSI C compiler on HP-UX if possible
-       if [ -z "$CC" -a -x /opt/ansic/bin/cc ]; then
-           CC=/opt/ansic/bin/cc; export CC
-           if [ -z "$CFLAGS" ]; then
-               CFLAGS=-O; export CFLAGS
+# Choose compiler options by osversion if not cross-compiling.
+if [ "$crossbuild" = "false" ]; then
+    case "$osversion" in
+       hpux*)
+           # Use the HP ANSI C compiler on HP-UX if possible
+           if [ -z "$CC" -a -x /opt/ansic/bin/cc ]; then
+               CC=/opt/ansic/bin/cc; export CC
+               if [ -z "$CFLAGS" ]; then
+                   CFLAGS=-O; export CFLAGS
+               fi
            fi
-       else
-           configure_opts="${configure_opts}${configure_opts+$tab}--disable-zlib"
-       fi
-       ;;
-esac
+           ;;
+       sol[0-9]*)
+           # Use the Sun Studio C compiler on Solaris if possible
+           if [ -z "$CC" -a -x /usr/bin/cc ]; then
+               CC=/usr/bin/cc; export CC
+               if [ -z "$CFLAGS" ]; then
+                   CFLAGS=-O; export CFLAGS
+               fi
+           fi
+           ;;
+    esac
+fi
 
-# Choose configure options by platform.
+# Choose configure options by osversion.
 # We use the same configure options as vendor packages when possible.
-case "$platform" in
+case "$osversion" in
     centos*|rhel*)
        prefix=/usr
        if [ $osrelease -ge 50 ]; then
            # RHEL 5 and up build pies and have audit support
-           export CFLAGS="$F_PIE" LDFLAGS="-pie"
+           export CFLAGS="-O2 $F_PIE" LDFLAGS="-pie"
            configure_opts="${configure_opts}${configure_opts+$tab}--with-linux-audit"
+           PPVARS="${PPVARS}${PPVARS+$space}linux_audit=1.4.0"
        fi
        # Note, must indent with tabs, not spaces due to IFS trickery
        configure_opts="$configure_opts
@@ -106,7 +134,7 @@ case "$platform" in
                --with-logfac=authpriv
                --with-pam
                --with-pam-login
-               --enable-zlib
+               --enable-zlib=system
                --with-editor=/bin/vi
                --with-env-editor
                --with-ignore-dot
@@ -119,14 +147,14 @@ case "$platform" in
        prefix=/usr
        if [ $osrelease -ge 10 ]; then
            # SLES 10 and higher build pies
-           export CFLAGS="$F_PIE" LDFLAGS="-pie"
+           export CFLAGS="-O2 $F_PIE" LDFLAGS="-pie"
            if [ $osrelease -ge 11 ]; then
                # SLES 11 and higher has SELinux
                configure_opts="${configure_opts}${configure_opts+$tab}--with-selinux"
            fi
        fi
        # SuSE doesn't have /usr/libexec
-       case "$platform" in
+       case "$osversion" in
            *64*)       libexec=lib64;;
            *)          libexec=lib;;
        esac
@@ -143,7 +171,7 @@ case "$platform" in
                --enable-shell-sets-home
                --with-sudoers-mode=0440
                --with-pam
-               --enable-zlib
+               --enable-zlib=system
                --with-ldap
                --with-env-editor
                --with-passprompt=%p\'s password: "
@@ -153,7 +181,7 @@ case "$platform" in
     deb*|ubu*)
        prefix=/usr
        # If Ubuntu, add --enable-admin-flag
-       case "$platform" in
+       case "$osversion" in
            ubu*)
                configure_opts="${configure_opts}${configure_opts+$tab}--enable-admin-flag${tab}--without-lecture"
                ;;
@@ -168,7 +196,7 @@ case "$platform" in
                --with-all-insults
                --with-exempt=sudo
                --with-pam
-               --enable-zlib
+               --enable-zlib=system
                --with-fqdn
                --with-logging=syslog
                --with-logfac=authpriv
@@ -186,6 +214,12 @@ case "$platform" in
                --with-secure-path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin"
        ;;
     *)
+       # For Solaris, add project support and use let configure choose zlib.
+       # For all others, use the builtin zlib.
+       case "$osversion" in
+           sol*) configure_opts="${configure_opts}${configure_opts+$tab}--with-project";;
+           *) configure_opts="${configure_opts}${configure_opts+$tab}--enable-zlib=builtin";;
+       esac
        if test "$flavor" = "ldap"; then
            configure_opts="${configure_opts}${configure_opts+$tab}--with-ldap"
        fi
index 09b141419a8bd2ae0d98d9dbc316565e05cec00a..f5cfbc158e8f2ab93eca0971fb62eadba88dd8e8 100644 (file)
@@ -17,6 +17,8 @@
 
 #include <config.h>
 
+#include <sys/types.h>
+
 #include <stdio.h>
 #ifdef STDC_HEADERS
 # include <stdlib.h>
@@ -28,7 +30,7 @@
 #endif /* STDC_HEADERS */
 #include <signal.h>
 
-#include <compat.h>
+#include "missing.h"
 
 int
 main(argc, argv)
@@ -42,7 +44,7 @@ main(argc, argv)
 
     printf("#include <config.h>\n");
     printf("#include <signal.h>\n");
-    printf("#include <compat.h>\n\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) {
index 7245f1972d2d9b7e9b57f9a5f86f25f4f20bae42..b3b688d7baf88cf2df9f75129a0348cbb4be91cb 100644 (file)
@@ -15,7 +15,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -62,7 +62,7 @@ mkstemps(path, slen)
                ;
        if (path + slen >= ep) {
                errno = EINVAL;
-               return(-1);
+               return -1;
        }
        ep -= slen;
 
@@ -81,11 +81,11 @@ mkstemps(path, slen)
 
                fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
                if (fd != -1 || errno != EEXIST)
-                       return(fd);
+                       return fd;
        } while (--tries);
 
        errno = EEXIST;
-       return(-1);
+       return -1;
 }
 
 #ifdef HAVE_RANDOM
@@ -129,5 +129,5 @@ get_random()
                initialized = 1;
        }
 
-       return(RAND() & 0xffffffff);
+       return RAND() & 0xffffffff;
 }
index ae2208b95e39ee0e5c9607a115646f1c8ed9c2d0..1849eb2cd9b633c0d6e96c1d9b2dd91286870196 100644 (file)
 # include <time.h>
 #endif
 #ifndef HAVE_TIMESPEC
-# include <emul/timespec.h>
+# include "emul/timespec.h"
 #endif
 #include <errno.h>
 
-#include "compat.h"
+#include "missing.h"
 
 int
 nanosleep(ts, rts)
@@ -52,5 +52,5 @@ nanosleep(ts, rts)
        rts->tv_sec = endtime.tv_sec;
        rts->tv_nsec = endtime.tv_usec * 1000;
     }
-    return(rval);
+    return rval;
 }
diff --git a/parse.c b/parse.c
index 97aba79ccaa4e1f3815a9fe14e2d8239e73c6e30..acf8e5fdc8145b4a213558d446e47d917529a0bc 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -83,9 +83,9 @@ sudo_file_open(nss)
     struct sudo_nss *nss;
 {
     if (def_ignore_local_sudoers)
-       return(-1);
+       return -1;
     nss->handle = open_sudoers(_PATH_SUDOERS, FALSE, NULL);
-    return(nss->handle ? 0 : -1);
+    return nss->handle ? 0 : -1;
 }
 
 int
@@ -99,7 +99,7 @@ sudo_file_close(nss)
        nss->handle = NULL;
        yyin = NULL;
     }
-    return(0);
+    return 0;
 }
 
 /*
@@ -110,16 +110,16 @@ sudo_file_parse(nss)
     struct sudo_nss *nss;
 {
     if (nss->handle == NULL)
-       return(-1);
+       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 -1;
     }
-    return(0);
+    return 0;
 }
 
 /*
@@ -130,11 +130,11 @@ sudo_file_setdefs(nss)
     struct sudo_nss *nss;
 {
     if (nss->handle == NULL)
-       return(-1);
+       return -1;
 
     if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER))
-       return(-1);
-    return(0);
+       return -1;
+    return 0;
 }
 
 /*
@@ -154,7 +154,7 @@ sudo_file_lookup(nss, validated, pwflag)
     struct userspec *us;
 
     if (nss->handle == NULL)
-       return(validated);
+       return validated;
 
     /*
      * Only check the actual command if pwflag is not set.
@@ -200,7 +200,7 @@ sudo_file_lookup(nss, validated, pwflag)
            SET(validated, FLAG_CHECK_USER);
        else if (pwcheck == never || nopass == TRUE)
            def_authenticate = FALSE;
-       return(validated);
+       return validated;
     }
 
     /* Need to be runas user while stat'ing things. */
@@ -259,7 +259,7 @@ sudo_file_lookup(nss, validated, pwflag)
        CLR(validated, VALIDATE_OK);
     }
     set_perms(PERM_ROOT);
-    return(validated);
+    return validated;
 }
 
 #define        TAG_CHANGED(t) \
@@ -361,7 +361,7 @@ sudo_file_display_priv_short(pw, us, lbuf)
        }
        lbuf_append(lbuf, "\n", NULL);
     }
-    return(nfound);
+    return nfound;
 }
 
 static int
@@ -416,7 +416,7 @@ sudo_file_display_priv_long(pw, us, lbuf)
            nfound++;
        }
     }
-    return(nfound);
+    return nfound;
 }
 
 int
@@ -441,7 +441,7 @@ sudo_file_display_privs(nss, pw, lbuf)
            nfound += sudo_file_display_priv_short(pw, us, lbuf);
     }
 done:
-    return(nfound);
+    return nfound;
 }
 
 /*
@@ -495,7 +495,7 @@ sudo_file_display_defaults(nss, pw, lbuf)
        nfound++;
     }
 done:
-    return(nfound);
+    return nfound;
 }
 
 /*
@@ -513,7 +513,7 @@ sudo_file_display_bound_defaults(nss, pw, lbuf)
     nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf);
     nfound += display_bound_defaults(DEFAULTS_CMND, lbuf);
 
-    return(nfound);
+    return nfound;
 }
 
 /*
@@ -551,7 +551,7 @@ display_bound_defaults(dtype, lbuf)
            dsep = "!";
            break;
        default:
-           return(-1);
+           return -1;
     }
     /* printf("Per-%s Defaults entries:\n", dname); */
     tq_foreach_fwd(&defaults, d) {
@@ -579,7 +579,7 @@ display_bound_defaults(dtype, lbuf)
            lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL);
     }
 
-    return(nfound);
+    return nfound;
 }
 
 int
@@ -612,8 +612,7 @@ sudo_file_display_cmnd(nss, pw)
                if (runas_match == ALLOW) {
                    cmnd_match = cmnd_matches(cs->cmnd);
                    if (cmnd_match != UNSPEC) {
-                       match = host_match && runas_match ?
-                           cs->cmnd : NULL;
+                       match = host_match && runas_match ? cs->cmnd : NULL;
                        goto matched;
                    }
                }
@@ -627,7 +626,7 @@ sudo_file_display_cmnd(nss, pw)
        rval = 0;
     }
 done:
-    return(rval);
+    return rval;
 }
 
 /*
index 3611b443de5c3a8d6eab69266d532d05233667ce..ee4245b25c8d4b903c8c31c246af59e769399583 100644 (file)
@@ -51,8 +51,7 @@
 /*
  * Local functions
  */
-static void usage_excl                 __P((int))
-                                           __attribute__((__noreturn__));
+static void usage_excl                 __P((int));
 
 /*
  * For sudo.c
@@ -122,7 +121,7 @@ parse_args(argc, argv)
                    break;
                case 'C':
                    if ((user_closefrom = atoi(optarg)) < 3) {
-                       warningx("the argument to -C must be at least 3");
+                       warningx("the argument to -C must be a number greater than or equal to 3");
                        usage(1);
                    }
                    break;
@@ -303,23 +302,30 @@ parse_args(argc, argv)
     if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL))
        SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
 
-    return(mode | flags);
+    return mode | flags;
 }
 
 static int
-usage_out(buf)
+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(exit_val)
-    int exit_val;
+usage(fatal)
+    int fatal;
 {
     struct lbuf lbuf;
     char *uvec[6];
@@ -345,22 +351,114 @@ usage(exit_val)
      * tty width.
      */
     ulen = (int)strlen(getprogname()) + 8;
-    lbuf_init(&lbuf, usage_out, ulen, NULL);
+    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);
-    exit(exit_val);
+    if (fatal)
+       exit(1);
 }
 
 /*
  * Tell which options are mutually exclusive and exit.
  */
 static void
-usage_excl(exit_val)
-    int exit_val;
+usage_excl(fatal)
+    int fatal;
 {
     warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified");
-    usage(exit_val);
+    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);
 }
diff --git a/pp b/pp
index 2776485b663b7c2a5e82fd2e9c94a71066e53c8a..a7267c9193623cf4d572de8b619de7080957a114 100755 (executable)
--- a/pp
+++ b/pp
@@ -1,6 +1,6 @@
 #!/bin/sh
-# (c) 2010 Quest Software, Inc. All rights reserved
-pp_revision="283"
+# (c) 2011 Quest Software, Inc. All rights reserved
+pp_revision="305"
  # Copyright 2010 Quest Software, Inc.  All rights reserved.
  #
  # Redistribution and use in source and binary forms, with or without
@@ -1554,6 +1554,8 @@ pp_backend_aix_init () {
         pp_aix_start_services_after_install=false
         pp_aix_init_services_after_install=true
 
+        pp_aix_sudo=sudo       # AIX package tools must run as root
+
         case "$pp_aix_os" in
             *) pp_readlink_fn=pp_ls_readlink;;  # XXX
         esac
@@ -1688,8 +1690,6 @@ pp_aix_inventory () {
       esac
       echo " type = $type"
       echo " class = inventory,apply,$fileset"
-      set -- `/bin/ls -ld "$pp_destdir$p" 2>/dev/null`
-      owner=$3 group=$4 size=$5
       if test x"$m" = x"-"; then m="$defm"; fi
       if test x"$o" = x"-"; then o="root"; fi
       if test x"$g" = x"-"; then g="system"; fi
@@ -2043,7 +2043,7 @@ pp_backend_aix () {
        (cd $pp_destdir && pp_verbose  /usr/sbin/backup -i -q -p -f -) \
           < $pp_wrkdir/bff.list \
          > $pp_wrkdir/$outbff || pp_error "backup failed"
-        ${SUDO:-sudo} /usr/sbin/installp -l -d $pp_wrkdir/$outbff
+        $pp_aix_sudo /usr/sbin/installp -l -d $pp_wrkdir/$outbff
 }
 
 pp_backend_aix_cleanup () {
@@ -2224,6 +2224,7 @@ pp_backend_sd_init () {
     pp_sd_default_start=1           # config_file default start value
 
     pp_readlink_fn=pp_ls_readlink   # HPUX has no readlink
+    pp_shlib_suffix='.sl'           # .so on most other platforms
 
     pp_sd_detect_os
 }
@@ -2249,11 +2250,21 @@ pp_sd_write_files () {
     while read t m o g f p st; do
         line="                file"
         case "$f" in *v*) line="$line -v";; esac    # FIXME for uninstall
-        case $t in
-            f) dm=644;;
-            d) line="$line -t d"; p=${p%/}; dm=755;;
-            s) line="$line -t s";;
-        esac
+       case ${pp_sd_os} in
+           10.*)
+               case $t in
+                   f) dm=644;;
+                   d) p=${p%/}; dm=755;;
+               esac
+               ;;
+           *)
+               case $t in
+                   f) dm=644;;
+                   d) line="$line -t d"; p=${p%/}; dm=755;;
+                   s) line="$line -t s";;
+               esac
+               ;;
+       esac
 
         test x"$o" = x"-" && o=root
         test x"$g" = x"-" && g=sys
@@ -2439,11 +2450,16 @@ pp_sd_service_script () {
 
 pp_sd_make_service () {
         typeset level startpriority stoppriority startlevels stoplevels
-        typeset svc svcvar
+        typeset svc svcvar symtype
 
         svc="$1"
        svcvar=`pp_makevar $svc`
 
+       case ${pp_sd_os} in
+           10.*) symtype="file";;
+           *) symtype="file -t s";;
+       esac
+
         # TODO: Figure out why this check is here
         #-- don't do anything if the script exists
         #if test -s "$pp_destdir/sbin/init.d/$svc"; then
@@ -2487,12 +2503,12 @@ pp_sd_make_service () {
 
         # create the symlinks
         test -z "$startlevels" || for level in $startlevels; do
-            echo "                file -t s" \
+            echo "                ${symtype}" \
                     "/sbin/init.d/$svc" \
                     "/sbin/rc$level.d/S$startpriority$svc"
         done
         test -z "$stoplevels" || for level in $stoplevels; do
-            echo "                file -t s" \
+            echo "                ${symtype}" \
                     "/sbin/init.d/$svc" \
                     "/sbin/rc$level.d/K$stoppriority$svc"
         done
@@ -2514,9 +2530,10 @@ pp_sd_control () {
 }
 
 pp_backend_sd () {
-    typeset psf cpt svc outfile
+    typeset psf cpt svc outfile release swp_flags
 
     psf=$pp_wrkdir/psf
+    release="?.${pp_sd_os%.[0-9][0-9]}.*"
 
     echo "depot" > $psf
     echo "layout_version 1.0" >>$psf
@@ -2537,7 +2554,7 @@ pp_backend_sd () {
             copyright       "$copyright"
             machine_type    *
             os_name         HP-UX
-            os_release      ?.11.*
+            os_release      $release
             os_version      ?
             directory       /
             is_locatable    false
@@ -2618,10 +2635,15 @@ pp_backend_sd () {
     test -s $pp_wrkdir/%fixup && . $pp_wrkdir/%fixup
 
     outfile=`pp_backend_sd_names`
-    if pp_verbose ${pp_sd_sudo} /usr/sbin/swpackage \
-        -s $psf \
-        -x run_as_superuser=false \
-        -x media_type=tape \
+    case ${pp_sd_os} in
+       10.*)
+           swp_flags="-x target_type=tape"
+           ;;
+       *)
+           swp_flags="-x media_type=tape"
+           ;;
+    esac
+    if pp_verbose ${pp_sd_sudo} /usr/sbin/swpackage -s $psf $swp_flags \
         @ $pp_wrkdir/$outfile
     then
         pp_verbose ${pp_sd_sudo} /usr/sbin/swlist -l file -s $pp_wrkdir/$outfile
@@ -2753,7 +2775,9 @@ pp_backend_solaris_init () {
        pp_solaris_category=
        pp_solaris_istates="s S 1 2 3"  # run-states when install is ok
        pp_solaris_rstates="s S 1 2 3"  # run-states when remove is ok
+       pp_solaris_maxinst=
        pp_solaris_vendor=
+       pp_solaris_pstamp=
        pp_solaris_copyright=
        pp_solaris_name=
        pp_solaris_desc=
@@ -2982,8 +3006,12 @@ pp_backend_solaris () {
          echo "RSTATES=$pp_solaris_rstates" >> $pkginfo
        test -n "$pp_solaris_istates" &&
          echo "ISTATES=$pp_solaris_istates" >> $pkginfo
+       test -n "$pp_solaris_maxinst" &&
+         echo "MAXINST=$pp_solaris_maxinst" >> $pkginfo
        test -n "${pp_solaris_vendor:-$vendor}" &&
          echo "VENDOR=${pp_solaris_vendor:-$vendor}" >> $pkginfo
+       test -n "$pp_solaris_pstamp" &&
+         echo "PSTAMP=$pp_solaris_pstamp" >> $pkginfo
 
        if test -n "${pp_solaris_copyright:-$copyright}"; then
            echo "${pp_solaris_copyright:-$copyright}" > $pp_wrkdir/copyright
@@ -3028,11 +3056,11 @@ pp_backend_solaris () {
         test -n "$pp_services" &&
             for _svc in $pp_services; do
                 pp_load_service_vars $_svc
+                pp_solaris_smf $_svc
                 pp_solaris_make_service $_svc
                 pp_solaris_install_service $_svc | pp_prepend $pp_wrkdir/postinstall
-                pp_prepend $pp_wrkdir/preremove <<-.
-                    /etc/init.d/$_svc stop >/dev/null 2>/dev/null
-.
+                pp_solaris_remove_service $_svc | pp_prepend $pp_wrkdir/preremove
+                unset pp_svc_xml_file
             done
 
         test -n "$pp_service_groups" &&
@@ -3110,9 +3138,9 @@ if $pp_opt_debug; then
   echo "$prototype::"; cat $prototype
 fi >&2
 
-       pkgmk -a $pp_solaris_arch -d $pp_wrkdir/pkg \
-             -f $prototype || { error "pkgmk failed"; return; }
-        pkgtrans -s $pp_wrkdir/pkg \
+       pkgmk -d $pp_wrkdir/pkg -f $prototype \
+               || { error "pkgmk failed"; return; }
+       pkgtrans -s $pp_wrkdir/pkg \
                $pp_wrkdir/`pp_backend_solaris_names` \
                 ${pp_solaris_name:-$name} \
                || { error "pkgtrans failed"; return; }
@@ -3284,12 +3312,12 @@ pp_backend_solaris_function() {
 }
 
 pp_backend_solaris_init_svc_vars () {
-    pp_solaris_smf_category=
+    _smf_category=${pp_solaris_smf_category:-application}
+    _smf_method_envvar_name=${smf_method_envvar_name:-"PP_SMF_SERVICE"}
     pp_solaris_service_shell=/sbin/sh
 }
 
 pp_solaris_init_svc () {
-    smf_category=${pp_solaris_smf_category:-application}
     smf_version=1
     smf_type=service
     solaris_user=
@@ -3307,40 +3335,116 @@ pp_solaris_init_svc () {
 }
 
 pp_solaris_smf () {
-    typeset f
-    f=/var/svc/manifest/$smf_category/$1
+    typeset f _pp_solaris_service_script svc _pp_solaris_manpage
+
+    pp_solaris_name=${pp_solaris_name:-$name}
+    pp_solaris_manpath=${pp_solaris_manpath:-"/usr/share/man"}
+    smf_start_timeout=${smf_start_timeout:-60}
+    smf_stop_timeout=${smf_stop_timeout:-60}
+    smf_restart_timeout=${smf_restart_timeout:-60}
+
+    svc=${pp_solaris_smf_service_name:-$1}
+    _pp_solaris_service_script=${pp_solaris_service_script:-"/etc/init.d/${pp_solaris_service_script_name:-$svc}"}
+    _pp_solaris_manpage=${pp_solaris_manpage:-$pp_solaris_smf_service_name}
+
+    if [ -z $pp_svc_xml_file ]; then
+        pp_svc_xml_file="/var/svc/manifest/$_smf_category/$svc.xml"
+        echo "## Generating the smf service manifest file for $pp_svc_xml_file"
+    else
+        echo "## SMF service manifest file already defined at $pp_svc_xml_file"
+        if [ -z $pp_solaris_smf_service_name ] || [ -z $pp_solaris_smf_category ] || [ -z $pp_solaris_service_script ] || [ -z $smf_method_envvar_name ]; then
+          pp_error "All required variables are not set.\n"\
+                   "When using a custom manifest file all of the following variables must be set:\n"\
+                   "pp_solaris_smf_service_name, pp_solaris_smf_category, pp_solaris_service_script and smf_method_envvar_name.\n\n"\
+                   "Example:\n"\
+                   " \$pp_solaris_smf_category=application\n"\
+                   " \$pp_solaris_smf_service_name=pp\n\n"\
+                   "  <service name='application/pp' type='service' version='1'>\n\n"\
+                   "Example:\n"\
+                   " \$pp_solaris_service_script=/etc/init.d/pp\n\n"\
+                   "  <exec_method type='method' name='start' exec='/etc/init.d/pp' />\n\n"\
+                   "Example:\n"\
+                   " \$smf_method_envvar_name=PP_SMF_SERVICE\n\n"\
+                   "  <method_environment>\n"\
+                   "    <envvar name='PP_SMF_SERVICE' value='1'/>\n"\
+                   "  </method_environment>\n"
+
+          return 1
+        fi
+        return 0
+    fi
+
+    f=$pp_svc_xml_file
     pp_add_file_if_missing $f ||
         return 0
 
-    cat <<-. >$pp_destdir$f
-       <?xml version="1.0"?>
-        <!--
-            $copyright
-            Generated by PolyPackage $pp_version
-       -->
-
-        <service name='$smf_category/$1'
-                 type='$smf_type'
-                 version='$smf_version'>
-
-            <single_instance />
-
-            <exec_method type='method' name='start'
-                exec=''
-                timeout_seconds='60'>
-                <method_context>
-                  <method_credential user='${solaris_user:-$user}' />
-                </method_context>
-            </exec>
-
-            <exec_method type='method' name='stop'
-                exec=':kill -${solaris_stop_signal:-$stop_signal}'>
-                <method_context>
-                  <method_credential user='${solaris_user:-$user}' />
-                </method_context>
-            </exec>
+    _pp_solaris_smf_dependencies="
+          <dependency name='pp_local_filesystems'
+                grouping='require_all'
+                restart_on='none'
+                type='service'>
+                <service_fmri value='svc:/system/filesystem/local'/>
+          </dependency>
+
+          <dependency name='pp_single-user'
+                grouping='require_all'
+                restart_on='none'
+                type='service'>
+                <service_fmri value='svc:/milestone/single-user' />
+          </dependency>
+"
+    _pp_solaris_smf_dependencies=${pp_solaris_smf_dependencies:-$_pp_solaris_smf_dependencies}
 
+    cat <<-. >$pp_destdir$f
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
+<!--
+       $copyright
+        Generated by PolyPackage $pp_version
+-->
+
+    <service_bundle type='manifest' name='${pp_solaris_name}:${svc}' >
+          <service name='$_smf_category/$svc'
+                type='$smf_type'
+                version='$smf_version'>
+
+          <create_default_instance enabled='false'/>
+
+          <single_instance />
+
+          $_pp_solaris_smf_dependencies
+
+          $pp_solaris_smf_additional_dependencies
+
+          <method_context>
+                <method_credential user='${solaris_user:-$user}' />
+                <method_environment>
+                    <envvar name='$_smf_method_envvar_name' value='1'/>
+                </method_environment>
+          </method_context>
+
+          <exec_method type='method' name='start'
+                exec='$_pp_solaris_service_script start'
+                timeout_seconds='$smf_start_timeout' />
+
+          <exec_method type='method' name='stop'
+                exec='$_pp_solaris_service_script stop'
+                timeout_seconds='$smf_stop_timeout' />
+
+          <exec_method type='method' name='restart'
+                exec='$_pp_solaris_service_script restart'
+                timeout_seconds='$smf_restart_timeout' />
+
+          <template>
+              <common_name>
+                  <loctext xml:lang='C'>$description</loctext>
+              </common_name>
+              <documentation>
+                  <manpage title='$pp_solaris_manpage' section='1' manpath='$pp_solaris_manpath'/>
+              </documentation>
+          </template>
         </service>
+    </service_bundle>
 .
 }
 
@@ -3411,15 +3515,13 @@ pp_solaris_make_service_group () {
 .
 }
 
-
 pp_solaris_make_service () {
     typeset file out _cmd svc
 
-    svc="$1"
-    file="/etc/init.d/$svc"
+    svc="${pp_solaris_smf_service_name:-$1}"
+    file=${pp_solaris_service_script:-"/etc/init.d/${pp_solaris_service_script_name:-$svc}"}
     out="$pp_destdir$file"
 
-
     #-- return if we don't need to create the init script
     pp_add_file_if_missing "$file" run 755 ||
         return 0
@@ -3427,6 +3529,43 @@ pp_solaris_make_service () {
     echo "#! /sbin/sh" >$out
     echo "#-- This service init file generated by polypkg" >>$out
 
+    #-- Start SMF integration.
+    if [ -n "$pp_svc_xml_file" ] ; then
+        cat <<_EOF >>$out
+if [ -x /usr/sbin/svcadm ] && [ "x\$1" != "xstatus" ] && [ "t\$$_smf_method_envvar_name" = "t" ] ; then
+    case "\$1" in
+        start)
+            echo "starting $svc"
+            /usr/sbin/svcadm clear svc:/$_smf_category/$svc:default >/dev/null 2>&1
+            /usr/sbin/svcadm enable -s $_smf_category/$svc
+            RESULT=\$?
+            if [ "\$RESULT" -ne 0 ] ; then
+                echo "Error \$RESULT starting $svc"
+                fi
+            ;;
+        stop)
+            echo "stopping $svc"
+            /usr/sbin/svcadm disable -ts $_smf_category/$svc
+            ;;
+        restart)
+            echo "restarting $svc"
+            /usr/sbin/svcadm disable -ts $_smf_category/$svc
+            /usr/sbin/svcadm clear svc:/$_smf_category/$svc:default >/dev/null 2>&1
+            /usr/sbin/svcadm enable -s $_smf_category/$svc
+            RESULT=\$?
+            if [ "\$RESULT" -ne 0 ] ; then
+                echo "Error \$RESULT starting $svc"
+                    fi
+                    ;;
+        *)
+            echo "Usage: $file {start|stop|restart|status}"
+            exit 1
+    esac
+    exit 0
+fi
+_EOF
+    fi
+
     #-- construct a start command that builds a pid file as needed
     #   and forks the daemon
     _cmd="$cmd";
@@ -3528,13 +3667,33 @@ pp_solaris_make_service () {
 .
 }
 
+pp_solaris_remove_service () {
+    typeset file svc
+
+    svc="${pp_solaris_smf_service_name:-$1}"
+    file=${pp_solaris_service_script:-"/etc/init.d/${pp_solaris_service_script_name:-$svc}"}
+
+    echo '
+'$file' stop >/dev/null 2>/dev/null
+if [ "x${PKG_INSTALL_ROOT}" = 'x' ]; then
+    if [ -x /usr/sbin/svcadm ] ; then
+        # Likely un-needed, but just in case.
+        /usr/sbin/svcadm disable -s '$svc' 2>/dev/null
+        /usr/sbin/svccfg delete '$svc' 2>/dev/null
+    fi
+fi
+    '
+}
 
 pp_solaris_install_service () {
-    typeset s k l
-    s="${solaris_sysv_init_start}$1"
-    k="${solaris_sysv_init_kill}$1"
+    typeset s k l file svc
+
+    svc="${pp_solaris_smf_service_name:-$1}"
+    file=${pp_solaris_service_script:-"/etc/init.d/${pp_solaris_service_script_name:-$svc}"}
+
+    s="${solaris_sysv_init_start}$svc"
+    k="${solaris_sysv_init_kill}$svc"
 
-    echo 'case " $SERVICES " in *" '$1' "*)'
     echo '
 if [ "x${PKG_INSTALL_ROOT}" != "x" ]; then
   if [ -x ${PKG_INSTALL_ROOT}/usr/sbin/svcadm ]; then
@@ -3544,41 +3703,42 @@ if [ "x${PKG_INSTALL_ROOT}" != "x" ]; then
         for state in ${solaris_sysv_init_start_states}; do
             l="/etc/rc$state.d/$s"
             echo "echo '$l'"
-            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=../init.d/$1 s"
+            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=$file s"
             pp_solaris_space /etc/rc$state.d 0 1
         done
     test -n "${solaris_sysv_init_kill_states}" &&
         for state in ${solaris_sysv_init_kill_states}; do
             l="/etc/rc$state.d/$k"
             echo "echo '$l'"
-            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=../init.d/$1 s"
+            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=$file s"
             pp_solaris_space /etc/rc$state.d 0 1
         done
     echo '
   fi
 else
     if [ -x /usr/sbin/svcadm ]; then
-        echo "Registering '$1' with SMF"
-        /usr/sbin/svcadm disable -s '$1' 2>/dev/null
-        /usr/sbin/svccfg delete '$1' 2>/dev/null
-        /usr/sbin/svccfg import '$pp_svc_xml_file' 2>/dev/null
+        echo "Registering '$svc' with SMF"
+        /usr/sbin/svcadm disable -s '$svc' 2>/dev/null
+        /usr/sbin/svccfg delete '$svc' 2>/dev/null
+        /usr/sbin/svccfg import '$pp_svc_xml_file'
     else'
     test -n "${solaris_sysv_init_start_states}" &&
         for state in ${solaris_sysv_init_start_states}; do
             l="/etc/rc$state.d/$s"
             echo "echo '$l'"
-            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=../init.d/$1 s"
+            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=$file s"
             pp_solaris_space /etc/rc$state.d 0 1
         done
     test -n "${solaris_sysv_init_kill_states}" &&
         for state in ${solaris_sysv_init_kill_states}; do
             l="/etc/rc$state.d/$k"
             echo "echo '$l'"
-            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=../init.d/$1 s"
+            echo "installf -c run \$PKGINST \$PKG_INSTALL_ROOT$l=$file s"
             pp_solaris_space /etc/rc$state.d 0 1
         done
-    echo " :;; esac"
-
+    echo '
+    fi
+fi'
 }
 
 pp_platforms="$pp_platforms deb"
@@ -3666,11 +3826,24 @@ pp_deb_detect_arch () {
    pp_deb_arch_std=`uname -m`
 }
 
+pp_deb_sanitize_version() {
+    echo "$@" | tr -d -c '[:alnum:].+-:~'
+}
+
+pp_deb_version_final() {
+    if test -n "$pp_deb_version"; then
+        # Don't sanitize; assume the user is sane (hah!)
+        echo "$pp_deb_version"
+    else
+        pp_deb_sanitize_version "$version"
+    fi
+}
+
 pp_deb_make_control() {
     package_name=`pp_deb_cmp_full_name "$1"`
     cat <<-.
        Package: ${package_name}
-       Version: ${pp_deb_version:-$version}-${pp_deb_release:-1}
+       Version: `pp_deb_version_final`-${pp_deb_release:-1}
        Section: ${pp_deb_section:-contrib}
        Priority: optional
        Architecture: ${pp_deb_arch}
@@ -3897,7 +4070,7 @@ pp_backend_deb_cleanup () {
 
 pp_deb_name () {
     local cmp="${1:-run}"
-    echo `pp_deb_cmp_full_name $cmp`"_${pp_deb_version:-$version}-${pp_deb_release:-1}_${pp_deb_arch}.deb"
+    echo `pp_deb_cmp_full_name $cmp`"_"`pp_deb_version_final`"-${pp_deb_release:-1}_${pp_deb_arch}.deb"
 }
 pp_backend_deb_names () {
     for cmp in $pp_components
@@ -5096,28 +5269,29 @@ pp_rpm_detect_arch () {
     rm $pp_wrkdir/dummy.spec
 
     #-- Ask the kernel what machine architecture is in use
-    local arch=`uname -p`
-    if [ "$arch" = "unknown" ]; then
-       arch=`uname -m`
-    fi
-
-    case "$arch" in
-       i?86)   pp_rpm_arch_std=i386;;
-       x86_64) pp_rpm_arch_std=x86_64;;
-       ppc)    pp_rpm_arch_std=ppc;;
-       ppc64)  pp_rpm_arch_std=ppc64;;
-       ia64)   pp_rpm_arch_std=ia64;;
-       s390)   pp_rpm_arch_std=s390;;
-       s390x)  pp_rpm_arch_std=s390x;;
-       powerpc)
+    local arch
+    for arch in "`uname -m`" "`uname -p`"; do
+       case "$arch" in
+           i?86)
+               pp_rpm_arch_std=i386
+               break
+               ;;
+           x86_64|ppc|ppc64|ia64|s390|s390x)
+               pp_rpm_arch_std="$arch"
+               break
+               ;;
+           powerpc)
                # Probably AIX
                case "`/usr/sbin/lsattr -El proc0 -a type -F value`" in
                    PowerPC_POWER*)     pp_rpm_arch_std=ppc64;;
                    *)                  pp_rpm_arch_std=ppc;;
                esac
+               break
                ;;
-       *)      pp_rpm_arch_std=unknown;;
-    esac
+           *)  pp_rpm_arch_std=unknown
+               ;;
+       esac
+    done
 
     #-- Later on, when files are processed, we use 'file' to determine
     #   what platform ABIs are used. This is used when pp_rpm_arch == auto
@@ -5130,6 +5304,15 @@ pp_rpm_detect_distro () {
        pp_rpm_distro=`awk '
           /^White Box Enterprise Linux release/ { print "wbel" $6; exit; }
        ' /etc/whitebox-release`
+    elif test -f /etc/mandrakelinux-release; then
+       pp_rpm_distro=`awk '
+          /^Mandrakelinux release/ { print "mand" $3; exit; }
+       ' /etc/mandrake-release`
+    elif test -f /etc/mandrake-release; then
+       pp_rpm_distro=`awk '
+          /^Linux Mandrake release/ { print "mand" $4; exit; }
+          /^Mandrake Linux release/ { print "mand" $4; exit; }
+       ' /etc/mandrake-release`
     elif test -f /etc/fedora-release; then
        pp_rpm_distro=`awk '
           /^Fedora Core release/ { print "fc" $4; exit; }
@@ -5150,6 +5333,10 @@ pp_rpm_detect_distro () {
           /^S[uU]SE LINUX Enterprise Server [0-9]/ { print "sles" $5; exit; }
           /^SuSE SLES-[0-9]/  { print "sles" substr($2,6); exit; }
        ' /etc/SuSE-release`
+    elif test -f /etc/pld-release; then
+       pp_rpm_distro=`awk '
+          /^[^ ]* PLD Linux/ { print "pld" $1; exit; }
+       ' /etc/pld-release`
     elif test X"`uname -s 2>/dev/null`" = X"AIX"; then
        local r v
        r=`uname -r`
@@ -5221,10 +5408,34 @@ pp_rpm_writefiles () {
                *"executable (RISC System/6000)"*)
                    farch=ppc;;
                *"64-bit XCOFF executable"*)
-                   fatch=ppc64;;
+                   farch=ppc64;;
+               *" ELF "*)
+                   farch=ELF;;
                *)
                    farch=noarch;;
            esac
+           # If file(1) doesn't provide enough info, try readelf(1)
+           if test "$farch" = "ELF"; then
+               fo=`readelf -h "${pp_destdir}$p" | awk '{if ($1 == "Class:") {class=$2} else if ($1 == "Machine:") {machine=$0; sub(/^ *Machine: */, "", machine)}} END {print class " " machine}' 2>/dev/null`
+               case "$fo" in
+                   "ELF32 Intel 80386")
+                       farch=i386;;
+                   "ELF64 "*[xX]"86-64")
+                       farch=x86_64;;
+                   "ELF32 PowerPC")
+                       farch=ppc;;
+                   "ELF64 PowerPC")
+                       farch=ppc64;;
+                   "ELF64 IA-64")
+                       farch=ia64;;
+                   "ELF32 IBM S/390")
+                       farch=s390;;
+                   "ELF64 IBM S/390")
+                       farch=s390x;;
+                   *)
+                       farch=noarch;;
+               esac
+           fi
            pp_debug "file: $fo -> $farch"
            test x"$farch" = x"noarch" || pp_add_to_list pp_rpm_arch_seen $farch
        fi
@@ -6244,6 +6455,9 @@ pp_backend_macos_init () {
     pp_macos_prog_packagemaker=/Developer/usr/bin/packagemaker
     pp_macos_pkg_domain=anywhere
     pp_macos_pkg_extra_flags=
+    pp_macos_sudo=
+    # OS X puts the library version *before* the .dylib extension
+    pp_shlib_suffix='*.dylib'
 }
 
 pp_macos_plist () {
@@ -6436,20 +6650,20 @@ pp_macos_mkbom () {
     bomstage=$pp_wrkdir/bom_stage
     while IFS='        ' read path mode ugid size cksumi linkpath; do
        if test -h "$pp_destdir/$path"; then
-           /bin/ln -s "$linkpath" "$bomstage/$path"
+           $pp_macos_sudo /bin/ln -s "$linkpath" "$bomstage/$path"
        else
            if test -d "$pp_destdir/$path"; then
-               /bin/mkdir -p "$bomstage/$path"
+               $pp_macos_sudo /bin/mkdir -p "$bomstage/$path"
            else
-               /bin/cp "$pp_destdir/$path" "$bomstage/$path"
+               $pp_macos_sudo /bin/cp "$pp_destdir/$path" "$bomstage/$path"
            fi
-           /bin/chmod $mode "$bomstage/$path"
-           /usr/sbin/chown `echo $ugid| tr / :` "$bomstage/$path"
+           $pp_macos_sudo /bin/chmod $mode "$bomstage/$path"
+           $pp_macos_sudo /usr/sbin/chown `echo $ugid| tr / :` "$bomstage/$path"
        fi
     done <"$1"
-    (cd $bomstage && mkbom . $pp_wrkdir/bom_stage.bom) ||
+    (cd $bomstage && $pp_macos_sudo mkbom . $pp_wrkdir/bom_stage.bom) ||
        pp_error "mkbom failed"
-    mv $pp_wrkdir/bom_stage.bom "$2"
+    $pp_macos_sudo mv $pp_wrkdir/bom_stage.bom "$2"
 }
 
 pp_backend_macos () {
@@ -6620,7 +6834,9 @@ CompressedSize 0
     cat $pp_wrkdir/%files.* | awk '{ print "." $6 }' | sed '/\/$/d' | sort | /bin/pax -w -f - | gzip -9 -c > $Contents/Archive.pax.gz
     )
 
-       rm -rf $pp_wrkdir/bom_stage
+       $pp_macos_sudo rm -rf $pp_wrkdir/bom_stage
+
+    hdiutil create -fs HFS+ -srcfolder $pkgdir -volname $name ${name}-${version}.dmg
 }
 
 pp_backend_macos_cleanup () {
index 86ae0ab2b92ebd16bf71fd27c5c72dd8060e7685..548da4d2d85eaaf97f3cd860acc15442fcf1361e 100644 (file)
--- a/pwutil.c
+++ b/pwutil.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 1998-2005, 2007-2010
+ * 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
@@ -63,7 +63,25 @@ static struct rbtree *grcache_bygid, *grcache_byname;
 static int  cmp_pwuid  __P((const void *, const void *));
 static int  cmp_pwnam  __P((const void *, const void *));
 static int  cmp_grgid  __P((const void *, const void *));
-static int  cmp_grnam  __P((const void *, const void *));
+
+#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.
@@ -73,9 +91,9 @@ cmp_pwuid(v1, v2)
     const void *v1;
     const void *v2;
 {
-    const struct passwd *pw1 = (const struct passwd *) v1;
-    const struct passwd *pw2 = (const struct passwd *) v2;
-    return(pw1->pw_uid - pw2->pw_uid);
+    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;
 }
 
 /*
@@ -86,9 +104,9 @@ cmp_pwnam(v1, v2)
     const void *v1;
     const void *v2;
 {
-    const struct passwd *pw1 = (const struct passwd *) v1;
-    const struct passwd *pw2 = (const struct passwd *) v2;
-    return(strcasecmp(pw1->pw_name, pw2->pw_name));
+    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)                    \
@@ -109,16 +127,22 @@ do {                                                      \
 } while (0)
 
 /*
- * Dynamically allocate space for a struct password and the constituent parts
- * that we care about.  Fills in pw_passwd from shadow file.
+ * 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 passwd *
-sudo_pwdup(pw)
+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. */
@@ -127,7 +151,7 @@ sudo_pwdup(pw)
 
     /* Allocate in one big chunk for easy freeing. */
     nsize = psize = csize = gsize = dsize = ssize = 0;
-    total = sizeof(struct passwd);
+    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
@@ -138,15 +162,19 @@ sudo_pwdup(pw)
     /* Treat shell specially since we expand "" -> _PATH_BSHELL */
     ssize = strlen(pw_shell) + 1;
     total += ssize;
+    if (name != NULL)
+       total += strlen(name) + 1;
 
-    if ((cp = malloc(total)) == NULL)
-           return(NULL);
-    newpw = (struct passwd *) cp;
+    /* 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);
@@ -159,8 +187,43 @@ sudo_pwdup(pw)
     /* 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);
+}
 
-    return(newpw);
+void
+pw_delref(pw)
+    struct passwd *pw;
+{
+    pw_delref_item(ptr_to_item(pw));
 }
 
 /*
@@ -171,13 +234,12 @@ struct passwd *
 sudo_getpwuid(uid)
     uid_t uid;
 {
-    struct passwd key, *pw;
+    struct cache_item key, *item;
     struct rbnode *node;
-    char *cp;
 
-    key.pw_uid = uid;
+    key.k.uid = uid;
     if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
-       pw = (struct passwd *) node->data;
+       item = (struct cache_item *) node->data;
        goto done;
     }
     /*
@@ -186,27 +248,26 @@ sudo_getpwuid(uid)
 #ifdef HAVE_SETAUTHDB
     aix_setauthdb(IDtouser(uid));
 #endif
-    if ((pw = getpwuid(uid)) != NULL) {
-       pw = sudo_pwdup(pw);
-       cp = sudo_getepw(pw);           /* get shadow password */
-       if (pw->pw_passwd != NULL)
-           zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
-       pw->pw_passwd = cp;
-       if (rbinsert(pwcache_byuid, (void *) pw) != NULL)
-           errorx(1, "unable to cache uid %lu (%s), already exists",
-               uid, pw->pw_name);
+    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 {
-       pw = emalloc(sizeof(*pw));
-       zero_bytes(pw, sizeof(*pw));
-       pw->pw_uid = uid;
-       if (rbinsert(pwcache_byuid, (void *) pw) != NULL)
-           errorx(1, "unable to cache uid %lu, already exists", uid);
+       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:
-    return(pw->pw_name != NULL ? pw : NULL);
+    item->refcnt++;
+    return item->d.pw;
 }
 
 /*
@@ -217,14 +278,13 @@ struct passwd *
 sudo_getpwnam(name)
     const char *name;
 {
-    struct passwd key, *pw;
+    struct cache_item key, *item;
     struct rbnode *node;
     size_t len;
-    char *cp;
 
-    key.pw_name = (char *) name;
+    key.k.name = (char *) name;
     if ((node = rbfind(pwcache_byname, &key)) != NULL) {
-       pw = (struct passwd *) node->data;
+       item = (struct cache_item *) node->data;
        goto done;
     }
     /*
@@ -233,31 +293,26 @@ sudo_getpwnam(name)
 #ifdef HAVE_SETAUTHDB
     aix_setauthdb((char *) name);
 #endif
-    if ((pw = getpwnam(name)) != NULL) {
-       pw = sudo_pwdup(pw);
-       cp = sudo_getepw(pw);           /* get shadow password */
-       if (pw->pw_passwd != NULL)
-           zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
-       pw->pw_passwd = cp;
-       if (rbinsert(pwcache_byname, (void *) pw) != NULL)
+    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;
-       cp = emalloc(sizeof(*pw) + len);
-       zero_bytes(cp, sizeof(*pw));
-       pw = (struct passwd *) cp;
-       cp += sizeof(*pw);
-       memcpy(cp, name, len);
-       pw->pw_name = cp;
-       pw->pw_uid = (uid_t) -1;
-       if (rbinsert(pwcache_byname, (void *) pw) != NULL)
+       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:
-    return(pw->pw_uid != (uid_t) -1 ? pw : NULL);
+    item->refcnt++;
+    return item->d.pw;
 }
 
 /*
@@ -268,119 +323,84 @@ sudo_fakepwnam(user, gid)
     const char *user;
     gid_t gid;
 {
+    struct cache_item *item;
     struct passwd *pw;
     struct rbnode *node;
-    size_t len;
+    size_t len, namelen;
+    int i;
 
-    len = strlen(user);
-    pw = emalloc(sizeof(struct passwd) + len + 1 /* pw_name */ +
+    namelen = strlen(user);
+    len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +
        sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
-       sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL));
-    zero_bytes(pw, sizeof(struct passwd));
-    pw->pw_uid = (uid_t) atoi(user + 1);
-    pw->pw_gid = gid;
-    pw->pw_name = (char *)pw + sizeof(struct passwd);
-    memcpy(pw->pw_name, user, len + 1);
-    pw->pw_passwd = pw->pw_name + len + 1;
-    memcpy(pw->pw_passwd, "*", 2);
-    pw->pw_gecos = pw->pw_passwd + 2;
-    pw->pw_gecos[0] = '\0';
-    pw->pw_dir = pw->pw_gecos + 1;
-    memcpy(pw->pw_dir, "/", 2);
-    pw->pw_shell = pw->pw_dir + 2;
-    memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
-
-    /* Store by uid and by name, overwriting cached version. */
-    if ((node = rbinsert(pwcache_byuid, pw)) != NULL) {
-       efree(node->data);
-       node->data = (void *) pw;
-    }
-    if ((node = rbinsert(pwcache_byname, pw)) != NULL) {
-       efree(node->data);
-       node->data = (void *) pw;
-    }
-    return(pw);
-}
-
-/*
- * Take a gid in string form "#123" and return a faked up group struct.
- */
-struct group *
-sudo_fakegrnam(group)
-    const char *group;
-{
-    struct group *gr;
-    struct rbnode *node;
-    size_t len;
-
-    len = strlen(group);
-    gr = emalloc(sizeof(struct group) + len + 1);
-    zero_bytes(gr, sizeof(struct group));
-    gr->gr_gid = (gid_t) atoi(group + 1);
-    gr->gr_name = (char *)gr + sizeof(struct group);
-    strlcpy(gr->gr_name, group, len + 1);
-
-    /* Store by gid and by name, overwriting cached version. */
-    if ((node = rbinsert(grcache_bygid, gr)) != NULL) {
-       efree(node->data);
-       node->data = (void *) gr;
-    }
-    if ((node = rbinsert(grcache_byname, gr)) != NULL) {
-       efree(node->data);
-       node->data = (void *) gr;
+       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;
+           }
+       }
     }
-    return(gr);
+    item->refcnt++;
+    return pw;
 }
 
 void
 sudo_setpwent()
 {
     setpwent();
-    sudo_setspent();
     if (pwcache_byuid == NULL)
        pwcache_byuid = rbcreate(cmp_pwuid);
     if (pwcache_byname == NULL)
        pwcache_byname = rbcreate(cmp_pwnam);
 }
 
-#ifdef PURIFY
-static void pw_free    __P((void *));
-
 void
 sudo_freepwcache()
 {
     if (pwcache_byuid != NULL) {
-       rbdestroy(pwcache_byuid, pw_free);
+       rbdestroy(pwcache_byuid, pw_delref_item);
        pwcache_byuid = NULL;
     }
     if (pwcache_byname != NULL) {
-       rbdestroy(pwcache_byname, NULL);
+       rbdestroy(pwcache_byname, pw_delref_item);
        pwcache_byname = NULL;
     }
 }
 
-static void
-pw_free(v)
-    void *v;
-{
-    struct passwd *pw = (struct passwd *) v;
-
-    if (pw->pw_passwd != NULL) {
-       zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd));
-       efree(pw->pw_passwd);
-    }
-    efree(pw);
-}
-#endif /* PURIFY */
-
 void
 sudo_endpwent()
 {
     endpwent();
-    sudo_endspent();
-#ifdef PURIFY
     sudo_freepwcache();
-#endif
 }
 
 /*
@@ -391,35 +411,29 @@ cmp_grgid(v1, v2)
     const void *v1;
     const void *v2;
 {
-    const struct group *grp1 = (const struct group *) v1;
-    const struct group *grp2 = (const struct group *) v2;
-    return(grp1->gr_gid - grp2->gr_gid);
+    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;
 }
 
 /*
- * Compare by group name.
+ * 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 int
-cmp_grnam(v1, v2)
-    const void *v1;
-    const void *v2;
-{
-    const struct group *grp1 = (const struct group *) v1;
-    const struct group *grp2 = (const struct group *) v2;
-    return(strcasecmp(grp1->gr_name, grp2->gr_name));
-}
-
-struct group *
-sudo_grdup(gr)
+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 group);
+    total = sizeof(struct cache_item) + sizeof(struct group);
     FIELD_SIZE(gr, gr_name, nsize);
     FIELD_SIZE(gr, gr_passwd, psize);
     if (gr->gr_mem) {
@@ -428,16 +442,20 @@ sudo_grdup(gr)
        nmem++;
        total += sizeof(char *) * nmem;
     }
-    if ((cp = malloc(total)) == NULL)
-           return(NULL);
-    newgr = (struct group *)cp;
+    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.
      */
-    (void)memcpy(newgr, gr, sizeof(struct group));
+    newgr = (struct group *)cp;
+    memcpy(newgr, gr, sizeof(struct group));
     cp += sizeof(struct group);
     if (gr->gr_mem) {
        newgr->gr_mem = (char **)cp;
@@ -453,7 +471,41 @@ sudo_grdup(gr)
     FIELD_COPY(gr, newgr, gr_passwd, psize);
     FIELD_COPY(gr, newgr, gr_name, nsize);
 
-    return(newgr);
+    /* 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));
 }
 
 /*
@@ -463,31 +515,34 @@ struct group *
 sudo_getgrgid(gid)
     gid_t gid;
 {
-    struct group key, *gr;
+    struct cache_item key, *item;
     struct rbnode *node;
 
-    key.gr_gid = gid;
+    key.k.gid = gid;
     if ((node = rbfind(grcache_bygid, &key)) != NULL) {
-       gr = (struct group *) node->data;
+       item = (struct cache_item *) node->data;
        goto done;
     }
     /*
      * Cache group db entry if it exists or a negative response if not.
      */
-    if ((gr = getgrgid(gid)) != NULL) {
-       gr = sudo_grdup(gr);
-       if (rbinsert(grcache_bygid, (void *) gr) != NULL)
-           errorx(1, "unable to cache gid %lu (%s), already exists",
-               gid, gr->gr_name);
+    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 {
-       gr = emalloc(sizeof(*gr));
-       zero_bytes(gr, sizeof(*gr));
-       gr->gr_gid = gid;
-       if (rbinsert(grcache_bygid, (void *) gr) != NULL)
-           errorx(1, "unable to cache gid %lu, already exists, gid");
+       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:
-    return(gr->gr_name != NULL ? gr : NULL);
+    item->refcnt++;
+    return item->d.gr;
 }
 
 /*
@@ -497,37 +552,81 @@ struct group *
 sudo_getgrnam(name)
     const char *name;
 {
-    struct group key, *gr;
+    struct cache_item key, *item;
     struct rbnode *node;
     size_t len;
-    char *cp;
 
-    key.gr_name = (char *) name;
+    key.k.name = (char *) name;
     if ((node = rbfind(grcache_byname, &key)) != NULL) {
-       gr = (struct group *) node->data;
+       item = (struct cache_item *) node->data;
        goto done;
     }
     /*
      * Cache group db entry if it exists or a negative response if not.
      */
-    if ((gr = getgrnam(name)) != NULL) {
-       gr = sudo_grdup(gr);
-       if (rbinsert(grcache_byname, (void *) gr) != NULL)
+    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;
-       cp = emalloc(sizeof(*gr) + len);
-       zero_bytes(cp, sizeof(*gr));
-       gr = (struct group *) cp;
-       cp += sizeof(*gr);
-       memcpy(cp, name, len);
-       gr->gr_name = cp;
-       gr->gr_gid = (gid_t) -1;
-       if (rbinsert(grcache_byname, (void *) gr) != NULL)
+       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:
-    return(gr->gr_gid != (gid_t) -1 ? gr : NULL);
+    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
@@ -540,28 +639,24 @@ sudo_setgrent()
        grcache_byname = rbcreate(cmp_grnam);
 }
 
-#ifdef PURIFY
 void
 sudo_freegrcache()
 {
     if (grcache_bygid != NULL) {
-       rbdestroy(grcache_bygid, free);
+       rbdestroy(grcache_bygid, gr_delref_item);
        grcache_bygid = NULL;
     }
     if (grcache_byname != NULL) {
-       rbdestroy(grcache_byname, NULL);
+       rbdestroy(grcache_byname, gr_delref_item);
        grcache_byname = NULL;
     }
 }
-#endif /* PURIFY */
 
 void
 sudo_endgrent()
 {
     endgrent();
-#ifdef PURIFY
     sudo_freegrcache();
-#endif
 }
 
 int
@@ -577,32 +672,41 @@ user_in_group(pw, group)
     int i;
 #endif
     struct group *grp;
+    int retval = FALSE;
 
 #ifdef HAVE_SETAUTHDB
     aix_setauthdb(pw->pw_name);
 #endif
-    grp = sudo_getgrnam(group);
+    /* 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)
-       return(FALSE);
+       goto done;
 
     /* check against user's primary (passwd file) gid */
-    if (grp->gr_gid == pw->pw_gid)
-       return(TRUE);
+    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)
-           return(TRUE);
+           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)
-           return(TRUE);
+           mbr_check_membership(uu, gu, &ismember) == 0 && ismember) {
+           retval = TRUE;
+           goto done;
+       }
     }
 #else /* HAVE_MBR_CHECK_MEMBERSHIP */
 # ifdef HAVE_GETGROUPS
@@ -613,20 +717,27 @@ user_in_group(pw, group)
     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])
-               return(TRUE);
+           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)
-                   return(TRUE);
+               if (strcmp(*gr_mem, pw->pw_name) == 0) {
+                   retval = TRUE;
+                   goto done;
+               }
            }
        }
     }
 #endif /* HAVE_MBR_CHECK_MEMBERSHIP */
 
-    return(FALSE);
+done:
+    if (grp != NULL)
+       gr_delref(grp);
+    return retval;
 }
index 95ac095b05f7f4d99fbdf662805caf73ad8f6558..fb3611b2d06004e0c1707d869246e4a6cd25474c 100644 (file)
@@ -110,7 +110,7 @@ rbcreate(compar)
     tree->root.color = black;
     tree->root.data = NULL;
 
-    return(tree);
+    return tree;
 }
 
 /*
@@ -181,7 +181,7 @@ rbinsert(tree, data)
     while (node != rbnil(tree)) {
        parent = node;
        if ((res = tree->compar(data, node->data)) == 0)
-           return(node);
+           return node;
        node = res < 0 ? node->left : node->right;
     }
 
@@ -255,7 +255,7 @@ rbinsert(tree, data)
        }
     }
     rbfirst(tree)->color = black;      /* first node is always black */
-    return(NULL);
+    return NULL;
 }
 
 /*
@@ -272,10 +272,10 @@ rbfind(tree, key)
 
     while (node != rbnil(tree)) {
        if ((res = tree->compar(key, node->data)) == 0)
-           return(node);
+           return node;
        node = res < 0 ? node->left : node->right;
     }
-    return(NULL);
+    return NULL;
 }
 
 /*
@@ -296,19 +296,19 @@ rbapply_node(tree, node, func, cookie, order)
     if (node != rbnil(tree)) {
        if (order == preorder)
            if ((error = func(node->data, cookie)) != 0)
-               return(error);
+               return error;
        if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0)
-           return(error);
+           return error;
        if (order == inorder)
            if ((error = func(node->data, cookie)) != 0)
-               return(error);
+               return error;
        if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0)
-           return(error);
+           return error;
        if (order == postorder)
            if ((error = func(node->data, cookie)) != 0)
-               return(error);
+               return error;
     }
-    return (0);
+    return 0;
 }
 
 /*
@@ -331,7 +331,7 @@ rbsuccessor(tree, node)
        if (succ == rbroot(tree))
            succ = rbnil(tree);
     }
-    return(succ);
+    return succ;
 }
 
 /*
@@ -404,7 +404,7 @@ void *rbdelete(tree, z)
     }
     free(z); 
     
-    return (data);
+    return data;
 }
 
 /*
index 4b87e054e0799f5d5ce4a2aea109c17ad1a0600d..cfdc7cbb9988369191527d78a73f7d1b8fa5ad75 100644 (file)
@@ -158,6 +158,63 @@ name: sudoRunAsGroup
 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
@@ -182,6 +239,9 @@ mayContain: sudoRunAs
 mayContain: sudoRunAsUser\r
 mayContain: sudoRunAsGroup\r
 mayContain: sudoUser\r
+mayContain: sudoNotBefore
+mayContain: sudoNotAfter
+mayContain: sudoOrder
 rDNAttID: cn\r
 showInAdvancedViewOnly: FALSE\r
 adminDisplayName: sudoRole\r
index df3fc0fab6546574cdf5c871fdaa8a19e222edb1..d3e95e00c716811c916169802c924234c3468450 100644 (file)
@@ -47,9 +47,30 @@ attributetype ( 1.3.6.1.4.1.15953.9.1.7
     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 $
+    MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $
            description )
     )
index 3718fd7fa7882d789f753186dbc6ba92393d4450..e512864369b6c29b5b38a62e4e9cb936bbcc1bd1 100644 (file)
@@ -6,4 +6,7 @@ attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) imperso
 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' )
-objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) X-ORIGIN 'SUDO' )
+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/sesh.c b/sesh.c
index 3195e25b9e8f429a315e7c203f8057376de7dab7..40016140b845665499a63211d48e60a0ce1adc5c 100644 (file)
--- a/sesh.c
+++ b/sesh.c
@@ -27,7 +27,7 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "compat.h"
+#include "missing.h"
 
 int
 main (int argc, char **argv)
index d028b2c39104867a67e1e894237f7109aab4b0d7..355baad555b4483fa7ddc2df55b0bf7d54cc1db4 100644 (file)
@@ -87,7 +87,7 @@ set_perms(perm)
     CLR(perm, PERM_MASK);
 
     if (perm == current_perm)
-       return(1);
+       return 1;
 
     switch (perm) {
        case PERM_ROOT:
@@ -172,12 +172,12 @@ set_perms(perm)
     }
 
     current_perm = perm;
-    return(1);
+    return 1;
 bad:
     warningx("%s: %s", errstr,
        errno == EAGAIN ? "too many processes" : strerror(errno));
     if (noexit)
-       return(0);
+       return 0;
     exit(1);
 }
 
@@ -201,7 +201,7 @@ set_perms(perm)
     CLR(perm, PERM_MASK);
 
     if (perm == current_perm)
-       return(1);
+       return 1;
 
     switch (perm) {
        case PERM_ROOT:
@@ -289,12 +289,12 @@ set_perms(perm)
     }
 
     current_perm = perm;
-    return(1);
+    return 1;
 bad:
     warningx("%s: %s", errstr,
        errno == EAGAIN ? "too many processes" : strerror(errno));
     if (noexit)
-       return(0);
+       return 0;
     exit(1);
 }
 
@@ -316,7 +316,7 @@ set_perms(perm)
     CLR(perm, PERM_MASK);
 
     if (perm == current_perm)
-       return(1);
+       return 1;
 
     /*
      * Since we only have setuid() and seteuid() and semantics
@@ -408,12 +408,12 @@ set_perms(perm)
     }
 
     current_perm = perm;
-    return(1);
+    return 1;
 bad:
     warningx("%s: %s", errstr,
        errno == EAGAIN ? "too many processes" : strerror(errno));
     if (noexit)
-       return(0);
+       return 0;
     exit(1);
 }
 
@@ -435,7 +435,7 @@ set_perms(perm)
     CLR(perm, PERM_MASK);
 
     if (perm == current_perm)
-       return(1);
+       return 1;
 
     switch (perm) {
        case PERM_ROOT:
@@ -472,12 +472,12 @@ set_perms(perm)
     }
 
     current_perm = perm;
-    return(1);
+    return 1;
 bad:
     warningx("%s: %s", errstr,
        errno == EAGAIN ? "too many processes" : strerror(errno));
     if (noexit)
-       return(0);
+       return 0;
     exit(1);
 }
 #  endif /* HAVE_SETEUID */
index d8bba8b30e5668daa6af118515eaf2e6180d9874..79271c86583af33f87f00ea58eb8747e9545b009 100644 (file)
--- a/setsid.c
+++ b/setsid.c
@@ -26,7 +26,7 @@
 #endif /* HAVE_UNISTD_H */
 
 #include <pathnames.h>
-#include <compat.h>
+#include "missing.h"
 
 pid_t
 setsid()
index e34d471c803e587bae82548466728c010d8f95ea..9285ddac61be7262c8a3dc5d6e13b8f52871599e 100644 (file)
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
+#include <config.h>
+
+#include <sys/types.h>
+
 #include <signal.h>
 #include <errno.h>
 
-#include <compat.h>
+#include "missing.h"
 
 int
 sigaction(signo, sa, osa)
@@ -43,7 +47,7 @@ sigaction(signo, sa, osa)
     if (!error && osa)
        osa->sa_flags ^= SV_INTERRUPT;          /* flip SV_INTERRUPT as above */
 
-    return(error);
+    return error;
 }
 
 int
@@ -52,7 +56,7 @@ sigemptyset(set)
 {
 
     *set = 0;
-    return(0);
+    return 0;
 }
 
 int
@@ -61,7 +65,7 @@ sigfillset(set)
 {
 
     *set = ~0;;
-    return(0);
+    return 0;
 }
 
 int
@@ -72,11 +76,11 @@ sigaddset(set, signo)
 
     if (signo <= 0 || signo >= NSIG) {
        errno = EINVAL;
-       return(-1);
+       return -1;
     }
 
     SET(*set, sigmask(signo));
-    return(0);
+    return 0;
 }
 
 int
@@ -87,11 +91,11 @@ sigdelset(set, signo)
 
     if (signo <= 0 || signo >= NSIG) {
        errno = EINVAL;
-       return(-1);
+       return -1;
     }
 
     CLR(*set, sigmask(signo));
-    return(0);
+    return 0;
 }
 
 int
@@ -100,7 +104,7 @@ sigismember(set, signo)
     int signo;
 {
 
-    return(ISSET(*set, sigmask(signo)));
+    return ISSET(*set, sigmask(signo));
 }
 
 int
@@ -120,18 +124,18 @@ sigprocmask(how, set, oset)
                mask = sigblock(*set);
                break;
            case SIG_UNBLOCK:
-               mask = sigsetmask(~*set);
+               mask = sigsetmask(sigblock(0) & ~(*set));
                break;
            case SIG_SETMASK:
                mask = sigsetmask(*set);
                break;
            default:
-               return(-1);
+               return -1;
        }
 
     if (mask == -1)
-       return(-1);
+       return -1;
     if (oset)
        *oset = mask;
-    return(0);
+    return 0;
 }
index 4123a9d77464fcc8ea6c0ff0e94a65372b50816f..303523232d9a872c28bffe78b943ca82ca4ba5cf 100644 (file)
@@ -76,7 +76,7 @@
 # include <varargs.h>
 #endif
 
-#include <compat.h>
+#include "missing.h"
 
 static int xxxprintf    __P((char **, size_t, int, const char *, va_list));
 
@@ -139,10 +139,10 @@ memchr(s, c, n)
 
                do {
                        if (*p++ == c)
-                               return ((void *)(p - 1));
+                               return (void *)(p - 1);
                } while (--n != 0);
        }
-       return (NULL);
+       return NULL;
 }
 #endif /* !HAVE_MEMCHR */
 
@@ -170,7 +170,7 @@ __ultoa(val, endp, base, octzero, xdigs)
        case 10:
                if (val < 10) { /* many numbers are 1 digit */
                        *--cp = to_char(val);
-                       return (cp);
+                       return cp;
                }
                /*
                 * On many machines, unsigned arithmetic is harder than
@@ -208,7 +208,7 @@ __ultoa(val, endp, base, octzero, xdigs)
        default:                        /* oops */
                abort();
        }
-       return (cp);
+       return cp;
 }
 
 /* Identical to __ultoa, but for quads. */
@@ -229,12 +229,12 @@ __uqtoa(val, endp, base, octzero, xdigs)
        /* 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));
+               return __ultoa((unsigned long)val, endp, base, octzero, xdigs);
        switch (base) {
        case 10:
                if (val < 10) {
                        *--cp = to_char(val % 10);
-                       return (cp);
+                       return cp;
                }
                if (val > LLONG_MAX) {
                        *--cp = to_char(val % 10);
@@ -266,7 +266,7 @@ __uqtoa(val, endp, base, octzero, xdigs)
        default:                        /* oops */
                abort();
        }
-       return (cp);
+       return cp;
 }
 # endif /* !SIZEOF_LONG_INT */
 #endif /* HAVE_LONG_LONG_INT */
@@ -291,16 +291,16 @@ xxxprintf(strp, strsize, alloc, fmt0, ap)
        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;    /* integer arguments %[diouxX] */
+       unsigned long ulval = 0; /* integer arguments %[diouxX] */
 #ifdef HAVE_LONG_LONG_INT
-       unsigned long long uqval; /* %q (quad) integers */
+       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 *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 */
@@ -340,13 +340,13 @@ xxxprintf(strp, strsize, alloc, fmt0, ap)
 } while (0)
 
        /* BEWARE, PAD uses `n'. */
-#define        PAD(howmany, with) do { \
-       if ((n = (howmany)) > 0) { \
+#define        PAD(plen, pstr) do { \
+       if ((n = (plen)) > 0) { \
                while (n > PADSIZE) { \
-                       PRINT(with, PADSIZE); \
+                       PRINT(pstr, PADSIZE); \
                        n -= PADSIZE; \
                } \
-               PRINT(with, n); \
+               PRINT(pstr, n); \
        } \
 } while (0)
 
@@ -693,7 +693,7 @@ number:                     if ((dprec = prec) >= 0)
 done:
        if (strsize)
                *str = '\0';
-       return (ret);
+       return ret;
        /* NOTREACHED */
 }
 
@@ -706,7 +706,7 @@ vsnprintf(str, n, fmt, ap)
        va_list ap;
 {
 
-       return (xxxprintf(&str, n, 0, fmt, ap));
+       return xxxprintf(&str, n, 0, fmt, ap);
 }
 #endif /* HAVE_VSNPRINTF */
 
@@ -732,7 +732,7 @@ snprintf(str, n, fmt, va_alist)
 #endif
        ret = xxxprintf(&str, n, 0, fmt, ap);
        va_end(ap);
-       return (ret);
+       return ret;
 }
 #endif /* HAVE_SNPRINTF */
 
@@ -744,7 +744,7 @@ vasprintf(str, fmt, ap)
        va_list ap;
 {
 
-       return (xxxprintf(str, 0, 1, fmt, ap));
+       return xxxprintf(str, 0, 1, fmt, ap);
 }
 #endif /* HAVE_VASPRINTF */
 
@@ -769,6 +769,6 @@ asprintf(str, fmt, va_alist)
 #endif
        ret = xxxprintf(str, 0, 1, fmt, ap);
        va_end(ap);
-       return (ret);
+       return ret;
 }
 #endif /* HAVE_ASPRINTF */
index d14fdfb382661f4231bf4251479f2404b93f43e5..9ab451c1d63fbdedcb2151183ac0513e9e2f5f8c 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
 #include <config.h>
-#include <compat.h>
+
+#include <sys/types.h>
+
+#include "missing.h"
 
 /*
  * Case insensitive string compare routines, same semantics as str[n]cmp()
index cacd3f634e1d2d48f2b9cc0362937ad6d6854cae..88b888bc463b670040e8c7076fd1618999034b17 100644 (file)
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  */
 
+#include <config.h>
+
+#include <sys/types.h>
+
 #include <stdio.h>
 #include <errno.h>
 
-#include <config.h>
-#include <compat.h>
+#include "missing.h"
 
 /*
  * Map errno -> error string.
@@ -35,7 +38,7 @@ strerror(n)
     extern char *sys_errlist[];
 
     if (n > 0 && n < sys_nerr)
-       return(sys_errlist[n]);
+       return sys_errlist[n];
     errno = EINVAL;
-    return("Unknown error");
+    return "Unknown error";
 }
index 97a803b20bdb46bd76bb4a2f0b789017120c9f9b..77f6c8663b4089b5bc69b71ac30ea0eced1759a4 100644 (file)
--- a/strlcat.c
+++ b/strlcat.c
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <config.h>
+
 #include <sys/types.h>
 #include <string.h>
 
-#include <config.h>
-#include <compat.h>
-
+#include "missing.h"
 
 /*
  * Appends src to string dst of size siz (unlike strncat, siz is the
@@ -48,7 +48,7 @@ strlcat(dst, src, siz)
        n = siz - dlen;
 
        if (n == 0)
-               return(dlen + strlen(s));
+               return dlen + strlen(s);
        while (*s != '\0') {
                if (n != 1) {
                        *d++ = *s;
@@ -58,5 +58,5 @@ strlcat(dst, src, siz)
        }
        *d = '\0';
 
-       return(dlen + (s - src));       /* count does not include NUL */
+       return dlen + (s - src);        /* count does not include NUL */
 }
index 8d301c3a5c2408acbc3e5f75cce6d48227e6690c..df2e677418fadd7479426212d0d6adbdedf7d20e 100644 (file)
--- a/strlcpy.c
+++ b/strlcpy.c
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <config.h>
+
 #include <sys/types.h>
 
-#include <config.h>
-#include <compat.h>
+#include "missing.h"
 
 /*
  * Copy src to string dst of size siz.  At most siz-1 characters
@@ -52,5 +53,5 @@ strlcpy(dst, src, siz)
                        ;
        }
 
-       return(s - src - 1);    /* count does not include NUL */
+       return s - src - 1;     /* count does not include NUL */
 }
index cead4ada194bad133487a0c64bea5bb4e15f4418..a5514290dfa410b36e4c04d33e97c82eb6e20da4 100644 (file)
  * 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 <config.h>
-#include <compat.h>
+#include "missing.h"
 
 #if defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST == 1
 # define my_sys_siglist        sys_siglist
@@ -38,6 +41,6 @@ strsignal(signo)
     int signo;
 {
     if (signo > 0 && signo < NSIG)
-       return((char *)my_sys_siglist[signo]);
-    return("Unknown signal");
+       return (char *)my_sys_siglist[signo];
+    return "Unknown signal";
 }
diff --git a/sudo.c b/sudo.c
index c03b726febaf255cebaff4d367ce5d78e697a407..0dc2e78ad276cd906e2b9a6a94860df20ee6cf56 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -117,7 +117,6 @@ 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 struct passwd *get_authpw       __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 */
@@ -130,7 +129,7 @@ char **Argv, **NewArgv;
 char *prev_user;
 int user_closefrom = -1;
 struct sudo_user sudo_user;
-struct passwd *auth_pw, *list_pw;
+struct passwd *list_pw;
 struct interface *interfaces;
 int num_interfaces;
 int tgetpass_flags;
@@ -236,7 +235,7 @@ main(argc, argv, envp)
                show_version();
                break;
            case MODE_HELP:
-               usage(0);
+               help();
                break;
            case MODE_VALIDATE:
            case MODE_VALIDATE|MODE_INVALIDATE:
@@ -313,7 +312,7 @@ main(argc, argv, envp)
 
     /* Update initial shell now that runas is set. */
     if (ISSET(sudo_mode, MODE_LOGIN_SHELL))
-       NewArgv[0] = runas_pw->pw_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) {
@@ -388,6 +387,7 @@ main(argc, argv, envp)
            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. */
@@ -422,9 +422,6 @@ main(argc, argv, envp)
     /* Build a new environment that avoids any nasty bits. */
     rebuild_env(def_noexec);
 
-    /* Fill in passwd struct based on user we are authenticating as.  */
-    auth_pw = get_authpw();
-
     /* Require a password if sudoers says so.  */
     if (def_authenticate)
        check_user(validated, sudo_mode);
@@ -436,6 +433,8 @@ main(argc, argv, envp)
            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);
@@ -487,8 +486,11 @@ main(argc, argv, envp)
 #endif
 
        /* Deferred exit due to sudo_ldap_close() */
-       if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST)))
+       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);
@@ -557,6 +559,31 @@ main(argc, argv, envp)
     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.
@@ -639,9 +666,7 @@ init_vars(envp)
     }
 
     /*
-     * 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.
+     * 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. */
@@ -649,8 +674,8 @@ init_vars(envp)
        char pw_name[MAX_UID_T_LEN + 1];
 
        pw.pw_uid = getuid();
-       (void) snprintf(pw_name, sizeof(pw_name), "%lu",
-           (unsigned long) pw.pw_uid);
+       (void) snprintf(pw_name, sizeof(pw_name), "%u",
+           (unsigned int) pw.pw_uid);
        pw.pw_name = pw_name;
        sudo_user.pw = &pw;
 
@@ -708,32 +733,14 @@ init_vars(envp)
 
        av[0] = user_shell;     /* may be updated later */
        if (NewArgc > 0) {
-           size_t cmnd_size = 1024;
-           char *cmnd, *src, *dst, **ap;
-
+           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);
-           for (ap = NewArgv; *ap != NULL; ap++) {
-               for (src = *ap; *src != '\0'; src++) {
-                   /* reserve room for an escaped char + space */
-                   if (cmnd_size < (dst - cmnd) + 3) {
-                       char *new_cmnd;
-                       cmnd_size <<= 1;
-                       new_cmnd = erealloc(cmnd, cmnd_size);
-                       dst = new_cmnd + (dst - cmnd);
-                       cmnd = new_cmnd;
-                   }
-                   if (isalnum((unsigned char)*src) || *src == '_' || *src == '-') {
-                       *dst++ = *src;
-                   } else {
-                       /* quote potential meta character */
-                       *dst++ = '\\';
-                       *dst++ = *src;
-                   }
-               }
-               *dst++ = ' ';
-           }
-           if (cmnd != dst)
-               dst--;  /* replace last space with a NUL */
+           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;
@@ -816,7 +823,7 @@ set_cmnd(sudo_mode)
     if (!runas_user && !runas_group)
        set_runaspw(def_runas_default); /* may have been updated above */
 
-    return(rval);
+    return rval;
 }
 
 /*
@@ -838,10 +845,6 @@ exec_setup(rbac_enabled, ttyname, ttyfd)
     }
 #endif
 
-    /* Close the password and group files and free up memory. */
-    sudo_endpwent();
-    sudo_endgrent();
-
     /*
      * For sudoedit, the command runas a the user with no additional setup.
      */
@@ -898,10 +901,18 @@ exec_setup(rbac_enabled, ttyname, ttyfd)
     }
 #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);
+    return rval;
 }
 
 /*
@@ -925,6 +936,13 @@ run_command(path, argv, envp, uid, dowait)
     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));
 
@@ -951,7 +969,13 @@ run_command(path, argv, envp, uid, dowait)
 #ifdef _PATH_SUDO_IO_LOGDIR
     io_log_close();
 #endif
-    return(exitcode);
+    sudo_endpwent();
+    sudo_endgrent();
+    pw_delref(sudo_user.pw);
+    pw_delref(runas_pw);
+    if (runas_gr != NULL)
+       gr_delref(runas_gr);
+    return exitcode;
 }
 
 /*
@@ -1001,16 +1025,16 @@ open_sudoers(sudoers, doedit, keepopen)
        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 & 07777) != SUDOERS_MODE)
+    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 %lu, should be %lu", sudoers,
-           (unsigned long) statbuf.st_uid, (unsigned long) 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 %lu, should be %lu", sudoers,
-           (unsigned long) statbuf.st_gid, (unsigned long) 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 {
@@ -1031,7 +1055,7 @@ open_sudoers(sudoers, doedit, keepopen)
     }
 
     set_perms(PERM_ROOT);              /* change back to root */
-    return(fp);
+    return fp;
 }
 
 /*
@@ -1042,10 +1066,15 @@ 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
@@ -1178,13 +1207,15 @@ set_fqdn()
 }
 
 /*
- * Get passwd entry for the user we are going to run commands as.
- * By default, this is "root".  Updates runas_pw as a side effect.
+ * 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);
@@ -1197,13 +1228,15 @@ set_runaspw(user)
 }
 
 /*
- * Get group entry for the group we are going to run commands as.
- * Updates runas_pw as a side effect.
+ * 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);
@@ -1213,33 +1246,6 @@ set_runasgr(group)
     }
 }
 
-/*
- * 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: %lu",
-               (unsigned long) runas_pw->pw_uid);
-       pw = runas_pw;
-    } else
-       pw = sudo_user.pw;
-
-    return(pw);
-}
-
 /*
  * Cleanup hook for error()/errorx()
  */
index 9f85ccdec747b050ea6f43d6fc900b9f3156a573..4cee4867d990fd4045522ec58a2f58bd814dfc2f 100644 (file)
--- a/sudo.cat
+++ b/sudo.cat
@@ -61,7 +61,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
 
 
-1.7.4                     July 19, 2010                         1
+1.7.6                     April  9, 2011                        1
 
 
 
@@ -127,7 +127,7 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
 
 
 
-1.7.4                     July 19, 2010                         2
+1.7.6                     April  9, 2011                        2
 
 
 
@@ -185,15 +185,15 @@ SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
                    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 usage message
-                   and exit.
+       -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.4                     July 19, 2010                         3
+1.7.6                     April  9, 2011                        3
 
 
 
@@ -259,7 +259,7 @@ SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
 
-1.7.4                     July 19, 2010                         4
+1.7.6                     April  9, 2011                        4
 
 
 
@@ -325,7 +325,7 @@ SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
 
-1.7.4                     July 19, 2010                         5
+1.7.6                     April  9, 2011                        5
 
 
 
@@ -391,7 +391,7 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
 
 
 
-1.7.4                     July 19, 2010                         6
+1.7.6                     April  9, 2011                        6
 
 
 
@@ -457,7 +457,7 @@ SUDO(1m)               MAINTENANCE COMMANDS              SUDO(1m)
 
 
 
-1.7.4                     July 19, 2010                         7
+1.7.6                     April  9, 2011                        7
 
 
 
@@ -523,7 +523,7 @@ E\bEN\bNV\bVI\bIR\bRO\bON\bNM\bME\bEN\bNT\bT
 
 
 
-1.7.4                     July 19, 2010                         8
+1.7.6                     April  9, 2011                        8
 
 
 
@@ -589,7 +589,7 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
 
 
 
-1.7.4                     July 19, 2010                         9
+1.7.6                     April  9, 2011                        9
 
 
 
@@ -655,6 +655,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.7.4                     July 19, 2010                        10
+1.7.6                     April  9, 2011                       10
 
 
diff --git a/sudo.h b/sudo.h
index f946291d9eb1d986c264bc456377a0be0ad5bc9b..a59677b3edb30737861d3e261da4da6172222041 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -24,7 +24,7 @@
 
 #include <pathnames.h>
 #include <limits.h>
-#include "compat.h"
+#include "missing.h"
 #include "alloc.h"
 #include "defaults.h"
 #include "error.h"
@@ -235,6 +235,8 @@ 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 *));
@@ -301,6 +303,10 @@ 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));
@@ -314,7 +320,7 @@ int set_perms               __P((int));
 /* sudo.c */
 FILE *open_sudoers     __P((const char *, int, int *));
 int exec_setup         __P((int, const char *, int));
-void cleanup           __P((int));
+RETSIGTYPE cleanup     __P((int));
 void set_fqdn          __P((void));
 
 /* sudo_auth.c */
@@ -350,7 +356,7 @@ 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 *auth_pw, *list_pw;
+extern struct passwd *list_pw;
 
 extern int tgetpass_flags;
 extern int long_list;
index 3d67a7640e6dd9c7ecc0f8fe3ab48de059301fa7..09f1508b4c579274a2f5ab66be36f288106eb26b 100644 (file)
@@ -23,7 +23,7 @@
 .nr LC @LCMAN@
 .nr PT @password_timeout@
 .\"
-.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 .\" ========================================================================
 .\"
 .IX Title "SUDO @mansectsu@"
-.TH SUDO @mansectsu@ "July 19, 2010" "1.7.4" "MAINTENANCE COMMANDS"
+.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
@@ -339,7 +339,8 @@ 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 usage message and exit.
+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
index 33bcb6a4ed2cd5268223763ac98e5ae9a8bb6354..555274cf2725f376afa94809ae118cbed90b2117 100644 (file)
--- a/sudo.pod
+++ b/sudo.pod
@@ -221,7 +221,8 @@ command line.
 
 =item -h
 
-The B<-h> (I<help>) option causes B<sudo> to print a usage message and exit.
+The B<-h> (I<help>) option causes B<sudo> to print a short help message
+to the standard output and exit.
 
 =item -i [command]
 
diff --git a/sudo.pp b/sudo.pp
index 1f203d8817040acb96d913ccf35c797b2a6b35ab..35c18b7b80e3148efd0ac48c551c8e67e19799f9 100644 (file)
--- a/sudo.pp
+++ b/sudo.pp
@@ -12,26 +12,42 @@ limited root privileges to users and log root activity.  \
 The basic philosophy is to give as few privileges as possible but \
 still allow people to get their work done."
        vendor="Todd C. Miller"
-       copyright="(c) 1993-1996,1998-2010 Todd C. Miller"
+       copyright="(c) 1993-1996,1998-2011 Todd C. Miller"
+
+%if [aix]
+       # AIX package summary is limited to 40 characters
+       summary="Configurable super-user privileges"
 
        # Convert to 4 part version for AIX, including patch level
-       pp_aix_version=`echo $version|sed -e 's/\([0-9]*\.[0-9]*\.[0-9]*\)$/\1.0/' -e 's/[^0-9]*\([0-9]*\)$/.\1/'`
+       pp_aix_version=`echo $version|sed -e 's/^\([0-9]*\.[0-9]*\.[0-9]*\)p\([0-9]*\)$/\1.\2/' -e 's/^\([0-9]*\.[0-9]*\.[0-9]*\)[^0-9\.].*$/\1/' -e 's/^\([0-9]*\.[0-9]*\.[0-9]*\)$/\1.0/'`
+%endif
 
-       # Strip of patchlevel for kit which only supports x.y.z versions
-       pp_kit_version="`echo $version|sed -e 's/\.//g' -e 's/p[0-9]*$//'`"
+%if [kit]
+       # Strip off patchlevel for kit which only supports xyz versions
+       pp_kit_version="`echo $version|sed -e 's/\.//g' -e 's/[^0-9][^0-9]*[0-9][0-9]*$//'`"
        pp_kit_name="TCM"
+%endif
 
+%if [sd]
        pp_sd_vendor_tag="TCM"
+%endif
+
+%if [solaris]
        pp_solaris_name="TCM${name}"
+       pp_solaris_pstamp=`/usr/bin/date "+%B %d, %Y"`
+%endif
+
 %if [rpm,deb]
        # Convert patch level into release and remove from version
-       pp_rpm_release="`echo $version|sed 's/^[0-9]*\.[0-9]*\.[0-9]*[^0-9]*//'`"
-       pp_rpm_release="`expr $pp_rpm_release + 1`"
-       pp_rpm_version="`echo $version|sed 's/p[0-9]*$//'`"
+       pp_rpm_release="`expr \( $version : '.*p\([0-9][0-9]*\)' \| 0 \) + 1`"
+       pp_rpm_version="`expr $version : '\(.*\)p[0-9][0-9]*'`"
        pp_rpm_license="BSD"
        pp_rpm_url="http://www.sudo.ws/"
        pp_rpm_group="Applications/System"
        pp_rpm_packager="Todd.Miller@courtesan.com"
+       if test -n "$linux_audit"; then
+               pp_rpm_requires="audit-libs >= $linux_audit"
+       fi
 
        pp_deb_maintainer="$pp_rpm_packager"
        pp_deb_release="$pp_rpm_release"
@@ -42,7 +58,7 @@ still allow people to get their work done."
        mv ${pp_destdir}$sudoersdir/sudoers ${pp_destdir}$sudoersdir/sudoers.dist
 %endif
 
-%set [rpm]
+%if [rpm]
        # Add distro info to release
        osrelease=`echo "$pp_rpm_distro" | sed -e 's/^[^0-9]*//' -e 's/-.*$//'`
        case "$pp_rpm_distro" in
@@ -136,8 +152,9 @@ still allow people to get their work done."
                fi
                ;;
        esac
+%endif
 
-%set [deb]
+%if [deb]
        # Uncomment some Defaults and the %sudo rule in sudoers
        # Note that the order must match that of sudoers and be tab-indented.
        /bin/ed - ${pp_destdir}${sudoersdir}/sudoers <<-'EOF'
@@ -157,9 +174,7 @@ still allow people to get their work done."
        session required pam_permit.so
        session required pam_limits.so
        EOF
-
-%set [aix]
-       summary="Configurable super-user privileges"
+%endif
 
 %files
        $bindir/sudo        4111 root:
index 6e2691377683def349e9dc950efedff6df32f24b..ea43d55beace8aff26bcfcd3fc606c706ab6ee48 100644 (file)
 #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[],
@@ -30,9 +37,9 @@ int fork_pty __P((const char *path, char *argv[], char *envp[], int sv[],
 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));
-void handler __P((int s));
+RETSIGTYPE handler __P((int s));
 void pty_close __P((struct command_status *cstat));
 void pty_setup __P((uid_t uid));
-extern sig_atomic_t recvsig[NSIG];
+extern int signal_pipe[2];
 
 #endif /* _SUDO_EXEC_H */
index eff07b9ee68aedf2a094cc89d3d08bacbebf659f..ba180b5d0b8d63c94cc68fd733037ef26b70e08f 100644 (file)
@@ -16,6 +16,8 @@
 
 #include <config.h>
 
+#include <sys/types.h>
+
 #include <errno.h>
 #ifndef HAVE_TIMESPEC
 # include <time.h>
@@ -26,7 +28,7 @@
 # include <varargs.h>
 #endif
 
-#include <compat.h>
+#include "missing.h"
 
 /*
  * Dummy versions of the execve() family of syscalls.  We don't need
@@ -43,7 +45,7 @@ extern int errno;
 #define DUMMY_BODY                             \
 {                                              \
     errno = EACCES;                            \
-    return(-1);                                        \
+    return -1;                                 \
 }
 
 #ifdef __STDC__
index e21aaae495681dc3612092b4470ed06c2ed26913..96303202ed5eb61325461def47f7f7141004c1a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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
@@ -100,7 +100,7 @@ nomatch:
     if (tq_empty(&snl))
        tq_append(&snl, &sudo_nss_file);
 
-    return(&snl);
+    return &snl;
 }
 
 #else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */
@@ -179,7 +179,7 @@ nomatch:
     if (tq_empty(&snl))
        tq_append(&snl, &sudo_nss_file);
 
-    return(&snl);
+    return &snl;
 }
 
 # else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */
@@ -197,7 +197,7 @@ sudo_read_nss()
 #  endif
     tq_append(&snl, &sudo_nss_file);
 
-    return(&snl);
+    return &snl;
 }
 
 # endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */
@@ -212,9 +212,10 @@ reset_groups(pw)
 #if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS)
     if (pw != sudo_user.pw) {
 # ifdef HAVE_SETAUTHDB
-        aix_setauthdb(pw->pw_name);
+       aix_setauthdb(pw->pw_name);
 # endif
-       (void) initgroups(pw->pw_name, pw->pw_gid);
+       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) {
@@ -223,7 +224,7 @@ reset_groups(pw)
                log_error(USE_ERRNO|MSG_ONLY, "can't get group vector");
        }
 # ifdef HAVE_SETAUTHDB
-        aix_restoreauthdb();
+       aix_restoreauthdb();
 # endif
     }
 #endif /* HAVE_INITGROUPS && HAVE_GETGROUPS */
@@ -246,52 +247,57 @@ display_privs(snl, pw)
     struct passwd *pw;
 {
     struct sudo_nss *nss;
-    struct lbuf lbuf;
-    int count;
+    struct lbuf defs, privs;
+    int count, olen;
 
     /* Reset group vector so group matching works correctly. */
     reset_groups(pw);
 
-    lbuf_init(&lbuf, output, 4, NULL);
+    lbuf_init(&defs, output, 4, NULL);
+    lbuf_init(&privs, output, 4, NULL);
 
     /* Display defaults from all sources. */
-    lbuf_append(&lbuf, "Matching Defaults entries for ", pw->pw_name,
+    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, &lbuf);
-    }
-    if (count) {
-       lbuf_append(&lbuf, "\n\n", NULL);
-       lbuf_print(&lbuf);
+       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. */
-    lbuf.len = 0;
-    lbuf_append(&lbuf, "Runas and Command-specific defaults for ", pw->pw_name,
+    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, &lbuf);
-    }
-    if (count) {
-       lbuf_append(&lbuf, "\n\n", NULL);
-       lbuf_print(&lbuf);
+       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.len = 0;
-    lbuf_append(&lbuf, "User ", pw->pw_name,
+    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, &lbuf);
+       count += nss->display_privs(nss, pw, &privs);
     }
     if (count) {
-       lbuf_print(&lbuf);
+       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(&lbuf);
+    lbuf_destroy(&defs);
+    lbuf_destroy(&privs);
 }
 
 /*
@@ -310,7 +316,7 @@ display_cmnd(snl, pw)
 
     tq_foreach_fwd(snl, nss) {
        if (nss->display_cmnd(nss, pw) == 0)
-           return(0);
+           return 0;
     }
-    return(1);
+    return 1;
 }
index af15b879088a87eac787059e72b87428cd527103..b26e3ec1d9d19b9cb7e9b2aa98f06bb001e2e676 100644 (file)
@@ -19,7 +19,8 @@
 #ifndef _SUDO_USAGE_H
 #define _SUDO_USAGE_H
 
-void usage __P((int)) __attribute__((__noreturn__));
+void help __P((void)) __attribute__((__noreturn__));
+void usage __P((int));
 
 /*
  * Usage strings for sudo.  These are here because we
index 018d80566d49cb176fc50b9d81dd57668e7072db..2a7a521ce569f3ed6c30ba325a7d6c8ad2c47ff5 100644 (file)
@@ -61,7 +61,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
 
 
-1.7.4                    January 12, 2011                       1
+1.7.6                     April  9, 2011                        1
 
 
 
@@ -93,25 +93,31 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                       User ',' User_List
 
         User ::= '!'* user name |
-                 '!'* '#'uid |
-                 '!'* '%'group |
-                 '!'* '+'netgroup |
-                 '!'* '%:'nonunix_group |
+                 '!'* #uid |
+                 '!'* %group |
+                 '!'* %#gid |
+                 '!'* +netgroup |
+                 '!'* %:nonunix_group |
+                 '!'* %:#nonunix_gid |
                  '!'* User_Alias
 
-       A User_List is made up of one or more user names, uids (prefixed with
-       '#'), system groups (prefixed with '%'), netgroups (prefixed with '+')
-       and User_Aliases.  Each list item may be prefixed with zero or more '!'
-       operators.  An odd number of '!' operators negate the value of the
-       item; an even number just cancel each other out.
+       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, group, netgroup or nonunix_group 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.
+       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 syntax depends on the underlying implementation.  For
-       instance, the QAS AD backend supports the following formats:
+       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"
 
@@ -119,15 +125,9 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        +\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 the '@' symbol.
-
-        Runas_List ::= Runas_Member |
-                       Runas_Member ',' Runas_List
 
 
-
-1.7.4                    January 12, 2011                       2
+1.7.6                     April  9, 2011                        2
 
 
 
@@ -136,10 +136,20 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 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 |
+                         '!'* #uid |
+                         '!'* %group |
+                         '!'* %#gid |
+                         '!'* %:nonunix_group |
+                         '!'* %:#nonunix_gid |
                          '!'* +netgroup |
                          '!'* Runas_Alias
 
@@ -156,7 +166,7 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         Host ::= '!'* host name |
                  '!'* ip_addr |
                  '!'* network(/netmask)? |
-                 '!'* '+'netgroup |
+                 '!'* +netgroup |
                  '!'* Host_Alias
 
        A Host_List is made up of one or more host names, IP addresses, network
@@ -180,28 +190,28 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                       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
 
+1.7.6                     April  9, 2011                        3
 
 
-1.7.4                    January 12, 2011                       3
 
 
 
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-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
@@ -246,27 +256,27 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        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.
 
 
+1.7.6                     April  9, 2011                        4
 
 
-1.7.4                    January 12, 2011                       4
 
 
 
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(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.
@@ -294,7 +304,7 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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)
+       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
@@ -312,27 +322,27 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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.
+1.7.6                     April  9, 2011                        5
 
 
 
 
-1.7.4                    January 12, 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
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+       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:
@@ -348,13 +358,48 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         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.  Note that in this example only the
-       group will be set, the command still runs as user t\btc\bcm\bm.
+       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
@@ -388,18 +433,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         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
-
-
-
-1.7.4                    January 12, 2011                       6
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
        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
@@ -421,17 +454,31 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
         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, any environment
-       variables set on the command line way are not subject to the
-       restrictions imposed by _\be_\bn_\bv_\b__\bc_\bh_\be_\bc_\bk, _\be_\bn_\bv_\b__\bd_\be_\bl_\be_\bt_\be, or _\be_\bn_\bv_\b__\bk_\be_\be_\bp.  As such,
-       only trusted users should be allowed to set variables in this manner.
-       If the command matched is A\bAL\bLL\bL, the SETENV tag is implied for that
-       command; this default may be overridden by use of the NOSETENV tag.
+       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
 
@@ -455,17 +502,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        ?       Matches any single character.
 
-
-
-1.7.4                    January 12, 2011                       7
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
        [...]   Matches any character in the specified range.
 
        [!...]  Matches any character n\bno\bot\bt in the specified range.
@@ -485,6 +521,17 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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.
@@ -521,17 +568,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        #include /etc/sudoers.%h
 
-
-
-1.7.4                    January 12, 2011                       8
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
        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
@@ -550,6 +586,18 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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.
@@ -582,21 +630,8 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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): '@', '!', '=',
-       ':', ',', '(', ')', '\'.
-
-
-
-
-
-1.7.4                    January 12, 2011                       9
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
+       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
@@ -611,11 +646,24 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
                        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 _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is disabled.  This flag
-                       is _\bo_\bf_\bf by default.
+                       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.
@@ -652,18 +700,6 @@ S\bSU\bUD\bDO\bOE\bER\bRS\bS O\bOP\bPT\bTI\bIO\bON\bNS\bS
                        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-
-
-
-
-1.7.4                    January 12, 2011                      10
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
                        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
@@ -682,6 +718,18 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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
@@ -718,10 +766,28 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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.4                    January 12, 2011                      11
+
+
+1.7.6                     April  9, 2011                       12
 
 
 
@@ -730,7 +796,22 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       syslog) s\bsu\bud\bdo\bo log file.  This flag is _\bo_\bf_\bf by default.
+       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.
@@ -770,6 +851,17 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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
@@ -784,18 +876,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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:".
-
-
-
-1.7.4                    January 12, 2011                      12
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
                        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.
 
@@ -836,32 +916,33 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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 _\be_\bn_\bv_\b__\br_\be_\bs_\be_\bt is
-                       disabled.  This flag is _\bo_\bf_\bf by default.
 
-       set_logname     Normally, s\bsu\bud\bdo\bo will set the LOGNAME, USER and USERNAME
 
+1.7.6                     April  9, 2011                       14
 
 
-1.7.4                    January 12, 2011                      13
 
 
 
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-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
@@ -901,25 +982,10 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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.
-
-       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 _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo directory 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=.
 
 
 
-
-1.7.4                    January 12, 2011                      14
+1.7.6                     April  9, 2011                       15
 
 
 
@@ -928,21 +994,10 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 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 _\b/_\bv_\ba_\br_\b/_\bl_\bo_\bg_\b/_\bs_\bu_\bd_\bo_\b-_\bi_\bo directory
-                       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.
+                       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
@@ -982,28 +1037,28 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
        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.4                    January 12, 2011                      15
 
 
 
+1.7.6                     April  9, 2011                       16
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       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.
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-       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
@@ -1049,22 +1104,28 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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 ***.
 
-1.7.4                    January 12, 2011                      16
+       noexec_file     Path to a shared library containing dummy versions of
 
 
 
+1.7.6                     April  9, 2011                       17
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       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
+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
@@ -1114,21 +1175,22 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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.4                    January 12, 2011                      17
 
+1.7.6                     April  9, 2011                       18
 
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-       sudoers_locale  Locale to use when parsing the sudoers file.  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.
@@ -1180,10 +1242,14 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                    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.4                    January 12, 2011                      18
+1.7.6                     April  9, 2011                       19
 
 
 
@@ -1192,11 +1258,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       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:
@@ -1246,23 +1307,22 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                    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.4                    January 12, 2011                      19
-
 
+1.7.6                     April  9, 2011                       20
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                   to disable syslog logging).  Defaults to auth.
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-       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
@@ -1312,10 +1372,16 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
                        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.4                    January 12, 2011                      20
+1.7.6                     April  9, 2011                       21
 
 
 
@@ -1324,12 +1390,6 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                       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.
@@ -1378,24 +1438,24 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
         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.4                    January 12, 2011                      21
 
+1.7.6                     April  9, 2011                       22
 
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-        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
@@ -1445,22 +1505,23 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
        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.4                    January 12, 2011                      22
 
 
+1.7.6                     April  9, 2011                       23
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-        jack           CSNETS = ALL
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
+
 
-       The user j\bja\bac\bck\bk may run any command on the machines in the _\bC_\bS_\bN_\bE_\bT_\bS alias
-       (the networks 128.138.243.0, 128.138.204.0, and 128.138.242.0).  Of
-       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.
 
@@ -1510,22 +1571,22 @@ SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
         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.4                    January 12, 2011                      23
 
 
+1.7.6                     April  9, 2011                       24
 
 
 
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       The user f\bfr\bre\bed\bd can run commands as any user in the _\bD_\bB Runas_Alias
-       (o\bor\bra\bac\bcl\ble\be or s\bsy\byb\bba\bas\bse\be) without giving a password.
+SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
-        john           ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root*
 
        On the _\bA_\bL_\bP_\bH_\bA machines, user j\bjo\boh\bhn\bn may su to anyone except root but he is
        not allowed to specify any options to the _\bs_\bu(1) command.
@@ -1576,10 +1637,15 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
        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.4                    January 12, 2011                      24
+
+1.7.6                     April  9, 2011                       25
 
 
 
@@ -1588,11 +1654,6 @@ S\bSE\bEC\bCU\bUR\bRI\bIT\bTY\bY N\bNO\bOT\bTE\bES\bS
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-       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
@@ -1642,10 +1703,15 @@ 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
 
                      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.4                    January 12, 2011                      25
+1.7.6                     April  9, 2011                       26
 
 
 
@@ -1654,11 +1720,6 @@ P\bPR\bRE\bEV\bVE\bEN\bNT\bTI\bIN\bNG\bG S\bSH\bHE\bEL\bLL\bL E\bES\bSC\bCA\bAP\bPE\bES\bS
 SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
 
 
-                 then s\bsu\bud\bdo\bo may be able to replace the exec family of functions
-                 in the standard library with its own that simply return an
-                 error.  Unfortunately, there is no foolproof way to know
-                 whether or not _\bn_\bo_\be_\bx_\be_\bc will work at compile-time.  _\bn_\bo_\be_\bx_\be_\bc
-                 should work on SunOS, Solaris, *BSD, Linux, IRIX, Tru64 UNIX,
                  MacOS X, and HP-UX 11.x.  It is known n\bno\bot\bt to work on AIX and
                  UnixWare.  _\bn_\bo_\be_\bx_\be_\bc is expected to work on most operating
                  systems that support the LD_PRELOAD environment variable.
@@ -1707,19 +1768,6 @@ S\bSU\bUP\bPP\bPO\bOR\bRT\bT
        http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
        the archives.
 
-
-
-
-
-1.7.4                    January 12, 2011                      26
-
-
-
-
-
-SUDOERS(4)             MAINTENANCE COMMANDS            SUDOERS(4)
-
-
 D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
        s\bsu\bud\bdo\bo is provided ``AS IS'' and any express or implied warranties,
        including, but not limited to, the implied warranties of
@@ -1729,54 +1777,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-1.7.4                    January 12, 2011                      27
+1.7.6                     April  9, 2011                       27
 
 
index 20374d493e8197f75e9aefb899c5add2cfdb22dd..8b1433382cf9ebea8d4be13adab294dcd0e8e556 100644 (file)
@@ -43,7 +43,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
        For the most part, there is really no need for s\bsu\bud\bdo\bo-specific Aliases.
        Unix groups or user netgroups can be used in place of User_Aliases and
-       RunasAliases.  Host netgroups can be used in place of HostAliases.
+       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.
 
@@ -61,7 +61,7 @@ D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN
 
 
 
-1.7.4                     July 12, 2010                         1
+1.7.6                     April  9, 2011                        1
 
 
 
@@ -82,7 +82,7 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            sudoOption: env_keep+=SSH_AUTH_SOCK
 
        The equivalent of a sudoer in LDAP is a sudoRole.  It consists of the
-       following components:
+       following attributes:
 
        s\bsu\bud\bdo\boU\bUs\bse\ber\br
            A user name, uid (prefixed with '#'), Unix group (prefixed with a
@@ -109,32 +109,71 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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.
 
-       Each component listed above should contain a single value, but there
-       may be multiple instances of each component type.  A sudoRole must
-       contain at least one sudoUser, sudoHost and sudoCommand.
-
-       The following example allows users in group wheel to run any command on
-       any host via s\bsu\bud\bdo\bo:
-
-
+           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
 
 
-1.7.4                     July 12, 2010                         2
 
 
 
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
 
-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
@@ -151,15 +190,35 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
        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.  If there are conflicting command rules
-       on an entry, the negative takes precedence.  This is called paranoid
-       behavior (not necessarily the most specific match).
+       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:
 
@@ -190,23 +249,24 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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.4                     July 12, 2010                         3
 
 
 
+1.7.6                     April  9, 2011                        4
 
 
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
 
-           sudoCommand: ALL
 
-       Another difference is that negations on the Host, User or Runas are
-       currently ignorred.  For example, the following attributes do not
-       behave the way one might expect.
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
+
 
            # does not match all but joe
            # rather, does not match anyone
@@ -246,7 +306,7 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
        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_\bthat are
+       Only those options explicitly listed in _\b/_\be_\bt_\bc_\b/_\bl_\bd_\ba_\bp_\b._\bc_\bo_\bn_\bas 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.
 
@@ -256,10 +316,16 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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.4                     July 12, 2010                         4
+1.7.6                     April  9, 2011                        5
 
 
 
@@ -268,13 +334,6 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
 
-           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
@@ -296,43 +355,59 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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.
 
 
 
+1.7.6                     April  9, 2011                        6
 
 
-1.7.4                     July 12, 2010                         5
 
 
 
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
 
-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
@@ -376,22 +451,13 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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.
+           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
 
 
 
-1.7.4                     July 12, 2010                         6
+1.7.6                     April  9, 2011                        7
 
 
 
@@ -400,6 +466,16 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 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
@@ -443,28 +519,29 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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.
 
 
+1.7.6                     April  9, 2011                        8
 
 
-1.7.4                     July 12, 2010                         7
 
 
 
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
 
-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.
@@ -509,28 +586,29 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
            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:
 
+1.7.6                     April  9, 2011                        9
 
 
-1.7.4                     July 12, 2010                         8
 
 
 
+SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
 
-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
 
@@ -574,6 +652,18 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
          #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
@@ -586,18 +676,9 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
          #
          # verbose sudoers matching from ldap
          #sudoers_debug 2
-
-
-
-1.7.4                     July 12, 2010                         9
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
+         #
+         # Enable support for time-based entries in sudoers.
+         #sudoers_timed yes
          #
          # optional proxy credentials
          #binddn        <who to search as>
@@ -637,6 +718,18 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
          #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.
          #
@@ -652,18 +745,6 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
          # For OpenLDAP:
          #tls_cert /etc/certs/client_cert.pem
          #tls_key  /etc/certs/client_key.pem
-
-
-
-1.7.4                     July 12, 2010                        10
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
          #
          # 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
@@ -689,7 +770,8 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
          # krb5_ccname /etc/.ldapcache
 
    S\bSu\bud\bdo\bo s\bsc\bch\bhe\bem\bma\ba f\bfo\bor\br O\bOp\bpe\ben\bnL\bLD\bDA\bAP\bP
-       The following schema is in OpenLDAP format.  Simply copy it to the
+       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.
 
@@ -702,6 +784,18 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
 
         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
@@ -719,18 +813,6 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            EQUALITY caseExactIA5Match
            SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
 
-
-
-1.7.4                     July 12, 2010                        11
-
-
-
-
-
-SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
-
-
-
         attributetype ( 1.3.6.1.4.1.15953.9.1.5
            NAME 'sudoOption'
            DESC 'Options(s) followed by sudo'
@@ -749,21 +831,54 @@ SUDOERS.LDAP(4)        MAINTENANCE COMMANDS       SUDOERS.LDAP(4)
            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 $ description )
+                 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
-       The way that _\bs_\bu_\bd_\bo_\be_\br_\bs is parsed differs between Note that there are
-       differences in the way that LDAP-based _\bs_\bu_\bd_\bo_\be_\br_\bs is parsed compared to
-       file-based _\bs_\bu_\bd_\bo_\be_\br_\bs.  See the "Differences between LDAP and non-LDAP
-       sudoers" section for more information.
+       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
@@ -787,6 +902,23 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-1.7.4                     July 12, 2010                        12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1.7.6                     April  9, 2011                       14
 
 
index 66a1b03db9251f90323ff904e2fdd7c21f8e29da..74cafeca5f82340554bfa59c2c073f74b669d163 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 2003-2010
+.\" Copyright (c) 2003-2011
 .\"    Todd C. Miller <Todd.Miller@courtesan.com>
 .\" 
 .\" Permission to use, copy, modify, and distribute this software for any
@@ -14,7 +14,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\" 
-.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 .\" ========================================================================
 .\"
 .IX Title "SUDOERS.LDAP @mansectform@"
-.TH SUDOERS.LDAP @mansectform@ "July 12, 2010" "1.7.4" "MAINTENANCE COMMANDS"
+.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
@@ -183,14 +183,14 @@ is that in \s-1LDAP\s0, \fBsudo\fR\-specific Aliases are not supported.
 .PP
 For the most part, there is really no need for \fBsudo\fR\-specific
 Aliases.  Unix groups or user netgroups can be used in place of
-User_Aliases and RunasAliases.  Host netgroups can be used in place
-of HostAliases.  Since Unix groups and netgroups can also be stored
+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 sudoRole.  Instead of defining
+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 sudoRole that contains the commands and assign multiple users
+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"
@@ -213,7 +213,7 @@ in the environment for all users.
 .Ve
 .PP
 The equivalent of a sudoer in \s-1LDAP\s0 is a \f(CW\*(C`sudoRole\*(C'\fR.  It consists of
-the following components:
+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
@@ -241,13 +241,56 @@ as or a Unix group (prefixed with a \f(CW\*(Aq%\*(Aq\fR) or user netgroup (prefi
 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 component listed above should contain a single value, but there
-may be multiple instances of each component type.  A sudoRole must
+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
@@ -271,13 +314,21 @@ 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.  If there are
-conflicting command rules on an entry, the negative takes precedence.
+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
@@ -315,7 +366,7 @@ Here is an example:
 .Ve
 .PP
 Another difference is that negations on the Host, User or Runas are
-currently ignorred.  For example, the following attributes do not
+currently ignored.  For example, the following attributes do not
 behave the way one might expect.
 .PP
 .Vb 3
@@ -358,7 +409,7 @@ 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 that are
+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
@@ -395,16 +446,32 @@ The \fB\s-1BIND_TIMELIMIT\s0\fR parameter specifies the amount of time, in secon
 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
@@ -461,7 +528,7 @@ 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.
+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
@@ -664,6 +731,9 @@ determines sudoers source order on \s-1AIX\s0
 \&  # 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>
@@ -743,9 +813,10 @@ determines sudoers source order on \s-1AIX\s0
 .Ve
 .SS "Sudo schema for OpenLDAP"
 .IX Subsection "Sudo schema for OpenLDAP"
-The following schema is in OpenLDAP format.  Simply copy it to the
-schema directory (e.g. \fI/etc/openldap/schema\fR), add the proper
-\&\f(CW\*(C`include\*(C'\fR line in \f(CW\*(C`slapd.conf\*(C'\fR and restart \fBslapd\fR.
+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
@@ -792,11 +863,33 @@ schema directory (e.g. \fI/etc/openldap/schema\fR), add the proper
 \&    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 $ description )
+\&          sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $
+\&          sudoOrder $ description )
 \&    )
 .Ve
 .SH "SEE ALSO"
@@ -804,10 +897,9 @@ schema directory (e.g. \fI/etc/openldap/schema\fR), add the proper
 \&\fIldap.conf\fR\|(@mansectform@), \fIsudoers\fR\|(5)
 .SH "CAVEATS"
 .IX Header "CAVEATS"
-The way that \fIsudoers\fR is parsed differs between Note that there
-are differences in the way that LDAP-based \fIsudoers\fR is parsed
-compared to file-based \fIsudoers\fR.  See the \*(L"Differences between
-\&\s-1LDAP\s0 and non-LDAP sudoers\*(R" section for more information.
+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
index f7a39c93425dc183ddd141d5f72dcc5cd8ab9e29..a9816546b348bdcb7e308d0cb4724cb4042ca08d 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (c) 2003-2010
+Copyright (c) 2003-2011
        Todd C. Miller <Todd.Miller@courtesan.com>
 
 Permission to use, copy, modify, and distribute this software for any
@@ -68,14 +68,14 @@ is that in LDAP, B<sudo>-specific Aliases are not supported.
 
 For the most part, there is really no need for B<sudo>-specific
 Aliases.  Unix groups or user netgroups can be used in place of
-User_Aliases and RunasAliases.  Host netgroups can be used in place
-of HostAliases.  Since Unix groups and netgroups can also be stored
+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 sudoRole.  Instead of defining
+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 sudoRole that contains the commands and assign multiple users
+a C<sudoRole> that contains the commands and assign multiple users
 to it.
 
 =head2 SUDOers LDAP container
@@ -97,7 +97,7 @@ in the environment for all users.
     sudoOption: env_keep+=SSH_AUTH_SOCK
  
 The equivalent of a sudoer in LDAP is a C<sudoRole>.  It consists of
-the following components:
+the following attributes:
 
 =over 4
 
@@ -133,15 +133,61 @@ 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 component listed above should contain a single value, but there
-may be multiple instances of each component type.  A sudoRole must
+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
@@ -165,13 +211,21 @@ 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.  If there are
-conflicting command rules on an entry, the negative takes precedence.
+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).
 
@@ -207,7 +261,7 @@ Here is an example:
     sudoCommand: ALL
 
 Another difference is that negations on the Host, User or Runas are
-currently ignorred.  For example, the following attributes do not
+currently ignored.  For example, the following attributes do not
 behave the way one might expect.
 
     # does not match all but joe
@@ -250,7 +304,7 @@ Also note that on systems using the OpenLDAP libraries, default
 values specified in F</etc/openldap/ldap.conf> or the user's
 F<.ldaprc> files are not used.
 
-Only those options explicitly listed in F<@ldap_conf@> that are
+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.
 
@@ -294,11 +348,20 @@ 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
@@ -306,6 +369,17 @@ 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
@@ -370,7 +444,7 @@ should be installed locally so it can be verified.
 
 =item B<TLS_CACERT> file name
 
-An alias for B<TLS_CACERTFILE>.
+An alias for B<TLS_CACERTFILE> for OpenLDAP compatibility.
 
 =item B<TLS_CACERTFILE> file name
 
@@ -577,6 +651,9 @@ determines sudoers source order on AIX
   # 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>
@@ -656,9 +733,10 @@ determines sudoers source order on AIX
 
 =head2 Sudo schema for OpenLDAP 
 
-The following schema is in OpenLDAP format.  Simply copy it to the
-schema directory (e.g. F</etc/openldap/schema>), add the proper
-C<include> line in C<slapd.conf> and restart B<slapd>.
+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'
@@ -704,11 +782,33 @@ C<include> line in C<slapd.conf> and restart B<slapd>.
     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 $ description )
+         sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $
+         sudoOrder $ description )
     )
 
 =head1 SEE ALSO
@@ -717,10 +817,9 @@ L<ldap.conf(5)>, L<sudoers(5)>
 
 =head1 CAVEATS
 
-The way that I<sudoers> is parsed differs between Note that there
-are differences in the way that LDAP-based I<sudoers> is parsed
-compared to file-based I<sudoers>.  See the L<Differences between
-LDAP and non-LDAP sudoers> section for more information.
+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
 
index 210cf9036935e65c97040c4d219928cb6dddbefe..531ead6eda471adf846faf9036c54ea50790d876 100644 (file)
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1994-1996, 1998-2005, 2007-2010
+.\" 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
 .\" ========================================================================
 .\"
 .IX Title "SUDOERS @mansectform@"
-.TH SUDOERS @mansectform@ "January 12, 2011" "1.7.4" "MAINTENANCE COMMANDS"
+.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
@@ -246,26 +246,33 @@ The definitions of what constitutes a valid \fIalias\fR member follow.
 \&               User \*(Aq,\*(Aq User_List
 \&
 \& User ::= \*(Aq!\*(Aq* user name |
-\&          \*(Aq!\*(Aq* \*(Aq#\*(Aquid |
-\&          \*(Aq!\*(Aq* \*(Aq%\*(Aqgroup |
-\&          \*(Aq!\*(Aq* \*(Aq+\*(Aqnetgroup |
-\&          \*(Aq!\*(Aq* \*(Aq%:\*(Aqnonunix_group |
+\&          \*(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, uids (prefixed
-with '#'), system groups (prefixed with '%'), netgroups (prefixed
-with '+') and \f(CW\*(C`User_Alias\*(C'\fRes.  Each list item may be prefixed with
-zero or more '!' operators.  An odd number of '!' operators negate
-the value of the item; an even number just cancel each other out.
-.PP
-A \f(CW\*(C`user name\*(C'\fR, \f(CW\*(C`group\*(C'\fR, \f(CW\*(C`netgroup\*(C'\fR or \f(CW\*(C`nonunix_group\*(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.
-.PP
-The \f(CW\*(C`nonunix_group\*(C'\fR syntax depends on the underlying implementation.
-For instance, the \s-1QAS\s0 \s-1AD\s0 backend supports the following formats:
+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
@@ -273,16 +280,21 @@ 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 the '@' symbol.
+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* \*(Aq#\*(Aquid |
-\&                  \*(Aq!\*(Aq* \*(Aq%\*(Aqgroup |
+\&                  \*(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
@@ -301,7 +313,7 @@ and toor), you can use a uid instead (#0 in the example given).
 \& Host ::= \*(Aq!\*(Aq* host name |
 \&          \*(Aq!\*(Aq* ip_addr |
 \&          \*(Aq!\*(Aq* network(/netmask)? |
-\&          \*(Aq!\*(Aq* \*(Aq+\*(Aqnetgroup |
+\&          \*(Aq!\*(Aq* +netgroup |
 \&          \*(Aq!\*(Aq* Host_Alias
 .Ve
 .PP
@@ -429,7 +441,7 @@ 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)
+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"
@@ -460,7 +472,7 @@ The user \fBdgb\fR may run \fI/bin/ls\fR, \fI/bin/kill\fR, and
 \&\fI/usr/bin/lprm\fR \*(-- but only as \fBoperator\fR.  E.g.,
 .PP
 .Vb 1
-\& $ sudo \-u operator /bin/ls.
+\& $ sudo \-u operator /bin/ls
 .Ve
 .PP
 It is also possible to override a \f(CW\*(C`Runas_Spec\*(C'\fR later on in an
@@ -481,14 +493,43 @@ the user or group set to \fBoperator\fR:
 \&        /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.  Note that in this example
-only the group will be set, the command still runs as user \fBtcm\fR.
+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"
@@ -562,13 +603,14 @@ on how \f(CW\*(C`NOEXEC\*(C'\fR works and whether or not it will work on your sy
 .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, any
-environment variables set on the command line way 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.
+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"
@@ -725,7 +767,7 @@ 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'.
+\&'!', '=', ':', ',', '(', ')', '\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
@@ -740,7 +782,8 @@ 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 \fIenv_reset\fR is disabled.
+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"
@@ -777,7 +820,7 @@ and \f(CW\*(C`env_check\*(C'\fR lists are then added.  The default contents of t
 \&\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 \fIon\fR by default.
+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
@@ -831,6 +874,37 @@ password.  This flag is \fI@insults@\fR by default.
 .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.
@@ -936,7 +1010,8 @@ 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 \fIenv_reset\fR is disabled.
+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"
@@ -982,32 +1057,6 @@ 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 "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 \fI/var/log/sudo\-io\fR directory using a unique
-session \s-1ID\s0 that is included in the normal \fBsudo\fR log line, prefixed
-with \fITSID=\fR.
-.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
-\&\fI/var/log/sudo\-io\fR directory 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 "tty_tickets" 16
 .IX Item "tty_tickets"
 If set, users must authenticate on a per-tty basis.  With this flag
@@ -1022,7 +1071,7 @@ 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 \fIoff\fR by default.
+\&\fIsudoers\fR.  This flag is \fI@umask_override@\fR by default.
 .if \n(LC \{\
 .IP "use_loginclass" 16
 .IX Item "use_loginclass"
@@ -1102,6 +1151,12 @@ 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
@@ -1176,9 +1231,9 @@ Syslog priority to use when user authenticates successfully.
 Defaults to \f(CW\*(C`@goodpri@\*(C'\fR.
 .IP "sudoers_locale" 16
 .IX Item "sudoers_locale"
-Locale to use when parsing the sudoers file.  Note that changing
-the locale may affect how sudoers is interpreted.
-Defaults to \f(CW"C"\fR.
+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.
@@ -1391,8 +1446,9 @@ Local groups file
 .IP "\fI/etc/netgroup\fR" 24
 .IX Item "/etc/netgroup"
 List of network groups
-.IP "\fI/var/log/sudo\-io\fR" 24
-.IX Item "/var/log/sudo-io"
+.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"
index da7ea5faa4b2b6aaa90773929741f1d8d0b732ca..ef250cd7cac81e43f93f70fe49ff6aa51381f679 100644 (file)
@@ -1,4 +1,4 @@
-Copyright (c) 1994-1996, 1998-2005, 2007-2010
+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
@@ -112,25 +112,32 @@ The definitions of what constitutes a valid I<alias> member follow.
               User ',' User_List
 
  User ::= '!'* user name |
-         '!'* '#'uid |
-         '!'* '%'group |
-         '!'* '+'netgroup |
-         '!'* '%:'nonunix_group |
+         '!'* #uid |
+         '!'* %group |
+         '!'* %#gid |
+         '!'* +netgroup |
+         '!'* %:nonunix_group |
+         '!'* %:#nonunix_gid |
          '!'* User_Alias
 
-A C<User_List> is made up of one or more user names, uids (prefixed
-with '#'), system groups (prefixed with '%'), netgroups (prefixed
-with '+') and C<User_Alias>es.  Each list item may be prefixed with
-zero or more '!' operators.  An odd number of '!' operators negate
-the value of the item; an even number just cancel each other out.
-
-A C<user name>, C<group>, C<netgroup> or C<nonunix_group> 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.
-
-The C<nonunix_group> syntax depends on the underlying implementation.
-For instance, the QAS AD backend supports the following formats:
+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
 
@@ -148,15 +155,20 @@ 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 the '@' symbol.
+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 |
+                 '!'* #uid |
+                 '!'* %group |
+                 '!'* %#gid |
+                 '!'* %:nonunix_group |
+                 '!'* %:#nonunix_gid |
                  '!'* +netgroup |
                  '!'* Runas_Alias
 
@@ -173,7 +185,7 @@ and toor), you can use a uid instead (#0 in the example given).
  Host ::= '!'* host name |
          '!'* ip_addr |
          '!'* network(/netmask)? |
-         '!'* '+'netgroup |
+         '!'* +netgroup |
          '!'* Host_Alias
 
 A C<Host_List> is made up of one or more host names, IP addresses,
@@ -293,7 +305,7 @@ 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)
+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
@@ -322,7 +334,7 @@ What this means is that for the entry:
 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.
+ $ 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:
@@ -338,13 +350,36 @@ 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.  Note that in this example
-only the group will be set, the command still runs as user B<tcm>.
+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
@@ -408,13 +443,14 @@ 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, any
-environment variables set on the command line way 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.
+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
 
@@ -579,7 +615,7 @@ 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
 
@@ -598,7 +634,8 @@ 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 I<env_reset> is disabled.
+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
@@ -640,7 +677,7 @@ 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<on> by default.
+This flag is I<@env_reset@> by default.
 
 =item fast_glob
 
@@ -701,6 +738,39 @@ password.  This flag is I<@insults@> by default.
 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.
@@ -822,7 +892,8 @@ 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 I<env_reset> is disabled.
+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
@@ -874,34 +945,6 @@ 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 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 F</var/log/sudo-io> directory using a unique
-session ID that is included in the normal B<sudo> log line, prefixed
-with I<TSID=>.
-
-=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
-F</var/log/sudo-io> directory 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 tty_tickets
 
 If set, users must authenticate on a per-tty basis.  With this flag
@@ -917,7 +960,7 @@ 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<off> by default.
+I<sudoers>.  This flag is I<@umask_override@> by default.
 
 =item use_loginclass
 
@@ -1019,6 +1062,13 @@ 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>
@@ -1098,9 +1148,9 @@ Defaults to C<@goodpri@>.
 
 =item sudoers_locale
 
-Locale to use when parsing the sudoers file.  Note that changing
-the locale may affect how sudoers is interpreted.
-Defaults to C<"C">.
+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
 
@@ -1357,7 +1407,7 @@ Local groups file
 
 List of network groups
 
-=item F</var/log/sudo-io>
+=item F<@iolog_dir@>
 
 I/O log files
 
old mode 100644 (file)
new mode 100755 (executable)
index 0fe0ad1..442155e
@@ -25,6 +25,7 @@ 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 (<>){
@@ -67,8 +68,9 @@ while (<>){
         print "objectClass: top\n";
         print "objectClass: sudoRole\n";
         print "cn: defaults\n";
-     print "description: Default sudoOption's go here\n";
+        print "description: Default sudoOption's go here\n";
         print "sudoOption: $_\n" foreach @options;
+        printf "sudoOrder: %d\n", ++$order;
         print "\n";
       }
       # Definition
@@ -96,6 +98,7 @@ while (<>){
       }
       print "sudoCommand: $_\n" foreach expand(\%CA,@cmds);
       print "sudoOption: $_\n" foreach @options;
+      printf "sudoOrder: %d\n", ++$order;
       print "\n";
     }
 
@@ -120,6 +123,10 @@ sub expand{
     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
   }
index 58b8639d7a1b641e02fd285670621805832cf880..9fdb5bbc5ae2c000e2dfbc919f3796ec4ce5bc8b 100644 (file)
@@ -18,6 +18,9 @@
 
 #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>
@@ -50,7 +53,7 @@
 # include <time.h>
 #endif
 #ifndef HAVE_TIMESPEC
-# include <emul/timespec.h>
+# include "emul/timespec.h"
 #endif
 #include <ctype.h>
 #include <errno.h>
 
 #include <pathnames.h>
 
-#include "compat.h"
+#include "missing.h"
 #include "alloc.h"
 #include "error.h"
-#include "missing.h"
 
 #ifndef LINE_MAX
 # define LINE_MAX 2048
@@ -191,13 +193,14 @@ 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));
-void cleanup __P((int));
+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 usage __P((void));
+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));
 
@@ -235,7 +238,7 @@ main(argc, argv)
     decimal = localeconv()->decimal_point;
 #endif
 
-    while ((ch = getopt(argc, argv, "d:f:lm:s:V")) != -1) {
+    while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) {
        switch(ch) {
        case 'd':
            session_dir = optarg;
@@ -254,6 +257,9 @@ main(argc, argv)
                    errorx(1, "invalid filter option: %s", optarg);
            }
            break;
+       case 'h':
+           help();
+           /* NOTREACHED */
        case 'l':
            listonly = 1;
            break;
@@ -273,7 +279,7 @@ main(argc, argv)
            (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
            exit(0);
        default:
-           usage();
+           usage(1);
            /* NOTREACHED */
        }
 
@@ -285,7 +291,7 @@ main(argc, argv)
        exit(list_sessions(argc, argv, pattern, user, tty));
 
     if (argc != 1)
-       usage();
+       usage(1);
 
     /* 6 digit ID in base 36, e.g. 01G712AB */
     id = argv[0];
@@ -316,9 +322,12 @@ main(argc, argv)
        error(1, "unable to open %s", path);
     cp = NULL;
     len = 0;
-    getline(&cp, &len, lfile); /* log */
-    getline(&cp, &len, lfile); /* cwd */
-    getline(&cp, &len, lfile); /* command */
+    /* 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);
@@ -537,7 +546,7 @@ parse_expr(headp, argv)
                errorx(1, "unmatched ')' in expression");
            if (node_stack[stack_top])
                sn->next = node_stack[stack_top]->next;
-           return(av - argv + 1);
+           return av - argv + 1;
        bad:
        default:
            errorx(1, "unknown search term \"%s\"", *av);
@@ -583,7 +592,7 @@ parse_expr(headp, argv)
     if (not)
        errorx(1, "illegal trailing \"!\"");
 
-    return(av - argv);
+    return av - argv;
 }
 
 static int
@@ -641,7 +650,7 @@ match_expr(head, log)
        if (sn->negated)
            matched = !matched;
     }
-    return(matched);
+    return matched;
 }
 
 static int
@@ -662,7 +671,7 @@ list_session_dir(pathbuf, re, user, tty)
     d = opendir(pathbuf);
     if (d == NULL && errno != ENOTDIR) {
        warning("cannot opendir %s", pathbuf);
-       return(-1);
+       return -1;
     }
     while ((dp = readdir(d)) != NULL) {
        if (NAMLEN(dp) != 2 || !isalnum((unsigned char)dp->d_name[0]) ||
@@ -747,7 +756,7 @@ list_session_dir(pathbuf, re, user, tty)
            printf("GROUP=%s ; ", li.runas_group);
        printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd);
     }
-    return(0);
+    return 0;
 }
 
 static int
@@ -819,7 +828,7 @@ list_sessions(argc, argv, pattern, user, tty)
        closedir(d2);
     }
     closedir(d1);
-    return(0);
+    return 0;
 }
 
 /*
@@ -934,21 +943,39 @@ bad:
 }
 
 static void
-usage()
+usage(fatal)
+    int fatal;
 {
-    fprintf(stderr,
-       "usage: %s [-d directory] [-m max_wait] [-s speed_factor] ID\n",
+    fprintf(fatal ? stderr : stdout,
+       "usage: %s [-h] [-d directory] [-f filter] [-m max_wait] [-s speed_factor] ID\n",
        getprogname());
-    fprintf(stderr,
-       "usage: %s [-d directory] -l [search expression]\n",
+    fprintf(fatal ? stderr : stdout,
+       "usage: %s [-h] [-d directory] -l [search expression]\n",
        getprogname());
-    exit(1);
+    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()
   */
-void
+RETSIGTYPE
 cleanup(signo)
     int signo;
 {
index 9c03469dfd322ba9d70274def7dc60f4d59df30e..aee5497cfd4aba86d15ffe3bf422f3a4013a89b0 100644 (file)
@@ -8,10 +8,10 @@ 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-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] [-\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-d\bd _\bd_\bi_\br_\be_\bc_\bt_\bo_\br_\by] -l [search expression]
+       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
@@ -47,21 +47,21 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
                    _\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.
 
-       -l          Enable "list mode".  In this mode, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will list
+       -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
 
 
 
-1.7.4                     July 12, 2010                         1
+
+1.7.6                     April  9, 2011                        1
 
 
 
@@ -70,6 +70,11 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
 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.
 
@@ -119,15 +124,10 @@ SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
 
        -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
 
 
 
-1.7.4                     July 12, 2010                         2
+1.7.6                     April  9, 2011                        2
 
 
 
@@ -136,6 +136,11 @@ SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
 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
@@ -186,14 +191,9 @@ SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
        2 hours ago
                2 hours ago.
 
-       next Friday
-               The first second of the next Friday.
 
 
-
-
-
-1.7.4                     July 12, 2010                         3
+1.7.6                     April  9, 2011                        3
 
 
 
@@ -202,6 +202,9 @@ SUDOREPLAY(1m)         MAINTENANCE COMMANDS        SUDOREPLAY(1m)
 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.
 
@@ -254,12 +257,9 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
 
         sudoreplay -l user millert
 
-       List sessions run by user _\bb_\bo_\bb with a command containing the string vi:
-
-
 
 
-1.7.4                     July 12, 2010                         4
+1.7.6                     April  9, 2011                        4
 
 
 
@@ -268,6 +268,8 @@ E\bEX\bXA\bAM\bMP\bPL\bLE\bES\bS
 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:
@@ -323,8 +325,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-
-
-1.7.4                     July 12, 2010                         5
+1.7.6                     April  9, 2011                        5
 
 
index 1ed044d17ea32922f27a099ac128e0ce0e5bd3cc..89418d8ee9ab3bf74c78dcd1aacc1aa33a170af1 100644 (file)
@@ -13,7 +13,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\" 
-.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 .\" ========================================================================
 .\"
 .IX Title "SUDOREPLAY @mansectsu@"
-.TH SUDOREPLAY @mansectsu@ "July 12, 2010" "1.7.4" "MAINTENANCE COMMANDS"
+.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
 sudoreplay \- replay sudo session logs
 .SH "SYNOPSIS"
 .IX Header "SYNOPSIS"
-\&\fBsudoreplay\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
+\&\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\-d\fR \fIdirectory\fR] \-l [search expression]
+\&\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
@@ -187,8 +187,12 @@ 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 "\-l" 12
-.IX Item "-l"
+.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
index c36f9133e49c56e394c1a0122ec5cbf8acbadd30..5eb6e1e550fc456882b4777c9998a24f44f52b45 100644 (file)
@@ -21,9 +21,9 @@ sudoreplay - replay sudo session logs
 
 =head1 SYNOPSIS
 
-B<sudoreplay> [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>] [B<-f> I<filter>] [B<-m> I<max_wait>] [B<-s> I<speed_factor>] ID
 
-B<sudoreplay> [B<-d> I<directory>] -l [search expression]
+B<sudoreplay> [B<-h>] [B<-d> I<directory>] -l [search expression]
 
 =head1 DESCRIPTION
 
@@ -76,7 +76,12 @@ 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 -l
+=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
diff --git a/term.c b/term.c
index 85b730092deb00f2313bd7d66b1608b3e88f91e8..4aa712848e1a320f3f5fb60db95537265ab1636f 100644 (file)
--- a/term.c
+++ b/term.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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
@@ -112,10 +112,10 @@ term_restore(fd, flush)
        int flags = TCSASOFT;
        flags |= flush ? TCSAFLUSH : TCSADRAIN;
        if (tcsetattr(fd, flags, &oterm) != 0)
-           return(0);
+           return 0;
        changed = 0;
     }
-    return(1);
+    return 1;
 }
 
 int
@@ -123,7 +123,7 @@ term_noecho(fd)
     int fd;
 {
     if (!changed && tcgetattr(fd, &oterm) != 0)
-       return(0);
+       return 0;
     (void) memcpy(&term, &oterm, sizeof(term));
     CLR(term.c_lflag, ECHO|ECHONL);
 #ifdef VSTATUS
@@ -131,9 +131,9 @@ term_noecho(fd)
 #endif
     if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
        changed = 1;
-       return(1);
+       return 1;
     }
-    return(0);
+    return 0;
 }
 
 #if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
@@ -146,7 +146,7 @@ term_raw(fd, isig)
     struct termios term;
 
     if (!changed && tcgetattr(fd, &oterm) != 0)
-       return(0);
+       return 0;
     (void) memcpy(&term, &oterm, sizeof(term));
     /* Set terminal to raw mode */
     term.c_cc[VMIN] = 1;
@@ -158,9 +158,9 @@ term_raw(fd, isig)
        SET(term.c_lflag, ISIG);
     if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
        changed = 1;
-       return(1);
+       return 1;
     }
-    return(0);
+    return 0;
 }
 
 int
@@ -168,7 +168,7 @@ term_cbreak(fd)
     int fd;
 {
     if (!changed && tcgetattr(fd, &oterm) != 0)
-       return(0);
+       return 0;
     (void) memcpy(&term, &oterm, sizeof(term));
     /* Set terminal to half-cooked mode */
     term.c_cc[VMIN] = 1;
@@ -182,9 +182,9 @@ term_cbreak(fd)
        term_erase = term.c_cc[VERASE];
        term_kill = term.c_cc[VKILL];
        changed = 1;
-       return(1);
+       return 1;
     }
-    return(0);
+    return 0;
 }
 
 int
@@ -195,11 +195,11 @@ term_copy(src, dst)
     struct termios tt;
 
     if (tcgetattr(src, &tt) != 0)
-       return(0);
+       return 0;
     /* XXX - add TCSANOW compat define */
     if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0)
-       return(0);
-    return(1);
+       return 0;
+    return 1;
 }
 
 #else /* SGTTY */
@@ -210,7 +210,7 @@ term_raw(fd, isig)
     int isig;
 {
     if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
-       return(0);
+       return 0;
     (void) memcpy(&term, &oterm, sizeof(term));
     /* Set terminal to raw mode */
     /* XXX - how to support isig? */
@@ -218,9 +218,9 @@ term_raw(fd, isig)
     SET(term.sg_flags, RAW);
     if (ioctl(fd, TIOCSETP, &term) == 0) {
        changed = 1;
-       return(1);
+       return 1;
     }
-    return(0);
+    return 0;
 }
 
 int
@@ -228,7 +228,7 @@ term_cbreak(fd)
     int fd;
 {
     if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0)
-       return(0);
+       return 0;
     (void) memcpy(&term, &oterm, sizeof(term));
     /* Set terminal to half-cooked mode */
     CLR(term.c_lflag, ECHO);
@@ -237,9 +237,9 @@ term_cbreak(fd)
        term_erase = term.sg_erase;
        term_kill = term.sg_kill;
        changed = 1;
-       return(1);
+       return 1;
     }
-    return(0);
+    return 0;
 }
 
 int
@@ -255,14 +255,14 @@ term_copy(src, dst)
     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);
+       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 0;
     }
-    return(1);
+    return 1;
 }
 
 #endif
index 1bf2cd301a8fd031c668334afe24aec549f3d8b2..139c7c7cddfebce7dba2eff284deecde60da70af 100644 (file)
@@ -60,6 +60,7 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 
+#include "tsgetgrpw.h"
 #include "sudo.h"
 #include "interfaces.h"
 #include "parse.h"
@@ -100,19 +101,6 @@ void usage __P((void)) __attribute__((__noreturn__));
 void set_runasgr __P((char *));
 void set_runaspw __P((char *));
 
-extern void setgrfile __P((const char *));
-extern void setgrent __P((void));
-extern void endgrent __P((void));
-extern struct group *getgrent __P((void));
-extern struct group *getgrnam __P((const char *));
-extern struct group *getgrgid __P((gid_t));
-extern void setpwfile __P((const char *));
-extern void setpwent __P((void));
-extern void endpwent __P((void));
-extern struct passwd *getpwent __P((void));
-extern struct passwd *getpwnam __P((const char *));
-extern struct passwd *getpwuid __P((uid_t));
-
 int
 main(argc, argv)
     int argc;
@@ -123,7 +111,8 @@ main(argc, argv)
     struct userspec *us;
     char *p, *grfile, *pwfile, *runas_group, *runas_user;
     char hbuf[MAXHOSTNAMELEN + 1];
-    int ch, dflag, rval, matched;
+    int match, host_match, runas_match, cmnd_match;
+    int ch, dflag;
 
 #if defined(SUDO_DEVEL) && defined(__OpenBSD__)
     malloc_options = "AFGJPR";
@@ -178,8 +167,8 @@ main(argc, argv)
     if (argc < 2) {
        if (!dflag)
            usage();
-       if ((sudo_user.pw = sudo_getpwnam("nobody")) == NULL)
-            errorx(1, "no passwd entry for nobody!");
+       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)
@@ -207,7 +196,7 @@ main(argc, argv)
     }
 
     /* Fill in user_args from NewArgv. */
-    if (NewArgc > 1) {
+    if (NewArgc > 0) {
        char *to, **from;
        size_t size, n;
 
@@ -234,10 +223,12 @@ main(argc, argv)
     /* Allocate space for data structures in the parser. */
     init_parser("sudoers", 0);
 
-    if (yyparse() != 0 || parse_error)
+    if (yyparse() != 0 || parse_error) {
+       parse_error = TRUE;
        (void) fputs("Does not parse", stdout);
-    else
+    } else {
        (void) fputs("Parses OK", stdout);
+    }
 
     if (!update_defaults(SETDEF_ALL))
        (void) fputs(" (problem with defaults entries)", stdout);
@@ -259,12 +250,12 @@ main(argc, argv)
        (void) putchar('\n');
        dump_sudoers();
        if (argc < 2)
-           exit(0);
+           exit(parse_error ? 1 : 0);
     }
 
-    /* This loop must match the one in sudoers_lookup() */
+    /* This loop must match the one in sudo_file_lookup() */
     printf("\nEntries for user %s:\n", user_name);
-    matched = UNSPEC;
+    match = UNSPEC;
     tq_foreach_rev(&userspecs, us) {
        if (userlist_matches(sudo_user.pw, &us->users) != ALLOW)
            continue;
@@ -272,27 +263,38 @@ main(argc, argv)
            putchar('\n');
            print_privilege(priv); /* XXX */
            putchar('\n');
-           if (hostlist_matches(&priv->hostlist) == ALLOW) {
+           host_match = hostlist_matches(&priv->hostlist);
+           if (host_match == ALLOW) {
                puts("\thost  matched");
                tq_foreach_rev(&priv->cmndlist, cs) {
-                   if (runaslist_matches(&cs->runasuserlist,
-                       &cs->runasgrouplist) == ALLOW) {
+                   runas_match = runaslist_matches(&cs->runasuserlist,
+                       &cs->runasgrouplist);
+                   if (runas_match == ALLOW) {
                        puts("\trunas matched");
-                       rval = cmnd_matches(cs->cmnd);
-                       if (rval != UNSPEC)
-                           matched = rval;
-                       printf("\tcmnd  %s\n", rval == ALLOW ? "allowed" :
-                           rval == DENY ? "denied" : "unmatched");
+                       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", matched == ALLOW ? "allowed" :
-       matched == DENY ? "denied" : "unmatched");
+    printf("\nCommand %s\n", match == ALLOW ? "allowed" :
+       match == DENY ? "denied" : "unmatched");
 
-    exit(0);
+    /*
+     * 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
@@ -337,7 +339,7 @@ char *
 sudo_getepw(pw)
     const struct passwd *pw;
 {
-    return (pw->pw_passwd);
+    return pw->pw_passwd;
 }
 
 void
@@ -352,7 +354,7 @@ open_sudoers(path, isdir, keepopen)
     int isdir;
     int *keepopen;
 {
-    return(fopen(path, "r"));
+    return fopen(path, "r");
 }
 
 void
@@ -365,7 +367,7 @@ int
 set_perms(perm)
     int perm;
 {
-    return(1);
+    return 1;
 }
 
 void
@@ -461,11 +463,14 @@ print_alias(v1, v2)
            c = (struct sudo_command *) m->name;
            printf("%s%s%s", c->cmnd, c->args ? " " : "",
                c->args ? c->args : "");
-       } else
+       } else if (m->type == ALL) {
+           fputs("ALL", stdout);
+       } else {
            fputs(m->name, stdout);
+       }
     }
     putchar('\n');
-    return(0);
+    return 0;
 }
 
 void
@@ -490,13 +495,26 @@ print_privilege(priv)
        tq_foreach_fwd(&p->cmndlist, cs) {
            if (cs != tq_first(&p->cmndlist))
                fputs(", ", stdout);
-           /* XXX - runasgrouplist too */
-           if (!tq_empty(&cs->runasuserlist)) {
+           if (!tq_empty(&cs->runasuserlist) || !tq_empty(&cs->runasgrouplist)) {
                fputs("(", stdout);
-               tq_foreach_fwd(&cs->runasuserlist, m) {
-                   if (m != tq_first(&cs->runasuserlist))
-                       fputs(", ", stdout);
-                   print_member(m);
+               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);
            }
index 8127eab1e0540bf8a89f81d8bbee97e9a3ad593a..b64bb8d3e51e5ca3c8379f4ecbba7f68aac00b37 100644 (file)
@@ -57,7 +57,7 @@
 
 static volatile sig_atomic_t signo[NSIG];
 
-static void handler __P((int));
+static RETSIGTYPE handler __P((int));
 static char *getln __P((int, char *, size_t, int));
 static char *sudo_askpass __P((const char *));
 
@@ -80,7 +80,7 @@ tgetpass(prompt, timeout, flags)
 
     /* If using a helper program to get the password, run it instead. */
     if (ISSET(flags, TGP_ASKPASS) && user_askpass)
-       return(sudo_askpass(prompt));
+       return sudo_askpass(prompt);
 
 restart:
     for (i = 0; i < NSIG; i++)
@@ -127,8 +127,10 @@ restart:
     sa.sa_handler = SIG_IGN;
     (void) sigaction(SIGPIPE, &sa, &savepipe);
 
-    if (prompt)
-       (void) write(output, prompt, strlen(prompt));
+    if (prompt) {
+       if (write(output, prompt, strlen(prompt)) == -1)
+           goto restore;
+    }
 
     if (timeout > 0)
        alarm(timeout);
@@ -136,9 +138,12 @@ restart:
     alarm(0);
     save_errno = errno;
 
-    if (neednl || pass == NULL)
-       (void) write(output, "\n", 1);
+    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);
@@ -175,7 +180,7 @@ restart:
 
     if (save_errno)
        errno = save_errno;
-    return(pass);
+    return pass;
 }
 
 /*
@@ -223,7 +228,7 @@ sudo_askpass(prompt)
     (void) close(pfd[0]);
     (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL);
 
-    return(pass);
+    return pass;
 }
 
 extern int term_erase, term_kill;
@@ -242,7 +247,7 @@ getln(fd, buf, bufsiz, feedback)
 
     if (left == 0) {
        errno = EINVAL;
-       return(NULL);                   /* sanity */
+       return NULL;                    /* sanity */
     }
 
     while (--left) {
@@ -252,20 +257,23 @@ getln(fd, buf, bufsiz, feedback)
        if (feedback) {
            if (c == term_kill) {
                while (cp > buf) {
-                   (void) write(fd, "\b \b", 3);
+                   if (write(fd, "\b \b", 3) == -1)
+                       break;
                    --cp;
                }
                left = bufsiz;
                continue;
            } else if (c == term_erase) {
                if (cp > buf) {
-                   (void) write(fd, "\b \b", 3);
+                   if (write(fd, "\b \b", 3) == -1)
+                       break;
                    --cp;
                    left++;
                }
                continue;
            }
-           (void) write(fd, "*", 1);
+           if (write(fd, "*", 1) == -1)
+               /* shut up glibc */;
        }
        *cp++ = c;
     }
@@ -273,15 +281,16 @@ getln(fd, buf, bufsiz, feedback)
     if (feedback) {
        /* erase stars */
        while (cp > buf) {
-           (void) write(fd, "\b \b", 3);
+           if (write(fd, "\b \b", 3) == -1)
+               break;
            --cp;
        }
     }
 
-    return(nr == 1 ? buf : NULL);
+    return nr == 1 ? buf : NULL;
 }
 
-static void
+static RETSIGTYPE
 handler(s)
     int s;
 {
@@ -296,5 +305,5 @@ tty_present()
 
     if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1)
        close(fd);
-    return(fd != -1);
+    return fd != -1;
 }
index 3b2a18dd7f2e43b137b01df92bb73aa45a6f19fd..9369e8c4abbc6026b5a97880bfc8cf81a3eae323 100644 (file)
--- a/timestr.c
+++ b/timestr.c
@@ -28,7 +28,7 @@
 #endif /* STDC_HEADERS */
 #include <time.h>
 
-#include "compat.h"
+#include "missing.h"
 
 char *get_timestr      __P((time_t, int));
 
@@ -55,7 +55,7 @@ get_timestr(tstamp, log_year)
     /* 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);
+       return buf;
 
 #endif /* HAVE_STRFTIME */
 
@@ -65,5 +65,5 @@ get_timestr(tstamp, log_year)
     else
        s[15] = '\0';                   /* don't care about year */
 
-    return(s);
+    return s;
 }
diff --git a/toke.c b/toke.c
index e58fed9f0f270ff2e70e98e19d8ea4fb9d869a09..77b6ecb7077d3a8fd3e7e75898475e2b75dc13ca 100644 (file)
--- a/toke.c
+++ b/toke.c
@@ -1,3 +1,4 @@
+#include <config.h>
 /*     $OpenBSD: flex.skl,v 1.11 2010/08/04 18:24:50 millert Exp $     */
 
 /* A lexical scanner generated by flex */
@@ -288,75 +289,75 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
        *yy_cp = '\0'; \
        yy_c_buf_p = yy_cp;
 
-#define YY_NUM_RULES 54
-#define YY_END_OF_BUFFER 55
-static yyconst short int yy_accept[593] =
+#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,   55,   42,   50,   49,   48,   42,   53,   42,
-       43,   44,   42,   45,   42,   42,   42,   42,   47,   46,
-       53,   37,   37,   37,   37,   37,   37,   37,   53,   42,
-       42,   50,   53,   37,   37,   37,   37,   37,    1,   53,
-       42,   42,   16,   15,   16,   15,   15,   53,   53,   53,
-        2,    8,    7,    8,    3,    8,    4,   53,   12,   12,
-       12,   10,   11,   42,    0,   50,   48,   42,    0,    0,
-        0,   52,    0,   42,   32,    0,    0,   31,    0,   40,
-       40,    0,   42,   42,    0,   42,   42,   42,   42,    0,
-
-       35,   37,   37,   37,   37,   37,   37,   37,   42,   51,
-       42,   50,    0,    0,    0,    0,    0,    0,   42,   42,
-       42,   42,   42,    1,    0,   38,   38,    0,   42,   16,
-       16,   14,   13,   14,    0,    0,    2,    8,    0,    5,
-        6,    8,    8,   12,    0,   12,   12,    0,    9,   41,
-       41,    0,    0,   32,    0,    0,   42,   42,   42,   42,
-       42,    0,    0,   35,   35,   37,   37,   37,   37,   37,
-       37,   37,   37,   37,   42,    0,    0,    0,    0,    0,
-        0,   42,   42,   42,   42,   42,    0,   42,    9,    0,
-       42,   42,   42,   42,   42,   42,    0,   36,   36,   36,
-
-        0,    0,   35,   35,   35,   35,   35,   35,   35,   37,
-       37,   37,   37,   37,   37,   37,   37,   37,   42,    0,
-        0,    0,    0,    0,    0,   42,   42,   42,   42,   42,
-       42,   42,    0,    0,   36,   36,   36,    0,   35,   35,
-        0,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,   35,    0,   24,   37,   37,   37,   37,   37,   37,
-       37,   37,   42,    0,    0,    0,    0,   42,   42,   42,
-       42,   42,   42,   42,   42,    0,   36,    0,   35,   35,
-       35,    0,    0,    0,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   37,   37,   37,
-
-       37,   37,   37,   37,   37,   42,    0,    0,    0,   42,
-       42,   42,   33,   33,   33,    0,    0,   35,   35,   35,
-       35,   35,   35,   35,    0,    0,    0,    0,    0,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   37,   37,    0,   23,   37,   37,   37,
-       37,    0,   22,    0,   25,   42,    0,    0,    0,   42,
-       42,   42,   42,   33,   33,   33,   33,    0,   35,    0,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,    0,    0,    0,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   37,   37,   37,
-
-       37,   37,   37,   39,    0,    0,    0,   42,   19,   38,
-       42,   34,   34,   34,   35,    0,    0,    0,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,    0,    0,    0,    0,    0,   35,   35,   35,   35,
-       35,   35,   35,   35,   37,   37,   37,   37,    0,   21,
-        0,   26,    0,   19,    0,    0,   42,    0,   42,   42,
-       42,   34,   34,   34,   34,   34,    0,    0,    0,    0,
-        0,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,    0,   29,   37,   37,   37,    0,    0,    0,   20,
-
-       19,    0,    0,   19,    0,   42,   42,   42,   34,   34,
-        0,    0,    0,   35,   35,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   35,   35,   35,
-       35,    0,   27,   37,   37,   20,    0,   17,    0,   42,
-       42,   42,   42,   42,    0,    0,    0,    0,    0,   35,
-       35,   35,   35,   35,   35,   35,   35,    0,   30,   37,
-        0,   42,   42,   42,   35,   35,   35,   35,   35,   35,
-        0,   28,    0,   42,   42,   42,   42,   42,   35,   35,
-       35,   35,   35,    0,   18,   33,   33,   33,   33,   33,
-       33,    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
 
     } ;
 
@@ -394,168 +395,170 @@ static yyconst int yy_ec[256] =
 
 static yyconst int yy_meta[66] =
     {   0,
-        1,    2,    3,    4,    5,    2,    1,    6,    6,    1,
-        1,    2,    1,    7,    8,    9,    9,    9,    9,    9,
-        9,    9,    9,   10,   11,    6,    1,    9,    9,    9,
-        9,    9,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,   12,   13,   14,
-       14,   14,   14,   14,   14,   13,   13,   13,   13,   13,
-       13,   13,   13,   13,   13
+        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[659] =
+static yyconst short int yy_base[663] =
     {   0,
-        0,   64,   65,   66,   72,   87,  134,  198,  262,  309,
-       83,   98, 2616, 2548, 2586, 3619, 2562,  356,  402,   58,
-     3619, 3619, 2517, 3619,  106,  412,  139,  105, 2540, 3619,
-     3619,  467, 2516,  517, 2487, 2486, 2496, 2482,  571,  149,
-       44,  175,  595, 2444, 2446, 2438, 2433, 2434, 2494,  204,
-      268,   65,    0, 3619, 2474, 3619,    0,  276,  650,  114,
-        0, 2420, 3619,   79, 3619,   93, 3619,  131, 2417,   71,
-      103, 3619,  140, 2416,  206, 2461, 2458,  672, 2456, 2428,
-     2426, 3619,  217,  286,  125, 2380,  321, 2377,  347,  328,
-     2375,  382,  322,  705, 2398, 2407,  379,  429,  393, 2387,
-
-      124,  745,    0, 2366, 2361,  253, 2351, 2347,  241, 3619,
-       99,  558, 2329, 2333, 2325, 2319, 2320,  147,  116,  214,
-      233,  181,   29, 2380,  534,  555, 2325,  617,  126,    0,
-     2359,  178, 3619, 3619,  614,  268,    0, 2297,  677, 3619,
-     3619, 2296,  315, 2295, 2337,  243,  280,  295, 2339, 2292,
-     3619, 2336, 2320, 2274,  705,  777,  789,  824,  859,  894,
-     2307, 2259,  934,  129,  975, 1015, 2252, 2232, 2224, 2221,
-     2229, 2224, 2213, 2222,  287, 2193, 2197, 2162, 2162, 2167,
-      323,  321, 2170,  235,  163,  304,  811,  331, 2217, 2215,
-      638,  369, 1057, 1092,  724,  379, 2193, 2184,  730,  421,
-
-     2166, 2163,  363,  628, 1127,  808,  437, 1168,  834, 2162,
-      365,  434, 2153, 2151, 2141, 2139, 2119, 2117,  422, 2099,
-     2095, 2069, 2082, 2069,  413,  444,  542,  495,  528, 1210,
-     1245, 1280, 2106, 2105,  842, 2097, 2074, 2072, 2035,  563,
-      867,  570,  875,  586, 1315,    0,  885, 1326,  911,  674,
-     1367,  953,  603, 3619, 2006, 1993, 2006, 1986, 1962, 1965,
-     1965, 1929,  538, 1922, 1905, 1906,  328,  431,   21,  556,
-      920,  592, 1409, 1444,  994, 1944, 1942, 1874, 1872, 1477,
-      684, 1034, 1067, 1077,  686,  691,  756, 1000,  767, 1519,
-        0, 1102, 1530, 1111,  961, 1571, 1146, 1854, 1831,  663,
-
-      526, 1809, 1816,  790,  791,  655, 1823, 1742,  239,  580,
-      640,  721, 1612, 1646, 1680, 1774, 1765, 1757, 1185, 1715,
-     1193, 1042, 1755, 1220, 1228, 1766, 1255, 1265, 1290,  770,
-      985, 1025, 1298, 1298, 1337, 1797,    0, 1348, 1808, 1384,
-     1154, 1849, 1419, 1697, 1690,  847, 3619, 1689, 1682, 1693,
-     1632,  959, 3619, 1000, 3619,  652, 1618, 1595,  539, 1044,
-      576,  740, 1427,  670, 1890, 1924, 1462, 1634, 1633, 1392,
-      808, 1468, 1058, 1959,    0,  764, 1970, 1495, 1236, 2010,
-     1549, 1590, 1622, 1632, 1137, 1265, 1656, 1658, 1503, 1660,
-     2052,    0, 1690, 2063, 1669, 1435, 1699, 1534, 1531, 1534,
-
-     1530, 1100, 1101, 1509, 1447, 1439,  816,  572, 1849, 1428,
-     2105, 2140, 2175, 2210, 1450, 1734, 1774, 1827, 1368, 1211,
-     1246, 1866, 1281, 2245,    0,  798, 2256, 1898, 1452, 2296,
-     1908, 1932, 1346, 1942, 1989, 2029, 1540, 1581, 2073,  819,
-      853, 2338,    0,  896, 1152, 1284, 1248, 1113, 1193, 3619,
-     1351, 3619, 1089, 1552, 2087,  813,  872,  671, 1322, 2087,
-     1090, 2348, 2383, 2418, 2453, 1785, 2035, 1123, 2120, 2150,
-     2130, 1083, 1040, 1410, 1623, 2158, 1669, 2488,    0,  937,
-     2499, 2183, 1598, 2539, 2193, 2219, 2228, 2274, 1725, 1026,
-     1121, 1369, 3619, 1392,  958,  877,  811,  836, 1594,  742,
-
-     1455, 1675, 2383, 1677, 2418, 2581, 2616, 2651, 2282, 1875,
-     2315, 2358, 2396,  760,  715, 1828, 1943, 2429, 1971, 2686,
-        0, 1171, 2697, 2437, 1742, 2463,  717, 2472, 2517, 1998,
-      649, 1596, 3619, 1740,  619, 3619,  559, 3619, 1288, 2525,
-     1311, 2739, 2774, 2558, 2564,  530, 2591, 2601, 2626,  451,
-      437, 2087,  371,  363, 2634,    0, 1301, 1780, 3619, 1832,
-     2097, 2809, 2844, 2879, 2659, 2667, 2675,  326,    0,  305,
-     1833, 3619,  200, 2715, 1664, 2914, 2949, 2725, 3619, 2748,
-     2758, 1916, 3619,  175, 3619, 2785, 2793, 2826,  127, 2859,
-     2835, 3619, 2997, 3011, 3025, 3039, 3053, 3067, 3081, 3095,
-
-     3109, 3123, 3129, 3143, 3157, 1360, 3171, 3185, 3199, 3213,
-     3227, 3241, 3255, 3269, 3275, 3282, 3296, 3310, 3316, 3323,
-     3329, 3335, 3341, 3348, 3354, 3360, 3366, 3373, 3381, 3387,
-     3393, 3399, 3406, 3414, 3420, 3426, 3433, 3441, 3447, 3455,
-     3462, 3470, 3476, 3484, 3491, 3499, 3513, 3527, 3533, 3541,
-     3548, 3562, 3568, 3576, 3582, 3590, 1881, 3604
+        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[659] =
+static yyconst short int yy_def[663] =
     {   0,
-      592,    1,    1,    1,  593,  593,  594,  594,  595,  595,
-      596,  596,  592,  597,  592,  592,  592,  598,  599,  600,
-      592,  592,  601,  592,  602,  597,   26,   26,  603,  592,
-      592,  592,   32,   32,   34,   34,   34,   34,  597,   26,
-      597,  592,  599,   32,   32,   34,   34,   34,  592,  592,
-      604,  597,  605,  592,  605,  592,  605,  592,  599,  592,
-      606,  607,  592,  607,  592,  607,  592,  608,  609,  609,
-      609,  592,  592,  597,  597,  592,  592,  598,  610,  598,
-      611,  592,  612,  592,  600,  613,  600,  601,  601,  602,
-      614,  597,  597,   26,  603,   94,   94,   94,   94,  615,
-
-      616,   32,   34,   34,   34,   34,   34,   34,  597,  592,
-      597,  592,  592,  592,  592,  592,  592,  611,  597,   94,
-      597,  597,  597,  592,  592,  604,  617,  597,  597,  605,
-      605,  592,  592,  592,  612,  592,  606,  607,  607,  592,
-      592,  607,  607,  609,  592,  609,  609,  592,  592,  597,
-      592,  611,  618,  613,  613,  592,  597,  597,  597,   94,
-      160,  619,  592,  620,  592,   32,   34,   34,   34,   34,
-       34,   34,   34,   34,  597,  592,  592,  592,  592,  592,
-      611,  597,  160,  597,  597,  597,  592,  597,  592,  618,
-      597,  597,  597,  597,  597,  597,  621,  622,  622,  199,
-
-      623,  622,  624,  165,  592,  205,  205,  592,  205,   34,
-       34,   34,   34,   34,   34,   34,   34,   34,  597,  592,
-      592,  592,  592,  592,  611,  597,  597,  597,  597,  597,
-      597,  597,  592,  625,  625,  235,  625,  626,  627,  628,
-      592,  629,  208,  629,  629,  245,  629,  592,  248,  248,
-      592,  248,  592,  592,   34,   34,   34,   34,   34,   34,
-       34,   34,  597,  592,  592,  592,  611,  597,  597,  597,
-      597,  597,  597,  597,  597,  630,  630,  631,  632,  592,
-      592,  592,  592,  592,  633,  633,  634,  251,  634,  634,
-      290,  634,  592,  293,  293,  592,  293,   34,   34,   34,
-
-       34,   34,   34,   34,   34,  597,  592,  592,  611,  597,
-      597,  597,  597,  597,  597,  592,  635,  636,  280,  592,
-      320,  320,  592,  320,  592,  592,  592,  592,  592,  592,
-      637,  637,  638,  296,  638,  638,  336,  638,  592,  339,
-      339,  592,  339,   34,   34,  592,  592,   34,   34,   34,
-       34,  592,  592,  592,  592,  597,  592,  592,  611,  597,
-      597,  597,  597,  597,  597,  597,  597,  592,  639,  592,
-      640,  323,  640,  640,  374,  374,  592,  377,  377,  592,
-      377,  592,  592,  592,  592,  641,  641,  642,  342,  642,
-      642,  391,  642,  592,  394,  394,  394,   34,   34,   34,
-
-       34,   34,   34,  597,  592,  592,  611,  597,  597,  597,
-      597,  597,  597,  597,  592,  592,  592,  592,  643,  643,
-      644,  380,  644,  644,  424,  424,  592,  427,  427,  592,
-      427,  592,  592,  592,  592,  592,  592,  645,  645,  646,
-      646,  646,  442,  442,   34,   34,   34,   34,  592,  592,
-      592,  592,  592,  592,  611,  611,  597,  647,  648,  597,
-      597,  597,  597,  597,  597,  597,  592,  592,  592,  592,
-      592,  592,  649,  649,  650,  430,  650,  650,  478,  478,
-      592,  481,  481,  592,  481,  592,  592,  592,  592,  651,
-      651,  592,  592,   34,   34,   34,  592,  652,  611,  597,
-
-      647,  647,  647,  648,  648,  597,  597,  597,  597,  597,
-      592,  592,  592,  592,  653,  653,  654,  484,  654,  654,
-      520,  520,  592,  523,  523,  523,  592,  592,  592,  592,
-      592,  592,  592,   34,   34,  592,  652,  592,  611,  597,
-      597,  597,  597,  597,  592,  592,  592,  592,  592,  592,
-      655,  655,  656,  656,  656,  555,  555,  592,  592,   34,
-      611,  597,  597,  597,  592,  592,  592,  592,  657,  657,
-      592,  592,  658,  597,  597,  597,  597,  597,  592,  592,
-      592,  592,  592,  658,  592,  597,  597,  597,  597,  597,
-      597,    0,  592,  592,  592,  592,  592,  592,  592,  592,
-
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592
+      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[3685] =
+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,
@@ -563,408 +566,414 @@ static yyconst short int yy_nxt[3685] =
        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,   75,   43,
-       50,   50,  146,   15,   54,   55,   75,   56,  311,   51,
-       51,   86,  186,   56,   70,   16,   71,   72,   15,   54,
-       55,   75,   56,   44,   45,   56,   57,   46,   56,   70,
-
-       16,   71,   72,  140,   47,   87,  147,   48,  111,   91,
-       56,   57,   75,   91,   91,  136,  110,  141,  145,   58,
-       98,   98,   98,   98,   98,   99,  139,   52,   52,  129,
-       73,   91,  143,  110,   58,   15,   16,   17,  163,   59,
-      139,  148,  149,  163,  144,   73,   75,  165,  592,   82,
-      145,  175,  204,   92,   97,   97,   97,   97,   97,   97,
-       97,   97,   74,   75,   96,   96,   96,   96,   96,   96,
-       96,   96,   87,   75,   75,  182,  112,  585,  188,  136,
-      110,   60,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   15,
-
-       16,   17,  585,   59,  113,  114,  181,   74,  115,   74,
-       75,   74,  228,   74,   74,  116,  125,   74,  117,   84,
-       84,   84,   84,   84,   84,   84,   84,   74,   75,   74,
-       74,   74,   84,   84,   84,   84,   84,   84,   84,   84,
-      185,   82,  136,  110,  146,   60,   61,   61,   61,   61,
-       61,   61,   61,   61,   61,   61,   61,   61,   61,   61,
-       61,   61,   61,   15,   16,   17,   63,   59,  183,  136,
-      110,  127,   64,   65,   66,  127,  127,  132,  110,  133,
-       75,  134,   75,  147,  169,  133,   67,  134,   75,  170,
-      145,  359,  171,  127,  172,  184,  148,  149,  226,  134,
-
-      134,   84,   84,   84,   84,   84,   84,   84,   84,   68,
-       15,   16,   17,   63,   59,  128,  136,  110,  370,   64,
-       65,   66,   85,  134,   85,   82,   85,  145,   85,   85,
-       82,   91,   85,   67,   75,   91,   91,  157,  158,  159,
-      157,  157,  157,  157,  157,   85,   85,  219,   88,  518,
-       88,   75,   88,   91,   88,   88,   68,   79,   88,   79,
-       74,   79,  139,   79,   79,  226,  253,   79,   75,   75,
-       88,   88,   88,  226,  225,   92,  592,  163,   75,   79,
-       79,   79,  191,   90,  370,   74,  204,   90,  254,   74,
-       74,  229,  309,   90,  161,  161,  161,  161,  161,  161,
-
-      161,  161,   95,   80,   82,   90,   90,   74,  161,  161,
-      161,  161,  161,  161,   83,   82,   75,   84,   84,   84,
-       84,   84,   84,   84,   84,   93,   75,   94,   94,   94,
-       94,   94,   94,   94,   94,   95,  237,  237,  237,   96,
-       96,   96,   96,   96,  161,  161,  161,  161,  161,  161,
-      161,  161,  246,  246,  246,  246,  246,  247,  310,   75,
-      518,   96,   96,   96,   96,   96,   96,   74,  255,   75,
-      267,   74,  256,   74,  476,  263,   74,   74,   75,   74,
-       74,   74,  102,  102,  102,  102,  102,  102,  102,  102,
-       95,   75,  268,   74,  102,  102,  102,  102,  102,  103,
-
-      103,  103,  103,  103,  103,  103,  103,  103,  103,  103,
-      103,  103,  103,  103,   75,  103,   96,   96,   96,   96,
-       96,   96,   74,   74,   74,   74,   74,   74,   74,   74,
-       74,   74,  103,  103,  103,  103,  103,  103,  103,  103,
-      592,   82,   75,  545,  103,  103,  103,  103,  103,   84,
-       84,   84,   84,   84,   84,   84,   84,  226,  127,  112,
-      348,  538,  127,  127,  349,   95,   74,   74,   74,   74,
-       74,   74,  109,  110,   74,   75,   74,  163,   74,   74,
-      127,  270,   74,  241,  163,   75,  204,  113,  114,   75,
-      306,  115,  407,  243,   74,   74,   74,   82,  116,  592,
-
-      163,  117,  128,   75,  253,  271,  269,   83,  312,  243,
-       84,   84,   84,   84,   84,   84,   84,   84,  126,   75,
-       74,  457,  126,   75,   74,   74,  254,   75,  126,  592,
-      592,  592,  592,  592,  592,  592,  592,  360,  409,   75,
-      126,  126,   74,  209,  209,  209,  209,  209,  209,  209,
-      209,  118,   82,  230,  231,  232,  230,  230,  230,  230,
-      230,  560,  135,  163,  346,  592,  592,  592,  592,  592,
-      592,  592,  592,   79,  502,   79,  150,   79,  138,   79,
-       79,  138,  138,   79,  363,   75,  347,   75,  138,  291,
-      291,  291,  291,  291,  292,   79,   79,   79,  163,   75,
-
-      163,  138,   75,  361,  241,  163,  154,  204,  154,  243,
-      154,  356,  154,  154,  243,  404,  154,   75,  503,   80,
-      160,  160,  160,  160,  160,  160,  160,  160,  154,  154,
-      154,  163,  160,  160,  160,  160,  160,  191,  476,  192,
-      192,  192,  192,  192,  192,  235,  235,  236,  237,  237,
-      237,  237,  237,  201,  160,  160,  160,  160,  160,  160,
-      166,  166,  166,  166,  166,  166,  166,  166,   75,  241,
-      163,   75,  166,  166,  166,  166,  166,  362,   91,  288,
-      592,  163,   91,  422,  163,  419,  419,   75,   91,   75,
-      288,  352,  354,  243,  160,  160,  160,  160,  160,  160,
-
-       91,   91,  191,  410,  192,  192,  192,  192,  192,  192,
-      192,  192,  127,  353,  355,   82,  127,  455,   82,  473,
-      473,  370,  127,  245,  245,  245,  245,  245,  245,  245,
-      245,  372,  241,  163,  127,  127,   75,  191,  538,  193,
-      193,  193,  193,  193,  193,  193,  193,  592,  346,  244,
-      244,  244,  244,  244,  244,  244,  244,  277,  277,  277,
-      277,  277,  277,  277,  277,  201,  592,  163,  456,  499,
-      347,   75,  191,  536,  194,  194,  194,  194,  194,  195,
-      192,  192,  282,  283,  284,  282,  282,  282,  282,  282,
-      252,  252,  252,  252,  252,  252,  252,  252,  241,  163,
-
-      286,  286,  286,  286,  286,  286,   75,   74,  243,  196,
-      196,  196,  196,  196,  196,  196,  196,  490,  490,   75,
-      535,  196,  196,  196,  196,  196,  290,  290,  290,  290,
-      290,  290,  290,  290,  500,  313,  314,  315,  313,  313,
-      313,  313,  313,  196,  196,  196,  196,  196,  196,  198,
-      199,  200,  200,  200,  200,  200,  200,  201,  515,  515,
-      352,  202,  202,  202,  202,  202,  592,   75,  289,  289,
-      289,  289,  289,  289,  289,  289,  337,  337,  337,  337,
-      337,  338,  353,  202,  202,  202,  202,  202,  202,  163,
-      205,  206,  207,  205,  205,  205,  205,  205,  208,  163,
-
-      534,  354,  209,  209,  209,  209,  209,  271,  288,  272,
-      272,  272,  272,  272,  272,  297,  297,  297,  297,  297,
-      297,  297,  297,  355,  209,  209,  209,  209,  209,  209,
-      210,  210,  210,  210,  210,  210,  210,  210,  241,  163,
-      163,   75,  210,  210,  210,  210,  210,  325,  288,  326,
-      326,  326,  326,  326,  326,  326,  326,  375,  375,  375,
-      375,  375,  376,  422,  196,  196,  196,  196,  196,  196,
-      191,  592,  192,  192,  192,  192,  192,  192,  192,  192,
-      325,  372,  327,  327,  327,  327,  327,  327,  327,  327,
-      325,   75,  328,  328,  328,  328,  328,  329,  326,  326,
-
-      408,  449,  451,  460,   75,  191,  372,  192,  192,  192,
-      192,  192,  192,  192,  192,  241,  163,  332,  332,  332,
-      332,  332,  332,  450,  452,  288,  336,  336,  336,  336,
-      336,  336,  336,  336,  241,  163,  467,   75,  497,   75,
-      241,  163,  242,  242,  242,  242,  242,  242,  242,  242,
-      243,  163,  496,  492,  244,  244,  244,  244,  244,  592,
-      288,  335,  335,  335,  335,  335,  335,  335,  335,  392,
-      392,  392,  392,  392,  393,  493,  244,  244,  244,  244,
-      244,  244,  163,  248,  249,  250,  248,  248,  248,  248,
-      248,  251,  551,  551,  449,  252,  252,  252,  252,  252,
-
-      324,  324,  324,  324,  324,  324,  324,  324,  374,  374,
-      374,  374,  374,  374,  374,  374,  450,  252,  252,  252,
-      252,  252,  252,  271,  370,  272,  272,  272,  272,  272,
-      272,  272,  272,  592,  372,  373,  373,  373,  373,  373,
-      373,  373,  373,  382,  383,  384,  382,  382,  382,  382,
-      382,  425,  425,  425,  425,  425,  426,   75,  271,  370,
-      273,  273,  273,  273,  273,  273,  273,  273,  325,  422,
-      326,  326,  326,  326,  326,  326,  326,  326,  325,  163,
-      326,  326,  326,  326,  326,  326,  326,  326,  334,  561,
-       82,  495,   75,  271,  592,  274,  274,  274,  274,  274,
-
-      275,  272,  272,  325,  422,  326,  326,  326,  326,  326,
-      326,  241,  163,  343,  343,  343,  343,  343,  343,  343,
-      343,  334,  569,  569,  540,  502,  494,   75,  241,  163,
-      286,  286,  286,  286,  286,  286,  286,  286,  243,  241,
-      163,  287,  287,  287,  287,  287,  287,  287,  287,  288,
-      592,  163,  451,  289,  289,  289,  289,  289,   75,  432,
-      334,  241,  163,  387,  387,  387,  387,  387,  387,  505,
-      492,  334,  137,  137,  452,  289,  289,  289,  289,  289,
-      289,  163,  293,  294,  295,  293,  293,  293,  293,  293,
-      296,  372,  493,  532,  297,  297,  297,  297,  297,  391,
-
-      391,  391,  391,  391,  391,  391,  391,  416,  417,  418,
-      416,  416,  416,  416,  416,  533,  297,  297,  297,  297,
-      297,  297,  271,  370,  272,  272,  272,  272,  272,  272,
-      272,  272,  592,  422,  390,  390,  390,  390,  390,  390,
-      390,  390,  411,  412,  413,  414,  411,  411,  411,  411,
-      443,  443,  443,  443,  443,  444,   75,  271,  592,  272,
-      272,  272,  272,  272,  272,  272,  272,  479,  479,  479,
-      479,  479,  480,  319,   75,   75,  363,  364,  364,  364,
-      364,  364,  364,  381,  381,  381,  381,  381,  381,  381,
-      381,   75,  320,  321,  322,  320,  320,  320,  320,  320,
-
-      323,  454,  503,  453,  324,  324,  324,  324,  324,   75,
-      424,  424,  424,  424,  424,  424,  424,  424,  397,  397,
-      397,  397,  397,  397,  397,  397,  324,  324,  324,  324,
-      324,  324,  241,  163,  332,  332,  332,  332,  332,  332,
-      332,  332,  288,  241,  163,  333,  333,  333,  333,  333,
-      333,  333,  333,  334,  163,  458,   75,  335,  335,  335,
-      335,  335,  592,  334,  423,  423,  423,  423,  423,  423,
-      423,  423,  448,  447,  446,  458,  445,  458,  458,  335,
-      335,  335,  335,  335,  335,  163,  339,  340,  341,  339,
-      339,  339,  339,  339,  342,  163,   82,  532,  343,  343,
-
-      343,  343,  343,  432,  389,  433,  433,  433,  433,  433,
-      433,  433,  433,  521,  521,  521,  521,  521,  522,  533,
-      343,  343,  343,  343,  343,  343,  363,  364,  364,  364,
-      364,  364,  364,  364,  364,  432,  370,  434,  434,  434,
-      434,  434,  434,  434,  434,  432,  476,  435,  435,  435,
-      435,  435,  436,  433,  433,  539,  319,  239,  406,   75,
-      363,  365,  365,  365,  365,  365,  365,  365,  365,  241,
-      163,  241,  163,  592,  163,  405,  403,  574,  592,  334,
-      592,  389,  592,  389,  442,  442,  442,  442,  442,  442,
-      442,  442,  476,   75,  363,  366,  366,  366,  366,  366,
-
-      367,  364,  364,  241,  163,  439,  439,  439,  439,  439,
-      439,   75,  592,  389,  441,  441,  441,  441,  441,  441,
-      441,  441,  503,  402,  505,  401,  400,   75,  370,  399,
-      371,  371,  371,  371,  371,  371,  371,  371,  372,  163,
-      398,  558,  373,  373,  373,  373,  373,  467,  389,  468,
-      468,  468,  468,  468,  468,  468,  468,  556,  556,  556,
-      556,  556,  557,  559,  373,  373,  373,  373,  373,  373,
-      377,  378,  379,  377,  377,  377,  377,  377,  380,  325,
-      319,  558,  381,  381,  381,  381,  381,  467,  239,  469,
-      469,  469,  469,  469,  469,  469,  469,  201,  460,  358,
-
-      510,  510,  510,  559,  381,  381,  381,  381,  381,  381,
-      241,  163,  387,  387,  387,  387,  387,  387,  387,  387,
-      334,  241,  163,  388,  388,  388,  388,  388,  388,  388,
-      388,  389,   75,  571,  571,  390,  390,  390,  390,  390,
-      467,  370,  470,  470,  470,  470,  470,  471,  468,  468,
-      357,  476,  458,  351,  350,  572,  572,  390,  390,  390,
-      390,  390,  390,  163,  394,  395,  396,  394,  394,  394,
-      394,  394,  458,  345,  458,  459,  397,  397,  397,  397,
-      397,  431,  431,  431,  431,  431,  431,  431,  431,  583,
-      510,  510,  510,  344,  583,  319,   75,  239,  397,  397,
-
-      397,  397,  397,  397,  363,  364,  364,  364,  364,  364,
-      364,  364,  364,  478,  478,  478,  478,  478,  478,  478,
-      478,  592,   75,  477,  477,  477,  477,  477,  477,  477,
-      477,  579,  579,  579,  579,  579,  579,   75,  363,  364,
-      364,  364,  364,  364,  364,  364,  364,  486,  487,  488,
-      486,  486,  486,  486,  486,  432,  370,  433,  433,  433,
-      433,  433,  433,  433,  433,  201,  518,  201,  264,  308,
-      307,   75,  370,  305,  420,  420,  420,  420,  420,  420,
-      420,  420,  372,  370,  592,  421,  421,  421,  421,  421,
-      421,  421,  421,  422,  518,  304,  303,  423,  423,  423,
-
-      423,  423,  432,  302,  433,  433,  433,  433,  433,  433,
-      433,  433,  163,  527,  527,  527,  527,  527,  527,  423,
-      423,  423,  423,  423,  423,  427,  428,  429,  427,  427,
-      427,  427,  427,  430,  301,  300,  299,  431,  431,  431,
-      431,  431,  432,  298,  433,  433,  433,  433,  433,  433,
-      511,  512,  513,  511,  511,  511,  511,  511,  280,  431,
-      431,  431,  431,  431,  431,  241,  163,  439,  439,  439,
-      439,  439,  439,  439,  439,  389,  241,  163,  440,  440,
-      440,  440,  440,  440,  440,  440,  241,  163,  455,   82,
-      441,  441,  441,  441,  441,  239,  389,  201,  561,   82,
-
-      370,  498,  506,  507,  508,  506,  506,  506,  506,  506,
-      518,  573,  441,  441,  441,  441,  441,  441,  460,  276,
-      461,  461,  461,  461,  461,  461,  461,  461,  201,  101,
-      264,  266,  264,  467,   75,  468,  468,  468,  468,  468,
-      468,  468,  468,  467,  265,  468,  468,  468,  468,  468,
-      468,  264,   75,  460,  262,  462,  462,  462,  462,  462,
-      462,  462,  462,  467,  261,  468,  468,  468,  468,  468,
-      468,  468,  468,  485,  485,  485,  485,  485,  485,  485,
-      485,  260,  259,  258,  257,   95,  201,   75,  460,  239,
-      463,  463,  463,  463,  463,  464,  465,  465,  520,  520,
-
-      520,  520,  520,  520,  520,  520,  592,  201,  519,  519,
-      519,  519,  519,  519,  519,  519,  101,   82,  189,  227,
-      224,  223,   75,  460,  222,  466,  466,  466,  461,  461,
-      461,  461,  461,  163,  527,  527,  527,  527,  527,  527,
-      527,  527,  163,  528,  528,  528,  528,  528,  528,  528,
-      528,  221,  220,  218,  217,  216,  215,   75,  370,  214,
-      474,  474,  474,  474,  474,  474,  474,  474,  422,  370,
-      213,  475,  475,  475,  475,  475,  475,  475,  475,  476,
-      212,  211,  101,  477,  477,  477,  477,  477,  163,  529,
-      529,  529,  529,  529,  530,  527,  527,  509,  509,  509,
-
-      509,  509,  509,  509,  509,  477,  477,  477,  477,  477,
-      477,  481,  482,  483,  481,  481,  481,  481,  481,  484,
-       93,  155,   82,  485,  485,  485,  485,  485,  545,   75,
-      546,  546,  546,  546,  546,  546,  546,  546,   82,   75,
-      189,  144,  145,  139,  139,  485,  485,  485,  485,  485,
-      485,  241,  163,  491,  491,  491,  491,  491,  491,  491,
-      491,  460,  131,  465,  465,  465,  465,  465,  465,  465,
-      465,  545,  187,  547,  547,  547,  547,  547,  547,  547,
-      547,  124,  180,  179,  501,  178,  177,  176,  501,  174,
-      501,  501,  173,  168,  501,   75,  460,  167,  465,  465,
-
-      465,  465,  465,  465,  465,  465,  501,  501,  501,  545,
-      101,  548,  548,  548,  548,  548,  549,  546,  546,  504,
-       74,  101,  156,  504,   89,  504,  504,  155,   82,  504,
-       75,  460,  150,  465,  465,  465,  465,  465,  465,  509,
-      509,  504,  504,  504,  526,  526,  526,  526,  526,  526,
-      526,  526,  555,  555,  555,  555,  555,  555,  555,  555,
-      151,   77,   76,   75,  145,   75,  460,  139,  509,  509,
-      509,  509,  509,  509,  509,  509,  592,  131,  554,  554,
-      554,  554,  554,  554,  554,  554,  163,  527,  527,  527,
-      527,  527,  527,  527,  527,  124,  123,  122,  121,  120,
-
-       75,  370,  119,  516,  516,  516,  516,  516,  516,  516,
-      516,  476,  370,  108,  517,  517,  517,  517,  517,  517,
-      517,  517,  518,  107,  106,  105,  519,  519,  519,  519,
-      519,  163,  527,  527,  527,  527,  527,  527,  527,  527,
-      562,  563,  564,  562,  562,  562,  562,  562,  519,  519,
-      519,  519,  519,  519,  523,  524,  525,  523,  523,  523,
-      523,  523,  104,  101,   89,   77,  526,  526,  526,  526,
-      526,  540,   75,  541,  541,  541,  541,  541,  541,  565,
-      566,  567,  565,  565,  565,  565,  565,   76,  526,  526,
-      526,  526,  526,  526,  540,   75,  541,  541,  541,  541,
-
-      541,  541,  541,  541,  545,   75,  546,  546,  546,  546,
-      546,  546,  546,  546,  545,  592,  546,  546,  546,  546,
-      546,  546,  546,  546,  592,  592,  592,  592,   75,  540,
-      592,  542,  542,  542,  542,  542,  542,  542,  542,  545,
-      592,  546,  546,  546,  546,  546,  546,  370,  592,  570,
-      570,  570,  570,  570,  570,  570,  570,  592,  592,  592,
-      592,  592,  592,   75,  540,  592,  543,  543,  543,  543,
-      543,  544,  541,  541,  579,  579,  579,  579,  579,  579,
-      579,  579,  580,  580,  580,  580,  580,  580,  580,  580,
-      581,  581,  581,  581,  581,  582,  579,  579,   75,  370,
-
-      592,  552,  552,  552,  552,  552,  552,  552,  552,  518,
-      370,  592,  553,  553,  553,  553,  553,  553,  553,  553,
-      592,  592,  592,  592,  554,  554,  554,  554,  554,  592,
-      586,  587,  588,  586,  586,  586,  586,  586,  574,  592,
-      575,  575,  575,  575,  575,  575,  554,  554,  554,  554,
-      554,  554,  540,  592,  541,  541,  541,  541,  541,  541,
-      541,  541,   75,  579,  579,  579,  579,  579,  579,  579,
-      579,  592,   75,  579,  579,  579,  579,  579,  579,  579,
-      579,  592,  592,  592,  592,  592,   75,  540,  592,  541,
-      541,  541,  541,  541,  541,  541,  541,  592,  592,  592,
-
-      589,  589,  589,  589,  589,  589,  589,  589,  586,  586,
-      586,  586,  586,  586,  586,  586,  592,  592,  592,  592,
-      592,   75,  574,  592,  575,  575,  575,  575,  575,  575,
-      575,  575,   75,  592,  592,  592,  592,  592,  592,  592,
-       75,  590,  590,  590,  590,  590,  591,  589,  589,  592,
-      589,  589,  589,  589,  589,  589,   75,  574,  592,  576,
-      576,  576,  576,  576,  576,  576,  576,  592,  592,  592,
-      592,  592,  592,   75,  589,  589,  589,  589,  589,  589,
-      589,  589,   75,  592,  592,  592,  592,  592,  592,  592,
-      592,   75,  574,  592,  577,  577,  577,  577,  577,  578,
-
-      575,  575,  592,  592,  592,  592,   75,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,   75,  574,  592,  575,
-      575,  575,  575,  575,  575,  575,  575,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,   75,  574,  592,  575,  575,  575,  575,  575,  575,
-      575,  575,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,   75,   53,   53,   53,
-
-       53,   53,   53,   53,   53,   53,   53,   53,   53,   53,
-       53,   31,   31,   31,   31,   31,   31,   31,   31,   31,
-       31,   31,   31,   31,   31,   62,   62,   62,   62,   62,
-       62,   62,   62,   62,   62,   62,   62,   62,   62,   69,
-       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
-       69,   69,   69,   74,  592,  592,  592,   74,  592,   74,
-       74,   74,  592,  592,   74,   74,   74,   78,   78,  592,
-       78,   78,   78,   78,   78,   78,   78,   78,   78,   78,
-       78,   81,   81,   81,   81,   81,   81,   81,   81,   81,
-       81,   81,   81,   81,   81,   85,  592,  592,  592,   85,
-
-      592,   85,   85,   85,   85,  592,   85,   85,   85,   88,
-      592,  592,  592,   88,  592,   88,   88,   88,  592,  592,
-       88,   88,   88,   90,  592,  592,   90,   90,   90,   90,
-       90,   90,  592,  592,   90,   90,   90,  100,  100,  592,
-      592,  592,  100,  126,  592,  592,  126,  126,  126,  126,
-      126,  126,  592,  592,  126,  126,  126,  130,  592,  592,
-      130,  130,  130,  130,  130,  130,  592,  130,  592,  130,
-      130,  138,  592,  592,  138,  592,  138,  138,  138,  138,
-      138,  592,  138,  138,  138,  142,  142,  142,  142,  142,
-      142,  142,  142,  142,  142,  142,  142,  142,  142,  144,
-
-      144,  592,  144,  592,  144,  144,  144,  144,  144,  144,
-      144,  144,  144,   79,   79,  592,   79,   79,   79,   79,
-       79,   79,   79,   79,   79,   79,   79,  152,  152,  152,
+       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,  153,  153,  592,  153,  153,  153,  153,  153,  153,
-      153,  153,  153,  153,  153,  154,  592,  592,  592,  154,
-      592,  154,  154,  154,  592,  592,  154,  154,  154,   91,
-      592,  592,   91,   91,   91,   91,   91,   91,  592,  592,
-       91,   91,   91,  162,  162,  592,  592,  592,  162,  164,
-      164,  164,  592,  592,  592,  164,  127,  592,  592,  127,
-
-      127,  127,  127,  127,  127,  592,  592,  127,  127,  127,
-      190,  190,  190,  190,  190,  190,  190,  190,  190,  190,
-      190,  190,  190,  190,  197,  197,  592,  592,  592,  197,
-      203,  203,  203,  592,  592,  592,  203,  233,  233,  592,
-      592,  592,  233,  234,  234,  592,  592,  592,  234,  238,
-      238,  592,  592,  592,  238,  240,  240,  240,  592,  592,
-      592,  240,  276,  276,  592,  592,  592,  276,  278,  278,
-      592,  592,  592,  278,  279,  279,  592,  592,  592,  279,
-      281,  281,  281,  592,  592,  592,  281,  285,  285,  285,
-      285,  592,  592,  592,  285,  316,  316,  592,  592,  592,
-
-      316,  317,  317,  592,  592,  592,  317,  318,  318,  592,
-      592,  592,  318,  330,  330,  330,  592,  592,  592,  330,
-      331,  331,  331,  331,  592,  592,  592,  331,  368,  368,
-      592,  592,  592,  368,  369,  369,  592,  592,  592,  369,
-      385,  385,  385,  592,  592,  592,  385,  386,  386,  386,
-      386,  592,  592,  592,  386,  415,  415,  592,  592,  592,
-      415,  419,  592,  419,  419,  592,  592,  592,  419,  437,
-      437,  437,  592,  592,  592,  437,  438,  438,  438,  438,
-      592,  592,  592,  438,  472,  472,  592,  592,  592,  472,
-      473,  592,  473,  473,  592,  592,  592,  473,  489,  489,
-
-      489,  592,  592,  592,  489,  490,  490,  490,  592,  592,
-      592,  592,  490,  501,  592,  592,  501,  501,  592,  501,
-      501,  501,  592,  592,  501,  501,  501,  504,  592,  592,
-      504,  504,  592,  504,  504,  504,  592,  592,  504,  504,
-      504,  514,  514,  592,  592,  592,  514,  515,  592,  515,
-      515,  592,  592,  592,  515,  531,  531,  592,  592,  592,
-      592,  531,  537,  537,  537,  537,  537,  537,  537,  537,
-      537,  537,  537,  537,  537,  537,  550,  550,  592,  592,
-      592,  550,  551,  592,  551,  551,  592,  592,  592,  551,
-      568,  568,  592,  592,  592,  568,  569,  592,  569,  592,
-
-      592,  592,  592,  569,  584,  584,  584,  584,  584,  584,
-      584,  584,  584,  584,  584,  584,  584,  584,   13,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592
+      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[3685] =
+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,
@@ -972,405 +981,411 @@ static yyconst short int yy_chk[3685] =
         1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
         1,    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,  269,    2,
-        3,    4,   70,    5,    5,    5,  123,    5,  269,    3,
-        4,   20,  123,    5,   11,   11,   11,   11,    6,    6,
-        6,   41,    6,    2,    2,    5,    5,    2,    6,   12,
-
-       12,   12,   12,   64,    2,   20,   71,    2,   41,   25,
-        6,    6,   52,   25,   25,   60,   60,   66,   70,    5,
-       28,   28,   28,   28,   28,   28,   64,    3,    4,   52,
-       11,   25,   68,   68,    6,    7,    7,    7,  101,    7,
-       66,   73,   73,  164,   73,   12,  111,  101,   85,  118,
-       71,  111,  164,   25,   27,   27,   27,   27,   27,   27,
-       27,   27,   40,  119,   40,   40,   40,   40,   40,   40,
-       40,   40,   85,  129,  589,  119,   42,  584,  129,  132,
-      132,    7,    7,    7,    7,    7,    7,    7,    7,    7,
-        7,    7,    7,    7,    7,    7,    7,    7,    7,    8,
-
-        8,    8,  573,    8,   42,   42,  118,   75,   42,   75,
-      185,   75,  185,   75,   75,   42,   50,   75,   42,   50,
-       50,   50,   50,   50,   50,   50,   50,  120,  122,   75,
-       75,   75,   83,   83,   83,   83,   83,   83,   83,   83,
-      122,  309,  109,  109,  146,    8,    8,    8,    8,    8,
+        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,    9,    9,    9,    9,    9,  120,  136,
-      136,   51,    9,    9,    9,   51,   51,   58,   58,   58,
-      121,   58,  184,  147,  106,   58,    9,   58,  109,  106,
-      146,  309,  106,   51,  106,  121,  148,  148,  184,   58,
-
-       58,   84,   84,   84,   84,   84,   84,   84,   84,    9,
-       10,   10,   10,   10,   10,   51,  143,  143,  570,   10,
-       10,   10,   87,   58,   87,  181,   87,  147,   87,   87,
-      267,   90,   87,   10,  175,   90,   90,   93,   93,   93,
-       93,   93,   93,   93,   93,   87,   87,  175,   89,  568,
-       89,  186,   89,   90,   89,   89,   10,   18,   89,   18,
-       18,   18,  143,   18,   18,  186,  211,   18,  182,   93,
-       89,   89,   89,  182,  181,   90,  554,  203,  188,   18,
-       18,   18,  192,   92,  553,   92,  203,   92,  211,   92,
-       92,  188,  267,   92,   97,   97,   97,   97,   97,   97,
-
-       97,   97,  196,   18,   19,   92,   92,   92,   99,   99,
-       99,   99,   99,   99,   19,  225,  192,   19,   19,   19,
-       19,   19,   19,   19,   19,   26,  196,   26,   26,   26,
-       26,   26,   26,   26,   26,   26,  200,  200,  200,   26,
-       26,   26,   26,   26,   98,   98,   98,   98,   98,   98,
-       98,   98,  207,  207,  207,  207,  207,  207,  268,   26,
-      551,   26,   26,   26,   26,   26,   26,   32,  212,  219,
-      225,   32,  212,   32,  550,  219,   32,   32,  268,   32,
-       32,   32,   32,   32,   32,   32,   32,   32,   32,   32,
-       32,  226,  226,   32,   32,   32,   32,   32,   32,   32,
-
+        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,   34,   34,   34,   34,   34,   34,   34,   34,
-       34,  359,  228,  546,   34,   34,   34,   34,   34,  125,
-      125,  125,  125,  125,  125,  125,  125,  228,  126,  112,
-      301,  537,  126,  126,  301,  227,   34,   34,   34,   34,
-       34,   34,   39,   39,   39,  229,   39,  240,   39,   39,
-      126,  229,   39,  242,  242,  263,  240,  112,  112,  227,
-      263,  112,  359,  242,   39,   39,   39,   43,  112,  244,
-
-      244,  112,  126,  270,  253,  272,  227,   43,  270,  244,
-       43,   43,   43,   43,   43,   43,   43,   43,  128,  408,
-      128,  408,  128,  361,  128,  128,  253,  310,  128,  135,
-      135,  135,  135,  135,  135,  135,  135,  310,  361,  272,
-      128,  128,  128,  204,  204,  204,  204,  204,  204,  204,
-      204,   43,   59,  191,  191,  191,  191,  191,  191,  191,
-      191,  535,   59,  531,  300,   59,   59,   59,   59,   59,
-       59,   59,   59,   78,  458,   78,   78,   78,  139,   78,
-       78,  139,  139,   78,  364,  191,  300,  311,  139,  250,
-      250,  250,  250,  250,  250,   78,   78,   78,  281,  356,
-
-      285,  139,  306,  311,  286,  286,  155,  281,  155,  285,
-      155,  306,  155,  155,  286,  356,  155,  364,  458,   78,
-       94,   94,   94,   94,   94,   94,   94,   94,  155,  155,
-      155,  527,   94,   94,   94,   94,   94,  195,  515,  195,
-      195,  195,  195,  195,  195,  199,  199,  199,  199,  199,
-      199,  199,  199,  199,   94,   94,   94,   94,   94,   94,
-      102,  102,  102,  102,  102,  102,  102,  102,  312,  287,
-      287,  195,  102,  102,  102,  102,  102,  312,  156,  287,
-      289,  289,  156,  514,  330,  376,  376,  362,  156,  500,
-      289,  304,  305,  330,  102,  102,  102,  102,  102,  102,
-
-      156,  156,  157,  362,  157,  157,  157,  157,  157,  157,
-      157,  157,  187,  304,  305,  456,  187,  407,  407,  426,
-      426,  371,  187,  206,  206,  206,  206,  206,  206,  206,
-      206,  371,  440,  440,  187,  187,  157,  158,  498,  158,
-      158,  158,  158,  158,  158,  158,  158,  209,  346,  209,
-      209,  209,  209,  209,  209,  209,  209,  235,  235,  235,
-      235,  235,  235,  235,  235,  235,  441,  441,  407,  456,
-      346,  158,  159,  497,  159,  159,  159,  159,  159,  159,
-      159,  159,  241,  241,  241,  241,  241,  241,  241,  241,
-      243,  243,  243,  243,  243,  243,  243,  243,  247,  247,
-
-      247,  247,  247,  247,  247,  247,  159,  160,  247,  160,
-      160,  160,  160,  160,  160,  160,  160,  444,  444,  457,
-      496,  160,  160,  160,  160,  160,  249,  249,  249,  249,
-      249,  249,  249,  249,  457,  271,  271,  271,  271,  271,
-      271,  271,  271,  160,  160,  160,  160,  160,  160,  163,
-      163,  163,  163,  163,  163,  163,  163,  163,  480,  480,
-      352,  163,  163,  163,  163,  163,  252,  271,  252,  252,
-      252,  252,  252,  252,  252,  252,  295,  295,  295,  295,
-      295,  295,  352,  163,  163,  163,  163,  163,  163,  165,
-      165,  165,  165,  165,  165,  165,  165,  165,  165,  331,
-
-      495,  354,  165,  165,  165,  165,  165,  275,  331,  275,
-      275,  275,  275,  275,  275,  288,  288,  288,  288,  288,
-      288,  288,  288,  354,  165,  165,  165,  165,  165,  165,
-      166,  166,  166,  166,  166,  166,  166,  166,  332,  332,
-      490,  275,  166,  166,  166,  166,  166,  282,  332,  282,
-      282,  282,  282,  282,  282,  282,  282,  322,  322,  322,
-      322,  322,  322,  473,  166,  166,  166,  166,  166,  166,
-      193,  373,  193,  193,  193,  193,  193,  193,  193,  193,
-      283,  373,  283,  283,  283,  283,  283,  283,  283,  283,
-      284,  360,  284,  284,  284,  284,  284,  284,  284,  284,
-
-      360,  402,  403,  461,  193,  194,  472,  194,  194,  194,
-      194,  194,  194,  194,  194,  292,  292,  292,  292,  292,
-      292,  292,  292,  402,  403,  292,  294,  294,  294,  294,
-      294,  294,  294,  294,  491,  491,  468,  461,  453,  194,
-      205,  205,  205,  205,  205,  205,  205,  205,  205,  205,
-      205,  385,  448,  445,  205,  205,  205,  205,  205,  297,
-      385,  297,  297,  297,  297,  297,  297,  297,  297,  341,
-      341,  341,  341,  341,  341,  445,  205,  205,  205,  205,
-      205,  205,  208,  208,  208,  208,  208,  208,  208,  208,
-      208,  208,  522,  522,  449,  208,  208,  208,  208,  208,
-
-      319,  319,  319,  319,  319,  319,  319,  319,  321,  321,
-      321,  321,  321,  321,  321,  321,  449,  208,  208,  208,
-      208,  208,  208,  230,  420,  230,  230,  230,  230,  230,
-      230,  230,  230,  324,  420,  324,  324,  324,  324,  324,
-      324,  324,  324,  325,  325,  325,  325,  325,  325,  325,
-      325,  379,  379,  379,  379,  379,  379,  230,  231,  421,
-      231,  231,  231,  231,  231,  231,  231,  231,  327,  421,
-      327,  327,  327,  327,  327,  327,  327,  327,  328,  386,
-      328,  328,  328,  328,  328,  328,  328,  328,  386,  539,
-      539,  447,  231,  232,  423,  232,  232,  232,  232,  232,
-
-      232,  232,  232,  329,  423,  329,  329,  329,  329,  329,
-      329,  333,  333,  334,  334,  334,  334,  334,  334,  334,
-      334,  333,  557,  557,  541,  459,  446,  232,  245,  245,
-      245,  245,  245,  245,  245,  245,  245,  245,  245,  248,
-      248,  248,  248,  248,  248,  248,  248,  248,  248,  248,
-      335,  335,  451,  248,  248,  248,  248,  248,  541,  433,
-      335,  338,  338,  338,  338,  338,  338,  338,  338,  459,
-      492,  338,  606,  606,  451,  248,  248,  248,  248,  248,
-      248,  251,  251,  251,  251,  251,  251,  251,  251,  251,
-      251,  419,  492,  494,  251,  251,  251,  251,  251,  340,
-
-      340,  340,  340,  340,  340,  340,  340,  370,  370,  370,
-      370,  370,  370,  370,  370,  494,  251,  251,  251,  251,
-      251,  251,  273,  474,  273,  273,  273,  273,  273,  273,
-      273,  273,  343,  474,  343,  343,  343,  343,  343,  343,
-      343,  343,  363,  363,  363,  363,  363,  363,  363,  363,
-      396,  396,  396,  396,  396,  396,  273,  274,  501,  274,
-      274,  274,  274,  274,  274,  274,  274,  429,  429,  429,
-      429,  429,  429,  415,  363,  410,  367,  367,  367,  367,
-      367,  367,  367,  372,  372,  372,  372,  372,  372,  372,
-      372,  274,  280,  280,  280,  280,  280,  280,  280,  280,
-
-      280,  406,  501,  405,  280,  280,  280,  280,  280,  367,
-      378,  378,  378,  378,  378,  378,  378,  378,  389,  389,
-      389,  389,  389,  389,  389,  389,  280,  280,  280,  280,
-      280,  280,  290,  290,  290,  290,  290,  290,  290,  290,
-      290,  290,  290,  293,  293,  293,  293,  293,  293,  293,
-      293,  293,  293,  293,  437,  454,  404,  293,  293,  293,
-      293,  293,  381,  437,  381,  381,  381,  381,  381,  381,
-      381,  381,  401,  400,  399,  454,  398,  454,  454,  293,
-      293,  293,  293,  293,  293,  296,  296,  296,  296,  296,
-      296,  296,  296,  296,  296,  438,  499,  532,  296,  296,
-
-      296,  296,  296,  382,  438,  382,  382,  382,  382,  382,
-      382,  382,  382,  483,  483,  483,  483,  483,  483,  532,
-      296,  296,  296,  296,  296,  296,  313,  313,  313,  313,
-      313,  313,  313,  313,  313,  383,  475,  383,  383,  383,
-      383,  383,  383,  383,  383,  384,  475,  384,  384,  384,
-      384,  384,  384,  384,  384,  499,  369,  368,  358,  313,
-      314,  314,  314,  314,  314,  314,  314,  314,  314,  387,
-      387,  388,  388,  390,  390,  357,  351,  575,  502,  387,
-      504,  388,  477,  390,  395,  395,  395,  395,  395,  395,
-      395,  395,  477,  314,  315,  315,  315,  315,  315,  315,
-
-      315,  315,  315,  393,  393,  393,  393,  393,  393,  393,
-      393,  575,  397,  393,  397,  397,  397,  397,  397,  397,
-      397,  397,  502,  350,  504,  349,  348,  315,  320,  345,
-      320,  320,  320,  320,  320,  320,  320,  320,  320,  489,
-      344,  534,  320,  320,  320,  320,  320,  416,  489,  416,
-      416,  416,  416,  416,  416,  416,  416,  525,  525,  525,
-      525,  525,  525,  534,  320,  320,  320,  320,  320,  320,
-      323,  323,  323,  323,  323,  323,  323,  323,  323,  326,
-      318,  558,  323,  323,  323,  323,  323,  417,  317,  417,
-      417,  417,  417,  417,  417,  417,  417,  316,  466,  308,
-
-      466,  466,  466,  558,  323,  323,  323,  323,  323,  323,
-      336,  336,  336,  336,  336,  336,  336,  336,  336,  336,
-      336,  339,  339,  339,  339,  339,  339,  339,  339,  339,
-      339,  339,  466,  560,  571,  339,  339,  339,  339,  339,
-      418,  516,  418,  418,  418,  418,  418,  418,  418,  418,
-      307,  516,  409,  303,  302,  560,  571,  339,  339,  339,
-      339,  339,  339,  342,  342,  342,  342,  342,  342,  342,
-      342,  342,  409,  299,  409,  409,  342,  342,  342,  342,
-      342,  422,  422,  422,  422,  422,  422,  422,  422,  657,
-      510,  510,  510,  298,  657,  279,  409,  278,  342,  342,
-
-      342,  342,  342,  342,  365,  365,  365,  365,  365,  365,
-      365,  365,  365,  428,  428,  428,  428,  428,  428,  428,
-      428,  431,  510,  431,  431,  431,  431,  431,  431,  431,
-      431,  582,  582,  582,  582,  582,  582,  365,  366,  366,
-      366,  366,  366,  366,  366,  366,  366,  432,  432,  432,
-      432,  432,  432,  432,  432,  434,  517,  434,  434,  434,
-      434,  434,  434,  434,  434,  277,  517,  276,  266,  265,
-      264,  366,  374,  262,  374,  374,  374,  374,  374,  374,
-      374,  374,  374,  377,  519,  377,  377,  377,  377,  377,
-      377,  377,  377,  377,  519,  261,  260,  377,  377,  377,
-
-      377,  377,  435,  259,  435,  435,  435,  435,  435,  435,
-      435,  435,  530,  530,  530,  530,  530,  530,  530,  377,
-      377,  377,  377,  377,  377,  380,  380,  380,  380,  380,
-      380,  380,  380,  380,  258,  257,  256,  380,  380,  380,
-      380,  380,  436,  255,  436,  436,  436,  436,  436,  436,
-      467,  467,  467,  467,  467,  467,  467,  467,  239,  380,
-      380,  380,  380,  380,  380,  391,  391,  391,  391,  391,
-      391,  391,  391,  391,  391,  391,  394,  394,  394,  394,
-      394,  394,  394,  394,  394,  394,  439,  439,  455,  455,
-      394,  394,  394,  394,  394,  238,  439,  237,  561,  561,
-
-      552,  455,  460,  460,  460,  460,  460,  460,  460,  460,
-      552,  561,  394,  394,  394,  394,  394,  394,  411,  236,
-      411,  411,  411,  411,  411,  411,  411,  411,  234,  233,
-      224,  223,  222,  469,  460,  469,  469,  469,  469,  469,
-      469,  469,  469,  471,  221,  471,  471,  471,  471,  471,
-      471,  220,  411,  412,  218,  412,  412,  412,  412,  412,
-      412,  412,  412,  470,  217,  470,  470,  470,  470,  470,
-      470,  470,  470,  476,  476,  476,  476,  476,  476,  476,
-      476,  216,  215,  214,  213,  210,  202,  412,  413,  201,
-      413,  413,  413,  413,  413,  413,  413,  413,  482,  482,
-
-      482,  482,  482,  482,  482,  482,  485,  198,  485,  485,
-      485,  485,  485,  485,  485,  485,  197,  190,  189,  183,
-      180,  179,  413,  414,  178,  414,  414,  414,  414,  414,
-      414,  414,  414,  486,  486,  486,  486,  486,  486,  486,
-      486,  486,  487,  487,  487,  487,  487,  487,  487,  487,
-      487,  177,  176,  174,  173,  172,  171,  414,  424,  170,
-      424,  424,  424,  424,  424,  424,  424,  424,  424,  427,
-      169,  427,  427,  427,  427,  427,  427,  427,  427,  427,
-      168,  167,  162,  427,  427,  427,  427,  427,  488,  488,
-      488,  488,  488,  488,  488,  488,  488,  509,  509,  509,
-
-      509,  509,  509,  509,  509,  427,  427,  427,  427,  427,
-      427,  430,  430,  430,  430,  430,  430,  430,  430,  430,
-      161,  154,  153,  430,  430,  430,  430,  430,  511,  509,
-      511,  511,  511,  511,  511,  511,  511,  511,  152,  150,
-      149,  145,  144,  142,  138,  430,  430,  430,  430,  430,
-      430,  442,  442,  442,  442,  442,  442,  442,  442,  442,
-      442,  462,  131,  462,  462,  462,  462,  462,  462,  462,
-      462,  512,  127,  512,  512,  512,  512,  512,  512,  512,
-      512,  124,  117,  116,  503,  115,  114,  113,  503,  108,
-      503,  503,  107,  105,  503,  462,  463,  104,  463,  463,
-
-      463,  463,  463,  463,  463,  463,  503,  503,  503,  513,
-      100,  513,  513,  513,  513,  513,  513,  513,  513,  505,
-       96,   95,   91,  505,   88,  505,  505,   86,   81,  505,
-      463,  464,   80,  464,  464,  464,  464,  464,  464,  464,
-      464,  505,  505,  505,  518,  518,  518,  518,  518,  518,
-      518,  518,  524,  524,  524,  524,  524,  524,  524,  524,
-       79,   77,   76,   74,   69,  464,  465,   62,  465,  465,
-      465,  465,  465,  465,  465,  465,  526,   55,  526,  526,
-      526,  526,  526,  526,  526,  526,  528,  528,  528,  528,
-      528,  528,  528,  528,  528,   49,   48,   47,   46,   45,
-
-      465,  478,   44,  478,  478,  478,  478,  478,  478,  478,
-      478,  478,  481,   38,  481,  481,  481,  481,  481,  481,
-      481,  481,  481,   37,   36,   35,  481,  481,  481,  481,
-      481,  529,  529,  529,  529,  529,  529,  529,  529,  529,
-      540,  540,  540,  540,  540,  540,  540,  540,  481,  481,
-      481,  481,  481,  481,  484,  484,  484,  484,  484,  484,
-      484,  484,   33,   29,   23,   17,  484,  484,  484,  484,
-      484,  544,  540,  544,  544,  544,  544,  544,  544,  545,
-      545,  545,  545,  545,  545,  545,  545,   15,  484,  484,
-      484,  484,  484,  484,  506,   14,  506,  506,  506,  506,
-
-      506,  506,  506,  506,  547,  544,  547,  547,  547,  547,
-      547,  547,  547,  547,  548,   13,  548,  548,  548,  548,
-      548,  548,  548,  548,    0,    0,    0,    0,  506,  507,
-        0,  507,  507,  507,  507,  507,  507,  507,  507,  549,
-        0,  549,  549,  549,  549,  549,  549,  555,    0,  555,
-      555,  555,  555,  555,  555,  555,  555,    0,    0,    0,
-        0,    0,    0,  507,  508,    0,  508,  508,  508,  508,
-      508,  508,  508,  508,  565,  565,  565,  565,  565,  565,
-      565,  565,  566,  566,  566,  566,  566,  566,  566,  566,
-      567,  567,  567,  567,  567,  567,  567,  567,  508,  520,
-
-        0,  520,  520,  520,  520,  520,  520,  520,  520,  520,
-      523,    0,  523,  523,  523,  523,  523,  523,  523,  523,
-        0,    0,    0,    0,  523,  523,  523,  523,  523,    0,
-      574,  574,  574,  574,  574,  574,  574,  574,  578,    0,
-      578,  578,  578,  578,  578,  578,  523,  523,  523,  523,
-      523,  523,  542,    0,  542,  542,  542,  542,  542,  542,
-      542,  542,  574,  580,  580,  580,  580,  580,  580,  580,
-      580,    0,  578,  581,  581,  581,  581,  581,  581,  581,
-      581,    0,    0,    0,    0,    0,  542,  543,    0,  543,
-      543,  543,  543,  543,  543,  543,  543,    0,    0,    0,
-
-      586,  586,  586,  586,  586,  586,  586,  586,  587,  587,
-      587,  587,  587,  587,  587,  587,    0,    0,    0,    0,
-        0,  543,  562,    0,  562,  562,  562,  562,  562,  562,
-      562,  562,  586,    0,    0,    0,    0,    0,    0,    0,
-      587,  588,  588,  588,  588,  588,  588,  588,  588,    0,
-      591,  591,  591,  591,  591,  591,  562,  563,    0,  563,
-      563,  563,  563,  563,  563,  563,  563,    0,    0,    0,
-        0,    0,    0,  588,  590,  590,  590,  590,  590,  590,
-      590,  590,  591,    0,    0,    0,    0,    0,    0,    0,
-        0,  563,  564,    0,  564,  564,  564,  564,  564,  564,
-
-      564,  564,    0,    0,    0,    0,  590,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,  564,  576,    0,  576,
-      576,  576,  576,  576,  576,  576,  576,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,  576,  577,    0,  577,  577,  577,  577,  577,  577,
-      577,  577,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    0,    0,    0,  577,  593,  593,  593,
-
-      593,  593,  593,  593,  593,  593,  593,  593,  593,  593,
-      593,  594,  594,  594,  594,  594,  594,  594,  594,  594,
-      594,  594,  594,  594,  594,  595,  595,  595,  595,  595,
-      595,  595,  595,  595,  595,  595,  595,  595,  595,  596,
-      596,  596,  596,  596,  596,  596,  596,  596,  596,  596,
-      596,  596,  596,  597,    0,    0,    0,  597,    0,  597,
-      597,  597,    0,    0,  597,  597,  597,  598,  598,    0,
+       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,  599,  599,  599,  599,  599,  599,  599,  599,  599,
-      599,  599,  599,  599,  599,  600,    0,    0,    0,  600,
-
-        0,  600,  600,  600,  600,    0,  600,  600,  600,  601,
-        0,    0,    0,  601,    0,  601,  601,  601,    0,    0,
-      601,  601,  601,  602,    0,    0,  602,  602,  602,  602,
-      602,  602,    0,    0,  602,  602,  602,  603,  603,    0,
-        0,    0,  603,  604,    0,    0,  604,  604,  604,  604,
-      604,  604,    0,    0,  604,  604,  604,  605,    0,    0,
-      605,  605,  605,  605,  605,  605,    0,  605,    0,  605,
-      605,  607,    0,    0,  607,    0,  607,  607,  607,  607,
-      607,    0,  607,  607,  607,  608,  608,  608,  608,  608,
-      608,  608,  608,  608,  608,  608,  608,  608,  608,  609,
-
-      609,    0,  609,    0,  609,  609,  609,  609,  609,  609,
-      609,  609,  609,  610,  610,    0,  610,  610,  610,  610,
-      610,  610,  610,  610,  610,  610,  610,  611,  611,  611,
-      611,  611,  611,  611,  611,  611,  611,  611,  611,  611,
-      611,  612,  612,    0,  612,  612,  612,  612,  612,  612,
-      612,  612,  612,  612,  612,  613,    0,    0,    0,  613,
-        0,  613,  613,  613,    0,    0,  613,  613,  613,  614,
-        0,    0,  614,  614,  614,  614,  614,  614,    0,    0,
-      614,  614,  614,  615,  615,    0,    0,    0,  615,  616,
-      616,  616,    0,    0,    0,  616,  617,    0,    0,  617,
-
-      617,  617,  617,  617,  617,    0,    0,  617,  617,  617,
-      618,  618,  618,  618,  618,  618,  618,  618,  618,  618,
-      618,  618,  618,  618,  619,  619,    0,    0,    0,  619,
-      620,  620,  620,    0,    0,    0,  620,  621,  621,    0,
-        0,    0,  621,  622,  622,    0,    0,    0,  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,  629,
-      629,    0,    0,    0,  629,  630,  630,    0,    0,    0,
-
-      630,  631,  631,    0,    0,    0,  631,  632,  632,    0,
-        0,    0,  632,  633,  633,  633,    0,    0,    0,  633,
-      634,  634,  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,    0,  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,    0,    0,
-        0,    0,  646,  647,    0,    0,  647,  647,    0,  647,
-      647,  647,    0,    0,  647,  647,  647,  648,    0,    0,
-      648,  648,    0,  648,  648,  648,    0,    0,  648,  648,
-      648,  649,  649,    0,    0,    0,  649,  650,    0,  650,
-      650,    0,    0,    0,  650,  651,  651,    0,    0,    0,
-        0,  651,  652,  652,  652,  652,  652,  652,  652,  652,
-      652,  652,  652,  652,  652,  652,  653,  653,    0,    0,
-        0,  653,  654,    0,  654,  654,    0,    0,    0,  654,
-      655,  655,    0,    0,    0,  655,  656,    0,  656,    0,
-
-        0,    0,    0,  656,  658,  658,  658,  658,  658,  658,
-      658,  658,  658,  658,  658,  658,  658,  658,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592,  592,  592,  592,  592,  592,  592,
-      592,  592,  592,  592
+      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;
@@ -1453,42 +1468,35 @@ char *yytext;
 #  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 = 1;
+int sudolineno;
 char *sudoers;
-static int sawspace = 0;
-static int arg_len = 0;
-static int arg_size = 0;
-
-static int append              __P((char *, int));
-static int _fill               __P((char *, int, int));
-static int fill_cmnd           __P((char *, int));
-static int fill_args           __P((char *, int, int));
+
+static int continued, prev_state, sawspace;
+
 static int _push_include       __P((char *, int));
 static int pop_include         __P((void));
-static int ipv6_valid          __P((const char *s));
 static char *parse_include     __P((char *));
-extern void yyerror            __P((const char *));
 
-#define fill(a, b)             _fill(a, b, 0)
+#define fill(a, b)             fill_txt(a, b, 0)
 
 #define        push_include(_p)        (_push_include((_p), FALSE))
 #define        push_includedir(_p)     (_push_include((_p), TRUE))
 
-/* realloc() to size + COMMANDARGINC to make room for command args */
-#define COMMANDARGINC  64
-
 #ifdef TRACELEXER
 #define LEXTRACE(msg)  fputs(msg, stderr)
 #else
 #define LEXTRACE(msg)
 #endif
+#define YY_NO_INPUT 1
 #define YY_NO_UNPUT 1
 #define GOTDEFS 1
 
@@ -1500,7 +1508,7 @@ extern void yyerror               __P((const char *));
 
 #define INSTR 5
 
-#line 1504 "lex.yy.c"
+#line 1511 "lex.yy.c"
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -1654,9 +1662,9 @@ YY_DECL
        register char *yy_cp, *yy_bp;
        register int yy_act;
 
-#line 127 "toke.l"
+#line 120 "toke.l"
 
-#line 1660 "lex.yy.c"
+#line 1667 "lex.yy.c"
 
        if ( yy_init )
                {
@@ -1708,13 +1716,13 @@ yy_match:
                        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 >= 593 )
+                               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] != 3619 );
+               while ( yy_base[yy_current_state] != 3671 );
 
 yy_find_action:
                yy_act = yy_accept[yy_current_state];
@@ -1742,105 +1750,140 @@ do_action:    /* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 128 "toke.l"
-BEGIN STARTDEFS;
+#line 121 "toke.l"
+{
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
        YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 130 "toke.l"
+#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);
+                           return DEFVAR;
                        }
        YY_BREAK
 
-case 3:
+case 4:
 YY_RULE_SETUP
-#line 139 "toke.l"
+#line 137 "toke.l"
 {
                            BEGIN STARTDEFS;
                            LEXTRACE(", ");
-                           return(',');
+                           return ',';
                        }                       /* return ',' */
        YY_BREAK
-case 4:
+case 5:
 YY_RULE_SETUP
-#line 145 "toke.l"
+#line 143 "toke.l"
 {
                            LEXTRACE("= ");
-                           return('=');
+                           return '=';
                        }                       /* return '=' */
        YY_BREAK
-case 5:
+case 6:
 YY_RULE_SETUP
-#line 150 "toke.l"
+#line 148 "toke.l"
 {
                            LEXTRACE("+= ");
-                           return('+');
+                           return '+';
                        }                       /* return '+' */
        YY_BREAK
-case 6:
+case 7:
 YY_RULE_SETUP
-#line 155 "toke.l"
+#line 153 "toke.l"
 {
                            LEXTRACE("-= ");
-                           return('-');
+                           return '-';
                        }                       /* return '-' */
        YY_BREAK
-case 7:
+case 8:
 YY_RULE_SETUP
-#line 160 "toke.l"
+#line 158 "toke.l"
 {
                            LEXTRACE("BEGINSTR ");
                            yylval.string = NULL;
+                           prev_state = YY_START;
                            BEGIN INSTR;
                        }
        YY_BREAK
-case 8:
+case 9:
 YY_RULE_SETUP
-#line 166 "toke.l"
+#line 165 "toke.l"
 {
                            LEXTRACE("WORD(2) ");
                            if (!fill(yytext, yyleng))
                                yyterminate();
-                           return(WORD);
+                           return WORD;
                        }
        YY_BREAK
 
 
-case 9:
+case 10:
 YY_RULE_SETUP
-#line 175 "toke.l"
+#line 174 "toke.l"
 {
                            /* Line continuation char followed by newline. */
                            ++sudolineno;
-                           LEXTRACE("\n");
+                           continued = TRUE;
                        }
        YY_BREAK
-case 10:
+case 11:
 YY_RULE_SETUP
-#line 181 "toke.l"
+#line 180 "toke.l"
 {
                            LEXTRACE("ENDSTR ");
-                           BEGIN INDEFS;
-                           return(WORD);
+                           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 11:
+case 12:
 YY_RULE_SETUP
-#line 187 "toke.l"
+#line 212 "toke.l"
 {
                            LEXTRACE("BACKSLASH ");
                            if (!append(yytext, yyleng))
                                yyterminate();
                        }
        YY_BREAK
-case 12:
+case 13:
 YY_RULE_SETUP
-#line 193 "toke.l"
+#line 218 "toke.l"
 {
                            LEXTRACE("STRBODY ");
                            if (!append(yytext, yyleng))
@@ -1849,9 +1892,9 @@ YY_RULE_SETUP
        YY_BREAK
 
 
-case 13:
+case 14:
 YY_RULE_SETUP
-#line 201 "toke.l"
+#line 226 "toke.l"
 {
                            /* quoted fnmatch glob char, pass verbatim */
                            LEXTRACE("QUOTEDCHAR ");
@@ -1860,9 +1903,9 @@ YY_RULE_SETUP
                            sawspace = FALSE;
                        }
        YY_BREAK
-case 14:
+case 15:
 YY_RULE_SETUP
-#line 209 "toke.l"
+#line 234 "toke.l"
 {
                            /* quoted sudoers special char, strip backslash */
                            LEXTRACE("QUOTEDCHAR ");
@@ -1871,18 +1914,18 @@ YY_RULE_SETUP
                            sawspace = FALSE;
                        }
        YY_BREAK
-case 15:
+case 16:
 YY_RULE_SETUP
-#line 217 "toke.l"
+#line 242 "toke.l"
 {
                            BEGIN INITIAL;
                            yyless(0);
-                           return(COMMAND);
+                           return COMMAND;
                        }                       /* end of command line args */
        YY_BREAK
-case 16:
+case 17:
 YY_RULE_SETUP
-#line 223 "toke.l"
+#line 248 "toke.l"
 {
                            LEXTRACE("ARG ");
                            if (!fill_args(yytext, yyleng, sawspace))
@@ -1891,12 +1934,17 @@ YY_RULE_SETUP
                        }                       /* a command line arg */
        YY_BREAK
 
-case 17:
+case 18:
 YY_RULE_SETUP
-#line 231 "toke.l"
+#line 256 "toke.l"
 {
                            char *path;
 
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
                            if ((path = parse_include(yytext)) == NULL)
                                yyterminate();
 
@@ -1907,12 +1955,17 @@ YY_RULE_SETUP
                                yyterminate();
                        }
        YY_BREAK
-case 18:
+case 19:
 YY_RULE_SETUP
-#line 244 "toke.l"
+#line 274 "toke.l"
 {
                            char *path;
 
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
                            if ((path = parse_include(yytext)) == NULL)
                                yyterminate();
 
@@ -1926,252 +1979,278 @@ YY_RULE_SETUP
                                yyterminate();
                        }
        YY_BREAK
-case 19:
+case 20:
 YY_RULE_SETUP
-#line 260 "toke.l"
+#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 += 8;
+                           n += sizeof("Defaults") - 1;
+                           if ((deftype = yytext[n++]) != '\0') {
+                               while (isblank((unsigned char)yytext[n]))
+                                   n++;
+                           }
                            BEGIN GOTDEFS;
-                           switch (yytext[n++]) {
+                           switch (deftype) {
                                case ':':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_USER ");
-                                   return(DEFAULTS_USER);
+                                   return DEFAULTS_USER;
                                case '>':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_RUNAS ");
-                                   return(DEFAULTS_RUNAS);
+                                   return DEFAULTS_RUNAS;
                                case '@':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_HOST ");
-                                   return(DEFAULTS_HOST);
+                                   return DEFAULTS_HOST;
                                case '!':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_CMND ");
-                                   return(DEFAULTS_CMND);
+                                   return DEFAULTS_CMND;
                                default:
                                    LEXTRACE("DEFAULTS ");
-                                   return(DEFAULTS);
+                                   return DEFAULTS;
                            }
                        }
        YY_BREAK
-case 20:
+case 21:
 YY_RULE_SETUP
-#line 289 "toke.l"
+#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);
+                                   return HOSTALIAS;
                                case 'C':
                                    LEXTRACE("CMNDALIAS ");
-                                   return(CMNDALIAS);
+                                   return CMNDALIAS;
                                case 'U':
                                    LEXTRACE("USERALIAS ");
-                                   return(USERALIAS);
+                                   return USERALIAS;
                                case 'R':
                                    LEXTRACE("RUNASALIAS ");
-                                   return(RUNASALIAS);
+                                   return RUNASALIAS;
                            }
                        }
        YY_BREAK
-case 21:
+case 22:
 YY_RULE_SETUP
-#line 309 "toke.l"
+#line 361 "toke.l"
 {
                                /* cmnd does not require passwd for this user */
                                LEXTRACE("NOPASSWD ");
-                               return(NOPASSWD);
+                               return NOPASSWD;
                        }
        YY_BREAK
-case 22:
+case 23:
 YY_RULE_SETUP
-#line 315 "toke.l"
+#line 367 "toke.l"
 {
                                /* cmnd requires passwd for this user */
                                LEXTRACE("PASSWD ");
-                               return(PASSWD);
+                               return PASSWD;
                        }
        YY_BREAK
-case 23:
+case 24:
 YY_RULE_SETUP
-#line 321 "toke.l"
+#line 373 "toke.l"
 {
                                LEXTRACE("NOEXEC ");
-                               return(NOEXEC);
+                               return NOEXEC;
                        }
        YY_BREAK
-case 24:
+case 25:
 YY_RULE_SETUP
-#line 326 "toke.l"
+#line 378 "toke.l"
 {
                                LEXTRACE("EXEC ");
-                               return(EXEC);
+                               return EXEC;
                        }
        YY_BREAK
-case 25:
+case 26:
 YY_RULE_SETUP
-#line 331 "toke.l"
+#line 383 "toke.l"
 {
                                LEXTRACE("SETENV ");
-                               return(SETENV);
+                               return SETENV;
                        }
        YY_BREAK
-case 26:
+case 27:
 YY_RULE_SETUP
-#line 336 "toke.l"
+#line 388 "toke.l"
 {
                                LEXTRACE("NOSETENV ");
-                               return(NOSETENV);
+                               return NOSETENV;
                        }
        YY_BREAK
-case 27:
+case 28:
 YY_RULE_SETUP
-#line 341 "toke.l"
+#line 393 "toke.l"
 {
                                LEXTRACE("LOG_OUTPUT ");
-                               return(LOG_OUTPUT);
+                               return LOG_OUTPUT;
                        }
        YY_BREAK
-case 28:
+case 29:
 YY_RULE_SETUP
-#line 346 "toke.l"
+#line 398 "toke.l"
 {
                                LEXTRACE("NOLOG_OUTPUT ");
-                               return(NOLOG_OUTPUT);
+                               return NOLOG_OUTPUT;
                        }
        YY_BREAK
-case 29:
+case 30:
 YY_RULE_SETUP
-#line 351 "toke.l"
+#line 403 "toke.l"
 {
                                LEXTRACE("LOG_INPUT ");
-                               return(LOG_INPUT);
+                               return LOG_INPUT;
                        }
        YY_BREAK
-case 30:
+case 31:
 YY_RULE_SETUP
-#line 356 "toke.l"
+#line 408 "toke.l"
 {
                                LEXTRACE("NOLOG_INPUT ");
-                               return(NOLOG_INPUT);
+                               return NOLOG_INPUT;
                        }
        YY_BREAK
-case 31:
+case 32:
 YY_RULE_SETUP
-#line 361 "toke.l"
+#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);
+                           return NETGROUP;
                        }
        YY_BREAK
-case 32:
+case 34:
 YY_RULE_SETUP
-#line 369 "toke.l"
+#line 427 "toke.l"
 {
-                           /* UN*X group */
+                           /* group */
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("USERGROUP ");
-                           return(USERGROUP);
+                           return USERGROUP;
                        }
        YY_BREAK
-case 33:
+case 35:
 YY_RULE_SETUP
-#line 377 "toke.l"
+#line 435 "toke.l"
 {
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
        YY_BREAK
-case 34:
+case 36:
 YY_RULE_SETUP
-#line 384 "toke.l"
+#line 442 "toke.l"
 {
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
        YY_BREAK
-case 35:
+case 37:
 YY_RULE_SETUP
-#line 391 "toke.l"
+#line 449 "toke.l"
 {
                            if (!ipv6_valid(yytext)) {
                                LEXTRACE("ERROR ");
-                               return(ERROR);
+                               return ERROR;
                            }
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
        YY_BREAK
-case 36:
+case 38:
 YY_RULE_SETUP
-#line 402 "toke.l"
+#line 460 "toke.l"
 {
                            if (!ipv6_valid(yytext)) {
                                LEXTRACE("ERROR ");
-                               return(ERROR);
+                               return ERROR;
                            }
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
        YY_BREAK
-case 37:
+case 39:
 YY_RULE_SETUP
-#line 413 "toke.l"
+#line 471 "toke.l"
 {
                            if (strcmp(yytext, "ALL") == 0) {
                                LEXTRACE("ALL ");
-                               return(ALL);
+                               return ALL;
                            }
 #ifdef HAVE_SELINUX
                            /* XXX - restrict type/role to initial state */
                            if (strcmp(yytext, "TYPE") == 0) {
                                LEXTRACE("TYPE ");
-                               return(TYPE);
+                               return TYPE;
                            }
                            if (strcmp(yytext, "ROLE") == 0) {
                                LEXTRACE("ROLE ");
-                               return(ROLE);
+                               return ROLE;
                            }
 #endif /* HAVE_SELINUX */
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("ALIAS ");
-                           return(ALIAS);
+                           return ALIAS;
                        }
        YY_BREAK
-case 38:
+case 40:
 YY_RULE_SETUP
-#line 435 "toke.l"
+#line 493 "toke.l"
 {
                            /* no command args allowed for Defaults!/path */
                            if (!fill_cmnd(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("COMMAND ");
-                           return(COMMAND);
+                           return COMMAND;
                        }
        YY_BREAK
-case 39:
+case 41:
 YY_RULE_SETUP
-#line 443 "toke.l"
+#line 501 "toke.l"
 {
                            BEGIN GOTCMND;
                            LEXTRACE("COMMAND ");
@@ -2179,16 +2258,16 @@ YY_RULE_SETUP
                                yyterminate();
                        }                       /* sudo -e */
        YY_BREAK
-case 40:
+case 42:
 YY_RULE_SETUP
-#line 450 "toke.l"
+#line 508 "toke.l"
 {
                            /* directories can't have args... */
                            if (yytext[yyleng - 1] == '/') {
                                LEXTRACE("COMMAND ");
                                if (!fill_cmnd(yytext, yyleng))
                                    yyterminate();
-                               return(COMMAND);
+                               return COMMAND;
                            } else {
                                BEGIN GOTCMND;
                                LEXTRACE("COMMAND ");
@@ -2197,127 +2276,125 @@ YY_RULE_SETUP
                            }
                        }                       /* a pathname */
        YY_BREAK
-case 41:
+case 43:
 YY_RULE_SETUP
-#line 465 "toke.l"
+#line 523 "toke.l"
 {
-                           /* a quoted user/group name */
-                           if (!fill(yytext + 1, yyleng - 2))
-                               yyterminate();
-                           switch (yytext[1]) {
-                           case '%':
-                               LEXTRACE("USERGROUP ");
-                               return(USERGROUP);
-                           case '+':
-                               LEXTRACE("NETGROUP ");
-                               return(NETGROUP);
-                           default:
-                               LEXTRACE("WORD(4) ");
-                               return(WORD);
-                           }
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           prev_state = YY_START;
+                           BEGIN INSTR;
                        }
        YY_BREAK
-case 42:
+case 44:
 YY_RULE_SETUP
-#line 482 "toke.l"
+#line 530 "toke.l"
 {
                            /* a word */
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("WORD(5) ");
-                           return(WORD);
+                           return WORD;
                        }
        YY_BREAK
-case 43:
+case 45:
 YY_RULE_SETUP
-#line 490 "toke.l"
+#line 538 "toke.l"
 {
                            LEXTRACE("( ");
-                           return ('(');
+                           return '(';
                        }
        YY_BREAK
-case 44:
+case 46:
 YY_RULE_SETUP
-#line 495 "toke.l"
+#line 543 "toke.l"
 {
                            LEXTRACE(") ");
-                           return(')');
+                           return ')';
                        }
        YY_BREAK
-case 45:
+case 47:
 YY_RULE_SETUP
-#line 500 "toke.l"
+#line 548 "toke.l"
 {
                            LEXTRACE(", ");
-                           return(',');
+                           return ',';
                        }                       /* return ',' */
        YY_BREAK
-case 46:
+case 48:
 YY_RULE_SETUP
-#line 505 "toke.l"
+#line 553 "toke.l"
 {
                            LEXTRACE("= ");
-                           return('=');
+                           return '=';
                        }                       /* return '=' */
        YY_BREAK
-case 47:
+case 49:
 YY_RULE_SETUP
-#line 510 "toke.l"
+#line 558 "toke.l"
 {
                            LEXTRACE(": ");
-                           return(':');
+                           return ':';
                        }                       /* return ':' */
        YY_BREAK
-case 48:
+case 50:
 YY_RULE_SETUP
-#line 515 "toke.l"
+#line 563 "toke.l"
 {
-                           if (yyleng % 2 == 1)
-                               return('!');    /* return '!' */
+                           if (yyleng & 1) {
+                               LEXTRACE("!");
+                               return '!';     /* return '!' */
+                           }
                        }
        YY_BREAK
-case 49:
+case 51:
 YY_RULE_SETUP
-#line 520 "toke.l"
+#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 COMMENT;
                        }                       /* return newline */
        YY_BREAK
-case 50:
+case 52:
 YY_RULE_SETUP
-#line 527 "toke.l"
+#line 582 "toke.l"
 {                      /* throw away space/tabs */
                            sawspace = TRUE;    /* but remember for fill_args */
                        }
        YY_BREAK
-case 51:
+case 53:
 YY_RULE_SETUP
-#line 531 "toke.l"
+#line 586 "toke.l"
 {
                            sawspace = TRUE;    /* remember for fill_args */
                            ++sudolineno;
-                           LEXTRACE("\n\t");
+                           continued = TRUE;
                        }                       /* throw away EOL after \ */
        YY_BREAK
-case 52:
+case 54:
 YY_RULE_SETUP
-#line 537 "toke.l"
+#line 592 "toke.l"
 {
                            BEGIN INITIAL;
                            ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
+                           continued = FALSE;
+                           LEXTRACE("#\n");
+                           return COMMENT;
                        }                       /* comment, not uid/gid */
        YY_BREAK
-case 53:
+case 55:
 YY_RULE_SETUP
-#line 544 "toke.l"
+#line 600 "toke.l"
 {
                            LEXTRACE("ERROR ");
-                           return(ERROR);
+                           return ERROR;
                        }       /* parse error */
        YY_BREAK
 case YY_STATE_EOF(INITIAL):
@@ -2326,23 +2403,23 @@ case YY_STATE_EOF(GOTCMND):
 case YY_STATE_EOF(STARTDEFS):
 case YY_STATE_EOF(INDEFS):
 case YY_STATE_EOF(INSTR):
-#line 549 "toke.l"
+#line 605 "toke.l"
 {
                            if (YY_START != INITIAL) {
                                BEGIN INITIAL;
                                LEXTRACE("ERROR ");
-                               return(ERROR);
+                               return ERROR;
                            }
                            if (!pop_include())
                                yyterminate();
                        }
        YY_BREAK
-case 54:
+case 56:
 YY_RULE_SETUP
-#line 559 "toke.l"
+#line 615 "toke.l"
 ECHO;
        YY_BREAK
-#line 2346 "lex.yy.c"
+#line 2422 "lex.yy.c"
 
        case YY_END_OF_BUFFER:
                {
@@ -2633,7 +2710,7 @@ static yy_state_type yy_get_previous_state()
                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 >= 593 )
+                       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];
@@ -2668,11 +2745,11 @@ yy_state_type yy_current_state;
        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 >= 593 )
+               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 == 592);
+       yy_is_jam = (yy_current_state == 598);
 
        return yy_is_jam ? 0 : yy_current_state;
        }
@@ -3233,178 +3310,7 @@ int main()
        return 0;
        }
 #endif
-#line 559 "toke.l"
-
-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);
-}
-
-static int
-_fill(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);
-}
-
-static int
-append(src, len)
-    char *src;
-    int len;
-{
-    int olen = 0;
-
-    if (yylval.string != NULL)
-       olen = strlen(yylval.string);
-
-    return(_fill(src, len, olen));
-}
-
-#define SPECIAL(c) \
-    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
-
-static int
-fill_cmnd(src, len)
-    char *src;
-    int len;
-{
-    char *dst;
-    int i;
-
-    arg_len = arg_size = 0;
-
-    dst = yylval.command.cmnd = (char *) malloc(len + 1);
-    if (yylval.command.cmnd == NULL) {
-       yyerror("unable to allocate memory");
-       return(FALSE);
-    }
-
-    /* Copy the string and collapse any escaped sudo-specific characters. */
-    for (i = 0; i < len; i++) {
-       if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
-           *dst++ = src[++i];
-       else
-           *dst++ = src[i];
-    }
-    *dst = '\0';
-
-    yylval.command.args = NULL;
-    return(TRUE);
-}
-
-static int
-fill_args(s, len, addspace)
-    char *s;
-    int len;
-    int addspace;
-{
-    int new_len;
-    char *p;
-
-    if (yylval.command.args == NULL) {
-       addspace = 0;
-       new_len = len;
-    } else
-       new_len = arg_len + len + addspace;
-
-    if (new_len >= arg_size) {
-       /* Allocate more space than we need for subsequent args */
-       while (new_len >= (arg_size += COMMANDARGINC))
-           ;
-
-       p = yylval.command.args ?
-           (char *) realloc(yylval.command.args, arg_size) :
-           (char *) malloc(arg_size);
-       if (p == NULL) {
-           efree(yylval.command.args);
-           yyerror("unable to allocate memory");
-           return(FALSE);
-       } else
-           yylval.command.args = p;
-    }
-
-    /* Efficiently append the arg (with a leading space if needed). */
-    p = yylval.command.args + arg_len;
-    if (addspace)
-       *p++ = ' ';
-    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) {
-       yyerror("fill_args: buffer overflow");  /* paranoia */
-       return(FALSE);
-    }
-    arg_len = new_len;
-    return(TRUE);
-}
+#line 615 "toke.l"
 
 struct path_list {
     char *path;
@@ -3427,7 +3333,7 @@ pl_compare(v1, v2)
     const struct path_list * const *p1 = v1;
     const struct path_list * const *p2 = v2;
 
-    return(strcmp((*p1)->path, (*p2)->path));
+    return strcmp((*p1)->path, (*p2)->path);
 }
 
 static char *
@@ -3444,8 +3350,16 @@ switch_dir(stack, dirpath)
     struct path_list **sorted = NULL;
 
     if (!(dir = opendir(dirpath))) {
-       yyerror(dirpath);
-       return(NULL);
+       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. */
@@ -3459,6 +3373,7 @@ switch_dir(stack, dirpath)
        }
        if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
            efree(path);
+           path = NULL;
            continue;
        }
        pl = malloc(sizeof(*pl));
@@ -3503,7 +3418,7 @@ switch_dir(stack, dirpath)
     }
 done:
     efree(dirpath);
-    return(path);
+    return path;
 bad:
     while (first != NULL) {
        pl = first;
@@ -3514,7 +3429,7 @@ bad:
     efree(sorted);
     efree(dirpath);
     efree(path);
-    return(NULL);
+    return NULL;
 }
 
 #define MAX_SUDOERS_DEPTH      128
@@ -3544,7 +3459,11 @@ init_lexer()
     efree(istack);
     istack = NULL;
     istacksize = idepth = 0;
+    sudolineno = 1;
     keepopen = FALSE;
+    sawspace = FALSE;
+    continued = FALSE;
+    prev_state = INITIAL;
 }
 
 static int
@@ -3559,34 +3478,40 @@ _push_include(path, isdir)
     if (idepth >= istacksize) {
        if (idepth > MAX_SUDOERS_DEPTH) {
            yyerror("too many levels of includes");
-           return(FALSE);
+           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);
+           return FALSE;
        }
     }
     if (isdir) {
        if (!(path = switch_dir(&istack[idepth], path))) {
            /* switch_dir() called yyerror() for us */
-           return(FALSE);
+           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);
+               return FALSE;
            path = pl->path;
            istack[idepth].more = pl->next;
            efree(pl);
        }
     } else {
        if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
-           yyerror(path);
-           return(FALSE);
+           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;
     }
@@ -3600,7 +3525,7 @@ _push_include(path, isdir)
     sudoers = path;
     yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
 
-    return(TRUE);
+    return TRUE;
 }
 
 static int
@@ -3610,7 +3535,7 @@ pop_include()
     FILE *fp;
 
     if (idepth == 0)
-       return(FALSE);
+       return FALSE;
 
     if (!keepopen)
        fclose(YY_CURRENT_BUFFER->yy_input_file);
@@ -3641,7 +3566,7 @@ pop_include()
        sudolineno = istack[idepth].lineno;
        keepopen = istack[idepth].keepopen;
     }
-    return(TRUE);
+    return TRUE;
 }
 
 static char *
@@ -3694,28 +3619,5 @@ parse_include(base)
     if (*ep != '\0')
        yyless((int)(ep - base));
 
-    return(path);
-}
-
-/*
- * Check to make sure an IPv6 address does not contain multiple instances
- * of the string "::".  Assumes strlen(s) >= 1.
- * Returns TRUE if address is valid else FALSE.
- */
-static int
-ipv6_valid(s)
-    const char *s;
-{
-    int nmatch = 0;
-
-    for (; *s != '\0'; s++) {
-       if (s[0] == ':' && s[1] == ':') {
-           if (++nmatch > 1)
-               break;
-       }
-       if (s[0] == '/')
-           nmatch = 0;                 /* reset if we hit netmask */
-    }
-
-    return (nmatch <= 1);
+    return path;
 }
diff --git a/toke.h b/toke.h
new file mode 100644 (file)
index 0000000..75e9495
--- /dev/null
+++ b/toke.h
@@ -0,0 +1,30 @@
+/*
+ * 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
index 263693e3519305e2f5b809ca5638b32cc3e42d7a..05ea663e74f96cc1c385c6114b73168d3869e6cf 100644 (file)
--- a/toke.l
+++ b/toke.l
 #  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 = 1;
+int sudolineno;
 char *sudoers;
-static int sawspace = 0;
-static int arg_len = 0;
-static int arg_size = 0;
-
-static int append              __P((char *, int));
-static int _fill               __P((char *, int, int));
-static int fill_cmnd           __P((char *, int));
-static int fill_args           __P((char *, int, int));
+
+static int continued, prev_state, sawspace;
+
 static int _push_include       __P((char *, int));
 static int pop_include         __P((void));
-static int ipv6_valid          __P((const char *s));
 static char *parse_include     __P((char *));
-extern void yyerror            __P((const char *));
 
-#define fill(a, b)             _fill(a, b, 0)
+#define fill(a, b)             fill_txt(a, b, 0)
 
 #define        push_include(_p)        (_push_include((_p), FALSE))
 #define        push_includedir(_p)     (_push_include((_p), TRUE))
 
-/* realloc() to size + COMMANDARGINC to make room for command args */
-#define COMMANDARGINC  64
-
 #ifdef TRACELEXER
 #define LEXTRACE(msg)  fputs(msg, stderr)
 #else
@@ -109,12 +101,13 @@ IPV4ADDR          {OCTET}(\.{OCTET}){3}
 IPV6ADDR               ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR}
 
 HOSTNAME               [[:alnum:]_-]+
-WORD                   ([^#>!=:,\(\) \t\n\\]|\\[^\n])+
+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
 
@@ -125,6 +118,11 @@ DEFVAR                     [a-z_]+
 %x     INSTR
 
 %%
+<GOTDEFS>[[:blank:]]*,[[:blank:]]* {
+                           LEXTRACE(", ");
+                           return ',';
+                       }                       /* return ',' */
+
 <GOTDEFS>[[:blank:]]+  BEGIN STARTDEFS;
 
 <STARTDEFS>{DEFVAR}    {
@@ -132,34 +130,35 @@ DEFVAR                    [a-z_]+
                            LEXTRACE("DEFVAR ");
                            if (!fill(yytext, yyleng))
                                yyterminate();
-                           return(DEFVAR);
+                           return DEFVAR;
                        }
 
 <INDEFS>{
     ,                  {
                            BEGIN STARTDEFS;
                            LEXTRACE(", ");
-                           return(',');
+                           return ',';
                        }                       /* return ',' */
 
     =                  {
                            LEXTRACE("= ");
-                           return('=');
+                           return '=';
                        }                       /* return '=' */
 
     \+=                        {
                            LEXTRACE("+= ");
-                           return('+');
+                           return '+';
                        }                       /* return '+' */
 
     -=                 {
                            LEXTRACE("-= ");
-                           return('-');
+                           return '-';
                        }                       /* return '-' */
 
     \"                 {
                            LEXTRACE("BEGINSTR ");
                            yylval.string = NULL;
+                           prev_state = YY_START;
                            BEGIN INSTR;
                        }
 
@@ -167,7 +166,7 @@ DEFVAR                      [a-z_]+
                            LEXTRACE("WORD(2) ");
                            if (!fill(yytext, yyleng))
                                yyterminate();
-                           return(WORD);
+                           return WORD;
                        }
 }
 
@@ -175,13 +174,39 @@ DEFVAR                    [a-z_]+
     \\[[:blank:]]*\n[[:blank:]]*       {
                            /* Line continuation char followed by newline. */
                            ++sudolineno;
-                           LEXTRACE("\n");
+                           continued = TRUE;
                        }
 
     \"                 {
                            LEXTRACE("ENDSTR ");
-                           BEGIN INDEFS;
-                           return(WORD);
+                           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;
                        }
 
     \\                 {
@@ -217,7 +242,7 @@ DEFVAR                      [a-z_]+
     [#:\,=\n]          {
                            BEGIN INITIAL;
                            yyless(0);
-                           return(COMMAND);
+                           return COMMAND;
                        }                       /* end of command line args */
 
     [^#\\:, \t\n]+     {
@@ -231,6 +256,11 @@ DEFVAR                     [a-z_]+
 <INITIAL>^#include[[:blank:]]+\/.*\n {
                            char *path;
 
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
                            if ((path = parse_include(yytext)) == NULL)
                                yyterminate();
 
@@ -244,6 +274,11 @@ DEFVAR                     [a-z_]+
 <INITIAL>^#includedir[[:blank:]]+\/.*\n {
                            char *path;
 
+                           if (continued) {
+                               LEXTRACE("ERROR ");
+                               return ERROR;
+                           }
+
                            if ((path = parse_include(yytext)) == NULL)
                                yyterminate();
 
@@ -257,105 +292,128 @@ DEFVAR                  [a-z_]+
                                yyterminate();
                        }
 
-<INITIAL>^[[:blank:]]*Defaults([:@>\!]\!?{WORD})? {
+<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 += 8;
+                           n += sizeof("Defaults") - 1;
+                           if ((deftype = yytext[n++]) != '\0') {
+                               while (isblank((unsigned char)yytext[n]))
+                                   n++;
+                           }
                            BEGIN GOTDEFS;
-                           switch (yytext[n++]) {
+                           switch (deftype) {
                                case ':':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_USER ");
-                                   return(DEFAULTS_USER);
+                                   return DEFAULTS_USER;
                                case '>':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_RUNAS ");
-                                   return(DEFAULTS_RUNAS);
+                                   return DEFAULTS_RUNAS;
                                case '@':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_HOST ");
-                                   return(DEFAULTS_HOST);
+                                   return DEFAULTS_HOST;
                                case '!':
                                    yyless(n);
                                    LEXTRACE("DEFAULTS_CMND ");
-                                   return(DEFAULTS_CMND);
+                                   return DEFAULTS_CMND;
                                default:
                                    LEXTRACE("DEFAULTS ");
-                                   return(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);
+                                   return HOSTALIAS;
                                case 'C':
                                    LEXTRACE("CMNDALIAS ");
-                                   return(CMNDALIAS);
+                                   return CMNDALIAS;
                                case 'U':
                                    LEXTRACE("USERALIAS ");
-                                   return(USERALIAS);
+                                   return USERALIAS;
                                case 'R':
                                    LEXTRACE("RUNASALIAS ");
-                                   return(RUNASALIAS);
+                                   return RUNASALIAS;
                            }
                        }
 
 NOPASSWD[[:blank:]]*:  {
                                /* cmnd does not require passwd for this user */
                                LEXTRACE("NOPASSWD ");
-                               return(NOPASSWD);
+                               return NOPASSWD;
                        }
 
 PASSWD[[:blank:]]*:    {
                                /* cmnd requires passwd for this user */
                                LEXTRACE("PASSWD ");
-                               return(PASSWD);
+                               return PASSWD;
                        }
 
 NOEXEC[[:blank:]]*:    {
                                LEXTRACE("NOEXEC ");
-                               return(NOEXEC);
+                               return NOEXEC;
                        }
 
 EXEC[[:blank:]]*:      {
                                LEXTRACE("EXEC ");
-                               return(EXEC);
+                               return EXEC;
                        }
 
 SETENV[[:blank:]]*:    {
                                LEXTRACE("SETENV ");
-                               return(SETENV);
+                               return SETENV;
                        }
 
 NOSETENV[[:blank:]]*:  {
                                LEXTRACE("NOSETENV ");
-                               return(NOSETENV);
+                               return NOSETENV;
                        }
 
 LOG_OUTPUT[[:blank:]]*:        {
                                LEXTRACE("LOG_OUTPUT ");
-                               return(LOG_OUTPUT);
+                               return LOG_OUTPUT;
                        }
 
 NOLOG_OUTPUT[[:blank:]]*:      {
                                LEXTRACE("NOLOG_OUTPUT ");
-                               return(NOLOG_OUTPUT);
+                               return NOLOG_OUTPUT;
                        }
 
 LOG_INPUT[[:blank:]]*: {
                                LEXTRACE("LOG_INPUT ");
-                               return(LOG_INPUT);
+                               return LOG_INPUT;
                        }
 
 NOLOG_INPUT[[:blank:]]*:       {
                                LEXTRACE("NOLOG_INPUT ");
-                               return(NOLOG_INPUT);
+                               return NOLOG_INPUT;
+                       }
+
+<INITIAL,GOTDEFS>(\+|\%|\%:) {
+                           /* empty group or netgroup */
+                           LEXTRACE("ERROR ");
+                           return ERROR;
                        }
 
 \+{WORD}               {
@@ -363,73 +421,73 @@ NOLOG_INPUT[[:blank:]]*:  {
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NETGROUP ");
-                           return(NETGROUP);
+                           return NETGROUP;
                        }
 
-\%:?{WORD}             {
-                           /* UN*X group */
+\%:?({WORD}|{ID})      {
+                           /* group */
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("USERGROUP ");
-                           return(USERGROUP);
+                           return USERGROUP;
                        }
 
 {IPV4ADDR}(\/{IPV4ADDR})? {
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
 
 {IPV4ADDR}\/([12][0-9]*|3[0-2]*) {
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
 
 {IPV6ADDR}(\/{IPV6ADDR})? {
                            if (!ipv6_valid(yytext)) {
                                LEXTRACE("ERROR ");
-                               return(ERROR);
+                               return ERROR;
                            }
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(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);
+                               return ERROR;
                            }
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("NTWKADDR ");
-                           return(NTWKADDR);
+                           return NTWKADDR;
                        }
 
 [[:upper:]][[:upper:][:digit:]_]* {
                            if (strcmp(yytext, "ALL") == 0) {
                                LEXTRACE("ALL ");
-                               return(ALL);
+                               return ALL;
                            }
 #ifdef HAVE_SELINUX
                            /* XXX - restrict type/role to initial state */
                            if (strcmp(yytext, "TYPE") == 0) {
                                LEXTRACE("TYPE ");
-                               return(TYPE);
+                               return TYPE;
                            }
                            if (strcmp(yytext, "ROLE") == 0) {
                                LEXTRACE("ROLE ");
-                               return(ROLE);
+                               return ROLE;
                            }
 #endif /* HAVE_SELINUX */
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("ALIAS ");
-                           return(ALIAS);
+                           return ALIAS;
                        }
 
 <GOTDEFS>({PATH}|sudoedit) {
@@ -437,7 +495,7 @@ NOLOG_INPUT[[:blank:]]*:    {
                            if (!fill_cmnd(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("COMMAND ");
-                           return(COMMAND);
+                           return COMMAND;
                        }
 
 sudoedit               {
@@ -453,7 +511,7 @@ sudoedit            {
                                LEXTRACE("COMMAND ");
                                if (!fill_cmnd(yytext, yyleng))
                                    yyterminate();
-                               return(COMMAND);
+                               return COMMAND;
                            } else {
                                BEGIN GOTCMND;
                                LEXTRACE("COMMAND ");
@@ -462,21 +520,11 @@ sudoedit          {
                            }
                        }                       /* a pathname */
 
-<INITIAL,GOTDEFS>\"[^"\n]+\" {
-                           /* a quoted user/group name */
-                           if (!fill(yytext + 1, yyleng - 2))
-                               yyterminate();
-                           switch (yytext[1]) {
-                           case '%':
-                               LEXTRACE("USERGROUP ");
-                               return(USERGROUP);
-                           case '+':
-                               LEXTRACE("NETGROUP ");
-                               return(NETGROUP);
-                           default:
-                               LEXTRACE("WORD(4) ");
-                               return(WORD);
-                           }
+<INITIAL,GOTDEFS>\" {
+                           LEXTRACE("BEGINSTR ");
+                           yylval.string = NULL;
+                           prev_state = YY_START;
+                           BEGIN INSTR;
                        }
 
 <INITIAL,GOTDEFS>({ID}|{WORD}) {
@@ -484,44 +532,51 @@ sudoedit          {
                            if (!fill(yytext, yyleng))
                                yyterminate();
                            LEXTRACE("WORD(5) ");
-                           return(WORD);
+                           return WORD;
                        }
 
 \(                     {
                            LEXTRACE("( ");
-                           return ('(');
+                           return '(';
                        }
 
 \)                     {
                            LEXTRACE(") ");
-                           return(')');
+                           return ')';
                        }
 
 ,                      {
                            LEXTRACE(", ");
-                           return(',');
+                           return ',';
                        }                       /* return ',' */
 
 =                      {
                            LEXTRACE("= ");
-                           return('=');
+                           return '=';
                        }                       /* return '=' */
 
 :                      {
                            LEXTRACE(": ");
-                           return(':');
+                           return ':';
                        }                       /* return ':' */
 
 <*>!+                  {
-                           if (yyleng % 2 == 1)
-                               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 COMMENT;
                        }                       /* return newline */
 
 <*>[[:blank:]]+                {                       /* throw away space/tabs */
@@ -531,203 +586,33 @@ sudoedit         {
 <*>\\[[:blank:]]*\n    {
                            sawspace = TRUE;    /* remember for fill_args */
                            ++sudolineno;
-                           LEXTRACE("\n\t");
+                           continued = TRUE;
                        }                       /* throw away EOL after \ */
 
 <INITIAL,STARTDEFS,INDEFS>#(-[^\n0-9].*|[^\n0-9-].*)?\n        {
                            BEGIN INITIAL;
                            ++sudolineno;
-                           LEXTRACE("\n");
-                           return(COMMENT);
+                           continued = FALSE;
+                           LEXTRACE("#\n");
+                           return COMMENT;
                        }                       /* comment, not uid/gid */
 
 <*>.                   {
                            LEXTRACE("ERROR ");
-                           return(ERROR);
+                           return ERROR;
                        }       /* parse error */
 
 <*><<EOF>>             {
                            if (YY_START != INITIAL) {
                                BEGIN INITIAL;
                                LEXTRACE("ERROR ");
-                               return(ERROR);
+                               return ERROR;
                            }
                            if (!pop_include())
                                yyterminate();
                        }
 
 %%
-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);
-}
-
-static int
-_fill(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);
-}
-
-static int
-append(src, len)
-    char *src;
-    int len;
-{
-    int olen = 0;
-
-    if (yylval.string != NULL)
-       olen = strlen(yylval.string);
-
-    return(_fill(src, len, olen));
-}
-
-#define SPECIAL(c) \
-    ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#')
-
-static int
-fill_cmnd(src, len)
-    char *src;
-    int len;
-{
-    char *dst;
-    int i;
-
-    arg_len = arg_size = 0;
-
-    dst = yylval.command.cmnd = (char *) malloc(len + 1);
-    if (yylval.command.cmnd == NULL) {
-       yyerror("unable to allocate memory");
-       return(FALSE);
-    }
-
-    /* Copy the string and collapse any escaped sudo-specific characters. */
-    for (i = 0; i < len; i++) {
-       if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1]))
-           *dst++ = src[++i];
-       else
-           *dst++ = src[i];
-    }
-    *dst = '\0';
-
-    yylval.command.args = NULL;
-    return(TRUE);
-}
-
-static int
-fill_args(s, len, addspace)
-    char *s;
-    int len;
-    int addspace;
-{
-    int new_len;
-    char *p;
-
-    if (yylval.command.args == NULL) {
-       addspace = 0;
-       new_len = len;
-    } else
-       new_len = arg_len + len + addspace;
-
-    if (new_len >= arg_size) {
-       /* Allocate more space than we need for subsequent args */
-       while (new_len >= (arg_size += COMMANDARGINC))
-           ;
-
-       p = yylval.command.args ?
-           (char *) realloc(yylval.command.args, arg_size) :
-           (char *) malloc(arg_size);
-       if (p == NULL) {
-           efree(yylval.command.args);
-           yyerror("unable to allocate memory");
-           return(FALSE);
-       } else
-           yylval.command.args = p;
-    }
-
-    /* Efficiently append the arg (with a leading space if needed). */
-    p = yylval.command.args + arg_len;
-    if (addspace)
-       *p++ = ' ';
-    if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) {
-       yyerror("fill_args: buffer overflow");  /* paranoia */
-       return(FALSE);
-    }
-    arg_len = new_len;
-    return(TRUE);
-}
-
 struct path_list {
     char *path;
     struct path_list *next;
@@ -749,7 +634,7 @@ pl_compare(v1, v2)
     const struct path_list * const *p1 = v1;
     const struct path_list * const *p2 = v2;
 
-    return(strcmp((*p1)->path, (*p2)->path));
+    return strcmp((*p1)->path, (*p2)->path);
 }
 
 static char *
@@ -766,8 +651,16 @@ switch_dir(stack, dirpath)
     struct path_list **sorted = NULL;
 
     if (!(dir = opendir(dirpath))) {
-       yyerror(dirpath);
-       return(NULL);
+       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. */
@@ -781,6 +674,7 @@ switch_dir(stack, dirpath)
        }
        if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) {
            efree(path);
+           path = NULL;
            continue;
        }
        pl = malloc(sizeof(*pl));
@@ -825,7 +719,7 @@ switch_dir(stack, dirpath)
     }
 done:
     efree(dirpath);
-    return(path);
+    return path;
 bad:
     while (first != NULL) {
        pl = first;
@@ -836,7 +730,7 @@ bad:
     efree(sorted);
     efree(dirpath);
     efree(path);
-    return(NULL);
+    return NULL;
 }
 
 #define MAX_SUDOERS_DEPTH      128
@@ -866,7 +760,11 @@ init_lexer()
     efree(istack);
     istack = NULL;
     istacksize = idepth = 0;
+    sudolineno = 1;
     keepopen = FALSE;
+    sawspace = FALSE;
+    continued = FALSE;
+    prev_state = INITIAL;
 }
 
 static int
@@ -881,34 +779,40 @@ _push_include(path, isdir)
     if (idepth >= istacksize) {
        if (idepth > MAX_SUDOERS_DEPTH) {
            yyerror("too many levels of includes");
-           return(FALSE);
+           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);
+           return FALSE;
        }
     }
     if (isdir) {
        if (!(path = switch_dir(&istack[idepth], path))) {
            /* switch_dir() called yyerror() for us */
-           return(FALSE);
+           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);
+               return FALSE;
            path = pl->path;
            istack[idepth].more = pl->next;
            efree(pl);
        }
     } else {
        if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) {
-           yyerror(path);
-           return(FALSE);
+           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;
     }
@@ -922,7 +826,7 @@ _push_include(path, isdir)
     sudoers = path;
     yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
 
-    return(TRUE);
+    return TRUE;
 }
 
 static int
@@ -932,7 +836,7 @@ pop_include()
     FILE *fp;
 
     if (idepth == 0)
-       return(FALSE);
+       return FALSE;
 
     if (!keepopen)
        fclose(YY_CURRENT_BUFFER->yy_input_file);
@@ -963,7 +867,7 @@ pop_include()
        sudolineno = istack[idepth].lineno;
        keepopen = istack[idepth].keepopen;
     }
-    return(TRUE);
+    return TRUE;
 }
 
 static char *
@@ -1016,28 +920,5 @@ parse_include(base)
     if (*ep != '\0')
        yyless((int)(ep - base));
 
-    return(path);
-}
-
-/*
- * Check to make sure an IPv6 address does not contain multiple instances
- * of the string "::".  Assumes strlen(s) >= 1.
- * Returns TRUE if address is valid else FALSE.
- */
-static int
-ipv6_valid(s)
-    const char *s;
-{
-    int nmatch = 0;
-
-    for (; *s != '\0'; s++) {
-       if (s[0] == ':' && s[1] == ':') {
-           if (++nmatch > 1)
-               break;
-       }
-       if (s[0] == '/')
-           nmatch = 0;                 /* reset if we hit netmask */
-    }
-
-    return (nmatch <= 1);
+    return path;
 }
diff --git a/toke_util.c b/toke_util.c
new file mode 100644 (file)
index 0000000..99e7552
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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;
+}
index 6f14d3fb5ab928b01dc734432e1906dd34d6e792..5b38298c54348a898604940c1348c7ad0d62207f 100644 (file)
@@ -44,9 +44,8 @@
 #endif /* HAVE_STRINGS_H */
 #include <fcntl.h>
 #include <limits.h>
-#include <pwd.h>
-#include <grp.h>
 
+#include "tsgetgrpw.h"
 #include "sudo.h"
 
 #ifndef LINE_MAX
@@ -64,20 +63,6 @@ static FILE *grf;
 static const char *grfile = "/etc/group";
 static int gr_stayopen;
 
-void setgrfile __P((const char *));
-void setgrent __P((void));
-void endgrent __P((void));
-struct group *getgrent __P((void));
-struct group *getgrnam __P((const char *));
-struct group *getgrgid __P((gid_t));
-
-void setpwfile __P((const char *));
-void setpwent __P((void));
-void endpwent __P((void));
-struct passwd *getpwent __P((void));
-struct passwd *getpwnam __P((const char *));
-struct passwd *getpwuid __P((uid_t));
-
 void
 setpwfile(file)
     const char *file;
@@ -119,38 +104,38 @@ getpwent()
     char *cp, *colon;
 
     if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL)
-       return(NULL);
+       return NULL;
 
     zero_bytes(&pw, sizeof(pw));
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     pw.pw_name = cp;
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     pw.pw_passwd = cp;
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     pw.pw_uid = atoi(cp);
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     pw.pw_gid = atoi(cp);
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     pw.pw_gecos = cp;
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(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);
+    return &pw;
 }
 
 struct passwd *
@@ -161,7 +146,7 @@ getpwnam(name)
 
     if (pwf == NULL) {
        if ((pwf = fopen(pwfile, "r")) == NULL)
-           return(NULL);
+           return NULL;
        fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
     } else {
        rewind(pwf);
@@ -174,7 +159,7 @@ getpwnam(name)
        fclose(pwf);
        pwf = NULL;
     }
-    return(pw);
+    return pw;
 }
 
 struct passwd *
@@ -185,7 +170,7 @@ getpwuid(uid)
 
     if (pwf == NULL) {
        if ((pwf = fopen(pwfile, "r")) == NULL)
-           return(NULL);
+           return NULL;
        fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC);
     } else {
        rewind(pwf);
@@ -198,7 +183,7 @@ getpwuid(uid)
        fclose(pwf);
        pwf = NULL;
     }
-    return(pw);
+    return pw;
 }
 
 void
@@ -243,19 +228,19 @@ getgrent()
     int n;
 
     if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL)
-       return(NULL);
+       return NULL;
 
     zero_bytes(&gr, sizeof(gr));
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     gr.gr_name = cp;
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     gr.gr_passwd = cp;
     if ((colon = strchr(cp = colon, ':')) == NULL)
-       return(NULL);
+       return NULL;
     *colon++ = '\0';
     gr.gr_gid = atoi(cp);
     len = strlen(colon);
@@ -271,7 +256,7 @@ getgrent()
        gr.gr_mem[n++] = NULL;
     } else
        gr.gr_mem = NULL;
-    return(&gr);
+    return &gr;
 }
 
 struct group *
@@ -282,7 +267,7 @@ getgrnam(name)
 
     if (grf == NULL) {
        if ((grf = fopen(grfile, "r")) == NULL)
-           return(NULL);
+           return NULL;
        fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
     } else {
        rewind(grf);
@@ -295,7 +280,7 @@ getgrnam(name)
        fclose(grf);
        grf = NULL;
     }
-    return(gr);
+    return gr;
 }
 
 struct group *
@@ -306,7 +291,7 @@ getgrgid(gid)
 
     if (grf == NULL) {
        if ((grf = fopen(grfile, "r")) == NULL)
-           return(NULL);
+           return NULL;
        fcntl(fileno(grf), F_SETFD, FD_CLOEXEC);
     } else {
        rewind(grf);
@@ -319,5 +304,5 @@ getgrgid(gid)
        fclose(grf);
        grf = NULL;
     }
-    return(gr);
+    return gr;
 }
index 84f4c433cb6d8c7c52dd26b818f9a26b814609b0..5ff4379c0f9fb682a11e70d7553026f7c7a257a3 100644 (file)
--- a/utimes.c
+++ b/utimes.c
 #ifdef HAVE_UTIME_H
 # include <utime.h>
 #else
-# include <emul/utime.h>
+# include "emul/utime.h"
 #endif
 
-#include <compat.h>
+#include "missing.h"
 
 #ifndef HAVE_UTIMES
 /*
@@ -45,9 +45,9 @@ utimes(file, times)
 
        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));
+       return utime(file, &utb);
     } else
-       return(utime(file, NULL));
+       return utime(file, NULL);
 }
 #endif /* !HAVE_UTIMES */
 
@@ -65,8 +65,8 @@ futimes(fd, times)
 
        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));
+       return futime(fd, &utb);
     } else
-       return(futime(fd, NULL));
+       return futime(fd, NULL);
 }
 #endif /* HAVE_FUTIME */
index a7c6c34fbd181ecd6444f1127b24706f89e18f9c..0ba33e1b5bac16cf44ce4cdb8bcace473e13b863 100644 (file)
@@ -28,7 +28,7 @@
  * POSSIBILITY OF SUCH DAMAGE. 
  */
 
-#include "config.h"
+#include <config.h>
 
 #include <stdlib.h>
 #include <sys/types.h>
@@ -40,7 +40,7 @@
 
 #include <vas.h>
 
-#include "compat.h"
+#include "missing.h"
 #include "logging.h"
 #include "nonunix.h"
 #include "sudo.h"
@@ -165,7 +165,7 @@ FINISHED: /* cleanups */
     if( vas_group )              v_group_free( sudo_vas_ctx, vas_group );
     if( vas_user )              v_user_free( sudo_vas_ctx, vas_user );
 
-    return(rval);
+    return rval;
 }
 
 
index ab8d58744e258899cf59ee97631d6f2ada935e6d..bc77377f10e33a043f188714f8f289a578ca1413 100644 (file)
--- a/visudo.c
+++ b/visudo.c
@@ -90,7 +90,7 @@ struct sudoersfile {
     int modified;
     int doedit;
 };
-TQ_DECLARE(sudoersfile);
+TQ_DECLARE(sudoersfile)
 
 /*
  * Function prototypes
@@ -110,7 +110,8 @@ 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 usage              __P((void)) __attribute__((__noreturn__));
+static void help               __P((void)) __attribute__((__noreturn__));
+static void usage              __P((int));
 
 extern void yyerror            __P((const char *));
 extern void yyrestart          __P((FILE *));
@@ -153,14 +154,14 @@ main(argc, argv)
 
     Argv = argv;
     if ((Argc = argc) < 1)
-       usage();
+       usage(1);
 
     /*
      * Arg handling.
      */
     checkonly = oldperms = quiet = strict = FALSE;
     sudoers_path = _PATH_SUDOERS;
-    while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) {
+    while ((ch = getopt(argc, argv, "Vcf:hsq")) != -1) {
        switch (ch) {
            case 'V':
                (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION);
@@ -172,6 +173,9 @@ main(argc, argv)
                sudoers_path = optarg;  /* sudoers file path */
                oldperms = TRUE;
                break;
+           case 'h':
+               help();
+               break;
            case 's':
                strict++;               /* strict mode */
                break;
@@ -179,13 +183,13 @@ main(argc, argv)
                quiet++;                /* quiet mode */
                break;
            default:
-               usage();
+               usage(1);
        }
     }
     argc -= optind;
     argv += optind;
     if (argc)
-       usage();
+       usage(1);
 
     sudo_setpwent();
     sudo_setgrent();
@@ -293,7 +297,8 @@ edit_sudoers(sp, editor, args, lineno)
            /* Add missing newline at EOF if needed. */
            if (nread > 0 && buf[nread - 1] != '\n') {
                buf[0] = '\n';
-               write(tfd, buf, 1);
+               if (write(tfd, buf, 1) != 1)
+                   error(1, "write error");
            }
        }
        (void) close(tfd);
@@ -349,17 +354,17 @@ edit_sudoers(sp, editor, args, lineno)
        if (stat(sp->tpath, &sb) < 0) {
            warningx("cannot stat temporary file (%s), %s unchanged",
                sp->tpath, sp->path);
-           return(FALSE);
+           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);
+           return FALSE;
        }
     } else {
        warningx("editor (%s) failed, %s unchanged", editor, sp->path);
-       return(FALSE);
+       return FALSE;
     }
 
     /* Set modified bit if use changed the file. */
@@ -383,7 +388,7 @@ edit_sudoers(sp, editor, args, lineno)
     else
        warningx("%s unchanged", sp->tpath);
 
-    return(TRUE);
+    return TRUE;
 }
 
 /*
@@ -464,7 +469,7 @@ reparse_sudoers(editor, args, strict, quiet)
        }
     } while (parse_error);
 
-    return(TRUE);
+    return TRUE;
 }
 
 /*
@@ -490,18 +495,24 @@ install_sudoers(sp, oldperms)
        if (stat(sp->path, &sb) == -1)
 #endif
            error(1, "can't stat %s", sp->path);
-       (void) chown(sp->tpath, sb.st_uid, sb.st_gid);
-       (void) chmod(sp->tpath, sb.st_mode & 0777);
+       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);
+           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);
+           return FALSE;
        }
     }
 
@@ -535,17 +546,17 @@ install_sudoers(sp, oldperms)
                (void) unlink(sp->tpath);
                efree(sp->tpath);
                sp->tpath = NULL;
-               return(FALSE);
+               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 FALSE;
        }
     }
-    return(TRUE);
+    return TRUE;
 }
 
 /* STUB */
@@ -566,7 +577,7 @@ init_envtables()
 int
 user_is_exempt()
 {
-    return(FALSE);
+    return FALSE;
 }
 
 /* STUB */
@@ -587,7 +598,7 @@ char *
 sudo_getepw(pw)
     const struct passwd *pw;
 {
-    return (pw->pw_passwd);
+    return pw->pw_passwd;
 }
 
 /*
@@ -612,7 +623,7 @@ whatnow()
            case 'e':
            case 'x':
            case 'Q':
-               return(choice);
+               return choice;
            default:
                (void) puts("Options are:");
                (void) puts("  (e)dit sudoers file again");
@@ -674,8 +685,8 @@ run_command(path, argv)
     } while (rv == -1 && errno == EINTR);
 
     if (rv == -1 || !WIFEXITED(status))
-       return(-1);
-    return(WEXITSTATUS(status));
+       return -1;
+    return WEXITSTATUS(status);
 }
 
 static int
@@ -687,7 +698,10 @@ check_syntax(sudoers_path, quiet, strict)
     struct stat sb;
     int error;
 
-    if ((yyin = fopen(sudoers_path, "r")) == NULL) {
+    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);
@@ -717,9 +731,9 @@ check_syntax(sudoers_path, quiet, strict)
     }
     /* Check mode and owner in strict mode. */
 #ifdef HAVE_FSTAT
-    if (strict && fstat(fileno(yyin), &sb) == 0)
+    if (strict && yyin != stdin && fstat(fileno(yyin), &sb) == 0)
 #else
-    if (strict && stat(sudoers_path, &sb) == 0)
+    if (strict && yyin != stdin && stat(sudoers_path, &sb) == 0)
 #endif
     {
        if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) {
@@ -738,7 +752,7 @@ check_syntax(sudoers_path, quiet, strict)
        }
     }
 
-    return(error);
+    return error;
 }
 
 /*
@@ -771,7 +785,7 @@ open_sudoers(path, doedit, keepopen)
        if (entry->fd == -1) {
            warning("%s", entry->path);
            efree(entry);
-           return(NULL);
+           return NULL;
        }
        if (!lock_file(entry->fd, SUDO_TLOCK))
            errorx(1, "%s busy, try again later", entry->path);
@@ -791,7 +805,7 @@ open_sudoers(path, doedit, keepopen)
     }
     if (keepopen != NULL)
        *keepopen = TRUE;
-    return(fp);
+    return fp;
 }
 
 static char *
@@ -892,7 +906,7 @@ get_editor(args)
            errorx(1, "no editor found (editor path = %s)", def_editor);
     }
     *args = EditorArgs;
-    return(Editor);
+    return Editor;
 }
 
 /*
@@ -912,7 +926,7 @@ get_args(cmnd)
        while (*args && isblank((unsigned char) *args))
            args++;
     }
-    return(*args ? args : NULL);
+    return *args ? args : NULL;
 }
 
 /*
@@ -967,7 +981,7 @@ alias_remove_recursive(name, type, strict, quiet)
     a = alias_remove(name, type);
     if (a)
        rbinsert(alias_freelist, a);
-    return(error);
+    return error;
 }
 
 /*
@@ -1041,7 +1055,7 @@ check_aliases(strict, quiet)
        tq_foreach_fwd(&us->privileges, priv) {
            tq_foreach_fwd(&priv->hostlist, m) {
                if (m->type == ALIAS)
-                   if (!alias_remove_recursive(m->name, HOSTALIAS, strict, 
+                   if (!alias_remove_recursive(m->name, HOSTALIAS, strict,
                        quiet))
                        error++;
            }
@@ -1090,7 +1104,7 @@ check_aliases(strict, quiet)
     if (!no_aliases() && !quiet)
        alias_apply(print_unused, strict ? "Error" : "Warning");
 
-    return (strict ? error : 0);
+    return strict ? error : 0;
 }
 
 static void
@@ -1137,7 +1151,7 @@ print_unused(v1, v2)
        a->type == HOSTALIAS ? "Host" : a->type == CMNDALIAS ? "Cmnd" :
        a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" :
        "Unknown", a->name);
-    return(0);
+    return 0;
 }
 
 /*
@@ -1168,15 +1182,33 @@ quit(signo)
 {
     cleanup(signo);
 #define        emsg     " exiting due to signal.\n"
-    write(STDERR_FILENO, getprogname(), strlen(getprogname()));
-    write(STDERR_FILENO, emsg, sizeof(emsg) - 1);
+    if (write(STDERR_FILENO, getprogname(), strlen(getprogname())) == -1 ||
+       write(STDERR_FILENO, emsg, sizeof(emsg) - 1) == -1)
+       /* shut up glibc */;
     _exit(signo);
 }
 
 static void
-usage()
+usage(fatal)
+    int fatal;
 {
-    (void) fprintf(stderr, "usage: %s [-c] [-q] [-s] [-V] [-f sudoers]\n",
-       getprogname());
-    exit(1);
+    (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);
 }
index c99374f8f302d4148c6ed804cc8064d9ddb23c4c..ce7c1a3f62ad89a6f01f3ac0c3b67114c3b9e4cc 100644 (file)
@@ -8,7 +8,7 @@ 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\bc] [-\b-q\bq] [-\b-s\bs] [-\b-V\bV] [-\b-f\bf _\bs_\bu_\bd_\bo_\be_\br_\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).
@@ -54,14 +54,14 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
                    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.
+                   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.
 
-       -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
 
 
 
-1.7.4                     July 14, 2010                         1
+1.7.6                     April  9, 2011                        1
 
 
 
@@ -70,6 +70,11 @@ O\bOP\bPT\bTI\bIO\bON\bNS\bS
 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
@@ -118,16 +123,11 @@ D\bDI\bIA\bAG\bGN\bNO\bOS\bST\bTI\bIC\bCS\bS
            used.  You may wish to comment out or remove the unused alias.  In
            -\b-s\bs (strict) mode this is an error, not a warning.
 
-S\bSE\bEE\bE A\bAL\bLS\bSO\bO
-       _\bv_\bi(1), _\bs_\bu_\bd_\bo_\be_\br_\bs(4), _\bs_\bu_\bd_\bo(1m), _\bv_\bi_\bp_\bw(8)
 
-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:
 
 
 
-1.7.4                     July 14, 2010                         2
+1.7.6                     April  9, 2011                        2
 
 
 
@@ -136,6 +136,13 @@ A\bAU\bUT\bTH\bHO\bOR\bR
 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
@@ -186,13 +193,6 @@ D\bDI\bIS\bSC\bCL\bLA\bAI\bIM\bME\bER\bR
 
 
 
-
-
-
-
-
-
-
-1.7.4                     July 14, 2010                         3
+1.7.6                     April  9, 2011                        3
 
 
index 563fd3bcebd6363e1d5c2dc8328019e3b1178650..c8ee72e5af593f54ffeecb21b3e2851a1afe38a1 100644 (file)
@@ -18,7 +18,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\" 
-.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07)
+.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
 .\" ========================================================================
 .\"
 .IX Title "VISUDO @mansectsu@"
-.TH VISUDO @mansectsu@ "July 14, 2010" "1.7.4" "MAINTENANCE COMMANDS"
+.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
 visudo \- edit the sudoers file
 .SH "SYNOPSIS"
 .IX Header "SYNOPSIS"
-\&\fBvisudo\fR [\fB\-c\fR] [\fB\-q\fR] [\fB\-s\fR] [\fB\-V\fR] [\fB\-f\fR \fIsudoers\fR]
+\&\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
@@ -203,6 +203,12 @@ 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
index ccc5c00b223b961219e28ae56f1b966a9970420c..708d9549a410f1c4b3a5c28d3b52b66b16bc728b 100644 (file)
@@ -26,7 +26,7 @@ visudo - edit the sudoers file
 
 =head1 SYNOPSIS
 
-B<visudo> [B<-c>] [B<-q>] [B<-s>] [B<-V>] [B<-f> I<sudoers>]
+B<visudo> [B<-chqsV>] [B<-f> I<sudoers>]
 
 =head1 DESCRIPTION
 
@@ -82,6 +82,13 @@ 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
 
index 7391780aa0c9a938a771455f54e89a02a7db968e..bce089584236e60fcfdd3faa6b4f3686ad14f5f2 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <config.h>
+
 #include <sys/types.h>
 
-#include <config.h>
-#include <compat.h>
+#include "missing.h"
 
 /*
  * Like bzero(3) but with a volatile pointer.  The hope is that
diff --git a/zlib/adler32.c b/zlib/adler32.c
new file mode 100644 (file)
index 0000000..65ad6a5
--- /dev/null
@@ -0,0 +1,169 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2007 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);
+
+#define BASE 65521UL    /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+#  define MOD(a) \
+    do { \
+        if (a >= (BASE << 16)) a -= (BASE << 16); \
+        if (a >= (BASE << 15)) a -= (BASE << 15); \
+        if (a >= (BASE << 14)) a -= (BASE << 14); \
+        if (a >= (BASE << 13)) a -= (BASE << 13); \
+        if (a >= (BASE << 12)) a -= (BASE << 12); \
+        if (a >= (BASE << 11)) a -= (BASE << 11); \
+        if (a >= (BASE << 10)) a -= (BASE << 10); \
+        if (a >= (BASE << 9)) a -= (BASE << 9); \
+        if (a >= (BASE << 8)) a -= (BASE << 8); \
+        if (a >= (BASE << 7)) a -= (BASE << 7); \
+        if (a >= (BASE << 6)) a -= (BASE << 6); \
+        if (a >= (BASE << 5)) a -= (BASE << 5); \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD4(a) \
+    do { \
+        if (a >= (BASE << 4)) a -= (BASE << 4); \
+        if (a >= (BASE << 3)) a -= (BASE << 3); \
+        if (a >= (BASE << 2)) a -= (BASE << 2); \
+        if (a >= (BASE << 1)) a -= (BASE << 1); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD4(sum2);             /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    rem = (unsigned)(len2 % BASE);
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+    if (sum2 >= BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/zlib/compress.c b/zlib/compress.c
new file mode 100644 (file)
index 0000000..ea4dfbe
--- /dev/null
@@ -0,0 +1,80 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    err = deflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        deflateEnd(&stream);
+        return err == Z_OK ? Z_BUF_ERROR : err;
+    }
+    *destLen = stream.total_out;
+
+    err = deflateEnd(&stream);
+    return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13;
+}
diff --git a/zlib/crc32.c b/zlib/crc32.c
new file mode 100644 (file)
index 0000000..91be372
--- /dev/null
@@ -0,0 +1,442 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+#  ifdef STDC           /* need ANSI C limits.h to determine sizes */
+#    include <limits.h>
+#    define BYFOUR
+#    if (UINT_MAX == 0xffffffffUL)
+       typedef unsigned int u4;
+#    else
+#      if (ULONG_MAX == 0xffffffffUL)
+         typedef unsigned long u4;
+#      else
+#        if (USHRT_MAX == 0xffffffffUL)
+           typedef unsigned short u4;
+#        else
+#          undef BYFOUR     /* can't find a four-byte integer type! */
+#        endif
+#      endif
+#    endif
+#  endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+#  define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \
+                (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, unsigned));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2);
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    unsigned long c;
+    int n, k;
+    unsigned long poly;                 /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0UL;
+        for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+            poly |= 1UL << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (unsigned long)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = REV(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = REV(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const unsigned long FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const unsigned long FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ", table[n],
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    uInt len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        u4 endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = (u4)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    unsigned len;
+{
+    register u4 c;
+    register const u4 FAR *buf4;
+
+    c = REV((u4)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const u4 FAR *)(const void FAR *)buf;
+    buf4--;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf4++;
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case (also disallow negative lengths) */
+    if (len2 <= 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/zlib/crc32.h b/zlib/crc32.h
new file mode 100644 (file)
index 0000000..8053b61
--- /dev/null
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/zlib/deflate.c b/zlib/deflate.c
new file mode 100644 (file)
index 0000000..5c4022f
--- /dev/null
@@ -0,0 +1,1834 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle    OF((deflate_state *s, int flush));
+local block_state deflate_huff   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->high_water = 0;      /* nothing written to s->window yet */
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+        strm->state->wrap == 2 ||
+        (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+        return Z_STREAM_ERROR;
+
+    s = strm->state;
+    if (s->wrap)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > s->w_size) {
+        length = s->w_size;
+        dictionary += dictLength - length; /* use the tail of the dictionary */
+    }
+    zmemcpy(s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+        INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    strm->state->bi_valid = bits;
+    strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if ((strategy != s->strategy || func != configuration_table[level].func) &&
+        strm->total_in != 0) {
+        /* Flush the last buffer: */
+        err = deflate(strm, Z_BLOCK);
+    }
+    if (s->level != level) {
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = good_length;
+    s->max_lazy_match = max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel.  But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong complen, wraplen;
+    Bytef *str;
+
+    /* conservative upper bound for compressed data */
+    complen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+    /* if can't get parameters, return conservative bound plus zlib wrapper */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return complen + 6;
+
+    /* compute wrapper length */
+    s = strm->state;
+    switch (s->wrap) {
+    case 0:                                 /* raw deflate */
+        wraplen = 0;
+        break;
+    case 1:                                 /* zlib wrapper */
+        wraplen = 6 + (s->strstart ? 4 : 0);
+        break;
+    case 2:                                 /* gzip wrapper */
+        wraplen = 18;
+        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */
+            if (s->gzhead->extra != Z_NULL)
+                wraplen += 2 + s->gzhead->extra_len;
+            str = s->gzhead->name;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            str = s->gzhead->comment;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            if (s->gzhead->hcrc)
+                wraplen += 2;
+        }
+        break;
+    default:                                /* for compiler happiness */
+        wraplen = 6;
+    }
+
+    /* if not default parameters, return conservative bound */
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return complen + wraplen;
+
+    /* default settings: return tight bound for that case */
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len = strm->state->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, strm->state->pending_out, len);
+    strm->next_out  += len;
+    strm->state->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    strm->state->pending -= len;
+    if (strm->state->pending == 0) {
+        strm->state->pending_out = strm->state->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        flush > Z_BLOCK || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+#ifdef GZIP
+        if (s->wrap == 2) {
+            strm->adler = crc32(0L, Z_NULL, 0);
+            put_byte(s, 31);
+            put_byte(s, 139);
+            put_byte(s, 8);
+            if (s->gzhead == Z_NULL) {
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, 0);
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, OS_CODE);
+                s->status = BUSY_STATE;
+            }
+            else {
+                put_byte(s, (s->gzhead->text ? 1 : 0) +
+                            (s->gzhead->hcrc ? 2 : 0) +
+                            (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                            (s->gzhead->name == Z_NULL ? 0 : 8) +
+                            (s->gzhead->comment == Z_NULL ? 0 : 16)
+                        );
+                put_byte(s, (Byte)(s->gzhead->time & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+                put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+                put_byte(s, s->level == 9 ? 2 :
+                            (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                             4 : 0));
+                put_byte(s, s->gzhead->os & 0xff);
+                if (s->gzhead->extra != Z_NULL) {
+                    put_byte(s, s->gzhead->extra_len & 0xff);
+                    put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+                }
+                if (s->gzhead->hcrc)
+                    strm->adler = crc32(strm->adler, s->pending_buf,
+                                        s->pending);
+                s->gzindex = 0;
+                s->status = EXTRA_STATE;
+            }
+        }
+        else
+#endif
+        {
+            uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+            uInt level_flags;
+
+            if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+                level_flags = 0;
+            else if (s->level < 6)
+                level_flags = 1;
+            else if (s->level == 6)
+                level_flags = 2;
+            else
+                level_flags = 3;
+            header |= (level_flags << 6);
+            if (s->strstart != 0) header |= PRESET_DICT;
+            header += 31 - (header % 31);
+
+            s->status = BUSY_STATE;
+            putShortMSB(s, header);
+
+            /* Save the adler32 of the preset dictionary: */
+            if (s->strstart != 0) {
+                putShortMSB(s, (uInt)(strm->adler >> 16));
+                putShortMSB(s, (uInt)(strm->adler & 0xffff));
+            }
+            strm->adler = adler32(0L, Z_NULL, 0);
+        }
+    }
+#ifdef GZIP
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+
+            while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size)
+                        break;
+                }
+                put_byte(s, s->gzhead->extra[s->gzindex]);
+                s->gzindex++;
+            }
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (s->gzindex == s->gzhead->extra_len) {
+                s->gzindex = 0;
+                s->status = NAME_STATE;
+            }
+        }
+        else
+            s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0) {
+                s->gzindex = 0;
+                s->status = COMMENT_STATE;
+            }
+        }
+        else
+            s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != Z_NULL) {
+            uInt beg = s->pending;  /* start of bytes to update crc */
+            int val;
+
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    if (s->gzhead->hcrc && s->pending > beg)
+                        strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                            s->pending - beg);
+                    flush_pending(strm);
+                    beg = s->pending;
+                    if (s->pending == s->pending_buf_size) {
+                        val = 1;
+                        break;
+                    }
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            if (s->gzhead->hcrc && s->pending > beg)
+                strm->adler = crc32(strm->adler, s->pending_buf + beg,
+                                    s->pending - beg);
+            if (val == 0)
+                s->status = HCRC_STATE;
+        }
+        else
+            s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size)
+                flush_pending(strm);
+            if (s->pending + 2 <= s->pending_buf_size) {
+                put_byte(s, (Byte)(strm->adler & 0xff));
+                put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+                strm->adler = crc32(0L, Z_NULL, 0);
+                s->status = BUSY_STATE;
+            }
+        }
+        else
+            s->status = BUSY_STATE;
+    }
+#endif
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+                    (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+                        (*(configuration_table[s->level].func))(s, flush));
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                    if (s->lookahead == 0) {
+                        s->strstart = 0;
+                        s->block_start = 0L;
+                    }
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+    if (status != INIT_STATE &&
+        status != EXTRA_STATE &&
+        status != NAME_STATE &&
+        status != COMMENT_STATE &&
+        status != HCRC_STATE &&
+        status != BUSY_STATE &&
+        status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy(dest, source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, strm->next_in, len);
+    }
+#endif
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+#ifndef FASTEST
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+#endif
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+    /* If the WIN_INIT bytes after the end of the current data have never been
+     * written, then zero those bytes in order to avoid memory check reports of
+     * the use of uninitialized (or uninitialised as Julian writes) bytes by
+     * the longest match routines.  Update the high water mark for the next
+     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
+     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+     */
+    if (s->high_water < s->window_size) {
+        ulg curr = s->strstart + (ulg)(s->lookahead);
+        ulg init;
+
+        if (s->high_water < curr) {
+            /* Previous high water mark below current data -- zero WIN_INIT
+             * bytes or up to end of window, whichever is less.
+             */
+            init = s->window_size - curr;
+            if (init > WIN_INIT)
+                init = WIN_INIT;
+            zmemzero(s->window + curr, (unsigned)init);
+            s->high_water = curr + init;
+        }
+        else if (s->high_water < (ulg)curr + WIN_INIT) {
+            /* High water mark at or above current data, but below current data
+             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+             * to end of window, whichever is less.
+             */
+            init = (ulg)curr + WIN_INIT - s->high_water;
+            if (init > s->window_size - s->high_water)
+                init = s->window_size - s->high_water;
+            zmemzero(s->window + s->high_water, (unsigned)init);
+            s->high_water += init;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (last)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+   FLUSH_BLOCK_ONLY(s, last); \
+   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+                   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+        Assert(s->block_start >= 0L, "block gone");
+
+        s->strstart += s->lookahead;
+        s->lookahead = 0;
+
+        /* Emit a stored block if pending_buf will be full: */
+        max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+            /* strstart == 0 is possible when wraparound on 16-bit machine */
+            s->lookahead = (uInt)(s->strstart - max_start);
+            s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+        }
+        /* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+        }
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;       /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;          /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+    uInt prev;              /* byte at distance one to match */
+    Bytef *scan, *strend;   /* scan goes up to strend for length of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest encodable run.
+         */
+        if (s->lookahead < MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        s->match_length = 0;
+        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+            scan = s->window + s->strstart - 1;
+            prev = *scan;
+            if (prev == *++scan && prev == *++scan && prev == *++scan) {
+                strend = s->window + s->strstart + MAX_MATCH;
+                do {
+                } while (prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         scan < strend);
+                s->match_length = MAX_MATCH - (int)(strend - scan);
+                if (s->match_length > s->lookahead)
+                    s->match_length = s->lookahead;
+            }
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+            s->strstart += s->match_length;
+            s->match_length = 0;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we have a literal to write. */
+        if (s->lookahead == 0) {
+            fill_window(s);
+            if (s->lookahead == 0) {
+                if (flush == Z_NO_FLUSH)
+                    return need_more;
+                break;      /* flush the current block */
+            }
+        }
+
+        /* Output a literal byte */
+        s->match_length = 0;
+        Tracevv((stderr,"%c", s->window[s->strstart]));
+        _tr_tally_lit (s, s->window[s->strstart], bflush);
+        s->lookahead--;
+        s->strstart++;
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
diff --git a/zlib/deflate.h b/zlib/deflate.h
new file mode 100644 (file)
index 0000000..cbf0d1e
--- /dev/null
@@ -0,0 +1,342 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define EXTRA_STATE   69
+#define NAME_STATE    73
+#define COMMENT_STATE 91
+#define HCRC_STATE   103
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    uInt   pending;      /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    uInt   gzindex;      /* where in extra, name, or comment */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+    ulg high_water;
+    /* High water mark offset in window for initialized bytes -- bytes above
+     * this are set to zero in order to avoid memory check warnings when
+     * longest match routines access bytes past the input.  This is then
+     * updated to the new high water mark.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+   memory checker errors from longest match routines */
+
+        /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch ZLIB_INTERNAL _length_code[];
+  extern uch ZLIB_INTERNAL _dist_code[];
+#else
+  extern const uch ZLIB_INTERNAL _length_code[];
+  extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (length); \
+    ush dist = (distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/zlib/gzclose.c b/zlib/gzclose.c
new file mode 100644 (file)
index 0000000..caeb99a
--- /dev/null
@@ -0,0 +1,25 @@
+/* gzclose.c -- zlib gzclose() function
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* gzclose() is in a separate file so that it is linked in only if it is used.
+   That way the other gzclose functions can be used instead to avoid linking in
+   unneeded compression or decompression routines. */
+int ZEXPORT gzclose(file)
+    gzFile file;
+{
+#ifndef NO_GZCOMPRESS
+    gz_statep state;
+
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
+#else
+    return gzclose_r(file);
+#endif
+}
diff --git a/zlib/gzguts.h b/zlib/gzguts.h
new file mode 100644 (file)
index 0000000..e554830
--- /dev/null
@@ -0,0 +1,132 @@
+/* gzguts.h -- zlib internal header definitions for gz* operations
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifdef _LARGEFILE64_SOURCE
+#  ifndef _LARGEFILE_SOURCE
+#    define _LARGEFILE_SOURCE 1
+#  endif
+#  ifdef _FILE_OFFSET_BITS
+#    undef _FILE_OFFSET_BITS
+#  endif
+#endif
+
+#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)
+#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+#  define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+#include <stdio.h>
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#  include <limits.h>
+#endif
+#include <fcntl.h>
+
+#ifdef NO_DEFLATE       /* for compatibility with old definition */
+#  define NO_GZCOMPRESS
+#endif
+
+#ifdef _MSC_VER
+#  include <io.h>
+#  define vsnprintf _vsnprintf
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+/* gz* functions always use library allocation functions */
+#ifndef STDC
+  extern voidp  malloc OF((uInt size));
+  extern void   free   OF((voidpf ptr));
+#endif
+
+/* get errno and strerror definition */
+#if defined UNDER_CE
+#  include <windows.h>
+#  define zstrerror() gz_strwinerror((DWORD)GetLastError())
+#else
+#  ifdef STDC
+#    include <errno.h>
+#    define zstrerror() strerror(errno)
+#  else
+#    define zstrerror() "stdio error (consult errno)"
+#  endif
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
+    ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+    ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+    ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+    ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+#endif
+
+/* default i/o buffer size -- double this for output when reading */
+#define GZBUFSIZE 8192
+
+/* gzip modes, also provide a little integrity check on the passed structure */
+#define GZ_NONE 0
+#define GZ_READ 7247
+#define GZ_WRITE 31153
+#define GZ_APPEND 1     /* mode set to GZ_WRITE after the file is opened */
+
+/* values for gz_state how */
+#define LOOK 0      /* look for a gzip header */
+#define COPY 1      /* copy input directly */
+#define GZIP 2      /* decompress a gzip stream */
+
+/* internal gzip file state data structure */
+typedef struct {
+        /* used for both reading and writing */
+    int mode;               /* see gzip modes above */
+    int fd;                 /* file descriptor */
+    char *path;             /* path or fd for error messages */
+    z_off64_t pos;          /* current position in uncompressed data */
+    unsigned size;          /* buffer size, zero if not allocated yet */
+    unsigned want;          /* requested buffer size, default is GZBUFSIZE */
+    unsigned char *in;      /* input buffer */
+    unsigned char *out;     /* output buffer (double-sized when reading) */
+    unsigned char *next;    /* next output data to deliver or write */
+        /* just for reading */
+    unsigned have;          /* amount of output data unused at next */
+    int eof;                /* true if end of input file reached */
+    z_off64_t start;        /* where the gzip data started, for rewinding */
+    z_off64_t raw;          /* where the raw data started, for seeking */
+    int how;                /* 0: get header, 1: copy, 2: decompress */
+    int direct;             /* true if last read direct, false if gzip */
+        /* just for writing */
+    int level;              /* compression level */
+    int strategy;           /* compression strategy */
+        /* seek request */
+    z_off64_t skip;         /* amount to skip (already rewound if backwards) */
+    int seek;               /* true if seek request pending */
+        /* error information */
+    int err;                /* error code */
+    char *msg;              /* error message */
+        /* zlib inflate or deflate stream */
+    z_stream strm;          /* stream structure in-place (not a pointer) */
+} gz_state;
+typedef gz_state FAR *gz_statep;
+
+/* shared functions */
+void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+#if defined UNDER_CE
+char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
+#endif
+
+/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
+   value -- needed when comparing unsigned to z_off64_t, which is signed
+   (possible z_off64_t types off_t, off64_t, and long are all signed) */
+#ifdef INT_MAX
+#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
+#else
+unsigned ZLIB_INTERNAL gz_intmax OF((void));
+#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
+#endif
diff --git a/zlib/gzlib.c b/zlib/gzlib.c
new file mode 100644 (file)
index 0000000..603e60e
--- /dev/null
@@ -0,0 +1,537 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+#  define LSEEK lseek64
+#else
+#  define LSEEK lseek
+#endif
+
+/* Local functions */
+local void gz_reset OF((gz_statep));
+local gzFile gz_open OF((const char *, int, const char *));
+
+#if defined UNDER_CE
+
+/* Map the Windows error number in ERROR to a locale-dependent error message
+   string and return a pointer to it.  Typically, the values for ERROR come
+   from GetLastError.
+
+   The string pointed to shall not be modified by the application, but may be
+   overwritten by a subsequent call to gz_strwinerror
+
+   The gz_strwinerror function does not change the current setting of
+   GetLastError. */
+char ZLIB_INTERNAL *gz_strwinerror (error)
+     DWORD error;
+{
+    static char buf[1024];
+
+    wchar_t *msgbuf;
+    DWORD lasterr = GetLastError();
+    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+        NULL,
+        error,
+        0, /* Default language */
+        (LPVOID)&msgbuf,
+        0,
+        NULL);
+    if (chars != 0) {
+        /* If there is an \r\n appended, zap it.  */
+        if (chars >= 2
+            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
+            chars -= 2;
+            msgbuf[chars] = 0;
+        }
+
+        if (chars > sizeof (buf) - 1) {
+            chars = sizeof (buf) - 1;
+            msgbuf[chars] = 0;
+        }
+
+        wcstombs(buf, msgbuf, chars + 1);
+        LocalFree(msgbuf);
+    }
+    else {
+        sprintf(buf, "unknown win32 error (%ld)", error);
+    }
+
+    SetLastError(lasterr);
+    return buf;
+}
+
+#endif /* UNDER_CE */
+
+/* Reset gzip file state */
+local void gz_reset(state)
+    gz_statep state;
+{
+    if (state->mode == GZ_READ) {   /* for reading ... */
+        state->have = 0;            /* no output data available */
+        state->eof = 0;             /* not at end of file */
+        state->how = LOOK;          /* look for gzip header */
+        state->direct = 1;          /* default for empty file */
+    }
+    state->seek = 0;                /* no seek request pending */
+    gz_error(state, Z_OK, NULL);    /* clear error */
+    state->pos = 0;                 /* no uncompressed data yet */
+    state->strm.avail_in = 0;       /* no input data yet */
+}
+
+/* Open a gzip file either by name or file descriptor. */
+local gzFile gz_open(path, fd, mode)
+    const char *path;
+    int fd;
+    const char *mode;
+{
+    gz_statep state;
+
+    /* allocate gzFile structure to return */
+    state = malloc(sizeof(gz_state));
+    if (state == NULL)
+        return NULL;
+    state->size = 0;            /* no buffers allocated yet */
+    state->want = GZBUFSIZE;    /* requested buffer size */
+    state->msg = NULL;          /* no error message yet */
+
+    /* interpret mode */
+    state->mode = GZ_NONE;
+    state->level = Z_DEFAULT_COMPRESSION;
+    state->strategy = Z_DEFAULT_STRATEGY;
+    while (*mode) {
+        if (*mode >= '0' && *mode <= '9')
+            state->level = *mode - '0';
+        else
+            switch (*mode) {
+            case 'r':
+                state->mode = GZ_READ;
+                break;
+#ifndef NO_GZCOMPRESS
+            case 'w':
+                state->mode = GZ_WRITE;
+                break;
+            case 'a':
+                state->mode = GZ_APPEND;
+                break;
+#endif
+            case '+':       /* can't read and write at the same time */
+                free(state);
+                return NULL;
+            case 'b':       /* ignore -- will request binary anyway */
+                break;
+            case 'f':
+                state->strategy = Z_FILTERED;
+                break;
+            case 'h':
+                state->strategy = Z_HUFFMAN_ONLY;
+                break;
+            case 'R':
+                state->strategy = Z_RLE;
+                break;
+            case 'F':
+                state->strategy = Z_FIXED;
+            default:        /* could consider as an error, but just ignore */
+                ;
+            }
+        mode++;
+    }
+
+    /* must provide an "r", "w", or "a" */
+    if (state->mode == GZ_NONE) {
+        free(state);
+        return NULL;
+    }
+
+    /* save the path name for error messages */
+    state->path = malloc(strlen(path) + 1);
+    if (state->path == NULL) {
+        free(state);
+        return NULL;
+    }
+    strcpy(state->path, path);
+
+    /* open the file with the appropriate mode (or just use fd) */
+    state->fd = fd != -1 ? fd :
+        open(path,
+#ifdef O_LARGEFILE
+            O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+            O_BINARY |
+#endif
+            (state->mode == GZ_READ ?
+                O_RDONLY :
+                (O_WRONLY | O_CREAT | (
+                    state->mode == GZ_WRITE ?
+                        O_TRUNC :
+                        O_APPEND))),
+            0666);
+    if (state->fd == -1) {
+        free(state->path);
+        free(state);
+        return NULL;
+    }
+    if (state->mode == GZ_APPEND)
+        state->mode = GZ_WRITE;         /* simplify later checks */
+
+    /* save the current position for rewinding (only if reading) */
+    if (state->mode == GZ_READ) {
+        state->start = LSEEK(state->fd, 0, SEEK_CUR);
+        if (state->start == -1) state->start = 0;
+    }
+
+    /* initialize stream */
+    gz_reset(state);
+
+    /* return stream */
+    return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen(path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen64(path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzdopen(fd, mode)
+    int fd;
+    const char *mode;
+{
+    char *path;         /* identifier for error messages */
+    gzFile gz;
+
+    if (fd == -1 || (path = malloc(7 + 3 * sizeof(int))) == NULL)
+        return NULL;
+    sprintf(path, "<fd:%d>", fd);   /* for debugging */
+    gz = gz_open(path, fd, mode);
+    free(path);
+    return gz;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzbuffer(file, size)
+    gzFile file;
+    unsigned size;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* make sure we haven't already allocated memory */
+    if (state->size != 0)
+        return -1;
+
+    /* check and set requested size */
+    if (size == 0)
+        return -1;
+    state->want = size;
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzrewind(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* back up and start over */
+    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+        return -1;
+    gz_reset(state);
+    return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzseek64(file, offset, whence)
+    gzFile file;
+    z_off64_t offset;
+    int whence;
+{
+    unsigned n;
+    z_off64_t ret;
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* check that there's no error */
+    if (state->err != Z_OK)
+        return -1;
+
+    /* can only seek from start or relative to current position */
+    if (whence != SEEK_SET && whence != SEEK_CUR)
+        return -1;
+
+    /* normalize offset to a SEEK_CUR specification */
+    if (whence == SEEK_SET)
+        offset -= state->pos;
+    else if (state->seek)
+        offset += state->skip;
+    state->seek = 0;
+
+    /* if within raw area while reading, just go there */
+    if (state->mode == GZ_READ && state->how == COPY &&
+        state->pos + offset >= state->raw) {
+        ret = LSEEK(state->fd, offset - state->have, SEEK_CUR);
+        if (ret == -1)
+            return -1;
+        state->have = 0;
+        state->eof = 0;
+        state->seek = 0;
+        gz_error(state, Z_OK, NULL);
+        state->strm.avail_in = 0;
+        state->pos += offset;
+        return state->pos;
+    }
+
+    /* calculate skip amount, rewinding if needed for back seek when reading */
+    if (offset < 0) {
+        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
+            return -1;
+        offset += state->pos;
+        if (offset < 0)                     /* before start of file! */
+            return -1;
+        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
+            return -1;
+    }
+
+    /* if reading, skip what's in output buffer (one less gzgetc() check) */
+    if (state->mode == GZ_READ) {
+        n = GT_OFF(state->have) || (z_off64_t)state->have > offset ?
+            (unsigned)offset : state->have;
+        state->have -= n;
+        state->next += n;
+        state->pos += n;
+        offset -= n;
+    }
+
+    /* request skip (if not zero) */
+    if (offset) {
+        state->seek = 1;
+        state->skip = offset;
+    }
+    return state->pos + offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzseek(file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    z_off64_t ret;
+
+    ret = gzseek64(file, (z_off64_t)offset, whence);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gztell64(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* return position */
+    return state->pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gztell(file)
+    gzFile file;
+{
+    z_off64_t ret;
+
+    ret = gztell64(file);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzoffset64(file)
+    gzFile file;
+{
+    z_off64_t offset;
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* compute and return effective offset in file */
+    offset = LSEEK(state->fd, 0, SEEK_CUR);
+    if (offset == -1)
+        return -1;
+    if (state->mode == GZ_READ)             /* reading */
+        offset -= state->strm.avail_in;     /* don't count buffered input */
+    return offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzoffset(file)
+    gzFile file;
+{
+    z_off64_t ret;
+
+    ret = gzoffset64(file);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzeof(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return 0;
+
+    /* return end-of-file state */
+    return state->mode == GZ_READ ?
+        (state->eof && state->strm.avail_in == 0 && state->have == 0) : 0;
+}
+
+/* -- see zlib.h -- */
+const char * ZEXPORT gzerror(file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return NULL;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return NULL;
+
+    /* return error information */
+    if (errnum != NULL)
+        *errnum = state->err;
+    return state->msg == NULL ? "" : state->msg;
+}
+
+/* -- see zlib.h -- */
+void ZEXPORT gzclearerr(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return;
+
+    /* clear error and end-of-file */
+    if (state->mode == GZ_READ)
+        state->eof = 0;
+    gz_error(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+   state->msg accordingly.  Free any previous error message already there.  Do
+   not try to free or allocate space if the error is Z_MEM_ERROR (out of
+   memory).  Simply save the error message as a static string.  If there is an
+   allocation failure constructing the error message, then convert the error to
+   out of memory. */
+void ZLIB_INTERNAL gz_error(state, err, msg)
+    gz_statep state;
+    int err;
+    const char *msg;
+{
+    /* free previously allocated message and clear */
+    if (state->msg != NULL) {
+        if (state->err != Z_MEM_ERROR)
+            free(state->msg);
+        state->msg = NULL;
+    }
+
+    /* set error code, and if no message, then done */
+    state->err = err;
+    if (msg == NULL)
+        return;
+
+    /* for an out of memory error, save as static string */
+    if (err == Z_MEM_ERROR) {
+        state->msg = (char *)msg;
+        return;
+    }
+
+    /* construct error message with path */
+    if ((state->msg = malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) {
+        state->err = Z_MEM_ERROR;
+        state->msg = (char *)"out of memory";
+        return;
+    }
+    strcpy(state->msg, state->path);
+    strcat(state->msg, ": ");
+    strcat(state->msg, msg);
+    return;
+}
+
+#ifndef INT_MAX
+/* portably return maximum value for an int (when limits.h presumed not
+   available) -- we need to do this to cover cases where 2's complement not
+   used, since C standard permits 1's complement and sign-bit representations,
+   otherwise we could just use ((unsigned)-1) >> 1 */
+unsigned ZLIB_INTERNAL gz_intmax()
+{
+    unsigned p, q;
+
+    p = 1;
+    do {
+        q = p;
+        p <<= 1;
+        p++;
+    } while (p > q);
+    return q >> 1;
+}
+#endif
diff --git a/zlib/gzread.c b/zlib/gzread.c
new file mode 100644 (file)
index 0000000..548201a
--- /dev/null
@@ -0,0 +1,653 @@
+/* gzread.c -- zlib functions for reading gzip files
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
+local int gz_avail OF((gz_statep));
+local int gz_next4 OF((gz_statep, unsigned long *));
+local int gz_head OF((gz_statep));
+local int gz_decomp OF((gz_statep));
+local int gz_make OF((gz_statep));
+local int gz_skip OF((gz_statep, z_off64_t));
+
+/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
+   state->fd, and update state->eof, state->err, and state->msg as appropriate.
+   This function needs to loop on read(), since read() is not guaranteed to
+   read the number of bytes requested, depending on the type of descriptor. */
+local int gz_load(state, buf, len, have)
+    gz_statep state;
+    unsigned char *buf;
+    unsigned len;
+    unsigned *have;
+{
+    int ret;
+
+    *have = 0;
+    do {
+        ret = read(state->fd, buf + *have, len - *have);
+        if (ret <= 0)
+            break;
+        *have += ret;
+    } while (*have < len);
+    if (ret < 0) {
+        gz_error(state, Z_ERRNO, zstrerror());
+        return -1;
+    }
+    if (ret == 0)
+        state->eof = 1;
+    return 0;
+}
+
+/* Load up input buffer and set eof flag if last data loaded -- return -1 on
+   error, 0 otherwise.  Note that the eof flag is set when the end of the input
+   file is reached, even though there may be unused data in the buffer.  Once
+   that data has been used, no more attempts will be made to read the file.
+   gz_avail() assumes that strm->avail_in == 0. */
+local int gz_avail(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+
+    if (state->err != Z_OK)
+        return -1;
+    if (state->eof == 0) {
+        if (gz_load(state, state->in, state->size,
+                (unsigned *)&(strm->avail_in)) == -1)
+            return -1;
+        strm->next_in = state->in;
+    }
+    return 0;
+}
+
+/* Get next byte from input, or -1 if end or error. */
+#define NEXT() ((strm->avail_in == 0 && gz_avail(state) == -1) ? -1 : \
+                (strm->avail_in == 0 ? -1 : \
+                 (strm->avail_in--, *(strm->next_in)++)))
+
+/* Get a four-byte little-endian integer and return 0 on success and the value
+   in *ret.  Otherwise -1 is returned and *ret is not modified. */
+local int gz_next4(state, ret)
+    gz_statep state;
+    unsigned long *ret;
+{
+    int ch;
+    unsigned long val;
+    z_streamp strm = &(state->strm);
+
+    val = NEXT();
+    val += (unsigned)NEXT() << 8;
+    val += (unsigned long)NEXT() << 16;
+    ch = NEXT();
+    if (ch == -1)
+        return -1;
+    val += (unsigned long)ch << 24;
+    *ret = val;
+    return 0;
+}
+
+/* Look for gzip header, set up for inflate or copy.  state->have must be zero.
+   If this is the first time in, allocate required memory.  state->how will be
+   left unchanged if there is no more input data available, will be set to COPY
+   if there is no gzip header and direct copying will be performed, or it will
+   be set to GZIP for decompression, and the gzip header will be skipped so
+   that the next available input data is the raw deflate stream.  If direct
+   copying, then leftover input data from the input buffer will be copied to
+   the output buffer.  In that case, all further file reads will be directly to
+   either the output buffer or a user buffer.  If decompressing, the inflate
+   state and the check value will be initialized.  gz_head() will return 0 on
+   success or -1 on failure.  Failures may include read errors or gzip header
+   errors.  */
+local int gz_head(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+    int flags;
+    unsigned len;
+
+    /* allocate read buffers and inflate memory */
+    if (state->size == 0) {
+        /* allocate buffers */
+        state->in = malloc(state->want);
+        state->out = malloc(state->want << 1);
+        if (state->in == NULL || state->out == NULL) {
+            if (state->out != NULL)
+                free(state->out);
+            if (state->in != NULL)
+                free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        state->size = state->want;
+
+        /* allocate inflate memory */
+        state->strm.zalloc = Z_NULL;
+        state->strm.zfree = Z_NULL;
+        state->strm.opaque = Z_NULL;
+        state->strm.avail_in = 0;
+        state->strm.next_in = Z_NULL;
+        if (inflateInit2(&(state->strm), -15) != Z_OK) {    /* raw inflate */
+            free(state->out);
+            free(state->in);
+            state->size = 0;
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+    }
+
+    /* get some data in the input buffer */
+    if (strm->avail_in == 0) {
+        if (gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in == 0)
+            return 0;
+    }
+
+    /* look for the gzip magic header bytes 31 and 139 */
+    if (strm->next_in[0] == 31) {
+        strm->avail_in--;
+        strm->next_in++;
+        if (strm->avail_in == 0 && gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in && strm->next_in[0] == 139) {
+            /* we have a gzip header, woo hoo! */
+            strm->avail_in--;
+            strm->next_in++;
+
+            /* skip rest of header */
+            if (NEXT() != 8) {      /* compression method */
+                gz_error(state, Z_DATA_ERROR, "unknown compression method");
+                return -1;
+            }
+            flags = NEXT();
+            if (flags & 0xe0) {     /* reserved flag bits */
+                gz_error(state, Z_DATA_ERROR, "unknown header flags set");
+                return -1;
+            }
+            NEXT();                 /* modification time */
+            NEXT();
+            NEXT();
+            NEXT();
+            NEXT();                 /* extra flags */
+            NEXT();                 /* operating system */
+            if (flags & 4) {        /* extra field */
+                len = (unsigned)NEXT();
+                len += (unsigned)NEXT() << 8;
+                while (len--)
+                    if (NEXT() < 0)
+                        break;
+            }
+            if (flags & 8)          /* file name */
+                while (NEXT() > 0)
+                    ;
+            if (flags & 16)         /* comment */
+                while (NEXT() > 0)
+                    ;
+            if (flags & 2) {        /* header crc */
+                NEXT();
+                NEXT();
+            }
+            /* an unexpected end of file is not checked for here -- it will be
+               noticed on the first request for uncompressed data */
+
+            /* set up for decompression */
+            inflateReset(strm);
+            strm->adler = crc32(0L, Z_NULL, 0);
+            state->how = GZIP;
+            state->direct = 0;
+            return 0;
+        }
+        else {
+            /* not a gzip file -- save first byte (31) and fall to raw i/o */
+            state->out[0] = 31;
+            state->have = 1;
+        }
+    }
+
+    /* doing raw i/o, save start of raw data for seeking, copy any leftover
+       input to output -- this assumes that the output buffer is larger than
+       the input buffer, which also assures space for gzungetc() */
+    state->raw = state->pos;
+    state->next = state->out;
+    if (strm->avail_in) {
+        memcpy(state->next + state->have, strm->next_in, strm->avail_in);
+        state->have += strm->avail_in;
+        strm->avail_in = 0;
+    }
+    state->how = COPY;
+    state->direct = 1;
+    return 0;
+}
+
+/* Decompress from input to the provided next_out and avail_out in the state.
+   If the end of the compressed data is reached, then verify the gzip trailer
+   check value and length (modulo 2^32).  state->have and state->next are set
+   to point to the just decompressed data, and the crc is updated.  If the
+   trailer is verified, state->how is reset to LOOK to look for the next gzip
+   stream or raw data, once state->have is depleted.  Returns 0 on success, -1
+   on failure.  Failures may include invalid compressed data or a failed gzip
+   trailer verification. */
+local int gz_decomp(state)
+    gz_statep state;
+{
+    int ret;
+    unsigned had;
+    unsigned long crc, len;
+    z_streamp strm = &(state->strm);
+
+    /* fill output buffer up to end of deflate stream */
+    had = strm->avail_out;
+    do {
+        /* get more input for inflate() */
+        if (strm->avail_in == 0 && gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in == 0) {
+            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
+            return -1;
+        }
+
+        /* decompress and handle errors */
+        ret = inflate(strm, Z_NO_FLUSH);
+        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
+            gz_error(state, Z_STREAM_ERROR,
+                      "internal error: inflate stream corrupt");
+            return -1;
+        }
+        if (ret == Z_MEM_ERROR) {
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
+            gz_error(state, Z_DATA_ERROR,
+                      strm->msg == NULL ? "compressed data error" : strm->msg);
+            return -1;
+        }
+    } while (strm->avail_out && ret != Z_STREAM_END);
+
+    /* update available output and crc check value */
+    state->have = had - strm->avail_out;
+    state->next = strm->next_out - state->have;
+    strm->adler = crc32(strm->adler, state->next, state->have);
+
+    /* check gzip trailer if at end of deflate stream */
+    if (ret == Z_STREAM_END) {
+        if (gz_next4(state, &crc) == -1 || gz_next4(state, &len) == -1) {
+            gz_error(state, Z_DATA_ERROR, "unexpected end of file");
+            return -1;
+        }
+        if (crc != strm->adler) {
+            gz_error(state, Z_DATA_ERROR, "incorrect data check");
+            return -1;
+        }
+        if (len != (strm->total_out & 0xffffffffL)) {
+            gz_error(state, Z_DATA_ERROR, "incorrect length check");
+            return -1;
+        }
+        state->how = LOOK;      /* ready for next stream, once have is 0 (leave
+                                   state->direct unchanged to remember how) */
+    }
+
+    /* good decompression */
+    return 0;
+}
+
+/* Make data and put in the output buffer.  Assumes that state->have == 0.
+   Data is either copied from the input file or decompressed from the input
+   file depending on state->how.  If state->how is LOOK, then a gzip header is
+   looked for (and skipped if found) to determine wither to copy or decompress.
+   Returns -1 on error, otherwise 0.  gz_make() will leave state->have as COPY
+   or GZIP unless the end of the input file has been reached and all data has
+   been processed.  */
+local int gz_make(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+
+    if (state->how == LOOK) {           /* look for gzip header */
+        if (gz_head(state) == -1)
+            return -1;
+        if (state->have)                /* got some data from gz_head() */
+            return 0;
+    }
+    if (state->how == COPY) {           /* straight copy */
+        if (gz_load(state, state->out, state->size << 1, &(state->have)) == -1)
+            return -1;
+        state->next = state->out;
+    }
+    else if (state->how == GZIP) {      /* decompress */
+        strm->avail_out = state->size << 1;
+        strm->next_out = state->out;
+        if (gz_decomp(state) == -1)
+            return -1;
+    }
+    return 0;
+}
+
+/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
+local int gz_skip(state, len)
+    gz_statep state;
+    z_off64_t len;
+{
+    unsigned n;
+
+    /* skip over len bytes or reach end-of-file, whichever comes first */
+    while (len)
+        /* skip over whatever is in output buffer */
+        if (state->have) {
+            n = GT_OFF(state->have) || (z_off64_t)state->have > len ?
+                (unsigned)len : state->have;
+            state->have -= n;
+            state->next += n;
+            state->pos += n;
+            len -= n;
+        }
+
+        /* output buffer empty -- return if we're at the end of the input */
+        else if (state->eof && state->strm.avail_in == 0)
+            break;
+
+        /* need more data to skip -- load up output buffer */
+        else {
+            /* get more output, looking for header if required */
+            if (gz_make(state) == -1)
+                return -1;
+        }
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzread(file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    unsigned got, n;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* since an int is returned, make sure len fits in one, otherwise return
+       with an error (this avoids the flaw in the interface) */
+    if ((int)len < 0) {
+        gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
+        return -1;
+    }
+
+    /* if len is zero, avoid unnecessary operations */
+    if (len == 0)
+        return 0;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* get len bytes to buf, or less than len if at the end */
+    got = 0;
+    do {
+        /* first just try copying data from the output buffer */
+        if (state->have) {
+            n = state->have > len ? len : state->have;
+            memcpy(buf, state->next, n);
+            state->next += n;
+            state->have -= n;
+        }
+
+        /* output buffer empty -- return if we're at the end of the input */
+        else if (state->eof && strm->avail_in == 0)
+            break;
+
+        /* need output data -- for small len or new stream load up our output
+           buffer */
+        else if (state->how == LOOK || len < (state->size << 1)) {
+            /* get more output, looking for header if required */
+            if (gz_make(state) == -1)
+                return -1;
+            continue;       /* no progress yet -- go back to memcpy() above */
+            /* the copy above assures that we will leave with space in the
+               output buffer, allowing at least one gzungetc() to succeed */
+        }
+
+        /* large len -- read directly into user buffer */
+        else if (state->how == COPY) {      /* read directly */
+            if (gz_load(state, buf, len, &n) == -1)
+                return -1;
+        }
+
+        /* large len -- decompress directly into user buffer */
+        else {  /* state->how == GZIP */
+            strm->avail_out = len;
+            strm->next_out = buf;
+            if (gz_decomp(state) == -1)
+                return -1;
+            n = state->have;
+            state->have = 0;
+        }
+
+        /* update progress */
+        len -= n;
+        buf = (char *)buf + n;
+        got += n;
+        state->pos += n;
+    } while (len);
+
+    /* return number of bytes read into user buffer (will fit in int) */
+    return (int)got;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    int ret;
+    unsigned char buf[1];
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* try output buffer (no need to check for skip request) */
+    if (state->have) {
+        state->have--;
+        state->pos++;
+        return *(state->next)++;
+    }
+
+    /* nothing there -- try gzread() */
+    ret = gzread(file, buf, 1);
+    return ret < 1 ? -1 : buf[0];
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzungetc(c, file)
+    int c;
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return -1;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* can't push EOF */
+    if (c < 0)
+        return -1;
+
+    /* if output buffer empty, put byte at end (allows more pushing) */
+    if (state->have == 0) {
+        state->have = 1;
+        state->next = state->out + (state->size << 1) - 1;
+        state->next[0] = c;
+        state->pos--;
+        return c;
+    }
+
+    /* if no room, give up (must have already done a gzungetc()) */
+    if (state->have == (state->size << 1)) {
+        gz_error(state, Z_BUF_ERROR, "out of room to push characters");
+        return -1;
+    }
+
+    /* slide output data if needed and insert byte before existing data */
+    if (state->next == state->out) {
+        unsigned char *src = state->out + state->have;
+        unsigned char *dest = state->out + (state->size << 1);
+        while (src > state->out)
+            *--dest = *--src;
+        state->next = dest;
+    }
+    state->have++;
+    state->next--;
+    state->next[0] = c;
+    state->pos--;
+    return c;
+}
+
+/* -- see zlib.h -- */
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    unsigned left, n;
+    char *str;
+    unsigned char *eol;
+    gz_statep state;
+
+    /* check parameters and get internal structure */
+    if (file == NULL || buf == NULL || len < 1)
+        return NULL;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ || state->err != Z_OK)
+        return NULL;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return NULL;
+    }
+
+    /* copy output bytes up to new line or len - 1, whichever comes first --
+       append a terminating zero to the string (we don't check for a zero in
+       the contents, let the user worry about that) */
+    str = buf;
+    left = (unsigned)len - 1;
+    if (left) do {
+        /* assure that something is in the output buffer */
+        if (state->have == 0) {
+            if (gz_make(state) == -1)
+                return NULL;            /* error */
+            if (state->have == 0) {     /* end of file */
+                if (buf == str)         /* got bupkus */
+                    return NULL;
+                break;                  /* got something -- return it */
+            }
+        }
+
+        /* look for end-of-line in current output buffer */
+        n = state->have > left ? left : state->have;
+        eol = memchr(state->next, '\n', n);
+        if (eol != NULL)
+            n = (unsigned)(eol - state->next) + 1;
+
+        /* copy through end-of-line, or remainder if not found */
+        memcpy(buf, state->next, n);
+        state->have -= n;
+        state->next += n;
+        state->pos += n;
+        left -= n;
+        buf += n;
+    } while (left && eol == NULL);
+
+    /* found end-of-line or out of space -- terminate string and return it */
+    buf[0] = 0;
+    return str;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzdirect(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+
+    /* check that we're reading */
+    if (state->mode != GZ_READ)
+        return 0;
+
+    /* if the state is not known, but we can find out, then do so (this is
+       mainly for right after a gzopen() or gzdopen()) */
+    if (state->how == LOOK && state->have == 0)
+        (void)gz_head(state);
+
+    /* return 1 if reading direct, 0 if decompressing a gzip stream */
+    return state->direct;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_r(file)
+    gzFile file;
+{
+    int ret;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're reading */
+    if (state->mode != GZ_READ)
+        return Z_STREAM_ERROR;
+
+    /* free memory and close file */
+    if (state->size) {
+        inflateEnd(&(state->strm));
+        free(state->out);
+        free(state->in);
+    }
+    gz_error(state, Z_OK, NULL);
+    free(state->path);
+    ret = close(state->fd);
+    free(state);
+    return ret ? Z_ERRNO : Z_OK;
+}
diff --git a/zlib/gzwrite.c b/zlib/gzwrite.c
new file mode 100644 (file)
index 0000000..e8defc6
--- /dev/null
@@ -0,0 +1,531 @@
+/* gzwrite.c -- zlib functions for writing gzip files
+ * Copyright (C) 2004, 2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_init OF((gz_statep));
+local int gz_comp OF((gz_statep, int));
+local int gz_zero OF((gz_statep, z_off64_t));
+
+/* Initialize state for writing a gzip file.  Mark initialization by setting
+   state->size to non-zero.  Return -1 on failure or 0 on success. */
+local int gz_init(state)
+    gz_statep state;
+{
+    int ret;
+    z_streamp strm = &(state->strm);
+
+    /* allocate input and output buffers */
+    state->in = malloc(state->want);
+    state->out = malloc(state->want);
+    if (state->in == NULL || state->out == NULL) {
+        if (state->out != NULL)
+            free(state->out);
+        if (state->in != NULL)
+            free(state->in);
+        gz_error(state, Z_MEM_ERROR, "out of memory");
+        return -1;
+    }
+
+    /* allocate deflate memory, set up for gzip compression */
+    strm->zalloc = Z_NULL;
+    strm->zfree = Z_NULL;
+    strm->opaque = Z_NULL;
+    ret = deflateInit2(strm, state->level, Z_DEFLATED,
+                       15 + 16, 8, state->strategy);
+    if (ret != Z_OK) {
+        free(state->in);
+        gz_error(state, Z_MEM_ERROR, "out of memory");
+        return -1;
+    }
+
+    /* mark state as initialized */
+    state->size = state->want;
+
+    /* initialize write buffer */
+    strm->avail_out = state->size;
+    strm->next_out = state->out;
+    state->next = strm->next_out;
+    return 0;
+}
+
+/* Compress whatever is at avail_in and next_in and write to the output file.
+   Return -1 if there is an error writing to the output file, otherwise 0.
+   flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
+   then the deflate() state is reset to start a new gzip stream. */
+local int gz_comp(state, flush)
+    gz_statep state;
+    int flush;
+{
+    int ret, got;
+    unsigned have;
+    z_streamp strm = &(state->strm);
+
+    /* allocate memory if this is the first time through */
+    if (state->size == 0 && gz_init(state) == -1)
+        return -1;
+
+    /* run deflate() on provided input until it produces no more output */
+    ret = Z_OK;
+    do {
+        /* write out current buffer contents if full, or if flushing, but if
+           doing Z_FINISH then don't write until we get to Z_STREAM_END */
+        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
+            (flush != Z_FINISH || ret == Z_STREAM_END))) {
+            have = (unsigned)(strm->next_out - state->next);
+            if (have && ((got = write(state->fd, state->next, have)) < 0 ||
+                         (unsigned)got != have)) {
+                gz_error(state, Z_ERRNO, zstrerror());
+                return -1;
+            }
+            if (strm->avail_out == 0) {
+                strm->avail_out = state->size;
+                strm->next_out = state->out;
+            }
+            state->next = strm->next_out;
+        }
+
+        /* compress */
+        have = strm->avail_out;
+        ret = deflate(strm, flush);
+        if (ret == Z_STREAM_ERROR) {
+            gz_error(state, Z_STREAM_ERROR,
+                      "internal error: deflate stream corrupt");
+            return -1;
+        }
+        have -= strm->avail_out;
+    } while (have);
+
+    /* if that completed a deflate stream, allow another to start */
+    if (flush == Z_FINISH)
+        deflateReset(strm);
+
+    /* all done, no errors */
+    return 0;
+}
+
+/* Compress len zeros to output.  Return -1 on error, 0 on success. */
+local int gz_zero(state, len)
+    gz_statep state;
+    z_off64_t len;
+{
+    int first;
+    unsigned n;
+    z_streamp strm = &(state->strm);
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return -1;
+
+    /* compress len zeros (len guaranteed > 0) */
+    first = 1;
+    while (len) {
+        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
+            (unsigned)len : state->size;
+        if (first) {
+            memset(state->in, 0, n);
+            first = 0;
+        }
+        strm->avail_in = n;
+        strm->next_in = state->in;
+        state->pos += n;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return -1;
+        len -= n;
+    }
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzwrite(file, buf, len)
+    gzFile file;
+    voidpc buf;
+    unsigned len;
+{
+    unsigned put = len;
+    unsigned n;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* since an int is returned, make sure len fits in one, otherwise return
+       with an error (this avoids the flaw in the interface) */
+    if ((int)len < 0) {
+        gz_error(state, Z_BUF_ERROR, "requested length does not fit in int");
+        return 0;
+    }
+
+    /* if len is zero, avoid unnecessary operations */
+    if (len == 0)
+        return 0;
+
+    /* allocate memory if this is the first time through */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* for small len, copy to input buffer, otherwise compress directly */
+    if (len < state->size) {
+        /* copy to input buffer, compress when full */
+        do {
+            if (strm->avail_in == 0)
+                strm->next_in = state->in;
+            n = state->size - strm->avail_in;
+            if (n > len)
+                n = len;
+            memcpy(strm->next_in + strm->avail_in, buf, n);
+            strm->avail_in += n;
+            state->pos += n;
+            buf = (char *)buf + n;
+            len -= n;
+            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
+                return 0;
+        } while (len);
+    }
+    else {
+        /* consume whatever's left in the input buffer */
+        if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+            return 0;
+
+        /* directly compress user buffer to file */
+        strm->avail_in = len;
+        strm->next_in = (voidp)buf;
+        state->pos += len;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return 0;
+    }
+
+    /* input was all buffered or compressed (put will fit in int) */
+    return (int)put;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned char buf[1];
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return -1;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* try writing to input buffer for speed (state->size == 0 if buffer not
+       initialized) */
+    if (strm->avail_in < state->size) {
+        if (strm->avail_in == 0)
+            strm->next_in = state->in;
+        strm->next_in[strm->avail_in++] = c;
+        state->pos++;
+        return c;
+    }
+
+    /* no room in buffer or not initialized, use gz_write() */
+    buf[0] = c;
+    if (gzwrite(file, buf, 1) != 1)
+        return -1;
+    return c;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputs(file, str)
+    gzFile file;
+    const char *str;
+{
+    int ret;
+    unsigned len;
+
+    /* write string */
+    len = (unsigned)strlen(str);
+    ret = gzwrite(file, str, len);
+    return ret == 0 && len != 0 ? -1 : ret;
+}
+
+#ifdef STDC
+#include <stdarg.h>
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
+{
+    int size, len;
+    gz_statep state;
+    z_streamp strm;
+    va_list va;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* make sure we have some buffer space */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return 0;
+
+    /* do the printf() into the input buffer, put length in len */
+    size = (int)(state->size);
+    state->in[size - 1] = 0;
+    va_start(va, format);
+#ifdef NO_vsnprintf
+#  ifdef HAS_vsprintf_void
+    (void)vsprintf(state->in, format, va);
+    va_end(va);
+    for (len = 0; len < size; len++)
+        if (state->in[len] == 0) break;
+#  else
+    len = vsprintf(state->in, format, va);
+    va_end(va);
+#  endif
+#else
+#  ifdef HAS_vsnprintf_void
+    (void)vsnprintf(state->in, size, format, va);
+    va_end(va);
+    len = strlen(state->in);
+#  else
+    len = vsnprintf((char *)(state->in), size, format, va);
+    va_end(va);
+#  endif
+#endif
+
+    /* check that printf() results fit in buffer */
+    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+        return 0;
+
+    /* update buffer and position, defer compression until needed */
+    strm->avail_in = (unsigned)len;
+    strm->next_in = state->in;
+    state->pos += len;
+    return len;
+}
+
+#else /* !STDC */
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    int size, len;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* make sure we have some buffer space */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return 0;
+
+    /* do the printf() into the input buffer, put length in len */
+    size = (int)(state->size);
+    state->in[size - 1] = 0;
+#ifdef NO_snprintf
+#  ifdef HAS_sprintf_void
+    sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
+            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    for (len = 0; len < size; len++)
+        if (state->in[len] == 0) break;
+#  else
+    len = sprintf(state->in, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#else
+#  ifdef HAS_snprintf_void
+    snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    len = strlen(state->in);
+#  else
+    len = snprintf(state->in, size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#endif
+
+    /* check that printf() results fit in buffer */
+    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
+        return 0;
+
+    /* update buffer and position, defer compression until needed */
+    strm->avail_in = (unsigned)len;
+    strm->next_in = state->in;
+    state->pos += len;
+    return len;
+}
+
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzflush(file, flush)
+    gzFile file;
+    int flush;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* check flush parameter */
+    if (flush < 0 || flush > Z_FINISH)
+        return Z_STREAM_ERROR;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* compress remaining data with requested flush */
+    gz_comp(state, flush);
+    return state->err;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzsetparams(file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* if no change is requested, then do nothing */
+    if (level == state->level && strategy == state->strategy)
+        return Z_OK;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* change compression parameters for subsequent input */
+    if (state->size) {
+        /* flush previous input with previous parameters before changing */
+        if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
+            return state->err;
+        deflateParams(strm, level, strategy);
+    }
+    state->level = level;
+    state->strategy = strategy;
+    return Z_OK;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_w(file)
+    gzFile file;
+{
+    int ret = 0;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're writing */
+    if (state->mode != GZ_WRITE)
+        return Z_STREAM_ERROR;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        ret += gz_zero(state, state->skip);
+    }
+
+    /* flush, free memory, and close file */
+    ret += gz_comp(state, Z_FINISH);
+    (void)deflateEnd(&(state->strm));
+    free(state->out);
+    free(state->in);
+    gz_error(state, Z_OK, NULL);
+    free(state->path);
+    ret += close(state->fd);
+    free(state);
+    return ret ? Z_ERRNO : Z_OK;
+}
diff --git a/zlib/infback.c b/zlib/infback.c
new file mode 100644 (file)
index 0000000..af3a8c9
--- /dev/null
@@ -0,0 +1,632 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->wnext = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    NEEDBITS(here.bits);
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(here.bits);
+            state->length = (unsigned)here.val;
+
+            /* process literal */
+            if (here.op == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(here.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(here.bits);
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(here.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
diff --git a/zlib/inffast.c b/zlib/inffast.c
new file mode 100644 (file)
index 0000000..2f1d60b
--- /dev/null
@@ -0,0 +1,340 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+   Based on testing to date,
+   Pre-increment preferred for:
+   - PowerPC G3 (Adler)
+   - MIPS R5000 (Randers-Pehrson)
+   Post-increment preferred for:
+   - none
+   No measurable difference:
+   - Pentium III (Anderson)
+   - M68060 (Nikl)
+ */
+#ifdef POSTINC
+#  define OFF 0
+#  define PUP(a) *(a)++
+#else
+#  define OFF 1
+#  define PUP(a) *++(a)
+#endif
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *in;      /* local strm->next_in */
+    unsigned char FAR *last;    /* while in < last, enough input available */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code here;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in - OFF;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out - OFF;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    wnext = state->wnext;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+            hold += (unsigned long)(PUP(in)) << bits;
+            bits += 8;
+        }
+        here = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(here.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(here.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", here.val));
+            PUP(out) = (unsigned char)(here.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(here.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+                hold += (unsigned long)(PUP(in)) << bits;
+                bits += 8;
+            }
+            here = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(here.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(here.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(here.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(PUP(in)) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(PUP(in)) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        if (state->sane) {
+                            strm->msg =
+                                (char *)"invalid distance too far back";
+                            state->mode = BAD;
+                            break;
+                        }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                        if (len <= op - whave) {
+                            do {
+                                PUP(out) = 0;
+                            } while (--len);
+                            continue;
+                        }
+                        len -= op - whave;
+                        do {
+                            PUP(out) = 0;
+                        } while (--op > whave);
+                        if (op == 0) {
+                            from = out - dist;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--len);
+                            continue;
+                        }
+#endif
+                    }
+                    from = window - OFF;
+                    if (wnext == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (wnext < op) {      /* wrap around window */
+                        from += wsize + wnext - op;
+                        op -= wnext;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = window - OFF;
+                            if (wnext < len) {  /* some from start of window */
+                                op = wnext;
+                                len -= op;
+                                do {
+                                    PUP(out) = PUP(from);
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += wnext - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                PUP(out) = PUP(from);
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    }
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        PUP(out) = PUP(from);
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        PUP(out) = PUP(from);
+                        if (len > 1)
+                            PUP(out) = PUP(from);
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                here = dcode[here.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            here = lcode[here.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in + OFF;
+    strm->next_out = out + OFF;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and wnext == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/zlib/inffast.h b/zlib/inffast.h
new file mode 100644 (file)
index 0000000..e5c1aa4
--- /dev/null
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/zlib/inffixed.h b/zlib/inffixed.h
new file mode 100644 (file)
index 0000000..75ed4b5
--- /dev/null
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications. It
+       is part of the implementation of the compression library and
+       is subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/zlib/inflate.c b/zlib/inflate.c
new file mode 100644 (file)
index 0000000..a8431ab
--- /dev/null
@@ -0,0 +1,1480 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+                              unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    strm->adler = 1;        /* to support ill-conceived Java test suite */
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->wsize = 0;
+    state->whave = 0;
+    state->wnext = 0;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    state->sane = 1;
+    state->back = -1;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+    int wrap;
+    struct inflate_state FAR *state;
+
+    /* get the state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* extract wrap request from windowBits parameter */
+    if (windowBits < 0) {
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+        if (windowBits < 48)
+            windowBits &= 15;
+#endif
+    }
+
+    /* set number of window bits, free window if different */
+    if (windowBits && (windowBits < 8 || windowBits > 15))
+        return Z_STREAM_ERROR;
+    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+        ZFREE(strm, state->window);
+        state->window = Z_NULL;
+    }
+
+    /* update state and reset the rest of it */
+    state->wrap = wrap;
+    state->wbits = (unsigned)windowBits;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    int ret;
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->window = Z_NULL;
+    ret = inflateReset2(strm, windowBits);
+    if (ret != Z_OK) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+    }
+    return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits < 0) {
+        state->hold = 0;
+        state->bits = 0;
+        return Z_OK;
+    }
+    if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += value << state->bits;
+    state->bits += bits;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+               state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+    struct inflate_state FAR *state;
+    unsigned copy, dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->wnext = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    copy = out - strm->avail_out;
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+        state->wnext = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->wnext;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, strm->next_out - copy, copy);
+            state->wnext = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->wnext += dist;
+            if (state->wnext == state->wsize) state->wnext = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+    ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (state->wbits == 0)
+                state->wbits = len;
+            else if (len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if (state->flags & 0x0200) CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if (state->flags & 0x0200) CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if (state->flags & 0x0200) CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if (state->flags & 0x0200)
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = len;
+                } while (len && copy < have);
+                if (state->flags & 0x0200)
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if (hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = REVERSE(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN_;             /* decode codes */
+                if (flush == Z_TREES) {
+                    DROPBITS(2);
+                    goto inf_leave;
+                }
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY_;
+            if (flush == Z_TREES) goto inf_leave;
+        case COPY_:
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    NEEDBITS(here.bits);
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN_;
+            if (flush == Z_TREES) goto inf_leave;
+        case LEN_:
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                if (state->mode == TYPE)
+                    state->back = -1;
+                break;
+            }
+            state->back = 0;
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            state->length = (unsigned)here.val;
+            if ((int)(here.op) == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                state->mode = LIT;
+                break;
+            }
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->back = -1;
+                state->mode = TYPE;
+                break;
+            }
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->was = state->length;
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->whave) {
+                    if (state->sane) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                    Trace((stderr, "inflate.c too far\n"));
+                    copy -= state->whave;
+                    if (copy > state->length) copy = state->length;
+                    if (copy > left) copy = left;
+                    left -= copy;
+                    state->length -= copy;
+                    do {
+                        *put++ = 0;
+                    } while (--copy);
+                    if (state->length == 0) state->mode = LEN;
+                    break;
+#endif
+                }
+                if (copy > state->wnext) {
+                    copy -= state->wnext;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->wnext - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if (out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     REVERSE(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+        if (updatewindow(strm, out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if (state->wrap && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0) +
+                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long id;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary id */
+    if (state->mode == DICT) {
+        id = adler32(0L, Z_NULL, 0);
+        id = adler32(id, dictionary, dictLength);
+        if (id != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window */
+    if (updatewindow(strm, strm->avail_out)) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    if (dictLength > state->wsize) {
+        zmemcpy(state->window, dictionary + dictLength - state->wsize,
+                state->wsize);
+        state->whave = state->wsize;
+    }
+    else {
+        zmemcpy(state->window + state->wsize - dictLength, dictionary,
+                dictLength);
+        state->whave = dictLength;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+        source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+    return Z_OK;
+#else
+    state->sane = 1;
+    return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+    state = (struct inflate_state FAR *)strm->state;
+    return ((long)(state->back) << 16) +
+        (state->mode == COPY ? state->length :
+            (state->mode == MATCH ? state->was - state->length : 0));
+}
diff --git a/zlib/inflate.h b/zlib/inflate.h
new file mode 100644 (file)
index 0000000..95f4986
--- /dev/null
@@ -0,0 +1,122 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD,       /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY_,      /* i/o: same as COPY below, but only first time in */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN_,       /* i: same as LEN below, but only first time in */
+            LEN,        /* i: waiting for length/lit/eob code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib) or (raw)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+                  HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+        (raw) -> TYPEDO
+    Read deflate blocks:
+            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+            STORED -> COPY_ -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN_
+            LEN_ -> LEN
+    Read deflate codes in fixed or dynamic block:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls.  Approximately 10K bytes. */
+struct inflate_state {
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+    int sane;                   /* if false, allow invalid distance too far */
+    int back;                   /* bits back of last unprocessed length/lit */
+    unsigned was;               /* initial length of match */
+};
diff --git a/zlib/inftrees.c b/zlib/inftrees.c
new file mode 100644 (file)
index 0000000..11e9c52
--- /dev/null
@@ -0,0 +1,330 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.5 Copyright 1995-2010 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code here;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    int end;                    /* use base and extra for symbol > end */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 73, 195};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        here.op = (unsigned char)64;    /* invalid code marker */
+        here.bits = (unsigned char)1;
+        here.val = (unsigned short)0;
+        *(*table)++ = here;             /* make a table to force an error */
+        *(*table)++ = here;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min < max; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked for LENS and DIST tables against
+       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+       the initial root table size constants.  See the comments in inftrees.h
+       for more information.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        end = 19;
+        break;
+    case LENS:
+        base = lbase;
+        base -= 257;
+        extra = lext;
+        extra -= 257;
+        end = 256;
+        break;
+    default:            /* DISTS */
+        base = dbase;
+        extra = dext;
+        end = -1;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if ((type == LENS && used >= ENOUGH_LENS) ||
+        (type == DISTS && used >= ENOUGH_DISTS))
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        here.bits = (unsigned char)(len - drop);
+        if ((int)(work[sym]) < end) {
+            here.op = (unsigned char)0;
+            here.val = work[sym];
+        }
+        else if ((int)(work[sym]) > end) {
+            here.op = (unsigned char)(extra[work[sym]]);
+            here.val = base[work[sym]];
+        }
+        else {
+            here.op = (unsigned char)(32 + 64);         /* end of block */
+            here.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = here;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if ((type == LENS && used >= ENOUGH_LENS) ||
+                (type == DISTS && used >= ENOUGH_DISTS))
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /*
+       Fill in rest of table for incomplete codes.  This loop is similar to the
+       loop above in incrementing huff for table indices.  It is assumed that
+       len is equal to curr + drop, so there is no loop needed to increment
+       through high index bits.  When the current sub-table is filled, the loop
+       drops back to the root table to fill in any remaining entries there.
+     */
+    here.op = (unsigned char)64;                /* invalid code marker */
+    here.bits = (unsigned char)(len - drop);
+    here.val = (unsigned short)0;
+    while (huff != 0) {
+        /* when done with sub-table, drop back to root table */
+        if (drop != 0 && (huff & mask) != low) {
+            drop = 0;
+            len = root;
+            next = *table;
+            here.bits = (unsigned char)len;
+        }
+
+        /* put invalid code marker in table */
+        next[huff >> drop] = here;
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/zlib/inftrees.h b/zlib/inftrees.h
new file mode 100644 (file)
index 0000000..baa53a0
--- /dev/null
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table.  The maximum number of code structures is
+   1444, which is the sum of 852 for literal/length codes and 592 for distance
+   codes.  These values were found by exhaustive searches using the program
+   examples/enough.c found in the zlib distribtution.  The arguments to that
+   program are the number of symbols, the initial root table size, and the
+   maximum bit length of a code.  "enough 286 9 15" for literal/length codes
+   returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+   The initial root table size (9 or 6) is found in the fifth argument of the
+   inflate_table() calls in inflate.c and infback.c.  If the root table size is
+   changed, then these maximum sizes would be need to be recalculated and
+   updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
diff --git a/zlib/trees.c b/zlib/trees.c
new file mode 100644 (file)
index 0000000..56e9bb1
--- /dev/null
@@ -0,0 +1,1244 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2010 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local int  detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (ush)val << s->bi_valid;\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (ush)(value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header,
+        "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */
+#ifdef DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+#endif
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+        s->compressed_len += 10L;
+#endif
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (s->strm->data_type == Z_UNKNOWN)
+            s->strm->data_type = detect_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+last, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+last, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (last) {
+        bi_windup(s);
+#ifdef DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ *    a) There are no non-portable control characters belonging to the
+ *       "black list" (0..6, 14..25, 28..31).
+ *    b) There is at least one printable character belonging to the
+ *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ *   "gray list" that is ignored in this detection algorithm:
+ *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+    deflate_state *s;
+{
+    /* black_mask is the bit mask of black-listed bytes
+     * set bits 0..6, 14..25, and 28..31
+     * 0xf3ffc07f = binary 11110011111111111100000001111111
+     */
+    unsigned long black_mask = 0xf3ffc07fUL;
+    int n;
+
+    /* Check for non-textual ("black-listed") bytes. */
+    for (n = 0; n <= 31; n++, black_mask >>= 1)
+        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+            return Z_BINARY;
+
+    /* Check for textual ("white-listed") bytes. */
+    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+            || s->dyn_ltree[13].Freq != 0)
+        return Z_TEXT;
+    for (n = 32; n < LITERALS; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            return Z_TEXT;
+
+    /* There are no "black-listed" or "white-listed" bytes:
+     * this stream either is empty or has tolerated ("gray-listed") bytes only.
+     */
+    return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);
+        put_short(s, (ush)~len);
+#ifdef DEBUG
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG
+    s->bits_sent += (ulg)len<<3;
+#endif
+    while (len--) {
+        put_byte(s, *buf++);
+    }
+}
diff --git a/zlib/trees.h b/zlib/trees.h
new file mode 100644 (file)
index 0000000..d35639d
--- /dev/null
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
diff --git a/zlib/uncompr.c b/zlib/uncompr.c
new file mode 100644 (file)
index 0000000..ad98be3
--- /dev/null
@@ -0,0 +1,59 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    z_stream stream;
+    int err;
+
+    stream.next_in = (Bytef*)source;
+    stream.avail_in = (uInt)sourceLen;
+    /* Check for source > 64K on 16-bit machine: */
+    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+    stream.next_out = dest;
+    stream.avail_out = (uInt)*destLen;
+    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    err = inflate(&stream, Z_FINISH);
+    if (err != Z_STREAM_END) {
+        inflateEnd(&stream);
+        if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+            return Z_DATA_ERROR;
+        return err;
+    }
+    *destLen = stream.total_out;
+
+    err = inflateEnd(&stream);
+    return err;
+}
diff --git a/zlib/zconf.h.in b/zlib/zconf.h.in
new file mode 100644 (file)
index 0000000..a8b4521
--- /dev/null
@@ -0,0 +1,436 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/* The following four defines are enabled by sudo's configure script. */
+#undef HAVE_UNISTD_H
+#undef HAVE_VSNPRINTF
+#undef HAVE_MEMCPY
+#undef _FILE_OFFSET_BITS
+#undef _LARGE_FILES
+#undef const
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+
+/* all linked symbols */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  define gz_error              z_gz_error
+#  define gz_intmax             z_gz_intmax
+#  define gz_strwinerror        z_gz_strwinerror
+#  define gzbuffer              z_gzbuffer
+#  define gzclearerr            z_gzclearerr
+#  define gzclose               z_gzclose
+#  define gzclose_r             z_gzclose_r
+#  define gzclose_w             z_gzclose_w
+#  define gzdirect              z_gzdirect
+#  define gzdopen               z_gzdopen
+#  define gzeof                 z_gzeof
+#  define gzerror               z_gzerror
+#  define gzflush               z_gzflush
+#  define gzgetc                z_gzgetc
+#  define gzgets                z_gzgets
+#  define gzoffset              z_gzoffset
+#  define gzoffset64            z_gzoffset64
+#  define gzopen                z_gzopen
+#  define gzopen64              z_gzopen64
+#  define gzprintf              z_gzprintf
+#  define gzputc                z_gzputc
+#  define gzputs                z_gzputs
+#  define gzread                z_gzread
+#  define gzrewind              z_gzrewind
+#  define gzseek                z_gzseek
+#  define gzseek64              z_gzseek64
+#  define gzsetparams           z_gzsetparams
+#  define gztell                z_gztell
+#  define gztell64              z_gztell64
+#  define gzungetc              z_gzungetc
+#  define gzwrite               z_gzwrite
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  define uncompress            z_uncompress
+#  define zError                z_zError
+#  define zcalloc               z_zcalloc
+#  define zcfree                z_zcfree
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  define gzFile                z_gzFile
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef STDC
+#  include <sys/types.h>    /* for off_t */
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#  include <unistd.h>       /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>     /* for off_t */
+#  endif
+#  ifndef z_off_t
+#    define z_off_t off_t
+#  endif
+#endif
+
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+#  define z_off64_t off64_t
+#else
+#  define z_off64_t z_off_t
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/zlib/zlib.h b/zlib/zlib.h
new file mode 100644 (file)
index 0000000..bfbba83
--- /dev/null
@@ -0,0 +1,1613 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.5, April 19th, 2010
+
+  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
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.5"
+#define ZLIB_VERNUM 0x1250
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 5
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+    The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed data.
+  This version of the library supports only one compression method (deflation)
+  but other algorithms will be added later and will have the same stream
+  interface.
+
+    Compression can be done in a single step if the buffers are large enough,
+  or can be done by repeated calls of the compression function.  In the latter
+  case, the application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+    The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+    The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+    This library can optionally read and write gzip streams in memory as well.
+
+    The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+    The library does not install any signal handler.  The decoder checks
+  the consistency of the compressed data, so the library should never crash
+  even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+     The application must update next_in and avail_in when avail_in has dropped
+   to zero.  It must update next_out and avail_out when avail_out has dropped
+   to zero.  The application must initialize zalloc, zfree and opaque before
+   calling the init function.  All other fields are set by the compression
+   library and must not be updated by the application.
+
+     The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree.  This can be useful for custom
+   memory management.  The compression library attaches no meaning to the
+   opaque value.
+
+     zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+     On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this if
+   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
+   returned by zalloc for objects of exactly 65536 bytes *must* have their
+   offset normalized to zero.  The default allocation function provided by this
+   library ensures this (see zutil.c).  To reduce memory requirements and avoid
+   any allocation of 64K objects, at the expense of compression ratio, compile
+   the library with -DMAX_WBITS=14 (see zconf.h).
+
+     The fields total_in and total_out can be used for statistics or progress
+   reports.  After compression, total_in holds the total size of the
+   uncompressed data and may be saved for use in the decompressor (particularly
+   if the decompressor wants to decompress everything in a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+#define Z_TREES         6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at all
+   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
+   requests a default compromise between speed and compression (currently
+   equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if level is not a valid compression level, or
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
+   if there is no error message.  deflateInit does not perform any compression:
+   this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating avail_in or avail_out accordingly; avail_out should
+  never be zero before the call.  The application can consume the compressed
+  output when it wants, for example when the output buffer is full (avail_out
+  == 0), or after each call of deflate().  If deflate returns Z_OK and with
+  zero avail_out, it must be called again after making room in the output
+  buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumulate before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far.  (In
+  particular avail_in is zero after the call if enough output space has been
+  provided before the call.) Flushing may degrade compression for some
+  compression algorithms and so it should be used only when necessary.  This
+  completes the current deflate block and follows it with an empty stored block
+  that is three bits plus filler bits to the next byte, followed by four bytes
+  (00 00 ff ff).
+
+    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+  output buffer, but the output is not aligned to a byte boundary.  All of the
+  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+  This completes the current deflate block and follows it with an empty fixed
+  codes block that is 10 bits long.  This assures that enough bytes are output
+  in order for the decompressor to finish the block before the empty fixed code
+  block.
+
+    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+  seven bits of the current block are held to be written as the next byte after
+  the next deflate block is completed.  In this case, the decompressor may not
+  be provided enough bits at this point in order to complete decompression of
+  the data provided so far to the compressor.  It may need to wait for the next
+  block to be emitted.  This is for advanced applications that need to control
+  the emission of deflate blocks.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there was
+  enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error.  After
+  deflate has returned Z_STREAM_END, the only possible operations on the stream
+  are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, avail_out must be at least the
+  value returned by deflateBound (see below).  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
+  binary.  This field is only for information purposes and does not affect the
+  compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there is
+    no more input data or no more space in the output buffer (see below about
+    the flush parameter).
+
+    Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating the next_* and avail_* values accordingly.  The
+  application can consume the uncompressed output when it wants, for example
+  when the output buffer is full (avail_out == 0), or after each call of
+  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
+  called again after making room in the output buffer because there might be
+  more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer.  Z_BLOCK requests that inflate()
+  stop if and when it gets to the next deflate block boundary.  When decoding
+  the zlib or gzip format, this will cause inflate() to return immediately
+  after the header and before the first block.  When doing a raw inflate,
+  inflate() will go ahead and process the first block, and will return when it
+  gets to the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  inflate() is currently decoding the last block in the deflate stream, plus
+  128 if inflate() returned immediately after decoding an end-of-block code or
+  decoding the complete header up to just before the first byte of the deflate
+  stream.  The end-of-block will not be indicated until all of the uncompressed
+  data from that block has been written to strm->next_out.  The number of
+  unused bits may in general be greater than seven, except when bit 7 of
+  data_type is set, in which case the number of unused bits will be less than
+  eight.  data_type is set as noted here every time inflate() returns for all
+  flush options, and so can be used to determine the amount of currently
+  consumed input in bits.
+
+    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+  end of each deflate block header is reached, before any actual data in that
+  block is decoded.  This allows the caller to determine the length of the
+  deflate block header for later use in random access within a deflate block.
+  256 is added to the value of strm->data_type when inflate() returns
+  immediately after reaching the end of the deflate block header.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error.  However if all decompression is to be performed in a single step (a
+  single call of inflate), the parameter flush should be set to Z_FINISH.  In
+  this case all pending input is processed and all pending output is flushed;
+  avail_out must be large enough to hold all the uncompressed data.  (The size
+  of the uncompressed data may have been saved by the compressor for this
+  purpose.) The next operation on this stream must be inflateEnd to deallocate
+  the decompression state.  The use of Z_FINISH is never required, but can be
+  used to inform inflate that a faster approach may be used for the single
+  inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call.  So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK or Z_TREES is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below.  At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically, if requested when
+  initializing with inflateInit2().  Any information contained in the gzip
+  header is not retained, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing.  If Z_DATA_ERROR is returned, the application may
+  then call inflateSync() to look for a good compression block if a partial
+  recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, zalloc, zfree and opaque must be initialized before by the
+   caller.
+
+     The method parameter is the compression method.  It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library.  Larger values of this parameter result in better
+   compression at the expense of memory usage.  The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+   determines the window size.  deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding.  Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper.  The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero), no
+   header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state.  memLevel=1 uses minimum memory but is
+   slow and reduces compression ratio; memLevel=9 uses maximum memory for
+   optimal speed.  The default value is 8.  See zconf.h for total memory usage
+   as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm.  Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding).  Filtered data consists mostly of small values with a somewhat
+   random distribution.  In this case, the compression algorithm is tuned to
+   compress them better.  The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
+   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
+   strategy parameter only affects the compression ratio but not the
+   correctness of the compressed output even if it is not set appropriately.
+   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+   decoder for special applications.
+
+     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
+   set to null if there is no error message.  deflateInit2 does not perform any
+   compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any call
+   of deflate.  The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort).  deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is.  Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding.  Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
+   crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit2 does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit2() does not process any header information -- that is
+   deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+     Skips invalid compressed data until a full flush point (see above the
+   description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+   if no more input was provided, Z_DATA_ERROR if no flush point has been
+   found, or Z_STREAM_ERROR if the stream structure was inconsistent.  In the
+   success case, the application may save the current current value of total_in
+   which indicates where valid compressed data was found.  In the error case,
+   the application may repeatedly call inflateSync, providing more input each
+   time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.  The
+   stream will keep attributes that may have been set by inflateInit2.
+
+     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+                                      int windowBits));
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+   the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+   in the deflate stream (in which case strm->msg is set to indicate the nature
+   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+   In the case of Z_BUF_ERROR, an input or output error can be distinguished
+   using strm->next_in which will be Z_NULL only if in() returned an error.  If
+   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+   non-zero.  (in() will always be called before out(), so strm->next_in is
+   assured to be defined if out() returns non-zero.) Note that inflateBack()
+   cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data.  (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit, destLen
+   is the actual size of the uncompressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+                        /* gzip file access functions */
+
+/*
+     This library supports reading and writing files in gzip (.gz) format with
+   an interface similar to that of stdio, using the functions that start with
+   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
+   wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef voidp gzFile;       /* opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
+   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+   for fixed code compression as in "wb9F".  (See the description of
+   deflateInit2 for more information about the strategy parameter.) Also "a"
+   can be used instead of "w" to request that the gzip stream that will be
+   written be appended to the file.  "+" will result in an error, since reading
+   and writing to the same gzip file is not supported.
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened, if there was
+   insufficient memory to allocate the gzFile state, or if an invalid mode was
+   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+   errno can be checked to determine if the reason gzopen failed was that the
+   file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
+   are obtained from calls like open, dup, creat, pipe or fileno (if the file
+   has been previously opened with fopen).  The mode parameter is as in gzopen.
+
+     The next call of gzclose on the returned gzFile will also close the file
+   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+   mode);.  The duplicated descriptor should be saved to avoid a leak, since
+   gzdopen does not close fd if it fails.
+
+     gzdopen returns NULL if there was insufficient memory to allocate the
+   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
+   used until the next gz* read, write, seek, or close operation, so gzdopen
+   will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+     Set the internal buffer size used by this library's functions.  The
+   default buffer size is 8192 bytes.  This function must be called after
+   gzopen() or gzdopen(), and before any other calls that read or write the
+   file.  The buffer memory allocation is always deferred to the first read or
+   write.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  A larger buffer size of, for example, 64K or 128K bytes will
+   noticeably increase the speed of decompression (reading).
+
+     The new buffer size also affects the maximum length for gzprintf().
+
+     gzbuffer() returns 0 on success, or -1 on failure, such as being called
+   too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  If
+   the input file was not in gzip format, gzread copies the given number of
+   bytes into the buffer.
+
+     After reaching the end of a gzip stream in the input, gzread will continue
+   to read, looking for another gzip stream, or failing that, reading the rest
+   of the input file directly without decompression.  The entire input file
+   will be read if gzread is called until it returns less than the requested
+   len.
+
+     gzread returns the number of uncompressed bytes actually read, less than
+   len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+                                voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 in case of error.  The number of
+   uncompressed bytes written is limited to 8191, or one less than the buffer
+   size given to gzbuffer().  The caller should assure that this limit is not
+   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
+   nothing written.  In this case, there may also be a buffer overflow with
+   unpredictable consequences, which is possible only if zlib was compiled with
+   the insecure functions sprintf() or vsprintf() because the secure snprintf()
+   or vsnprintf() functions were not available.  This can be determined using
+   zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or a
+   newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  If any characters are read or if len == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, then the buffer is left untouched.
+
+     gzgets returns buf which is a null-terminated string, or it returns NULL
+   for end-of-file or in case of error.  If there was an error, the contents at
+   buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+   in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is allowed.
+   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
+   fail if c is -1, and may fail if a character has been pushed but not read
+   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
+   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
+   The pushed character will be discarded if the stream is repositioned with
+   gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file.  The parameter flush
+   is as in the deflate() function.  The return value is the zlib error number
+   (see function gzerror below).  gzflush is only permitted when writing.
+
+     If the flush parameter is Z_FINISH, the remaining data is written and the
+   gzip stream is completed in the output.  If gzwrite() is called again, a new
+   gzip stream will be started in the output.  gzread() is able to read such
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+                                   z_off_t offset, int whence));
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed file.  The offset represents a number of bytes in the
+   uncompressed data stream.  The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow.  If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+     gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed file.  This position represents a number of bytes in the
+   uncompressed data stream, and is zero when starting, even if appending or
+   reading a gzip stream from the middle of a file using gzdopen().
+
+     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+     Returns the current offset in the file being read or written.  This offset
+   includes the count of bytes that precede the gzip stream, for example when
+   appending or when using gzdopen() for reading.  When reading, the offset
+   does not include as yet unused buffered input.  This information can be used
+   for a progress indicator.  On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns true (1) if the end-of-file indicator has been set while reading,
+   false (0) otherwise.  Note that the end-of-file indicator is set only if the
+   read tried to go past the end of the input, but came up short.  Therefore,
+   just like feof(), gzeof() may return false even if there is no more data to
+   read, in the event that the last read request was for the exact number of
+   bytes remaining in the input file.  This will happen if the input file size
+   is an exact multiple of the buffer size.
+
+     If gzeof() returns true, then the read functions will return no more data,
+   unless the end-of-file indicator is reset by gzclearerr() and the input file
+   has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns true (1) if file is being copied directly while reading, or false
+   (0) if file is a gzip stream being decompressed.  This state can change from
+   false to true while reading the input file if the end of a gzip stream is
+   reached, but is followed by data that is not another gzip stream.
+
+     If the input file is empty, gzdirect() will return true, since the input
+   does not contain a gzip stream.
+
+     If gzdirect() is used immediately after gzopen() or gzdopen() it will
+   cause buffers to be allocated to allow reading the file to determine if it
+   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
+   gzdirect().
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates the (de)compression state.  Note that once file is closed, you
+   cannot call gzerror with file, since its structures have been deallocated.
+   gzclose must not be called more than once on the same file, just as free
+   must not be called more than once on the same allocation.
+
+     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+   file operation error, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed file.  errnum is set to zlib error number.  If an error occurred
+   in the file system and not in the compression library, errnum is set to
+   Z_ERRNO and the application may consult errno to get the exact error code.
+
+     The application must not modify the returned string.  Future calls to
+   this function may invalidate the previously returned string.  If file is
+   closed, then the string previously returned by gzerror will no longer be
+   available.
+
+     gzerror() should be used to distinguish errors from end-of-file for those
+   functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file.  This is analogous to the
+   clearerr() function in stdio.  This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the compression
+   library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  If buf is Z_NULL, this function returns the
+   required initial value for the checksum.
+
+     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster.
+
+   Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  If buf is Z_NULL, this function returns the required
+   initial value for the for the crc.  Pre- and post-conditioning (one's
+   complement) is performed within this function so it shouldn't be done by the
+   application.
+
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+                                            ZLIB_VERSION, sizeof(z_stream))
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0
+#  define gzopen gzopen64
+#  define gzseek gzseek64
+#  define gztell gztell64
+#  define gzoffset gzoffset64
+#  define adler32_combine adler32_combine64
+#  define crc32_combine crc32_combine64
+#  ifdef _LARGEFILE64_SOURCE
+     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#  endif
+#else
+   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/zlib/zutil.c b/zlib/zutil.c
new file mode 100644 (file)
index 0000000..898ed34
--- /dev/null
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch ((int)(sizeof(uInt))) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch ((int)(sizeof(uLong))) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch ((int)(sizeof(voidpf))) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch ((int)(sizeof(z_off_t))) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#ifdef STDC
+#  ifdef NO_vsnprintf
+        flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#else
+        flags += 1L << 24;
+#  ifdef NO_snprintf
+        flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+        flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+        flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+
+#ifdef DEBUG
+
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/zlib/zutil.h b/zlib/zutil.h
new file mode 100644 (file)
index 0000000..258fa88
--- /dev/null
@@ -0,0 +1,274 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)
+#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+#  define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#ifdef STDC
+#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#      include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#  ifdef M_I86
+#    include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#ifdef WIN32
+#  ifndef __CYGWIN__  /* Cygwin is Unix, not Win32 */
+#    define OS_CODE  0x0b
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+#if defined(__BORLANDC__)
+  #pragma warn -8004
+  #pragma warn -8008
+  #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
+    ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+    ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#if defined(__CYGWIN__)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+#ifndef HAVE_VSNPRINTF
+#  ifdef MSDOS
+     /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+        but for now we just assume it doesn't. */
+#    define NO_vsnprintf
+#  endif
+#  ifdef __TURBOC__
+#    define NO_vsnprintf
+#  endif
+#  ifdef WIN32
+     /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
+#      if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
+#         define vsnprintf _vsnprintf
+#      endif
+#    endif
+#  endif
+#  ifdef __SASC
+#    define NO_vsnprintf
+#  endif
+#endif
+#ifdef VMS
+#  define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+   int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+   void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int ZLIB_INTERNAL z_verbose;
+   extern void ZLIB_INTERNAL z_error OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+                        unsigned size));
+void ZLIB_INTERNAL zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */