From f3530d8198251b72d01da9a07b1fa518446ec0f0 Mon Sep 17 00:00:00 2001 From: Bdale Garbee Date: Tue, 26 Apr 2011 13:58:18 -0600 Subject: [PATCH] Imported Upstream version 1.7.6p1 --- ChangeLog | 1919 +++++++++++++++++++++++----- INSTALL | 45 +- LICENSE | 29 +- Makefile.in | 158 ++- NEWS | 121 ++ README | 4 +- README.LDAP | 5 + TROUBLESHOOTING | 8 + UPGRADE | 51 + aclocal.m4 | 54 +- aix.c | 10 +- alias.c | 19 +- alloc.c | 30 +- audit.c | 2 +- auth/afs.c | 12 +- auth/aix_auth.c | 4 +- auth/bsdauth.c | 16 +- auth/dce.c | 28 +- auth/fwtk.c | 20 +- auth/kerb4.c | 14 +- auth/kerb5.c | 20 +- auth/pam.c | 40 +- auth/passwd.c | 40 +- auth/rfc1938.c | 10 +- auth/secureware.c | 40 +- auth/securid.c | 12 +- auth/securid5.c | 18 +- auth/sia.c | 10 +- auth/sudo_auth.c | 4 +- auth/sudo_auth.h | 2 + boottime.c | 10 +- bsm_audit.c | 5 +- check.c | 70 +- closefrom.c | 4 +- compat.h | 312 ----- config.h.in | 27 +- configure | 527 ++++++-- configure.in | 170 ++- def_data.c | 4 + def_data.h | 2 + def_data.in | 3 + defaults.c | 108 +- env.c | 51 +- error.c | 7 +- exec.c | 399 ++++-- exec_pty.c | 151 +-- fileops.c | 20 +- find_path.c | 12 +- fnmatch.c | 50 +- get_pty.c | 35 +- getcwd.c | 10 +- getdate.c | 3 +- getdate.y | 2 +- getline.c | 6 +- getprogname.c | 9 +- getspwuid.c | 34 +- gettime.c | 4 +- glob.c | 90 +- goodpath.c | 8 +- gram.c | 10 +- gram.y | 5 +- iolog.c | 28 +- isblank.c | 7 +- lbuf.c | 42 +- ldap.c | 1092 +++++++++++----- linux_audit.c | 3 +- list.c | 32 +- list.h | 1 + logging.c | 62 +- match.c | 203 +-- memrchr.c | 10 +- missing.h | 306 ++++- mkpkg | 88 +- mksiglist.c | 6 +- mkstemps.c | 10 +- nanosleep.c | 6 +- parse.c | 43 +- parse_args.c | 122 +- pp | 418 ++++-- pwutil.c | 525 +++++--- redblack.c | 26 +- schema.ActiveDirectory | 60 + schema.OpenLDAP | 23 +- schema.iPlanet | 5 +- sesh.c | 2 +- set_perms.c | 24 +- setsid.c | 2 +- sigaction.c | 30 +- snprintf.c | 40 +- strcasecmp.c | 6 +- strerror.c | 11 +- strlcat.c | 10 +- strlcpy.c | 7 +- strsignal.c | 11 +- sudo.c | 170 +-- sudo.cat | 24 +- sudo.h | 12 +- sudo.man.in | 7 +- sudo.pod | 3 +- sudo.pp | 39 +- sudo_exec.h | 11 +- sudo_noexec.c | 6 +- sudo_nss.c | 66 +- sudo_usage.h.in | 3 +- sudoers.cat | 636 ++++----- sudoers.ldap.cat | 364 ++++-- sudoers.ldap.man.in | 138 +- sudoers.ldap.pod | 141 +- sudoers.man.in | 198 +-- sudoers.pod | 192 +-- sudoers2ldif | 9 +- sudoreplay.c | 75 +- sudoreplay.cat | 58 +- sudoreplay.man.in | 16 +- sudoreplay.pod | 11 +- term.c | 48 +- testsudoers.c | 106 +- tgetpass.c | 41 +- timestr.c | 6 +- toke.c | 2762 +++++++++++++++++++--------------------- toke.h | 30 + toke.l | 485 +++---- toke_util.c | 251 ++++ tsgetgrpw.c | 59 +- utimes.c | 12 +- vasgroups.c | 6 +- visudo.c | 116 +- visudo.cat | 38 +- visudo.man.in | 12 +- visudo.pod | 9 +- zero_bytes.c | 5 +- zlib/adler32.c | 169 +++ zlib/compress.c | 80 ++ zlib/crc32.c | 442 +++++++ zlib/crc32.h | 441 +++++++ zlib/deflate.c | 1834 ++++++++++++++++++++++++++ zlib/deflate.h | 342 +++++ zlib/gzclose.c | 25 + zlib/gzguts.h | 132 ++ zlib/gzlib.c | 537 ++++++++ zlib/gzread.c | 653 ++++++++++ zlib/gzwrite.c | 531 ++++++++ zlib/infback.c | 632 +++++++++ zlib/inffast.c | 340 +++++ zlib/inffast.h | 11 + zlib/inffixed.h | 94 ++ zlib/inflate.c | 1480 +++++++++++++++++++++ zlib/inflate.h | 122 ++ zlib/inftrees.c | 330 +++++ zlib/inftrees.h | 62 + zlib/trees.c | 1244 ++++++++++++++++++ zlib/trees.h | 128 ++ zlib/uncompr.c | 59 + zlib/zconf.h.in | 436 +++++++ zlib/zlib.h | 1613 +++++++++++++++++++++++ zlib/zutil.c | 318 +++++ zlib/zutil.h | 274 ++++ 157 files changed, 21581 insertions(+), 5067 deletions(-) delete mode 100644 compat.h mode change 100644 => 100755 sudoers2ldif create mode 100644 toke.h create mode 100644 toke_util.c create mode 100644 zlib/adler32.c create mode 100644 zlib/compress.c create mode 100644 zlib/crc32.c create mode 100644 zlib/crc32.h create mode 100644 zlib/deflate.c create mode 100644 zlib/deflate.h create mode 100644 zlib/gzclose.c create mode 100644 zlib/gzguts.h create mode 100644 zlib/gzlib.c create mode 100644 zlib/gzread.c create mode 100644 zlib/gzwrite.c create mode 100644 zlib/infback.c create mode 100644 zlib/inffast.c create mode 100644 zlib/inffast.h create mode 100644 zlib/inffixed.h create mode 100644 zlib/inflate.c create mode 100644 zlib/inflate.h create mode 100644 zlib/inftrees.c create mode 100644 zlib/inftrees.h create mode 100644 zlib/trees.c create mode 100644 zlib/trees.h create mode 100644 zlib/uncompr.c create mode 100644 zlib/zconf.h.in create mode 100644 zlib/zlib.h create mode 100644 zlib/zutil.c create mode 100644 zlib/zutil.h diff --git a/ChangeLog b/ChangeLog index b0e2b30..5efe57d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,79 +1,1187 @@ +2011-04-14 Todd C. Miller + + * 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 + + * 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 + + * .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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * aclocal.m4: + Quote first argument to AC_DEFUN(); from Elan Ruusamae + [a245e4891bab] <1.7> + +2011-03-27 Todd C. Miller + + * 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 + + * testsudoers.c: + Fix printing "User_Alias FOO = ALL" + [8e6e810e89ce] <1.7> + +2011-03-22 Todd C. Miller + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * mkpkg: + Fix default setting of osversion variable. + [c67d9d3bfa2b] <1.7> + +2011-03-07 Todd C. Miller + + * 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 + + * sudo.pp: + Don't use the beta or release candidate version as the rpm release. + [56f8c0b1eb46] <1.7> + +2011-02-25 Todd C. Miller + + * .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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * alias.c: + Remove unneeded variable. + [23329353f964] <1.7> + +2011-02-09 Todd C. Miller + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * sudoers2ldif: + Add sudoOrder attribute to each entry Parse LOG_{INPUT,OUTPUT} tags + [05a0d25b0f8d] <1.7> + +2011-01-30 Todd C. Miller + + * UPGRADE: + Mention LDAP attribute compatibility status. + [adb74ad2331b] <1.7> + +2011-01-28 Todd C. Miller + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * NEWS: + sync + [deb822cce3dd] <1.7> + 2011-01-18 Todd C. Miller * 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 + + * sudo.c: + delref list_pw before exit + [0df5a53f3484] <1.7> + +2011-01-14 Todd C. Miller + + * 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 + + * sudoers.cat, sudoers.man.in, sudoers.pod: + fix typo + [075e92a756a1] <1.7> + +2011-01-12 Todd C. Miller + + * 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 + * 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 + * 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 + * 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 * 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 + + * ldap.c, sudoers.ldap.pod: + Pick last match in LDAP sudoers too + [607801b83e25] <1.7> + +2010-12-10 Todd C. Miller + + * 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 + + * 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 + + * 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 * 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 * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Makefile.in: + Include zlib in the tar file. + [3b7900c3f2af] <1.7> + +2010-10-28 Todd C. Miller + + * 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 + + * 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 + + * 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 + * 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 + + * exec_pty.c, lbuf.c: + Prefer newer TIOCGWINSZ ioctl to old TIOCGSIZE + [0813e3030b1a] <1.7> 2010-10-01 Todd C. Miller * 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 + + * env.c: + Preserve ODMDIR environment variable by default on AIX. + [75266d18e4a7] <1.7> 2010-09-21 Todd C. Miller * 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 + + * pp: + Sync with git version + [9a328aa25c53] <1.7> + +2010-09-16 Todd C. Miller + + * defaults.c, fileops.c: + Cast isblank argument to unsigned char. + [64b9f3bed954] <1.7> + +2010-09-14 Todd C. Miller + + * 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 @@ -81,27 +1189,104 @@ 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 + + * 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 + + * 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 + + * 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 * 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 * 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 @@ -110,31 +1295,42 @@ 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 * 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 * 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 + * 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 @@ -143,54 +1339,74 @@ 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 * 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 + * 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 * lbuf.c: Convert a remaining puts() and putchar() to use the output function. - [d68c213feb0f] + [d68c213feb0f] <1.7> 2010-08-18 Todd C. Miller * 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 * boottime.c, get_pty.c: Fix typos that prevented compilation on Irix; Friedrich Haubensak - [a3e6c5a66890] + [a3e6c5a66890] <1.7> + +2010-08-16 Todd C. Miller + + * 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 @@ -199,159 +1415,230 @@ 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 * 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 * 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 * 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 + + * 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 + * 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 * 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 + * 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 * 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 * .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 * 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 * 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 * 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 @@ -360,442 +1647,442 @@ 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 * 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 * sudoers: Add commented out Defaults entry for log_output - [b3fe97e59ae0] + [b3fe97e59ae0] <1.7> 2010-07-23 Todd C. Miller * 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 * 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 * 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 * 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 * 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 * pp: decode debian code names - [2df0ecbc23b4] + [2df0ecbc23b4] <1.7> * WHATSNEW: fix typo - [b66a95fa1869] + [b66a95fa1869] <1.7> 2010-07-16 Todd C. Miller * 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 * 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 * 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 * 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 * 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 * 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 * 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 * env.c, sudoreplay.c: Fix K&R compilation - [e44d3be7ab85] + [e44d3be7ab85] <1.7> 2010-07-09 Todd C. Miller @@ -803,18 +2090,18 @@ 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 @@ -823,32 +2110,32 @@ 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 * 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 * sudoers.ldap.pod: fix typo. - [d5f2922cecf2] + [d5f2922cecf2] <1.7> 2010-06-29 Todd C. Miller * .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, @@ -863,32 +2150,32 @@ 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 * 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 * 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 @@ -896,324 +2183,324 @@ 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 * 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 * 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 * HISTORY, history.pod: Mention when LDAP was incorporated. - [4e6c8ec4f67c] + [4e6c8ec4f67c] <1.7> 2010-06-21 Todd C. Miller * 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 * 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 * 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 * Makefile.in, linux_audit.c, linux_audit.h: Add Linux audit support. - [b207dc9960de] + [b207dc9960de] <1.7> 2010-06-16 Todd C. Miller * 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 * 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 * 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, @@ -1223,206 +2510,206 @@ 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 @@ -1432,32 +2719,32 @@ 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, @@ -1468,67 +2755,67 @@ 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 * 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 @@ -1537,11 +2824,11 @@ 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 @@ -1549,29 +2836,29 @@ 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 @@ -1579,20 +2866,20 @@ 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 * 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 * alias.c: Fix use after free in error message when a duplicate alias exists. - [9eaac49bd22b] + [9eaac49bd22b] <1.7> 2010-04-14 Todd C. Miller @@ -1600,13 +2887,13 @@ 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 * TODO, sudoers.cat, sudoers.man.in, sudoers.pod: Fix typo - [57198cae9cf5] + [57198cae9cf5] <1.7> 2010-04-09 Todd C. Miller @@ -1615,31 +2902,31 @@ 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 * 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 * 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 * 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 @@ -1647,12 +2934,12 @@ 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 @@ -1660,42 +2947,42 @@ 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 * 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 * 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 * 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 * Makefile.in: Generate correct ChangeLog for 1.7 branch. - [586dd90b8878] + [586dd90b8878] <1.7> 2010-01-17 Todd C. Miller diff --git a/INSTALL b/INSTALL index 8d92b4c..d9568d3 100644 --- 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 6e9a547..2af4e0f 100644 --- 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 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 diff --git a/Makefile.in b/Makefile.in index 0114ca7..b16338b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,5 @@ # -# Copyright (c) 1996, 1998-2005, 2007-2010 +# Copyright (c) 1996, 1998-2005, 2007-2011 # Todd C. Miller # # 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 " > $(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 " > $(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 " > $(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 71be281..87bac52 100644 --- 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 4f6f454..387734f 100644 --- 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 diff --git a/README.LDAP b/README.LDAP index 5b7f6d8..84ac231 100644 --- a/README.LDAP +++ b/README.LDAP @@ -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. diff --git a/TROUBLESHOOTING b/TROUBLESHOOTING index 57e2012..9ed1817 100644 --- a/TROUBLESHOOTING +++ b/TROUBLESHOOTING @@ -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 fb27119..8b7da22 100644 --- 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 diff --git a/aclocal.m4 b/aclocal.m4 index 1276746..255b91f 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -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 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 -int main() {char *p = _PATH_MAILDIR;}], [])], [maildir=yes], []) +#include ], +[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 5735ec9..873896e 100644 --- a/aix.c +++ b/aix.c @@ -31,7 +31,7 @@ #include #include -#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 b1f57e7..238830c 100644 --- 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 8e6a7e2..535465c 100644 --- 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 +# endif # include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H @@ -45,7 +48,9 @@ # include #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 9226d30..15ac8ee 100644 --- a/audit.c +++ b/audit.c @@ -32,7 +32,7 @@ # include #endif -#include "compat.h" +#include "missing.h" #include "logging.h" #ifdef HAVE_BSM_AUDIT diff --git a/auth/afs.c b/auth/afs.c index 2b9d7b9..393605a 100644 --- a/auth/afs.c +++ b/auth/afs.c @@ -43,12 +43,12 @@ #endif /* HAVE_UNISTD_H */ #include -#include "sudo.h" -#include "sudo_auth.h" - #include #include +#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; } diff --git a/auth/aix_auth.c b/auth/aix_auth.c index 7a776be..fe65b0b 100644 --- a/auth/aix_auth.c +++ b/auth/aix_auth.c @@ -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; } diff --git a/auth/bsdauth.c b/auth/bsdauth.c index 2539713..727df13 100644 --- a/auth/bsdauth.c +++ b/auth/bsdauth.c @@ -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; } diff --git a/auth/dce.c b/auth/dce.c index 76b43b3..3333a72 100644 --- a/auth/dce.c +++ b/auth/dce.c @@ -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; } diff --git a/auth/fwtk.c b/auth/fwtk.c index fba99e8..f1c164e 100644 --- a/auth/fwtk.c +++ b/auth/fwtk.c @@ -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; } diff --git a/auth/kerb4.c b/auth/kerb4.c index f3107a0..883035d 100644 --- a/auth/kerb4.c +++ b/auth/kerb4.c @@ -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; } diff --git a/auth/kerb5.c b/auth/kerb5.c index 230898f..4ce04aa 100644 --- a/auth/kerb5.c +++ b/auth/kerb5.c @@ -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 diff --git a/auth/pam.c b/auth/pam.c index ca2ef10..265de36 100644 --- a/auth/pam.c +++ b/auth/pam.c @@ -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; } diff --git a/auth/passwd.c b/auth/passwd.c index 4f9efb8..8835c03 100644 --- a/auth/passwd.c +++ b/auth/passwd.c @@ -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; } diff --git a/auth/rfc1938.c b/auth/rfc1938.c index 3bc39c3..b0640e5 100644 --- a/auth/rfc1938.c +++ b/auth/rfc1938.c @@ -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; } diff --git a/auth/secureware.c b/auth/secureware.c index e7148d3..c1c43d0 100644 --- a/auth/secureware.c +++ b/auth/secureware.c @@ -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; } diff --git a/auth/securid.c b/auth/securid.c index 6aec109..83ff94c 100644 --- a/auth/securid.c +++ b/auth/securid.c @@ -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; } diff --git a/auth/securid5.c b/auth/securid5.c index ef9e228..6880c1a 100644 --- a/auth/securid5.c +++ b/auth/securid5.c @@ -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; } diff --git a/auth/sia.c b/auth/sia.c index 188676a..6c972c6 100644 --- a/auth/sia.c +++ b/auth/sia.c @@ -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; } diff --git a/auth/sudo_auth.c b/auth/sudo_auth.c index 69b0a3a..42455ee 100644 --- a/auth/sudo_auth.c +++ b/auth/sudo_auth.c @@ -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) diff --git a/auth/sudo_auth.h b/auth/sudo_auth.h index a4efe14..5024955 100644 --- a/auth/sudo_auth.h +++ b/auth/sudo_auth.h @@ -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)); diff --git a/boottime.c b/boottime.c index f75af3e..bdcd1f2 100644 --- a/boottime.c +++ b/boottime.c @@ -42,12 +42,16 @@ #if TIME_WITH_SYS_TIME # include #endif - +#ifdef HAVE_GETUTXID +# include +#endif +#ifdef HAVE_GETUTID +# include +#endif #ifdef HAVE_SYSCTL # include #endif -#include "compat.h" #include "missing.h" /* @@ -102,7 +106,6 @@ get_boottime(tv) #elif defined(HAVE_GETUTXID) -#include int get_boottime(tv) struct timeval *tv; @@ -121,7 +124,6 @@ get_boottime(tv) #elif defined(HAVE_GETUTID) -#include int get_boottime(tv) struct timeval *tv; diff --git a/bsm_audit.c b/bsm_audit.c index a673d28..94ed4a8 100644 --- a/bsm_audit.c +++ b/bsm_audit.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2009-2010 Todd C. Miller * 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 badf3e4..df44bfc 100644 --- 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 * * 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; +} diff --git a/closefrom.c b/closefrom.c index fb9958e..68da392 100644 --- a/closefrom.c +++ b/closefrom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005, 2007 + * Copyright (c) 2004-2005, 2007, 2010 * Todd C. Miller * * 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 index c01924d..0000000 --- a/compat.h +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2008-2010 - * Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 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 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 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 */ diff --git a/config.h.in b/config.h.in index af5653b..a4b000d 100644 --- a/config.h.in +++ b/config.h.in @@ -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 @@ -280,6 +283,9 @@ /* 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 @@ -355,6 +361,9 @@ /* Define to 1 if you have the 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 @@ -537,6 +546,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STROPTS_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSMACROS_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H @@ -574,9 +586,6 @@ /* 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 @@ -729,7 +738,7 @@ /* 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. */ @@ -741,6 +750,10 @@ /* 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 @@ -761,6 +774,12 @@ /* 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 diff --git a/configure b/configure index f7c4838..4ac04df 100755 --- 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 . # @@ -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 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" @@ -14033,6 +14095,261 @@ fi 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 + /* 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 + /* 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 + /* 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 + /* 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 + /* 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 +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 +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 -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 <&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 + + diff --git a/configure.in b/configure.in index 04ae074..29d7f28 100644 --- a/configure.in +++ b/configure.in @@ -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 +dnl Copyright (c) 1994-1996,1998-2011 Todd C. Miller 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 ]], [[int i = AUDIT_USER_CMD; (void)i;]])], [ + yes) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[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 ], [])], [sudo_cv_xopen_source_extended=no], [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#define _XOPEN_SOURCE_EXTENDED + AC_INCLUDES_DEFAULT + #include ], [])], [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 ]) - 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.]) diff --git a/def_data.c b/def_data.c index fbdc0c7..c63d595 100644 --- a/def_data.c +++ b/def_data.c @@ -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 } diff --git a/def_data.h b/def_data.h index e868d32..0996ec8 100644 --- a/def_data.h +++ b/def_data.h @@ -152,6 +152,8 @@ #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, diff --git a/def_data.in b/def_data.in index d903cfa..4a7ae96 100644 --- a/def_data.in +++ b/def_data.in @@ -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" diff --git a/defaults.c b/defaults.c index 10757ee..c1f0afa 100644 --- a/defaults.c +++ b/defaults.c @@ -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 739631f..654565e 100644 --- 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 317f105..e5cb959 100644 --- a/error.c +++ b/error.c @@ -14,13 +14,16 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + +#include + #include #include #include #include -#include -#include +#include "missing.h" #include "error.h" static void _warning __P((int, const char *, va_list)); diff --git a/exec.c b/exec.c index 784f90a..19dbad2 100644 --- a/exec.c +++ b/exec.c @@ -18,6 +18,9 @@ #include #include +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif #include #include #include @@ -65,9 +68,24 @@ #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; } diff --git a/exec_pty.c b/exec_pty.c index 2d6b0e8..ec54a1f 100644 --- a/exec_pty.c +++ b/exec_pty.c @@ -18,6 +18,9 @@ #include #include +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif #include #include #include @@ -72,11 +75,10 @@ #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); } diff --git a/fileops.c b/fileops.c index ca4903f..ae9a7df 100644 --- a/fileops.c +++ b/fileops.c @@ -44,7 +44,7 @@ # include #endif #ifndef HAVE_TIMESPEC -# include +# 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; } diff --git a/find_path.c b/find_path.c index 78c96ea..fb7fb5f 100644 --- a/find_path.c +++ b/find_path.c @@ -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; } diff --git a/fnmatch.c b/fnmatch.c index 2255e52..723e53d 100644 --- a/fnmatch.c +++ b/fnmatch.c @@ -38,6 +38,8 @@ #include +#include + #include #include #ifdef HAVE_STRING_H @@ -47,7 +49,7 @@ # include #endif /* HAVE_STRINGS_H */ -#include +#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; } diff --git a/get_pty.c b/get_pty.c index 7b35108..8549794 100644 --- 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 */ diff --git a/getcwd.c b/getcwd.c index 109794a..1260ad4 100644 --- a/getcwd.c +++ b/getcwd.c @@ -71,7 +71,7 @@ # endif #endif -#include +#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; } diff --git a/getdate.c b/getdate.c index 928246b..7544c3f 100644 --- a/getdate.c +++ b/getdate.c @@ -1,3 +1,4 @@ +#include #include #include #define YYBYACC 1 @@ -50,7 +51,7 @@ #endif #include -#include "compat.h" +#include "missing.h" #define EPOCH 1970 diff --git a/getdate.y b/getdate.y index 2b2e3c9..7094083 100644 --- a/getdate.y +++ b/getdate.y @@ -39,7 +39,7 @@ #endif #include -#include "compat.h" +#include "missing.h" #define EPOCH 1970 diff --git a/getline.c b/getline.c index b7db379..2b3d324 100644 --- a/getline.c +++ b/getline.c @@ -35,7 +35,7 @@ #endif /* HAVE_STRINGS_H */ #include -#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 diff --git a/getprogname.c b/getprogname.c index f269405..0790222 100644 --- a/getprogname.c +++ b/getprogname.c @@ -18,11 +18,14 @@ * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ +#include + +#include + #include #include -#include -#include +#include "missing.h" const char * getprogname() @@ -39,5 +42,5 @@ getprogname() else progname = Argv[0]; } - return(progname); + return progname; } diff --git a/getspwuid.c b/getspwuid.c index 7ee5eba..7a7ffb8 100644 --- a/getspwuid.c +++ b/getspwuid.c @@ -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 diff --git a/gettime.c b/gettime.c index 9a13003..6cb15d7 100644 --- a/gettime.c +++ b/gettime.c @@ -24,7 +24,7 @@ # include #endif -#include +#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 9673626..66dcadc 100644 --- a/glob.c +++ b/glob.c @@ -95,7 +95,7 @@ #include #include -#include +#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 diff --git a/goodpath.c b/goodpath.c index 1971314..45066d3 100644 --- a/goodpath.c +++ b/goodpath.c @@ -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 d2e8b46..ed7e21b 100644 --- a/gram.c +++ b/gram.c @@ -1,3 +1,4 @@ +#include #include #include #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 f319eea..9a07ee7 100644 --- 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 4e492b6..131770e 100644 --- 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) diff --git a/isblank.c b/isblank.c index e6ad58d..a7f01e2 100644 --- a/isblank.c +++ b/isblank.c @@ -15,12 +15,15 @@ */ #include -#include + +#include + +#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 bd218da..bafea18 100644 --- a/lbuf.c +++ b/lbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2010 Todd C. Miller + * Copyright (c) 2007-2011 Todd C. Miller * * 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 +# endif # include #endif /* HAVE_STRING_H */ #ifdef HAVE_STRINGS_H @@ -51,10 +54,11 @@ #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 81d3c40..3097af7 100644 --- a/ldap.c +++ b/ldap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Todd C. Miller + * Copyright (c) 2003-2011 Todd C. Miller * * This code is derived from software contributed by Aaron Spangler. * @@ -37,12 +37,12 @@ #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif #include #include #include @@ -97,8 +97,13 @@ #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) \ @@ -116,6 +121,53 @@ #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 diff --git a/linux_audit.c b/linux_audit.c index b4160c9..16e21af 100644 --- a/linux_audit.c +++ b/linux_audit.c @@ -31,10 +31,9 @@ #include #include -#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 60c1138..2fb4967 100644 --- 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 17aab41..719afa2 100644 --- 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 *)); diff --git a/logging.c b/logging.c index 2b32968..d0aeab9 100644 --- a/logging.c +++ b/logging.c @@ -47,6 +47,12 @@ #ifdef HAVE_UNISTD_H # include #endif /* HAVE_UNISTD_H */ +#ifdef HAVE_SETLOCALE +# include +#endif /* HAVE_SETLOCALE */ +#ifdef HAVE_NL_LANGINFO +# include +#endif /* HAVE_NL_LANGINFO */ #include #include #include @@ -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 6431425..ba299e1 100644 --- 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 * * 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; } diff --git a/memrchr.c b/memrchr.c index 35e07de..425fcb4 100644 --- a/memrchr.c +++ b/memrchr.c @@ -14,9 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include -#include + +#include + +#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; } diff --git a/missing.h b/missing.h index 749323a..7b2d29d 100644 --- a/missing.h +++ b/missing.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2009-2010 Todd C. Miller + * Copyright (c) 1996, 1998-2005, 2008-2010 + * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -12,17 +13,320 @@ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 #ifdef __STDC__ # include #else # include #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 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 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 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 ae41356..12c1d84 100755 --- 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 diff --git a/mksiglist.c b/mksiglist.c index 09b1414..f5cfbc1 100644 --- a/mksiglist.c +++ b/mksiglist.c @@ -17,6 +17,8 @@ #include +#include + #include #ifdef STDC_HEADERS # include @@ -28,7 +30,7 @@ #endif /* STDC_HEADERS */ #include -#include +#include "missing.h" int main(argc, argv) @@ -42,7 +44,7 @@ main(argc, argv) printf("#include \n"); printf("#include \n"); - printf("#include \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) { diff --git a/mkstemps.c b/mkstemps.c index 7245f19..b3b688d 100644 --- a/mkstemps.c +++ b/mkstemps.c @@ -15,7 +15,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "config.h" +#include #include #include @@ -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; } diff --git a/nanosleep.c b/nanosleep.c index ae2208b..1849eb2 100644 --- a/nanosleep.c +++ b/nanosleep.c @@ -25,11 +25,11 @@ # include #endif #ifndef HAVE_TIMESPEC -# include +# include "emul/timespec.h" #endif #include -#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 97aba79..acf8e5f 100644 --- 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; } /* diff --git a/parse_args.c b/parse_args.c index 3611b44..ee4245b 100644 --- a/parse_args.c +++ b/parse_args.c @@ -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 2776485..a7267c9 100755 --- 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"\ + " \n\n"\ + "Example:\n"\ + " \$pp_solaris_service_script=/etc/init.d/pp\n\n"\ + " \n\n"\ + "Example:\n"\ + " \$smf_method_envvar_name=PP_SMF_SERVICE\n\n"\ + " \n"\ + " \n"\ + " \n" + + return 1 + fi + return 0 + fi + + f=$pp_svc_xml_file pp_add_file_if_missing $f || return 0 - cat <<-. >$pp_destdir$f - - - - - - - - - - - - - - - - - - + _pp_solaris_smf_dependencies=" + + + + + + + +" + _pp_solaris_smf_dependencies=${pp_solaris_smf_dependencies:-$_pp_solaris_smf_dependencies} + cat <<-. >$pp_destdir$f + + + + + + + + + + + + $_pp_solaris_smf_dependencies + + $pp_solaris_smf_additional_dependencies + + + + + + + + + + + + + + + + . } @@ -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 () { diff --git a/pwutil.c b/pwutil.c index 86ae0ab..548da4d 100644 --- 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 * * 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; } diff --git a/redblack.c b/redblack.c index 95ac095..fb3611b 100644 --- a/redblack.c +++ b/redblack.c @@ -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; } /* diff --git a/schema.ActiveDirectory b/schema.ActiveDirectory index 4b87e05..cfdc7cb 100644 --- a/schema.ActiveDirectory +++ b/schema.ActiveDirectory @@ -158,6 +158,63 @@ name: sudoRunAsGroup schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw== objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X +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: changetype: modify add: schemaUpdateNow @@ -182,6 +239,9 @@ mayContain: sudoRunAs mayContain: sudoRunAsUser mayContain: sudoRunAsGroup mayContain: sudoUser +mayContain: sudoNotBefore +mayContain: sudoNotAfter +mayContain: sudoOrder rDNAttID: cn showInAdvancedViewOnly: FALSE adminDisplayName: sudoRole diff --git a/schema.OpenLDAP b/schema.OpenLDAP index df3fc0f..d3e95e0 100644 --- a/schema.OpenLDAP +++ b/schema.OpenLDAP @@ -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 ) ) diff --git a/schema.iPlanet b/schema.iPlanet index 3718fd7..e512864 100644 --- a/schema.iPlanet +++ b/schema.iPlanet @@ -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 3195e25..4001614 100644 --- a/sesh.c +++ b/sesh.c @@ -27,7 +27,7 @@ #include #include -#include "compat.h" +#include "missing.h" int main (int argc, char **argv) diff --git a/set_perms.c b/set_perms.c index d028b2c..355baad 100644 --- a/set_perms.c +++ b/set_perms.c @@ -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 */ diff --git a/setsid.c b/setsid.c index d8bba8b..79271c8 100644 --- a/setsid.c +++ b/setsid.c @@ -26,7 +26,7 @@ #endif /* HAVE_UNISTD_H */ #include -#include +#include "missing.h" pid_t setsid() diff --git a/sigaction.c b/sigaction.c index e34d471..9285dda 100644 --- a/sigaction.c +++ b/sigaction.c @@ -18,10 +18,14 @@ * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ +#include + +#include + #include #include -#include +#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; } diff --git a/snprintf.c b/snprintf.c index 4123a9d..3035232 100644 --- a/snprintf.c +++ b/snprintf.c @@ -76,7 +76,7 @@ # include #endif -#include +#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 */ diff --git a/strcasecmp.c b/strcasecmp.c index d14fdfb..9ab451c 100644 --- a/strcasecmp.c +++ b/strcasecmp.c @@ -14,9 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include -#include + +#include + +#include "missing.h" /* * Case insensitive string compare routines, same semantics as str[n]cmp() diff --git a/strerror.c b/strerror.c index cacd3f6..88b888b 100644 --- a/strerror.c +++ b/strerror.c @@ -18,11 +18,14 @@ * Materiel Command, USAF, under agreement number F39502-99-1-0512. */ +#include + +#include + #include #include -#include -#include +#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"; } diff --git a/strlcat.c b/strlcat.c index 97a803b..77f6c86 100644 --- a/strlcat.c +++ b/strlcat.c @@ -16,12 +16,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include #include -#include -#include - +#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 */ } diff --git a/strlcpy.c b/strlcpy.c index 8d301c3..df2e677 100644 --- a/strlcpy.c +++ b/strlcpy.c @@ -16,10 +16,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include -#include -#include +#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 */ } diff --git a/strsignal.c b/strsignal.c index cead4ad..a551429 100644 --- a/strsignal.c +++ b/strsignal.c @@ -14,11 +14,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + +#include + #include #include -#include -#include +#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 c03b726..0dc2e78 100644 --- 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() */ diff --git a/sudo.cat b/sudo.cat index 9f85ccd..4cee486 100644 --- a/sudo.cat +++ b/sudo.cat @@ -61,7 +61,7 @@ DDEESSCCRRIIPPTTIIOONN -1.7.4 July 19, 2010 1 +1.7.6 April 9, 2011 1 @@ -127,7 +127,7 @@ OOPPTTIIOONNSS -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 _s_e_t___h_o_m_e is set and the --ss option is specified on the command line. - -h The --hh (_h_e_l_p) option causes ssuuddoo to print a usage message - and exit. + -h The --hh (_h_e_l_p) option causes ssuuddoo to print a short help + message to the standard output and exit. -i [command] The --ii (_s_i_m_u_l_a_t_e _i_n_i_t_i_a_l _l_o_g_i_n) 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 @@ SSEECCUURRIITTYY NNOOTTEESS -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 @@ EENNVVIIRROONNMMEENNTT -1.7.4 July 19, 2010 8 +1.7.6 April 9, 2011 8 @@ -589,7 +589,7 @@ EEXXAAMMPPLLEESS -1.7.4 July 19, 2010 9 +1.7.6 April 9, 2011 9 @@ -655,6 +655,6 @@ DDIISSCCLLAAIIMMEERR -1.7.4 July 19, 2010 10 +1.7.6 April 9, 2011 10 diff --git a/sudo.h b/sudo.h index f946291..a59677b 100644 --- a/sudo.h +++ b/sudo.h @@ -24,7 +24,7 @@ #include #include -#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; diff --git a/sudo.man.in b/sudo.man.in index 3d67a76..09f1508 100644 --- a/sudo.man.in +++ b/sudo.man.in @@ -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: .\" ======================================================================== @@ -149,7 +149,7 @@ .\" ======================================================================== .\" .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 diff --git a/sudo.pod b/sudo.pod index 33bcb6a..555274c 100644 --- a/sudo.pod +++ b/sudo.pod @@ -221,7 +221,8 @@ command line. =item -h -The B<-h> (I) option causes B to print a usage message and exit. +The B<-h> (I) option causes B to print a short help message +to the standard output and exit. =item -i [command] diff --git a/sudo.pp b/sudo.pp index 1f203d8..35c18b7 100644 --- 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: diff --git a/sudo_exec.h b/sudo_exec.h index 6e26913..ea43d55 100644 --- a/sudo_exec.h +++ b/sudo_exec.h @@ -17,12 +17,19 @@ #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 */ diff --git a/sudo_noexec.c b/sudo_noexec.c index eff07b9..ba180b5 100644 --- a/sudo_noexec.c +++ b/sudo_noexec.c @@ -16,6 +16,8 @@ #include +#include + #include #ifndef HAVE_TIMESPEC # include @@ -26,7 +28,7 @@ # include #endif -#include +#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__ diff --git a/sudo_nss.c b/sudo_nss.c index e21aaae..9630320 100644 --- a/sudo_nss.c +++ b/sudo_nss.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2010 Todd C. Miller + * Copyright (c) 2007-2011 Todd C. Miller * * 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; } diff --git a/sudo_usage.h.in b/sudo_usage.h.in index af15b87..b26e3ec 100644 --- a/sudo_usage.h.in +++ b/sudo_usage.h.in @@ -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 diff --git a/sudoers.cat b/sudoers.cat index 018d805..2a7a521 100644 --- a/sudoers.cat +++ b/sudoers.cat @@ -61,7 +61,7 @@ DDEESSCCRRIIPPTTIIOONN -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: +o Group in the same domain: "Group Name" @@ -119,15 +125,9 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) +o 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 ffllaaggss, iinntteeggeerr values, ssttrriinnggss, or lliissttss. 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 rroooott, 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: RRuunnaass__SSppeecc @@ -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 rroooott 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 ddggbb may run _/_b_i_n_/_l_s, _/_b_i_n_/_k_i_l_l, and _/_u_s_r_/_b_i_n_/_l_p_r_m -- but only - as ooppeerraattoorr. 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 ddggbb may run _/_b_i_n_/_l_s, _/_b_i_n_/_k_i_l_l, and _/_u_s_r_/_b_i_n_/_l_p_r_m -- but only + as ooppeerraattoorr. 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 ttccmm 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 ttccmm. + 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 ttccmm. 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 --uu and + --gg options. In this example: + + alan ALL = (root, bin : operator, system) ALL + + user aallaann 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) + + SSEELLiinnuuxx__SSppeecc On systems with SELinux support, _s_u_d_o_e_r_s 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 _e_x_e_m_p_t___g_r_o_u_p 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. _S_E_T_E_N_V _a_n_d _N_O_S_E_T_E_N_V These tags override the value of the _s_e_t_e_n_v 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 _e_n_v___c_h_e_c_k, _e_n_v___d_e_l_e_t_e, or _e_n_v___k_e_e_p. As such, - only trusted users should be allowed to set variables in this manner. - If the command matched is AALLLL, 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 _e_n_v___r_e_s_e_t option from the command line via the --EE option. + Additionally, environment variables set on the command line are not + subject to the restrictions imposed by _e_n_v___c_h_e_c_k, _e_n_v___d_e_l_e_t_e, or + _e_n_v___k_e_e_p. As such, only trusted users should be allowed to set + variables in this manner. If the command matched is AALLLL, the SETENV + tag is implied for that command; this default may be overridden by use + of the NOSETENV tag. _L_O_G___I_N_P_U_T _a_n_d _N_O_L_O_G___I_N_P_U_T @@ -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 nnoott 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 ddooeess 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 _/_u_s_r_/_b_i_n_/_w_h_o but not _/_u_s_r_/_b_i_n_/_X_1_1_/_x_t_e_r_m. @@ -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 ssuuddoo to include the file _/_e_t_c_/_s_u_d_o_e_r_s_._x_e_r_x_e_s. The #includedir directive can be used to create a _s_u_d_o_._d 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, vviissuuddoo 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 vviissuuddoo with the -f flag to edit the files directly. @@ -582,21 +630,8 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) characters in a _U_s_e_r _S_p_e_c_i_f_i_c_a_t_i_o_n ('=', ':', '(', ')') 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): '!', '=', ':', + ',', '(', ')', '\'. SSUUDDOOEERRSS OOPPTTIIOONNSS ssuuddoo's behavior can be modified by Default_Entry lines, as explained @@ -611,11 +646,24 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS that the --HH option is always implied. Note that HOME is already set when the the _e_n_v___r_e_s_e_t option is enabled, so _a_l_w_a_y_s___s_e_t___h_o_m_e is only effective for - configurations where _e_n_v___r_e_s_e_t is disabled. This flag - is _o_f_f by default. + configurations where either _e_n_v___r_e_s_e_t is disabled or + HOME is present in the _e_n_v___k_e_e_p list. This flag is _o_f_f + 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 _o_n by default. @@ -652,18 +700,6 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS variable. This flag is _o_n by default. fast_glob Normally, ssuuddoo uses the _g_l_o_b(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, _g_l_o_b(3) can take a long time to complete for some patterns, especially @@ -682,6 +718,18 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) flag is _o_f_f 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 _s_u_d_o_e_r_s 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 _o_f_f by default. log_host If set, the host name will be logged in the (non- + syslog) ssuuddoo log file. This flag is _o_f_f by default. + log_input If set, ssuuddoo will run the command in a _p_s_e_u_d_o _t_t_y 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_o_l_o_g___d_i_r option (_/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o by default) using a + unique session ID that is included in the normal ssuuddoo + log line, prefixed with _T_S_I_D_=. + 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 _l_o_g___o_u_t_p_u_t 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) ssuuddoo log file. This flag is _o_f_f by default. + log_output If set, ssuuddoo will run the command in a _p_s_e_u_d_o _t_t_y and + log all output that is sent to the screen, similar to + the _s_c_r_i_p_t(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_o_l_o_g___d_i_r option (_/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o by default) using a + unique session ID that is included in the normal ssuuddoo + log line, prefixed with _T_S_I_D_=. + + Output logs may be viewed with the _s_u_d_o_r_e_p_l_a_y(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) ssuuddoo log file. This flag is _o_f_f 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 _o_f_f by default. + + +1.7.6 April 9, 2011 13 + + + + + +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + path_info Normally, ssuuddoo 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 _p_a_s_s_p_r_o_m_p_t 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 _p_a_s_s_p_r_o_m_p_t___o_v_e_r_r_i_d_e is set, _p_a_s_s_p_r_o_m_p_t will always be used. This flag is _o_f_f by default. @@ -836,32 +916,33 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) by default. runaspw If set, ssuuddoo will prompt for the password of the user - defined by the _r_u_n_a_s___d_e_f_a_u_l_t option (defaults to root) - instead of the password of the invoking user. This - flag is _o_f_f by default. - set_home If enabled and ssuuddoo is invoked with the --ss option the - HOME environment variable will be set to the home - directory of the target user (which is root unless the - --uu option is used). This effectively makes the --ss - option imply --HH. Note that HOME is already set when - the the _e_n_v___r_e_s_e_t option is enabled, so _s_e_t___h_o_m_e is - only effective for configurations where _e_n_v___r_e_s_e_t is - disabled. This flag is _o_f_f by default. - set_logname Normally, ssuuddoo 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 _r_u_n_a_s___d_e_f_a_u_l_t option (defaults to root) + instead of the password of the invoking user. This + flag is _o_f_f by default. + set_home If enabled and ssuuddoo is invoked with the --ss option the + HOME environment variable will be set to the home + directory of the target user (which is root unless the + --uu option is used). This effectively makes the --ss + option imply --HH. Note that HOME is already set when + the the _e_n_v___r_e_s_e_t option is enabled, so _s_e_t___h_o_m_e is + only effective for configurations where either + _e_n_v___r_e_s_e_t is disabled or HOME is present in the + _e_n_v___k_e_e_p list. This flag is _o_f_f by default. + set_logname Normally, ssuuddoo will set the LOGNAME, USER and USERNAME environment variables to the name of the target user (usually root unless the --uu 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, ssuuddoo will prompt for the password of the user specified by the --uu 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 - --uu option. This flag is _o_f_f by default. - - log_input If set, ssuuddoo will run the command in a _p_s_e_u_d_o _t_t_y 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 _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o directory using - a unique session ID that is included in the normal ssuuddoo - log line, prefixed with _T_S_I_D_=. - -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, ssuuddoo will run the command in a _p_s_e_u_d_o _t_t_y and - log all output that is sent to the screen, similar to - the _s_c_r_i_p_t(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 _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o directory - using a unique session ID that is included in the - normal ssuuddoo log line, prefixed with _T_S_I_D_=. - - Output logs may be viewed with the _s_u_d_o_r_e_p_l_a_y(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 + --uu option. This flag is _o_f_f by default. tty_tickets If set, users must authenticate on a per-tty basis. With this flag enabled, ssuuddoo will use a file named for @@ -982,28 +1037,28 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) closefrom Before it executes a command, ssuuddoo will close all open file descriptors other than standard input, standard + output and standard error (ie: file descriptors 0-2). + The _c_l_o_s_e_f_r_o_m 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 ssuuddoo logs the failure and exits. The + default is 3. + IInntteeggeerrss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: -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 _c_l_o_s_e_f_r_o_m 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 ssuuddoo logs the failure and exits. The - default is 3. +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - IInntteeggeerrss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: 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 _l_o_g___i_n_p_u_t or _l_o_g___o_u_t_p_u_t 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 _m_a_i_l_t_o 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 _m_a_i_l_t_o 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 _e_x_e_c_v_(_), _e_x_e_c_v_e_(_) and _f_e_x_e_c_v_e_(_) library functions that just return an error. This is used to implement the _n_o_e_x_e_c 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 ssuuddoo stores its timestamp files. The default is _/_v_a_r_/_a_d_m_/_s_u_d_o. @@ -1180,10 +1242,14 @@ SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) Negating the option results in a value of _n_e_v_e_r being used. The default value is _o_n_c_e. + lecture_file + Path to a file containing an alternate ssuuddoo lecture that + will be used in place of the standard lecture if the named + file exists. By default, ssuuddoo 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 ssuuddoo lecture that - will be used in place of the standard lecture if the named - file exists. By default, ssuuddoo uses a built-in lecture. - listpw This option controls when a password will be required when a user runs ssuuddoo with the --ll 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 ssuuddoo with the --vv 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 ssuuddoo with the --vv option. It has the following - possible values: all All the user's _s_u_d_o_e_r_s 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 ssuuddoo). env_keep Environment variables to be preserved in the user's + environment when the _e_n_v___r_e_s_e_t option is in effect. + This allows fine-grained control over the environment + ssuuddoo-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 _e_n_v___r_e_s_e_t option is in effect. - This allows fine-grained control over the environment - ssuuddoo-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 ssuuddoo is run by root with the _-_V option. @@ -1378,24 +1438,24 @@ EEXXAAMMPPLLEESS 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 jjaacckk may run any command on the machines in the _C_S_N_E_T_S 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 jjaacckk may run any command on the machines in the _C_S_N_E_T_S 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 _C_S_N_E_T_S, 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 ffrreedd can run commands as any user in the _D_B Runas_Alias + (oorraaccllee or ssyybbaassee) 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 ffrreedd can run commands as any user in the _D_B Runas_Alias - (oorraaccllee or ssyybbaassee) without giving a password. +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* On the _A_L_P_H_A machines, user jjoohhnn may su to anyone except root but he is not allowed to specify any options to the _s_u(1) command. @@ -1576,10 +1637,15 @@ SSEECCUURRIITTYY NNOOTTEESS Doesn't really prevent bbiillll from running the commands listed in _S_U or _S_H_E_L_L_S 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 _f_a_s_t___g_l_o_b 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 @@ SSEECCUURRIITTYY NNOOTTEESS SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - kind of restrictions should be considered advisory at best (and - reinforced by policy). - - Furthermore, if the _f_a_s_t___g_l_o_b 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 _f_n_m_a_t_c_h(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 @@ PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS File containing dummy exec functions: + then ssuuddoo 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 _n_o_e_x_e_c will work at compile-time. _n_o_e_x_e_c + 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 @@ PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - then ssuuddoo 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 _n_o_e_x_e_c will work at compile-time. _n_o_e_x_e_c - should work on SunOS, Solaris, *BSD, Linux, IRIX, Tru64 UNIX, MacOS X, and HP-UX 11.x. It is known nnoott to work on AIX and UnixWare. _n_o_e_x_e_c is expected to work on most operating systems that support the LD_PRELOAD environment variable. @@ -1707,19 +1768,6 @@ SSUUPPPPOORRTT 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) - - DDIISSCCLLAAIIMMEERR ssuuddoo is provided ``AS IS'' and any express or implied warranties, including, but not limited to, the implied warranties of @@ -1729,54 +1777,6 @@ DDIISSCCLLAAIIMMEERR - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -1.7.4 January 12, 2011 27 +1.7.6 April 9, 2011 27 diff --git a/sudoers.ldap.cat b/sudoers.ldap.cat index 20374d4..8b14333 100644 --- a/sudoers.ldap.cat +++ b/sudoers.ldap.cat @@ -43,7 +43,7 @@ DDEESSCCRRIIPPTTIIOONN For the most part, there is really no need for ssuuddoo-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 ssuuddoo-specific aliases. @@ -61,7 +61,7 @@ DDEESSCCRRIIPPTTIIOONN -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: ssuuddooUUsseerr 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 ssuuddoo versions + 1.7.0 and higher. Older versions of ssuuddoo use the sudoRunAs + attribute instead. + ssuuddooRRuunnAAssGGrroouupp 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 ssuuddoo: - - + The sudoRunAsGroup attribute is only available in ssuuddoo versions + 1.7.0 and higher. + ssuuddooNNoottBBeeffoorree + 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 ssuuddoo versions + 1.7.5 and higher and must be explicitly enabled via the + SSUUDDOOEERRSS__TTIIMMEEDD option in _/_e_t_c_/_l_d_a_p_._c_o_n_f. + + ssuuddooNNoottAAfftteerr + 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 ssuuddoo versions 1.7.5 + and higher and must be explicitly enabled via the SSUUDDOOEERRSS__TTIIMMEEDD + option in _/_e_t_c_/_l_d_a_p_._c_o_n_f. + + ssuuddooOOrrddeerr + 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 ssuuddoo 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 ssuuddoo: 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 SSUUDDOOEERRSS__TTIIMMEEDD configuration + directive, the LDAP queries include a subfilter that limits retrieval + to entries that satisfy the time constraints, if any. + DDiiffffeerreenncceess bbeettwweeeenn LLDDAAPP aanndd nnoonn--LLDDAAPP ssuuddooeerrss 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 _/_e_t_c_/_o_p_e_n_l_d_a_p_/_l_d_a_p_._c_o_n_f or the user's _._l_d_a_p_r_c files are not used. - Only those options explicitly listed in _/_e_t_c_/_l_d_a_p_._c_o_n_f that are + Only those options explicitly listed in _/_e_t_c_/_l_d_a_p_._c_o_n_f as being supported by ssuuddoo 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 llddaapp or llddaappss, the latter being for servers that support TLS (SSL) encryption. If no _p_o_r_t is specified, the default is port 389 for ldap:// or port 636 for ldaps://. If no _h_o_s_t_n_a_m_e is specified, + ssuuddoo will connect to llooccaallhhoosstt. Multiple UURRII lines are treated + identically to a UURRII 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) - ssuuddoo will connect to llooccaallhhoosstt. Multiple UURRII lines are treated - identically to a UURRII 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. - HHOOSSTT name[:port] ... If no UURRII is specified, the HHOOSSTT 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 UURRIIs or HHOOSSTTs are specified, this is the amount of time to wait before trying the next one in the list. + NNEETTWWOORRKK__TTIIMMEEOOUUTT seconds + An alias for BBIINNDD__TTIIMMEELLIIMMIITT for OpenLDAP compatibility. + TTIIMMEELLIIMMIITT seconds The TTIIMMEELLIIMMIITT parameter specifies the amount of time, in seconds, to wait for a response to an LDAP query. + TTIIMMEEOOUUTT seconds + The TTIIMMEEOOUUTT parameter specifies the amount of time, in seconds, to + wait for a response from the various LDAP APIs. + SSUUDDOOEERRSS__BBAASSEE base The base DN to use when performing ssuuddoo LDAP queries. Typically this is of the form ou=SUDOers,dc=example,dc=com for the domain example.com. Multiple SSUUDDOOEERRSS__BBAASSEE lines may be specified, in which case they are queried in the order specified. + SSUUDDOOEERRSS__SSEEAARRCCHH__FFIILLTTEERR ldap_filter + An LDAP filter which is used to restrict the set of records + returned when performing a ssuuddoo LDAP query. Typically, this is of + the form attribute=value or + (&(attribute=value)(attribute2=value2)). + + SSUUDDOOEERRSS__TTIIMMEEDD on/true/yes/off/false/no + Whether or not to evaluate the sudoNotBefore and sudoNotAfter + attributes that implement time-dependent sudoers entries. + SSUUDDOOEERRSS__DDEEBBUUGG debug_level This sets the debug level for ssuuddoo 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. - - BBIINNDDDDNN DN - The BBIINNDDDDNN 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. + BBIINNDDDDNN DN + The BBIINNDDDDNN 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. BBIINNDDPPWW secret The BBIINNDDPPWW parameter specifies the password to use when performing @@ -376,22 +451,13 @@ SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) can be verified. TTLLSS__CCAACCEERRTT file name - An alias for TTLLSS__CCAACCEERRTTFFIILLEE. + An alias for TTLLSS__CCAACCEERRTTFFIILLEE for OpenLDAP compatibility. - TTLLSS__CCAACCEERRTTFFIILLEE 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. _/_e_t_c_/_s_s_l_/_c_a_-_b_u_n_d_l_e_._p_e_m. This option is only - supported by the OpenLDAP libraries. Netscape-derived LDAP - libraries use the same certificate database for CA and client - certificates (see TTLLSS__CCEERRTT). - TTLLSS__CCAACCEERRTTDDIIRR directory - Similar to TTLLSS__CCAACCEERRTTFFIILLEE 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) + TTLLSS__CCAACCEERRTTFFIILLEE 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. _/_e_t_c_/_s_s_l_/_c_a_-_b_u_n_d_l_e_._p_e_m. This option is only + supported by the OpenLDAP libraries. Netscape-derived LDAP + libraries use the same certificate database for CA and client + certificates (see TTLLSS__CCEERRTT). + + TTLLSS__CCAACCEERRTTDDIIRR directory + Similar to TTLLSS__CCAACCEERRTTFFIILLEE but instead of a file, it is a directory containing individual Certificate Authority certificates, e.g. _/_e_t_c_/_s_s_l_/_c_e_r_t_s. The directory specified by TTLLSS__CCAACCEERRTTDDIIRR is checked after TTLLSS__CCAACCEERRTTFFIILLEE. 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. - UUSSEE__SSAASSLL on/true/yes/off/false/no - Enable UUSSEE__SSAASSLL for LDAP servers that support SASL authentication. - SSAASSLL__AAUUTTHH__IIDD identity - The SASL user name to use when connecting to the LDAP server. By - default, ssuuddoo will use an anonymous connection. - RROOOOTTUUSSEE__SSAASSLL on/true/yes/off/false/no - Enable RROOOOTTUUSSEE__SSAASSLL to enable SASL authentication when connecting - to an LDAP server from a privileged process, such as ssuuddoo. +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) + UUSSEE__SSAASSLL on/true/yes/off/false/no + Enable UUSSEE__SSAASSLL for LDAP servers that support SASL authentication. + + SSAASSLL__AAUUTTHH__IIDD identity + The SASL user name to use when connecting to the LDAP server. By + default, ssuuddoo will use an anonymous connection. + RROOOOTTUUSSEE__SSAASSLL on/true/yes/off/false/no + Enable RROOOOTTUUSSEE__SSAASSLL to enable SASL authentication when connecting + to an LDAP server from a privileged process, such as ssuuddoo. RROOOOTTSSAASSLL__AAUUTTHH__IIDD identity The SASL user name to use when RROOOOTTUUSSEE__SSAASSLL is enabled. @@ -509,28 +586,29 @@ SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) sudoers: files - Note that _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f is supported even when the underlying - operating system does not use an nsswitch.conf file. - CCoonnffiigguurriinngg nneettssvvcc..ccoonnff - On AIX systems, the _/_e_t_c_/_n_e_t_s_v_c_._c_o_n_f file is consulted instead of - _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f. ssuuddoo simply treats _n_e_t_s_v_c_._c_o_n_f as a variant of - _n_s_s_w_i_t_c_h_._c_o_n_f; 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 _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f is supported even when the underlying + operating system does not use an nsswitch.conf file. + + CCoonnffiigguurriinngg nneettssvvcc..ccoonnff + On AIX systems, the _/_e_t_c_/_n_e_t_s_v_c_._c_o_n_f file is consulted instead of + _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f. ssuuddoo simply treats _n_e_t_s_v_c_._c_o_n_f as a variant of + _n_s_s_w_i_t_c_h_._c_o_n_f; 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 @@ EEXXAAMMPPLLEESS #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 @@ EEXXAAMMPPLLEESS # # 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 @@ -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 SSuuddoo sscchheemmaa ffoorr OOppeennLLDDAAPP - The following schema is in OpenLDAP format. Simply copy it to the + The following schema, in OpenLDAP format, is included with ssuuddoo source + and binary distributions as _s_c_h_e_m_a_._O_p_e_n_L_D_A_P. Simply copy it to the schema directory (e.g. _/_e_t_c_/_o_p_e_n_l_d_a_p_/_s_c_h_e_m_a), add the proper include line in slapd.conf and restart ssllaappdd. @@ -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 ) ) SSEEEE AALLSSOO _l_d_a_p_._c_o_n_f(4), _s_u_d_o_e_r_s(5) CCAAVVEEAATTSS - The way that _s_u_d_o_e_r_s is parsed differs between Note that there are - differences in the way that LDAP-based _s_u_d_o_e_r_s is parsed compared to - file-based _s_u_d_o_e_r_s. See the "Differences between LDAP and non-LDAP - sudoers" section for more information. + Note that there are differences in the way that LDAP-based _s_u_d_o_e_r_s is + parsed compared to file-based _s_u_d_o_e_r_s. See the "Differences between + LDAP and non-LDAP sudoers" section for more information. BBUUGGSS If you feel you have found a bug in ssuuddoo, please submit a bug report at @@ -787,6 +902,23 @@ DDIISSCCLLAAIIMMEERR -1.7.4 July 12, 2010 12 + + + + + + + + + + + + + + + + + +1.7.6 April 9, 2011 14 diff --git a/sudoers.ldap.man.in b/sudoers.ldap.man.in index 66a1b03..74cafec 100644 --- a/sudoers.ldap.man.in +++ b/sudoers.ldap.man.in @@ -1,4 +1,4 @@ -.\" Copyright (c) 2003-2010 +.\" Copyright (c) 2003-2011 .\" Todd C. Miller .\" .\" 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: .\" ======================================================================== @@ -140,7 +140,7 @@ .\" ======================================================================== .\" .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 \& #bindpw @@ -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 diff --git a/sudoers.ldap.pod b/sudoers.ldap.pod index f7a39c9..a981654 100644 --- a/sudoers.ldap.pod +++ b/sudoers.ldap.pod @@ -1,4 +1,4 @@ -Copyright (c) 2003-2010 +Copyright (c) 2003-2011 Todd C. Miller Permission to use, copy, modify, and distribute this software for any @@ -68,14 +68,14 @@ is that in LDAP, B-specific Aliases are not supported. For the most part, there is really no need for B-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-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. 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 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. 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 will match any user. +The C attribute is only available in B versions +1.7.0 and higher. Older versions of B use the C +attribute instead. + =item B A Unix group or gid (prefixed with C<'#'>) that commands may be run as. The special value C will match any group. +The C attribute is only available in B versions +1.7.0 and higher. + +=item B + +A timestamp in the form C that can be used to provide +a start date/time for when the C will be valid. If +multiple C entries are present, the earliest is used. +Note that timestamps must be in Coordinated Universal Time (UTC), +not the local timezone. + +The C attribute is only available in B versions +1.7.5 and higher and must be explicitly enabled via the B +option in F<@ldap_conf@>. + +=item B + +A timestamp in the form C that indicates an expiration +date/time, after which the C will no longer be valid. If +multiple C entries are present, the last one is used. +Note that timestamps must be in Coordinated Universal Time (UTC), +not the local timezone. + +The C attribute is only available in B versions +1.7.5 and higher and must be explicitly enabled via the B +option in F<@ldap_conf@>. + +=item B + +The C entries retrieved from the LDAP directory have no +inherent order. The C 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 attribute is chosen. This +corresponds to the "last match" behavior of the sudoers file. If +the C attribute is not present, a value of 0 is assumed. + +The C attribute is only available in B 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 must contain at least one C, C and C. 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 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 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 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 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 Bs or Bs are specified, this is the amount of time to wait before trying the next one in the list. +=item B seconds + +An alias for B for OpenLDAP compatibility. + =item B seconds The B parameter specifies the amount of time, in seconds, to wait for a response to an LDAP query. +=item B seconds + +The B parameter specifies the amount of time, in seconds, +to wait for a response from the various LDAP APIs. + =item B base The base DN to use when performing B LDAP queries. Typically @@ -306,6 +369,17 @@ this is of the form C for the domain C. Multiple B lines may be specified, in which case they are queried in the order specified. +=item B ldap_filter + +An LDAP filter which is used to restrict the set of records returned +when performing a B LDAP query. Typically, this is of the +form C or C<(&(attribute=value)(attribute2=value2))>. + +=item B on/true/yes/off/false/no + +Whether or not to evaluate the C and C +attributes that implement time-dependent sudoers entries. + =item B debug_level This sets the debug level for B LDAP queries. Debugging @@ -370,7 +444,7 @@ should be installed locally so it can be verified. =item B file name -An alias for B. +An alias for B for OpenLDAP compatibility. =item B 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 #bindpw @@ -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), add the proper -C line in C and restart B. +The following schema, in OpenLDAP format, is included with B +source and binary distributions as F. Simply copy +it to the schema directory (e.g. F), add the +proper C line in C and restart B. attributetype ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' @@ -704,11 +782,33 @@ C line in C and restart B. 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, L =head1 CAVEATS -The way that I is parsed differs between Note that there -are differences in the way that LDAP-based I is parsed -compared to file-based I. See the L section for more information. +Note that there are differences in the way that LDAP-based I +is parsed compared to file-based I. See the L section for more information. =head1 BUGS diff --git a/sudoers.man.in b/sudoers.man.in index 210cf90..531ead6 100644 --- a/sudoers.man.in +++ b/sudoers.man.in @@ -1,4 +1,4 @@ -.\" Copyright (c) 1994-1996, 1998-2005, 2007-2010 +.\" Copyright (c) 1994-1996, 1998-2005, 2007-2011 .\" Todd C. Miller .\" .\" Permission to use, copy, modify, and distribute this software for any @@ -148,7 +148,7 @@ .\" ======================================================================== .\" .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" diff --git a/sudoers.pod b/sudoers.pod index da7ea5f..ef250cd 100644 --- a/sudoers.pod +++ b/sudoers.pod @@ -1,4 +1,4 @@ -Copyright (c) 1994-1996, 1998-2005, 2007-2010 +Copyright (c) 1994-1996, 1998-2005, 2007-2011 Todd C. Miller Permission to use, copy, modify, and distribute this software for any @@ -112,25 +112,32 @@ The definitions of what constitutes a valid I 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 is made up of one or more user names, uids (prefixed -with '#'), system groups (prefixed with '%'), netgroups (prefixed -with '+') and Ces. 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, C, C or C 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 syntax depends on the underlying implementation. -For instance, the QAS AD backend supports the following formats: +A C 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 +Ces. 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, C, C, C, C, C +or C 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 and C 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 is made up of one or more host names, IP addresses, @@ -293,7 +305,7 @@ A B determines which commands a user may run (and as what user) on specified hosts. By default, commands are run as B, 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 may run F, F, and F -- but only as B. E.g., - $ sudo -u operator /bin/ls. + $ sudo -u operator /bin/ls It is also possible to override a C later on in an entry. If we modify the entry like so: @@ -338,13 +350,36 @@ the user or group set to B: dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \ /usr/bin/lprm +Note that while the group portion of the C 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 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. +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. E.g. + + $ sudo -g dialer /usr/bin/cu + +Multiple users and groups may be present in a C, 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 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 entries may optionally have @@ -408,13 +443,14 @@ on how C works and whether or not it will work on your system. =head3 SETENV and NOSETENV These tags override the value of the I option on a per-command -basis. Note that if C has been set for a command, any -environment variables set on the command line way are not subject -to the restrictions imposed by I, I, or -I. As such, only trusted users should be allowed to set -variables in this manner. If the command matched is B, the -C tag is implied for that command; this default may -be overridden by use of the C tag. +basis. Note that if C has been set for a command, the user +may disable the I 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, +I, or I. As such, only trusted users should +be allowed to set variables in this manner. If the command matched +is B, the C tag is implied for that command; this +default may be overridden by use of the C tag. =head3 LOG_INPUT and NOLOG_INPUT @@ -579,7 +615,7 @@ characters in a I ('=', ':', '(', ')') is optional. The following characters must be escaped with a backslash ('\') when used as part of a word (e.g.Ea 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 is already set when the the I option is enabled, so I is only -effective for configurations where I is disabled. +effective for configurations where either I is disabled +or C is present in the I list. This flag is I by default. =item authenticate @@ -640,7 +677,7 @@ and C lists are then added. The default contents of the C and C lists are displayed when B is run by root with the I<-V> option. If the I option is set, its value will be used for the C environment variable. -This flag is I 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 log file. This flag is I by default. +=item log_input + +If set, B will run the command in a I 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 +option (F<@iolog_dir@> by default) using a unique session ID that +is included in the normal B log line, prefixed with I. + +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 is all that is required. + +=item log_output + +If set, B will run the command in a I 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 +option (F<@iolog_dir@> by default) using a unique session ID that +is included in the normal B log line, prefixed with I. + +Output logs may be viewed with the L 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 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 is already set when the the I option is enabled, so I is -only effective for configurations where I is disabled. +only effective for configurations where either I is disabled +or C is present in the I list. This flag is I 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 by default. -=item log_input - -If set, B will run the command in a I 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 directory using a unique -session ID that is included in the normal B log line, prefixed -with I. - -=item log_output - -If set, B will run the command in a I 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 directory using a unique session ID that is -included in the normal B log line, prefixed with I. - -Output logs may be viewed with the L 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 than the user's own umask and matches historical behavior. If I is not set, B will set the umask to be the union of the user's umask and what is specified in -I. This flag is I by default. +I. This flag is I<@umask_override@> by default. =item use_loginclass @@ -1019,6 +1062,13 @@ B. B 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 +or I options are enabled or when the C or +C tags are present for a command. +The default is C<"@iolog_dir@">. + =item mailsub Subject of the mail sent to the I 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 +=item F<@iolog_dir@> I/O log files diff --git a/sudoers2ldif b/sudoers2ldif old mode 100644 new mode 100755 index 0fe0ad1..442155e --- a/sudoers2ldif +++ b/sudoers2ldif @@ -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 } diff --git a/sudoreplay.c b/sudoreplay.c index 58b8639..9fdb5bb 100644 --- a/sudoreplay.c +++ b/sudoreplay.c @@ -18,6 +18,9 @@ #include #include +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif #include #include #include @@ -50,7 +53,7 @@ # include #endif #ifndef HAVE_TIMESPEC -# include +# include "emul/timespec.h" #endif #include #include @@ -85,10 +88,9 @@ #include -#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; { diff --git a/sudoreplay.cat b/sudoreplay.cat index 9c03469..aee5497 100644 --- a/sudoreplay.cat +++ b/sudoreplay.cat @@ -8,10 +8,10 @@ NNAAMMEE sudoreplay - replay sudo session logs SSYYNNOOPPSSIISS - ssuuddoorreeppllaayy [--dd _d_i_r_e_c_t_o_r_y] [--ff _f_i_l_t_e_r] [--mm _m_a_x___w_a_i_t] [--ss _s_p_e_e_d___f_a_c_t_o_r] - ID + ssuuddoorreeppllaayy [--hh] [--dd _d_i_r_e_c_t_o_r_y] [--ff _f_i_l_t_e_r] [--mm _m_a_x___w_a_i_t] [--ss + _s_p_e_e_d___f_a_c_t_o_r] ID - ssuuddoorreeppllaayy [--dd _d_i_r_e_c_t_o_r_y] -l [search expression] + ssuuddoorreeppllaayy [--hh] [--dd _d_i_r_e_c_t_o_r_y] -l [search expression] DDEESSCCRRIIPPTTIIOONN ssuuddoorreeppllaayy plays back or lists the session logs created by ssuuddoo. When @@ -47,21 +47,21 @@ OOPPTTIIOONNSS _f_i_l_t_e_r argument is a comma-separated list, consisting of one or more of following: _s_t_d_o_u_t, _s_t_d_e_r_r, and _t_t_y_o_u_t. - -l Enable "list mode". In this mode, ssuuddoorreeppllaayy will list + -h The --hh (_h_e_l_p) option causes ssuuddoorreeppllaayy to print a short + help message to the standard output and exit. + + -l [_s_e_a_r_c_h _e_x_p_r_e_s_s_i_o_n] + Enable "list mode". In this mode, ssuuddoorreeppllaayy will list available session IDs. If a _s_e_a_r_c_h _e_x_p_r_e_s_s_i_o_n is specified, it will be used to restrict the IDs that are displayed. An expression is composed of the following predicates: - command _c_o_m_m_a_n_d _p_a_t_t_e_r_n - Evaluates to true if the command run matches - _c_o_m_m_a_n_d _p_a_t_t_e_r_n. 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 @@ OOPPTTIIOONNSS SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) + command _c_o_m_m_a_n_d _p_a_t_t_e_r_n + Evaluates to true if the command run matches + _c_o_m_m_a_n_d _p_a_t_t_e_r_n. 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 _m_a_x___w_a_i_t Specify an upper bound on how long to wait between key presses or output data. By default, ssuuddoo__rreeppllaayy will - accurately reproduce the delays between key presses or - program output. However, this can be tedious when the - session includes long pauses. When the _-_m option is - specified, ssuuddoorreeppllaayy will limit these pauses to at most - _m_a_x___w_a_i_t 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 _-_m option is + specified, ssuuddoorreeppllaayy will limit these pauses to at most + _m_a_x___w_a_i_t seconds. The value may be specified as a floating point number, .e.g. _2_._5. -s _s_p_e_e_d___f_a_c_t_o_r @@ -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 @@ EEXXAAMMPPLLEESS sudoreplay -l user millert - List sessions run by user _b_o_b 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 @@ EEXXAAMMPPLLEESS SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) + List sessions run by user _b_o_b with a command containing the string vi: + sudoreplay -l user bob command vi List sessions run by user _j_e_f_f that match a regular expression: @@ -323,8 +325,6 @@ DDIISSCCLLAAIIMMEERR - - -1.7.4 July 12, 2010 5 +1.7.6 April 9, 2011 5 diff --git a/sudoreplay.man.in b/sudoreplay.man.in index 1ed044d..89418d8 100644 --- a/sudoreplay.man.in +++ b/sudoreplay.man.in @@ -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: .\" ======================================================================== @@ -139,7 +139,7 @@ .\" ======================================================================== .\" .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 @@ -148,9 +148,9 @@ 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 diff --git a/sudoreplay.pod b/sudoreplay.pod index c36f913..5eb6e1e 100644 --- a/sudoreplay.pod +++ b/sudoreplay.pod @@ -21,9 +21,9 @@ sudoreplay - replay sudo session logs =head1 SYNOPSIS -B [B<-d> I] [B<-f> I] [B<-m> I] [B<-s> I] ID +B [B<-h>] [B<-d> I] [B<-f> I] [B<-m> I] [B<-s> I] ID -B [B<-d> I] -l [search expression] +B [B<-h>] [B<-d> I] -l [search expression] =head1 DESCRIPTION @@ -76,7 +76,12 @@ used to select which of these to output. The I argument is a comma-separated list, consisting of one or more of following: I, I, and I. -=item -l +=item -h + +The B<-h> (I) option causes B to print a short +help message to the standard output and exit. + +=item -l [I] Enable "list mode". In this mode, B will list available session IDs. If a I is specified, it will be diff --git a/term.c b/term.c index 85b7300..4aa7128 100644 --- a/term.c +++ b/term.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2010 Todd C. Miller + * Copyright (c) 2009-2011 Todd C. Miller * * 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 diff --git a/testsudoers.c b/testsudoers.c index 1bf2cd3..139c7c7 100644 --- a/testsudoers.c +++ b/testsudoers.c @@ -60,6 +60,7 @@ #include #include +#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); } diff --git a/tgetpass.c b/tgetpass.c index 8127eab..b64bb8d 100644 --- a/tgetpass.c +++ b/tgetpass.c @@ -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; } diff --git a/timestr.c b/timestr.c index 3b2a18d..9369e8c 100644 --- a/timestr.c +++ b/timestr.c @@ -28,7 +28,7 @@ #endif /* STDC_HEADERS */ #include -#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 e58fed9..77b6ecb 100644 --- a/toke.c +++ b/toke.c @@ -1,3 +1,4 @@ +#include /* $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 # endif #endif +#include #include #include "sudo.h" #include "parse.h" +#include "toke.h" #include 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 index 0000000..75e9495 --- /dev/null +++ b/toke.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 263693e..05ea663 100644 --- a/toke.l +++ b/toke.l @@ -65,37 +65,29 @@ # include # endif #endif +#include #include #include "sudo.h" #include "parse.h" +#include "toke.h" #include 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 %% +[[:blank:]]*,[[:blank:]]* { + LEXTRACE(", "); + return ','; + } /* return ',' */ + [[:blank:]]+ BEGIN STARTDEFS; {DEFVAR} { @@ -132,34 +130,35 @@ DEFVAR [a-z_]+ LEXTRACE("DEFVAR "); if (!fill(yytext, yyleng)) yyterminate(); - return(DEFVAR); + return DEFVAR; } { , { 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_]+ ^#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_]+ ^#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(); } -^[[:blank:]]*Defaults([:@>\!]\!?{WORD})? { +^[[: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; } } ^[[: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; + } + +(\+|\%|\%:) { + /* 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; } ({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 */ -\"[^"\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); - } +\" { + LEXTRACE("BEGINSTR "); + yylval.string = NULL; + prev_state = YY_START; + BEGIN INSTR; } ({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 \ */ #(-[^\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 */ <*><> { 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 index 0000000..99e7552 --- /dev/null +++ b/toke_util.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 1996, 1998-2005, 2007-2011 + * Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#include +#include "sudo.h" +#include "parse.h" +#include "toke.h" +#include + +static int arg_len = 0; +static int arg_size = 0; + +static unsigned char +hexchar(s) + const char *s; +{ + int i; + int result = 0; + + s += 2; /* skip \\x */ + for (i = 0; i < 2; i++) { + switch (*s) { + case 'A': + case 'a': + result += 10; + break; + case 'B': + case 'b': + result += 11; + break; + case 'C': + case 'c': + result += 12; + break; + case 'D': + case 'd': + result += 13; + break; + case 'E': + case 'e': + result += 14; + break; + case 'F': + case 'f': + result += 15; + break; + default: + result += *s - '0'; + break; + } + if (i == 0) { + result *= 16; + s++; + } + } + return (unsigned char)result; +} + +int +fill_txt(src, len, olen) + char *src; + int len, olen; +{ + char *dst; + + dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1); + if (dst == NULL) { + yyerror("unable to allocate memory"); + return FALSE; + } + yylval.string = dst; + + /* Copy the string and collapse any escaped characters. */ + dst += olen; + while (len--) { + if (*src == '\\' && len) { + if (src[1] == 'x' && len >= 3 && + isxdigit((unsigned char) src[2]) && + isxdigit((unsigned char) src[3])) { + *dst++ = hexchar(src); + src += 4; + len -= 3; + } else { + src++; + len--; + *dst++ = *src++; + } + } else { + *dst++ = *src++; + } + } + *dst = '\0'; + return TRUE; +} + +int +append(src, len) + char *src; + int len; +{ + int olen = 0; + + if (yylval.string != NULL) + olen = strlen(yylval.string); + + return fill_txt(src, len, olen); +} + +#define SPECIAL(c) \ + ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#') + +int +fill_cmnd(src, len) + char *src; + int len; +{ + char *dst; + int i; + + arg_len = arg_size = 0; + + dst = yylval.command.cmnd = (char *) malloc(len + 1); + if (yylval.command.cmnd == NULL) { + yyerror("unable to allocate memory"); + return FALSE; + } + + /* Copy the string and collapse any escaped sudo-specific characters. */ + for (i = 0; i < len; i++) { + if (src[i] == '\\' && i != len - 1 && SPECIAL(src[i + 1])) + *dst++ = src[++i]; + else + *dst++ = src[i]; + } + *dst = '\0'; + + yylval.command.args = NULL; + return TRUE; +} + +int +fill_args(s, len, addspace) + char *s; + int len; + int addspace; +{ + int new_len; + char *p; + + if (yylval.command.args == NULL) { + addspace = 0; + new_len = len; + } else + new_len = arg_len + len + addspace; + + if (new_len >= arg_size) { + /* Allocate more space than we need for subsequent args */ + while (new_len >= (arg_size += COMMANDARGINC)) + ; + + p = yylval.command.args ? + (char *) realloc(yylval.command.args, arg_size) : + (char *) malloc(arg_size); + if (p == NULL) { + efree(yylval.command.args); + yyerror("unable to allocate memory"); + return FALSE; + } else + yylval.command.args = p; + } + + /* Efficiently append the arg (with a leading space if needed). */ + p = yylval.command.args + arg_len; + if (addspace) + *p++ = ' '; + if (strlcpy(p, s, arg_size - (p - yylval.command.args)) != len) { + yyerror("fill_args: buffer overflow"); /* paranoia */ + return FALSE; + } + arg_len = new_len; + return TRUE; +} + +/* + * Check to make sure an IPv6 address does not contain multiple instances + * of the string "::". Assumes strlen(s) >= 1. + * Returns TRUE if address is valid else FALSE. + */ +int +ipv6_valid(s) + const char *s; +{ + int nmatch = 0; + + for (; *s != '\0'; s++) { + if (s[0] == ':' && s[1] == ':') { + if (++nmatch > 1) + break; + } + if (s[0] == '/') + nmatch = 0; /* reset if we hit netmask */ + } + + return nmatch <= 1; +} diff --git a/tsgetgrpw.c b/tsgetgrpw.c index 6f14d3f..5b38298 100644 --- a/tsgetgrpw.c +++ b/tsgetgrpw.c @@ -44,9 +44,8 @@ #endif /* HAVE_STRINGS_H */ #include #include -#include -#include +#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; } diff --git a/utimes.c b/utimes.c index 84f4c43..5ff4379 100644 --- a/utimes.c +++ b/utimes.c @@ -26,10 +26,10 @@ #ifdef HAVE_UTIME_H # include #else -# include +# include "emul/utime.h" #endif -#include +#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 */ diff --git a/vasgroups.c b/vasgroups.c index a7c6c34..0ba33e1 100644 --- a/vasgroups.c +++ b/vasgroups.c @@ -28,7 +28,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include "config.h" +#include #include #include @@ -40,7 +40,7 @@ #include -#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; } diff --git a/visudo.c b/visudo.c index ab8d587..bc77377 100644 --- 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); } diff --git a/visudo.cat b/visudo.cat index c99374f..ce7c1a3 100644 --- a/visudo.cat +++ b/visudo.cat @@ -8,7 +8,7 @@ NNAAMMEE visudo - edit the sudoers file SSYYNNOOPPSSIISS - vviissuuddoo [--cc] [--qq] [--ss] [--VV] [--ff _s_u_d_o_e_r_s] + vviissuuddoo [--cchhqqssVV] [--ff _s_u_d_o_e_r_s] DDEESSCCRRIIPPTTIIOONN vviissuuddoo edits the _s_u_d_o_e_r_s file in a safe fashion, analogous to _v_i_p_w(1m). @@ -54,14 +54,14 @@ OOPPTTIIOONNSS option vviissuuddoo will edit (or check) the _s_u_d_o_e_r_s file of your choice, instead of the default, _/_e_t_c_/_s_u_d_o_e_r_s. The lock file used is the specified _s_u_d_o_e_r_s file with ".tmp" - appended to it. + appended to it. In cchheecckk--oonnllyy mode only, the argument to + --ff may be "-", indicating that _s_u_d_o_e_r_s will be read from + the standard input. - -q Enable qquuiieett 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 @@ OOPPTTIIOONNSS VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) + -h The --hh (_h_e_l_p) option causes vviissuuddoo to print a short help + message to the standard output and exit. + + -q Enable qquuiieett mode. In this mode details about syntax + errors are not printed. This option is only useful when combined with the --cc option. -s Enable ssttrriicctt checking of the _s_u_d_o_e_r_s file. If an alias is @@ -118,16 +123,11 @@ DDIIAAGGNNOOSSTTIICCSS used. You may wish to comment out or remove the unused alias. In --ss (strict) mode this is an error, not a warning. -SSEEEE AALLSSOO - _v_i(1), _s_u_d_o_e_r_s(4), _s_u_d_o(1m), _v_i_p_w(8) -AAUUTTHHOORR - Many people have worked on _s_u_d_o over the years; this version of vviissuuddoo - was written by: -1.7.4 July 14, 2010 2 +1.7.6 April 9, 2011 2 @@ -136,6 +136,13 @@ AAUUTTHHOORR VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) +SSEEEE AALLSSOO + _v_i(1), _s_u_d_o_e_r_s(4), _s_u_d_o(1m), _v_i_p_w(8) + +AAUUTTHHOORR + Many people have worked on _s_u_d_o over the years; this version of vviissuuddoo + was written by: + Todd Miller See the HISTORY file in the sudo distribution or visit @@ -186,13 +193,6 @@ DDIISSCCLLAAIIMMEERR - - - - - - - -1.7.4 July 14, 2010 3 +1.7.6 April 9, 2011 3 diff --git a/visudo.man.in b/visudo.man.in index 563fd3b..c8ee72e 100644 --- a/visudo.man.in +++ b/visudo.man.in @@ -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: .\" ======================================================================== @@ -144,7 +144,7 @@ .\" ======================================================================== .\" .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 @@ -153,7 +153,7 @@ 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 diff --git a/visudo.pod b/visudo.pod index ccc5c00..708d954 100644 --- a/visudo.pod +++ b/visudo.pod @@ -26,7 +26,7 @@ visudo - edit the sudoers file =head1 SYNOPSIS -B [B<-c>] [B<-q>] [B<-s>] [B<-V>] [B<-f> I] +B [B<-chqsV>] [B<-f> I] =head1 DESCRIPTION @@ -82,6 +82,13 @@ Specify and alternate I file location. With this option B will edit (or check) the I file of your choice, instead of the default, F<@sysconfdir@/sudoers>. The lock file used is the specified I file with ".tmp" appended to it. +In B mode only, the argument to B<-f> may be "-", +indicating that I will be read from the standard input. + +=item -h + +The B<-h> (I) option causes B to print a short help message +to the standard output and exit. =item -q diff --git a/zero_bytes.c b/zero_bytes.c index 7391780..bce0895 100644 --- a/zero_bytes.c +++ b/zero_bytes.c @@ -14,10 +14,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include -#include -#include +#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 index 0000000..65ad6a5 --- /dev/null +++ b/zlib/adler32.c @@ -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 index 0000000..ea4dfbe --- /dev/null +++ b/zlib/compress.c @@ -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 index 0000000..91be372 --- /dev/null +++ b/zlib/crc32.c @@ -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 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 +# 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 +# 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 index 0000000..8053b61 --- /dev/null +++ b/zlib/crc32.h @@ -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 index 0000000..5c4022f --- /dev/null +++ b/zlib/deflate.c @@ -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)<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 index 0000000..cbf0d1e --- /dev/null +++ b/zlib/deflate.h @@ -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 index 0000000..caeb99a --- /dev/null +++ b/zlib/gzclose.c @@ -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 index 0000000..e554830 --- /dev/null +++ b/zlib/gzguts.h @@ -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 +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifdef _MSC_VER +# include +# 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 +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifdef STDC +# include +# 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 index 0000000..603e60e --- /dev/null +++ b/zlib/gzlib.c @@ -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); /* 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 index 0000000..548201a --- /dev/null +++ b/zlib/gzread.c @@ -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 index 0000000..e8defc6 --- /dev/null +++ b/zlib/gzwrite.c @@ -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 + +/* -- 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 index 0000000..af3a8c9 --- /dev/null +++ b/zlib/infback.c @@ -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 index 0000000..2f1d60b --- /dev/null +++ b/zlib/inffast.c @@ -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 index 0000000..e5c1aa4 --- /dev/null +++ b/zlib/inffast.h @@ -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 index 0000000..75ed4b5 --- /dev/null +++ b/zlib/inffixed.h @@ -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 index 0000000..a8431ab --- /dev/null +++ b/zlib/inflate.c @@ -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 + +/* + 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 index 0000000..95f4986 --- /dev/null +++ b/zlib/inflate.h @@ -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 index 0000000..11e9c52 --- /dev/null +++ b/zlib/inftrees.c @@ -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 index 0000000..baa53a0 --- /dev/null +++ b/zlib/inftrees.h @@ -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 index 0000000..56e9bb1 --- /dev/null +++ b/zlib/trees.c @@ -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 +#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< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 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 +# 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<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 index 0000000..d35639d --- /dev/null +++ b/zlib/trees.h @@ -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 index 0000000..ad98be3 --- /dev/null +++ b/zlib/uncompr.c @@ -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 index 0000000..a8b4521 --- /dev/null +++ b/zlib/zconf.h.in @@ -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 + /* 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 /* 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 /* for SEEK_* and off_t */ +# ifdef VMS +# include /* 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 index 0000000..bfbba83 --- /dev/null +++ b/zlib/zlib.h @@ -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 index 0000000..898ed34 --- /dev/null +++ b/zlib/zutil.c @@ -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 index 0000000..258fa88 --- /dev/null +++ b/zlib/zutil.h @@ -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 +# endif +# include +# include +#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 +# endif +# else /* MSC or DJGPP */ +# include +# 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 +# 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 /* 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 + 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 */ -- 2.30.2