From: Bdale Garbee Date: Tue, 25 Sep 2012 16:23:23 +0000 (-0600) Subject: Merge tag 'debian/1.8.5p2-1' into squeeze X-Git-Tag: 1.8.5p2-1_bpo60+1~1 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=6ad45aa23af5f5f3b54468937d6a13089201b891;hp=97bd3ae46779c69fcdab82d0c64bdf05be009ec3;p=debian%2Fsudo Merge tag 'debian/1.8.5p2-1' into squeeze Conflicts: debian/changelog plugins/sudoers/check.c plugins/sudoers/env.c --- diff --git a/ChangeLog b/ChangeLog index d5247b7..ce73728 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,1596 +1,9719 @@ -2010-09-06 Todd C. Miller +2012-05-29 Todd C. Miller - * match.c: - When matching the runas user and runas group (-u and -g command line - options), keep track of runas group and runas user matches - separately. Only return a positive match if we have a match for - both runas user and runas group (if specified). - [68d30216c13a] + * NEWS: + Update for sudo 1.8.5p2 + [d369d4d40a19] -2010-09-04 Todd C. Miller +2012-05-27 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] + * src/env_hooks.c, src/sudo.h, src/tgetpass.c: + Provide unhooked version of getenv() and use it when looking up + DISPLAY and SUDO_ASKPASS in the environment. + [04dbdccf4a14] - * ldap.c: - display_bound_defaults now returns a count so make the stub return - 0, not 1. - [97293ced4908] +2012-05-21 Todd C. Miller -2010-09-03 Todd C. Miller + * plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c: + If sudoers_mode is group-readable but the actual sudoers file is + not, open the file as uid 0, not uid 1. This fixes a problem when + sudoers has a more restrictive mode than what sudo expects to find. + In older versions, sudo would silently chmod the file to add the + group-readable bit. + [c056b6003e6f] - * get_pty.c: - It looks like AIX doesn't need to push STREAMS modules for ptys. - [62c281fcd4ad] +2012-05-17 Todd C. Miller -2010-08-30 Todd C. Miller + * NEWS, configure, configure.in: + Update for 1.8.5p1 + [c33c49bf5b4b] - * Makefile.in: - Install sudoers file from the build dir not hte src dir. - [a26afd8db531] + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Fix #includedir; from Mike Frysinger + [d4833d4e39a0] -2010-08-26 Todd C. Miller + * plugins/sudoers/check.c: + Don't prompt for a password if the user is in the exempt group, is + root, or is running the command as themselves even if the -k option + was specified. This makes "sudo -k command" consistent with the + behavior one would get if the user ran "sudo -k" immediately before + running the command. + [632b3961df00] - * set_perms.c: - If runas_pw changes, reset the stashed runas aux group vector. - Otherwise, if runas_default is set in a per-command Defaults - statement, the command runs with root's aux group vector (i.e. the - one that was used when locating the command). - [24a695707b67] +2012-05-15 Todd C. Miller - * Makefile.in: - Add target to generate sudoers file Remove generated sudoers file as - part of distclean - [448627fc35b6] + * INSTALL: + Fix capitalization + [7258aa977caf] -2010-08-23 millert + * mkpkg: + Build PIE executable on Mac OS X 10.5 and above. + [2a5c7ef92182] - * exec.c: - When not logging I/O install a handler for SIGCONT and deliver it to - the command upon resume. Fixes bugzilla #431 - [e84690aa67bd] +2012-05-14 Todd C. Miller -2010-08-21 Todd C. Miller + * NEWS: + Update for sudo 1.8.4p5 + [21164f508b68] - * sudo.c: - Don't need to fork and wait when compiled with --disable-pam-session - [2ae1bbe4437a] + * plugins/sudoers/match_addr.c: + Add missing break between AF_INET and AF_INET6 in + addr_matches_if_netmask() + [672a4793931a] -2010-08-20 Todd C. Miller + * plugins/sudoers/mon_systrace.c: + Move systrace monitor code to the attic + [d6faf4754e9c] - * lbuf.c: - Convert a remaining puts() and putchar() to use the output function. - [d68c213feb0f] +2012-05-11 Todd C. Miller -2010-08-18 Todd C. Miller + * src/exec.c: + The pointer to the siginfo_t struct in a signal handler may be NULL. + [41a4ee934b53] - * Makefile.in: - Replace sudoers with sudoers.in in DISTFILES - [616509f85d6c] +2012-05-10 Todd C. Miller - * 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] + * plugins/sudoers/pwutil.c: + Fix an alignment problem on NetBSD systems with a 64-bit time_t and + strict alignment. Based on a patch from Martin Husemann. + [1e5ba3c18f17] - * configure, configure.in, sudoers, sudoers.in: - Substitute sysconfdir in the installed sudoers file to get the - correct path for sudoers.d. - [ab14a68e546f] + * include/missing.h: + Add offsetof macro for those without it. + [e44cb51d2587] -2010-08-17 Todd C. Miller + * MANIFEST: + add system_group plugin + [6169793b510c] - * boottime.c, get_pty.c: - Fix typos that prevented compilation on Irix; Friedrich Haubensak - [a3e6c5a66890] +2012-05-09 Todd C. Miller -2010-08-14 Todd C. Miller + * compat/dlopen.c: + Implement RTLD_NEXT and fix RTLD_DEFAULT for HP-UX. + [85bd03bc5d94] - * auth/pam.c: - If the user hits ^C while a password is being read, error out before - reading any further passwords in the pam conversation function. - Otherwise, if multiple PAM auth methods are required, the user will - have to hit ^C for each one. - [c8f6bc58fd86] +2012-05-08 Todd C. Miller -2010-08-09 Todd C. Miller + * NEWS: + Mention system_group plugin + [05393dd4bdb8] - * exec.c: - Fix waitpid() loop termination condition. - [97719b3259f2] + * Makefile.in, plugins/sudoers/Makefile.in, + plugins/system_group/Makefile.in: + update depends + [6feb0b824fc4] - * exec_pty.c: - Use sudo_waitpid() instead of bare waitpid() - [624a40269189] + * plugins/system_group/system_group.c: + Only call gr_delref() when use sudo's password caching functions. + [1103442e21fa] -2010-08-07 Todd C. Miller + * plugins/sample_group/Makefile.in, plugins/system_group/Makefile.in: + Add missing dependency on libreplace.la + [05bfd9d4657f] - * sudo.pp: - Set pp_kit_version and strip off patchlevel - [814c87778567] + * compat/dlopen.c: + Emulate RTLD_DEFAULT and RTLD_SELF w/ shl_findsym() using NULL and + PROG_HANDLE. + [2382d0693acc] - * 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] + * Makefile.in, configure, configure.in, + plugins/system_group/Makefile.in, + plugins/system_group/system_group.c, + plugins/system_group/system_group.sym: + Add group plugin that does lookups by name using the system group + database. + [2ddbb604112f] -2010-08-06 Todd C. Miller + * plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po, src/po/pl.mo, + src/po/pl.po: + sync with translationproject.org + [4ef05df4226d] - * auth/sudo_auth.c: - For non-standalone auth methods, stop reading the password if the - user enters ^C at the prompt. - [59d2b1328d1e] +2012-05-03 Todd C. Miller - * check.c: - When removing/resetting the timestamp file ignore the tty ticket - contents. - [8b285f601ec0] + * plugins/sudoers/po/eo.mo, plugins/sudoers/po/eo.po, + plugins/sudoers/po/fi.mo, plugins/sudoers/po/fi.po, + plugins/sudoers/po/ja.mo, plugins/sudoers/po/ja.po, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/uk.po, + plugins/sudoers/po/zh_CN.mo, plugins/sudoers/po/zh_CN.po, + src/po/de.mo, src/po/de.po, src/po/eo.mo, src/po/eo.po, + src/po/fi.mo, src/po/fi.po, src/po/ja.mo, src/po/ja.po, + src/po/ru.mo, src/po/ru.po, src/po/sr.mo, src/po/sr.po, + src/po/uk.mo, src/po/uk.po, src/po/vi.mo, src/po/vi.po, + src/po/zh_CN.mo, src/po/zh_CN.po: + sync with translationproject.org + [115c3f828fc5] -2010-08-04 Todd C. Miller +2012-05-01 Todd C. Miller - * UPGRADE: - Fix typo - [0f443aa22e96] + * sudo.pp: + Add mode for docdir and use '-' (default) for localedir mode. Fixes + a problem on Linux when building in a directory with the setgid bit + set. + [582279c8bcb1] -2010-08-03 Todd C. Miller +2012-04-30 Todd C. Miller - * check.c: - Do not produce a warning for "sudo -k" if the ticket file does not - exist. - [eeaaa73d7f5b] + * pp: + Match CentOS 6.0 + [1e99ef210f98] -2010-08-02 Todd C. Miller +2012-04-24 Todd C. Miller - * aclocal.m4, configure: - Add cross-compile defaults for remaining AC_TRY_RUN usage. - [fb88d22eabc6] + * NEWS: + Update with recent changes + [c5fc220ba696] -2010-07-31 Todd C. Miller + * pp: + Fix version check on AIX + [d272e39112f4] - * 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] + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen + [72b23509465a] -2010-07-30 Todd C. Miller + * plugins/sudoers/ldap.c: + Need to call ldapssl_clientauth_init() for start_tls on Mozilla LDAP + SDK. + [87b685e70b9a] - * .hgtags: - Added tag SUDO_1_7_4 for changeset 2920a3b9d568 - [e929004d5102] + * plugins/sudoers/ldap.c: + Fix printing of invalid uri + [645aa53acdde] - * pp: - Debian: Remove dots from decoded release number AIX: looser matching - of file command output for AIX 5.1 - [2920a3b9d568] [SUDO_1_7_4] + * plugins/sudoers/auth/pam.c: + Pass PAM_SILENT when deleting creds to remove an annoying warning + message on Solaris. + [1dd0301ef293] - * .hgtags: - Added tag SUDO_1_7_4 for changeset 0d844aa34c1d - [cf65ddcec602] +2012-04-23 Todd C. Miller -2010-07-29 Todd C. Miller + * src/utmp.c: + Fix the setutxent and endutxent compatibility defines (this time + correctly) when only setutent and endutent are available. + [d136d2867db9] + + * plugins/sudoers/ldap.c: + sudo_ldap_set_options_global() should not take an LDAP handle as an + argument since the options affect the global settings. + [1dc39b9d20f2] - * exec_pty.c: - exec_monitor is static - [0d844aa34c1d] + * mkpkg: + Debian sudo has not been built with --with-exempt=sudo since 1.6.8. + [c7716291a856] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + plugins/sudoers/auth/pam.c, src/exec.c, src/exec_pty.c, src/sudo.c, + src/sudo.h: + Call the policy's init_session() function before we fork the child. + That way, the session is created and destroyed in the same process, + which is needed by some modules, such as pam_mount. + [ece552ba002e] + + * doc/TROUBLESHOOTING: + Add entry for SSL LDAP errors on Mozilla SDKs when the cert dir is + not specified. + [bd293e100b28] + + * plugins/sudoers/auth/pam.c: + Delete creds after closing the PAM session. + [5158d726d6a5] + + * plugins/sudoers/ldap.c: + Provide a more useful error message if using a Mozilla-style LDAP + SDK and you forgot to specify TLS_CERT in ldap.conf. + [7cb78feb899c] + + * src/exec_pty.c: + Add missing initialization of a sigaction structure when I/O + logging. Fixes a potential problem when suspending the command. + [f4480f2ba816] + + * plugins/sudoers/ldap.c: + Split global and per-connection LDAP options into separate arrays. + Set global LDAP options before calling ldap_initialize() or + ldap_init(). After we have an LDAP handle, set the per-connection + options. Fixes a problem with OpenLDAP using the nss crypto backend; + bug #342 + [265c9d2dc12b] + + * plugins/sudoers/po/da.mo, plugins/sudoers/po/da.po, + plugins/sudoers/po/fi.mo, plugins/sudoers/po/fi.po, + plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/uk.po, + plugins/sudoers/po/zh_CN.mo, plugins/sudoers/po/zh_CN.po, + src/po/de.mo, src/po/de.po, src/po/hr.mo, src/po/hr.po, + src/po/vi.mo, src/po/vi.po, src/po/zh_CN.mo, src/po/zh_CN.po: + sync with translationproject.org + [6d7fe44be21e] + +2012-04-21 Todd C. Miller + + * src/sudo.c, src/sudo.h: + Move struct passwd pointer into struct command details. + [d6fb1eff2065] + +2012-04-20 Todd C. Miller * pp: - Update to latest version - [7b8a00defbd6] + Sync with upstream for Mac OS X (and other) fixes. + [c2f4998d01b0] -2010-07-28 Todd C. Miller + * mkpkg: + Only built Mac intel universal binary on an intel machine. + [0009e0b7e5a8] - * sudo.pp: - Let pp determine pp_aix_version itself. - [c5ee7944af03] + * src/Makefile.in: + Do not pass libtool the -static-libtool-libs option when building + sudo and sesh. Otherwise, libtool may prefer a static version of an + installed library over a dynamic one when linking. + [6fbac9adc885] - * 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] +2012-04-19 Todd C. Miller - * sudo.pp, sudoers: - Add commented out SuSE-like targetpw settings - [f4ad331ace46] + * MANIFEST, NEWS, doc/CONTRIBUTORS, plugins/sudoers/po/hr.mo, + plugins/sudoers/po/hr.po, src/po/de.mo, src/po/de.po: + Add German translation for sudo Add Croatian translation for sudoers + [fa4da1a6530c] - * 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] + * plugins/sudoers/iolog.c: + typo fix in comment + [abd721d1288e] - * configure, configure.in: - Prevent configure from adding the -g flag unless in devel mode - [e3c11f228c56] +2012-04-16 Todd C. Miller -2010-07-27 Todd C. Miller + * NEWS: + Update with recent changes + [6fa11e8448b9] - * sudo.pp: - Go back to sudo-flavor to match existing packages and only use an - underscore for those that need it. - [1f78ecf3b990] + * Makefile.in, plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + Sort xgettext output by file name. + [f650841810f0] - * sudo.pp: - Use sudo_$flavor instead of sudo-$flavor since that causes the least - amount of trouble for the various package managers. - [7e1e07115788] + * doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod: + Clarify what "sudoreplay -l" displays and mention that it is sorted. + [84031c117bd6] - * 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] + * config.h.in, configure, configure.in, src/ttyname.c: + Use AC_HEADER_MAJOR to determine where major/minor are defined. + [3c949650a223] - * configure, configure.in: - Back out version change in 5baf2187a138 - [bbc3a81afbba] + * config.h.in, configure, configure.in, src/ttyname.c: + Include sys/mkdev.h if present instead of sys/sysmacros.h for + minor(). This is needed on Solaris (at least) where the makedev + macros in sysmacros.h are obsolete and library functions should be + used instead. + [343928acf81e] * 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] + When building on Mac OS X, only set SDK_FLAGS if specified osversion + doesn't match host. + [d84c6efac872] - * configure, configure.in, mkpkg: - Use the HP ANSI C compiler on HP-UX if possible - [5baf2187a138] +2012-04-15 Todd C. Miller - * sudoreplay.c: - Some getline() implementations (FreeBSD 8.0) do not ignore the - length pointer when the line pointer is NULL as they should. - [8652300785ed] + * src/ttyname.c: + Add back buf and tty variables for _ttyname() case that were + inadvertantly removed. + [a4a820b22a44] - * sudoreplay.c: - Don't need to check for *cp being non-zero, isdigit() will do that. - [107301a99b6a] +2012-04-13 Todd C. Miller - * sudoreplay.c: - Add setlocale() so the command line arguments that use floating - point work in different locales. Since sudo now logs the timing - data in the C locale we must Parse the seconds in the timing file - manually instead of using strtod(). Furthermore, sudo 1.7.3 logged - the number of seconds with the user's locale so if the decimal point - is not '.' try using the locale-specific version. - [2b8ed181e37c] + * plugins/sudoers/po/sudoers.pot: + regen + [5446b12c1250] - * exec.c: - Do I/O logging in the C locale so the floating point numbers in the - timing file are not locale-dependent. - [18abbca14078] + * configure, configure.in: + Remove b8 from version number. + [5adc4dcec061] + + * src/ttyname.c: + remove some XXX + [187579a5f593] + + * src/ttyname.c: + When looking for a device match, do a breadth-first search instead + of depth-first. We already special case /dev/pts/ so chances are + good that if it is not a pseudo-tty it is in the base of /dev/. Also + avoid a stat(2) when possible if struct dirent has d_type. + [0183f8a1b278] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + src/sudo.c, src/sudo.h: + Pass pid, ppid, sid, pgid and tcpgid to plugin in user_info list. + [f0574d878491] + + * src/po/eo.mo, src/po/es.mo, src/po/es.po, src/po/fi.mo, + src/po/ja.mo, src/po/pl.mo, src/po/ru.mo, src/po/uk.mo, + src/po/vi.mo: + sync with translationproject.org + [4527ea78fbd5] + + * MANIFEST, NEWS, doc/CONTRIBUTORS, src/po/gl.mo, src/po/gl.po, + src/po/hr.mo, src/po/hr.po: + New Croatian and Galician translations from translationproject.org + [ad4bd924b4de] + + * src/ttyname.c: + Add depth-first traversal of /dev/ for the /proc case when not + /dev/pts/N + [499bd3456774] + + * config.h.in, configure, configure.in, plugins/sudoers/sudoreplay.c: + If struct dirent has d_type, use it to avoid an extra stat(). + [741dabbe4bcd] + + * plugins/sudoers/sudoreplay.c: + Sort output of "sudoreplay -l" + [c0615795bd4b] + +2012-04-12 Todd C. Miller + + * plugins/sudoers/sudoreplay.c: + Fix duplicate free introduced in last rev + [efdaabe69d75] + +2012-04-11 Todd C. Miller + + * plugins/sudoers/auth/pam.c: + Instead of treating ^C from tgetpass() specially, always return + AUTH_INTR if tgetpass() returned NULL. Treat PAM_AUTHINFO_UNAVAIL + like PAM_AUTH_ERR which Mac OS X returns this when there is no tty. + [a3b17298d4d0] + + * config.h.in, configure, configure.in, src/ttyname.c: + Rototill code to determine the tty. For Linux, we now look up the + tty device in /proc/pid/stat instead of trying to open + /proc/pid/fd/[0-2]. The sudo_ttyname_dev() function maps the given + device number to a string. On BSD, we can use devname(). On + Solaris, _ttyname_dev() does what we want. TODO: write /dev/ + traversal code for the generic sudo_ttyname_dev(). + [6b22be4d09f0] + +2012-04-10 Todd C. Miller + + * src/ttyname.c: + Define PRNODEV for those w/o it. + [f17290e64559] + + * config.h.in, configure, configure.in, src/ttyname.c: + Check for SVR4-style struct psinfo.pr_ttydev and use that to + determine the tty if std{in,out,err} are not ttys. + [76ad33a91f4b] + + * src/ttyname.c: + Better support for SVR4-style /proc entries where we can't use + ttyname() on the /proc/pid/fd/[0-2] entries. We can, however, + attempt to map the device number back to the correct pseudo-tty + slave device. + [4f9f48cc79eb] + + * src/ttyname.c: + When trying to determine the tty name, check parent's stderr in + addition to its stdin and stdout. + [604644056c7d] + + * src/exec_pty.c: + Treat a tty read failure like EOF as it usually means the pty has + gone away. Handle write() on the tty returning EIO. + [16957f4a706f] + + * src/exec.c, src/exec_pty.c: + Linux select() may return ENOMEM if there is a kernel resource + shortage. Older Solaris select() may return EIO instead of EBADF + when the tty goes away. If we get an unhandled select() failure, + kill the child and exit cleanly. + [d93940a311ab] + + * src/ttyname.c: + Open /proc/pid/fd/[0-2] in non-blocking mode just in case we might + block in open. + [a9f809d09d52] + +2012-04-09 Todd C. Miller + + * plugins/sudoers/set_perms.c: + Fix restoration of AIX permissions. + [30c717115988] + + * src/parse_args.c: + Allow the -k flag to be used along with the -i and -s flags. + [0653b17c97f1] + + * plugins/sudoers/sudoreplay.c: + Plug memory leak in parse_logfile() in the error path. + [9cce86fa833b] + + * plugins/sudoers/po/zh_CN.mo, plugins/sudoers/po/zh_CN.po, + src/po/da.mo, src/po/da.po, src/po/eo.po, src/po/es.po, + src/po/fi.po, src/po/it.mo, src/po/it.po, src/po/ja.po, + src/po/pl.po, src/po/ru.po, src/po/uk.po, src/po/vi.po, + src/po/zh_CN.mo, src/po/zh_CN.po: + sync with translationproject.org + [14af43d0b170] + +2012-04-08 Todd C. Miller + + * compat/regress/glob/globtest.c, config.h.in, configure, + configure.in, plugins/sudoers/match.c: + Do not use GLOB_BRACE or GLOB_TILDE flags to glob()--we want the + glob() and fnmatch() results to be consistent. + [4226750d73c2] + +2012-04-06 Todd C. Miller + + * MANIFEST, common/Makefile.in, common/ttysize.c, src/Makefile.in, + src/ttysize.c: + Move ttysize.c to common so sudoreplay can use it. + [b4a0aa514cd4] + + * plugins/sudoers/sudoreplay.c: + If I/O log file includes rows + cols, warn if the user's tty is not + big enough. + [b980ef89efff] + + * plugins/sudoers/sudoreplay.c: + Fix printing of TSID in "sudoreplay -l" + [4221e3e108b4] + + * common/sudo_debug.c, include/sudo_debug.h, + plugins/sudoers/logging.c, plugins/sudoers/visudo.c, src/exec.c, + src/exec_pty.c: + Log the process id in the debug file output. Since we don't want to + keep calling getpid(), stash the value at init time and when we + fork(). + [2782d30c024d] + + * src/exec_pty.c: + Ignore SIGTTIN and SIGTTOU in main sudo process when I/O logging. It + is better to receive EIO from read()/write() than to be suspended + when we don't expect it. Fixes a problem when our terminal is + revoked which can happen when, e.g. our sshd is killed + unceremoniously. Also, only change the value of "alive" from true to + false, never from false to true. It is possible for us to receive + notification of the child having stopped after it is already dead. + This does not mean it has risen from the grave. + [26c9fe8ce0f9] + + * src/exec_pty.c: + Distinguish between signals we received from the parent vs. those + delivered explicitly to the monitor process in debugging info. + [40716cb180e5] + +2012-04-05 Todd C. Miller + + * plugins/sudoers/check.c: + In Solaris 11, /dev/pts under the "dev" filesystem, not "devices". + Update tty_is_devpts() to match so we can determine when the tty has + been reused. + [2689665df027] + + * common/sudo_debug.c, include/error.h, include/sudo_debug.h: + Always pass __func__, __FILE__ and __LINE__ in sudo_debug_printf() + and use a new flag, SUDO_DEBUG_FILENO to specify when to use it. + This allows consumers of sudo_debug_printf() to log that data + without having to specify it manually. + [7c94c4879208] + + * src/exec_pty.c: + Make this compile after last change. + [ee09034f3266] + + * src/exec_pty.c: + Don't try to restore the terminal if we are not the foreground + process. Otherwise, we may be stopped by SIGTTOU when we try to + update the terminal settings when cleaning up. + [c48b24335456] + + * src/exec.c: + If select() return EBADF in the main event loop, one of the ttys + must have gone away so perform any I/O we can and close the bad fds. + [3bc8678c03ce] + + * common/sudo_debug.c, include/error.h, include/sudo_debug.h, + plugins/sudoers/toke.c, plugins/sudoers/toke.h, + plugins/sudoers/toke.l: + Log warning() at SUDO_DEBUG_WARN not SUDO_DEBUG_ERROR. Log the + function, file and line number in the debug log for warning() and + error(). + [894cd131f11d] + +2012-04-04 Todd C. Miller + + * common/sudo_debug.c, include/error.h, include/sudo_debug.h, + src/conversation.c: + Add SUDO_DEBUG_ERRNO flag to debug functions so we can log errno. + Use this flag when wrapping error() and warning() so the debug + output includes the error string. + [1e2c67adaf1f] + +2012-03-30 Todd C. Miller + + * NEWS: + Update for sudo 1.8.5 + [7d2b62b823fe] + + * plugins/sudoers/po/sudoers.pot: + regen + [718ad9de92cd] - * sudoreplay.c: - Use errorx() not error() for thingsthat don't set errno. - [a2e7c6793d26] + * doc/CONTRIBUTORS: + sync + [f48013aea641] -2010-07-26 Todd C. Miller + * plugins/sudoers/pwutil.c: + Use ecalloc() + [fabd23c1f271] - * sudo.pp: - Add Tru64 kit support - [40e2d21aa17f] + * src/exec_pty.c: + Don't need zero_bytes() after ecalloc() + [1a9d95cd10ef] - * pp: - Better support for 1.2.3 style versions in Tru64 kits - [f7133199a711] + * config.h.in, configure, configure.in, src/sudo_noexec.c: + Add execvpe(), exect(), posix_spawn() and posix_spawnp() wrappers to + sudo_noexec.c. + [cbaa1d4b0f8a] - * pp: - Remove apparently unnecessary use of sudo - [a667a69eeab0] + * src/utmp.c: + Fix compat setutxent and endutxent macros for systems with + setutent() but not setutxent(). From Gustavo Zacarias + [d7ce622fc5f2] - * Makefile.in: - Create timedir as part of install-dirs target. - [a2e394d694dd] +2012-03-29 Todd C. Miller - * exec_pty.c: - Handle ENXIO from read/write which can occur when reading/writing a - pty that has gone away. Fixes bugzilla 422 - [142f4c2efa17] + * configure.in: + Add ignore_result definition to AH_BOTTOM + [8d4096838a98] - * pwutil.c: - sudo_pwdup() was not expanding an empty pw_shell to _PATH_BSHELL - [82e5e46bf458] + * common/sudo_debug.c, config.h.in, plugins/sample/sample_plugin.c, + plugins/sudoers/iolog.c, plugins/sudoers/toke.c, + plugins/sudoers/toke.l, plugins/sudoers/visudo.c, src/env_hooks.c, + src/exec.c, src/exec_pty.c, src/tgetpass.c: + Fix compiler warnings on some platforms and provide a better method + of defeating gcc's warn_unused_result attribute. + [9a8f804fcc75] - * mkpkg: - platform is a pp flag not a variable - [9d0ab9b9bf0c] + * configure, configure.in: + Fix building the builtin zlib from a build dir. When a zlib dir was + specified, prepend its include path instead of appending so we get + the right zlib headers. + [5f61d591b186] + + * doc/LICENSE, zlib/adler32.c, zlib/crc32.c, zlib/crc32.h, + zlib/deflate.c, zlib/deflate.h, zlib/gzguts.h, zlib/gzlib.c, + zlib/gzread.c, zlib/gzwrite.c, zlib/infback.c, zlib/inffixed.h, + zlib/inflate.c, zlib/inftrees.c, zlib/trees.c, zlib/zconf.h.in, + zlib/zlib.h, zlib/zutil.c, zlib/zutil.h: + Update zlib to version 1.2.6 + [173c4bc4d4fc] + +2012-03-28 Todd C. Miller + + * include/missing.h: + g/c __unused which is no longer used + [7ef3f23edcd6] + + * src/env_hooks.c: + Fix compilation if RTLD_NEXT is not defined. + [d5605f468b71] + + * src/po/sr.mo, src/po/sr.po: + sync with translationproject.org + [27d559f7985d] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.cat, + doc/sudoers.man.in: + regen + [f9f63ce478b6] - * Makefile.in, mkpkg, sudo.pp: - Add simple arg parsing for mkpkg so we can set debug, flavor or - platform. - [8142ab01ccd9] + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen + [59035d82d15a] - * pp: - Make rpm backend work on AIX 5.x - [2467a79d0b4d] + * Makefile.in: + Ignore Project-Id-Version when comparing pot files. + [22feb9ede46b] + + * plugins/sudoers/bsm_audit.c: + Use error() instead of log_fatal() + [54130bda4b50] + + * plugins/sudoers/env.c: + Fix signedness of didvar in env_update_didvar() + [77048a80b3e4] + + * plugins/sudoers/iolog.c: + Quiet a compiler warning on some platforms. + [8fdcaece0400] + + * compat/fnmatch.c: + cast ctype(3) function/macro arguments from char to unsigned char to + avoid potential negative subscripting. + [bdcf7eef21ef] + + * common/setgroups.c: + Quiet a warning on systems where the gids array in setgroups() is + not prototyped as being const, even though it really is. + [fdd758c6302d] + + * src/env_hooks.c: + Quiet a compiler warning on systems where the argument to putenv(3) + is const. + [51bae2193b53] + + * plugins/sudoers/sudoreplay.c: + Undo an incorrect int -> bool conversion. + [b9a4ce320f14] + + * MANIFEST, NEWS, plugins/sudoers/po/sv.mo, plugins/sudoers/po/sv.po, + src/po/sv.mo, src/po/sv.po: + Add Swedish sudo and sudoers translations from + translationproject.org + [f7ce1de9073f] + + * plugins/sudoers/env.c: + No need to preserve ODMDIR on AIX now that we always read + /etc/environment. + [4aa04b2f0125] + +2012-03-27 Todd C. Miller + + * doc/sudoers.pod, plugins/sudoers/env.c: + When initializing the environment for env_reset, start out with the + contents of /etc/environment on AIX and login.conf on BSD. + [5717bdc321e2] + + * doc/TROUBLESHOOTING, src/sudo.c: + If we are not running with an effective uid of 0, try to give the + user enough information to debug the problem. + [fa4894896d8a] + + * plugins/sudoers/getdate.c, plugins/sudoers/gram.c: + Quiet a clang-analyzer false positive. + [c4c0c1b9c8b0] + + * src/tgetpass.c: + If there is nothing to read from the askpass program, set errno to + EINTR. This makes the cancel button behave like the user entered ^C + at the password prompt when PAM is used. + [594302cb9caf] + + * src/sudo.h, src/tgetpass.c: + Fetch the value of "askpass" from the sudo conf struct. + [4593ee8f1bd3] + + * common/sudo_conf.c: + Fix matching of "Path askpass" and "Path noexec" + [4df28d62afb9] + +2012-03-26 Todd C. Miller + + * plugins/sudoers/visudo.c: + Quiet a clang-analyzer dead store warning. + [dd90bf385a3f] + + * plugins/sudoers/sudoers.c: + If the "timestampowner" user cannot be resolved, use ROOT_UID + instead of exiting with a fatal error. + [8d62aae99715] + + * plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/kerb5.c, + plugins/sudoers/auth/pam.c, plugins/sudoers/auth/sia.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/bsm_audit.c, + plugins/sudoers/check.c, plugins/sudoers/env.c, + plugins/sudoers/iolog.c, plugins/sudoers/logging.c, + plugins/sudoers/logging.h, plugins/sudoers/parse.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c: + Remove the NO_EXIT flag to log_error() and add a log_fatal() + function that exits and is marked no_return. Fixes false positives + from static analyzers and is easier for humans to read too. + [a0fe785c2a3d] + +2012-03-24 Todd C. Miller + + * plugins/sudoers/po/eo.mo, plugins/sudoers/po/eo.po, src/po/eo.mo, + src/po/eo.po: + sync with translationproject.org + [df5e8777de13] + +2012-03-20 Todd C. Miller + + * src/po/da.mo, src/po/da.po: + sync with translationproject.org + [629d99548b78] + + * plugins/sudoers/po/da.mo, plugins/sudoers/po/da.po: + sync with translationproject.org + [9d122a2860d6] + +2012-03-19 Todd C. Miller + + * src/po/it.mo, src/po/it.po: + sync with translationproject.org + [6397593b15cf] + + * common/sudo_conf.c, plugins/sudoers/alias.c, + plugins/sudoers/defaults.c, plugins/sudoers/env.c, + plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/interfaces.c, plugins/sudoers/ldap.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/visudo.c, src/exec.c, src/exec_pty.c, src/hooks.c, + src/load_plugins.c: + Use ecalloc() when allocating structs. + [8b5888868db2] + + * common/alloc.c, include/alloc.h: + Add ecalloc() and commented out recalloc(). Use inline strnlen() + instead of strlen() in estrndup(). + [7fb9aa46c1e0] + +2012-03-18 Todd C. Miller + + * plugins/sudoers/po/fi.mo, plugins/sudoers/po/fi.po, + plugins/sudoers/po/ja.mo, plugins/sudoers/po/ja.po, + plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/uk.po, + plugins/sudoers/po/zh_CN.mo, plugins/sudoers/po/zh_CN.po, + src/po/fi.mo, src/po/fi.po, src/po/ja.mo, src/po/ja.po, + src/po/pl.mo, src/po/pl.po, src/po/ru.mo, src/po/ru.po, + src/po/uk.mo, src/po/uk.po, src/po/vi.mo, src/po/vi.po, + src/po/zh_CN.mo, src/po/zh_CN.po: + sync with translationproject.org + [45a032c37334] + +2012-03-16 Todd C. Miller + + * plugins/sudoers/set_perms.c: + Remove unused label + [2660bb0c1313] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document what changed in each plugin API revision + [59b30a6fc4d1] + + * plugins/sudoers/set_perms.c: + Remove bogus optimization that could lead to a double free of the + group list. + [b0bfbd2a83a8] + +2012-03-15 Todd C. Miller + + * doc/TROUBLESHOOTING: + Expand AIX /etc/security/privcmds entry. + [9f3f072e034e] + + * NEWS: + Update for sudo 1.8.5 + [086049011f25] + + * common/sudo_conf.c, doc/sample.sudo.conf, doc/sudo.cat, + doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudo_plugin.pod, doc/sudoers.cat, + doc/sudoers.man.in, doc/sudoers.pod, include/sudo_conf.h, + include/sudo_plugin.h, src/load_plugins.c, src/sudo.c, + src/sudo_plugin_int.h: + Rename plugin "args" to "options" + [f25624951bd2] + + * doc/CONTRIBUTORS: + Add Lithuanian and Vietnamese translators + [2b4c075b69e3] -2010-07-25 Todd C. Miller + * Makefile.in: + Ignore comments when comparing new and old pot files. + [f872999347b3] - * sudoers: - Add commented out Defaults entry for log_output - [b3fe97e59ae0] + * src/Makefile.in: + regen + [c8193b1b11c7] -2010-07-23 Todd C. Miller + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in: + regen + [15e3c17e8a3a] + + * doc/sudo_plugin.pod, include/sudo_plugin.h, + plugins/sudoers/auth/pam.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/auth/sudo_auth.h, plugins/sudoers/env.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, src/hooks.c, + src/sudo.c, src/sudo.h: + Pass a pointer to user_env in to the init_session policy plugin + function so session setup can modify the user environment as needed. + For PAM authentication, merge the PAM environment with the user + environment at init_session time. We no longer need to swap in the + user_env for environ during session init, nor do we need to disable + the env hooks at init_session time. + [3f5277b359d8] + + * plugins/sample/sample_plugin.c: + Add explicit NULL entries for init_session, register_hooks and + deregister_hooks with appropriate comments. + [727a57978b40] + + * compat/pw_dup.c: + Quiet a gcc "used uninitialized in this function" false positive. + [f14b68379ce9] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + We should always call warning() with a format string or a string + literal. In this case, the argument (path) is not user-controlled. + [e9ef51224024] + +2012-03-14 Todd C. Miller + + * src/selinux.c: + Include sudo_exec.h for the sudo_execve() prototype. + [769e58065edc] - * Makefile.in: - Install binary files with -b~ to make a backup. Fixes "text file - busy" error on HP-UX during install. - [3563e3e0163a] + * config.h.in, configure, configure.in: + Add check for pam_getenvlist() + [36bde3f26c60] - * 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] + * common/sudo_conf.c: + Set args to NULL in default plugin info struct when there is no + Plugin line in sudo.conf. + [93ec67708f01] - * configure, configure.in: - Some more ${foo} -> $(foo) conversion for consistent Makefiles. - [c214d50c32ec] + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen + [a9287677795c] -2010-07-22 Todd C. Miller + * doc/sudo.cat, doc/sudo.man.in, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudoers.cat, doc/sudoers.ldap.cat, + doc/sudoers.ldap.man.in, doc/sudoers.man.in, doc/sudoreplay.cat, + doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in: + regen + [a242769d7962] - * pathnames.h.in: - Add missing include of maillock.h for Solaris - [343f04b7a581] + * configure, configure.in: + Bump version to 1.8.5 + [e8618f0c2505] - * 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] + * doc/sudo_plugin.pod: + Document hooks API + [e6ad07d27958] - * 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] +2012-03-13 Todd C. Miller - * 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] + * sudo.pp: + Make sudoersdir relative to PKG_INSTALL_ROOT for Solaris. + [fd72340042d3] -2010-07-21 Todd C. Miller + * include/sudo_plugin.h: + Use sudo_hook_fn_t in struct sudo_hook. + [938f93112d6e] - * boottime.c, mkstemps.c: - Include time.h for struct timeval. - [50446e0b8398] + * doc/TROUBLESHOOTING: + If cross compiling, --host must include the OS in the tuple. E.g. + --host powerpc-unknown-linux + [b8c010070c1e] - * exec_pty.c: - The return value of strsignal() may be const and should be treated - as const regardless. - [c035b17b50e3] +2012-03-12 Todd C. Miller - * 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] + * plugins/sudoers/parse.c: + Fix bogus int -> bool conversion; tags can have a value of -1. + [e63d6434a303] - * Makefile.in: - fix typo - [f216d653404d] + * plugins/sudoers/env.c: + Add env_should_keep() and env_should_delete() wrapper functions to + simplify things a bit and hide the fact that matches_env_check() is + not bool. + [7a03d7a12b50] - * Makefile.in, NEWS, README, UPGRADE, WHATSNEW: - Rename WHATSNEW -> NEWS - [f3ce0a462ca0] + * sudo.pp: + Fix application of debian-specific sudoers mods when building + packages as non-root. + [34bf4c52c425] - * pp: - Updated pp with latest patches - [cded68af5ba0] + * plugins/sudoers/env.c: + matches_env_check() returns int, not boolean + [0ad915b8d5cb] - * 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] + * src/sudo_edit.c: + Fix compilation when seteuid() is not available. + [8a722f998000] - * sudoers.cat, sudoers.man.in: - regen sudoers manual - [7498a058eeb1] + * src/ttyname.c: + Simply move the free of ki_proc outside the realloc() loop. + [217b786da760] - * 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] + * src/ttyname.c: + Bring back the erealloc() for the ENOMEM loop and just zero the + pointer after we free it. + [29a016e45127] -2010-07-20 Todd C. Miller + * src/ttyname.c: + Don't try to erealloc() a potentially freed pointer; Mateusz Guzik + [266e08844065] - * sudoreplay.c: - Add LINE_MAX define for those without it. - [6248dd44573c] +2012-03-10 Todd C. Miller - * WHATSNEW: - Mention that tty_tickets is now the default. - [4cf26eaee5ba] + * plugins/sudoers/set_perms.c: + Use normal error path if unable to set sudoers gid. + [01c816918c99] - * 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] + * plugins/sudoers/set_perms.c: + Make this work again on systems w/o seteuid(). + [2e67f7421e97] - * WHATSNEW: - Mention that AIX authdb support has been fixed. - [9331829dc276] +2012-03-09 Todd C. Miller - * 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] + * plugins/sudoers/set_perms.c: + Fix compilation if no seteuid/setreuid/setresuid available. + [d0b3c1f88eb4] -2010-07-19 Todd C. Miller + * plugins/sudoers/set_perms.c: + Better error messages, and added debugging throughout. Fixed + seteuid() version of set_perms()/restore_perms(). Fixed logic bug in + AIX version of restore_perms(). Added checks to avoid changing + uid/gid when we don't have to. Never set gid/uid state to -1, use + the old value instead. + [29188d469b5c] - * sudoers.cat, sudoers.man.in, sudoers.pod: - Mention new handling of HOME in always_set_home and set_home - descriptions. - [a69c9bed3164] + * src/exec_pty.c, src/ttyname.c: + Fix format string warning on Solaris with gcc 3.4.3. + [d1eeb6e1dd0f] - * sudo.cat, sudo.man.in, sudo.pod: - fix typo - [9b90bb3e9187] + * src/sudo.c: + Always declare environ now that we swap it around unilaterally. + [aaa3e92e7d0d] - * 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] + * src/Makefile.in: + Honor LDFLAGS when linking sesh; from Vita Cizek + [498b41438f6e] - * sudoers.cat, sudoers.man.in, sudoers.pod: - The default for set_logname has been "true" for some time now. - [9f97e4b43a4b] + * src/sesh.c: + Include alloc.h for estrdup() prototype; from Vita Cizek + [93203655a320] - * sudoers.cat, sudoers.man.in, sudoers.pod: - Document that MAIL it set in env_reset mode. - [dcf9ad98079e] +2012-03-08 Todd C. Miller - * boottime.c: - Add missing include of time.h - [57bee414982d] + * plugins/sudoers/sudoers.c: + Don't read /etc/environment on Linux when using PAM, PAM should set + the environment variables as needed via pam_env. + [b1ef62cb2d40] - * defaults.c, sudo.c: - Check return value of setdefs() but don't stop setting defaults if - we hit an unknown one. - [a42cb2d6b7ed] + * INSTALL: + Fix editor goof. + [0c3dd3bb8b57] + + * src/hooks.c, src/sudo.c, src/sudo.h: + Disable environment hooks after we get user_env back to make sure a + plugin can't to modify user_env after we "own" it. This is kind of + a hack but we don't want the init_session plugin function to modify + user_env. + [8e6d119452a5] + + * src/hooks.c, src/sudo.c: + Add support for deregistering hooks. If an I/O log plugin fails to + initialize, deregister its hooks (if any). + [ac00c93900c5] + +2012-03-07 Todd C. Miller + + * plugins/sudoers/sudoers.c, src/sudo.c: + Move LOGIN_PATH and LOGIN_SETENV handling to plugin now that we hook + setenv. + [e75469dd9908] + + * MANIFEST, aclocal.m4, common/sudo_debug.c, compat/Makefile.in, + compat/setenv.c, compat/unsetenv.c, config.h.in, configure, + configure.in, include/sudo_debug.h, include/sudo_plugin.h, mkdep.pl, + plugins/sudoers/auth/aix_auth.c, plugins/sudoers/env.c, + plugins/sudoers/ldap.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/Makefile.in, src/env_hooks.c, + src/hooks.c, src/load_plugins.c, src/sudo.c, src/sudo.h, + src/sudo_plugin_int.h: + Initial cut at a hooks implementation. The plugin can register + hooks for getenv, putenv, setenv and unsetenv. This makes it + possible for the plugin to trap changes to the environment made by + authentication methods such as PAM or BSD auth so that such changes + are reflected in the environment passed back to sudo for execve(). + [61cffa06f863] + +2012-03-05 Todd C. Miller + + * MANIFEST, src/po/vi.mo, src/po/vi.po: + Add Vietnamese sudo translation from translationproject.org + [96df426790d5] + +2012-03-02 Todd C. Miller + + * doc/sample.sudo.conf, doc/sudo.pod, doc/sudo_plugin.pod, + doc/sudoers.pod: + List sudo_noexec.so not noexec.so in the sample sudo.conf + [53844e190ec5] + + * common/sudo_conf.c, doc/sample.sudo.conf, doc/sudo.pod, + doc/sudo_plugin.pod, doc/sudoers.pod, include/sudo_conf.h, + include/sudo_plugin.h, plugins/sample/sample_plugin.c, + plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c, + plugins/sudoers/toke.l, src/load_plugins.c, src/sudo.c, + src/sudo_plugin_int.h: + Add support for plugin args at the end of a Plugin line in + sudo.conf. Bump the minor number accordingly and update the + documentation. A plugin must check the sudo front end's version + before using the plugin_args parameter since it is only supported + for API version 1.2 and higher. + [587f1f819536] + +2012-03-01 Todd C. Miller + + * plugins/sudoers/Makefile.in: + update depends + [6d2da44e11e5] + + * MANIFEST: + secure_path.c is in common, not compat + [619c4a663dde] - * logging.c: - Fix check for dup2() return value. - [916cd7fdeba7] + * configure, configure.in: + Add check for variadic macro support in cpp. + [756854caf675] - * visudo.c: - Treat an unknown defaults entry as a parse error. - [1f94675835d9] +2012-02-29 Todd C. Miller - * env.c: - Check KEPT_MAIL not DID_MAIL when determining whether to set MAIL in - -i and env_reset mode. - [aa6657ccfe01] + * common/secure_path.c, common/sudo_conf.c, include/secure_path.h, + plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add type param to sudo_secure_path() and add sudo_secure_file() and + sudo_secure_dir() wrappers which get by #includedir in sudoers. + [2ec2d3d8df04] - * env.c: - Add PYTHONUSERBASE to initial_badenv_table - [93058374f0d9] +2012-02-28 Todd C. Miller - * 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] + * doc/visudo.pod, plugins/sudoers/visudo.c: + Check the owner and mode in -c (check) mode unless the -f option is + specified. Previously, the owner and mode were checked on the main + sudoers file when the -s (strict) option was given, but this was not + documented. + [b2d6ee1e547a] -2010-07-17 Todd C. Miller + * config.h.in, configure, configure.in, src/ttyname.c: + Prefer KERN_PROC2 over KERN_PROC. Fixes compilation on some + versions of OpenBSD versions that have KERN_PROC2 but not KERN_PROC. + [159f6a50456a] - * pp: - decode debian code names - [2df0ecbc23b4] +2012-02-27 Todd C. Miller - * WHATSNEW: - fix typo - [b66a95fa1869] + * doc/CONTRIBUTORS: + Add Eric Lakin for patch in bug #538 + [490c29c234c6] -2010-07-16 Todd C. Miller + * src/exec_pty.c: + Fix typo in safe_close() made while converting to debug framework + that prevented it from actually closing anything. + [a66422a62afd] - * WHATSNEW: - Add entry about SuSE bash script fix. - [04af78fa281c] + * src/exec_pty.c: + Add some more debugging. + [b5667947dda9] - * 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] + * common/Makefile.in, compat/Makefile.in, doc/Makefile.in, + include/Makefile.in: + We need sysconfdir in compat/Makfile to get the proper sudo.conf + path. Add standard prefix and foodir expansion in all Makefiles to + avoid this problem in the future. + [62b6ce4ecae9] -2010-07-15 Todd C. Miller +2012-02-25 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] + * MANIFEST, plugins/sudoers/po/lt.mo, plugins/sudoers/po/lt.po: + New Lithuanian sudoers translation from translationproject.org + [10436b649035] -2010-07-16 Todd C. Miller + * plugins/sudoers/po/ja.po: + Update from translationproject.org + [acb8db5f8ef1] - * WHATSNEW: - Mention polypkg - [c5f6e40bbb58] +2012-02-24 Todd C. Miller - * README, WHATSNEW: - Update for sudo 1.7.4 - [0c688f1f8160] + * plugins/sudoers/ldap.c: + When adding gids to the LDAP filter, only add the primary gid once. + This is consistent with the space computation/allocation. From Eric + Lakin + [35d9d99c92c6] - * INSTALL: - document --with-pam-login - [33ca3f6308ae] + * doc/TROUBLESHOOTING: + Add entry for AIX enhanced RBAC config. + [5e10b6f8def7] - * sudoers.cat, sudoers.man.in, sudoers.pod: - The tag is NOSETENV, not UNSETENV. From Petr Uzel. - [95f37e63ca15] - -2010-07-15 Todd C. Miller + * mkpkg: + Target Mac OS X 10.5 when building packages. + [06fce9bbebee] + +2012-02-22 Todd C. Miller + + * MANIFEST, common/Makefile.in, common/secure_path.c, + common/sudo_conf.c, include/secure_path.h, + plugins/sudoers/Makefile.in, plugins/sudoers/sudoers.c: + Relax the user/group/mode checks on sudoers files. As long as the + file is owned by the right user, not world-writable and not writable + by a group other than the one specified at configure time (gid 0 by + default), the file is considered OK. Note that visudo will still + set the mode to the value specified at configure time. + [241174babfcc] + +2012-02-21 Todd C. Miller + + * plugins/sudoers/set_perms.c: + Add AIX-specific version of permission setting code to make sure + that the saved uid gets restored properly. + [9a6f5d22c301] + + * config.h.in, configure, configure.in, src/exec_common.c: + Check for LD_PRELOAD variants in configure instead of checkign cpp + symbols. In disable_execute(), compute the length of the new envp + and allocate it once instead of reallocating on demand. Also append + old value of LD_PRELOAD (if any) to the new value. + [680266346917] + + * plugins/sudoers/def_data.c, plugins/sudoers/def_data.in: + Fix the description of noexec. + [6a6d142f3c80] + + * plugins/sudoers/defaults.c, plugins/sudoers/defaults.h: + The "op" parameter to set_default() must be int, not bool since it + is set to '+' or '-' for list add and subtract. + [8da5b137bea2] * sudo.pp: - Include flavor in solaris package name - [b6d56ccf367e] + Make sure sudoers is writable before calling ed script. + [95352ab6336b] - * mkpkg: - Older shells don't support IFS= so set explictly to space, tab, - newline. - [336925525e17] +2012-02-17 Todd C. Miller - * mkpkg: - Use '=' not '==' in test - [98c692271cfd] + * doc/CONTRIBUTORS, doc/contributors.pod: + Update contributors. Now includes translators and authors of compat + code. + [4fb5b616b50a] - * mkpkg: - Fix typo that prevented debian from matching - [af4deec35e37] +2012-02-16 Todd C. Miller - * mkpkg: - Add missing prefix setting for debian - [d0c1941cb6ec] + * src/po/sudo.pot: + regen + [2c86e2c328fe] - * 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] + * pp, sudo.pp: + Build flat packages, not package bundles, on Mac OS X. + [57bda3cd5520] + +2012-02-10 Todd C. Miller * 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] + Move macos section to be with the other OS-specific sections. + [51423bb2973a] - * sudoers: - Add commented out env_keep entries, sample Aliases and a %sudo line - for debian. - [8264e4ed42dc] + * plugins/sudoers/po/eo.mo, plugins/sudoers/po/eo.po, + plugins/sudoers/po/zh_CN.mo, plugins/sudoers/po/zh_CN.po: + Sync with translationproject.org + [8ce41cbb8da0] * configure, configure.in: - Remove check for egrep; configure has its own - [27b3d85ebf4f] + Don't permanently add -D_FORTIFY_SOURCE=2 to CPPFLAGS + [fa979aa6fe7d] - * configure.in: - Use enable_zlib instead of enableval for consistency - [4a15cfd43d3e] + * sudo.pp: + Add Mac OS X support, printing the latest chunk of the NEWS file and + the license text in the installer. + [ffeab72387c0] -2010-07-14 Todd C. Miller + * sudo.pp: + Add explicit file modes that match those used by "make install" + [7eb37242c920] - * mkpkg: - Enable zlib for linux distros - [fcab91448bb0] + * pp: + Sync with upstream for Mac OS X fixes. + [97cba179041e] + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Got back to using "install-sh -M" for files installed as non- + readable by owner. This fixes "make install" as non-root for + package building. + [967804ee77d6] + +2012-02-09 Todd C. Miller + + * plugins/sudoers/po/da.mo, plugins/sudoers/po/da.po, + plugins/sudoers/po/eo.mo, plugins/sudoers/po/eo.po, + plugins/sudoers/po/fi.mo, plugins/sudoers/po/fi.po, + plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/uk.po: + Sync with translationproject.org + [0e53db12039a] + + * Makefile.in, doc/Makefile.in, include/Makefile.in, + plugins/sample/Makefile.in, plugins/sample_group/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Use -m not -M for install-sh for everything except setuid. Install + locale .mo files mode 0444, not 0644. If timedir parent doesn't + exist, use default dir mode, not 0700. + [8b6f64c92090] + +2012-02-07 Todd C. Miller + + * pp: + Re-sync with upstream; no longer need a local patch. + [97a2c7be5e59] * mkpkg: - Add ldap flavor to default build - [e35a577c8994] + Add support for building Mac OS X packages. + [94d49ac223a4] - * mkpkg, sudo.pp: - Simplify rpm linux distro settings - [f30547765636] + * pp: + Sync with upstream + [1c97654fc841] - * 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] + * src/Makefile.in: + No longer need to define _PATH_SUDO_CONF here. + [2560905b7482] - * Makefile.in, mkpkg, sudo.pp: - Add ldap "flavor" for debian, controlled by the SUDO_FLAVOR - environment variable. - [9f418defc08a] + * src/exec_common.c: + Fix noexec for Mac OS X. + [b7a744bca2c0] - * sudo.pp: - Create sudo group on debian - [4b0cc7b8b0b5] +2012-02-06 Todd C. Miller - * mkpkg, sudo.pp: - Add debian 4/5/6 and use the dot when doing version matches - [d5184f0a1efc] + * common/Makefile.in: + Move _PATH_SUDO_CONF override to common to match sudo_debug.c + [f0788972a63a] - * sudoers.cat, sudoers.man.in, sudoers.pod: - Remove spurious "and"; from debian - [8b9f2a5937bc] + * plugins/sudoers/set_perms.c: + More complete fix for LDR_PRELOAD on AIX. The addition of + set_perm(PERM_ROOT) before calling the nss open functions (needed to + avoid a GNU TLS bug) also broke LDR_PRELOAD. Setting the effective + and then real uid to 0 for PERM_ROOT works around the issue. + [5888eda051af] - * aclocal.m4, configure: - Use a loop when searching for mv, sendmail and sh - [a1c7d19721a4] + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen + [997fe403e219] + + * src/sudo.c: + Set real uid to root before calling sudo_edit() or run_command() so + that the monitor process is owned by root and not by the user. + Otherwise, on AIX at least, the monitor process shows up in ps as + belonging to the user (and can be killed by the user). + [d4772d7d2fc5] + + * plugins/sudoers/set_perms.c: + For PERM_ROOT when using setreuid(), only set the euid to 0 prior to + the call to setuid(0) if the current euid is non-zero. This + effectively restores the state of things prior to rev 7bfeb629fccb. + Fixes a problem on AIX where LDR_PRELOAD was not being honored for + the command being executed. + [b9b40325b4dc] + + * MANIFEST, compat/pw_dup.c, config.h.in, configure, configure.in, + include/missing.h, src/sudo.c: + Make a copy of the struct passwd in exec_setup() to make sure + nothing in the policy init modifies it. + [b721261c921f] + +2012-02-05 Todd C. Miller + + * doc/sudoers.pod: + update copyright + [f9d229d1f65e] + + * common/sudo_debug.c, include/sudo_debug.h: + g/c now-unused debug subsystems + [8f21726e698f] + + * doc/sudo.pod, doc/sudoers.pod: + Enumerate the debug subsystems used by sudo and sudoers. + [ac4f84293d14] + +2012-02-03 Todd C. Miller + + * NEWS, common/sudo_conf.c, doc/sample.sudo.conf, doc/sudo.pod, + include/sudo_conf.h, src/sudo.c: + Normally, sudo disables core dumps while it is running. This + behavior can now be modified at run time with a line in sudo.conf + like "Set disable_coredumps false" + [ad14e0508b0d] + + * NEWS: + Mention Spanish translation + [600f3205bd6e] + + * common/sudo_debug.c: + Make sure we don't try to fall back to using the conversation + function for debugging in the main sudo process if we are unable to + open the debug file. + [ffa329aa908c] + + * MANIFEST, src/po/es.mo, src/po/es.po: + Add sudo Spanish translation from translationproject.org + [c1906654e740] + +2012-02-02 Todd C. Miller + + * plugins/sudoers/iolog.c: + Better debug subsystem usage + [1a31f115743c] + + * src/sudo.c: + Remove duplicate function prototypes + [ae04b00532eb] + +2012-02-01 Todd C. Miller - * 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] + * configure, configure.in: + Error out if user specified --with-pam but we can't find the headers + or library. Also throw an error if the headers are present but the + library is not and vice versa. + [d6bf3e3d0aae] -2010-07-13 Todd C. Miller +2012-01-31 Todd C. Miller - * mkpkg, pp, sudo.pp: - Initial debian 4.0 support - [6d73c000723f] + * plugins/sudoers/sudoers.c: + Fix the sudoers permission check when the expected sudoers mode is + owner-writable. + [8b0b7e770a22] - * mkpkg: - Some platforms need -fPIE instead of -fpie - [8533a29633e8] +2012-01-30 Todd C. Miller - * Makefile.in: - Add packaging bits to DISTFILES - [dea9f374f28b] + * configure, configure.in: + Verify that we can link executables built with -D_FORTIFY_SOURCE + before using it. + [7578215d1a95] - * 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] + * src/exec_common.c: + Fix potential off-by-one when making a copy of the environment for + LD_PRELOAD insertion. Fixes bug #534 + [cc699cd551b6] - * sudo.psf: - We now use pp to generate HP-UX packages - [6c9f8ae6bc11] + * configure, configure.in: + Add rudimentary check for _FORTIFY_SOURCE support by checking for + __sprintf_chk, one of the functions used by gcc to support it. + [a992673d2ef8] -2010-07-12 Todd C. Miller + * compat/stdbool.h, config.h.in, configure, configure.in: + Use AC_HEADER_STDBOOL instead of checking for stdbool.h ourselves. + [8ba1370884b3] - * auth/pam.c: - Fix indentation - [e52e9e6338d5] +2012-01-29 Todd C. Miller - * INSTALL, Makefile.in: - isntall-man -> install-doc - [02cc8198ea7a] + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen + [1e0b38397705] + +2012-01-25 Todd C. Miller + + * src/exec.c, src/sudo.c: + The change in 818e82ecbbfc that caused to exit when the monitor dies + created a race condition between the monitor exiting and the status + being read. All we really want to do is make sure that select() + notifies us that there is a status change when the monitor dies + unexpectedly so shutdown the socketpair connected to the monitor for + writing when it dies. That way we can still read the status that is + pending on the socket and select() on Linux will tell us that the fd + is ready. + [7fb5b30ea48d] + + * MANIFEST, src/Makefile.in, src/exec.c, src/exec_common.c, + src/exec_pty.c, src/selinux.c, src/sesh.c, src/sudo.c, src/sudo.h, + src/sudo_exec.h: + Refactor disable_execute() and my_execve() into exec_common.c for + use by sesh.c. This fixes NOEXEC when SELinux is used. Instead of + disabling exec in exec_setup(), disable it immediately before + executing the command. Adapted from a diff by Arno Schuring. + [ec4d8b53db6b] + +2012-01-20 Todd C. Miller + + * aclocal.m4, configure, configure.in: + Add custom version of AC_CHECK_LIB that uses the extra libs in the + cache value name. With this we no longer need to rely on a modified + version of autoconf. + [1c3b1d482d6c] + +2012-01-19 Todd C. Miller + + * configure, configure.in: + Better handling of network functions that need -lsocket -lnsl + [cc386342ec2b] + + * src/sudo.c: + When setting up the execution environment, set groups before + gid/egid like sudo 1.7 did. + [928e1c5fa6c1] + + * configure, configure.in: + Remove "WARNING: unable to find foo() trying -lsocket -lnsl" + [84b23cdf138f] + + * plugins/sudoers/sudoers.c: + For "sudo -g" prepend the specified group ID to the beginning of the + groups list. This matches BSD convention where the effective gid is + the first entry in the group list. This is required on newer + FreeBSD where the effective gid is not tracked separately and thus + setgroups() changes the egid if this convention is not followed. + Fixes bug #532 + [782d6909108b] + +2012-01-17 Todd C. Miller + + * configure, configure.in: + Fix sh warning; use "test" instead of "[" + [c6ee3407f65e] + + * src/exec.c: + When not logging I/O, use a signal handler that only forwards + SIGINT, SIGQUIT and SIGHUP when they are user-generated signals. + Fixes a race in the non-I/O logging path where the command may + receive two keyboard-generated signals; one from the kernel and one + from the sudo process. + [9638684e786a] + + * src/exec.c: + Back out change that put the command in its own pgrp when not + logging I/O. It causes problems with pipelines. + [4fc9c6e1e770] + +2012-01-16 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 to 1.7.4 - [df6ce4ea908a] + * compat/Makefile.in, configure, configure.in: + Only run compat regress tests on compat objects we actually build. + Fixes "make check" in the compat dir for systems that don't + implement character classes in fnmatch() or glob(). Bug #531 + [a7addc305e83] - * INSTALL.binary, Makefile.binary.in, Makefile.in: - Remove remaining bits of the old binary package - [8d4f82c23c22] +2012-01-14 Todd C. Miller + + * plugins/sudoers/po/da.mo, plugins/sudoers/po/da.po: + Update po files from translationproject.org + [5ea066af1356] + +2012-01-13 Todd C. Miller * sudo.pp: - Use http://rc.quest.com/topics/polypkg/ for packaging - [d71793085629] + Include parent directories in case they don't already exist. This + fixes a directory permissions problem with the AIX package when the + /usr/local directories don't already exist. + [a14f783dc827] - * Makefile.in, mkpkg, pp: - Use http://rc.quest.com/topics/polypkg/ for packaging - [675e505758c5] + * pp: + sync with git version + [2f79d0543661] - * install-sh: - Just ignore the -c option, it is the default Add support for -d - option - [2adfb3a63231] + * common/Makefile.in, plugins/sudoers/Makefile.in, src/Makefile.in: + regen dependencies + [24c92ca6c64d] - * env.c, logging.c, pathnames.h.in: - Use _PATH_STDPATH instead of _PATH_DEFPATH - [2c22d54a1f02] + * MANIFEST, src/Makefile.in, src/sudo.c, src/sudo.h, src/ttyname.c: + Move tty name lookup code to its own file. + [58faf072cbf4] - * Makefile.in: - Do not strip binaries. - [bc84682b372c] +2012-01-12 Todd C. Miller + + * NEWS: + Update with latest sudo 1.8.4 changes. + [a4ffe4f42528] + + * config.h.in, configure, configure.in: + Remove obsolete template for HAVE_TIMESPEC + [75709007c906] + + * src/sudo.c: + Add a check for devname() returning a fully-qualified pathname. None + of the devname() implementations do this today but you never know + when this might change. + [16813ace38f9] + +2012-01-11 Todd C. Miller + + * plugins/sudoers/visudo.c: + For "visudo -c" also list include files that were checked when + everything is OK. + [ad6f85b35c9c] + + * src/sudo.c: + The device name returned by devname() does not include the /dev/ + prefix so we need to add it ourselves. + [b55285abb7ed] + + * src/sudo.c: + Add debug warning if KERN_PROC sysctl fails or devname() can't + resolve the tty device to a name. + [b5a23916ba3a] + + * common/sudo_debug.c: + The result of writev() is never checked so just cast to NULL. + [4be4e9b58d5b] + + * plugins/sudoers/po/eo.mo, plugins/sudoers/po/eo.po, + plugins/sudoers/po/fi.mo, plugins/sudoers/po/fi.po, + plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/uk.po: + Update Esperanto, Finnish, Polish and Ukrainian translations from + translationproject.org. + [bb91bc6ad7e9] + +2012-01-10 Todd C. Miller + + * config.h.in, configure, configure.in, src/sudo.c: + Add support for determining tty via sysctl on other BSD variants. + [fd15f63f719a] + + * configure, configure.in: + Only check for struct kinfo_proc.ki_tdev on systems that support + sysctl. + [109b3f07a39d] + + * src/sudo.c: + For FreeBSD, try the KERN_PROC_PID sysctl() first, falling back on + ttyname() of std{in,out,err}. + [95969b70bd68] + +2012-01-09 Todd C. Miller + + * config.h.in, configure, configure.in, src/sudo.c: + On newer FreeBSD we can get the parent's tty name via sysctl(). + [3207290501ee] + + * plugins/sudoers/testsudoers.c: + Include locale.h + [a602cd0b8c2d] + + * src/sudo.c: + Silence a gcc warning. + [8c6d0e3cd534] + + * plugins/sudoers/bsm_audit.c: + Need to include gettext.h and sudo_debug.h; from John Hein + [447912aa7300] + + * plugins/sudoers/iolog.c: + Initialize the debug framework from the I/O plugin too. + [ce1bf44d96d2] + +2012-01-08 Todd C. Miller + + * plugins/sudoers/testsudoers.c: + Enable debugging via sudo.conf. + [d85669c749d0] + +2012-01-07 Todd C. Miller + + * plugins/sudoers/visudo.c: + Use SUDO_DEBUG_ALIAS for alias checking functions. + [fb84af30dc76] + + * configure, configure.in: + More complete test for getaddrinfo() that doesn't rely on the + network libraries already being added to LIBS. + [cbaf2369f4f0] + +2012-01-06 Todd C. Miller + + * common/aix.c: + Add debug support. + [def1bdf24485] + + * configure, configure.in: + Need -lsocket -lnsl for getaddrinfo(3) on Solaris at least. + [a2ea1c2eac61] + + * compat/getaddrinfo.c: + Include errno.h and missing.h + [7d15e17cc2f2] + + * .hgignore: + ignore doc/varsub + [417f9fc3231b] + + * configure.in, doc/visudo.pod, plugins/sudoers/Makefile.in, + plugins/sudoers/gram.y, plugins/sudoers/match.c, + plugins/sudoers/parse.c, plugins/sudoers/testsudoers.c, src/exec.c, + src/parse_args.c, src/sudo.c, src/sudo.h: + Update copyright year. + [5d0ffc7dd567] + + * NEWS: + Update for sudo 1.8.4 + [841e3eff9844] + + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen pot files + [c509cb45b66a] + + * plugins/sudoers/sudoreplay.c: + Enable debugging via sudo.conf. + [5087aaee8484] + + * plugins/sudoers/visudo.c: + Enable debugging via sudo.conf. + [04b067c16ed3] + + * plugins/sudoers/visudo.c: + Allow "visudo -c" to work when we only have read-only access to the + sudoers include files. + [d8c6713fe5c1] + + * doc/sudo.pod, doc/visudo.pod: + Mention the CONTRIBUTORS file, not HISTORY in AUTHOR section. Add + HISTORY section in sudo that points to HISTORY file. + [d1f1bcb051c5] + + * doc/sudo.pod, doc/sudo_plugin.pod: + Document Debug setting in sudo.conf and debug_flags in plugin. + [acfc505aa4a9] + +2012-01-05 Todd C. Miller + + * plugins/sudoers/match.c: + Do not include GLOB_MARK in the flags we pass to glob(3). Fixes a + bug where a pattern like "/usr/*" include /usr/bin/ in the results, + which would be incorrectly be interpreted as if the sudoers file had + specified a directory. From Vitezslav Cizek. + [0cdb6252188c] + + * INSTALL, config.h.in, configure, configure.in, + plugins/sudoers/auth/kerb5.c: + Add --enable-kerb5-instance configure option to allow people using + Kerberos V authentication to use a custom instance. Adapted from a + diff by Michael E Burr. + [e83af8bb7aa7] + + * doc/sudo.pod, src/parse_args.c, src/sudo.c, src/sudo.h: + Remove -D debug_level option. + [cbcd05094347] + + * doc/LICENSE: + Update copyright year. + [9f43dd7aa852] + +2012-01-04 Todd C. Miller + + * plugins/sudoers/parse.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/visudo.c: + parse_error is now bool, not int + [5ea7fb6fda38] + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/parse.c: + Print a more sensible error if yyparse() returns non-zero but + yyerror() was not called. + [d44ec88f1183] + + * plugins/sudoers/Makefile.in, plugins/sudoers/getdate.c, + plugins/sudoers/gram.c: + Replace y.tab.c with the correct filename in #line directives. + [3c84fcb7e959] + +2012-01-03 Todd C. Miller + + * src/sudo.c: + When trying to determine the tty, fall back on /proc/ppid/fd/{0,1,2} + if the main process's fds 0-2 are not hooked up to a tty. Adapted + from a diff by Zdenek Behan. + [b9dfce12af85] + + * src/exec.c: + When not logging I/O, put command in its own pgrp and make that the + controlling pgrp if the command is in the foreground. Fixes a race + in the non-I/O logging path where the command may receive two + keyboard-generated signals; one from the kernel and one from the + sudo process. + [d0e263ce496c] + +2011-12-20 Todd C. Miller + + * src/sudo_edit.c: + Quiet a bogus gcc warning. + [2009669e0608] + + * src/parse_args.c, src/sudo.h: + Fix warnings related to sudo.conf accessors. + [08ddc29ba50b] + + * common/sudo_conf.c, include/sudo_conf.h: + Separate sudo.conf parsing from plugin loading and move the parse + functions into the common lib so that visudo, etc. can use them. + [f1fc659a8079] + + * MANIFEST, common/Makefile.in, src/Makefile.in, src/load_plugins.c, + src/parse_args.c, src/sudo.c, src/sudo_plugin_int.h: + Separate sudo.conf parsing from plugin loading and move the parse + functions into the common lib so that visudo, etc. can use them. + [e1f2cf6bd57a] + + * doc/sudoers.pod, plugins/sudoers/def_data.c, + plugins/sudoers/def_data.h, plugins/sudoers/def_data.in, + plugins/sudoers/sudoers.c, src/sudo.c: + Remove support for noexec_file in sudoers and the plugin API + [3e2fd58879b5] + + * plugins/sudoers/sudoers.c: + Don't dump interfaces if there are none. + [9081bb4d3e9e] + + * plugins/sudoers/def_data.c, plugins/sudoers/def_data.in: + Add missing %s printf escape to the group_plugin, iolog_dir and + iolog_file descriptions. + [7db03f2b737e] + +2011-12-18 Todd C. Miller + + * plugins/sudoers/def_data.c, plugins/sudoers/def_data.in, src/exec.c: + Fix typo in visiblepw description; from Joel Pickett + [2fb4b26d5c2c] + +2011-12-08 Todd C. Miller + + * MANIFEST, configure, configure.in, mkdep.pl, + plugins/sudoers/Makefile.in, plugins/sudoers/env.c, + plugins/sudoers/login_class.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/sudo.c: + When running a login shell with a login_class specified, use + LOGIN_SETENV instead of rolling our own login.conf setenv support + since FreeBSD's login.conf has more than just setenv capabilities. + This requires us to swap the plugin-provided envp for the global + environ before calling setusercontext() and then stash the resulting + environ pointer back into the command details, which is kind of a + hack. + [ad4f1190143b] + + * plugins/sudoers/Makefile.in: + If srcdir is "." just use the basename of the yacc/lex file when + generating the C version. This matches the generated files + currently in the repo. + [0b11c3df87a8] + + * doc/Makefile.in, plugins/sudoers/Makefile.in: + Clean up the DEVEL noise + [9de2afe457fd] + + * src/exec.c: + Handle different Unix domain socket (actually socketpair) semantics + in BSD vs. Linux. In BSD if one end of the socketpair goes away + select() returns the fd as readable and the read will fail with + ECONNRESET. This doesn't appear to happen on Linux so if we notice + that the monitor process has died when I/O logging is enabled, + behave like the command has exited. This means we log the wait + status of the monitor, not the command, but there is nothing else we + can do at that point. This should only be an issue if SIGKILL is + sent to the monitor process. + [818e82ecbbfc] + + * src/exec_pty.c: + Catch common signals in the monitor process so they get passed to + the command. Fixes a problem when the entire login session is + killed when ssh is disconnected or the terminal window is closed. + Previously, the monitor would exit and plugin's close method would + not be called. + [0e4658263138] * 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] + Mention how to configure pam_hpsec on HP-UX to play nicely with + sudo. + [a7294cd8ce98] + +2011-12-07 Todd C. Miller + + * plugins/sudoers/ldap.c: + Escape values in the search expression as per RFC 4515. + [c2adbc5db92b] + + * doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in: + No need for install target to depend explicitly on install-dirs, the + install-foo targets all depend on it. + [62a36ed98279] + +2011-12-05 Todd C. Miller + + * .hgignore: + ignore src/sesh + [463d492f6782] + + * MANIFEST, common/Makefile.in, configure, configure.in, mkdep.pl, + plugins/sample/Makefile.in, plugins/sample_group/Makefile.in, + plugins/sudoers/Makefile.in, plugins/sudoers/env.c, + plugins/sudoers/login_class.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/Makefile.in: + Add support for setenv entries in login.conf. We can't use + LOGIN_SETENV since the plugin sets up the envp the command is + executed with. Also regen the Makefile.in files while here. Fixes + bug #527 + [088d507926e2] + +2011-12-02 Todd C. Miller + + * MANIFEST, aclocal.m4, compat/getaddrinfo.c, compat/getaddrinfo.h, + config.h.in, configure, configure.in, plugins/sudoers/sudoers.c, + src/net_ifs.c: + Add getaddrinfo() for those without it, written by Russ Allbery + [4cf9ac831222] + + * doc/Makefile.in: + Restore PACKAGE_TARNAME, it is used in docdir + [9d65e893edb1] + + * MANIFEST, compat/stdbool.h: + SunPro C Compiler also has a _Bool builtin. Also add stdbool.h to + the MANIFEST + [e67700dc5621] + + * common/atobool.c, common/term.c, src/exec.c: + Remove duplicate return statements. + [48a20d5215fd] + + * plugins/sudoers/auth/bsdauth.c: + Remove inaccurate comment + [e7f0265cf657] + + * plugins/sudoers/auth/bsdauth.c, plugins/sudoers/sudoers.c: + Fetch the login class for the user we authenticate specifically when + using BSD authentication. That user may have a different login + class than what we will use to run the command. When setting the + login class for the command, use the target user's struct passwd, + not the invoking user's. Fixes bug 526 + [21bf0af892f7] + + * compat/Makefile.in, configure, configure.in, doc/Makefile.in, + plugins/sudoers/Makefile.in: + Replace @DEV@ prefix with DEVEL variable so we can do "make DEVEL=1" + [8ee6e0891f27] + + * plugins/sudoers/regress/iolog_path/check_iolog_path.c, + plugins/sudoers/regress/logging/check_wrap.c, + plugins/sudoers/regress/parser/check_addr.c, + plugins/sudoers/regress/parser/check_fill.c: + Fix "make check" fallout from the sudo_conv changes in sudo_debug. + [b0aaa63c9081] + + * common/fileops.c, common/sudo_debug.c, configure, configure.in, + include/fileops.h, plugins/sample/Makefile.in, + plugins/sample/sample_plugin.c, plugins/sample_group/Makefile.in, + plugins/sample_group/sample_group.c, plugins/sudoers/alias.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/check.c, + plugins/sudoers/defaults.c, plugins/sudoers/defaults.h, + plugins/sudoers/env.c, plugins/sudoers/find_path.c, + plugins/sudoers/goodpath.c, plugins/sudoers/gram.c, + plugins/sudoers/gram.y, plugins/sudoers/group_plugin.c, + plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c, + plugins/sudoers/ldap.c, plugins/sudoers/match.c, + plugins/sudoers/match_addr.c, plugins/sudoers/parse.c, + plugins/sudoers/parse.h, plugins/sudoers/pwutil.c, + plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, plugins/sudoers/testsudoers.c, + plugins/sudoers/toke.c, plugins/sudoers/toke.h, + plugins/sudoers/toke.l, plugins/sudoers/toke_util.c, + plugins/sudoers/visudo.c, src/exec.c, src/exec_pty.c, + src/load_plugins.c, src/sudo.c, src/sudo.h, src/sudo_exec.h, + src/sudo_plugin_int.h, src/utmp.c: + Use stdbool.h instead of rolling our own TRUE/FALSE macros. + [dcb0bbc42fc9] + +2011-12-01 Todd C. Miller + + * compat/stdbool.h, config.h.in, configure, configure.in: + Add stdbool.h for systems without it. + [18bd9dda1dcd] -2010-07-10 Todd C. Miller + * aclocal.m4, config.h.in, configure, configure.in: + No longer need SUDO_CHECK_TYPE and SUDO_TYPE_* now that the default + includes have unistd.h in them. Add check for socklen_t for + upcoming getaddrinfo compat. + [d705465bef69] + + * common/fileops.c, compat/nanosleep.c, config.h.in, configure, + configure.in, plugins/sudoers/interfaces.c, + plugins/sudoers/interfaces.h, plugins/sudoers/match_addr.c, + plugins/sudoers/sudoreplay.c, src/net_ifs.c: + Use HAVE_STRUCT_TIMESPEC and HAVE_STRUCT_IN6_ADDR instead of + HAVE_TIMESPEC and HAVE_IN6_ADDR respectively. + [fa187c9bd2be] + + * src/sudo_noexec.c: + No longer need to include time.h here as missing.h does not use + time_t. + [fa3a089bf5b1] + +2011-11-30 Todd C. Miller + + * plugins/sudoers/visudo.c: + Fix mode on sudoers as needed when the -f option is not specified. + [7a1c40b0dc03] + + * MANIFEST, src/po/sr.mo, src/po/sr.po: + Add Serbian translation for sudo from translationproject.org + [9a0c25e25cba] + + * common/sudo_debug.c, plugins/sudoers/sudoers.c, src/load_plugins.c, + src/parse_args.c: + No longer pass debug_file to plugin, plugins must now use + CONV_DEBUG_MSG + [810cda1abb0b] - * env.c, sudoreplay.c: - Fix K&R compilation - [e44d3be7ab85] + * mkpkg: + Build PIE executables for newer Debian and Ubuntu + [1c5f25f8904a] -2010-07-09 Todd C. Miller + * common/sudo_debug.c: + Include time.h for ctime() prototype. + [10090cf3bca1] - * auth/pam.c, config.h.in, configure, configure.in, env.c, sudo.c, - sudo.h: - Add support for a sudo-i pam.d file to be used for "sudo -i". - Adapted from a RedHat patch. - [2984c3831d88] +2011-11-29 Todd C. Miller - * Makefile.in: - Fix installation of sudo_noexec.so - [d1f7ca8331b6] + * common/sudo_debug.c, include/sudo_debug.h, src/exec.c, + src/exec_pty.c: + Do not close error pipe or debug fd via closefrom() as we need them + to report an exec error should one occur. + [732f6587fafa] - * 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] + * doc/sudoers.ldap.pod: + Document that a sudoUser may now be a group ID. + [2fef46b9d3d3] -2010-07-08 Todd C. Miller + * plugins/sudoers/ldap.c: + Add support for permitting access by group ID in addition to group + name. + [b9450fdf1f69] - * ldap.c, sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod: - TLS_CACERT is now an alias for TLS_CACERTFILE. OpenLDAP uses - TLS_CACERT, not TLS_CACERTFILE in its ldap.conf. Other LDAP client - code, such as nss_ldap, uses TLS_CACERTFILE. Also document why you - should avoid disabling TLS_CHECKPEER is possible. - [1d626a5cf8c0] + * plugins/sudoers/ldap.c: + Older Netscape LDAP SDKs don't prototype ldapssl_set_strength() + [d62a1e7cff4f] -2010-07-07 Todd C. Miller + * compat/fnmatch.c, compat/fnmatch.h, doc/LICENSE: + Replace UCB fnmatch.c with a non-recursive version written by + William A. Rowe Jr. + [354d3384adb8] - * toke.c, toke.l: - Add suport for negated user/host/command lists in a Defaults entry. - E.g. Defaults:!baduser noexec - [24f07a805dce] + * plugins/sudoers/auth/pam.c: + Fix typo, return_debug vs. debug_return + [1b522efcbb0d] -2010-07-01 Todd C. Miller +2011-11-23 Todd C. Miller - * sudoers.ldap.pod: - fix typo. - [d5f2922cecf2] + * plugins/sudoers/po/ja.mo, plugins/sudoers/po/ja.po: + Update Japanese sudoers translation from translationproject.org + [ec0f2beaad36] -2010-06-29 Todd C. Miller + * doc/sudoers.pod: + Make the env_reset descriptions consistent. + [41c056f02688] - * .hgtags: - Added tag SUDO_1_7_3 for changeset 72fd1f510a08 - [cc8b2277e17e] +2011-11-22 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: - Sudo 1.7.3 GA - [72fd1f510a08] [SUDO_1_7_3] + * configure, configure.in: + Do multiple expansion when expanding paths to the noexec file, sesh + and the plugin directory. Adapted from a diff by Mike Frysinger + [d7e16c876c66] - * alias.c, alloc.c, auth/afs.c, auth/aix_auth.c, auth/bsdauth.c, - auth/dce.c, auth/fwtk.c, auth/kerb4.c, auth/kerb5.c, auth/pam.c, - auth/passwd.c, auth/rfc1938.c, auth/secureware.c, auth/securid.c, - auth/securid5.c, auth/sia.c, auth/sudo_auth.c, boottime.c, check.c, - defaults.c, env.c, exec.c, exec_pty.c, fileops.c, find_path.c, - fnmatch.c, get_pty.c, getcwd.c, getdate.c, getdate.y, getline.c, - getspwuid.c, glob.c, goodpath.c, gram.c, gram.y, interfaces.c, - iolog.c, lbuf.c, ldap.c, logging.c, match.c, parse.c, parse_args.c, - pwutil.c, set_perms.c, snprintf.c, sudo.c, sudo_edit.c, sudo_nss.c, - sudoreplay.c, term.c, testsudoers.c, tgetpass.c, toke.c, toke.l, - tsgetgrpw.c, visudo.c: - Include strings.h even if string.h exists since they may define - different things. Fixes warnings on AIX and others. - [7c6de7fb5dba] + * common/Makefile.in: + regen + [9d729e09c186] - * env.c: - Do not rely on env.env_len when unsetting a variable, just use the - NULL terminator. - [faf088613ce5] +2011-11-21 Todd C. Miller - * env.c: - In unsetenv() check for NULL or empty name as per POSIX 1003.1-2008 - [47f8dfcc7a48] + * .hgignore: + Add ignore file; from Mike Frysinger + [1fa8d52425f8] -2010-06-28 Todd C. Miller + * mkdep.pl: + no longer save old Makefile.in to .old + [378dd2395545] - * sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod: - Mention that multiple URI lines are merged into a single one. - [1dc0ac5929bf] + * plugins/sudoers/Makefile.in, src/Makefile.in: + regen + [769faf517720] - * WHATSNEW: - Document AIX fixes - [be36e8a6dddd] + * config.guess, config.sub, configure, ltmain.sh, m4/libtool.m4, + m4/ltoptions.m4, m4/ltversion.m4: + Update to libtool 2.4.2 + [9dac78d84b4f] -2010-06-26 Todd C. Miller +2011-11-18 Todd C. Miller - * env.c, sudo.c, sudo.h: - For env_init() just use environ not the envp from main(). - [d4f3e374caeb] + * plugins/sudoers/sudoers_version.h: + Bump grammar version for #include and #includedir relative path + support. + [82a4f7cd8f71] -2010-06-25 Todd C. Miller +2011-11-17 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: - Update version to 1.7.3rc1 - [fe43fe79070d] + * doc/sudoers.pod, plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add support for relative paths in #include and #includedir + [4d6e3bd0c24f] - * TODO: - fqdn issue is resolved - [f35cb63eb74b] + * plugins/sudoers/Makefile.in: + Fix install-plugin when shared objects are unsupported or disabled. + [cbdd770a7a1b] - * 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] + * plugins/sudoers/goodpath.c: + Don't write to sbp if it is NULL + [fc438f8e8570] - * 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] +2011-11-16 Todd C. Miller - * 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] + * Makefile.in: + Remove all sudo/sudoers .mo files on uninstall If LINGUAS is set, + only install matching .mo files + [c1dc30ab4ebc] - * sudo.c: - Defer call to sudo_nonunix_groupcheck_cleanup() until after we have - closed the sudoers sources. From Quest sudo. - [c1b33e3e0f9e] +2011-11-13 Todd C. Miller - * pwutil.c: - Ignore case when matching user/group names in the cache. From Quest - sudo. - [72df368a8a0e] + * plugins/sudoers/group_plugin.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.c, src/conversation.c: + Fix non-dynamic (no dlopen) sudo build. + [b0bd3fa925a3] -2010-06-24 Todd C. Miller + * configure, configure.in: + Don't error out if the user specified --disable-shared + [cf035dd1e5cc] + + * common/sudo_debug.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c, + src/conversation.c: + Use SUDO_CONV_DEBUG_MSG in the plugin instead of writing directly to + the debug file. + [640c62f83251] + + * plugins/sudoers/find_path.c, plugins/sudoers/goodpath.c, + plugins/sudoers/sudoers.h: + Make sudo_goodpath() return value bolean + [fea2d59a6e55] + + * INSTALL, MANIFEST, configure, configure.in, mkdep.pl, + plugins/sudoers/Makefile.in, plugins/sudoers/auth/securid.c: + Remove obsolete securid auth method. + [4e54f860214b] + + * plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c, + plugins/sudoers/auth/dce.c, plugins/sudoers/auth/fwtk.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c, + plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid5.c, + plugins/sudoers/auth/sia.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/auth/sudo_auth.h: + Prefix authentication functions with a "sudo_" prefix to avoid + namespace problems. + [581d74063ea1] + + * INSTALL, MANIFEST, config.h.in, configure, configure.in, + doc/TROUBLESHOOTING, mkdep.pl, plugins/sudoers/Makefile.in, + plugins/sudoers/auth/kerb4.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/auth/sudo_auth.h, plugins/sudoers/env.c: + Remove the old Kerberos IV support + [2e4b4a44209d] + +2011-11-12 Todd C. Miller + + * plugins/sudoers/check.c: + Don't print garbage at the end of the custom lecture. + [44bb788fafaa] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add lexer tracing as debug@parser + [d850f3f9d414] + + * plugins/sudoers/alias.c, plugins/sudoers/defaults.c, + plugins/sudoers/defaults.h, plugins/sudoers/gram.c, + plugins/sudoers/match.c, plugins/sudoers/parse.c, + plugins/sudoers/regress/parser/check_fill.c, + plugins/sudoers/testsudoers.c, plugins/sudoers/toke.c, + plugins/sudoers/toke.l, plugins/sudoers/toke_util.c, + plugins/sudoers/visudo.c: + Revert 003bdb078a15. We need to #include not "gram.h" and + and not "def_data.h" when generating the parser in a + build dir. + [7da701def753] + +2011-11-08 Todd C. Miller + + * mkdep.pl, plugins/sudoers/Makefile.in: + Better devdir support in mkdep.pl + [7dcec57bd155] + + * plugins/sudoers/Makefile.in: + Add devdir before srcdir in include path and fix up dependecies + accordingly. + [6e9958eca485] + + * plugins/sudoers/alias.c, plugins/sudoers/defaults.c, + plugins/sudoers/defaults.h, plugins/sudoers/match.c, + plugins/sudoers/parse.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/toke.c, plugins/sudoers/toke.l, + plugins/sudoers/toke_util.c, plugins/sudoers/visudo.c: + #include "gram.h" not and "def_data.h" and not + . + [003bdb078a15] - * config.h.in, configure, configure.in, selinux.c: - Add check for setkeycreatecon() when --with-selinux is specified. - [24144c52c0cc] + * sudo.pp: + Mark libexec files as optional. If we build without shared object + support, libexec is not used. + [4bffcf482219] + + * src/load_plugins.c: + Change Debug sudo.conf setting to take a program name as the first + argument. In the future, this will allow visudo and sudoreplay to + use their own Debug entries. + [cfb8f7e4867c] + + * src/sudo.c: + fix sudo_debug_printf priority + [dcb67e965609] + + * plugins/sudoers/sudoers.c: + add missing debug_return_int + [d88ec450c592] + +2011-11-07 Todd C. Miller + + * common/sudo_debug.c, include/error.h, include/sudo_debug.h, + plugins/sudoers/logging.c, src/exec.c, src/exec_pty.c: + Fold SUDO_DEBUG_PROGERR and SUDO_DEBUG_SYSERR into SUDO_DEBUG_ERROR + [dcee8efc294f] + + * doc/UPGRADE: + Add missing word in HOME security note. + [fd844fdcc1ac] + + * plugins/sudoers/testsudoers.c: + Prevent "testsudoers -d username" from trying to malloc(0). + [839126e56e8c] + +2011-11-06 Todd C. Miller + + * plugins/sudoers/regress/sudoers/test10.in, + plugins/sudoers/regress/sudoers/test10.out.ok, + plugins/sudoers/regress/sudoers/test10.toke.ok, + plugins/sudoers/regress/sudoers/test10.toke.out.ok, + plugins/sudoers/regress/sudoers/test11.in, + plugins/sudoers/regress/sudoers/test11.out.ok, + plugins/sudoers/regress/sudoers/test11.toke.ok, + plugins/sudoers/regress/sudoers/test11.toke.out.ok, + plugins/sudoers/regress/sudoers/test12.in, + plugins/sudoers/regress/sudoers/test12.out.ok, + plugins/sudoers/regress/sudoers/test12.toke.ok, + plugins/sudoers/regress/sudoers/test13.in, + plugins/sudoers/regress/sudoers/test13.out.ok, + plugins/sudoers/regress/sudoers/test13.toke.ok, + plugins/sudoers/regress/sudoers/test9.in, + plugins/sudoers/regress/sudoers/test9.out.ok, + plugins/sudoers/regress/sudoers/test9.toke.ok, + plugins/sudoers/regress/sudoers/test9.toke.out.ok: + Tests for empty sudoers (should parse OK) and syntax errors within a + line (should report correct line number) both with and without the + trailing newline. + [d57c879c4718] + + * plugins/sudoers/regress/sudoers/test4.out.ok, + plugins/sudoers/regress/sudoers/test5.out.ok, + plugins/sudoers/regress/sudoers/test7.out.ok, + plugins/sudoers/regress/sudoers/test8.out.ok, + plugins/sudoers/testsudoers.c: + Print line number when there is a parser error. + [5444ef6ac6dc] + +2011-11-05 Todd C. Miller + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Keep track of the last token returned. On error, if the last token + was COMMENT, decrement sudolineno since the error most likely + occurred on the preceding line. Previously we always uses + sudolineno-1 which will give the wrong line number for errors within + a line. + [d661a03a64da] + +2011-11-03 Todd C. Miller + + * NEWS: + update with sudo 1.8.3p1 info + [0f79ff31f602] + + * plugins/sudoers/sudoers.c: + Fix crash when "sudo -g group -i" is run. Fixes bug 521 + [a3087ae337c4] + +2011-10-26 Todd C. Miller + + * plugins/sudoers/visudo.c: + Make alias_remove_recursive() return TRUE/FALSE as its callers + expect and remove two unused arguments. Fixes bug 519. + [2ee3b2882844] + + * plugins/sudoers/regress/visudo/test1.out.ok, + plugins/sudoers/regress/visudo/test1.sh: + Add regress test for bugzilla 519 + [48000ebedf97] + + * plugins/sudoers/regress/iolog_path/check_iolog_path.c, + plugins/sudoers/regress/logging/check_wrap.c, + plugins/sudoers/regress/parser/check_addr.c, + plugins/sudoers/regress/parser/check_fill.c: + Disable warning/error wrapping in regress tests. + [373c589ba561] + +2011-10-25 Todd C. Miller + + * Makefile.in: + Do compile-po as part of sync-po so that the .mo files get rebuild + automatically when we sync with translationproject.org + [83f3cbfc2f33] + + * plugins/sudoers/Makefile.in: + check_addr needs to link with the network libraries on Solaris + [322bd70e316e] + + * plugins/sudoers/match.c: + When matching a RunasAlias for a runas group, pass the alias in as + the group_list, not the user_list. From Daniel Kopecek. + [766545edf141] + + * plugins/sudoers/check.c, plugins/sudoers/sudoers.c: + We need to init the auth system regardless of whether we need a + password since we will be closing the PAM session in the monitor + process. Fixes a crash in the monitor on Solaris; bugzilla #518 + [e82809f86fb3] + +2011-10-24 Todd C. Miller + + * src/exec.c: + Get rid of done: label. If the child exits we still need to close + the pty, update utmp and restore the SELinux tty context. + [cc127bf48405] + +2011-10-22 Todd C. Miller + + * common/Makefile.in, common/atobool.c, common/fileops.c, + common/fmt_string.c, common/lbuf.c, common/list.c, + common/setgroups.c, common/term.c, plugins/sudoers/Makefile.in, + plugins/sudoers/alias.c, plugins/sudoers/audit.c, + plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c, + plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c, + plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c, + plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c, + plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/boottime.c, + plugins/sudoers/bsm_audit.c, plugins/sudoers/check.c, + plugins/sudoers/defaults.c, plugins/sudoers/env.c, + plugins/sudoers/find_path.c, plugins/sudoers/getspwuid.c, + plugins/sudoers/goodpath.c, plugins/sudoers/gram.c, + plugins/sudoers/gram.y, plugins/sudoers/group_plugin.c, + plugins/sudoers/interfaces.c, plugins/sudoers/iolog.c, + plugins/sudoers/iolog_path.c, plugins/sudoers/ldap.c, + plugins/sudoers/linux_audit.c, plugins/sudoers/logging.c, + plugins/sudoers/logwrap.c, plugins/sudoers/match.c, + plugins/sudoers/match_addr.c, plugins/sudoers/parse.c, + plugins/sudoers/pwutil.c, plugins/sudoers/redblack.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/toke.c, plugins/sudoers/toke.h, + plugins/sudoers/toke.l, plugins/sudoers/toke_util.c, + src/Makefile.in, src/conversation.c, src/exec.c, src/exec_pty.c, + src/get_pty.c, src/load_plugins.c, src/net_ifs.c, src/parse_args.c, + src/selinux.c, src/sudo.c, src/sudo.h, src/sudo_edit.c, + src/tgetpass.c, src/ttysize.c, src/utmp.c: + Add debug_decl/debug_return (almost) everywhere. Remove old + sudo_debug() and convert users to sudo_debug_printf(). + [8f3bbf907b67] + + * common/alloc.c, include/error.h, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/visudo.c, src/error.c: + Wrap error/errorx and warning/warningx functions with debug + statements. Disable wrapping for standalone sudoers programs as well + as memory allocation functions (to avoid infinite recursion). + [562ed7b5ae8d] + + * README, config.h.in, configure, configure.in: + Add checks for __func__ and __FUNCTION__ and mention that we now + require a cpp that supports variadic macros. + [314cfe4c5d23] + + * MANIFEST, common/Makefile.in, common/sudo_debug.c, + include/sudo_debug.h, include/sudo_plugin.h, src/conversation.c, + src/load_plugins.c, src/parse_args.c, src/sudo.c, + src/sudo_plugin_int.h: + New debug framework for sudo and plugins using /etc/sudo.conf that + also supports function call tracing. + [cded741e9f10] + +2011-10-21 Todd C. Miller + + * plugins/sudoers/po/ja.mo, plugins/sudoers/po/ja.po: + Update Japanese sudoers translation from translationproject.org + [c24725775e32] + +2011-10-12 Todd C. Miller * 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] + Override and ignore the --disable-static option. Sudo already runs + libtool with -tag=disable-static where applicable and we need non- + PIC objects to build the executables. + [aff1227b853a] + +2011-10-10 Todd C. Miller + + * NEWS: + Add sudoedit fix + [74655c7ccad1] + + * plugins/sudoers/po/sudoers.pot: + regen pot files + [28d89a831ed3] + + * plugins/sudoers/env.c: + Ignore set_logname (which is now the default) for sudoedit since we + want the LOGNAME, USER and USERNAME environment variables to refer + to the calling user since that is who the editor runs as. This + allows the editor to find the user's startup files. Fixes bugzilla + #515 + [6c5dddf5ff05] + + * plugins/sudoers/pwutil.c: + Instead of trying to grow the buffer in make_grlist_item(), simply + increase the total length, free the old buffer and allocate a new + one. This is less error prone and saves us from having to adjust + all the pointers in the buffer. This code path is only taken when + there are groups longer than the length of the user field in struct + utmp or utmpx, which should be quite rare. + [5587dc8cffaf] + + * src/po/it.mo: + Add Italian translation for sudo from translationproject.org + [1b3dd886e7e3] + + * MANIFEST, NEWS, plugins/sudoers/po/ja.mo, plugins/sudoers/po/ja.po, + src/po/ja.mo, src/po/ja.po: + Japanese translation for sudo and sudoers from + translationproject.org + [c06dd866be6e] + +2011-10-07 Todd C. Miller + + * plugins/sudoers/Makefile.in: + sudoreplay depends on timestr.lo too; from Mike Frysinger + [b9e73214b2f1] + +2011-10-04 Todd C. Miller + + * plugins/sudoers/po/sudoers.pot: + Regen sudoers pot file. + [019588bafdb3] + + * NEWS: + Update with latest sudo 1.8.3 news + [6868042a88e9] + + * plugins/sudoers/sudoers.c: + It appears that LDAP or NSS may modify the euid so we need to be + root for the open(). We restore the old perms at the end of + sudoers_policy_open(). + [2da67a5497ef] + + * plugins/sudoers/set_perms.c: + Better warning message on setuid() failure for the setreuid() + version of set_perms(). + [07abcfe7bd9a] + +2011-09-27 Todd C. Miller + + * plugins/sudoers/check.c: + Delref auth_pw at the end of check_user() instead of getting a ref + twice. + [cb665f55e6a5] + + * plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/check.c: + Make sudo_auth_{init,cleanup} return TRUE on success and check for + sudo_auth_init() return value in check_user(). + [92631c919356] + + * plugins/sudoers/auth/sudo_auth.c: + Do not return without restoring permissions. + [59ef40b6696a] + + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + regen pot files + [9f320a340b7c] + + * plugins/sudoers/auth/API, plugins/sudoers/auth/bsdauth.c, + plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/secureware.c, + plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h, + plugins/sudoers/check.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Modify the authentication API such that the init and cleanup + functions are always called, regardless of whether or not we are + going to verify a password. This is needed for proper PAM session + support. + [19a53f3fb596] - * aix.c: - K&R function declaration for aix_setauthdb() - [82da12d222a6] + * compat/Makefile.in, mkdep.pl, plugins/sudoers/Makefile.in: + Add missing dependency for getspwuid.lo and regen other depends. + [f7f70eae819a] - * 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] + * plugins/sudoers/auth/pam.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/auth/sudo_auth.h, plugins/sudoers/sudoers.c: + Fix a PAM_USER mismatch in session open/close. We update PAM_USER + to the target user immediately before setting resource limits, which + is after the monitor process has forked (so it has the old value). + Also, if the user did not authenticate, there is no pamh in the + monitor so we need to init pam here too. This means we end up + calling pam_start() twice, which should be fixed, but at least the + session is always properly closed now. + [fbc063a2a872] - * ldap.c: - Add support for multiple URI lines by joining the contents and - passing the result to ldap_initialize. - [b4e10b2ffdb1] + * src/utmp.c: + Add check for old being NULL in utmp_setid(); from Steven McDonald + [e87126442f2e] -2010-06-23 Todd C. Miller +2011-09-25 Todd C. Miller - * pwutil.c, set_perms.c, sudo_nss.c: - Bracket initgroups with calls to aix_setauthdb() and - aix_restoreauthdb() - [363dbe449f1c] + * plugins/sudoers/pwutil.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + If the invoking user cannot be resolved by uid fake the struct + passwd and store it in the cache so we can delref it on exit. + [a27e2f8b9f5e] - * aix.c: - Include compat.h before alloc.h to get __P - [819a2667ffd7] +2011-09-24 Todd C. Miller - * auth/aix_auth.c: - Include usersec.h for authenticate() prototype - [2b8dd2b67131] + * plugins/sudoers/sudoers.c: + Don't error out if the group plugin cannot be loaded, just warn. + [0fbfcd381e33] - * aix.c: - Add missing includes Add missing trailing NUL in userinfo string - [8deaedf44943] +2011-09-23 Todd C. Miller -2010-06-22 Todd C. Miller + * plugins/sudoers/sudoers.c: + Quiet a false positive found by several static analysis tools. These + tools don't know that log_error() does not return (it longjmps to + error_jmp which returns to the sudo front-end). + [33d0469df21b] - * HISTORY, history.pod: - Mention when LDAP was incorporated. - [4e6c8ec4f67c] +2011-09-22 Todd C. Miller -2010-06-21 Todd C. Miller + * MANIFEST, plugins/sudoers/po/da.mo, plugins/sudoers/po/eo.mo, + plugins/sudoers/po/fi.mo, plugins/sudoers/po/pl.mo, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/zh_CN.mo, src/po/it.po: + Add Italian translation for sudo from translationproject.org Regen + .mo files + [c3c888a82be6] - * configure: - Define _LINUX_SOURCE_COMPAT on AIX for strsignal() prototype, it is - not covered by _ALL_SOURCE. - [3657f1b181b9] +2011-09-21 Todd C. Miller - * pwutil.c: - Include usersec.h on AIX to get IDtouser() prototype. - [11483bbe15c7] + * doc/TROUBLESHOOTING: + Update to current reality and add bit about ssh auth + [184a1e7c2eeb] - * configure.in: - Define _LINUX_SOURCE_COMPAT on AIX for strsignal() prototype, it is - not covered by _ALL_SOURCE. - [fd48e6e2136b] + * plugins/sudoers/gram.c, plugins/sudoers/gram.y: + Make "verbose" static; fixes a namespace clash with + pam_ssh_agent_auth (and it doesn't need to be extern these days). + [cc38d2eb2f4c] -2010-06-18 Todd C. Miller + * config.h.in, configure, configure.in, src/get_pty.c: + FreeBSD has libutil.h not util.h + [dab4c94b6d4f] - * iolog.c: - Add a cast to quiet a compiler warning. - [51e9d419bd83] + * configure, configure.in: + Define _BSD_SOURCE on FreeBSD, OpenBSD and DragonflyBSD + [41c362f0a92a] - * boottime.c: - Use memset() instead of zero_bytes() since we don't include sudo.h - [f310b2123ba9] +2011-09-20 Todd C. Miller + + * plugins/sudoers/po/da.po, plugins/sudoers/po/eo.po, + plugins/sudoers/po/fi.po, plugins/sudoers/po/pl.po, + plugins/sudoers/po/uk.po, plugins/sudoers/po/zh_CN.po: + Update po files from translationproject.org + [1e99e147c7fa] + +2011-09-16 Todd C. Miller + + * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Add support for DEREF in ldap.conf. + [3c1937a98547] * Makefile.in: - getline.o is already in LIB_OBJS, do not need it in COMMON_OBJS - [c8750c2d75ab] + install target should depend on ChangeLog too, not just install-doc + [1a7c83941175] - * getdate.c, getdate.y: - Quiet a compiler warning. - [9f231be15958] + * doc/sudoers.pod: + Only iolog_file (not iolog_dir) supports mktemp-style suffixes. + [0eca47d60a2c] - * defaults.c, sudo.c: - Call set_fqdn() after sudoers has parsed instead of inline as a - callback. - [26d413ddb6dd] + * NEWS: + Sync with 1.8 branch for sudo 1.8.2 and 1.8.3 changes. + [0501415cc5ff] - * WHATSNEW: - Do not call set_fqdn() until sudoers parses (where is gets run as a - callback). - [582453a993a1] + * doc/UPGRADE: + Document group lookup change and possible side effects. + [585743e1ebf7] - * 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] + * configure, configure.in: + Fix some square brackets in case statements that needed to be + doubled up. While here, use $OSMAJOR when it makes sense. + [8973343f4696] - * 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] + * plugins/sudoers/pwutil.c: + Fix a crash in make_grlist_item() on 64-bit machines with strict + alignment. + [c89508c73c46] - * WHATSNEW: - mention the change in tty ticket behavior when there is no tty - [93ddde63e453] + * plugins/sudoers/defaults.c, plugins/sudoers/defaults.h: + Remove list_options() function that is no longer used now that "sudo + -L" is gone. + [fcc6a776c135] - * TODO: - remove done items - [9601b2e8dcef] + * configure, configure.in: + Error message if user tries --with-CC + [ec5b478f813a] - * aix.c: - Remove comment; NAME in usrinfo should be user name. - [eb46f1e8ea08] + * configure, configure.in: + Check for -libmldap too when looking for ldap libs, which is the + Tivoli Directory Server client library. + [bb3007a97206] - * check.c: - Do not update tty ticket if there is no tty. - [e64e8c8f2286] +2011-09-09 Todd C. Miller - * sudo.cat, sudo.man.in, sudo.pod: - No longer need to use -- with the -s flag - [e45c18dd79dc] + * plugins/sudoers/parse.c: + Honor NOPASSWD tag for denied commands too. + [8dd92656db92] + +2011-09-08 Todd C. Miller + + * INSTALL, configure, configure.in: + Remove --with-CC option; it doesn't work correctly now that we use + libtool. Users can get the same effect by setting the CC + environment variable when running configure. + [ec22bd1a55e0] + +2011-08-31 Todd C. Miller + + * config.h.in, configure, configure.in, plugins/sudoers/visudo.c, + src/sudo_edit.c: + Assume all modern systems support fstat(2). + [6a5a8985f6a0] + +2011-08-30 Todd C. Miller + + * compat/regress/glob/globtest.c, config.h.in, configure, + configure.in, include/missing.h, plugins/sudoers/sudoers.h, + src/sudo.h, src/sudo_noexec.c: + Add configure test for missing errno declaration and only declare it + ourselves if it is missing. + [456e76c809a2] + + * plugins/sudoers/alias.c: + Include errno.h before sudo.h to avoid conflicting with the system + definition of errno. + [d0b97e392512] + +2011-08-29 Todd C. Miller + + * plugins/sudoers/regress/parser/check_addr.c: + Only print individual check status when there is a failure. + [2ac704c91441] + + * plugins/sudoers/regress/iolog_path/check_iolog_path.c, + plugins/sudoers/regress/logging/check_wrap.c, + plugins/sudoers/regress/parser/check_addr.c: + Add calls to setprogname() for test programs. + [a8d9b420e826] + + * configure, configure.in: + Add -Wall and -Werror after all tests so they don't cause failures. + [2661188ff3fa] + + * plugins/sudoers/Makefile.in: + Actually run check_addr in the check target + [0b2778bc86bf] + + * MANIFEST, plugins/sudoers/Makefile.in, plugins/sudoers/match.c, + plugins/sudoers/match_addr.c, + plugins/sudoers/regress/parser/check_addr.c, + plugins/sudoers/regress/parser/check_addr.in: + Split out address matching into its own file and add regression + tests for it. + [12b9a2bf8dba] + +2011-08-27 Todd C. Miller + + * plugins/sudoers/match.c: + When matching an address with a netmask in sudoers, AND the mask and + addr before checking against the local addresses. + [9747bb6d7b1c] + +2011-08-26 Todd C. Miller + + * plugins/sudoers/match.c: + Fix netmask matching. + [a3c8f8cc1464] + + * plugins/sudoers/visudo.c: + Don't assume all editors support the +linenumber command line + argument, use a whitelist of known good editors. + [21d43a91fd10] + +2011-08-23 Todd C. Miller + + * plugins/sudoers/set_perms.c, plugins/sudoers/visudo.c, src/exec.c, + src/exec_pty.c, src/sudo.c: + Silence compiler warnings on Solaris with gcc 3.4.3 + [da620bae6fdb] + + * mkpkg: + Fix building on RHEL 3 + [f3227fb2a252] + + * INSTALL, configure, configure.in: + Add --enable-werror configure option. + [fec2cdb95543] + + * common/setgroups.c: + setgroups() proto lives in grp.h on RHEL4, perhaps others. + [de91c0de5a98] + + * configure, configure.in: + Use PAM by default on AIX 6 and higher. + [e16493208e5f] + +2011-08-22 Todd C. Miller + + * MANIFEST, plugins/sudoers/po/eo.mo, plugins/sudoers/po/eo.po, + src/po/eo.mo, src/po/eo.po: + Add new Esperanto translation from translationproject.org + [0d9a59e04c64] + +2011-08-19 Todd C. Miller + + * plugins/sudoers/iolog_path.c: + Quiet an innocuous valgrind warning. + [0582b6027161] + +2011-08-18 Todd C. Miller + + * plugins/sudoers/iolog_path.c, + plugins/sudoers/regress/iolog_path/data: + Fix expansion of strftime() escapes in log_dir and add a regress + test that exhibited the problem. + [a5c7c1c4c589] + + * plugins/sudoers/Makefile.in: + Fix "make check" return value. + [33b58e175230] + +2011-08-17 Todd C. Miller + + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + Regen pot files + [063841aac19b] + + * Makefile.in: + Fix logic inversion in pot file up to date check. + [f6a8ca8654df] + +2011-08-15 Todd C. Miller + + * configure, configure.in: + Add caching for gettext() checks. + [01b7200f6105] + + * configure, configure.in: + Better handling of libintl header and library mismatch. + [9a49b1d4db69] + +2011-08-13 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Also check sudoers gid if sudoers is group writable. + [23ef96ca0d33] + +2011-08-12 Todd C. Miller + + * configure, configure.in: + If dlopen is present but libtool doesn't find it, error out since it + probably means that libtool doesn't support the system. + [a9da0a5f7941] + + * mkpkg: + configure args on the command line should override builtin defaults. + Disable NLS for non-Linux/Solaris unless explicitly enabled. + [b2fb05614504] + + * plugins/sudoers/auth/aix_auth.c: + Fix loop that calls authenticate(). If there was an error message + from authenticate(), display it. + [063a0c4f0b9a] + +2011-08-11 Todd C. Miller + + * m4/libtool.m4, m4/ltversion.m4: + Update to autoconf 2.68 and libtool 2.4 + [5a912a6eb67b] + + * config.guess, config.sub, configure, configure.in, ltmain.sh: + Update to autoconf 2.68 and libtool 2.4 + [931ab56aecf6] + + * doc/sudoers.pod: + Fix typo; OPT should be OTP + [e97bd2e46544] + + * plugins/sudoers/Makefile.in: + Rename libsudoers convenience library to libparsesudoers to avoid + libtool confusion. + [2a89a613f537] + +2011-08-10 Todd C. Miller + + * MANIFEST, plugins/sudoers/po/da.mo, plugins/sudoers/po/da.po: + Add Danish sudoers translation from translationproject.org + [27b96e85eb13] + + * plugins/sudoers/sudoers.c, plugins/sudoers/testsudoers.c: + Add dedicated callback function for runas_default sudoers setting + that only sets runas_pw if no runas user or group was specified by + the user. + [b8382d8eea34] + +2011-08-09 Todd C. Miller + + * plugins/sudoers/po/fi.mo, plugins/sudoers/po/fi.po, + plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po, + plugins/sudoers/po/uk.mo, plugins/sudoers/po/uk.po, src/po/ru.mo, + src/po/ru.po: + Update Finish, Polish, Russian and Ukrainian translations from + translationproject.org. + [f9339aff664e] + + * plugins/sudoers/defaults.h, plugins/sudoers/sudoers.c, + plugins/sudoers/testsudoers.c: + Go back to using a callback for runas_default to keep runas_pw in + sync. This is needed to make per-entry runas_default settings work + with LDAP-based sudoers. Instead of declaring it a callback in + def_data.in, sudo and testsudoers poke sudo_defs_table[] which is a + bit naughty, but avoids requiring stub functions in visudo and the + tests. + [9aaefb908415] + +2011-08-05 Todd C. Miller + + * Makefile.in: + Add check for out of date message catalogs when doing "make dist". + [e45a29b612f4] + +2011-08-02 Todd C. Miller + + * configure: + regen + [d6f9ad26774a] + + * configure.in: + Make sure compiler supports static-libgcc before using it. + [b01bd9566e50] + +2011-08-01 Todd C. Miller + + * src/Makefile.in: + Link libsudo_noexec.la with LDLDFLAGS for -static-libgcc + [c99c7ab3edef] + +2011-07-30 Todd C. Miller + + * MANIFEST, plugins/sudoers/po/fi.mo, plugins/sudoers/po/pl.mo, + plugins/sudoers/po/pl.po, plugins/sudoers/po/uk.mo, + plugins/sudoers/po/zh_CN.mo, src/po/ru.mo, src/po/ru.po, + src/po/zh_CN.mo: + Add new Russian sudo translation from translationproject.org and + rebuild the other translation files. + [e20015459056] + +2011-07-29 Todd C. Miller + + * plugins/sudoers/po/fi.po, plugins/sudoers/po/pl.po: + Update Finish and Polish translations from translationproject.org + [4e3dbba4a1de] + + * plugins/sudoers/sudoers.c, src/parse_args.c, src/sudo.c: + Go back to escaping the command args for "sudo -i" and "sudo -s" + before calling the plugin. Otherwise, spaces in the command args + are not treated properly. The sudoers plugin will unescape non- + spaces to make matching easier. + [dfa2c4636f33] + +2011-07-28 Todd C. Miller + + * plugins/sudoers/check.c, plugins/sudoers/group_plugin.c, + plugins/sudoers/ldap.c, plugins/sudoers/parse.c, + plugins/sudoers/set_perms.c, plugins/sudoers/toke.c, + plugins/sudoers/toke.l: + Fix some potential problems found by the clang static analyzer, none + serious. + [ff64aa74aae6] + + * plugins/sudoers/po/uk.po, plugins/sudoers/po/zh_CN.po, + src/po/zh_CN.po: + Updated Ukranian and Chinese (simplified) po files from + translationproject.org + [ec792becb48e] + +2011-07-27 Todd C. Miller + + * plugins/sudoers/po/pl.po: + Updated Polish translation from translationproject.org + [a3af53cb649c] + + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + Rebuild pot files + [c650524c0f0a] + + * plugins/sudoers/audit.c, plugins/sudoers/sudoers.c: + Don't try to audit failure if the runas user does not exist. We + don't have the user's command at this point so there is nothing to + audit. Add a NULL check in audit_success() and audit_failure() just + to be on the safe side. + [2a0007c2022f] + + * mkpkg: + Add -g to CFLAG for PIE builds. + [32a0a9693c9c] + +2011-07-25 Todd C. Miller + + * plugins/sudoers/pwutil.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/sudo.c: + Remove fallback to per-group lookup when matching groups in sudoers. + The sudo front-end will now use getgrouplist() to get the user's + list of groups if getgroups() fails or returns zero groups so we + always have a list of the user's groups. For systems with + mbr_check_membership() which support more that NGROUPS_MAX groups + (Mac OS X), skip the call to getgroups() and use getgrouplist() so + we get all the groups. + [51b3ed8c600b] + +2011-07-22 Todd C. Miller + + * common/setgroups.c: + Fix setgroups() fallback code on EINVAL. + [2b6faecd56a4] + + * plugins/sudoers/set_perms.c: + Fix two PERM_INITIAL cases that were still using user_gids. + [9680bab0acc6] + + * MANIFEST: + Add Polish sudo message catalog + [8bb40c3ba576] + + * plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + user_group is no longer used, remove it + [9acede0fe6c5] + +2011-07-20 Todd C. Miller + + * MANIFEST, plugins/sudoers/po/pl.mo, plugins/sudoers/po/pl.po: + Add Polish translation from translationproject.org + [afac5c638573] + + * MANIFEST, common/Makefile.in, common/setgroups.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.h, src/sudo.c, + src/sudo.h, src/sudo_edit.c: + Add a wrapper for setgroups() that trims off extra groups and + retries if setgroups() fails. Also add some missing addrefs for + PERM_USER and PERM_FULL_USER. + [224dfd8aae5c] + + * MANIFEST, compat/Makefile.in, compat/getgrouplist.c, config.h.in, + configure, configure.in, include/missing.h, mkdep.pl, + plugins/sudoers/ldap.c, plugins/sudoers/pwutil.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, src/sudo.c: + Instead of keeping separate groups and gids arrays, create struct + group_info and use it to store both, along with a count for each. + Cache group info on a per-user basis using getgrouplist() to get the + groups. We no longer need special to special case the user or list + user for user_in_group() and thus no longer need to reset the groups + list when listing another user. + [0ad849a8b2d5] + + * src/preload.c: + Don't rely on NULL since we don't include a header for it. + [b40937f1890c] + +2011-07-19 Todd C. Miller + + * doc/sudoers.pod: + Fix typo + [c1035360e169] + +2011-07-18 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Do not shadow global sudo_mode with a local variable in set_cmnd() + [0c72969503ad] + +2011-07-17 Todd C. Miller + + * plugins/sudoers/sudoers.c: + bash 2.x doesd not support the -l flag and exits with an error if it + is specified so use --login instead. This causes an error with bash + 1.x (which uses -login instead) but this version is hopefully less + used than 2.x. + [5c4c296e30e6] + + * src/po/pl.mo, src/po/pl.po: + Add Polish translation from translationproject.org + [48592dd6edcf] + +2011-07-13 Todd C. Miller + + * plugins/sudoers/set_perms.c: + Make error strings translatable. + [414c5c484768] + + * mkpkg: + Only run configure with --with-pam-login for RHEL 5 and above. + [6c16e4de4026] + + * sudo.pp: + Fix typo in summary + [9ac618c9a749] + +2011-07-11 Todd C. Miller + + * plugins/sudoers/logwrap.c: + Add missing logwrap.c + [c12a413ecc1d] + + * MANIFEST, plugins/sudoers/Makefile.in, plugins/sudoers/logging.c, + plugins/sudoers/logging.h, + plugins/sudoers/regress/logging/check_wrap.c, + plugins/sudoers/regress/logging/check_wrap.in, + plugins/sudoers/regress/logging/check_wrap.out.ok: + Split out log file word wrap code into its own file and add unit + tests. Fixes an off-by one in the word wrap when the log line + length matches loglinelen. + [52ed277f6690] + +2011-07-05 Todd C. Miller + + * mkpkg: + For SuSE, only use /usr/lib64 as libexec if generating 64-bit + binaries. + [645ab903cf77] + + * src/load_plugins.c, src/sudo.c: + Fix build error when --without-noexec configure option is used. + [b994f7b0d8b4] + + * configure, configure.in: + Disable noexec for AIX < 5. LDR_PRELOAD is only available in AIX + 5.3 and above. + [c2a6f9b472f3] + +2011-07-01 Todd C. Miller + + * plugins/sudoers/ldap.c, plugins/sudoers/pwutil.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Resolve the list of gids passed in from the sudo frontend (the + result of getgroups()) to names and store both the group names and + ids in the sudo_user struct. When matching groups in the sudoers + file, match based on the names in the groups list first and only do + a gid-based match when we absolutely have to. By matching on the + group name (as it is listed in sudoers) instead of id (which we + would have to resolve) we save a lot of group lookups for sudoers + files with a lot of groups in them. + [8dc19353f148] + +2011-06-26 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Workaround for "sudo -i command" and newer versions of bash which + don't go into login mode when -c is specified unless -l is too. + [9393762b80f3] + +2011-06-23 Todd C. Miller + + * plugins/sudoers/logging.c: + Rewrite logfile word wrapping code to be more straight-forward and + actually wrap at the correct place. + [f712a0c90f55] + +2011-06-22 Todd C. Miller + + * doc/CONTRIBUTORS, doc/contributors.pod, plugins/sudoers/sudoers.c: + Set use_pty=true in command details when use_pty is set in sudoers. + From Ludwig Nussel + [8d95a163dfc1] + +2011-06-20 Todd C. Miller + + * plugins/sudoers/po/zh_CN.mo, plugins/sudoers/po/zh_CN.po, + src/po/zh_CN.mo, src/po/zh_CN.po: + Sync Chinese (simplified) PO files from translationproject.org + [acce8eb7be18] + +2011-06-18 Todd C. Miller + + * MANIFEST, plugins/sudoers/po/eu.mo, plugins/sudoers/po/fi.mo, + plugins/sudoers/po/uk.mo, src/po/da.mo, src/po/da.po, src/po/eu.mo: + Add Danish translation from translationproject.org and add missing + Basque mo files. + [0c22bb21b9c4] + + * Makefile.in, configure, configure.in: + No longer need to specify LINGUAS in configure, "make install-nls" + now just installs all the .mo files it finds. + [fcd45cf04885] + +2011-06-17 Todd C. Miller + + * MANIFEST, doc/CONTRIBUTORS, doc/Makefile.in, doc/contributors.pod: + Build CONTRIBUTORS from newly-added contributors.pod + [8b192f2720f4] + + * doc/CONTRIBUTORS: + Rework the wording in the leading paragraph + [312044145cdd] + +2011-06-14 Todd C. Miller + + * MANIFEST, doc/CONTRIBUTORS: + Add a CONTRIBUTORS file with the names of folks who have contributed + code or patches to sudo since I started maintaining it (plus the + original authors). + [b8bdd8b59528] + +2011-06-13 Todd C. Miller + + * plugins/sudoers/env.c: + Preserve SHELL variable for "sudo -s". Otherwise we can end up with + a situation where the SHELL variable and the actual shell being run + do not match. + [b8b3974aee3e] + +2011-06-10 Todd C. Miller + + * configure, configure.in: + Only enable Solaris project support when setproject() is present in + libproject. + [49ad7857ab89] + + * sudo.pp: + Explicitly set mode and owner of /etc/sudoers instead of relying on + "cp -p" to work in the postinstall script. On AIX 6.1 at least the + postinstall script runs before the final file permissions are set. + [e41ffc0212b2] + +2011-06-09 Todd C. Miller + + * doc/sudo.pod, doc/sudoers.pod: + Refer the user to the "Command Environment" section in description + of sudo's -i option. + [263cc3be7eef] + + * doc/sudo.pod: + Fix typo + [35dfac450f4d] + +2011-06-08 Todd C. Miller + + * mkdep.pl: + If there is no old dependency for an object file, use the MANIFEST + to find its source. + [d15e3b9899f9] + + * compat/Makefile.in: + Remove dependency for getgrouplist.lo as we don't ship that source + file. + [312a6d5fe6b0] + +2011-06-07 Todd C. Miller + + * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y: + Do not declare yyparse() static as the actual function generated by + yacc is extern. + [9017b79dcf55] + +2011-06-06 Todd C. Miller + + * Makefile.in: + Remove locale files in "make uninstall" + [201ff261ecbe] + + * configure.in, plugins/sudoers/po/eu.po, plugins/sudoers/po/fi.po, + plugins/sudoers/po/uk.po, src/po/eu.po: + Add Basque translation and sync Finish and Ukranian translations. + [66d2c78c8a13] + + * configure, configure.in: + FreeBSD no longer needs the main sudo binary to link with -lpam now + that plug-ins are loaded with RTLD_GLOBAL. + [96c710df2457] + + * plugins/sudoers/group_plugin.c, src/load_plugins.c: + Load plugins with RTLD_GLOBAL instead of RTLD_LOCAL. This fixes + problems with pam modules not having access to symbols provided by + libpam on some platforms. Affects FreeBSD and SLES 10 at least. + [0d016983ec84] + + * Makefile.in: + Move xgettext invocation out of update-po target into update-pot + [19a73c6d017c] + +2011-06-04 Todd C. Miller + + * plugins/sudoers/po/sudoers.pot, src/po/sudo.pot: + Regenerate .pot files for 1.8.2rc2 + [c3037f591dd8] + + * Makefile.in, common/Makefile.in, compat/Makefile.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in, zlib/Makefile.in: + Move nls targets to the top level Makefile so the paths in the pot + file are saner + [65b9285cd8d9] + + * src/po/fi.mo: + Add compiled version of sudo Finish translation + [8f2405384ea3] + + * MANIFEST, plugins/sudoers/po/fi.mo, plugins/sudoers/po/uk.mo: + Update MANIFEST with .po and .mo files Rebuild sudoers fi and uk .mo + files + [a165e70fa9ec] + + * configure, configure.in, plugins/sudoers/po/fi.po: + Add Finish translation from translationproject.org + [4466f8a96ceb] + +2011-06-03 Todd C. Miller + + * doc/sudoers.pod: + The group named by exempt_group should not have a % prefix. + [df084d6b32c8] + +2011-06-01 Todd C. Miller + + * doc/sudoers.pod: + Fix typo; "Defaults group_plugin" not "Defaults sudo_plugin" + [5113699a3f8b] + +2011-05-31 Todd C. Miller + + * src/exec.c, src/exec_pty.c: + Fix compressed io log corruption in background mode by using _exit() + instead of exit() to avoid flushing buffers twice. + + Improved background mode support. When not allocating a pty, the + command is run in its own process group. This prevents write access + to the tty. When running in a pty, stdin is not hooked up and we + never read from /dev/tty, which results in similar behavior. + [87c15149894c] + + * compat/Makefile.in, mkdep.pl, plugins/sudoers/Makefile.in: + Clean up regress files Generate proper dependencies for regress objs + in compat + [88bfc728c1e7] + + * plugins/sudoers/Makefile.in: + Add missing dependency for check_fill.o. + [0bd6362e3e17] + +2011-05-29 Todd C. Miller + + * INSTALL, configure, configure.in: + Add support for --enable-nls[=location] + [b90db44a050f] + +2011-05-28 Todd C. Miller + + * plugins/sudoers/linux_audit.c: + Include gettext.h + [7f909a6e48cb] + + * plugins/sudoers/ldap.c, plugins/sudoers/parse.c: + Quiet gcc warnings. + [b41a6cdca583] + + * configure, configure.in: + Don't install .mo files if gettext was not found. + [1397b34cc165] + +2011-05-27 Todd C. Miller + + * src/exec.c: + Always allocate a pty when running a command in the background but + call setsid() after forking to make sure we don't end up with a + controlling tty. + [b6454ba172e8] + + * plugins/sudoers/iolog.c: + Add missing space between command name and the first command line + argument. + [fe217f0a36d4] + + * plugins/sudoers/sudoreplay.c: + Quiet a compiler warning on some platforms. + [de9f2849f236] + + * plugins/sudoers/po/README, src/po/README: + README file that directs people to translationproject.org + [30c0fc323281] + + * plugins/sudoers/po/uk.po, src/po/fi.po: + Sync translations with TP + [1d7d64559cba] + + * Makefile.in: + Add 'sync-po' target to top-level Makefile to rsync the po files + from translationproject.org. + [20508211aaa3] + + * plugins/sudoers/Makefile.in: + install nls files from install target + [5fc07b6cab38] + + * Makefile.in, plugins/sudoers/Makefile.in, src/Makefile.in, sudo.pp: + Include .mo files in sudo binary packags. + [278d4821a916] + + * configure, configure.in, plugins/sudoers/po/zh_CN.mo, + plugins/sudoers/po/zh_CN.po, src/po/zh_CN.mo, src/po/zh_CN.po: + Add simplified chinese translation + [2b33ffc755b9] + +2011-05-26 Todd C. Miller + + * configure, configure.in, plugins/sudoers/po/uk.mo, + plugins/sudoers/po/uk.po, src/po/uk.mo, src/po/uk.po: + Add ukranian translation + [2d8102688e93] + + * compat/Makefile.in: + refer to siglist.c, not ./siglist.c since not all makes will treat + foo and ./foo the same. + [6639d293ffba] + + * plugins/sudoers/sudoers.c: + Set def_preserve_groups before searching for the command when the -P + flag is specified. + [0edc7942f875] + + * Makefile.in, compat/Makefile.in, mkdep.pl, + plugins/sudoers/Makefile.in: + Add dependency for siglist.lo in compat. This is a generated file + so "make depend" needs to depend on it. + [28d0932f8b50] + + * compat/Makefile.in: + More dependency fixes. + [aad0d05cd020] + + * compat/Makefile.in: + Fix a few dependencies. + [eb21aa35a032] + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Place compiled mo files in the src dir, not the build dir. When + installing compiled mo files, display a status message. + [e15634c29cd3] + +2011-05-25 Todd C. Miller + + * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Tivoli Directory Server requires that seconds be present in a + timestamp, even though RFC 4517 states that they are optional. + [55fe23dd4ef9] + + * plugins/sudoers/sudo_nss.h: + Add missing bit of copyright + [d2eba3c364ca] + + * doc/visudo.pod: + Mention cycle detection warnings + [a76bef15ab67] + + * plugins/sudoers/visudo.c: + When checking aliases, also check the contents of the alias in case + there are problems with an alias that is referenced inside another. + Replace the self reference check with real alias cycle detection. + [a66c904cf53b] + + * plugins/sudoers/alias.c: + Set errno to ELOOP in alias_find() if there is a cycle. Set errno to + ENOENT in alias_find() and alias_remove() if the entry could not be + found. + [b4f0b89e433c] + + * plugins/sudoers/visudo.c: + Increment alias_seqno before calls to alias_remove_recursive() to + avoid false positives with the alias loop detection. Fixes spurious + warnings about unused aliases when they are nested. + [a344483b8193] + + * MANIFEST: + add mkdep.pl + [86b7ed33eab2] + + * plugins/sudoers/Makefile.in: + Add dependency on convenience libs to binaries + [cd3078b3c997] + + * Makefile.in: + mkdep.pl only works when run from the src dir + [f35a5e47c944] + + * Makefile.in, common/Makefile.in, compat/Makefile.in, mkdep.pl, + plugins/sample/Makefile.in, plugins/sample_group/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in, zlib/Makefile.in: + Auto-generate Makefile dependencies with a perl script. + [a3e4afcd7975] + +2011-05-23 Todd C. Miller + + * plugins/sudoers/match.c: + If the user specifies a runas group via sudo's -g option that + matches the runas user's group in the passwd database and that group + is not denied in the Runas_Spec, allow it. Thus, if user root's gid + in /etc/passwd is 0, then "sudo -u root -g root id" is allow even if + no groups are present in the Runas_Spec. + [e3f9732dc564] + +2011-05-22 Todd C. Miller + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Add dependencies on gettext.h + [a3a9dc51f78b] + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Fix install-nls target with HP-UX sh when gettext is not present. + [0c6b9655cd41] + +2011-05-20 Todd C. Miller + + * plugins/sudoers/Makefile.in, plugins/sudoers/po/sudoers.pot, + src/Makefile.in, src/po/sudo.pot: + regenerate .pot files for lbuf changes + [918ded125a0b] + + * configure, configure.in: + Add missing "checking" message for gettext when using the cache. + [9c21187ad1d2] + + * common/lbuf.c, include/lbuf.h, plugins/sudoers/ldap.c, + plugins/sudoers/parse.c, plugins/sudoers/sudo_nss.c, + src/parse_args.c: + Add primitive format string support to the lbuf code to make + translations simpler. + [ee71c7ef5299] + + * MANIFEST, plugins/sudoers/Makefile.in, + plugins/sudoers/po/sudoers.pot, src/Makefile.in, src/po/sudo.pot: + Add message catalog template files for sudo and the sudoers module. + [f3f8acb1f014] + + * MANIFEST, common/aix.c, common/alloc.c, compat/strsignal.c, + config.h.in, configure.in, doc/Makefile.in, include/gettext.h, + plugins/sudoers/iolog.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c, src/error.c, + src/net_ifs.c, src/sesh.c, src/sudo.c, src/sudo.h: + Add gettext.h convenience header. This is similar to but distinct + from the one included with the gettext package. + [930a0591f73c] + +2011-05-19 Todd C. Miller + + * configure, configure.in: + Add checks for nroff -c and -Tascii flags + [19ca990b3149] + + * configure, configure.in: + Add check for HP bundled C Compiler (which cannot create shared + libs) + [517716a7072d] + + * plugins/sudoers/sudoreplay.c: + Fix C format warnings. + [6514326013fa] + + * include/error.h: + Add __printflike + [e1749a30a406] + + * plugins/sudoers/ldap.c, plugins/sudoers/parse.c, + plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/visudo.c, src/parse_args.c: + Translate help / usage strings. + [ee1cc9b1a8bd] + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Set --msgid-bugs-address to the bugzilla url + [5a0aa250ca21] + + * Makefile.in, common/Makefile.in, compat/Makefile.in, configure, + configure.in, doc/Makefile.in, include/Makefile.in, + plugins/sample/Makefile.in, plugins/sample_group/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in, zlib/Makefile.in: + Add scaffolding to update .po files and install .mo files. + [f05f4eed1fe1] + + * doc/license.pod: + update copyright year + [fa0c62523875] + + * INSTALL, README: + No need to include version number at the top of these files. + [9f2981325351] + +2011-05-18 Todd C. Miller + + * plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/env.c, + plugins/sudoers/find_path.c, plugins/sudoers/group_plugin.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/visudo.c: + Minor warning/error cleanup + [9236dc85aeab] + + * config.h.in, configure.in: + Emulate ngettext for the non-nls case + [13571d63fa36] + + * plugins/sudoers/ldap.c: + Do not mark untranslatable strings for translation + [735f5d4413fe] + + * plugins/sudoers/check.c: + Use ROOT_UID not 0. + [09a268db8da4] + + * plugins/sudoers/check.c, plugins/sudoers/iolog.c, + plugins/sudoers/logging.c, src/exec.c, src/exec_pty.c, + src/load_plugins.c, src/sudo.c, src/sudo_edit.c: + Minor warning/error message cleanup + [3c7b1a7939b5] + + * plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/iolog.c, plugins/sudoers/ldap.c, + plugins/sudoers/logging.c, plugins/sudoers/mon_systrace.c, + plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c, src/exec.c, + src/exec_pty.c, src/net_ifs.c, src/selinux.c: + cannot -> "unable to" in warning/error messages + [31c3897649e9] + + * plugins/sudoers/check.c, plugins/sudoers/mon_systrace.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/visudo.c, src/exec_pty.c, + src/sudo.c, src/utmp.c: + can't -> "unable to" in warning/error messages + [127b75f15291] + + * configure, configure.in: + FreeBSD needs the main sudo executable to link with -lpam when + loading dynaic pam modules for some reason. + [944522cc9bef] + +2011-05-17 Todd C. Miller + + * plugins/sudoers/ldap.c, src/exec.c, src/exec_pty.c, src/sudo.c: + We don't want to translate debugging messages. + [56a1a365815a] + + * configure, configure.in, plugins/sudoers/Makefile.in, + plugins/sudoers/iolog.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c, + src/Makefile.in, src/sesh.c, src/sudo.c: + Add calls to bindtextdomain() and textdomain() Currently there are + two domains, one for the sudo front-end and one for the sudoers + plugin and its associated utilities. + [0426138f789e] + + * configure, configure.in: + Fix caching of libc gettext check. + [942142d2c43a] + + * plugins/sudoers/def_data.c, plugins/sudoers/defaults.c, + plugins/sudoers/mkdefaults: + Mark defaults descriptions for translation + [5b27f018e6cf] + + * NEWS: + Update for sudo 1.8.1p2 + [747c4dee2ca7] + +2011-05-16 Todd C. Miller + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Quiet compiler warning when SELinux is enabled. + [1fbf77dda240] + + * plugins/sudoers/plugin_error.c, plugins/sudoers/sudoreplay.c, + src/error.c, src/net_ifs.c, src/sesh.c: + Add missing includes of libintl.h. + [bc1d66316082] + + * plugins/sudoers/auth/pam.c: + Fix gettext marker. + [a5cf4ed66c66] + + * common/aix.c, common/alloc.c, compat/strsignal.c, + plugins/sudoers/auth/pam.c, plugins/sudoers/sudoers.h, src/sudo.h: + Include libint.h where needed. + [2b0e5a663c7b] + + * plugins/sudoers/alias.c, plugins/sudoers/auth/bsdauth.c, + plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb5.c, + plugins/sudoers/auth/pam.c, plugins/sudoers/auth/rfc1938.c, + plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c, + plugins/sudoers/auth/sia.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/bsm_audit.c, plugins/sudoers/check.c, + plugins/sudoers/defaults.c, plugins/sudoers/env.c, + plugins/sudoers/find_path.c, plugins/sudoers/gram.c, + plugins/sudoers/gram.y, plugins/sudoers/group_plugin.c, + plugins/sudoers/interfaces.c, plugins/sudoers/iolog.c, + plugins/sudoers/iolog_path.c, plugins/sudoers/ldap.c, + plugins/sudoers/linux_audit.c, plugins/sudoers/logging.c, + plugins/sudoers/parse.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/pwutil.c, plugins/sudoers/set_perms.c, + plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/toke.c, plugins/sudoers/toke.l, + plugins/sudoers/toke_util.c, plugins/sudoers/visudo.c: + Prepare sudoers module messages for translation. + [7212ae1909c5] + + * plugins/sudoers/sudoers.c: + Only check gid of sudoers file if it is group-readable. + [50e3bc0cb242] + + * plugins/sudoers/auth/aix_auth.c: + For AIX, keep calling authenticate() until reenter reaches 0. + [e240815b74b1] + +2011-05-09 Todd C. Miller + + * configure, configure.in: + Cache the status of the initial gettext() check. + [32751ebe1704] + + * INSTALL, configure, configure.in: + Add --disable-nls flag and improve checks for gettext. + [c7e6b17052de] + + * configure, configure.in: + When building with gcc on HP-UX, use -march=1.1 to produce portable + binaries on a pa-risc2 host. Previously, the +Dportable option was + used for the HP-UX C compiler but gcc always produced native + binaries. + [8f4c749324d7] + +2011-05-06 Todd C. Miller + + * common/aix.c, common/alloc.c, compat/strsignal.c, src/error.c, + src/exec.c, src/exec_pty.c, src/load_plugins.c, src/net_ifs.c, + src/parse_args.c, src/selinux.c, src/sesh.c, src/sudo.c, + src/sudo_edit.c, src/tgetpass.c, src/utmp.c: + Prepare sudo front end messages for translation. + [2fc2fabceccb] + +2011-05-04 Todd C. Miller + + * config.h.in, configure, configure.in, plugins/sudoers/auth/pam.c: + Add initial scaffolding to support localization via gettext() + [7d47b59fcf95] + + * compat/fnmatch.h, compat/glob.h: + Don't let the fnmatch/glob macros expand the function prototype. + [a9014aa0288e] + +2011-05-03 Todd C. Miller + + * compat/fnmatch.c, compat/fnmatch.h, compat/glob.c, compat/glob.h: + Resolve namespace collisions on HP-UX ia64 and possibly others by + adding a rpl_ prefix to our fnmatch and glob replacements and + #defining rpl_foo to foo in the header files. + [caa9b690a15d] + +2011-04-29 Todd C. Miller + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Split ALL, ROLE and TYPE into their own actions. Since you can only + have #ifdefs inside of braces, ROLE and TYPE use a naughty goto in + the non-SELinux case. This is safe because the actions are in one + big switch() statement. + [7473fc2cfa2c] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Fix regexp for matching a CIDR-style IPv4 netmask. From Marc Espie. + [9be3480c2865] + +2011-04-27 Todd C. Miller + + * doc/UPGRADE, doc/sudoers.pod: + askpass moved from sudoers to sudo.conf in sudo 1.8.0 + [b2c2956cec4e] + + * doc/sudoers.pod: + Remove obsolete warning about runas_default and ordering. Move + syslog facility and priority lists into the section where the + relevant options are described. + [e57b8dc3f779] + +2011-04-26 Todd C. Miller + + * plugins/sudoers/auth/sia.c: + Fix SIA support; we no longer have access to the real argc and argv + so allocate space for a fake one and use the argv passed to the + plugin with "sudo" for argv[0]. + [1c0552772ad2] + +2011-04-23 Todd C. Miller + + * src/net_ifs.c: + Remove useless realloc when trying to get the buffer size right. + [792225380a62] + + * plugins/sudoers/set_perms.c: + Be explicit when setting euid to 0 before call to setreuid(0, 0) + [7bfeb629fccb] + +2011-04-18 Todd C. Miller + + * configure, configure.in: + Need to do checks for krb5_verify_user, krb5_init_secure_context and + krb5_get_init_creds_opt_alloc regardless of whether or not + krb5-config is present. + [9d1b98ece1d3] + +2011-04-15 Todd C. Miller + + * plugins/sudoers/set_perms.c: + Work around weird AIX saved uid semantics on setuid() and + setreuid(). On AIX, setuid() will only set the saved uid if the euid + is already 0. + [069fc08150ca] + +2011-04-14 Todd C. Miller + + * sudo.pp: + update copyright year + [1c42d579ba6e] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Treat a missing includedir like an empty one and do not return an + error. + [92f71d8cbfd4] + +2011-04-12 Todd C. Miller + + * pp: + Fix ARCH setting in cross-compile Solaris packages. + [b0de281cc889] + + * sudo.pp: + Fix aix version setting. + [98437dbfb085] + + * plugins/sudoers/ldap.c: + Remove extraneous parens in LDAP filter when sudoers_search_filter + is enabled that causes a search error. From Matthew Thomas. + [1d75bf1fc8d9] + +2011-04-11 Todd C. Miller + + * plugins/sudoers/regress/iolog_path/check_iolog_path.c: + Correct sizeof() to fix test failure. + [fd2f7c0c0572] + + * plugins/sudoers/Makefile.in: + "install" target should depend on "install-dirs". Fixes "make -j" + problem and closes bz #487. From Chris Coleman. + [083902d38edb] + +2011-04-07 Todd C. Miller + + * config.h.in: + Add HAVE_RFC1938_SKEYCHALLENGE + [a94cb33758a8] + +2011-04-06 Todd C. Miller + + * NEWS: + Mention plugin loading and libgcc changes + [e11b30b5026a] + + * src/load_plugins.c, src/sudo.c, src/sudo_plugin_int.h: + Load plugins after parsing arguments and potentially printing the + version. That way, an error loading or initializing a plugin + doesn't break "sudo -h" or "sudo -V". + [1b76f2b096a2] + + * Makefile.in: + When using a sub-shell to invoke the sub-make, exec make instead of + running it inside the shell to avoid an extra process. + [fd2c04a71fbf] + + * compat/regress/fnmatch/fnm_test.in, compat/regress/glob/globtest.c: + Stop testing unspecified behavior in fnmatch Make glob test more + portable + [229803093725] + + * compat/Makefile.in: + No need to add current dir to include path and having it breaks the + test programs that expect to get the system glob.h and fnmatch.h + [68085f624be4] + + * INSTALL, configure, configure.in: + Fix and document --with-plugindir; partially from Diego Elio Petteno + [07edc52ea89e] + + * compat/Makefile.in, compat/regress/fnmatch/fnm_test.c, + compat/regress/fnmatch/fnm_test.in, compat/regress/glob/globtest.c, + compat/regress/glob/globtest.in: + Fix fnmatch and glob tests to not use hard-coded flag values in the + input file. Link test programs with libreplace so we get our + replacement verions as needed. + [c2cca448f660] + + * Makefile.in: + If make in a subdir fails, fail the target in the upper level + Makefile too. Adapted from a patch from Diego Elio Petteno + [76fc9a0d96fd] + + * configure, configure.in, plugins/sudoers/auth/rfc1938.c: + Add check for NetBSD-style 4-argument skeychallenge() as Gentoo also + has this. Adapted from a patch from Diego Elio Petteno + [a97279a59b93] + + * plugins/sudoers/Makefile.in: + Make SUDOERS_LDFLAGS reference $(LDFLAGS) instead of using @LDFLAGS@ + directly. + [47b884029b3b] + + * configure, configure.in: + Fix warnings when -without-skey, --without-opie, --without-kerb4, + --without-kerb5 or --without-SecurID were specified. + [71ad150f4d24] + + * MANIFEST: + Add plugins/sudoers/sudoers_version.h + [7423966de440] + + * configure, configure.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in: + Back out the --with-libpath addition to SUDOERS_LDFLAGS since that + now include LDFLAGS in the sudoers Makefile.in. Add missing settng + of @LDFLAGS@ in plugin Makefile.in files. + [b835826f889c] + +2011-04-05 Todd C. Miller + + * NEWS: + Mention %#gid support in User_List and Runas_List + [5a983dff017a] + + * plugins/sudoers/sudoers.c, plugins/sudoers/sudoers_version.h, + plugins/sudoers/visudo.c: + Keep track of sudoers grammar version and report it in the -V + output. + [52901a3c0296] + + * plugins/sudoers/sudo_nss.h: + Add multiple inclusion guard + [50853aed046e] + + * configure, configure.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in: + The --with-libpath option now adds to SUDOERS_LDFLAGS as well as + LDFLAGS. Remove old -static hack for HP-UX < 9. Add LTLDFLAGS and + set it to -Wc,-static-libgcc if not using GNU ld so we don't + have a dependency on the shared libgcc in sudoers.so. + [66ad8bc5e32d] + + * doc/sudoers.pod: + Fix typo; from Petr Uzel + [f9a7afd80892] + +2011-04-01 Todd C. Miller + + * plugins/sudoers/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. + [0c48e6414337] + +2011-03-31 Todd C. Miller + + * plugins/sudoers/testsudoers.c: + Remove NewArgv/NewArgc, they are no longer needed. + [16e18f734c7e] + + * plugins/sudoers/testsudoers.c: + Fix setting of user_args + [aa29e0d0a54a] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add '!' token to lex tracing + [5227ad266235] + + * plugins/sudoers/regress/testsudoers/test1.sh: + Use group bin in test, not wheel as most systems have the bin group + but the same is no longer true of wheel. + [718802b3b45e] + + * plugins/sudoers/toke.c, plugins/sudoers/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. + [78e281152c3a] + +2011-03-30 Todd C. Miller + + * sudo.pp: + Strip off the beta or release candidate version when building AIX + packages. + [28fe31668559] + + * configure, configure.in: + We need to include OSDEFS in CFLAGS when doing the utmp/utmpx + structure checks for glibc which only has __e_termination visible + when _GNU_SOURCE is *not* defined. + [59ae1698911f] + + * common/aix.c: + getuserattr(user, ...) will fall back to the "default" entry + automatically, there's no need to check "default" manually. + [3c7a47a61fdb] + +2011-03-29 Todd C. Miller + + * doc/UPGRADE: + Document parser changes. + [ec415503308d] + + * Makefile.in, common/Makefile.in, compat/Makefile.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in, zlib/Makefile.in: + If there is an existing sudoers file, only install if it passes a + syntax check. + [37427c73e8cb] + + * plugins/sudoers/regress/sudoers/test6.out.ok, + plugins/sudoers/testsudoers.c: + Add runasgroup support to testsudoers + [047ea5571f33] + + * plugins/sudoers/Makefile.in: + For "make check", keep going even if a test fails. + [ce6a0a73c372] + + * plugins/sudoers/testsudoers.c: + More useful exit codes: + * 0 - parsed OK and command matched. + * 1 - parse error + * 2 - command not matched + * 3 - command denied + [1d2ce1361903] + + * doc/sudoers.pod: + Document %#gid, and %:#nonunix_gid syntax. + [492d4f9696c4] + + * plugins/sudoers/pwutil.c: + Add support to user_in_group() for treating group names that begin + with a '#' as gids. + [20240c94a134] + + * config.h.in, configure, configure.in, src/utmp.c: + Add explicit check for struct utmpx.ut_exit.e_termination and struct + utmpx.ut_exit.__e_termination. HP-UX uses the latter. Only update + ut_exit if we detect one or the other. + [b4e8cab777e6] + +2011-03-28 Todd C. Miller + + * plugins/sudoers/toke.c: + Add back missing #include of config.h + [9ab3897a1b2e] + + * plugins/sudoers/iolog_path.c, + plugins/sudoers/regress/iolog_path/data: + Avoid a NULL deref on unrecognized escapes. Collapse %% -> % like + strftime() does. + [93395762cdcd] + + * aclocal.m4: + Quote first argument to AC_DEFUN(); from Elan Ruusamae + [97f53ad31d77] + +2011-03-27 Todd C. Miller + + * MANIFEST: + add new sudoers tests + [476af91b3da3] + + * plugins/sudoers/regress/sudoers/test8.in, + plugins/sudoers/regress/sudoers/test8.out.ok, + plugins/sudoers/regress/sudoers/test8.toke.ok: + Add test for a newline in the middle of a string when no line + continuation character is used. + [de2394bc86ab] + + * plugins/sudoers/toke.c, plugins/sudoers/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. + [bdb1d762a1d5] + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Move lexer globals initialization into init_lexer. + [1ce62211aadb] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Fix a potential crash when a non-regular file is present in an + includedir. Fixes bz #452 + [1586760c3525] + + * 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. + [b8535cb9012e] + +2011-03-25 Todd C. Miller + + * plugins/sudoers/redblack.c: + Don't need all sudoers.h here. + [8c0929f42dab] + + * src/sudo.c: + Print sudo version early, in case policy plugin init fails. + [47cddc4358bc] + +2011-03-24 Todd C. Miller + + * plugins/sudoers/regress/sudoers/test4.toke.ok: + Update to match change in input. + [4a3af8e68790] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Make an empty group or netgroup a syntax error. + [66f51ddc2ff6] + + * plugins/sudoers/regress/sudoers/test7.in, + plugins/sudoers/regress/sudoers/test7.out.ok, + plugins/sudoers/regress/sudoers/test7.toke.ok: + An empty group or netgroup should be a syntax error. + [bd5bf1e2edce] + + * plugins/sudoers/regress/sudoers/test6.in, + plugins/sudoers/regress/sudoers/test6.out.ok, + plugins/sudoers/regress/sudoers/test6.toke.ok: + Check that uids work in per-user and per-runas Defaults Check that + uids and gids work in a Command_Spec + [c5e848e6082b] + + * plugins/sudoers/regress/sudoers/test5.in, + plugins/sudoers/regress/sudoers/test5.out.ok, + plugins/sudoers/regress/sudoers/test5.toke.ok: + Test empty string in User_Alias and Command_Spec + [3a084d777e03] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Allow a group ID in the User_Spec. + [bc2859eb71dc] + +2011-03-23 Todd C. Miller + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Return an error for the empty string when a word is expected. Allow + an ID for per-user or per-runas Defaults. + [915c259b00ff] + + * plugins/sudoers/testsudoers.c: + Fix printing "User_Alias FOO = ALL" + [ba58c3d548b3] + +2011-03-22 Todd C. Miller + + * src/parse_args.c: + Better error message about invalid -C argument + [c9a8d15bbf5d] + + * NEWS: + fix typo + [cdcfbafed013] + + * doc/sudoers.pod: + Fix placement of equal size ('=') in user specification summary. + [5ad7178b230d] + +2011-03-21 Todd C. Miller + + * MANIFEST: + update to match sudoers regress + [e04db0648717] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Restore ability to define TRACELEXER and have trace output go to + stderr. + [d9531e4d1b20] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Restore old behavior of setting sawspace = TRUE for command line + args when a line continuation character is hit to avoid causing + problems for existing sudoers files. + [fd930ad25550] + + * plugins/sudoers/regress/sudoers/test4.in, + plugins/sudoers/regress/sudoers/test4.out.ok, + plugins/sudoers/regress/sudoers/test4.toke.ok: + Add test for line continuation and aliases + [29ab538ca6bb] + + * plugins/sudoers/Makefile.in: + Make test output line up nicely for parse vs. toke + [257ef82c1434] + + * plugins/sudoers/Makefile.in, + plugins/sudoers/regress/sudoers/test1.in, + plugins/sudoers/regress/sudoers/test1.out.ok, + plugins/sudoers/regress/sudoers/test1.toke.ok, + plugins/sudoers/regress/sudoers/test2.in, + plugins/sudoers/regress/sudoers/test2.out.ok, + plugins/sudoers/regress/sudoers/test2.toke.ok, + plugins/sudoers/regress/sudoers/test3.in, + plugins/sudoers/regress/sudoers/test3.out.ok, + plugins/sudoers/regress/sudoers/test3.toke.ok, + plugins/sudoers/regress/testsudoers/test1.ok, + plugins/sudoers/regress/testsudoers/test1.out.ok, + plugins/sudoers/regress/testsudoers/test1.sh, + plugins/sudoers/regress/testsudoers/test2.out, + plugins/sudoers/regress/testsudoers/test2.sh, + plugins/sudoers/regress/testsudoers/test3.ok, + plugins/sudoers/regress/testsudoers/test3.sh, + plugins/sudoers/regress/visudo/test1.ok, + plugins/sudoers/regress/visudo/test1.sh: + Move parser tests to sudoers directory and test the tokenizer output + too. + [44f529b3cdb6] + + * plugins/sudoers/toke.c, plugins/sudoers/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. + [355478293f8c] + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.h, + plugins/sudoers/toke.l: + Move LEXTRACE macro to toke.h so we can use it in yyerror(). + [72ee7a06d3ca] + +2011-03-20 Todd C. Miller + + * plugins/sudoers/testsudoers.c, plugins/sudoers/toke.c, + plugins/sudoers/toke.l: + Make lex tracing settable at run-time in testsudoers via the -t + flag. Trace output goes to stderr. Will be used by regress tests + to check lexer. + [93bd53c413c8] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Allow whitespace after the modifier in a Defaults entry. E.g. + "Defaults: username set_home" + [9dfcf8dd8a3a] + +2011-03-18 Todd C. Miller + + * mkpkg: + Don't set CC when cross-compiling. + [4b95b0c04e1c] + + * NEWS: + Credit Matthew Thomas for the sudoers_search_filter changes. + [a65998ab09f7] + + * MANIFEST: + Add the .sym files to the MANIFEST + [f599225cc861] + + * NEWS: + Update for sudo 1.8.1 beta + [71021e854c49] + + * doc/sudo_plugin.pod, plugins/sudoers/sudoers.c, src/parse_args.c: + user_shell -> run_shell to avoid confusion with the user's SHELL + variable. + [dc0ac6dafc21] + + * src/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). + [10b2883b7875] + + * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + 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. + [b0f1b721d102] + +2011-03-17 Todd C. Miller + + * configure, configure.in: + Remove the hack to disable -g in CFLAGS unless --with-devel + [89822cf84ef4] + + * doc/sudoers.pod: + The '@' character does not normally need to be quoted. + [7823f5ed829a] + + * plugins/sudoers/toke.c, plugins/sudoers/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. + [1ca6943e1824] + + * plugins/sudoers/regress/testsudoers/test3.ok, + plugins/sudoers/regress/testsudoers/test3.sh: + Add check for whitespace when a User_List is used for a per-user + Defaults entry. + [91f75e6dd19a] + + * plugins/sudoers/regress/testsudoers/test2.out, + plugins/sudoers/regress/testsudoers/test2.sh: + Expand quoted name checks to cover recent fixes. + [ce4f76bca146] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Fix parsing of double-quoted names in Defaultd and Aliases which was + broken in 601d97ea8792. + [424b0d6c1dc4] + + * plugins/sudoers/Makefile.in: + toke_util.c lives in $(srcdir) not $(devdir) + [94866bebee83] + +2011-03-16 Todd C. Miller + + * configure, configure.in: + Change trunk version to 1.8.x to distinguish from real 1.8.0. + [a9781e61d064] + + * NEWS, doc/UPGRADE: + Document major changes in 1.8.1 and add upgrade notes. + [f2cf51b0d9ce] + + * plugins/sudoers/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. + [06a2334dd674] + + * 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. + [1ce6481ece59] + + * doc/sudoers.pod: + Warn about the dangers of log_input and mention iolog_file and + iolog_dir in the log_input and log_output descriptions. + [ae854ffb0768] + + * pp: + sync with git version + [a993e39ce3cb] + + * doc/sudoers.pod: + It seems that h comes after i + [0f621109220d] + + * doc/sudoers.pod: + Move log_input and log_output to their proper, sorted, location. + Document set_utmp and utmp_runas. + [273b234b9c34] + + * src/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. + [f03a660315ee] + + * common/lbuf.c: + Fix printing of the remainder after a newline. Fixes "sudo -l" + output corruption that could occur in some cases. + [25d83fb501fc] + +2011-03-15 Todd C. Miller + + * config.h.in, configure, configure.in, src/exec_pty.c, + src/sudo_exec.h, src/utmp.c: + Add support for ut_exit + [b574c13f1bba] + + * doc/sudo_plugin.pod, plugins/sudoers/def_data.c, + plugins/sudoers/def_data.h, plugins/sudoers/def_data.in, + plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c, src/exec.c, + src/exec_pty.c, src/sudo.c, src/sudo.h, src/sudo_exec.h, src/utmp.c: + Add support for controlling whether utmp is updated and which user + is listed in the entry. + [44a81632133f] + + * plugins/sudoers/def_data.h, plugins/sudoers/defaults.h, + plugins/sudoers/ldap.c, plugins/sudoers/mkdefaults, + plugins/sudoers/parse.c: + Fix typo; tupple vs. tuple + [697744acb710] + + * src/utmp.c: + For legacy utmp, strip the /dev/ prefix before trying to determine + slot since the ttys file does not include the /dev/ prefix. + [7ad5b81ff90c] + + * aclocal.m4, configure, configure.in, pathnames.h.in: + Add check for _PATH_UTMP + [21e638029bfd] + +2011-03-14 Todd C. Miller + + * plugins/sudoers/regress/iolog_path/check_iolog_path.c: + Adapt check_iolog_path to sessid changes + [728b5fe2be6f] + + * config.h.in, configure, configure.in, src/Makefile.in, + src/exec_pty.c, src/sudo_exec.h, src/utmp.c: + Redo utmp handling. If no getutent()/getutxent() is available, + assume a ttyslot-based utmp. If getttyent() is available, use that + directly instead of ttyslot() so we don't have to do the stdin dup2 + dance. + [18aa455cd140] + +2011-03-11 Todd C. Miller + + * MANIFEST, src/Makefile.in, src/exec_pty.c, src/sudo_exec.h, + src/utmp.c: + Move utmp handling into utmp.c + [f6eae6c8e012] + + * common/aix.c, common/alloc.c, common/fileops.c, common/fmt_string.c, + common/lbuf.c, common/list.c, compat/isblank.c, compat/memrchr.c, + compat/mksiglist.c, compat/nanosleep.c, compat/snprintf.c, + compat/strlcat.c, compat/strlcpy.c, compat/strsignal.c, + compat/utimes.c, doc/sudo.pod, doc/visudo.pod, + include/sudo_plugin.h, plugins/sample/sample_plugin.c, + plugins/sample_group/getgrent.c, plugins/sample_group/plugin_test.c, + plugins/sudoers/alias.c, plugins/sudoers/auth/afs.c, + plugins/sudoers/auth/aix_auth.c, plugins/sudoers/auth/bsdauth.c, + plugins/sudoers/auth/dce.c, plugins/sudoers/auth/fwtk.c, + plugins/sudoers/auth/kerb4.c, plugins/sudoers/auth/kerb5.c, + plugins/sudoers/auth/pam.c, plugins/sudoers/auth/passwd.c, + plugins/sudoers/auth/rfc1938.c, plugins/sudoers/auth/secureware.c, + plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c, + plugins/sudoers/auth/sia.c, plugins/sudoers/boottime.c, + plugins/sudoers/bsm_audit.c, plugins/sudoers/env.c, + plugins/sudoers/find_path.c, plugins/sudoers/goodpath.c, + plugins/sudoers/logging.c, plugins/sudoers/parse.c, + plugins/sudoers/parse.h, plugins/sudoers/redblack.c, + plugins/sudoers/set_perms.c, plugins/sudoers/timestr.c, + plugins/sudoers/tsgetgrpw.c, plugins/sudoers/visudo.c, src/exec.c, + src/exec_pty.c, src/get_pty.c, src/parse_args.c, src/sudo.c, + src/sudo.h, src/sudo_edit.c, src/sudo_exec.h, src/sudo_noexec.c, + src/sudo_plugin_int.h, src/tgetpass.c: + Update copyright years. + [16aa39f9060a] + + * doc/sudo_plugin.pod, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/parse_args.c: + Add "user_shell" boolean as a way to indicate to the plugin that the + -s flag was given. + [fb1ef0897b32] + + * plugins/sudoers/iolog_path.c, plugins/sudoers/logging.c, + plugins/sudoers/sudoers.h: + Move sessid out of sudo_user. + [ba298ddb57f4] + + * plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c, + plugins/sudoers/logging.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Log the TSID even if it is not a simple session ID. + [d7cc1b9c513c] + + * doc/sample.sudo.conf, doc/sudo.pod, doc/sudoers.pod: + Document noexec in sample.sudo.conf and add back noexec_file section + in sudoers with a note that it is deprecated. + [4a6e961e494d] + + * plugins/sudoers/set_perms.c: + Fix running commands as non-root on systems where setreuid() changes + the saved uid based on the effective uid we are changing to. + [df0769b71b34] + +2011-03-10 Todd C. Miller + + * plugins/sudoers/defaults.c, src/load_plugins.c, src/sudo.c, + src/sudo.h: + Move noexec path into sudo.conf now that sudo itself handles noexec. + Currently can be configured in sudoers too but is now undocumented + and will be removed in a future release. + [6fa8befdc110] + + * doc/sudo.pod, doc/sudoers.pod: + Document "Path noexec ..." in sudo.conf. No longer document + noexec_file in sudoers, it will be removed in a future release. + [24eee3a0b3e5] + + * plugins/sudoers/env.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/sudo.c, src/sudo.h: + Move noexec handling to sudo front-end where it is documented as + being. + [3ed4f10d7052] + + * config.h.in, configure, configure.in, plugins/sudoers/sudoers.c, + src/exec.c, src/exec_pty.c, src/sudo.c, src/sudo.h, src/sudo_edit.c, + src/sudo_exec.h: + Add support for disabling exec via solaris privileges. Includes + preparation for moving noexec support out of sudoers and into front + end as documented. + [dec843ed553e] + + * plugins/sample/Makefile.in, plugins/sample/sample_plugin.sym, + plugins/sample_group/Makefile.in, + plugins/sample_group/sample_group.sym, plugins/sudoers/Makefile.in, + plugins/sudoers/sudoers.sym: + Only export the symbols corresponding to the plugin structs. + [8d8d03b0ca54] + + * configure, configure.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in: + Install plugins manually instead of using libtool. This works + around a problem on AIX where libtool will install a .a file + containing the .so file instead of the .so file itself. + [796971cfbddb] + + * Makefile.in: + Move check into its own rule since some versions of make will run + both targets as the default rule. + [34d759979176] + + * configure, ltmain.sh, m4/libtool.m4, m4/ltoptions.m4, + m4/ltversion.m4, m4/lt~obsolete.m4: + Update to libtool 2.2.10 + [34c130de6af7] + +2011-03-09 Todd C. Miller + + * src/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. + [d5b9c8eb9000] + + * compat/mktemp.c: + Reorder functions to quiet a compiler warning. + [c9e9a23729f0] + + * mkpkg: + Use the Sun Studio C compiler on Solaris if possible + [11a86e27891e] + +2011-03-08 Todd C. Miller + + * mkpkg: + Fix default setting of osversion variable. + [52e49ca1cedd] + + * doc/sudo_plugin.pod: + Make two login_class entris consistent. + [18ff1fa94a91] + + * config.h.in, configure, configure.in, src/exec.c, src/exec_pty.c, + src/sudo_exec.h: + Add support for adding a utmp entry when allocating a new pty. + Requires the BSD login(3) or SYSV/POSIX getutent()/getutxent(). + Currently only creates a new entry if the existing tty has a utmp + entry. + [32db72b81d80] + + * plugins/sudoers/boottime.c: + Avoid pulling in headers we don't need on Linux For getutx?id(), + call setutx?ent() first and always call endutx?ent(). + [5dad21e1ee1b] + + * configure, configure.in: + Add some more libs to SUDOERS_LIBS instead of relying on them to be + pulled in by SUDO_LIBS. + [18a7c21c09a7] + + * plugins/sudoers/sudoers.c: + Fix return value of "sudo -l command" when command is not allowed, + broken in [c7097ea22111]. The default return value is now TRUE and + a bad: label is used when permission is denied. Also fixed missing + permissions restoration on certain errors. On error()/errorx(), the + password and group files are now closed before returning. + [4f2d0e869ae5] + +2011-03-07 Todd C. Miller + + * plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c: + Fix passing of login class back to sudo front end. + [6f70a784ce48] + + * mkpkg: + Add --osversion flag to specify OS instead of running "pp + --probeonly" + [a8efdccb7bc1] + + * sudo.pp: + Fix expr usage w/ GNU expr + [48895599ee63] + +2011-03-06 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Fix exit value for validate and list mode. + [c7097ea22111] + + * plugins/sudoers/sudoers.c: + Fix non-interactive mode with sudoers plugin. + [172f29597bd2] + +2011-03-05 Todd C. Miller + + * doc/sudoreplay.pod: + sudoreplay can now find IDs other than %{seq} and display the + session. + [fc3dd3be67e9] + +2011-03-04 Todd C. Miller + + * plugins/sudoers/sudoreplay.c: + Add support for replaying sessions when iolog_file is set to + something other than %{seq}. + [ca3131243874] + + * plugins/sudoers/visudo.c: + If we are killed by a signal, display the name of the signal that + got us. + [994bb76a990e] + + * configure, configure.in: + Move libs used for authentication from SUDO_LIBS to SUDOERS_LIBS + where they belong. + [40f94b936fa4] + + * configure.in: + Fix bug in skey/opie check that could cause a shell warning. + [83c043072be5] + + * plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c: + No longer need sudo_getepw() stubs. + [bbee15c36912] + +2011-03-03 Todd C. Miller + + * plugins/sudoers/sudo_nss.c: + Fix exit value of "sudo -l command" in sudoers module. + [a6541867521b] + +2011-03-02 Todd C. Miller + + * compat/regress/glob/globtest.c: + Use fgets() not fgetln() for portability. + [df1bb67fb168] + + * sudo.pp: + Don't use the beta or release candidate version as the rpm release. + [d661ef78021a] + +2011-02-25 Todd C. Miller + + * configure, configure.in: + version 1.8.0 + [f6530d56f6ae] [SUDO_1_8_0] + + * NEWS: + update sudo 1.8 section + [f2ee2cf95d18] + +2011-02-23 Todd C. Miller + + * plugins/sudoers/regress/testsudoers/test2.sh: + fix test description + [cd5730fa9f09] + + * plugins/sudoers/regress/testsudoers/test2.out, + plugins/sudoers/regress/testsudoers/test2.sh, + plugins/sudoers/regress/visudo/test2.out, + plugins/sudoers/regress/visudo/test2.sh: + convert test2 to use testsudoers + [b5ec3f0b69f1] + + * include/sudo_plugin.h, src/sudo_plugin_int.h: + Move struct generic_plugin to sudo_plugin_int.h + [6f7bc629329c] + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/parse.c, plugins/sudoers/parse.h, + plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Allow sudoers file name, mode, uid and gid to be specified in the + settings list. The sudo front end does not currently set these but + may in the future. + [22f38a0fda2a] + +2011-02-21 Todd C. Miller + + * configure, configure.in, doc/sudo.cat, doc/sudo.man.in, + doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.cat, + doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.man.in, + doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/visudo.cat, + doc/visudo.man.in: + 1.8.0rc1 + [5d4588b9c057] + + * doc/sudo.pod, doc/sudoreplay.pod, doc/visudo.pod, + plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c, + src/parse_args.c, src/sudo.h: + add help text to sudo, visudo and sudoreplay for the -h option + [52e7378d8476] + +2011-02-19 Todd C. Miller + + * compat/snprintf.c: + avoid using "howmany" for a parameter name since it is a select- + related macro + [a14d565401a1] + + * doc/sudoers.pod: + mention group_plugin when describing nonunix_group + [e0d1d0034b17] + + * doc/sudo_plugin.pod: + Add missing period at end of sentence + [6744d7e9056d] + + * Makefile.in, doc/Makefile.in, include/Makefile.in, + plugins/sample/Makefile.in, plugins/sample_group/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + add localstatedir; closes bug 471 + [7aefcab85088] + + * config.h.in, configure, configure.in, plugins/sudoers/sudoreplay.c, + src/exec.c, src/exec_pty.c: + The howmany macro lives in sys/sysmacros.h on SVR5 systems Closes + Bug 470 + [927ed6740f32] + + * configure.in: + add missing AH_TEMPLATE for ENV_RESET + [16300010c986] + + * src/exec.c: + SVR5 systems return non-zero for success on socketpair(), check for + -1 instead. Closes Bug 469 + [4d276494bf8e] + +2011-02-16 Todd C. Miller + + * configure, configure.in: + 1.8.0b5 + [d611cd5d73d3] + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudoers.cat, doc/sudoers.ldap.cat, + doc/sudoers.ldap.man.in, doc/sudoers.man.in, doc/sudoreplay.cat, + doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in: + regen + [85e96eeaed82] + + * doc/sudo.pod: + Document that a sudo.conf file with no Pligin lines uses the default + sudoers plugins. + [88bd52da977f] + + * src/load_plugins.c: + If sudo.conf contains no Plugin lines, use the default sudoers + policy and I/O plugins. + [fd8f4cb811ab] + +2011-02-14 Todd C. Miller + + * plugins/sudoers/sudo_nss.c: + Avoid printing empty "Runas and Command-specific defaults for user" + line. + [2dd330fe4f8b] + + * common/lbuf.c: + Truncate the buffer at buf.len before printing in the non-wordwrap + case. + [901e9833f80d] + + * common/lbuf.c: + Remove extra newline when the tty width is very small or unavailable + [245c05506c0e] + +2011-02-11 Todd C. Miller + + * plugins/sudoers/alias.c: + Remove unneeded variable. + [2c086d30b796] + +2011-02-09 Todd C. Miller + + * configure, configure.in: + Prefer getutxid over getutid + [3f3322e9c93e] + + * plugins/sudoers/boottime.c: + Include utmp.h / utmpx.h before missing.h as apparently including it + afterwards causes a compilation problem on GNU Hurd. + [a528029ae962] + +2011-02-07 Todd C. Miller + + * plugins/sudoers/sudoreplay.c, plugins/sudoers/toke_util.c: + #include "foo.h", not for local includes. + [f65ec693998e] + + * src/parse_args.c: + remove bogus XXX + [9136c17d53ce] + + * compat/mksiglist.c: + Fix typo + [1a3bb7b455c9] + + * compat/glob.c, plugins/sudoers/ldap.c, plugins/sudoers/logging.c, + plugins/sudoers/match.c: + return foo not return(foo) + [5c9e0647359a] + +2011-02-06 Todd C. Miller + + * src/exec.c: + Remove duplicate FD_SET of signal_pipe[0] + [3096527d2215] + +2011-02-05 Todd C. Miller + + * compat/mksiglist.c: + Use "missing.h" not in generated code. + [d8e09cffbe09] + +2011-02-04 Todd C. Miller + + * aclocal.m4, configure: + fix --with-iologdir=no + [a89699cb5f5f] + + * aclocal.m4, configure: + fix typo that broke --with-iologdir + [91b54eb22403] + +2011-02-03 Todd C. Miller + + * configure, configure.in, doc/sudo.cat, doc/sudo.man.in, + doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.cat, + doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.man.in, + doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/visudo.cat, + doc/visudo.man.in: + Bump version to 1.8.0b4 + [e2b7f2cdc02e] + + * NEWS: + sync + [decf5a0a8a33] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Attempt to clarify how users and groups interact in Runas_Specs + [e6fb3a2dbd77] + + * plugins/sudoers/regress/visudo/test2.out, + plugins/sudoers/regress/visudo/test2.sh: + Add test for quoted group that contains escaped double quotes + [44596c48c629] + + * src/exec.c, src/exec_pty.c: + Pass SIGUSR1/SIGUSR2 through to the child. + [c3108a827b01] + + * src/exec_pty.c, src/sudo_exec.h: + Use special values SIGCONT_FG and SIGCONT_BG instead of SIGUSR1 and + SIGUSR2 to indicate whether the child should be continued in the + foreground or background. + [35ca47cc6785] + + * src/exec.c: + Use pid_t not int and check the return value of kill() + [36ae7d37d7f9] + +2011-02-02 Todd C. Miller + + * src/exec_pty.c: + Remove obsolete comment + [baebef4919f6] + + * src/exec.c: + In non-pty mode before continuing the child, make it the foreground + pgrp if possible. Fixes resuming a shell. + [fef5b1d02ddb] + + * src/exec_pty.c: + If we get a signal other than SIGCHLD in the monitor, pass it + directly to the child. + [b3ecb28163a0] + + * src/exec.c, src/exec_pty.c, src/sudo.h: + Save signal state before changing handlers and restore before we + execute the command. + [faf7475dc4bf] + +2011-02-01 Todd C. Miller + + * plugins/sudoers/iolog.c: + Use a char array to map a number to a base36 digit. + [257576c51f8b] + + * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod: + Be clear about what versions of sudo support new LDAP attributes. + Fix up some formatting of attribute names. Minor other tweaks. + [39f65df71f65] + +2011-01-31 Todd C. Miller + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + match quoted strings the same way whether in a Defaults line or as a + user/group/netgroup name. Fixes escaped double quotes in quoted + user/group/netgroup names. + [601d97ea8792] + + * plugins/sudoers/Makefile.in: + 'make check' depends on visudo and testsudoers + [127c5a24df8f] + + * plugins/sudoers/sudoers2ldif: + Add sudoOrder attribute to each entry Parse LOG_{INPUT,OUTPUT} tags + [9029163a58c3] + +2011-01-30 Todd C. Miller + + * doc/UPGRADE: + Mention LDAP attribute compatibility status. + [2c3595aaec63] + +2011-01-28 Todd C. Miller + + * README.LDAP: + Mention phpQLAdmin + [9304c9064fbe] + + * INSTALL, NEWS, config.h.in, configure, configure.in, + doc/sudoers.man.in, doc/sudoers.pod, plugins/sudoers/defaults.c: + Add --disable-env-reset configure option. + [8a753aa13a46] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Document that sudoers_locale also affects logging and email. + [998d6ac11277] + + * NEWS, config.h.in, configure, configure.in, + plugins/sudoers/logging.c: + Do logging and email sending in the locale specified by the + "sudoers_locale" setting ("C" by default). Email send by sudo + includes MIME headers when the sudoers locale is not "C". + [cb7e55408400] + +2011-01-27 Todd C. Miller + + * plugins/sudoers/check.c: + Fix indentation + [65ae7e92b9e4] + +2011-01-25 Todd C. Miller + + * NEWS, src/parse_args.c, src/sudo.c: + Perform command escaping for "sudo -s" and "sudo -i" after + validating sudoers so the sudoers entries don't need to have all the + backslashes. + [4e168c103f4b] + +2011-01-24 Todd C. Miller + + * plugins/sudoers/logging.c: + Prepend "list " to the command logged when "sudo -l command" is used + to make it clear that the command was listed, not run. + [f392a6056cd6] + + * plugins/sudoers/parse.c: + cosmetic change + [7c0951dbc2dd] + + * common/aix.c, common/alloc.c, common/fileops.c, common/fmt_string.c, + common/list.c, common/term.c, compat/fnmatch.c, compat/getcwd.c, + compat/glob.c, compat/isblank.c, compat/memrchr.c, compat/mktemp.c, + compat/nanosleep.c, compat/regress/glob/globtest.c, + compat/snprintf.c, compat/strlcat.c, compat/strlcpy.c, + compat/strsignal.c, compat/utimes.c, plugins/sample/sample_plugin.c, + plugins/sample_group/getgrent.c, plugins/sample_group/plugin_test.c, + plugins/sudoers/alias.c, plugins/sudoers/auth/afs.c, + plugins/sudoers/auth/aix_auth.c, plugins/sudoers/auth/bsdauth.c, + plugins/sudoers/auth/dce.c, plugins/sudoers/auth/fwtk.c, + plugins/sudoers/auth/kerb4.c, plugins/sudoers/auth/kerb5.c, + plugins/sudoers/auth/pam.c, plugins/sudoers/auth/passwd.c, + plugins/sudoers/auth/rfc1938.c, plugins/sudoers/auth/secureware.c, + plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c, + plugins/sudoers/auth/sia.c, plugins/sudoers/bsm_audit.c, + plugins/sudoers/check.c, plugins/sudoers/defaults.c, + plugins/sudoers/find_path.c, plugins/sudoers/goodpath.c, + plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/iolog.c, plugins/sudoers/ldap.c, + plugins/sudoers/match.c, plugins/sudoers/mon_systrace.c, + plugins/sudoers/parse.c, plugins/sudoers/pwutil.c, + plugins/sudoers/redblack.c, plugins/sudoers/set_perms.c, + plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/timestr.c, plugins/sudoers/toke.c, + plugins/sudoers/toke.l, plugins/sudoers/toke_util.c, + plugins/sudoers/tsgetgrpw.c, plugins/sudoers/visudo.c, + src/exec_pty.c, src/get_pty.c, src/load_plugins.c, src/parse_args.c, + src/sudo_noexec.c, src/tgetpass.c: + standardize on "return foo;" rather than "return(foo);" or "return + (foo);" + [32d76c5aaf8c] + + * plugins/sudoers/sudoers.c: + Do not reject sudoers file just because it is root-writable. + [0febc579185b] + +2011-01-21 Todd C. Miller + + * NEWS: + sync + [1ab03f8278ff] + + * plugins/sudoers/sudo_nss.c: + For "sudo -U user -l" if user is not authorized on the host, say so. + [289afe6dd15c] + + * plugins/sudoers/ldap.c: + In sudo_ldap_lookup(), always do the initial sudoers check as the + invoking user. If we are listing another user's privs we will do a + separate lookup using list_pw later. + [e52bc15de76d] + +2011-01-20 Todd C. Miller + + * MANIFEST: + add parser fill tests + [4f65140d3515] + + * compat/regress/glob/globtest.c, compat/regress/glob/globtest.in: + Don't test features not supported by the bundled glob() + [8ec7ace11949] + + * Makefile.in, aclocal.m4, common/Makefile.in, common/term.c, + compat/Makefile.in, configure.in, doc/LICENSE, doc/Makefile.in, + doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod, doc/sudoers.man.in, + doc/sudoers.pod, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + plugins/sudoers/check.c, plugins/sudoers/defaults.c, + plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c, + plugins/sudoers/ldap.c, plugins/sudoers/match.c, + plugins/sudoers/pwutil.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/toke.c, plugins/sudoers/toke.l, + plugins/sudoers/toke_util.c, src/Makefile.in, zlib/Makefile.in: + Update copyright year to 2011 + [ac1b45cb1809] + + * plugins/sudoers/sudo_nss.c: + When listing, use separate lbufs for the defaults and the privileges + and only print something if the number of privileges is non-zero. + Fixes extraneous Defaults output for "sudo -U unauthorized_user -l". + [d0854d39f8ef] + + * plugins/sudoers/ldap.c: + Stash pointer to user group vector in LDAP handle and only reuse the + query if it has not changed. We always allocate a new buffer when + we reset the group vector so a simple pointer check is sufficient. + [88861d4eba69] + + * plugins/sudoers/sudo_nss.c: + Check initgroups() return value. + [3bdaf58408a7] + + * plugins/sudoers/Makefile.in, + plugins/sudoers/regress/parser/check_fill.c: + Add tests for the fill functions in toke_util.c + [bca587ab4956] + +2011-01-19 Todd C. Miller + + * plugins/sudoers/regress/iolog_path/check_iolog_path.c: + fix copyright year + [e2038cdaf055] + + * NEWS: + sync + [56ca5d5eaebe] + +2011-01-18 Todd C. Miller + + * common/term.c: + Clear, don't set, OPOST in c_oflag as was intended in 506ad5ae9b4e. + [b91f266624ec] + +2011-01-14 Todd C. Miller + + * mkpkg, sudo.pp: + Add Requires line for audit-libs >= 1.4 for RHEL5+ + [6c02f976171b] + + * pp: + sync with git version + [d301c32d5865] + +2011-01-13 Todd C. Miller + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + fix typo + [39353f92976f] + +2011-01-12 Todd C. Miller + + * NEWS: + Update for sudo 1.7.4p5 + [b444da76901f] + + * doc/schema.OpenLDAP, doc/schema.iPlanet: + Add sudoNotBefore and sudoNotAfter attributes as optional attributes + to the sudoRole object class. From Andreas Mueller + [dacfad7e7a95] + +2011-01-11 Todd C. Miller + + * NEWS: + Mention "sudo -g group" password check fix. + [1eb8fb14e53b] + + * plugins/sudoers/sudoers.c: + Fix "sudo -g" support in the sudoers module. + [07d1b0ce530e] + + * plugins/sudoers/check.c: + If the user is running sudo as himself but as a different group we + need to prompt for a password. + [caf1fcc9a117] + +2011-01-10 Todd C. Miller + + * NEWS, config.h.in, configure, configure.in, doc/sudoers.ldap.cat, + doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod, + plugins/sudoers/ldap.c: + Add support for TIMEOUT in ldap.conf, mapping to the OpenLDAP + LDAP_OPT_TIMEOUT. There is no corresponding option for mozilla- + derived LDAP SDKs but we can pass the timeout parameter to + ldap_search_ext_s() or ldap_search_st() when possible. + [5537049991f7] + + * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in: + regen + [5b361c3c4324] + + * NEWS, doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Add NETWORK_TIMEOUT as an alias for BIND_TIMELIMIT for compatibility + with OpenLDAP ldap.conf files. + [e97843bd16fb] + + * plugins/sudoers/pwutil.c: + If user has no supplementary groups, fall back on checking the group + file expliticly. + [5223ad4eb690] + +2011-01-08 Todd C. Miller + + * plugins/sudoers/toke.h, plugins/sudoers/toke_util.c: + constify + [6e132a4cca61] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.h, + plugins/sudoers/toke.l: + Move fill macro to toke.h + [623d430798cf] + + * MANIFEST, plugins/sudoers/Makefile.in, plugins/sudoers/toke.c, + plugins/sudoers/toke.h, plugins/sudoers/toke.l, + plugins/sudoers/toke_util.c: + Split tokenizer utility functions out into toke_util.c + [89a97bd51618] + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/toke.c, plugins/sudoers/toke.l: + ANSIfy + [ca0eba1dfaa9] + +2011-01-07 Todd C. Miller + + * MANIFEST: + sync + [a43f94064bb3] + + * plugins/sudoers/Makefile.in: + Add visudo tests to check target + [8c82fb4ed40f] + + * compat/Makefile.in, compat/regress/fnmatch/fnm_test.c, + compat/regress/fnmatch/fnm_test.in, compat/regress/glob/files, + compat/regress/glob/globtest.c, compat/regress/glob/globtest.in: + Add my regress tests for fnmatch() and glob() from OpenBSD. + [6e8c1f211723] + + * plugins/sudoers/regress/testsudoers/test1.sh, + plugins/sudoers/regress/visudo/test1.ok, + plugins/sudoers/regress/visudo/test1.sh: + Add regress test for command tags using visudo -c + [18b0ef207c0f] + + * plugins/sudoers/Makefile.in, + plugins/sudoers/regress/testsudoers/test1.ok, + plugins/sudoers/regress/testsudoers/test1.sh: + Add support for regress tests using testsudoers + [1fa94bd2671b] + + * plugins/sudoers/testsudoers.c: + Need to set user_name explicitly due to internal changes made when + converting sudoers to a plugin. + [1fa54e86a364] + +2011-01-06 Todd C. Miller + + * MANIFEST, Makefile.in, common/Makefile.in, compat/Makefile.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + plugins/sudoers/regress/iolog_path/check_iolog_path.c, + plugins/sudoers/regress/iolog_path/data, src/Makefile.in, + zlib/Makefile.in: + Add regression tests for iolog_path() + [afa4b416e559] + + * Makefile.in, common/Makefile.in, compat/Makefile.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in, zlib/Makefile.in: + Add support for "make Makefile" to regenerate Makefile from + Makefile.in + [98bd2dda3294] + + * plugins/sudoers/iolog_path.c: + Quiest a bogus compiler warning. + [5ff932a7ad67] + +2011-01-05 Todd C. Miller + + * plugins/sudoers/iolog_path.c: + Protect call to setlocale() with HAVE_SETLOCALE + [2c29ee3ccc81] + +2011-01-04 Todd C. Miller + + * MANIFEST: + mkstemps.c was renamed mktemp.c + [ae299c3b1827] + + * NEWS: + Update from 1.7 branch + [20817d79717b] + + * Makefile.in: + Use "mv -f" when regenerating ChangeLog + [c163635206c6] + + * plugins/sudoers/match.c: + Fix NULL dereference with "sudo -g group" when the sudoers rule has + no runas user or group listed. Fixes RedHat bug Bug 667103. + [41a6a1243d9e] + +2011-01-03 Todd C. Miller + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Correct the default sudo.conf example + [4e791698cad1] + +2010-12-31 Todd C. Miller + + * plugins/sudoers/iolog_path.c: + Reset slashp if we allocate a new buffer for strftime() + [e491daa4203b] + + * plugins/sudoers/iolog_path.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Add extra out parameter to expand_iolog_path() to allow the caller + to split the path into dir and file components if needed. + [88346bc5ae39] + +2010-12-30 Todd C. Miller + + * plugins/sudoers/iolog.c: + mkdir_iopath() returns size_t now that it uses strlcpy() and not + snprintf() + [3c4c64d265eb] + + * plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c: + Trim leading slashes from iolog_file and trailing slashes from + iolog_dir + [a803b51f8948] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + plugins/sudoers/iolog.c, plugins/sudoers/iolog_path.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Pass a single I/O log file name in command_details instead of + separate dir + file parameters. + [d672a3e46e80] + + * plugins/sudoers/sudoreplay.c: + change an error() to errorx() + [8013dcfdd69d] + + * plugins/sudoers/iolog.c: + Add missing cwd line to I/O log info file that got dropped when + iolog_deserialize_info() was added + [7cf84f208423] + +2010-12-29 Todd C. Miller + + * plugins/sudoers/iolog.c: + Avoid relying on globals filled in by the sudoers policy module for + the sudoers I/O log module. The I/O log open function now pulls the + bits it needs out of user_info and command_info. + [c02f6951b0cc] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + If no iolog file is specified by the policy plugin, use io_nextid() + to determine the next file in the sequence. + [faa1130b1020] + +2010-12-28 Todd C. Miller + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document iolog_compress in command_info + [58895c7d12f5] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c: + Add support for the iolog_compress variable in command_info. + [36f13a2fd1c1] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c: + Add sigsetjmp() calls to all plugin entry points just to be safe. + [3fa482355bc4] + + * src/sudo.c, src/sudo.h: + Don't need iolog variables in struct command_details, they are for + the I/O log plugins to handle. + [5111579ffd9d] + +2010-12-27 Todd C. Miller + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Document use of mkdtemp() for iolog path teplates + [5db6101408a9] + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudoers.cat, doc/sudoers.ldap.cat, + doc/sudoers.ldap.man.in, doc/sudoers.man.in, doc/sudoreplay.cat, + doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in: + regen + [1ee11fd6d4eb] + + * doc/sudo_plugin.pod, doc/sudoers.pod: + Document iolog_file and supported escape sequences for sudoers. + Clarify that iolog_file can contain directories. + [da611dedcbdb] + + * compat/Makefile.in, configure, configure.in: + Fix building of mkstemps/mkdtemp replacements. + [793a5e303122] + + * compat/mkstemps.c, compat/mktemp.c, config.h.in, configure, + configure.in, include/missing.h: + Provide mkdtemp() for systems without it. + [b0527dfa965c] + + * plugins/sudoers/iolog_path.c: + Fix typo + [277f6c514cba] + + * plugins/sudoers/iolog.c: + Only use mkdtemp() if the path ends in at least 6 Xs since otherwise + glibc mkdtemp() returns EINVAL. + [2e7323b05579] + + * plugins/sudoers/Makefile.in, plugins/sudoers/def_data.c, + plugins/sudoers/def_data.h, plugins/sudoers/def_data.in, + plugins/sudoers/defaults.c, plugins/sudoers/iolog.c, + plugins/sudoers/iolog_path.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Allow sudoers to specify the iolog file in addition to the iolog + dir. Add escape sequence support to iolog file and dir: sequence + number, user, group, runas_user, runas_group, hostname and + command in addition to any escape sequence recognized by + strftime(3). + [75cd32ee0435] + + * plugins/sudoers/iolog.c: + Add missing sigsetjmp() call in I/O plugin open function. Fixes a + crash when the I/O plugin calls error(), errorx() or log_error(). + [1a6718bd817d] + +2010-12-21 Todd C. Miller + + * doc/sudo_plugin.pod, plugins/sudoers/iolog.c, + plugins/sudoers/sudoers.c: + Give the policy module fine-grained control over what the I/O plugin + logs. + [d29784fd2a66] + + * common/term.c: + Clear OPOST from c_oflag like we used to. Fixes screen-based + editors such as vi. + [506ad5ae9b4e] + + * doc/sudoers.pod: + Clarify umask option description. From Reuben Thomas. + [1294ac84222b] + +2010-12-20 Todd C. Miller + + * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Pick last match in LDAP sudoers too + [fbfd8e85703b] + + * doc/sudo_plugin.pod: + Document iolog_file, iolog_dir and use_pty + [26120a59c20e] + + * plugins/sample/sample_plugin.c, plugins/sudoers/iolog.c, + plugins/sudoers/sudoers.c: + Adapt plugins to version I/O logging ABI 1.1 + [880dd64bc1e8] + + * src/exec.c, src/sudo.h: + Add use_pty command_info flag for policies to indicate that a pty + should be allocated even if no I/O logging is performed. + [e7b167f8a6e5] + + * src/sudo.c: + Add remaining plugin convenience functions + [ffeaf96da031] + + * include/sudo_plugin.h, src/sudo.c, src/sudo.h, + src/sudo_plugin_int.h: + Change I/O log API to pass in command info to the I/O log open + function. Add iolog_file and iolog_dir parameters to command info. + This allows the policy plugin to specify the I/O log pathname. Add + convenience functions for calling plugin functions that handle ABI + backwards compatibility. + [9b81dce76ce5] + + * compat/dlopen.c: + Remove useless cast + [7cecce969739] + +2010-12-17 Todd C. Miller + + * configure, configure.in: + Bump version to 1.8.0b3 + [1dc9f040aae0] + +2010-12-13 Todd C. Miller + + * configure.in: + Remove extraneous newline + [71c94551eea5] + +2010-12-10 Todd C. Miller + + * doc/sudoers.pod, plugins/sudoers/def_data.c, + plugins/sudoers/def_data.h, plugins/sudoers/def_data.in, + plugins/sudoers/defaults.c, plugins/sudoers/iolog.c: + Make I/O log dir configurable. + [99b576667a38] + + * aclocal.m4, configure, configure.in, doc/sudoers.pod: + Rename io_logdir to iolog_dir + [0731662acc8d] + +2010-12-07 Todd C. Miller + + * pp: + Add missing '*' that prevented the generic ELF case from matching. + [be77ca26bfb2] + + * pp: + If file(1) can't identify the ELF binary type, try readelf(1). + [38a18d32a9e3] + +2010-11-30 Todd C. Miller + + * plugins/sudoers/auth/kerb4.c, plugins/sudoers/check.c, + plugins/sudoers/env.c, plugins/sudoers/pwutil.c, + plugins/sudoers/sudoers.c, src/sudo.c: + Use %u to print uid/gid, not %lu and adjust casts to match. + [03c43b8749cf] + + * doc/sudoers.ldap.pod: + Clarify ordering of entries and attributes. + [924e2a6bb603] + + * doc/sudoers.ldap.pod: + Fix typo and editing goof. + [79dc7ccd85a8] + + * doc/schema.ActiveDirectory, doc/schema.OpenLDAP, doc/schema.iPlanet, + doc/sudoers.ldap.pod: + Merge in ordered LDAP entry support from Andreas Mueller. + [ea5885989bad] + + * plugins/sudoers/ldap.c: + Make sure we don't dereference a NULL handle. + [1a9f9ee15371] + +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 + [dc09be959547] + +2010-11-23 Todd C. Miller + + * src/sudo.c: + exec_setup() does not need to setuid(0), the Ubuntu issue was in the + sudoers module. + [d6dd99fc6062] + + * plugins/sudoers/sudoers.c: + create_admin_success_flag() should use restore_perms() rather than + set_perms() to restore the uid. + [eba7a91c1f57] + + * src/sudo.c: + In exec_setup() call setuid(0) to make certain the subsequent uid + and gid changes will succeed. Fixes a problem on Ubuntu. + [c5d32abf0645] + + * src/sudo_edit.c: + Error out if we cannot change to root's uid so we catch the failure + early. + [7a2e7f8f2c80] + +2010-11-22 Todd C. Miller + + * doc/sudoers.pod: + fix typo; from Michael T Hunter + [a574a9d0db5b] + + * plugins/sudoers/match.c: + In sudoedit mode, assume command line arguments are paths and pass + FNM_PATHNAME to fnmatch(). + [ce0abff8ce9f] + +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. + [e337217f097a] + + * aclocal.m4: + Fix SUDO_MAILDIR usage of AC_LANG_PROGRAM + [fbbcee28961f] + + * sudo.pp: + For Tru64, strip off beta version. + [eeccd762df5e] + + * MANIFEST, plugins/sudoers/testsudoers.c, + plugins/sudoers/tsgetgrpw.c, plugins/sudoers/tsgetgrpw.h: + Avoid conflicts with system definitions in grp.h and pwd.h + [b219ffe1da09] + + * zlib/gzguts.h: + Include stdio.h after zlib.h, not before. We need the large file + defines to come first. + [21d6df39790f] + +2010-11-19 Todd C. Miller + + * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in: + regen + [3ff8750d0aac] + + * Makefile.in: + Don't clean ChangeLog + [ab0d30d289d4] + + * plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c: + Add prototype for cleanup() + [75626fd3769a] + +2010-11-18 Todd C. Miller + + * plugins/sudoers/group_plugin.c: + Avoid deferencing group_plugin if it is NULL in + group_plugin_query(). This should not happen. + [4f2933c8da7e] + + * plugins/sudoers/group_plugin.c: + group plugin init function return TRUE when successful + [198024477030] + +2010-11-17 Todd C. Miller + + * plugins/sudoers/ldap.c: + Enlarge the array of entry wrappers int blocks of 100 entries to + save on allocation time. From Andreas Mueller + [375c916bb03b] + + * plugins/sudoers/ldap.c: + Add back call to sudo_ldap_timefilter() in sudo_ldap_build_pass2() + that was mistakenly dropped. + [1555f5bc132d] + +2010-11-16 Todd C. Miller + + * doc/TROUBLESHOOTING: + Mention that sudo needs "ar" to build. + [65582ace2d09] + + * configure, configure.in: + Fail with a more useful error if "ar" is not found. + [d1cb83719c17] + +2010-11-14 Todd C. Miller + + * plugins/sudoers/ldap.c: + Merge in ordered LDAP entry support from Andreas Mueller and add + local changes from the 1.7 branch. + [bca29e461618] + +2010-11-12 Todd C. Miller + + * doc/schema.ActiveDirectory, doc/schema.OpenLDAP, doc/schema.iPlanet, + doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Add timed entry support from Andreas Mueller. + [e18d1df46a8d] + + * plugins/sudoers/group_plugin.c: + Don't try to unload if group_plugin is NULL. Don't call dlclose() if + group_handle is NULL + [de2273da37d5] + + * plugins/sudoers/sudoers.h: + It is now plugin_cleanup(), not cleanup() + [da62a4e1a78c] + + * plugins/sudoers/logging.c, plugins/sudoers/sudoers.c: + Call plugin_cleanup(), not cleanup() + [e800ad8b33ad] + +2010-11-11 Todd C. Miller + + * plugins/sudoers/ldap.c: + Use efree() not free() and remove malloc.h include since we never + directly call malloc() or free(). + [107fffd134bb] + +2010-11-09 Todd C. Miller + + * sudo.pp: + set PSTAMP for Solaris and move the backend-specific bits to their + own %if [xxx] %endif blocks in %set. + [a94ebe8920c1] + + * pp: + sync with git repo + [75ff509696b4] + + * configure, configure.in: + Only substitute file zlib files when using the builtin zlib + [6c8145b2deb4] + + * common/Makefile.in, compat/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in, zlib/Makefile.in: + Give up on using VPATH to find sources as it is implemented + inconsistenly in different versions of make. + [60517c69aaee] + + * plugins/sudoers/Makefile.in, plugins/sudoers/getdate.c, + plugins/sudoers/gram.c, plugins/sudoers/toke.c: + Include config.h before any other includes to make sure we get the + right value for _FILE_OFFSET_BITS. + [8fb007ca832e] + + * MANIFEST: + Add zlib + [04a3e23dfaa9] + + * zlib/Makefile.in: + Add missing targets + [40e45a177168] + + * src/Makefile.in: + g/c unused $(GENERATED) + [c8758068c1bc] + +2010-11-08 Todd C. Miller + + * plugins/sudoers/group_plugin.c: + Zero out group_plugin on unload just to be safe. + [0b10f4d101ca] + + * plugins/sudoers/group_plugin.c: + Unload group plugin if its init function fails. + [6552cdac4b7c] + + * src/sudo.c: + Only chdir to cwd if it is different from the current cwd or there + is a new root (chroot). + [b8203e875e84] + + * configure, configure.in, doc/sudo.cat, doc/sudo.man.in, + doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudoers.ldap.cat, + doc/sudoers.ldap.man.in, doc/visudo.cat, doc/visudo.man.in: + Bump version to 1.8.0b2 + [6dadeb75a878] + +2010-10-28 Todd C. Miller + + * INSTALL: + Better --enable-zlib description + [e0da54fa59a6] + + * mkpkg: + Use system zlib on Linux Let configure decide on Solaris For all + others, use builtin zlib + [3d52eddb523c] + + * zlib/zconf.h.in: + Add large file support. + [bec01215270d] + + * config.h.in: + Add large file support. + [244e95b034ec] + + * Makefile.in, configure, configure.in, doc/LICENSE, doc/license.pod, + zlib/Makefile.in, zlib/adler32.c, zlib/compress.c, zlib/crc32.c, + zlib/crc32.h, zlib/deflate.c, zlib/deflate.h, zlib/gzclose.c, + zlib/gzguts.h, zlib/gzlib.c, zlib/gzread.c, zlib/gzwrite.c, + zlib/infback.c, zlib/inffast.c, zlib/inffast.h, zlib/inffixed.h, + zlib/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. + [7542ca465c5a] + +2010-10-15 Todd C. Miller + + * src/exec.c: + If perform_io() fails, kill the child before exiting so it doesn't + complain about connection reset. We can get an I/O error if, for + example, and we get EIO reading from stdin. + [e59a05fa729f] + +2010-10-12 Todd C. Miller + + * plugins/sudoers/sudoers.c, src/sudo.c: + Fix complilation on systems with set_auth_parameters() Sprinkle + volatile to quiet warnings from gcc 2.8.0 + [a34c2b924ba7] + + * compat/dlfcn.h, compat/dlopen.c: + Avoid potential namespace issues with dlopen() emulation. + [aedfababd6ca] + + * MANIFEST: + sync + [6afb97e6d308] + + * plugins/sudoers/interfaces.c: + Use INADDR_NONE instead of casting -1 to in_addr_t (which may not + exist). + [ddfca5af1a36] + + * Makefile.in: + Mark ChangeLog as PHONY Don't overwrite ChangeLog if we can't run hg + [e9d04bfa4505] + + * configure, configure.in: + HP-UX 10.20 libc has an incompatible getline + [2e7bc202e78d] + + * plugins/sudoers/visudo.c: + Quiet an HP-UX compiler warning. + [55b9d587ac8c] + + * configure, configure.in: + Check for vi even with --with-editor specified; the sample plugin + needs it. + [94dfc3643f76] + +2010-10-11 Todd C. Miller + + * compat/dlopen.c: + Fix remaining syntax errors. + [9d729b5b577e] + + * src/Makefile.in: + sudo binary depends on the libtool-generated libs + [9e6148406adb] + + * plugins/sudoers/group_plugin.c, src/load_plugins.c: + Use HAVE_DLOPEN instead of HAVE_DLFCN_H when determining whether to + include the local or system dlfcn.h + [68cfe4c1089b] + + * pp: + Don't use run_as_superuser=false on HP-UX + [532242370b09] + + * src/net_ifs.c: + Use memset() instead of zero_bytes() since we don't include + sudoers.h + [a187c18c2472] + + * plugins/sudoers/interfaces.c: + Fix pasto; AF_INET not AF_INET6 + [2d2e9d7dc6f9] + + * compat/dlopen.c: + Actually call shl_load() + [ed8153b8a3cd] + + * pp: + Update from git repo. Debian: version numbers now compliant with + policy section 5.6.12 HP-UX: minimal changes needed to work on HP-UX + 10.20 + [ecf2692bceeb] + + * configure, configure.in: + Fix dlopen() detection for systems where dlopen() is in a separate + library. + [fa6b175582b6] + + * plugins/sudoers/auth/pam.c: + If pam_acct_mgmt() returns PAM_AUTH_ERR print a (hopefully) more + useful message and return AUTH_FATAL so sudo does not keep trying to + validate the user. + [1be8857e5291] + + * src/preload.c: + sudo_preload_table is an array + [b7704e72a9da] + + * compat/dlopen.c: + Quiet a compiler warning and fix sudo_preload_table external + definition. + [8234987664cc] + + * compat/dlfcn.h: + Fix multiple inclusion guard in dlfcn.h and fix dlerror() prototype. + [8bab6a4053cc] + + * plugins/sudoers/group_plugin.c: + Make this compile correctly when no dlopen is available. + [57643879bd2b] + +2010-10-07 Todd C. Miller + + * plugins/sudoers/check.c: + Having a timestamp file defined is no longer indicative of tty + tickets being enabled. Check def_tty_tickets directly. + [efcc11ad157f] + + * src/exec_pty.c, src/sudo.h, src/ttysize.c: + Fix TCGETWINSZ compat. + [da3a8b17cf7a] + +2010-10-02 Todd C. Miller + + * src/exec_pty.c, src/ttysize.c: + Prefer newer TIOCGWINSZ ioctl to old TIOCGSIZE + [926492dd10a6] + +2010-10-01 Todd C. Miller + + * plugins/sudoers/sudoers.c, src/sudo.c: + Move set_project() from sudoers module into sudo proper. + [beabafac03b4] + + * configure, configure.in: + Fix typo and regenerate + [4a3caf4234f3] + + * plugins/sudoers/ldap.c: + When iterating over returned LDAP entries, keep looking at remaining + matches even if we have a positive match. This catches negative + matches that may exist in other entries and more closely match the + sudoers file behavior. + [f47db6e609b0] + + * pp: + Add support for multiple package instances on Solaris. + [7f2a8b942545] + + * src/exec.c: + Add missing signal_pipe[0] to fdsr for the non-pty case. + [79d01e11b19c] + + * mkpkg: + Add --with-project for Solaris + [ffa4c2bb93f7] + + * README: + Need ar and ranlib too + [5c2f679172ef] + +2010-09-27 Todd C. Miller + + * plugins/sudoers/env.c: + Preserve ODMDIR environment variable by default on AIX. + [bd47cb1e804f] + +2010-09-26 Todd C. Miller + + * Makefile.in, compat/Makefile.in, compat/dlfcn.h, compat/dlopen.c, + config.h.in, configure, configure.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + plugins/sudoers/group_plugin.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.c, src/Makefile.in, src/load_plugins.c, + src/preload.c: + Add dlopen() emulation for systems without it. For HP-UX 10, emulate + using shl_load(). For others, link sudoers plugin statically and use + a lookup table to emulate dlsym(). + [e92edfb3c642] + +2010-09-24 Todd C. Miller + + * compat/fnmatch.c, compat/glob.c, compat/mksiglist.c, + compat/nanosleep.c, compat/utimes.c: + When including compat headers, use the compat dir as part of the + path so we are sure to get the correct header. + [6c2a45da6af5] + +2010-09-21 Todd C. Miller + + * plugins/sudoers/linux_audit.c: + Ignore ECONNREFUSED from audit_log_user_command() which will occur + if auditd is not running. + [d314fe4c8d03] + +2010-09-17 Todd C. Miller + + * pp: + Sync with git version + [1c0357744222] + +2010-09-16 Todd C. Miller + + * common/fileops.c, plugins/sudoers/defaults.c: + Cast isblank argument to unsigned char. + [c822dbb3ca54] + +2010-09-14 Todd C. Miller + + * INSTALL, config.h.in, configure, configure.in, doc/sudoers.cat, + doc/sudoers.man.in, doc/sudoers.pod, plugins/sudoers/defaults.c: + Implement --with-umask-override configure flag. + [863e3047df22] + + * plugins/sudoers/env.c: + Take MODE_LOGIN_SHELL into account when initially setting reset_home + instead of special-casing it later. + [5d6b16480fd6] + + * plugins/sudoers/sudoers.c: + In login mode, make a copy of the runas user's pw_shell for + NewArgv[0] because 1) we modify it and 2) it will runas_pw gets + freed before exec. + [1d1ccb568dfa] + + * plugins/sudoers/env.c: + Reset HOME for "sudo -i" even if HOME was listed in env_keep. + [c1c1c65a2d63] + + * src/sudo.c: + Use SIG_SETMASK when resetting signal mask instead of SIG_UNBLOCK. + [7443454e5f88] + + * src/sudo.c: + Reset signal mask at sudo startup time; we need to be able to rely + on normal signal delivery to control the child process. + [95800163ff94] + +2010-09-13 Todd C. Miller + + * install-sh: + 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. + [736065e14301] + + * common/lbuf.c: + Do not need sys/time.h after all + [91f6f668ccda] + + * common/lbuf.c: + Include sys/time.h for utimes() and struct timeval. No longer need + ioctl.h or termios.h + [2d75273d3213] + + * compat/snprintf.c: + Quiet bogus compiler warnings. + [fe252e1968f5] + + * include/missing.h: + Declare innetgr() for HP-UX which is missing a declaration. Declare + domainname() for HP-UX and Solaris which are missing a declaration. + [b37c50751138] + + * plugins/sudoers/bsm_audit.c: + Use __sun for consistency with the rest of the sources. + [6b086b61ccb6] + + * plugins/sudoers/group_plugin.c: + Quiet a bogus compiler warning. + [ebc069842c4a] + + * plugins/sudoers/pwutil.c: + Don't try to delref a NULL group. + [f6ff0838be21] + + * common/alloc.c, common/lbuf.c: + Include memory.h on systems that need it. + [4e676da81c6f] + +2010-09-11 Todd C. Miller + + * src/exec.c: + Quiet gcc warnings on glibc systems that use warn_unused_result for + write(2). + [0532da0b7cf7] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + sudo_plugin is in section 8; from Ted Percival + [b4506a0de87e] + + * plugins/sudoers/Makefile.in: + testsudoers depends on libsudoers.la, not sudoreplay + [cdb1cc3bf06a] + +2010-09-10 Todd C. Miller + + * src/exec.c: + Read as many signals on the signal pipe as we can before returning. + [b181671da047] + + * src/exec.c, src/exec_pty.c, src/sudo_exec.h: + Instead of using a array to store received signals, open a pipe and + have the signal handler write the signal number to one end and + select() on the other end. This makes it possible to handle signals + similar to I/O without race conditions. + [ee84d65c16b6] + +2010-09-09 Todd C. Miller + + * doc/visudo.pod, plugins/sudoers/visudo.c: + Make "visudo -c -f -" check the standard input. + [195a3d2a9a26] + + * doc/sudoers.pod: + set_home and always_set_home have an effect if HOME is present in + the env_keep list. + [159d0b9dc5c8] + + * plugins/sudoers/env.c: + Make -H flag work when HOME is listed in env_keep. Also makes + "set_home" and "always_set_home" override override HOME in env_keep. + [a3e5b966193f] + +2010-09-08 Todd C. Miller + + * plugins/sudoers/Makefile.in, plugins/sudoers/interfaces.c, + plugins/sudoers/interfaces.h, plugins/sudoers/match.c, + plugins/sudoers/sudoers.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/visudo.c, src/net_ifs.c: + Convert sudoers plugin to use interface list passed in settings. + [87d9b5f4f586] + + * doc/sudo_plugin.pod, src/Makefile.in, src/net_ifs.c, + src/parse_args.c, src/sudo.h: + Query local network interfaces in the main sudo driver and pass to + the plugin as "network_addrs" in the settings list. + [7f35bcfe77a7] + + * plugins/sudoers/bsm_audit.c: + Solaris BSM audit return EINVAL when auditing is not enabled, + whereas OpenBSM returns ENOSYS. + [411b980ec58b] + +2010-09-07 Todd C. Miller + + * compat/fnmatch.c: + missing.h should come before most local includes + [53921a7b8b5b] + + * plugins/sudoers/sudoreplay.c: + missing.h should come before most local includes + [e9abb0db1aac] + + * plugins/sudoers/sudoers.h: + Make local includes consistent; use double quotes for local includes + except for generated ones where we use angle brackets. + [09de4faa9547] + + * plugins/sudoers/sudoers.c: + Always fill in NewArgv for audit code. + [7c3aca60519f] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add missing LOG_INPUT/LOG_OUTPUT support in the lexer. + [007cf6560f92] + + * common/alloc.c, common/atobool.c, common/fileops.c, + common/fmt_string.c, common/lbuf.c, common/list.c, common/term.c, + common/zero_bytes.c, compat/closefrom.c, compat/fnmatch.c, + compat/getcwd.c, compat/getgrouplist.c, compat/getline.c, + compat/getprogname.c, compat/glob.c, compat/isblank.c, + compat/memrchr.c, compat/mksiglist.c, compat/mkstemps.c, + compat/nanosleep.c, compat/setenv.c, compat/snprintf.c, + compat/strlcat.c, compat/strlcpy.c, compat/strsignal.c, + compat/unsetenv.c, compat/utimes.c, include/compat.h, + plugins/sample/sample_plugin.c, plugins/sample_group/getgrent.c, + plugins/sample_group/plugin_test.c, + plugins/sample_group/sample_group.c, plugins/sudoers/audit.c, + plugins/sudoers/auth/afs.c, plugins/sudoers/boottime.c, + plugins/sudoers/getdate.c, plugins/sudoers/getdate.y, + plugins/sudoers/linux_audit.c, plugins/sudoers/match.c, + plugins/sudoers/plugin_error.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/timestr.c, src/error.c, src/sesh.c, src/sudo.h, + src/sudo_noexec.c, src/ttysize.c: + Make local includes consistent; use double quotes for local includes + except for generated ones where we use angle brackets. Also g/c + unused compat.h. + [e57070dc8f04] + +2010-09-06 Todd C. Miller + + * plugins/sudoers/match.c: + When matching the runas user and runas group (-u and -g command line + options), keep track of runas group and runas user matches + separately. Only return a positive match if we have a match for + both runas user and runas group (if specified). + [815219e04cc8] + +2010-09-04 Todd C. Miller + + * doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Add support for multiple URI lines by joining the contents and + passing the result to ldap_initialize. + [a47cae3b72e8] + + * plugins/sudoers/ldap.c, plugins/sudoers/parse.c: + Do not return -1 on error from the display functions; the caller + expects a return value >= 0. + [101456a7dd00] + + * plugins/sudoers/sudoers.c: + Do not set both MODE_EDIT and MODE_RUN + [8faa36694d54] + +2010-09-03 Todd C. Miller + + * include/missing.h: + Move includes to the top of the file. + [a51436798e8c] + +2010-08-30 Todd C. Miller + + * plugins/sudoers/Makefile.in: + Add missing definition of timedir + [458a749c2c5e] + + * compat/fnmatch.c, compat/getprogname.c, compat/isblank.c, + compat/mksiglist.c, compat/strsignal.c, + plugins/sudoers/plugin_error.c, src/error.c, src/sudo_noexec.c: + Add #include of sys/types.h for .c files that include missing.h to + be sure that size_t and ssize_t are defined. + [08e3132dbf4f] + + * plugins/sudoers/Makefile.in: + Install sudoers file from the build dir not hte src dir. + [ca89e962dbf4] + +2010-08-26 Todd C. Miller + + * plugins/sudoers/set_perms.c: + If runas_pw changes, reset the stashed runas aux group vector. + Otherwise, if runas_default is set in a per-command Defaults + statement, the command runs with root's aux group vector (i.e. the + one that was used when locating the command). + [24f9107cedd2] + + * plugins/sudoers/Makefile.in: + Add target to generate sudoers file Remove generated sudoers file as + part of distclean + [fb7422e90f03] + +2010-08-24 Todd C. Miller + + * src/exec.c: + When not logging I/O install a handler for SIGCONT and deliver it to + the command upon resume. Fixes bugzilla #431 + [495dce52a5aa] + +2010-08-21 Todd C. Miller + + * plugins/sudoers/sudoers.h: + g/c unused auth_pw extern definition + [40eb7477ba17] + + * plugins/sudoers/check.c, plugins/sudoers/sudoers.c: + Move get_auth() into check.c where it is actually used. + [e31db0ce3a61] + +2010-08-20 Todd C. Miller + + * common/lbuf.c: + Convert a remaining puts() and putchar() to use the output function. + [d69e363a506b] + + * plugins/sudoers/plugin_error.c: + Plug memory leak + [68895469ea8d] + +2010-08-18 Todd C. Miller + + * plugins/sudoers/env.c: + Set dupcheck to TRUE when setting new HOME value if !env_reset but + always_set_home is true. Prevents a duplicate HOME in the + environment (old value plus the new one) introduced in f421f8827340. + [9ca19183794f] + + * configure, configure.in, plugins/sudoers/sudoers, + plugins/sudoers/sudoers.in: + Substitute sysconfdir in the installed sudoers file to get the + correct path for sudoers.d. + [86072b6cd55d] + +2010-08-17 Todd C. Miller + + * src/get_pty.c: + Fix typo that prevented compilation on Irix; Friedrich Haubensak + [b48be51b65fc] + +2010-08-16 Todd C. Miller + + * MANIFEST, common/Makefile.in, common/aix.c, common/alloc.c, + common/atobool.c, common/fileops.c, common/fmt_string.c, + common/lbuf.c, common/list.c, common/term.c, common/zero_bytes.c, + compat/Makefile.in, compat/closefrom.c, compat/fnmatch.c, + compat/getcwd.c, compat/getgrouplist.c, compat/getline.c, + compat/getprogname.c, compat/glob.c, compat/isblank.c, + compat/memrchr.c, compat/mksiglist.c, compat/mkstemps.c, + compat/nanosleep.c, compat/setenv.c, compat/snprintf.c, + compat/strlcat.c, compat/strlcpy.c, compat/strsignal.c, + compat/unsetenv.c, compat/utimes.c, include/compat.h, + include/missing.h, plugins/sample/sample_plugin.c, + plugins/sample_group/getgrent.c, + plugins/sample_group/sample_group.c, plugins/sudoers/Makefile.in, + plugins/sudoers/audit.c, plugins/sudoers/boottime.c, + plugins/sudoers/getdate.c, plugins/sudoers/getdate.y, + plugins/sudoers/linux_audit.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.h, plugins/sudoers/sudoreplay.c, + plugins/sudoers/timestr.c, src/Makefile.in, src/error.c, src/sesh.c, + src/sudo.h, src/sudo_noexec.c, src/ttysize.c: + Merge compat.h and missing.h into missing.h + [572909ae9716] + +2010-08-14 Todd C. Miller + + * plugins/sudoers/auth/pam.c: + If the user hits ^C while a password is being read, error out before + reading any further passwords in the pam conversation function. + Otherwise, if multiple PAM auth methods are required, the user will + have to hit ^C for each one. + [23782631748c] + +2010-08-12 Todd C. Miller + + * plugins/sudoers/check.c: + Update comment + [a5296cb3a20a] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document sudo_conv_t function and sudo_printf_t return values. + [745c0017814c] + + * src/conversation.c: + Make _sudo_printf return the number of characters printed on success + like printf(3). + [8eeefe8d7e77] + +2010-08-10 Todd C. Miller + + * plugins/sudoers/sudoers.c: + sudoers.h includes sudo_plugin.h for us + [cabe68e07807] + + * common/Makefile.in, common/gettime.c, compat/mkstemps.c, + plugins/sudoers/sudoers.h, plugins/sudoers/visudo.c, src/sudo.h, + src/sudo_edit.c: + Use gettimeofday() directly instead of via the gettime() wrapper. + [7490426c99ae] + + * common/gettime.c, compat/snprintf.c, compat/strcasecmp.c, + compat/strerror.c, config.h.in, configure, configure.in, + include/compat.h, include/missing.h, plugins/sudoers/logging.c, + plugins/sudoers/sudoers.c, plugins/sudoers/visudo.c, src/sudo.c: + Remove some obsolete configure tests, ancient Unix systems are no + longer supported. + [2be6218c3a36] + +2010-08-07 Todd C. Miller + + * sudo.pp: + Set pp_kit_version and strip off patch level + [aacfda1b676d] + + * sudo.pp: + Better handling of versions with a patchlevel. For rpm and deb, use + the patchlevel+1 as the release. For AIX, use the patchlevel as the + 4th version number. For the rest, just leave the patchlevel in the + version string. + [638bd35f2346] + +2010-08-06 Todd C. Miller + + * plugins/sudoers/auth/sudo_auth.c: + For non-standalone auth methods, stop reading the password if the + user enters ^C at the prompt. + [82c2911bb264] + + * configure, configure.in, plugins/sudoers/Makefile.in, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/secureware.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h, + plugins/sudoers/pwutil.c: + No need to look up shadow password unless we are doing password- + style authentication. This moves the shadow password lookup to the + auth functions that need it. + [ba9e3eba2b72] + + * plugins/sudoers/sudoers.c: + Retain final passwd/group refs until the policy close() function. + Note that this doesn't get called in all cases so putting this in a + cleanup function is probably better. + [bbe214cb4119] + + * plugins/sudoers/check.c: + Fix mismerge + [395115f89dd6] + + * plugins/sudoers/check.c: + When removing/resetting the timestamp file ignore the tty ticket + contents. + [b709f5667a0b] + + * plugins/sudoers/sudoers.c: + delref sudo_user.pw, runas_pw and runas_gr immediately before we + return. + [4d67d15dfd3b] + +2010-08-04 Todd C. Miller + + * plugins/sudoers/check.c, plugins/sudoers/ldap.c, + plugins/sudoers/match.c, plugins/sudoers/pwutil.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Reference count cached passwd and group structs. The cache holds + one reference itself and another is added by sudo_getgr{gid,nam} and + sudo_getpw{uid,nam}. The final ref on the runas and user passwd and + group structs are persistent for now. + [e544685523c3] + + * doc/UPGRADE: + fix typo + [e32f2d35e6c9] + +2010-08-03 Todd C. Miller + + * plugins/sudoers/check.c: + Do not produce a warning for "sudo -k" if the ticket file does not + exist. + [1598f6061b75] + + * plugins/sudoers/pwutil.c: + Instead of caching struct passwd and struct group in the red-black + tree, store a struct cache_item which includes both the key and + datum. This allows us to user the actual name that was looked up as + 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). + [225d4a22f60e] + + * plugins/sudoers/Makefile.in: + Fix path to mkinstalldirs + [b4968379b12d] + + * plugins/sudoers/check.c, plugins/sudoers/logging.c, + plugins/sudoers/sudoreplay.c, plugins/sudoers/visudo.c, + src/exec_pty.c, src/get_pty.c, src/tgetpass.c: + Quiet gcc warnings on glibc systems that use warn_unused_result for + write(2) and others. + [c99f138960e0] + +2010-08-02 Todd C. Miller + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add %option noinput + [72b9cd49b4f1] + + * aclocal.m4, configure, configure.in: + Add cross-compile defaults for remaining AC_TRY_RUN usage. Also add + back getgroups() check since AC_FUNC_GETGROUPS defaults to "no" when + cross-compiling. + [e385c176d0ee] + +2010-07-31 Todd C. Miller + + * aclocal.m4, compat/snprintf.c, config.h.in, configure, configure.in: + Use AC_CHECK_MEMBER in SUDO_SOCK_SA_LEN Use AC_TYPE_LONG_LONG_INT + and AC_CHECK_SIZEOF([long int]) instead of rolling our own. + [cf3e60d9c440] + +2010-07-29 Todd C. Miller + + * pp: + Update to latest version + [32f93be33961] + +2010-07-28 Todd C. Miller + + * sudo.pp: + Let pp determine pp_aix_version itself. + [7cf0245d84ed] + + * INSTALL, config.h.in, configure, configure.in, mkpkg, + plugins/sudoers/sudoers.c: + Add support for Ubuntu admin flag file and enable it when building + Ubuntu packages. + [00e27cff2dfb] + + * plugins/sudoers/sudoers, sudo.pp: + Add commented out SuSE-like targetpw settings + [4605d47b7413] + + * configure, configure.in: + Only try to use +DAportable for non-GCC on hppa + [75d0f284ccf7] + + * configure, configure.in: + Prevent configure from adding the -g flag unless in devel mode + [b1fd3f8d45c0] + +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. + [d737069d1e1c] + + * sudo.pp: + Use sudo_$flavor instead of sudo-$flavor since that causes the least + amount of trouble for the various package managers. + [71f547af35fc] + + * mkpkg: + Fix handling of the ldap flavor Remove destdir unless --debug was + specified Make distclean before running configure if there is a + Makefile present + [6316f08de7d3] + + * sudo.pp: + Add back include file. + [195627bf68b8] + + * mkpkg: + Pass extra args on to configure on HP-UX, if we don't have the HP C + compiler, disable zlib to prevent gcc from finding it in + /usr/local/lib. + [473efa0e2bac] + + * mkpkg: + Use the HP ANSI C compiler on HP-UX if possible + [fb249b6b175d] + + * plugins/sudoers/sudoreplay.c: + Some getline() implementations (FreeBSD 8.0) do not ignore the + length pointer when the line pointer is NULL as they should. + [2410a1a3543c] + + * plugins/sudoers/sudoreplay.c: + Don't need to check for *cp being non-zero, isdigit() will do that. + [7df11ea8a487] + + * plugins/sudoers/sudoreplay.c: + Add setlocale() so the command line arguments that use floating + point work in different locales. Since sudo now logs the timing + data in the C locale we must Parse the seconds in the timing file + manually instead of using strtod(). Furthermore, sudo 1.7.3 logged + the number of seconds with the user's locale so if the decimal point + is not '.' try using the locale-specific version. + [4d385765f23b] + + * src/exec.c: + Do I/O logging in the C locale so the floating point numbers in the + timing file are not locale-dependent. + [5961cec044ec] + + * plugins/sudoers/sudoreplay.c: + Use errorx() not error() for thingsthat don't set errno. + [0fe5e692af84] + +2010-07-26 Todd C. Miller + + * pp: + Better support for 1.2.3 style versions in Tru64 kits + [997c549bb777] + + * sudo.pp: + Add Tru64 kit support + [e273a954f981] + + * pp: + Remove apparently unnecessary use of sudo + [be8840d85125] + + * Makefile.in, plugins/sudoers/Makefile.in: + Create timedir as part of install-dirs target. + [c736bc2fb14f] + + * src/exec_pty.c: + Handle ENXIO from read/write which can occur when reading/writing a + pty that has gone away. + [fa2e8059879f] + + * plugins/sudoers/pwutil.c: + sudo_pwdup() was not expanding an empty pw_shell to _PATH_BSHELL + [3a045475d5ee] + + * mkpkg: + platform is a pp flag not a variable + [12eba39a47c1] + + * Makefile.in, mkpkg, sudo.pp: + Add simple arg parsing for mkpkg so we can set debug, flavor or + platform. + [ada839fe252d] + + * pp: + Make rpm backend work on AIX 5.x + [549a76d11393] + +2010-07-25 Todd C. Miller + + * plugins/sudoers/sudoers: + Add commented out Defaults entry for log_output + [7e67d7588900] + +2010-07-23 Todd C. Miller + + * doc/Makefile.in: + Remove sudo docdir completely + [dce8e82878ef] + + * doc/sample.sudo.conf: + Add sample sudo.conf + [aafdba3fc411] + +2010-07-22 Todd C. Miller + + * plugins/sudoers/Makefile.in: + Add PACKAGE_TARNAME for docdir + [930c92b8f8f0] + +2010-07-23 Todd C. Miller + + * src/Makefile.in: + Pass install-sh -b~ here too. + [c3f5eb446c38] + + * plugins/sample/Makefile.in, plugins/sample_group/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Install binary files with -b~ to make a backup. Fixes "text file + busy" error on HP-UX during install. + [81f306f54f8c] + + * install-sh: + "mv -f" on HP-UX doesn't unlink the destination first so add an + explicit rm before moving the temporary into place. + [fb719a79582d] + + * configure, configure.in: + Some more ${foo} -> $(foo) conversion for consistent Makefiles. + [0aa098770074] + + * doc/Makefile.in, plugins/sudoers/Makefile.in: + Install sudoers2ldif in the doc dir + [33ac3b53d7f5] + +2010-07-22 Todd C. Miller + + * pathnames.h.in: + Add missing include of maillock.h for Solaris + [5a58883be23a] + + * NEWS, configure, configure.in, doc/TROUBLESHOOTING, doc/UPGRADE, + doc/sample.syslog.conf, doc/sudoers.cat: + Change the default syslog facility from local2 to authpriv (or auth + if the operating system doesn't support authpriv). + [3b70ba514f49] + + * Makefile.in, sudo.pp: + Install sudoers as /etc/sudoers on RPM and debian systems where the + package manager will not replace a user-modified configuration file. + This fixes upgrades from the vendor sudo packages. + [d886b6d60b5b] + + * pp: + RPM: use %config(noreplace) instead of %config for volatile This + results in the new file being installed with a .rpmnew suffix + instead of the file being replaced and the old one renamed with a + .rpmsave suffix. + [58be2119f8e8] + +2010-07-21 Todd C. Miller + + * compat/mkstemps.c, plugins/sudoers/boottime.c: + Include time.h for struct timeval + [ddf8b04f0276] + + * src/exec_pty.c: + The return value of strsignal() may be const and should be treated + as const regardless. + [620074ae1e77] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Mention that 127.0.0.1 will not match, nor will localhost unless + that is the actual host name. + [8b574122eb8f] + + * MANIFEST, NEWS, README, WHATSNEW, doc/Makefile.in, doc/UPGRADE: + Rename WHATSNEW -> NEWS + [d1a2c8c47d89] + + * pp: + Updated pp with latest patches + [98e16b9b8f62] + + * WHATSNEW: + Sync with 1.7.4 + [65ac4dafeef7] + + * doc/UPGRADE, doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod, + plugins/sudoers/sudoers: + Add commented out line to add HOME to env_keep and add a warning to + the note about the HOME change in UPGRADE. + [0d6a775bb6c8] + +2010-07-20 Todd C. Miller + + * plugins/sudoers/sudoreplay.c: + Add LINE_MAX define for those without it. + [446d9dbe7859] + + * INSTALL, WHATSNEW, config.h.in, configure, configure.in, + doc/UPGRADE, doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod, + plugins/sudoers/defaults.c: + The tty_tickets option is now on by default. + [a01c48206d80] + + * WHATSNEW: + Mention that AIX authdb support has been fixed. + [87bd7f4eba6a] + + * common/aix.c: + setauthdb() only sets the "old" registry if it was set by a previous + call to setauthdb(). To restore the original value, passing NULL + (or an empty string) to setauthdb() is sufficient. + [470da190a254] + +2010-07-19 Todd C. Miller + + * WHATSNEW, doc/UPGRADE, doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, + doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod, + plugins/sudoers/env.c: + Reset HOME when env_reset is enabled unless it is in env_keep + [f421f8827340] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + The default for set_logname has been "true" for some time now. + [f489da5674c3] + + * plugins/sudoers/boottime.c: + Add missing include of time.h + [624d7014932f] + + * plugins/sudoers/logging.c: + Fix check for dup2() return value. + [140ea2d50d20] + + * plugins/sudoers/env.c: + Add PYTHONUSERBASE to initial_badenv_table + [3149aae5b12c] + + * plugins/sudoers/visudo.c: + Treat an unknown defaults entry as a parse error. + [b3ebad73efb2] + + * plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c: + Check return value of setdefs() but don't stop setting defaults if + we hit an unknown one. + [945e752239ab] + + * WHATSNEW, aclocal.m4, config.h.in, configure, configure.in, + doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudoers.cat, + doc/sudoers.man.in, doc/sudoers.pod, pathnames.h.in, + plugins/sudoers/env.c: + If env_reset is enabled, set the MAIL environment variable based on + the target user unless MAIL is explicitly preserved in sudoers. + [a1b03e2e0e96] + +2010-07-17 Todd C. Miller + + * pp: + decode debian code names + [8741280d9960] + + * WHATSNEW: + fix typo + [a8a19451110b] + +2010-07-16 Todd C. Miller + + * WHATSNEW: + Merge with 1.7.4 + [9348fa7e15b8] + + * src/sudo.c: + Restore RLIMIT_NPROC after the uid switch if it appears that + runas_setup() did not do it for us. Fixes a bash script problem on + SuSE with RLIMIT_NPROC set to RLIM_INFINITY. + [786fb272e5fd] + +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. + [dcafdd53b88f] + +2010-07-16 Todd C. Miller + + * INSTALL: + document --with-pam-login + [ea93e4c6873c] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + The tag is NOSETENV, not UNSETENV. From Petr Uzel. + [2ac90d8de36e] + +2010-07-15 Todd C. Miller + + * sudo.pp: + Include flavor in solaris package name + [e605f6364c9f] + + * mkpkg: + Older shells don't support IFS= so set explictly to space, tab, + newline. + [7773960bc8a0] + + * mkpkg: + Use '=' not '==' in test + [c99d42bc48e6] + + * mkpkg: + Fix typo that prevented debian from matching + [84421078fcb7] + + * mkpkg: + Add missing prefix setting for debian + [6466f23de4aa] + + * sudo.pp: + Use tab indents to reduce the chance of problem with <<- Fix the + debian %set section, pp does not set pp_deb_distro Uncomment %sudo + line in sudoers for debian Uncomment some env_keep lines for RHEL, + SLES and debian to more closely match the vendor sudoers files. + Add /etc/pam.d to %files Remove the /etc/sudo-ldap.conf symlink on + debian for ldap flavor + [c5b49feb1a0c] + + * plugins/sudoers/sudoers: + Add commented out env_keep entries, sample Aliases and a %sudo line + for debian. + [387719e52d0f] + + * configure, configure.in: + Move zlib check later on in the script to avoid a strange shell + problem on SLES11. + [1a3153bb1291] + + * configure.in: + Remove check for egrep; configure has its own + [a3b9d98cb5d2] + +2010-07-14 Todd C. Miller + + * mkpkg: + Enable zlib for linux distros + [8fa51a1405a4] + + * mkpkg: + Add ldap flavor to default build + [97644f5a555f] + + * mkpkg, sudo.pp: + Simplify rpm linux distro settings + [b9dcf10cdf20] + + * aclocal.m4, configure, configure.in, doc/UPGRADE, doc/sudoers.cat: + Move time stamp files from /var/run/sudo to /var/{db,lib,adm}/sudo. + [2c549c1acde9] + + * Makefile.in: + Fix ChangeLog creation from build dir + [3d0c7904f173] + + * plugins/sudoers/sudoers.c: + Handle getcwd() failure. + [aef7bef87394] + + * doc/Makefile.in, mkpkg, sudo.pp: + Add ldap "flavor" for debian, controlled by the SUDO_FLAVOR + environment variable. + [be6ed611b7a8] + + * sudo.pp: + Create sudo group on debian + [6ed6c032042e] + + * mkpkg, sudo.pp: + Add debian 4/5/6 and use the dot when doing version matches + [6bcb664d1f4f] + + * aclocal.m4, configure: + Use a loop when searching for mv, sendmail and sh + [d5e9369f8d13] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Remove spurious "and"; from debian + [a21e6f7c5b99] + + * aclocal.m4, configure, configure.in, doc/sudoers.cat, + doc/sudoers.man.in, doc/sudoers.pod, doc/visudo.cat, + doc/visudo.man.in, doc/visudo.pod: + Substitute the value of EDITOR into the sudoers and visudo manuals. + [cd79e587dd7f] + +2010-07-13 Todd C. Miller + + * mkpkg, pp, sudo.pp: + Initial support for debian 4.0 + [ac6707915fa8] + + * mkpkg: + Some platforms need -fPIE instead of -fpie + [fd6be19e5bc2] + + * plugins/sudoers/auth/pam.c: + Only set PAM_RHOST for Solaris, where it is needed to avoid a bug. + On Linux it causes a DNS lookup via libaudit. + [1e10105ade5b] + + * MANIFEST: + Update MANIFEST to match packaging changes + [ef86ee557b5b] + + * sudo.psf: + We now use pp to generate HP-UX packages + [f7aa8da7844e] + + * INSTALL.binary, plugins/sudoers/Makefile.binary.in: + Remove vestiges of old binary package bits. + [afffd005452f] + + * INSTALL, Makefile.in, common/Makefile.in, compat/Makefile.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in: + install-man -> install-doc + [99b5fa05567c] + + * Makefile.in, doc/Makefile.in, include/Makefile.in, mkpkg, + plugins/sudoers/Makefile.in, pp, src/Makefile.in, sudo.pp: + Use http://rc.quest.com/topics/polypkg/ for packaging + [5ca8eb75b223] + + * install-sh: + Just ignore the -c option, it is the default Add support for -d + option + [a8b6b0a131e8] + +2010-07-12 Todd C. Miller + + * pathnames.h.in, plugins/sudoers/env.c, plugins/sudoers/logging.c: + Use _PATH_STDPATH instead of _PATH_DEFPATH + [137fa911908e] + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Do not strip binaries. + [20166e287176] + + * INSTALL, configure, configure.in: + Add --insults=disabled configure option to allow people to build in + insult support but have the insults disabled unless explicitly + enabled in sudoers. + [523b8c552e90] + + * compat/mkstemps.c: + Add prototype for gettime() + [275eee40473b] + + * config.h.in, configure, configure.in, plugins/sudoers/auth/pam.c, + plugins/sudoers/env.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Add support for a sudo-i pam.d file to be used for "sudo -i". + Adapted from a RedHat patch. + [06d34f16520b] + +2010-07-09 Todd C. Miller + + * include/missing.h: + Fix mkstemps() prototype + [2421841e815b] + + * MANIFEST, compat/Makefile.in, compat/mkstemp.c, compat/mkstemps.c, + config.h.in, configure, configure.in, include/missing.h, + src/sudo_edit.c: + Use mkstemps() instead of mkstemp() in sudoedit. This allows + sudoedit to preserve the file extension (if any) which may be used + by the editor (like emacs) to choose the editing mode. + [d33172d2c086] + +2010-07-08 Todd C. Miller + + * doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod, + plugins/sudoers/ldap.c: + TLS_CACERT is now an alias for TLS_CACERTFILE. OpenLDAP uses + TLS_CACERT, not TLS_CACERTFILE in its ldap.conf. Other LDAP client + code, such as nss_ldap, uses TLS_CACERTFILE. Also document why you + should avoid disabling TLS_CHECKPEER is possible. + [196622436212] + +2010-07-07 Todd C. Miller + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Make sudo_plugin format a bit more like a man page + [048d596e32da] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Add suport for negated user/host/command lists in a Defaults entry. + E.g. Defaults:!baduser noexec + [d41112cf0342] + + * Makefile.in, common/Makefile.in, compat/Makefile.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sample_group/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in: + Add uninstall target + [fea66ebf136a] + + * common/Makefile.in, compat/Makefile.in: + Remove unused AR, SED and RANLIB variables + [2ff9928bfdb3] + + * Makefile.in: + Do not install sample plugins + [5443b87bd1c3] + +2010-07-06 Todd C. Miller + + * MANIFEST, aclocal.m4, compat/setenv.c, compat/unsetenv.c, configure, + configure.in, plugins/sudoers/env.c: + Now that sudoers is a dynamically loaded module we cannot override + the libc environment functions because the symbols may already have + been resolved via libc. Remove getenv/putenv/setenv/unsetenv + replacements from sudoers and add replacements for setenv/unsetenv + for systems that lack them. + [3f2b43cb8851] + + * configure, configure.in, plugins/sudoers/Makefile.in: + Link testsudoers with -ldl when needed + [f79606f9fcd7] + + * plugins/sample_group/plugin_test.c: + Remove unused time.h and add limits.h for PATH_MAX + [3f5d0074d621] + + * doc/sudoers.ldap.pod: + Fix typo. + [bc855fd57397] + +2010-07-05 Todd C. Miller + + * plugins/sample_group/plugin_test.c: + Do not depend on strlcpy/strlcat + [6e7e2b5af051] + + * plugins/sample_group/plugin_test.c: + Standalone test driver for sudoers group plugin. + [eb1235fc3b8e] + +2010-07-02 Todd C. Miller + + * plugins/sudoers/group_plugin.c, src/load_plugins.c: + Use RTLD_LAZY instead of RTLD_NOW; was using RTLD_NOW as a debugging + aid. + [2a34e616229b] + + * plugins/sample_group/sample_group.c: + Fix style nit in function declarations + [ab87c7c76bf9] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Document group_plugin syntax. + [ed1faf72ddcb] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document the sudoers group plugin. + [f19a62dc8cfc] + + * INSTALL, MANIFEST, Makefile.in, config.h.in, configure, + configure.in, doc/LICENSE, doc/license.pod, include/sudo_plugin.h, + plugins/sample_group/Makefile.in, plugins/sample_group/getgrent.c, + plugins/sample_group/sample_group.c, plugins/sudoers/Makefile.in, + plugins/sudoers/def_data.c, plugins/sudoers/def_data.h, + plugins/sudoers/def_data.in, plugins/sudoers/group_plugin.c, + plugins/sudoers/match.c, plugins/sudoers/nonunix.h, + plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, plugins/sudoers/testsudoers.c, + plugins/sudoers/vasgroups.c, plugins/sudoers/visudo.c, src/sudo.c: + Replace built-in non-unix group support with a sudoers group plugin. + Include a sample plugin that can read Unix-format group files. + [8fc58ce0b1a8] + + * configure, configure.in, src/load_plugins.c: + Add a trailing slash to _PATH_SUDO_PLUGIN_DIR to simplify usage. + [5c491dddb8ef] + +2010-07-01 Todd C. Miller + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudoers.cat, + doc/sudoers.man.in, doc/sudoers.pod: + Move sudoers-specific bits out of sudo(8) and into sudoers(5) + [e8a5a5830cfe] + + * aclocal.m4, configure, configure.in: + Substitute @io_logdir@ for the sudoers I/O log directory. + [21a75ca7b0ab] + +2010-06-29 Todd C. Miller + + * MANIFEST, common/Makefile.in, common/aix.c, common/alloc.c, + common/atobool.c, common/fileops.c, common/fmt_string.c, + common/lbuf.c, common/term.c, compat/fnmatch.c, compat/getcwd.c, + compat/getgrouplist.c, compat/getline.c, compat/glob.c, + compat/snprintf.c, config.h.in, configure, configure.in, + include/fileops.h, plugins/sample/sample_plugin.c, + plugins/sudoers/alias.c, plugins/sudoers/auth/afs.c, + plugins/sudoers/auth/aix_auth.c, plugins/sudoers/auth/bsdauth.c, + plugins/sudoers/auth/dce.c, plugins/sudoers/auth/fwtk.c, + plugins/sudoers/auth/kerb4.c, plugins/sudoers/auth/kerb5.c, + plugins/sudoers/auth/pam.c, plugins/sudoers/auth/passwd.c, + plugins/sudoers/auth/rfc1938.c, plugins/sudoers/auth/secureware.c, + plugins/sudoers/auth/securid.c, plugins/sudoers/auth/securid5.c, + plugins/sudoers/auth/sia.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/boottime.c, plugins/sudoers/check.c, + plugins/sudoers/defaults.c, plugins/sudoers/env.c, + plugins/sudoers/find_path.c, plugins/sudoers/getdate.c, + plugins/sudoers/getdate.y, plugins/sudoers/getspwuid.c, + plugins/sudoers/goodpath.c, plugins/sudoers/gram.c, + plugins/sudoers/gram.y, plugins/sudoers/interfaces.c, + plugins/sudoers/iolog.c, plugins/sudoers/ldap.c, + plugins/sudoers/logging.c, plugins/sudoers/match.c, + plugins/sudoers/parse.c, plugins/sudoers/pwutil.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/toke.c, plugins/sudoers/toke.l, + plugins/sudoers/tsgetgrpw.c, plugins/sudoers/visudo.c, + src/Makefile.in, src/aix.c, src/conversation.c, src/exec.c, + src/exec_pty.c, src/get_pty.c, src/load_plugins.c, src/parse_args.c, + src/sudo.c, src/sudo.h, src/sudo_edit.c, src/tgetpass.c: + Set usrinfo for AIX Set adminstrative domain for the process when + looking up user's password or group info and when preparing for + execve(). Include strings.h even if string.h exists since they may + define different things. Fixes warnings on AIX and others. + [cf8b93e872c9] + + * Makefile.in: + Add a separate all target for AIX make which was using the entire + LHS (not just the first entry) of the first target as the implicit + target. + [a45b980a01ef] + + * plugins/sudoers/env.c: + Do not rely on env.env_len when unsetting a variable, just use the + NULL terminator. + [ca6eb239c829] + + * plugins/sudoers/env.c: + In unsetenv() check for NULL or empty name as per POSIX 1003.1-2008 + [7046ba7caa4e] + +2010-06-25 Todd C. Miller + + * plugins/sudoers/vasgroups.c: + Use warningx() instead of log_error() since the latter is not + available to visudo or testsudoers. This does mean that they don't + end up in syslog. + [152b7c50f426] + + * plugins/sudoers/sudoers.c: + Defer call to sudo_nonunix_groupcheck_cleanup() until after we have + closed the sudoers sources. From Quest sudo. + [c1cd573bab94] + + * plugins/sudoers/pwutil.c: + Ignore case when matching user/group names in the cache. From Quest + sudo. + [2aa4ecc7d7f5] + +2010-06-24 Todd C. Miller + + * config.h.in, configure, configure.in, src/selinux.c: + Add check for setkeycreatecon() when --with-selinux is specified. + [affae247b4e0] + + * configure, configure.in: + Error out if libaudit.h is missing or ununable when --with-linux- + audit was specified + [d82e743fac04] + + * doc/HISTORY, doc/history.pod: + Add =head3 entries, mostly for the html version + [ee93112d0308] + +2010-06-22 Todd C. Miller + + * doc/HISTORY, doc/history.pod: + Mention when LDAP was incorporate. + [2923dc17f79c] + +2010-06-21 Todd C. Miller + + * configure, configure.in: + Define _LINUX_SOURCE_COMPAT on AIX for strsignal() prototype, it is + not covered by _ALL_SOURCE. + [c92fd69809d0] + +2010-06-18 Todd C. Miller + + * plugins/sudoers/iolog.c: + Add a cast to quiet a compiler warning. + [a200e07ee1bc] + + * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y: + Quiet a compiler warning. + [c9acfc927cea] + + * plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c: + Call set_fqdn() after sudoers has parsed instead of inline as a + callback. + [5f4e5d075f2d] + + * WHATSNEW, plugins/sudoers/sudoers.c: + Do not call set_fqdn() until sudoers parses (where is gets run as a + callback). + [09040fca6d40] + + * WHATSNEW: + mention the change in tty ticket behavior when there is no tty + [575a1fd98f05] + + * plugins/sudoers/check.c: + Do not update tty ticket if there is no tty. + [63f9c33ce6a7] + + * doc/LICENSE, doc/license.pod: + Update copyright year + [0722ab5d404b] + + * doc/Makefile.in: + Do not rely on BSD make's $> + [936a86398bd9] + + * configure, configure.in: + Set timedir to /var/db/sudo for darwin to match Apple sudo's + location + [d5b9b03096f1] + +2010-06-16 Todd C. Miller + + * plugins/sudoers/sudoers.h: + Add stub declarations for struct stat and struct timeval + [f6d90551a4fd] + + * MANIFEST: + Remove compat/sigaction.c + [d0ed6d9a770e] + + * config.h.in, configure, configure.in, plugins/sudoers/defaults.c, + plugins/sudoers/iolog.c, plugins/sudoers/sudoreplay.c: + Check for zlib.h in addition to libz. + [6e191b4a6065] + + * MANIFEST, src/Makefile.in, src/exec.c, src/exec_pty.c, src/sudo.h, + src/sudo_exec.h: + Move functions and symbols shared between exec.c and exec_pty.c into + sudo_exec.h. + [14ae63403544] + + * doc/Makefile.in: + Comment out rules to build .man.in and .cat files unless --with- + devel + [3cf7e5606a85] + + * doc/Makefile.in: + Comment out rules to build .man.in and .cat files unless --with- + devel + [d30495b0e29e] + + * src/parse_args.c: + Quote any non-alphanumeric characters other than '_' or '-' when + passing a command to be run via the shell for the -s and -i options. + [d633f74fe2d9] + + * doc/Makefile.in: + Add back .man suffix + [6e63b60a2739] + + * INSTALL, MANIFEST, WHATSNEW, config.h.in, configure, configure.in, + plugins/sudoers/Makefile.in, plugins/sudoers/audit.c, + plugins/sudoers/bsm_audit.c, plugins/sudoers/linux_audit.c, + plugins/sudoers/linux_audit.h, plugins/sudoers/logging.h, + src/selinux.c: + Add Linux audit support. + [5a2f445e0bd4] + +2010-06-15 Todd C. Miller + + * plugins/sudoers/iolog.c: + Remove an XXX + [a170cbe651d1] + + * doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod, + plugins/sudoers/sudoreplay.c: + Add -f (filter) option to sudoreplay to allow certain streams to be + replayed and others ignored. + [62e51b432ea1] + + * src/load_plugins.c, src/parse_args.c, src/sudo.c, src/sudo.h, + src/tgetpass.c: + Fix -A flag when askpass is specified in sudo.conf or if sudo + doesn't need to read a password. + [2e401e4a00e3] + + * src/exec.c, src/exec_pty.c, src/parse_args.c, src/sudo.c, + src/sudo.h, src/sudo_edit.c, src/tgetpass.c: + Clean up some XXXs + [689f0b002d3d] + + * WHATSNEW, doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, + doc/sudoers.ldap.pod, plugins/sudoers/ldap.c: + Add support for multiple sudoers_base entries in ldap.conf. From + Joachim Henke + [e3e4a3c2bd5b] + + * config.h.in, configure, configure.in, plugins/sudoers/logging.c, + src/exec_pty.c: + remove setsid check, we require a POSIX system + [cc73cb9e22c0] + + * plugins/sudoers/logging.c, src/exec_pty.c, src/selinux.c, + src/sudo.c, src/tgetpass.c: + Check for dup2() failure. + [5d46d66794f5] + + * config.h.in, configure, configure.in: + Remove dup2() check, it is not optional. + [5f1d56de4384] + +2010-06-14 Todd C. Miller + + * WHATSNEW: + sync with sudo 1.7.3 + [88e5c0bd6d59] + + * INSTALL: + SunOS does not ship with an ANSI compiler + [f13c85c67069] + + * INSTALL: + Update OS specific notes. Delete some really ancient ones and move + older ones to the end of the list. + [59ce592c4c52] + + * README: + Sudo can be downloaded from the web site too Mention "OS dependent + notes" section in INSTALL + [191871538984] + + * src/exec_pty.c, src/selinux.c: + Call selinux_restore_tty() as part of cleanup() so it gets called + from error()/errorx() + [bb017da6b6da] + + * MANIFEST, doc/PORTING: + Remove obsolete porting guide + [321e35591344] + + * plugins/sudoers/interfaces.h, plugins/sudoers/match.c: + Move union sudo_in_addr_un into interfaces.h + [b2c8b19ee094] + + * doc/Makefile.in: + Remove useless circular dependencies + [5682181b59cf] + + * plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c, + plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c, + plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c, + plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c, + plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c: + Convert to ANSI C function declarations + [a4f76927d034] + + * common/alloc.c, common/fileops.c, common/gettime.c, common/list.c, + common/zero_bytes.c, compat/charclass.h, compat/closefrom.c, + compat/fnmatch.c, compat/glob.c, compat/isblank.c, compat/memrchr.c, + compat/mkstemp.c, compat/nanosleep.c, compat/snprintf.c, + compat/strcasecmp.c, compat/strerror.c, compat/strlcat.c, + compat/strlcpy.c, compat/timespec.h, compat/utime.h, + compat/utimes.c, doc/HISTORY, doc/history.pod, doc/license.pod, + include/alloc.h, include/error.h, include/lbuf.h, include/list.h, + include/missing.h, pathnames.h.in, plugins/sudoers/alias.c, + plugins/sudoers/audit.c, plugins/sudoers/auth/sudo_auth.h, + plugins/sudoers/boottime.c, plugins/sudoers/bsm_audit.c, + plugins/sudoers/bsm_audit.h, plugins/sudoers/defaults.c, + plugins/sudoers/defaults.h, plugins/sudoers/find_path.c, + plugins/sudoers/getspwuid.c, plugins/sudoers/goodpath.c, + plugins/sudoers/gram.y, plugins/sudoers/interfaces.c, + plugins/sudoers/interfaces.h, plugins/sudoers/logging.c, + plugins/sudoers/logging.h, plugins/sudoers/match.c, + plugins/sudoers/parse.h, plugins/sudoers/plugin_error.c, + plugins/sudoers/pwutil.c, plugins/sudoers/redblack.c, + plugins/sudoers/redblack.h, plugins/sudoers/sudo_nss.h, + plugins/sudoers/sudoers.h, plugins/sudoers/sudoreplay.c, + plugins/sudoers/testsudoers.c, plugins/sudoers/timestr.c, + plugins/sudoers/toke.l, plugins/sudoers/visudo.c, src/aix.c, + src/conversation.c, src/error.c, src/load_plugins.c, + src/parse_args.c, src/sesh.c, src/sudo.h, src/sudo_noexec.c, + src/sudo_plugin_int.h, src/sudo_usage.h.in, src/tgetpass.c: + Update copyright year + [26ac7991f7d8] + + * doc/Makefile.in: + Fix commented DEVDOCS when not in devel mode. + [e0a97eaf3793] + + * plugins/sudoers/match.c: + Quiet a compiler warning. + [b2a17ebd5d38] + + * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y: + Quiet a compiler warning. + [687843bc593d] + + * plugins/sudoers/ldap.c, plugins/sudoers/sudoers.h: + Make all functions in ldap.c static + [b2111e89eeba] + + * doc/schema.ActiveDirectory: + Updates from Alain Roy to provide better examples for importing the + schema and to fix problems caused by Windows validating attributes + which have not yet been added before committing the changes. + [69f4c5ccaf89] + +2010-06-11 Todd C. Miller + + * configure, configure.in, doc/Makefile.in, doc/sudo.cat, + doc/sudo.man.in, doc/sudo_plugin.cat, doc/sudo_plugin.man.in, + doc/sudoers.cat, doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, + doc/sudoers.man.in, doc/sudoreplay.cat, doc/sudoreplay.man.in, + doc/visudo.cat, doc/visudo.man.in: + Leave rules to build .man.in and .cat files uncommented but only + make them part of the "all" rule in devel mode. Generate .cat files + directly from .man.in instead of .man using default values in + configure.in + [c3054a44f6a5] + + * configure, configure.in: + Bump sudo version to 1.8.0b1 + [8f79c85135e1] + + * configure, configure.in, src/sudo.c, src/sudo_usage.h.in: + Print configure args with verbose version information. + [1ce690660ed2] + + * TODO, plugins/sudoers/visudo.c: + Remove tfd from struct sudoersfile; it is not used. Add prev pointer + to struct sudoersfile. Declare list of sudoersfile using TQ_DECLARE. + Use tq_append to append sudoers entries to the tail queue. + [1743f9a286e4] + +2010-06-10 Todd C. Miller + + * WHATSNEW: + Describe tty timestamp improvements + [e214e863a313] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + A comment character may not be part of a command line argument + unless it is quoted with a backslash. Fixes parsing of: + testuser ALL=NOPASSWD: /usr/bin/wl #comment foo bar closes bz #441 + [ea2e990f85ed] + + * doc/sudoers.pod: + Make this read a little bit better when passwd_timeout is 0. + [39d362757f31] + + * doc/sudo.man.in, doc/sudo.man.pl, doc/sudo.pod: + Attempt to handle a default password prompt timeout of zero more + gracefully. + [ea47d43acf5b] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + Do not override value of keepopen global, instead restore it to the + value we pushed onto the stack when popping. + [fe282e5a3402] + + * plugins/sudoers/Makefile.in: + Add dependency for utility programs on libreplace and libcommon + [2339aba64928] + + * compat/sigaction.c, config.h.in, configure.in, include/compat.h, + plugins/sudoers/logging.c, plugins/sudoers/mon_systrace.c, + src/exec.c, src/exec_pty.c, src/tgetpass.c: + Remove sigaction emulation Use SA_INTERRUPT in sa_flags + [7dd61f1bd8d2] + + * MANIFEST, config.h.in, configure, configure.in, include/missing.h: + We don't use getgrouplist() at the moment so there's no need to + provide a compat version. + [1597536fbada] + + * TODO: + sync with reality + [9e1a874e7885] + + * include/sudo_plugin.h, plugins/sudoers/auth/sudo_auth.c, + src/conversation.c, src/sudo.h, src/tgetpass.c: + Fix visiblepw sudoers option; the plugin API portion still needs + documenting + [60b6933ef5e0] + + * src/sudo.c: + Print sudo version as well. + [987ed459b459] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c: + Use sudo_printf for I/O log version Clarify policy plugin version + string + [5a58b7e8c80b] + + * plugins/sudoers/getdate.c, plugins/sudoers/getdate.y, + plugins/sudoers/ldap.c, plugins/sudoers/sudoreplay.c: + Silence some compiler warnings + [afb1eba90915] + + * src/load_plugins.c, src/tgetpass.c: + Store askpass path in a global instead of uses setenv() which many + systems lack. + [b440bcc0e660] + +2010-06-09 Todd C. Miller + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + plugins/sudoers/check.c, plugins/sudoers/def_data.c, + plugins/sudoers/def_data.h, plugins/sudoers/def_data.in, + plugins/sudoers/defaults.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/load_plugins.c, src/parse_args.c, + src/tgetpass.c: + Move askpass path specification from sudoers to sudo.conf. + [5507ab867c26] + + * src/exec.c, src/exec_pty.c, src/sudo.c, src/sudo.h: + Use a flag bit in struct command_details for selinux instead of a + separate field. + [c59ca4acded9] + + * src/exec.c, src/exec_pty.c, src/sudo.c, src/sudo.h: + Implement background mode. If I/O logging we use pipes instead of a + pty. + [c07a4b356cbd] + + * compat/mksiglist.c, compat/strsignal.c, include/compat.h, + src/exec.c, src/exec_pty.c, src/tgetpass.c: + Move compat definition of NSIG to compat.h + [ab0385467f25] + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Mention plugins in the sudo manual and add some missing path + substitution in the sudo_plugin manual. + [570f831f47a3] + + * src/Makefile.in: + Set _PATH_SUDO_CONF based on $(sysconfdir) + [fde51869cf07] + + * common/lbuf.c, common/term.c, config.h.in, configure, configure.in, + src/exec.c, src/exec_pty.c, src/ttysize.c: + Require POSIX termios to build sudo + [9ec6b41f3f95] + + * src/tgetpass.c: + Ignore SIGPIPE for "sudo -S" + [7ad27fde0c06] + + * src/tgetpass.c: + Fix uninitialized variable in TGP_ECHO case and print a newline if + the user interrupted password input. + [ce19204d8dd4] + + * src/tgetpass.c: + Make TGP_ECHO override TGP_MASK and don't try to restore the + terminal if we didn't modify it. + [a7e11abfe7e4] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + include/sudo_plugin.h, plugins/sudoers/auth/sudo_auth.c, + src/conversation.c, src/sudo.h, src/tgetpass.c: + Add SUDO_CONV_PROMPT_MASK define which corresponds to the + "pwfeedback" sudoers option. Do not disable echo if TGP_ECHO is + set. + [e0550590cabe] + + * src/exec_pty.c: + Use POSIX tcgetpgrp() instead of BSD TIOCGPGRP ioctl + [762448182fe3] + +2010-06-08 Todd C. Miller + + * src/exec.c, src/exec_pty.c, src/selinux.c, src/sudo.c, src/sudo.h: + Add selinux_enabled flag into struct command_details and set it in + command_info_to_details(). Return an error from selinux_setup() + instead of exiting. Call selinux_setup() from exec_setup(). + [011bea23a5a0] + +2010-06-09 Todd C. Miller + + * src/exec_pty.c: + Remove commented out copy of old sudo_execve() function. + [9c5e21380472] + +2010-06-08 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Fix setting selinux type on command line. + [814b20a0b3be] + + * plugins/sudoers/iolog.c: + In sudoers_io_close(), skip NULL io_fds[] elements. + [4011ff7d4daf] + + * include/compat.h: + No longer need NGROUPS_MAX define + [cae4c49d7077] + + * compat/nanosleep.c, config.h.in, configure, configure.in, + include/compat.h, plugins/sudoers/check.c, plugins/sudoers/iolog.c, + plugins/sudoers/visudo.c, src/sudo_edit.c: + Replace timerfoo macros with timevalfoo since the timer macros are + known to be busted on some systems. + [4f97d79f2d41] + + * src/exec_pty.c: + Remove duplicate call to selinux_setup(). + [82bd52764e21] + + * plugins/sudoers/auth/pam.c: + If pam_open_session() fails, pass its status to pam_end. + [1d8de4cf8ff3] + + * plugins/sudoers/toke.c, plugins/sudoers/toke.l: + If a file in a #includedir has improper permissions or owner just + skip it. This prevents packages that incorrectly install a file + into /etc/sudoers.d from breaking sudo so easily. Syntax errors in + #includedir files still result in a parse error (for now). + [ade99a4549a4] + + * WHATSNEW, doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod, + plugins/sudoers/def_data.c, plugins/sudoers/def_data.h, + plugins/sudoers/def_data.in, plugins/sudoers/iolog.c: + Add use_pty sudoers option to force use of a pty even when not + logging I/O. + [b280a8972a79] + + * plugins/sudoers/env.c, plugins/sudoers/sudoers.h: + Make env_init() void as it never fails. + [d3890e55daa7] + + * plugins/sudoers/env.c: + No longer use _NSGetEnviron so don't need crt_externs.h + [9b4e0e139881] + + * plugins/sudoers/env.c: + Remove unused VNULL define + [a42cacb263e3] + +2010-06-07 Todd C. Miller + + * plugins/sudoers/iolog.c: + Add #define for maximum session id + [9e18c17a28c2] + + * MANIFEST, src/Makefile.in, src/exec.c, src/exec_pty.c, src/sudo.h: + Split exec.c into exec.c and exec_pty.c + [d52376327332] + + * MANIFEST: + Sync with source file moves. + [4a62c6c9e846] + + * src/Makefile.in, src/get_pty.c, src/pty.c: + Rename pty.c -> get_pty.c + [5696a12bd29b] + +2010-06-06 Todd C. Miller + + * plugins/sudoers/iolog.c: + Only use I/O input log file if def_log_input is set and output file + if def_log_output is set. + [d866992f1681] + +2010-06-04 Todd C. Miller + + * compat/strsignal.c: + Update copyright year + [a96f2593fd4e] + + * src/pty.c: + uid -> ttyuid + [c3454d74ebcb] + + * plugins/sudoers/sudoers.c: + For sudoedit, make a local copy of editor string si become part of + argv. If no editor environment variable, split def_editor on ':' + since it may be a colon-delimited path. + [2ee298506a6e] + + * src/sudo_edit.c: + Remove unneeded endpwent()/endgrent() + [623f6743d101] + + * doc/Makefile.in: + Use value of nroff from configure + [b2ce649125ab] + + * src/exec.c: + Add missing const to I/O log action function + [d764a3955e04] + + * plugins/sudoers/check.c: + Update copyright year and fix whitespace + [e648c35b16be] + + * configure, configure.in: + Fix typo + [8e0bdfc47da4] + + * plugins/sudoers/iolog.c: + Remove redundant tty signal blocking in log function. + [f17f575dabd4] + +2010-06-03 Todd C. Miller + + * plugins/sudoers/iolog.c: + Place static keyword where it belongs + [b01aec7c86b4] + + * plugins/sudoers/logging.c: + Always use a printf format string for send_mail() + [13b1ada644c9] + + * common/atobool.c, plugins/sudoers/ldap.c: + Extend atobool() so we can use it in the LDAP code. + [73f8e6807044] + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod: + Sudo now stashes tty ctime for tty_tickets on Solaris too. + [e82df13ad3fd] + + * plugins/sudoers/boottime.c: + Fix dummy version of get_boottime() + [01d69c06013b] + +2010-06-02 Todd C. Miller + + * plugins/sudoers/check.c: + Enable tty_is_devpts() support for Solaris with the "devices" + filesystem. + [237c6b25fa84] + + * src/exec.c: + Unbreak the non-io logging case. + [4822b9f709fb] + + * src/conversation.c, src/sudo.c, src/sudo_plugin_int.h: + Fix symbol name conflict with sudo_printf. + [0d44eab0a8f6] + + * plugins/sudoers/auth/pam.c: + Fix OpenPAM detection for newer versions. + [1b2abed232d8] + + * plugins/sudoers/vasgroups.c: + Sync with Quest sudo git repo + [f1d98b3cba02] + + * aclocal.m4, configure, configure.in: + HP-UX ld uses +b instead or -R or -rpath Fix typo in libvas check + Add missing template for ENV_DEBUG Adapted from Quest sudo + [695dbd7b28f4] + + * README.LDAP: + Fix typos; from Quest Sudo + [4eba9da33b8e] + +2010-06-01 Todd C. Miller + + * plugins/sudoers/Makefile.in: + Add back -I$(top_srcdir); we need it for including compat/foo.h + since we cannot rely on "foo.h" being found relative to the source + file when the cwd is different. + [bbf24695f325] + + * src/exec.c: + Fix a bug where we could treat EAGAIN as a permanent error. Also set + cstat if perform_io() returns an error. + [200475c4326f] + + * common/alloc.c, plugins/sudoers/boottime.c, + plugins/sudoers/sudoers.c: + Add casts to quiet compiler warnings. + [85eb1c336697] + + * plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/visudo.c: + Fix typo in ternary operator usage. + [6492ac1450e2] + +2010-05-30 Todd C. Miller + + * INSTALL, configure, configure.in: + Add --enable-warnings and fix typo in SUDO_IO_LOGDIR + [92121d693b30] + + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod, + doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod: + Update docs to match sudoers I/O logging changes + [18d651989e49] + + * INSTALL, WHATSNEW, aclocal.m4, configure, configure.in, + pathnames.h.in, plugins/sudoers/def_data.c, + plugins/sudoers/def_data.h, plugins/sudoers/def_data.in, + plugins/sudoers/defaults.c, plugins/sudoers/gram.c, + plugins/sudoers/gram.h, plugins/sudoers/gram.y, + plugins/sudoers/iolog.c, plugins/sudoers/parse.c, + plugins/sudoers/parse.h, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoreplay.c: + Break sudoers transcript feature up into log_input and log_output. + [db3c1248d2ad] + + * plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/visudo.c: + Use setprogname() as needed. + [6beee63a4553] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoreplay.c: + Adapt sudoreplay to iolog changes. + [581f52c05f0f] + +2010-05-29 Todd C. Miller + + * plugins/sudoers/iolog.c: + Log all input and output into separate files and store a number on + each timing file line to indicate which file the data is in. + [fb460c5273dd] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Make sudoers_io functions static to iolog.c + [b2df3cc3eecb] + +2010-05-28 Todd C. Miller + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, src/parse_args.c, + src/sudo_usage.h.in: + Completely remove the -L flag from the sudo front end. + [3d220030b720] + + * plugins/sudoers/sudoreplay.c: + Fix EAGAIN handling when writing to stdout. + [4766d77cea49] + + * plugins/sudoers/sudoers.c: + Eliminate unused variables + [83bd711e79c4] + + * plugins/sudoers/sudoers.c, src/exec.c, src/sudo.c: + Re-enable cleanup functions in sudoers plugin and sudo driver for + error()/errorx(). + [43093f937dd8] + + * plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/defaults.c, + plugins/sudoers/interfaces.c, plugins/sudoers/iolog.c, + plugins/sudoers/parse.c, plugins/sudoers/sudoers.c, + plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c: + Use sudo_printf to display verbose version information. + [435cc9f8d4a2] + + * common/Makefile.in, compat/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Minor Makefile cleanup: fix a typo, change the removal order in the + clean targets, and remove a superfluous include path for the sudoers + plugin. + [6e3b2d6b4437] + + * plugins/sudoers/env.c: + Handle duplicate variables in the environment. For unsetenv(), keep + looking even after remove the first instance. For sudo_putenv(), + check for and remove dupes after we replace an existing value. + [c1bbb88d0435] + +2010-05-27 Todd C. Miller + + * plugins/sudoers/Makefile.in: + Use explicit path to source file instead of $< for files that live + in devdir and top_srcdir. + [358ab7f6cc64] + + * plugins/sudoers/Makefile.in: + Add explicit rules to compile gram.c and toke.c for HP-UX Pevent + ending LIBSUDOERS_OBJS with a backslash + [481a5c96d47e] + + * plugins/sudoers/Makefile.in, src/Makefile.in: + Link libcommon before libreplace since libcommon may use functions + only present in libreplace. + [1847c496ff5b] + + * common/Makefile.in: + Move code common to sudo and the sudoers plugin to a convenience + library, libcommon. Removes the need to make links in the sudoers + plugin dir and reduces re-compilation of duplicate object files. + [4c8986352937] + + * Makefile.in, common/alloc.c, common/atobool.c, common/fileops.c, + common/fmt_string.c, common/gettime.c, common/lbuf.c, common/list.c, + common/term.c, common/zero_bytes.c, configure, configure.in, + plugins/sample/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in, src/alloc.c, src/atobool.c, src/fileops.c, + src/fmt_string.c, src/gettime.c, src/lbuf.c, src/list.c, src/term.c, + src/zero_bytes.c: + Move code common to sudo and the sudoers plugin to a convenience + library, libcommon. Removes the need to make links in the sudoers + plugin dir and reduces re-compilation of duplicate object files. + [1d1d98bd55b9] + + * src/exec.c, src/sudo.c, src/sudo.h: + Rename script_execve to sudo_execve and rename script_foo in exec.c + [a35ec80de96a] + + * MANIFEST, src/Makefile.in, src/exec.c, src/script.c: + rename script.c exec.c and fix up the MANIFEST file + [36bc3bff9578] + + * src/script.c, src/sudo.c, src/sudo.h: + Rename script_setup() to pty_setup() and call from script_execve() + directly. + [899b0fb2a14d] + + * configure, configure.in: + bump version to 1.8.0a2 + [0b1c1ca9d4e5] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document init_session + [b5324785a406] + + * plugins/sudoers/auth/API, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/auth/sudo_auth.h: + Clean up the sudoers auth API a bit and update the docs. + [c40fd4cb6e68] + + * include/sudo_plugin.h, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, src/script.c, src/sudo.c: + Add init_session function to struct policy_plugin that gets called + before the uid/gid/etc changes. A struct passwd pointer is passed + in,which may be NULL if the user does not exist in the passwd + database.The sudoers module uses init_session to open the pam + session as needed. + [d71723320ee8] + +2010-05-26 Todd C. Miller + + * plugins/sudoers/auth/pam.c, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/auth/sudo_auth.h, plugins/sudoers/set_perms.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Add open/close session to sudo auth, only used by PAM. This allows + us to open (and close) the PAM session from sudoers. + [2665e2920d0d] + + * plugins/sudoers/Makefile.in: + Add explicit rule to build getdate.o for HP-UX make. + [7f049e989956] + + * plugins/sudoers/Makefile.in: + Back out most of change 45e406ebdea2. Create dummy .l.c and .y.c + rules as an alternate way to prevent HP-UX make (and others) from + trying to rebuild the parser in non-dev mode. + [f84badad98c5] + + * plugins/sudoers/sudoers.c: + Re-enable PATH_MAX check for command + [40d8a50da136] + + * Makefile.in: + For distclean, clean the main directory last since the subdirs need + to be able to run libtool to clean things. + [8949a9861634] + + * compat/Makefile.in: + Fix generation of mksiglist.h + [b7cdc9b36650] + + * src/script.c: + Now that we defer sending cstat until the end of script_child() we + cannot reuse cstat when reading command status from parent. + [25c882643466] + +2010-05-25 Todd C. Miller + + * configure, configure.in, doc/sudo.man.in, doc/sudo.man.pl, + doc/sudoers.cat, doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, + doc/sudoers.man.in, doc/sudoers.man.pl, doc/sudoreplay.cat, + doc/sudoreplay.man.in, doc/visudo.cat, doc/visudo.man.in: + Use numeric registers to handle conditionals instead of trying to do + it all with text processing. + [478079c3fd4b] + + * doc/sudoers.pod: + Document per-command SELinux settings + [13840d566805] + + * plugins/sudoers/sudoers.c: + Repair "sudo -l -U username" + [10a0dcdf2ddf] + + * plugins/sudoers/sudoers.c: + Set selinux role and type in command details. + [8ae6d35a126d] + + * src/script.c, src/selinux.c, src/sudo.h: + Rework SELinux support. + [83279cc94bf2] + +2010-05-24 Todd C. Miller + + * src/script.c, src/selinux.c, src/sudo.h: + Make SELinux support compile again. Needs more work to be complete. + [3d3addebcf82] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + src/parse_args.c, src/script.c, src/selinux.c, src/sudo.c, + src/sudo.h: + Bring back closefrom settings. + [b1c6257d4bbb] + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + If running a command or sudoedit in transcript mode, call + io_nextid() before log_allowed() so the session id is logged. + [c42f3ae40150] + + * configure, configure.in: + Use mandoc(1) if nroff(1) is not present. + [daad4bbd04af] + + * doc/Makefile.in: + Use the --file argument to config.status instead of setting + CONFIG_FILES in the environment. + [c89411a8bf70] + + * plugins/sudoers/Makefile.in: + We cannot conditionally update gram.h or the dependency ordering + gets messed up in devel mode. + [c938953231d9] + +2010-05-21 Todd C. Miller + + * Makefile.in, compat/Makefile.in, configure, configure.in, + doc/Makefile.in, include/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Substitute @SHELL@ into Makefiles + [36aa6a095335] + + * config.sub: + Fix typo + [16d294d26b58] + + * config.guess, config.sub, configure, configure.in: + Update to autoconf 2.65 + [4fa6ea8caea3] + + * Makefile.in: + Fix libtool target (space vs. tabs) + [755cf3892618] + + * config.h.in, plugins/sudoers/logging.h, plugins/sudoers/visudo.c: + Remove use of RETSIGTYPE; all modern systems have signal handlers + that return void. + [42b4e3aee668] + + * Makefile.in, aclocal.m4, acsite.m4, configure, configure.in, + ltmain.sh, m4/libtool.m4, m4/ltoptions.m4, m4/ltsugar.m4, + m4/ltversion.m4, m4/lt~obsolete.m4, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Update to libtool-2.2.6b. I haven't made any local modifications + this time, which should be OK since we install sudo_noexec.so by + hand now. + [6f79ced593bb] + + * compat/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Use libtool to clean objects + [1581057d6472] + + * include/Makefile.in: + Install sudo_plugin.h as part of "make install" and make other + install targets callable from the top-level Makefile + [aaaeb027d774] + + * configure, configure.in: + regen with autoupdate to eliminate AC_TRY_LINK + [5d5541c230f5] + + * Makefile.in, compat/Makefile.in, configure, configure.in, + doc/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Install sudo_plugin.h as part of "make install" and make other + install targets callable from the top-level Makefile + [b258b8401b1c] + + * plugins/sample/sample_plugin.c: + The sample plugin doesn't support being run with no args so return a + usage error in this case. + [473b3cf965be] + + * plugins/sudoers/iolog.c: + Set close on exec flag for descriptors used for I/O logging so they + are not present in the command being run. + [2c7e8708df76] + + * plugins/sudoers/tsgetgrpw.c: + Set close on exec flag in private versions of setpwent() and + setgrent(). + [64fef78cb833] + + * src/script.c: + Close the I/O pipes aftering dup2()ing them to std{in,out,err}. + Fixes extra fds being present in the command when it is part of a + pipeline. + [060451617713] + + * plugins/sudoers/sudoers.c: + Set user_tty to "unknown" if there is no tty, like sudo 1.7 does (it + is used when logging). Note that user_ttypath will still be NULL if + there is no tty. + [31b69a6ecda7] + + * src/script.c, src/sudo.h: + Cosmetic changes: add comments, remove orphaned prototype and + make a global static. + [f7851af0143e] + +2010-05-20 Todd C. Miller + + * src/script.c: + Move check for maxfd == -1 to flush_output where it belongs. + [b826a95b4491] + + * src/script.c: + Break out of select loop if all the fds we want to select on are -1. + [f5b387024238] + + * src/sudo.c: + Avoid possible malloc(0) if plugin returns an empty groups list. + [9765a8fe5ce7] + + * src/sudo.c: + Add debugging info when calling plugin close function + [95a273c7ff66] + + * src/script.c: + Avoid closing stdin/stdout/stderr when we are piping output. + [330e76423caf] + + * src/script.c: + When execve() of the command fails, it is possible to receive + SIGCHLD before we've read the error status from the pipe. Re-order + things such that we send the final status at the very end and prefer + error status over wait status. + [b0dcf825244f] + +2010-05-19 Todd C. Miller + + * plugins/sudoers/auth/sudo_auth.c: + Fix compilation for non PAM/BSD auth/AIX auth + [e382b39d2e4f] + +2010-05-18 Todd C. Miller + + * src/script.c: + Additional checks to make sure we don't close /dev/tty by mistake. + When flushing, sleep in select as long as we have buffers that need + to be written out. + [8139cbd3dd54] + + * src/script.c: + Now that we can use pipes for stdin/stdout/stderr there is no longer + a need to error out when there is no tty. We just need to make sure + we don't try to use the tty fd if it is -1. + [666621635d26] + +2010-05-17 Todd C. Miller + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + include/sudo_plugin.h, plugins/sample/sample_plugin.c, + plugins/sudoers/iolog.c, plugins/sudoers/sudoers.h, src/sudo.c: + Add argc and argv to I/O logger open function. + [0d7faa007d27] + + * doc/sudo_plugin.man.in, doc/sudo_plugin.pod, include/sudo_plugin.h, + plugins/sample/sample_plugin.c, plugins/sudoers/sudoers.c, + src/parse_args.c, src/sudo.c, src/sudo_edit.c: + Remove check_sudoedit function pointer in struct sudo_policy. + Instead, sudo will set sudoedit=true in the settings array. The + plugin should check for this and modify argv_out as appropriate in + check_policy. + [c0328e3276b8] + +2010-05-16 Todd C. Miller + + * plugins/sample/sample_plugin.c, src/sudo.c, src/sudo.h, + src/sudo_edit.c: + If plugin sets "sudoedit=true" in the command info, enable sudoedit + mode even if not invoked as sudoedit. This allows a plugin to + enable sudoedit when the user runs an editor. + [96d67b99e42e] + +2010-05-15 Todd C. Miller + + * plugins/sudoers/Makefile.in: + gram.h must not depend on gram.y if we want to avoid unnecessary + rebuilding of targets dependent on gram.h when gram.y changes. + [9db4b767fdca] + + * plugins/sample/sample_plugin.c: + Refactor common bits of check_policy and check_edit + [ac4d366a04cf] + + * plugins/sample/sample_plugin.c: + Add sudoedit support + [a1a6cc4c0cef] + +2010-05-14 Todd C. Miller + + * plugins/sudoers/Makefile.in: + Rely more on VPATH; fixes a dependency issue with the parser. + [45e406ebdea2] + + * include/compat.h: + Fix typo introduced in last commit + [3ccb0f853d11] + + * include/compat.h: + Emulate seteuid using setreuid() or setresuid() as needed. There are + still a few places that call seteuid() directly. + [36e8efa3a99d] + + * src/parse_args.c, src/sudo_edit.c: + Attempt to fix building on systems that only have setuid. + [8e9ba4083318] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Clarify sudoedit a tad. + [d39dfaa14ade] + +2010-05-13 Todd C. Miller + + * src/sudo_edit.c: + Fix compilation on HP-UX + [f6e47843d139] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document sudoedit + [4cbf5196d993] + + * plugins/sudoers/sudoers.c, src/sudo.c, src/sudo.h, src/sudo_edit.c: + Change how we handle the sudoedit argv. We now require that there + be a "--" in argv to separate the editor and any command line + arguments from the files to be edited. + [20623d549a3c] + + * include/sudo_plugin.h, plugins/sample/sample_plugin.c, + plugins/sudoers/Makefile.in, plugins/sudoers/gettime.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c, + src/Makefile.in, src/gettime.c, src/parse_args.c, src/sudo.c, + src/sudo.h, src/sudo_edit.c: + Work in progress support for sudoedit. The actual interface used by + the plugin for sudoedit is likely to change. + [c31262a31997] + + * plugins/sudoers/find_path.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, plugins/sudoers/visudo.c: + Make find_path() a little more generic by not checking def_foo + variables inside it. Instead, pass in ignore_dot as a function + argument. + [9c23101a094d] + + * plugins/sudoers/env.c: + Add version of getenv(3) that uses our own environ pointer. + [0e3783e63534] + +2010-05-12 Todd C. Miller + + * src/script.c: + Avoid a potential race condition if SIGCHLD is received immediately + before we call select(). + [99adc5ea7f0a] + + * plugins/sudoers/sudoers.c: + Call env_init() before we open the sudoers sources as those may call + our setenv() replacement. + [5f82601f5ab0] + + * plugins/sudoers/env.c: + Initialize env_len in env_init() + [7ae02b3029b5] + +2010-05-11 Todd C. Miller + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod: + Document time stamp shortcomings under SECURITY NOTES Use "time + stamp" instead of timestamp. + [2b86120815b2] + + * doc/Makefile.in: + Make sed substitution of mansectsu and mansectform global. + [94588632dba0] + + * plugins/sudoers/check.c: + If the tty lives on a devpts filesystem, stash the ctime in the tty + ticket file, as it is not updated when the tty is written to. This + helps us determine when a tty has been reused without the user + authenticating again with sudo. + [0e62a31bceb0] + + * src/tgetpass.c: + Fix pasto in mulitple signal fix and use _NSIG not NSIG since that + is what our compat checks set. + [df50f0a040c9] + + * configure, configure.in: + Add check for whether sudo need to link with -ldl to get dlopen(). + This is a bit of a hack that will get reworked when libtool is + updated. + [63bdcf579533] + + * plugins/sudoers/check.c: + Fix timestamp removal with -k/-K + [6b4639fef973] + + * plugins/sudoers/Makefile.in: + audit.c is now private to the sudoers plugin + [1974f342ae0b] + + * configure, configure.in: + Link with -lpthread on HP-UX since a plugin may be linked with + -lpthread and dlopen() will fail if the shared object has a + dependency on -lpthread but the main program is not linked with it. + [d42139391263] + + * config.h.in, configure, configure.in, plugins/sudoers/set_perms.c: + Add separate test for getresuid() since HP-UX has setresuid() but no + getresuid(). + [910fe727a374] + + * doc/Makefile.in: + Remove errant backslash + [dd5464257c69] + + * src/script.c: + Fix SIGPIPE handling. Now that we use may use pipes for + stdin/stdout we need to pass any SIGPIPE we receive to the running + command. + [3f6b1991f4fd] + + * src/script.c: + Also start the command in the background if stdin is not a tty. + [d93bc33a3740] + +2010-05-10 Todd C. Miller + + * plugins/sudoers/sudoreplay.c, src/script.c, src/sudo.h, src/term.c: + No need to use pseudo-cbreak mode now that we use pipes when stdout + is not a tty. Instead, check whether stdin is a tty and if not, + delay setting the tty to raw mode until the command tries to access + it itself (and receives SIGTTIN or SIGTTOU). + [e68315cf8c6b] + + * src/tgetpass.c: + Use an array for signals received instead of a single variable so we + don't lose any when there are multiple different signals. + [2ac726dac864] + + * src/tgetpass.c: + Do signal setup after turning off echo, not before. If we are using + a tty but are not the foreground pgrp this will generate SIGTTOU so + we want the default action to be taken (suspend process). + [bebb6209c795] + +2010-05-07 Todd C. Miller + + * src/script.c: + Flush the iobufs on suspend or child exit using the same logic as + the main event loop. + [c627feee1035] + + * src/script.c: + Free memory after we are done with it. + [8db9b611b45a] + +2010-05-06 Todd C. Miller + + * doc/HISTORY: + Quest now sponsors Sudo development + [6cc490083bc7] + +2010-05-05 Todd C. Miller + + * doc/Makefile.in: + Install sudo_plugin man page. + [c253729790b2] + + * src/script.c: + Go back to reseting io_buffer offset and length (and now also the + EOF handling) in the loop we do the FD_SET, not after we drain the + buffer after write() since we don't know what order reads and writes + will occur in. + [5f38bfa8497f] + + * MANIFEST: + audit files moved to sudoers plugin directory + [b1ead182428e] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document plugin_printf and new logging functions. + [fe9430b60ab5] + + * src/script.c: + Add support for logging stdin when it is not a tty. There is still a + bug where "cat | sudo cat" has problems because both cat and sudo + are trying to read from the tty. + [04c9c59fcfba] + + * include/sudo_plugin.h, plugins/sample/sample_plugin.c, + plugins/sudoers/sudoers.c, src/script.c: + Add separate I/O logging functions for tty in/out and + stdin/stdout/stderr. NOTE: stdin logging does not currently work and + is disabled for now. + [a36dfd4ca935] + +2010-05-04 Todd C. Miller + + * include/sudo_plugin.h, plugins/sample/sample_plugin.c, + plugins/sudoers/iolog.c, plugins/sudoers/ldap.c, + plugins/sudoers/logging.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + src/conversation.c, src/sudo.c, src/sudo_plugin_int.h: + Add pointer to a printf like function to plugin open functon. This + can be used instead of the conversation function to display info and + error messages. + [98734eea8ef1] + + * Makefile.in: + Stop if make in a subdir fails + [228bb3ad2dbc] + + * src/script.c: + Only set user's tty to blocking mode when doing the final flush. + Flush pipes as well as pty master when the process is done. + [20ff67218666] + +2010-05-03 Todd C. Miller + + * plugins/sudoers/ldap.c: + Use print_error() when displaying ldap config info in debugging + mode. + [d142e0cacb22] + + * compat/Makefile.in, compat/strdup.c, compat/strndup.c: + No longer need strdup() or strndup() replacements. + [df53697174ec] + + * plugins/sudoers/logging.c, plugins/sudoers/plugin_error.c, + plugins/sudoers/sudoers.h: + Add print_error() function that uses the conversation function to + print a variable number of error strings and use it in log_error(). + [b1fa2861b575] + + * src/script.c, src/sudo.h, src/term.c: + Do not need the opost flag to term_copy() now that we use pipes for + stdout/stderr when they are not a tty. + [f42811f70a19] + + * src/script.c: + Use pipes to the sudo process if stdout or stderr is not a tty. + Still needs some polishing and a decision as to whether it is + desirable to add additonal entry points for logging + stdout/stderr/stdin when they are not ttys. That would allow a + replay program to keep things separate and to know whether the + terminal needs to be in raw mode at replay time. + [1a945e0ab2da] + +2010-04-30 Todd C. Miller + + * plugins/sudoers/Makefile.in, plugins/sudoers/audit.c, + plugins/sudoers/bsm_audit.c, plugins/sudoers/bsm_audit.h, + src/audit.c, src/bsm_audit.c, src/bsm_audit.h: + Move audit sources into the sudoers plugin dir; the driver does not + use them. + [50ec36422cd0] + + * compat/getline.c, compat/mksiglist.c, compat/nanosleep.c, + compat/strdup.c, compat/strndup.c, plugins/sample/sample_plugin.c, + plugins/sudoers/boottime.c, plugins/sudoers/getdate.c, + plugins/sudoers/match.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/timestr.c, plugins/sudoers/vasgroups.c, src/alloc.c, + src/atobool.c, src/audit.c, src/lbuf.c, src/list.c, src/sesh.c, + src/term.c, src/ttysize.c: + Use angle brackets when including headers that can only be found + when an -I flag is specified. The files in the compat dir could get + away with double quotes here but I've converted all the source files + to use angle brackets for consistency. + [9e30a8fc6d4b] + + * plugins/sudoers/Makefile.in: + Add missing -I$(top_srcdir) to CPPFLAGS so includes in the compat + dir can be found when building outside the source tree. + [1150934b79dd] + + * plugins/sudoers/Makefile.in: + Clean up links in distclean + [78595028be8b] + + * plugins/sudoers/Makefile.in: + Hack around VPATH semantic differences by symlinking files we need + from ../../src into the current directory and build those. A better + fix would be to either make a .a or .la file with those files in it + or simply use a single, flat, Makefile instead of per-subdirs + Makefiles. + [892c332d3f05] + + * plugins/sudoers/Makefile.in, src/Makefile.in, src/fmt_string.c: + fmt_string is used by the sudoers plugin too so do not include + sudo.h (which is not really needed here anyway) + [231c35e3941f] + + * compat/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Fix building with non-BSD versions of make such as GNU make. + Requires VPATH support, which should be in any non-neolithic make. + [dc174f135919] + + * configure, configure.in, plugins/sudoers/Makefile.in, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/sudoers.c, + src/Makefile.in: + Re-enable bsm audit. Currently auditing is done within the sudoers + plugin itself. If possible, this should really be done in the main + driver but we don't presently have the needed data to do that. This + will be re-evaluated when Linux audit support is added. + [1d05a3236bfe] + + * compat/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Remove extraneous $srcdir and use more .c.lo and .c.o rules instead + of explicit rules in the dependency. + [88f80efd25f0] + + * plugins/sudoers/visudo.c: + Fix mismerge; alias_remove_recursive() now returns int + [6257a4849641] + +2010-04-29 Todd C. Miller + + * plugins/sudoers/visudo.c: + Fix a crash when checking a sudoers file that has aliases that + reference themselves. Based on a diff from David Wood. + [545d194484a7] + + * src/script.c: + Print signal info after restoring the tty mode, not before. + [a68618e67435] + + * src/script.c: + Defer call to alarm() until after we fork the child. Pass correct + pid to terminate_child() If the command exits due to signal, set + alive to false like we do when it exits normally. Add missing + check for errpipe[0] != -1 before using it in FD_ISSET + [22f0a1549391] + +2010-04-28 Todd C. Miller + + * plugins/sudoers/boottime.c: + Use 1/0 instead of TRUE/FALSE so we don't need sudoers.h + [0e627170c6e8] + +2010-04-27 Todd C. Miller + + * src/Makefile.in: + Simplify dependencies by using .c.o and .c.lo rules. + [6abcaef5d1ac] + + * configure, configure.in, plugins/sudoers/Makefile.in, + src/Makefile.in: + Substitute in @PROGS@ into src/Makefile to add sesh + [cc46d3b6208f] + +2010-04-26 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Add back calls to log_denial() if sudoers does not allow the + command. + [9783316207f0] + + * plugins/sudoers/sudoers.c: + Pass in correct pwflag for list and validate. + [973dd56d4b81] + + * plugins/sudoers/env.c: + Add missing check for NULL in validate_env_vars + [1d6eb6957824] + + * src/Makefile.in: + Add sudo_noexec.la to "all" target, otherwise it only gets built at + install time. + [644a9694d2ef] - * Makefile.in: - Add missing $(srcdir) to sudo.man.in target - [2bd89f6ca9f3] + * plugins/sudoers/sudoers.c: + Only set sudo_user.env_vars if the env_add list is empty. + [fccdf6f0e0e2] - * Makefile.in: - Do not rely on BSD make's $> - [cb328b82cb92] + * plugins/sudoers/sudoers.c: + Set sudo_user.env_vars so that environment variables specified on + the command line get logged correctly. + [9b51012c491e] - * configure, configure.in: - Set timedir to /var/db/sudo for darwin to match Apple sudo's - location - [860c7f1b001f] + * plugins/sudoers/env.c, plugins/sudoers/logging.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Re-enable environment files and setting environment variables on the + command line. + [5662d5645dbd] -2010-06-16 Todd C. Miller +2010-04-24 Todd C. Miller - * Makefile.in, configure, configure.in: - Move aix.o from SUDO_OBJS to COMMON_OBJS - [f8a9bdf346c1] + * plugins/sudoers/check.c: + Fix typo in last commit (ifndef vs ifdef) Make sure we pass ctime() + a pointer to time_t as tv_sec in struct timeval may be long. + [4de0c46e788e] - * config.h.in, configure, configure.in, defaults.c, iolog.c, - sudoreplay.c: - Check for zlib.h in addition to libz. - [fb77e44d5196] + * plugins/sudoers/check.c: + Don't stash ctime in on-disk tty ticket info for now; on many + (most?) systems the ctime is updated when the tty is written to. + Once I have a better idea of what systems do not update ctime on + ttys (and have a way to test for this) the ctime stash will be + conditionally re-enabled. + [a90eeec0f648] - * 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] +2010-04-23 Todd C. Miller - * sudo.h: - Add missing prototypes for aix_setauthdb and aix_restoreauthdb - [8bc2af6d4e17] + * MANIFEST, Makefile.in: + Add back "dist" target, this time using a MANIFEST file + [29277c05499f] * Makefile.in: - Comment out rules to build .man.in and .cat files unless --with- - devel - [81d6726a19ab] + Remove Makefile in distclean target + [83d695f4f450] + + * Makefile.in, src/Makefile.in: + Update clean and cleandir targets + [ad7b2afeb9c1] + + * include/fileops.h, plugins/sudoers/sudoers.h, src/fileops.c, + src/sudo.h: + Move fileops.c defines and prototypes to filesops.h + [4545e9b6892d] + + * plugins/sudoers/check.c: + Lock the tty timestamp when writing. We shouldn't have to lock when + reading since the file is updated via a single write system call. + [0c7276f02696] + +2010-04-22 Todd C. Miller + + * plugins/sudoers/alias.c, plugins/sudoers/check.c, + plugins/sudoers/defaults.c, plugins/sudoers/find_path.c, + plugins/sudoers/getspwuid.c, plugins/sudoers/gettime.c, + plugins/sudoers/goodpath.c, plugins/sudoers/interfaces.c, + plugins/sudoers/iolog.c, plugins/sudoers/ldap.c, + plugins/sudoers/logging.c, plugins/sudoers/match.c, + plugins/sudoers/nonunix.h, plugins/sudoers/parse.c, + plugins/sudoers/pwutil.c, plugins/sudoers/redblack.c, + plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/timestr.c, plugins/sudoers/tsgetgrpw.c, + plugins/sudoers/vasgroups.c, plugins/sudoers/visudo.c: + Convert to ANSI C function declarations + [9c45def57cf7] + + * plugins/sudoers/sudoers.h: + Remove extraneous bits and classify by source file. + [e8ea9f109ebb] + + * include/compat.h: + Add timercmp macro for systems without it + [d3bf87b1d08e] + + * plugins/sudoers/boottime.c, plugins/sudoers/check.c, + plugins/sudoers/sudoers.h: + get_boottime() now fills in a timeval struct + [3573c3f44e11] - * aix.c, pwutil.c, set_perms.c, sudo.h: - Fix AIX compilation problems. - [7d95f73eca42] + * plugins/sudoers/check.c: + Store info from stat(2)ing the tty in the tty ticket when tty + tickets are in use. On most systems, this closes the loophole + whereby a user can log out of a tty, log back in and still have the + timestamp be valid. + [53380f9f5242] - * sudo.c: - Cast isalnum() arg to unsigned char. - [5fff9a81af00] + * config.h.in, configure.in: + Add timespec2timeval and use it when getting ctime/mtime + [4cb7f7caec2c] - * WHATSNEW: - Add Linux audit support. - [e59e0670ba79] +2010-04-20 Todd C. Miller - * 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] + * plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/set_perms.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/testsudoers.c: + Convert perm setting to push/pop model; still needs some work Use + the stashed runas groups instead of using getgrouplist() Reset perms + to the initial value on error + [09c072ebde8b] - * sudo.c: - Add missing braces that broke -i mode. - [7fe124b078ec] + * config.h.in, configure.in: + fix ctim_get and mtim_get macros + [58773dc1e360] - * linux_audit.c: - Fix linux_audit_command() return value - [0c582476181c] + * config.h.in, configure, configure.in, include/compat.h, + plugins/sudoers/check.c, plugins/sudoers/gettime.c, + plugins/sudoers/sudoers.h, plugins/sudoers/visudo.c, src/fileops.c: + Use timeval directly instead of converting to timespec when dealing + with file times and time of day. + [a0ce1ae00a67] -2010-06-15 Todd C. Miller + * plugins/sudoers/Makefile.in: + Don't like sudoreplay with libsudoers.la due to a yacc symbol + conflict. + [f1a59cc63a15] - * Makefile.in, linux_audit.c, linux_audit.h: - Add Linux audit support. - [b207dc9960de] +2010-04-18 Todd C. Miller -2010-06-16 Todd C. Miller + * configure, configure.in: + Darwin >= 9.x has real setreuid(2) + [7ec942a64275] - * INSTALL, audit.c, bsm_audit.c, config.h.in, configure, configure.in, - logging.h, selinux.c: - Add Linux audit support. - [26ae31d7ff93] +2010-04-17 Todd C. Miller -2010-06-15 Todd C. Miller + * plugins/sudoers/env.c, plugins/sudoers/sudoers.h: + Ansify env.c + [f58551bad10a] - * sudoreplay.c, sudoreplay.cat, sudoreplay.man.in, sudoreplay.pod: - Sync sudoreplay with trunk - [65b780cccfa5] + * plugins/sudoers/env.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Remove remaining references to the environ pointer. + [96faa530816a] - * exec_pty.c: - Remove an XXX - [8304ac649241] +2010-04-16 Todd C. Miller - * 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] + * config.h.in, configure, configure.in, plugins/sudoers/env.c: + Don't change the environ directly in the sudoers plugin + [6db48ed3f7e0] - * ldap.c, parse.c: - Better prefix determination now that we can't rely on len==0 to tell - the beginning on an entry. - [32f1875d9605] +2010-04-15 Todd C. Miller - * 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] + * plugins/sudoers/sudoers.c: + Fix typo + [4aa452b07f8f] - * configure, configure.in: - Remove duplicate setsid check - [7712d6d52da1] + * plugins/sudoers/alias.c: + Fix use after free in error message when a duplicate alias exists. + [ce1d2812ee34] - * Makefile.in, config.h.in, configure, configure.in, exec_pty.c, - logging.c, missing.h, setsid.c: - Move setsid emulation into setsid.c - [f24743c9e4e9] +2010-04-14 Todd C. Miller - * exec_pty.c, logging.c, selinux.c, sudo.c, tgetpass.c: - Check for dup2() failure. - [b1b6ba761b61] + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + src/parse_args.c: + Add a "noninteractive" boolean to the settings passed in to the + plugin's open function that is set when the user specifies the -n + flag. + [68f8d9d6d4d0] - * config.h.in, configure, configure.in: - Remove dup2 check, it is not optional. - [cfbe5f3b5956] + * config.h.in, configure, configure.in, plugins/sudoers/env.c: + Add workaround for the lack of the environ pointer on Mac OS X in + dlopen()ed modules. Use of environ in the sudoers plugin should + ultimately be removed but this will do for the moment. + [80c61647434f] -2010-06-14 Todd C. Miller + * plugins/sudoers/visudo.c: + Set errorfile to the sudoers path if we set parse_error manually. + This prevents a NULL dereference in printf() when checking a sudoers + file in strict mode when alias errors are present. + [45e249ca99f7] - * WHATSNEW: - Add mbr_check_membership support and SELinux fixes - [af1936a7cf2f] + * plugins/sudoers/sudoers.c: + Main sudo no longer print "unable to execute" on exec failure so do + it here. + [50aaf62b43b5] - * Makefile.in: - Sync SRCS and DISTFILES with reality - [0971b5dcb1be] +2010-04-13 Todd C. Miller - * INSTALL: - Update OS specific notes. Delete some really ancient ones and move - older ones to the end of the list. - [872dd8b437a8] + * src/script.c: + Use a pipe to pass back errno to the parent if execve() fails. If we + get an error in script_child(), kill the command and exit. + [dc3bf870f91b] - * README: - Bump for sudo 1.7.3 Merge some changes from trunk - [a3088c75bf22] + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + src/parse_args.c, src/sudo.c: + Handle plugin's open function returning -2 (usage error). + [aadf900c1de8] - * selinux.c, sudo.c: - Call selinux_restore_tty() as part of cleanup() so it gets called - from error()/errorx() - [0197c07d4c1e] + * src/script.c: + If execve() fails, leave it to the plugin to print an error string. + [e25748f2d5b9] - * compat.h: - No longer use SA_NOCLDSTOP - [73ca654cd3f8] + * src/script.c: + If execve fails in logging mode, pass the errno directly to the + grandparent on the backchannel and exit. The immediate parent will + get SIGCHLD and try to report that status but its parent will no + longer be listening. It would probably be cleaner to pass this over + a pipe in script_child(). + [cb122acc81a8] - * interfaces.h, match.c: - Move union sudo_in_addr_un into interfaces.h - [c84bda7c332a] + * plugins/sudoers/sudoers.c: + Don't override rval with results of check_user() unless it failed. + [46fb7e87ac7d] - * pathnames.h.in: - Update copyright year - [94871f44206b] +2010-04-12 Todd C. Miller - * HISTORY, LICENSE, aix.c, alias.c, alloc.h, boottime.c, bsm_audit.h, - compat.h, defaults.c, defaults.h, env.c, fileops.c, find_path.c, - gettime.c, gram.y, history.pod, lbuf.h, license.pod, logging.c, - match.c, missing.h, nanosleep.c, parse.h, set_perms.c, - sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod, - sudoreplay.c, term.c, tgetpass.c, toke.l, visudo.c, visudo.cat, - visudo.man.in, visudo.pod: - Update copyright year - [4cfb47c799b8] + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Fix typo + [ccd0b693f3da] - * Makefile.in: - Remove varsub as part of clean - [61f04a21b0bb] + * src/parse_args.c: + NULL-terminate env_add + [2c534368a0c3] - * match.c: - Quiet a compiler warning. - [06d8cfe916c8] +2010-04-11 Todd C. Miller - * getdate.c, getdate.y: - Quiet a compiler warning. - [473d2b7d44a1] + * src/sudo.c: + Call the I/O log open function before the I/O version function. + [e88bf898990b] - * ldap.c, sudo.h: - Make the remaining functions in ldap.c static - [ba555565b30a] + * plugins/sudoers/iolog.c: + Remove io_conv and just use sudo_conv + [a280052468eb] - * ldap.c: - Make private functions static. Diff from Joachim Henke - [1603035b1863] + * plugins/sudoers/set_perms.c: + Fix set/restore perms for systems w/o setresuid + [4160517f6666] - * 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] +2010-04-10 Todd C. Miller -2010-06-12 Todd C. Miller + * plugins/sudoers/check.c, plugins/sudoers/logging.c, + plugins/sudoers/parse.c, plugins/sudoers/set_perms.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h: + Primitive set/restore permissions. Will be replaced by a push/pop + model. + [aae102290866] - * 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] + * src/script.c: + Only need to take action on SIGCHLD in parent if no I/O logger. If + there is an I/O logger we will receive ECONNRESET or EPIPE when we + try to read from the socketpair. + [e1e4560401f6] -2010-06-11 Todd C. Miller +2010-04-09 Todd C. Miller - * configure, configure.in, sudo.c, sudo_usage.h.in: - Print configure args with verbose version information. - [ca4a5fcf0af8] + * compat/memrchr.c, doc/sudoers.cat, doc/sudoers.man.in, + doc/sudoers.pod, plugins/sudoers/find_path.c: + Merge fb4d571495fa from the 1.7 branch to trunk. + [c8fb424ad4d2] + +2010-04-08 Todd C. Miller + + * src/script.c: + Don't set SA_RESTART when registering SIGALRM handler. Do set + SA_RESTART when registering SIGWINCH handler. + [173472b76525] + + * doc/Makefile.in: + Add dev targets for *.man.in and *.cat that don't specfify the + $(srcdir) prefix. + [b62f425da2e4] + + * src/script.c: + If log_input or log_output returns false, terminate the command. + [074f4c0c34a0] + + * src/script.c: + Better signal handling. Instead of using a single variable to store + the received signal, use an array so we can't lose a signal when + multiple are sent. Fix process termination by SIGALRM in non-I/O + logger mode. Fix relaying terminal signals to the child in non-I/O + logger mode. + [7a4723aca99d] + + * src/script.c: + Fix a race between when we get the child pid in the parent and when + the child process exits. The problem exhibited as a hang after a + short-lived process, e.g. "sudo id" when no IO logger was enabled. + [80bcc0aca70b] - * 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] +2010-04-07 Todd C. Miller -2010-06-10 Todd C. Miller + * doc/sudoers.cat, doc/sudoers.man.in, doc/sudoers.pod: + Add a note about the security implications of the fast_glob option. + [c37a92ab7c93] - * WHATSNEW: - Describe tty timestamp improvements - [136b0f832903] +2010-04-06 Todd C. Miller - * 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] + * config.h.in, configure, configure.in: + Fix up some AC_DEFINE descriptions and regen config.h.in + [f4655adc0db3] - * sudo.cat, sudo.man.in, sudoers.cat, sudoers.man.in: - regen - [c9fddd23c7e1] +2010-04-05 Todd C. Miller - * sudoers.pod: - Make this read a little bit better when passwd_timeout is 0. - [51644950823f] + * include/missing.h: + No longer check for strdup or strndup for LIBOBJ replacement. + [fdc764ee8109] - * Makefile.in: - Use the --file argument to config.status instead of setting - CONFIG_FILES - [fc2b42c60b5d] + * src/script.c: + Avoid installing signal handlers that are io-logger specific. Fixes + job control when no io logger is enabled. + [0853dd0906d4] - * sudo.man.pl, sudo.pod: - Attempt to handle a default password prompt timeout of zero more - gracefully. - [478b8e720993] + * doc/Makefile.in: + Only regen man pages from pod when configured with --with-devel + [ab1995f8103d] - * 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] +2010-04-04 Todd C. Miller - * exec.c, exec_pty.c, logging.c, mon_systrace.c, tgetpass.c: - Use SA_INTERRUPT in sa_flags - [3845c6637361] + * Makefile, Makefile.in, configure, configure.in: + Top-level Makefile.in. Nothing is currently substituted but this is + needed for separate build dirs. + [e80873cbd201] - * getdate.c, getdate.y, ldap.c, sudoreplay.c: - Silence some compiler warnings - [112ac65afd0c] + * compat/Makefile.in, doc/Makefile.in, plugins/sample/Makefile.in, + plugins/sudoers/Makefile.in, src/Makefile.in: + Fix out-of-tree builds + [59a35bef07b8] -2010-06-09 Todd C. Miller + * Merge + [386b848047e9] - * exec.c, exec_pty.c, sudo.c, sudo.h: - Implement background mode. If I/O logging we use pipes instead of a - pty. - [8d448eaf2aaa] + * doc/Makefile.in: + We always install sudoreplay in 1.8 + [ce52ba6617c9] - * compat.h, exec.c, exec_pty.c, mksiglist.c, strsignal.c, tgetpass.c: - Move compat definition of NSIG to compat.h - [cae72a4c9dec] +2010-04-03 Todd C. Miller - * tgetpass.c: - Ignore SIGPIPE for "sudo -S" - [c6595c8527c4] + * compat/siglist.in: + SIGPOLL is sometimes the same as SIGIO (like on HP-UX) + [6d69e1b05faf] - * tgetpass.c: - Properly handle TGP_ECHO again. Print a newline if the user - interrupted password input. - [15acbe4fb535] +2010-04-02 Todd C. Miller - * exec_pty.c: - Use POSIX tcgetpgrp() instead of BSD TIOCGPGRP ioctl - [dd041fc9554c] + * configure, configure.in: + No need to provide strdup() or strndup(), sudo uses estrdup() and + estrndup() + [57ec23b72958] + +2010-04-04 Todd C. Miller + + * plugins/sudoers/iolog.c, plugins/sudoers/sudoers.c: + Free str after using it in the version method. Use sudo_conv, not + io_conv since we don't have the IO conversation function pointer in + the I/O version method anymore now that io_open is delayed. + [f2ed132adeb0] + +2010-04-02 Todd C. Miller + + * compat/Makefile.in, compat/mksiglist.c, compat/mksiglist.h, + compat/siglist.in: + Add license to mksiglist.c and note that the bits from pdksh are + public domain + [d8121a2467e8] + + * compat/Makefile.in: + Fix LIBOBJDIR vs. srcdir wrt the siglist bits + [164160148421] + + * plugins/sudoers/Makefile.in: + Add sudoreplay testsudoers and visudo to clean target + [138a17e51c0c] + + * compat/Makefile.in, compat/mksiglist.c, compat/mksiglist.h, + compat/siglist.in, compat/strsignal.c, configure, configure.in, + include/missing.h, src/script.c: + Create our own sys_siglist for systems without it for use by + strsignal() + [2e5da011ebc3] + + * compat/Makefile.in: + Remove duplicate $(LIBOBJDIR) + [adf9abc9432f] + +2010-04-01 Todd C. Miller + + * plugins/sudoers/sudoers.c, src/sudo.c, src/sudo_edit.c: + Main sudo should not block signals; the plugin should do this in + check_policy. + [3f3736a7c5ed] + +2010-03-31 Todd C. Miller + + * src/script.c: + Fix a sizeof(ptr) vs. sizeof(*ptr) + [aa1bcf5afcce] + + * src/script.c: + Unlike most operating systems, HP-UX select() is not interrupted by + SIGCHLD when the signal is registered with SA_RESTART. If we clear + SA_RESTART when calling sigaction() for SIGCHLD we get the expected + behavior and the code in the select() loops already handles EINTR + correctly. + [9eba0115e35a] + + * compat/getprogname.c: + progname should be const + [130228f062b7] + + * plugins/sudoers/Makefile.in: + Move --tag=disable-static to when we link sudoers.la, not when we + install. + [ceb5e6c3b78b] + + * src/load_plugins.c: + Load the sudoers I/O plugin by default too now that it is hooked up. + [ea38befd0742] + +2010-03-30 Todd C. Miller + + * src/pty.c: + It looks like AIX doesn't need to push STREAMS modules for ptys. + [22da618ba0a1] -2010-06-08 Todd C. Miller +2010-03-28 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] + * src/parse_args.c, src/sudo.c: + Delay calling the I/O plugin open function until the policy plugin + returns success. + [f3297c325b48] - * 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] +2010-03-27 Todd C. Miller - * 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] + * plugins/sudoers/Makefile.in, plugins/sudoers/iolog.c, + plugins/sudoers/set_perms.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Add back io logging (transcript) support. Currently, the open + function runs too early and it is not possible to use the io module + independently of the policy module. + [9bd932f66226] - * 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] + * plugins/sudoers/set_perms.c: + Comment out dead code; will be removed when set_perms is rewritten. + [af7a995284f8] - * 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] +2010-03-23 Todd C. Miller - * 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] + * plugins/sudoers/sudoers.c: + Fix off by one error when allocating user_groups. + [6281fcf9c3bb] - * 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] +2010-03-22 Todd C. Miller - * set_perms.c: - Fix typo - [0f677fcdde04] + * configure, configure.in, plugins/sudoers/Makefile.in: + Add REPLAY_LIBS for sudoreplay and add -lrt to it on Solaris. + [fbce3e9eda3a] + + * plugins/sudoers/sudoers.c: + Fix typo in preserve groups case + [1fd72024fb5a] + + * plugins/sudoers/sudoers.c: + In command_info it is "runas_groups" not "groups". + [5c64dce4f285] + + * src/sudo.c: + Fix iteration over runas_groups list. + [b3c45a0cd643] + + * configure, configure.in, plugins/sudoers/env.c, + plugins/sudoers/match.c, src/script.c: + Merge 5177a284b9ff 549f8f7c2463 88f3181692fe from 1.7 branch. + [a8108a0776c2] + + * compat/getgrouplist.c: + getgrouplist(3) for those without it + [4ab4d21e3b16] + + * plugins/sudoers/sudoers.c: + Set preserve_groups or groups list in command_info + [1266119ad654] + + * src/sudo.c: + Fix setting of groups list + [e75315e40bd4] + + * config.h.in, configure, configure.in, include/compat.h, + include/missing.h: + Add checks for getgrset and getgrouplist and use replacement + getgrouplist if the system doesn't support it. + [a62b8ba50863] + + * src/parse_args.c: + Pass in preserve_groups when the -P flag is specified as per the + design + [7420c5d15474] + + * plugins/sudoers/sudoers.c: + Check preserve_groups and ignore_ticket args with atobool instead of + assuming they are true if present. + [71c905702697] + +2010-03-21 Todd C. Miller + + * plugins/sudoers/Makefile.in, plugins/sudoers/error.c, + plugins/sudoers/plugin_error.c: + Rename plugin-specific error.c to plugin_error.c Wire up visudo, + sudoreplay and testsudoers in the build + [9d581d5fa4d4] + + * src/Makefile.in, src/term.c: + term.c does not needto include sudo.h + [f6683cdcd2dd] + + * TODO, doc/sudo_plugin.cat, doc/sudo_plugin.man.in, + doc/sudo_plugin.pod: + Document the -2 return in the check_policy section too + [e9cb4c34bbcf] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + src/parse_args.c, src/sudo.c, src/sudo.h: + Fix the -s and -i flags and add support for the "implied_shell" + option. If the user does not specify a command, sudo will now pass + in the path to the user's shell and set impied_shell=true. The + plugin can them either check the command normally or return -2 to + cause sudo to print a usage message and exit. + [bf889c38f229] + +2010-03-19 Todd C. Miller + + * config.h.in, configure, configure.in, src/load_plugins.c: + Bring back SUDOERS_PLUGIN but add .dylib -> .so conversion for + Darwin where libraries end in .dylib but modules end in .so + [2c56aaa38e21] + + * plugins/sudoers/parse.c: + Better prefix determination now that we can't rely on len==0 to tell + the beginning on an entry. + [622bf18179e9] + + * plugins/sudoers/ldap.c: + display_bound_defaults() stub should return 0, not 1 since it is a + count, not a boolean. + [0327a6c3d55d] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document progname in settings + [42031d56a2e3] + + * compat/getprogname.c, include/compat.h, + plugins/sample/sample_plugin.c, plugins/sudoers/sudoers.c, + src/parse_args.c, src/sudo.c: + Rewrite compat/getprogname.c and add setprogname(). The progname is + now passed to the plugin via the settings array. + [25d8663e6006] + + * configure, configure.in, plugins/sudoers/Makefile.in: + Fix --with-ldap + [b64b633f426d] + + * plugins/sudoers/sudo_nss.c: + Add missing whitespace for Runas and Command-specific defaults + [65f4ddf5545e] + + * plugins/sudoers/ldap.c, plugins/sudoers/parse.c, + plugins/sudoers/sudo_nss.c: + Use embedded newlines in lbuf instead of multiple calls to + lbuf_print. + [eed3af9cc3e1] + + * src/lbuf.c: + Add support for embedded newlines. + [e11f79b18deb] + +2010-03-18 Todd C. Miller + + * compat/getprogname.c: + If system doesn't support getprogname or __programe and we are + building a shared object don't bother with Argc/Argv, just return + "sudo" + [aebde9062be7] + + * config.h.in, configure, configure.in, src/load_plugins.c: + Hard-code sudoers.so instead of using SUDOERS_PLUGIN since libtool + appears to always install a shared object with the .so suffix. + [f9bbd0c0e9d3] + + * compat/Makefile.in, configure, configure.in, + plugins/sample/Makefile.in, plugins/sudoers/Makefile.in, + src/Makefile.in: + Play more nicely with libtool and let it build libreplace (was + libmissing) for us. + [a4c6ebb2495c] + + * include/missing.h: + Include stdarg.h for va_list rather than requiring all consumers of + missing.h to include stdarg.h themselves. + [37382df948de] + + * include/lbuf.h, plugins/sudoers/auth/sudo_auth.c, + plugins/sudoers/check.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, src/lbuf.c, + src/parse_args.c: + Pass in output function to lbuf_init() instead of writing to stdout. + A side effect is that the usage info can now go to stderr as it + should. + [6d261261a072] + +2010-03-17 Todd C. Miller + + * include/lbuf.h, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, src/lbuf.c, + src/parse_args.c, src/sudo.c: + Use number of tty columns that is passed in user_info instead of + getting it directly in the lbuf code. + [8a16635c2638] + + * plugins/sudoers/alias.c, plugins/sudoers/auth/dce.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/sia.c, plugins/sudoers/auth/sudo_auth.h, + plugins/sudoers/check.c, plugins/sudoers/defaults.c, + plugins/sudoers/defaults.h, plugins/sudoers/env.c, + plugins/sudoers/getdate.c, plugins/sudoers/getdate.y, + plugins/sudoers/gram.c, plugins/sudoers/gram.y, + plugins/sudoers/interfaces.h, plugins/sudoers/logging.c, + plugins/sudoers/logging.h, plugins/sudoers/match.c, + plugins/sudoers/mon_systrace.h, plugins/sudoers/parse.c, + plugins/sudoers/parse.h, plugins/sudoers/pwutil.c, + plugins/sudoers/redblack.c, plugins/sudoers/redblack.h, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.h, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/sudoreplay.c, plugins/sudoers/testsudoers.c, + plugins/sudoers/timestr.c, plugins/sudoers/toke.c, + plugins/sudoers/toke.l, plugins/sudoers/tsgetgrpw.c, + plugins/sudoers/visudo.c: + Kill __P in sudoers + [63601e6cb171] + + * config.h.in, configure, configure.in, src/load_plugins.c: + Set the sudoers plugin name in configure so we get the extension + right. + [edad89924cd1] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document lines/cols in user_info + [a808872394f3] + + * src/Makefile.in, src/sudo.c, src/sudo.h, src/ttysize.c: + Add tty size to user info + [23f3d27e77a7] + + * src/script.c: + Use TIOCGSIZE/TIOCSSIZE instead of TIOCGWINSZ/TIOCSWINSZ + [a2208dd09051] + +2010-03-16 Todd C. Miller + + * plugins/sudoers/sudoers.c: + Kill dead code Add missing sigsetjmp in sudo_policy_invalidate Error + out if we fail to lookup the user's name that is passed in + [e4e3728ed482] + + * plugins/sudoers/error.c: + Pass the error value back via siglongjmp. + [667b8ad575ce] + + * plugins/sudoers/check.c: + Use conversation function for lecture. + [1ab4719f509b] + + * plugins/sudoers/check.c: + Don't update ticket file if verify_user returns FALSE. + [2bbc46a39a2b] + +2010-03-15 Todd C. Miller + + * plugins/sudoers/sudoers.c, src/sudo.c: + Wire up invalidate and validate methods for sudoers + [c0630c7bca47] + + * plugins/sudoers/check.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h: + Add support for -k flag with a command. + [edad239b098b] + + * src/parse_args.c: + Allow -k to be specified with a command. + [43a45add9974] + + * plugins/sudoers/sudoers.c: + Wire up policy_list + [27cc35699eca] + + * plugins/sudoers/error.c: + Add newline at the end of message and space after the colon in + warning message + [5a591aa8e744] + + * plugins/sudoers/auth/sudo_auth.c: + Add missing newline after pass password warning + [337dba3870a7] + + * plugins/sudoers/sudoers.c: + Set user_groups and user_ngroups based on user_info + [61bee85128c8] + + * plugins/sudoers/error.c: + Make this compile + [7041c441e1c8] + + * plugins/sudoers/error.c, plugins/sudoers/sudoers.c: + Make _warning in error.c use the conversation function and remove + commented out warning/warningx in sudoers.c. + [7c9b09024b63] + + * plugins/sudoers/logging.c: + Use siglongjmp() in log_error for fatal errors + [b50e26f1c73f] + + * plugins/sample/Makefile.in, plugins/sudoers/Makefile.in: + Quiet a libtool warning + [b2331fb006bc] + + * Makefile: + Build sudoers plugin + [5cdf06e66978] + + * plugins/sudoers/gram.c, plugins/sudoers/gram.y: + Use warningx in yyerror() so the conversation function gets used + when built as part of sudoers. + [85f964215eef] + +2010-03-14 Todd C. Miller + + * plugins/sudoers/auth/pam.c: + Rename sudo_conv to conversation to avoid a namespace conflict. + [1ad359d36be9] + + * plugins/sudoers/Makefile.in, plugins/sudoers/alias.c, + plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c, + plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c, + plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c, + plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c, + plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h, + plugins/sudoers/check.c, plugins/sudoers/defaults.c, + plugins/sudoers/env.c, plugins/sudoers/error.c, + plugins/sudoers/find_path.c, plugins/sudoers/getspwuid.c, + plugins/sudoers/goodpath.c, plugins/sudoers/gram.c, + plugins/sudoers/gram.y, plugins/sudoers/interfaces.c, + plugins/sudoers/ldap.c, plugins/sudoers/logging.c, + plugins/sudoers/match.c, plugins/sudoers/mon_systrace.c, + plugins/sudoers/parse.c, plugins/sudoers/pwutil.c, + plugins/sudoers/redblack.c, plugins/sudoers/set_perms.c, + plugins/sudoers/sudo_nss.c, plugins/sudoers/sudoers.c, + plugins/sudoers/sudoers.h, plugins/sudoers/testsudoers.c, + plugins/sudoers/toke.c, plugins/sudoers/tsgetgrpw.c, + plugins/sudoers/vasgroups.c, plugins/sudoers/visudo.c: + Initial bits of sudoers plugin; still needs work. + [af2a2c59a952] -2010-06-07 Todd C. Miller + * config.h.in: + Add HAVE_STRDUP and HAVE_STRNDUP + [50a3c0dd510f] - * sudo.h: - Rename pty.c -> get_pty.c - [39137dcc4420] + * compat/Makefile.in, configure, configure.in: + Build libmissing in two flavors (one PIC one non-PIC) and link with + the appropriate one. + [b62f411a4c18] - * iolog.c: - Add #define for maximum session id - [2a487437f013] + * Makefile, compat/fnmatch.c, compat/glob.c, compat/nanosleep.c, + compat/utimes.c, plugins/sample/Makefile.in, src/Makefile.in: + Build libmissing in two flavors (one PIC one non-PIC) and link with + the appropriate one. + [e1e04972b5fe] - * 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] +2010-03-13 Todd C. Miller - * Makefile.in, configure, configure.in, get_pty.c, pty.c: - Rename pty.c -> get_pty.c - [c0e5270bb28a] + * include/missing.h: + Add strdup and strndup and fix strsignal + [c159babe2896] - * aclocal.m4, configure, configure.in: - Fix --without-iologdir - [dcd6c5907b10] +2010-03-12 Todd C. Miller -2010-06-06 Todd C. Miller + * compat/strdup.c, compat/strndup.c, configure, configure.in, + plugins/sample/Makefile.in, src/Makefile.in: + Add strdup and strndup to compat + [25c9fd399a4d] - * 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] + * plugins/sample/sample_plugin.c: + Need to include compat.h before missing.h + [c94f7aad380f] -2010-06-05 Todd C. Miller + * compat/strsignal.c: + Must check HAVE_DECL_SYS_SIGLIST == 1 (not just if defined) since if + it doesn't exist configure will set it to 0. + [384580566389] - * 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] + * compat/glob.c: + Fix botched ANSI C coversion of globexp2() + [4a344b8cbe49] -2010-06-04 Todd C. Miller + * configure, configure.in: + Remove redundant getgroups check + [0b16ec210c81] - * tgetpass.c: - Do signal setup after turning off echo, not before. If we are using - a tty but are not the foreground pgrp this will generate SIGTTOU so - we want the default action to be taken (suspend process). Use an - array for signals received instead of a single variable so we don't - lose any when there are multiple different signals. - [de356064ea01] + * configure, configure.in, src/lbuf.c, src/script.c, src/term.c: + Require either termios or termio, no more sgtty. + [9b2fa2f17a1c] - * defaults.h, lbuf.h, sudo.h: - Reorg function prototypes a bit - [5c40f58bb28e] + * compat/strsignal.c, config.h.in, configure, configure.in: + Change the sys_siglist check to use AC_CHECK_DECLS and also check + for _sys_siglist and__sys_siglist + [2e078fed2408] - * Makefile.in, parse_args.c, sudo.c, sudo.h, sudo_usage.h.in: - Move argument parsing into parse_args.c - [fad7b8737c12] +2010-03-11 Todd C. Miller - * 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] + * configure, configure.in, src/Makefile.in: + Change SUDO_LDFLAGS to SUDOERS_LDFLAGS and add SUDOERS_OBJS. We now + use SUDO_OBJS for the main driver as part of OBJS. + [9ae4a80a5ade] - * exec.c, iolog.c, missing.h, sudo_edit.c: - K&R fixes - [dad62986f2fe] + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Mention in the conversation function section that a newline is not + implicit. + [04a233b6c491] - * exec.c, pty.c, sudo.c, sudo.h, sudo_edit.c: - Log sudoedit sessions as well; adapted from trunk - [2c5d9695022b] + * include/compat.h: + Add definition of WCOREDUMP for systems without it. This is known + to work on AIX and SunOS 4, but may be incorrect on other systems + that lack WCOREDUMP. + [c85b3ce6b77d] - * configure: - regen - [9b319e89a6c4] - - * INSTALL, Makefile.in, WHATSNEW, aclocal.m4, configure, configure.in, - def_data.c, def_data.h, def_data.in, defaults.c, exec.c, gram.c, - gram.h, gram.y, iolog.c, parse.c, parse.h, pathnames.h.in, pty.c, - script.c, selinux.c, sudo.c, sudo.h, sudoers.cat, sudoers.man.in, - sudoers.pod, sudoreplay.c, sudoreplay.cat, sudoreplay.man.in, - sudoreplay.pod, term.c: - Merge I/O logging changes from trunk. Disabling I/O log support at - compile time does not currently work. Sudoedit is not yet hooked up - to I/O logging. - [968c2c74c69b] +2010-03-09 Todd C. Miller -2010-06-03 Todd C. Miller + * plugins/sample/sample_plugin.c, src/conversation.c: + conversation function no longer puts a newline at the end of info or + error messages. + [c534cae1ac4a] - * INSTALL, configure, configure.in: - Add --enable-warnings configure option - [19cf967c36d1] +2010-03-07 Todd C. Miller - * check.c, lbuf.h, script.c, sudo.c, sudo_nss.c: - Fix K&R compilation issues on HP-UX. - [c01a547cdcf8] + * src/script.c: + Use parent process group id instead of parent process id when + checking foreground status and suspending parent. Fixes an issue + when running commands under /usr/bin/time and others. + [564f528c3bb7] - * 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] +2010-03-06 Todd C. Miller - * 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] + * aclocal.m4: + transcript option is now --with not --enable + [0646fac4cf93] - * sudoers.pod: - Document per-command SELinux settings - [bbce5acad1be] + * plugins/sample/sample_plugin.c: + Add support to -u and -g flags Check fmt_string retval Add timeout + for debugging purposes + [cfefa4fa60b5] - * sudo.pod: - timestamp -> time stamp - [d7335ce6286f] + * src/script.c, src/sudo.c: + Wire up SIGALRM handler Set close on exec flag for child side of the + socketpair Fix signal handling when not doing I/O logging + [379581ec7272] - * tsgetgrpw.c: - Set close on exec flag in private versions of setpwent() and - setgrent(). - [954814bdbd56] + * src/sudo.c: + g/c unused SIGCHLD handler + [0afa03912dce] - * logging.c: - Make send_mail() take a printf-style argument list - [0783ad585062] + * src/fmt_string.c, src/parse_args.c, src/sudo.c: + Don't use emalloc() in fmt_string(); we want to be able to use it + from a plugin. + [ade64d368147] - * 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] + * include/list.h: + tq_remove not list_remove + [0e0e1fd5c31c] - * boottime.c: - Don't use TRUE/FALSE which may not be defined. - [8649bf22b3b2] + * configure, configure.in: + AUTH_OBJS should contain .lo files not .o files. + [c64c82c9d5a2] - * sudo.cat, sudo.man.in, sudo.pod: - Document new tty_ticket behavior - [0663e0390338] +2010-03-05 Todd C. Miller - * 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] + * src/parse_args.c: + Simplify conversion of command line args to name=value pairs. + [75ab127c6a94] - * check.c: - Store info from stat(2)ing the tty in the tty ticket when tty - tickets are in use. If the tty lives on a devpts (Linux) or devices - (Solaris) filesystem, stash the ctime in the tty ticket file, as it - is not updated when the tty is written to. This helps us determine - when a tty has been reused without the user authenticating again - with sudo. - [f9aec9ab9054] - - * boottime.c, check.c, sudo.h: - get_boottime() now fills in a timeval struct - [dbd2003659c0] + * plugins/sample/sample_plugin.c: + Handle NULL reply from conversation function + [6ce09b6cb204] -2010-06-02 Todd C. Miller + * compat/getline.c: + Don't depend on emalloc/erealloc + [73df09e2109f] - * check.c, compat.h, config.h.in, configure, configure.in, fileops.c, - gettime.c, sudo.h, sudo_edit.c, visudo.c: - Use timeval directly instead of converting to timespec when dealing - with file times and time of day. - [c85bf3e41839] + * plugins/sample/Makefile.in: + Use $(OBJS) instead of sample_plugin.lo + [2d995db9aa99] - * auth/pam.c: - Fix OpenPAM detection for newer versions. - [67f29a0703d0] + * plugins/sample/sample_plugin.c: + runas_user is in settings not user_info + [7ee12068bc57] - * vasgroups.c: - Sync with Quest sudo git repo - [2680ad9762c2] + * src/parse_args.c: + Fix a mismatch between sudo_settings and settings_pairs that causes + some settings to get the wrong values. + [b1bc6d81a65f] - * 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] +2010-03-04 Todd C. Miller - * README.LDAP: - Fix typos; from Quest Sudo - [cf258fc69f1a] + * src/Makefile.in, src/aix.c, src/alloc.c, src/atobool.c, src/error.c, + src/fileops.c, src/lbuf.c, src/list.c, src/pty.c, src/sesh.c, + src/sudo.c, src/sudo_edit.c, src/term.c, src/zero_bytes.c: + Convert to ANSI C + [d03b6e4a3b75] - * Makefile.in, configure.in: - Use value of SHELL from configure in Makefile - [08aaf12221d6] + * src/load_plugins.c: + Fix strlcpy() return value check. + [7cd66999a374] -2010-05-28 Todd C. Miller + * INSTALL, configure, configure.in: + No longer need to substitute in script.o and pty.o; I/O logging + support is always built. + [45250024c5dc] - * env.c: - Handle duplicate variables in the environment. For unsetenv(), keep - looking even after remove the first instance. For sudo_putenv(), - check for and remove dupes after we replace an existing value. - [086c6397d8cd] +2010-02-28 Todd C. Miller -2010-04-29 Todd C. Miller + * src/script.c: + Add fallback to /bin/sh when execve() fails with ENOEXEC. + [7684a15a1352] - * visudo.c: - Fix a crash when checking a sudoers file that has aliases that - reference themselves. Based on a diff from David Wood. - [5efc702a3b35] + * include/alloc.h, src/alloc.c: + Add estrndup() + [47621c83bed9] -2010-04-15 Todd C. Miller +2010-02-27 Todd C. Miller - * alias.c: - Fix use after free in error message when a duplicate alias exists. - [9eaac49bd22b] + * src/script.c, src/sudo.c: + Refactor script_execve() a bit so that it can be used in non-script + mode. Needs more cleanup. + [f09e022d547c] -2010-04-14 Todd C. Miller + * src/sudo.c: + Ignore empty entries in command_info list + [1eea9a8de21c] - * visudo.c: - Set errorfile to the sudoers path if we set parse_error manually. - This prevents a NULL dereference in printf() when checking a sudoers - file in strict mode when alias errors are present. - [b4eed2f0615d] + * include/list.h, src/list.c: + Add tq_remove + [40908a617cb2] -2010-04-12 Todd C. Miller + * src/conversation.c: + Pass timeout to tgetpass() + [9e66c918b771] - * TODO, sudoers.cat, sudoers.man.in, sudoers.pod: - Fix typo - [57198cae9cf5] + * Makefile: + Add ChangeLog target + [da4a39150838] -2010-04-09 Todd C. Miller + * README, WHATSNEW: + Bump version and update things slightly for sudo 1.8.0 + [4b73cc45e2d4] - * find_path.c: - Qualify the command even if it is in the current working directory, - e.g. "./foo" instead of just returning "foo". This removes an - ambiguity between real commands and possible pseudo-commands in - command matching. - [fb4d571495fa] + * configure, configure.in: + Sudo now requires an ANSI/ISO C compiler + [1e51f72e6964] + + * src/alloc.c, src/audit.c, src/error.c, src/lbuf.c, + src/sudo_noexec.c: + Convert to ANSI C + [5cbd315dbde8] + + * include/alloc.h, include/compat.h, include/error.h, include/lbuf.h, + include/list.h, include/missing.h: + Convert to ANSI C + [3f5016ff64f4] + + * compat/charclass.h, compat/closefrom.c, compat/fnmatch.c, + compat/fnmatch.h, compat/getcwd.c, compat/getline.c, + compat/getprogname.c, compat/glob.c, compat/glob.h, + compat/isblank.c, compat/memrchr.c, compat/mkstemp.c, + compat/nanosleep.c, compat/sigaction.c, compat/snprintf.c, + compat/strcasecmp.c, compat/strerror.c, compat/strlcat.c, + compat/strlcpy.c, compat/strsignal.c, compat/utime.h, + compat/utimes.c: + Convert to ANSI C + [0d635c85461c] + +2010-02-24 Todd C. Miller + + * src/sudo.c, src/tgetpass.c: + Make user_details extern so tgetpass can get at the uid and gid. Set + uid/gid to user before executing askpass program. Check environment + for SUDO_ASKPASS and use that if set. TODO: a way for the policy to + set the askpass program itself + [d33606396176] + + * src/sudo.c: + No longer need sudo_usage.h in sudo.c + [063e2946c382] + + * doc/sudo.cat, doc/sudo.man.in, doc/sudo.pod, doc/sudo_plugin.man.in, + doc/sudo_plugin.pod, src/Makefile.in, src/parse_args.c, + src/sudo_usage.h.in: + Document -D level command line flag which maps to the debug_level + setting. + [61f1e2ab3ac1] + + * doc/sudo_plugin.cat, doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Document debug_level in plugin doc. Still need to document the -D + flag in sudo itself. + [8c62daea3e9b] + +2010-02-21 Todd C. Miller + + * plugins/sample/sample_plugin.c: + include missing,h for vasprintf + [92503de49b39] + + * doc/Makefile.in, doc/plugin.pod, doc/sudo_plugin.cat, + doc/sudo_plugin.man.in, doc/sudo_plugin.pod: + Rename plugin.pod -> sudo_plugin.pod and wire into Makefile + [14cfb4775238] + + * plugins/sample/sample_plugin.c: + Need to include limits.h + [bda7f74343d2] + + * compat/glob.c: + No more sudo_getpw* + [232e52907634] + + * plugins/sample/Makefile.in, src/Makefile.in: + Add missing compat bits + [4843dd000e08] + + * compat/closefrom.c, compat/mkstemp.c, plugins/sample/Makefile.in: + compat files should not include sudo.h wire up compat in sample + plugin + [a175b8185e0f] + + * Makefile, configure, configure.in, doc/Makefile.in, src/Makefile.in: + Fix up compat dependencies. Fix distclean target in doc/Makefile.in + [57e49bc20857] -2010-04-07 Todd C. Miller + * configure, configure.in: + Fix typo + [333655e3d5fe] - * sudoers.cat, sudoers.man.in, sudoers.pod: - Add a note about the security implications of the fast_glob option. - [84f8097553d9] + * plugins/sample/sample_plugin.c: + Log input and output to temp files for proof of concept. + [ae1dfc34f7d6] - * memrchr.c: - Remove duplicate includes - [3e8d90f4c30f] + * Makefile, configure, configure.in, doc/Makefile.in: + Add doc Makefile.in and wire it up + [6a310443c87d] -2010-03-22 Todd C. Miller + * src/script.c: + Handle SIGSTOP in addition to SIGTSTP. Fixes a problem with + suspending a shell with the "suspend" builtint. + [3d65f182819a] - * 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] + * src/script.c: + In child, handle parent side of the pipe going away. + [a29c14d78cd9] -2010-03-09 Todd C. Miller + * src/script.c: + No longer need to check for explicit death of the child (process #2) + since if it dies we will get EPIPE from the socketpair. Fix a + sizeof() that was causing a spurious error. Convert SCRIPT_DEBUG to + sudo_debug. + [24c55dd4ff60] - * match.c: - When doing a glob match, short circuit if gl.gl_pathc is 0. From - Mark Kettenis. - [549f8f7c2463] + * src/sudo.c: + Make sudo_debug do a single vfprintf() which will result in a single + write call on most systems. Avoids problems with interleaved debug + printf from different processes. Also remove an extraneous error + case since recv() can't return a short read and add some more XXX. + [b37a8533ef1e] -2010-03-08 Todd C. Miller +2010-02-20 Todd C. Miller - * script.c: - Use parent process group id instead of parent process id when - checking foreground status and suspending parent. Fixes an issue - when running commands under /usr/bin/time and others. - [eac86126e335] + * src/script.c: + Fix uninitialized variable. + [e012a0a30890] - * env.c: - In setenv(), if the var is empty, return 1 and set errno to EINVAL - instead of returning EINVAL directly. - [d202091ec15e] + * src/Makefile.in: + Fix sudo install target + [1417fa4b4ab9] -2010-02-22 Todd C. Miller + * src/parse_args.c, src/sudo.c, src/sudo.h: + Wire up debug_level + [144fab289c73] - * match.c: - Check for pseudo-command by looking at the first character of the - command in sudoers instead of checking the user-supplied command for - a slash. - [88f3181692fe] + * src/Makefile.in: + Fix dependencies + [5170940af2ce] -2010-02-09 Todd C. Miller + * configure, configure.in: + Fix setting of plugin dir + [144eda170a72] + + * Makefile: + add clean targets + [d53f6f6f5c3a] + + * src/atobool.c: + Add missing source for sudo front end + [42487de9c489] + + * plugins/sample/Makefile.in, plugins/sample/sample_plugin.c: + Sample plugin demonstrating the sudo plugin API + [f1fd62d7644f] + + * Makefile, configure, configure.in, install-sh, pathnames.h.in, + plugins/sudoers/install-sh, src/Makefile.in, src/conversation.c, + src/fileops.c, src/fmt_string.c, src/load_plugins.c, + src/parse_args.c, src/pty.c, src/script.c, src/sudo.c, src/sudo.h, + src/sudo_plugin_int.h, src/sudo_usage.h.in, src/tgetpass.c, + sudo_usage.h.in: + Modular sudo front-end which loads policy and I/O plugins that do + most the actual work. Currently relies on dynamic loading using + dlopen(). See doc/plugin.pod for the plugin API. + [924f6eb2fbba] + + * doc/plugin.pod, include/sudo_plugin.h: + Sudo plugin API + [374ccbbd24ae] + + * compat/fnmatch.c, compat/glob.c, compat/nanosleep.c, + compat/utimes.c, plugins/sudoers/check.c, plugins/sudoers/gettime.c, + plugins/sudoers/match.c, plugins/sudoers/sudoreplay.c, + plugins/sudoers/testsudoers.c, plugins/sudoers/visudo.c, + src/fileops.c, src/sudo_edit.c: + Replace emul/include.h with compat/include.h to match new source + tree layout. + [7eccd10449a1] + + * src/lbuf.c: + Include missing.h for memrchr() proto + [03abd63a8a33] + + * HISTORY, LICENSE, Makefile.binary.in, Makefile.in, PORTING, + TROUBLESHOOTING, UPGRADE, aix.c, aixcrypt.exp, alias.c, alloc.c, + alloc.h, audit.c, auth/API, auth/afs.c, auth/aix_auth.c, + auth/bsdauth.c, auth/dce.c, auth/fwtk.c, auth/kerb4.c, auth/kerb5.c, + auth/pam.c, auth/passwd.c, auth/rfc1938.c, auth/secureware.c, + auth/securid.c, auth/securid5.c, auth/sia.c, auth/sudo_auth.c, + auth/sudo_auth.h, boottime.c, bsm_audit.c, bsm_audit.h, check.c, + closefrom.c, compat.h, compat/charclass.h, compat/closefrom.c, + compat/fnmatch.c, compat/fnmatch.h, compat/getcwd.c, + compat/getline.c, compat/getprogname.c, compat/glob.c, + compat/glob.h, compat/isblank.c, compat/memrchr.c, compat/mkstemp.c, + compat/nanosleep.c, compat/sigaction.c, compat/snprintf.c, + compat/strcasecmp.c, compat/strerror.c, compat/strlcat.c, + compat/strlcpy.c, compat/strsignal.c, compat/timespec.h, + compat/utime.h, compat/utimes.c, def_data.c, def_data.h, + def_data.in, defaults.c, defaults.h, doc/HISTORY, doc/LICENSE, + doc/PORTING, doc/TROUBLESHOOTING, doc/UPGRADE, doc/history.pod, + doc/license.pod, doc/sample.pam, doc/sample.sudoers, + doc/sample.syslog.conf, doc/schema.ActiveDirectory, + doc/schema.OpenLDAP, doc/schema.iPlanet, doc/sudo.cat, + doc/sudo.man.in, doc/sudo.man.pl, doc/sudo.pod, doc/sudoers.cat, + doc/sudoers.ldap.cat, doc/sudoers.ldap.man.in, doc/sudoers.ldap.pod, + doc/sudoers.man.in, doc/sudoers.man.pl, doc/sudoers.pod, + doc/sudoreplay.cat, doc/sudoreplay.man.in, doc/sudoreplay.pod, + doc/visudo.cat, doc/visudo.man.in, doc/visudo.pod, emul/charclass.h, + emul/fnmatch.h, emul/glob.h, emul/timespec.h, emul/utime.h, env.c, + error.c, error.h, fileops.c, find_path.c, fnmatch.c, getcwd.c, + getdate.c, getdate.y, getline.c, getprogname.c, getspwuid.c, + gettime.c, glob.c, goodpath.c, gram.c, gram.h, gram.y, history.pod, + include/alloc.h, include/compat.h, include/error.h, include/lbuf.h, + include/list.h, include/missing.h, ins_2001.h, ins_classic.h, + ins_csops.h, ins_goons.h, install-sh, insults.h, interfaces.c, + interfaces.h, isblank.c, lbuf.c, lbuf.h, ldap.c, license.pod, + list.c, list.h, logging.c, logging.h, match.c, memrchr.c, missing.h, + mkdefaults, mkstemp.c, mon_systrace.c, mon_systrace.h, nanosleep.c, + nonunix.h, parse.c, parse.h, plugins/sudoers/Makefile.binary.in, + plugins/sudoers/Makefile.in, plugins/sudoers/aixcrypt.exp, + plugins/sudoers/alias.c, plugins/sudoers/auth/API, + plugins/sudoers/auth/afs.c, plugins/sudoers/auth/aix_auth.c, + plugins/sudoers/auth/bsdauth.c, plugins/sudoers/auth/dce.c, + plugins/sudoers/auth/fwtk.c, plugins/sudoers/auth/kerb4.c, + plugins/sudoers/auth/kerb5.c, plugins/sudoers/auth/pam.c, + plugins/sudoers/auth/passwd.c, plugins/sudoers/auth/rfc1938.c, + plugins/sudoers/auth/secureware.c, plugins/sudoers/auth/securid.c, + plugins/sudoers/auth/securid5.c, plugins/sudoers/auth/sia.c, + plugins/sudoers/auth/sudo_auth.c, plugins/sudoers/auth/sudo_auth.h, + plugins/sudoers/boottime.c, plugins/sudoers/check.c, + plugins/sudoers/def_data.c, plugins/sudoers/def_data.h, + plugins/sudoers/def_data.in, plugins/sudoers/defaults.c, + plugins/sudoers/defaults.h, plugins/sudoers/env.c, + plugins/sudoers/find_path.c, plugins/sudoers/getdate.c, + plugins/sudoers/getdate.y, plugins/sudoers/getspwuid.c, + plugins/sudoers/gettime.c, plugins/sudoers/goodpath.c, + plugins/sudoers/gram.c, plugins/sudoers/gram.h, + plugins/sudoers/gram.y, plugins/sudoers/ins_2001.h, + plugins/sudoers/ins_classic.h, plugins/sudoers/ins_csops.h, + plugins/sudoers/ins_goons.h, plugins/sudoers/install-sh, + plugins/sudoers/insults.h, plugins/sudoers/interfaces.c, + plugins/sudoers/interfaces.h, plugins/sudoers/ldap.c, + plugins/sudoers/logging.c, plugins/sudoers/logging.h, + plugins/sudoers/match.c, plugins/sudoers/mkdefaults, + plugins/sudoers/mon_systrace.c, plugins/sudoers/mon_systrace.h, + plugins/sudoers/nonunix.h, plugins/sudoers/parse.c, + plugins/sudoers/parse.h, plugins/sudoers/pwutil.c, + plugins/sudoers/redblack.c, plugins/sudoers/redblack.h, + plugins/sudoers/set_perms.c, plugins/sudoers/sudo_nss.c, + plugins/sudoers/sudo_nss.h, plugins/sudoers/sudoers, + plugins/sudoers/sudoers.c, plugins/sudoers/sudoers.h, + plugins/sudoers/sudoers2ldif, plugins/sudoers/sudoreplay.c, + plugins/sudoers/testsudoers.c, plugins/sudoers/timestr.c, + plugins/sudoers/toke.c, plugins/sudoers/toke.l, + plugins/sudoers/tsgetgrpw.c, plugins/sudoers/vasgroups.c, + plugins/sudoers/visudo.c, pty.c, pwutil.c, redblack.c, redblack.h, + sample.pam, sample.sudoers, sample.syslog.conf, + schema.ActiveDirectory, schema.OpenLDAP, schema.iPlanet, script.c, + selinux.c, sesh.c, set_perms.c, sigaction.c, snprintf.c, src/aix.c, + src/alloc.c, src/audit.c, src/bsm_audit.c, src/bsm_audit.h, + src/error.c, src/fileops.c, src/lbuf.c, src/list.c, src/pty.c, + src/script.c, src/selinux.c, src/sesh.c, src/sudo_edit.c, + src/sudo_noexec.c, src/term.c, src/tgetpass.c, src/zero_bytes.c, + strcasecmp.c, strerror.c, strlcat.c, strlcpy.c, strsignal.c, sudo.c, + sudo.cat, sudo.h, sudo.man.in, sudo.man.pl, sudo.pod, sudo_edit.c, + sudo_noexec.c, sudo_nss.c, sudo_nss.h, sudoers, sudoers.cat, + sudoers.ldap.cat, sudoers.ldap.man.in, sudoers.ldap.pod, + sudoers.man.in, sudoers.man.pl, sudoers.pod, sudoers2ldif, + sudoreplay.c, sudoreplay.cat, sudoreplay.man.in, sudoreplay.pod, + term.c, testsudoers.c, tgetpass.c, timestr.c, toke.c, toke.l, + tsgetgrpw.c, utimes.c, vasgroups.c, visudo.c, visudo.cat, + visudo.man.in, visudo.pod, zero_bytes.c: + Rework source layout in preparation for modular sudo. + [7fc1978c6ad5] - * toke.l: - Avoid a duplicate fclose() of the sudoers file. - [164d39108dde] +2010-02-13 Todd C. Miller - * toke.l: - Fix size arg when realloc()ing include stack. From Daniel Kopecek - [8900bccef219] + * Avoid a duplicate fclose() of the sudoers file. + [5dba851088c1] -2010-02-06 Todd C. Miller + * Fix size arg when realloc()ing include stack. From Daniel Kopecek + [0a2935061e33] - * aix.c, config.h.in, configure, configure.in: - Use setrlimit64(), if available, instead of setrlimit() when setting + * Use setrlimit64(), if available, instead of setrlimit() when setting AIX resource limits since rlim_t is 32bits. - [2cbb14d98fc1] + [353db89bac61] - * logging.c: - Fix use after free when sending error messages. From Timo Juhani + * Fix use after free when sending error messages. From Timo Juhani Lindfors - [caf183fd9d94] - -2010-01-18 Todd C. Miller + [e50dbd902382] * ChangeLog, Makefile.in: Generate the ChangeLog as part of "make dist" instead of having it in the repo. - [836c31615859] - -2010-01-17 Todd C. Miller - - * Makefile.in: - Generate correct ChangeLog for 1.7 branch. - [586dd90b8878] + [251b70964673] 2010-01-17 Todd C. Miller @@ -1619,6 +9742,12 @@ Remove CVS $Sudo$ tags. [de683a8b31f5] +2010-01-18 convert-repo + + * .hgtags: + update tags + [9b7aa44ae436] + 2009-12-26 Todd C. Miller * sudo_usage.h.in: diff --git a/HISTORY b/HISTORY deleted file mode 100644 index 63c7f9f..0000000 --- a/HISTORY +++ /dev/null @@ -1,56 +0,0 @@ -A brief history of sudo: - -Sudo was first conceived and implemented by Bob Coggeshall and Cliff Spencer -around 1980 at the Department of Computer Science at SUNY/Buffalo. It ran on -a VAX-11/750 running 4.1BSD. An updated version, credited to Phil Betchel, -Cliff Spencer, Gretchen Phillips, John LoVerso and Don Gworek, was posted to -the net.sources Usenet newsgroup in December of 1985. - -In the Summer of 1986, Garth Snyder released an enhanced version of sudo. -For the next 5 years, sudo was fed and watered by a handful of folks at -CU-Boulder, including Bob Coggeshall, Bob Manchek, and Trent Hein. - -In 1991, Dave Hieb and Jeff Nieusma wrote a new version of sudo with an -enhanced sudoers format under contract to a consulting firm called "The Root -Group". This version was later released under the GNU public license. - -In 1994, after maintaining sudo informally within CU-Boulder for some time, -Todd Miller made a public release of "CU sudo" (version 1.3) with bug fixes -and support for more operating systems. The "CU" was added to differentiate -it from the "official" version from "The Root Group". - -In 1995, a new parser for the sudoers file was contributed by Chris Jepeway. -The new parser was a proper grammar (unlike the old one) and could work with -both sudo and visudo (previously they had slightly different parsers). - -In 1996, Todd, who had been maintaining sudo for several years in his spare -time, moved distribution of sudo from a CU-Boulder ftp site to his domain, -courtesan.com. - -In 1999, the "CU" prefix was dropped from the name since there had been no -formal release of sudo from "The Root Group" since 1991 (the original -authors now work elsewhere). As of version 1.6, Sudo no longer contains any -of the original "Root Group" code and is available under an ISC-style -license. - -In 2001, the sudo web site, ftp site and mailing lists were moved from -courtesan.com to the sudo.ws domain (sudo.org was already taken). - -In 2003, Nationwide Mutual Insurance Company contributed code written by -Aaron Spangler to store the sudoers data in LDAP. These changes were -incorporated into Sudo 1.6.8. - -In 2005, Todd rewrote the sudoers parser to better support the features that -had been added in the past ten years. This new parser removes some -limitations of the previous one, removes ordering constraints and adds -support for including multiple sudoers files. - -In 2010, Quest Software began sponsoring Sudo development by hiring Todd to -work on Sudo as part of his full-time job. - -sudo, in its current form, is maintained by: - - Todd Miller - -Todd continues to enhance sudo and fix bugs. - diff --git a/INSTALL b/INSTALL index 8d92b4c..faa294a 100644 --- a/INSTALL +++ b/INSTALL @@ -1,5 +1,5 @@ -Installation instructions for Sudo 1.7 -====================================== +Sudo installation instructions +============================== Sudo uses a `configure' script to probe the capabilities and type of the system in question. In this release, `configure' takes many @@ -30,13 +30,13 @@ For most systems and configurations it is possible simply to: have changed the paths via options to `configure'. 5) Type `make' to compile sudo. If you are building sudo - in a separate build tree (apart from the sudo source) - GNU make will probably be required. If `configure' did - its job properly (and you have a supported configuration) - there won't be any problems. If this doesn't work, take - a look at the files TROUBLESHOOTING and PORTING for tips - on what might have gone wrong. Please mail us if you have a - fix or if you are unable to come up with a fix (address at EOF). + in a separate build tree (apart from the sudo source) GNU + make will probably be required. If `configure' did its job + properly (and you have a supported configuration) there won't + be any problems. If this doesn't work, take a look at the + TROUBLESHOOTING file for tips on what might have gone wrong. + Please mail us if you have a fix or if you are unable to + come up with a fix (address at EOF). 6) Type `make install' (as root) to install sudo, visudo, the man pages, and a skeleton sudoers file. Note that the install @@ -99,9 +99,6 @@ Directory and file names: Find the sources in DIR [configure dir or ..] Special features/options: - --with-CC=PATH - Specifies path to C compiler you wish to use. - --with-incpath=DIR Adds the specified directory (or directories) to CPPFLAGS so configure and the compiler will look there for include @@ -134,6 +131,10 @@ Special features/options: `-l' will be prepended to it. Multiple libraries may be specified as long as they are space separated. + --with-plugindir=PATH + Set the directory that sudo looks in to find the policy and I/O + logging plugins. Defaults to the libexec dir used by configure. + --with-efence Link with the "electric fence" debugging malloc. @@ -141,13 +142,18 @@ Special features/options: Enable support for sudo BSM audit logs on systems that support it. Currently only supported under FreeBSD and Mac OS X. + --with-csops + Add CSOps standard options. You probably aren't interested in this. + + --with-devel + Configure development options. This will enable compiler warnings + and set the Makefile to be able to regenerate the sudoers parser + as well as the manual pages. + --with-linux-audit Enable audit support for Linux systems. Audits attempts to run a command as well as SELinux role changes. - --with-csops - Add CSOps standard options. You probably aren't interested in this. - --with-skey[=DIR] Enable S/Key OTP (One Time Password) support. If specified, DIR should contain include and lib directories with skey.h @@ -160,19 +166,13 @@ Special features/options: --with-SecurID[=DIR] Enable SecurID support. If specified, DIR is directory containing - sdiclient.a, sdi_athd.h, sdconf.h, and sdacmvls.h. + libaceclnt.a, acexport.h, and sdacmvls.h. --with-fwtk[=DIR] Enable TIS Firewall Toolkit (FWTK) 'authsrv' support. If specified, DIR is the base directory containing the compiled FWTK package (or at least the library and header files). - --with-kerb4[=DIR] - Enable Kerberos IV support. If specified, DIR is the base - directory containing the Kerberos IV include and lib dirs. - This uses Kerberos passphrases for authentication but does - not use the Kerberos cookie scheme. - --with-kerb5[=DIR] Enable Kerberos V support. If specified, DIR is the base directory containing the Kerberos V include and lib dirs. @@ -180,6 +180,13 @@ Special features/options: does not use the Kerberos cookie scheme. Will not work for Kerberos V older than version 1.1. + --enable-kerb5-instance=string + By default, the user name is used as the principal name + when authenticating via Kerberos V. If this option is + enabled, the specified instance string will be appended to + the user name (separated by a slash) when creating the + principal name. + --with-ldap[=DIR] Enable LDAP support. If specified, DIR is the base directory containing the LDAP include and lib directories. Please see @@ -279,7 +286,7 @@ Special features/options: older PAM implementations or on operating systems where opening a PAM session changes the utmp or wtmp files. If PAM session support is disabled, resource limits may not - be updatedin for command being run. + be updated for the command being run. --disable-root-mailer By default sudo will run the mailer as root when tattling @@ -346,16 +353,6 @@ Special features/options: Enable support for role based access control (RBAC) on systems that support SELinux. - --with-libvas=[NAME] - Enable non-Unix group support using Quest Authentication - Services. If NAME is specified, it should be the name of - the shared library providing QAS support (libvas.so by default). - - --with-libvas-rpath=[PATH] - The path to search when loading libvas.so (or an alternate - name as specified by --with-libvas). This option only has - an effect when --with-libvas is specified. - The following options are also configurable at runtime: --with-long-otp-prompt @@ -463,6 +460,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 +564,12 @@ The following options are also configurable at runtime: prompt as an argument and print the received password to the standard output. + --with-iologdir[=DIR] + By default, sudo stores I/O log files in either /var/log/sudo-io, + /var/adm/sudo-io, or /usr/log/sudo-io. If this option is + specified, I/O logs will be stored in the indicated directory + instead. + --disable-authentication By default, sudo requires the user to authenticate via a password or similar means. This options causes sudo to @@ -603,22 +611,15 @@ 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-zlib[=location] 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. + I/O log files. If specified, location is the base directory + containing the zlib include and lib directories. The special + values "system" and "builtin" can be used to indicate that + the system version of zlib should be used or that the version + of zlib shipped with sudo should be used instead. + If this option is not specified, configure will use the + system zlib if it is present. --disable-zlib Disable the use of the zlib compress library when storing @@ -627,10 +628,32 @@ The following options are also configurable at runtime: --enable-warnings Enable compiler warnings when building sudo with gcc. + --enable-werror + Enable the -Werror compiler option when building sudo with gcc. + --enable-admin-flag 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. + + --enable-nls[=location] + Enable natural language support using the gettext() family + of functions. If specified, location is the base directory + containing the libintl include and lib directories. If + this option is not specified, configure will look for the + gettext() family of functions in the standard C library + first, then check for a standalone libintl (linking with + libiconv as needed). + + --disable-nls + Disable natural language support. By default, sudo will + use the gettext() family of functions, if available, to + implement messages in the invoking user's native language. + Note that translations do not exist for all languages. + Shadow password and C2 support ============================== @@ -690,14 +713,15 @@ Solaris 2.x: CD. You can also get them from various places on the net, including http://www.sunfreeware.com/ NOTE: sudo will *not* build with the sun C compiler in BSD - compatibility mode (/usr/ucb/cc). Sudo is designed to - compile with the standard C compiler (or gcc) and will - not build correctly with /usr/ucb/cc. You can use the - `--with-CC' option to point `configure' to the non-ucb - compiler if it is not the first cc in your path. Some - sites link /usr/ucb/cc to gcc; configure will not notice - this and still refuse to use /usr/ucb/cc, so make sure gcc - is also in your path if your site is setup this way. + compatibility mode (/usr/ucb/cc). Sudo is designed to + compile with the standard C compiler (or gcc) and will + not build correctly with /usr/ucb/cc. You can set the + CC environment variable to the non-ucb compiler when + running `configure' if it is not the first cc in your + path. Some sites link /usr/ucb/cc to gcc; configure will + not notice this and still refuse to use /usr/ucb/cc, so + make sure gcc is also in your path if your site is setup + this way. Also: Older versions of Solaris come with a broken syslogd. If you have having problems with sudo logging you should make sure you have the latest syslogd patch installed. @@ -712,17 +736,21 @@ Mac OS X: is bug id #7952709. HP-UX: - The default C compiler shipped with HP-UX does not support - creating position independent code and so is unable to support - sudo's "noexec" functionality. You must use either the HP ANSI - C compiler or gcc for noexec to work. Binary packages of gcc - are available http://hpux.connect.org.uk/. + The default C compiler shipped with HP-UX is not an ANSI compiler. + You must use either the HP ANSI C compiler or gcc to build sudo. + Binary packages of gcc are available from http://hpux.connect.org.uk/. To prevent PAM from overriding the value of umask on HP-UX 11, you will need to add a line like the following to /etc/pam.conf: sudo session required libpam_hpsec.so.1 bypass_umask + If every command run via sudo displays information about the last + successful login and the last authentication failure you should + make use an /etc/pam.conf line like: + + sudo session required libpam_hpsec.so.1 bypass_umask bypass_last_login + Digital UNIX: By default, sudo will use SIA (Security Integration Architecture) to validate a user. If you want to use an alternative authentication @@ -752,12 +780,18 @@ SCO ODT: and /SLS/lng225b.ltr.Z. SunOS 4.x: + SunOS does not ship with an ANSI C compiler. You will need to + install an ANSI compiler such as gcc to build sudo. + The /bin/sh shipped with SunOS blows up while running configure. You can work around this by installing bash or zsh. If you have bash or zsh in your path, configure will use it instead automatically. ULTRIX 4.x: + ULTRIX does not ship with an ANSI C compiler. You will need to + install an ANSI compiler such as gcc to build sudo. + The /bin/sh shipped with ULTRIX blows up while running configure. You can work around this by installing bash or zsh. If you have bash or zsh in your path, configure will use it instead diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 6e9a547..0000000 --- a/LICENSE +++ /dev/null @@ -1,78 +0,0 @@ -Sudo is distributed under the following ISC-style license: - - Copyright (c) 1994-1996, 1998-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. - -Additionally, fnmatch.c, fnmatch.h, getcwd.c, glob.c, glob.h and snprintf.c -bear the following UCB license: - - Copyright (c) 1987, 1989, 1990, 1991, 1992, 1993, 1994 - The Regents of the University of California. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - -nonunix.h and vasgroups.c bear the following license: - - Copyright (c) 2006 Quest Software, Inc. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of Quest Software, Inc. nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..1b9496e --- /dev/null +++ b/MANIFEST @@ -0,0 +1,365 @@ +ChangeLog +INSTALL +INSTALL.configure +MANIFEST +Makefile.in +NEWS +README +README.LDAP +aclocal.m4 +common/Makefile.in +common/aix.c +common/alloc.c +common/atobool.c +common/fileops.c +common/fmt_string.c +common/lbuf.c +common/list.c +common/secure_path.c +common/setgroups.c +common/sudo_conf.c +common/sudo_debug.c +common/term.c +common/ttysize.c +common/zero_bytes.c +compat/Makefile.in +compat/charclass.h +compat/closefrom.c +compat/dlfcn.h +compat/dlopen.c +compat/fnmatch.c +compat/fnmatch.h +compat/getaddrinfo.c +compat/getaddrinfo.h +compat/getcwd.c +compat/getgrouplist.c +compat/getline.c +compat/getprogname.c +compat/glob.c +compat/glob.h +compat/isblank.c +compat/memrchr.c +compat/mksiglist.c +compat/mksiglist.h +compat/mktemp.c +compat/nanosleep.c +compat/pw_dup.c +compat/regress/fnmatch/fnm_test.c +compat/regress/fnmatch/fnm_test.in +compat/regress/glob/files +compat/regress/glob/globtest.c +compat/regress/glob/globtest.in +compat/siglist.in +compat/snprintf.c +compat/stdbool.h +compat/strlcat.c +compat/strlcpy.c +compat/strsignal.c +compat/timespec.h +compat/utime.h +compat/utimes.c +config.guess +config.h.in +config.sub +configure +configure.in +doc/CONTRIBUTORS +doc/HISTORY +doc/LICENSE +doc/Makefile.in +doc/TROUBLESHOOTING +doc/UPGRADE +doc/contributors.pod +doc/history.pod +doc/license.pod +doc/sample.pam +doc/sample.sudo.conf +doc/sample.sudoers +doc/sample.syslog.conf +doc/schema.ActiveDirectory +doc/schema.OpenLDAP +doc/schema.iPlanet +doc/sudo.cat +doc/sudo.man.in +doc/sudo.man.pl +doc/sudo.pod +doc/sudo_plugin.cat +doc/sudo_plugin.man.in +doc/sudo_plugin.pod +doc/sudoers.cat +doc/sudoers.ldap.cat +doc/sudoers.ldap.man.in +doc/sudoers.ldap.pod +doc/sudoers.man.in +doc/sudoers.man.pl +doc/sudoers.pod +doc/sudoreplay.cat +doc/sudoreplay.man.in +doc/sudoreplay.pod +doc/visudo.cat +doc/visudo.man.in +doc/visudo.pod +include/Makefile.in +include/alloc.h +include/error.h +include/fileops.h +include/gettext.h +include/lbuf.h +include/list.h +include/missing.h +include/secure_path.h +include/sudo_conf.h +include/sudo_debug.h +include/sudo_plugin.h +indent.pro +install-sh +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +mkdep.pl +mkinstalldirs +mkpkg +pathnames.h.in +plugins/sample/Makefile.in +plugins/sample/sample_plugin.c +plugins/sample/sample_plugin.sym +plugins/sample_group/Makefile.in +plugins/sample_group/getgrent.c +plugins/sample_group/plugin_test.c +plugins/sample_group/sample_group.c +plugins/sample_group/sample_group.sym +plugins/system_group/Makefile.in +plugins/system_group/system_group.c +plugins/system_group/system_group.sym +plugins/sudoers/Makefile.in +plugins/sudoers/aixcrypt.exp +plugins/sudoers/alias.c +plugins/sudoers/audit.c +plugins/sudoers/auth/API +plugins/sudoers/auth/afs.c +plugins/sudoers/auth/aix_auth.c +plugins/sudoers/auth/bsdauth.c +plugins/sudoers/auth/dce.c +plugins/sudoers/auth/fwtk.c +plugins/sudoers/auth/kerb5.c +plugins/sudoers/auth/pam.c +plugins/sudoers/auth/passwd.c +plugins/sudoers/auth/rfc1938.c +plugins/sudoers/auth/secureware.c +plugins/sudoers/auth/securid5.c +plugins/sudoers/auth/sia.c +plugins/sudoers/auth/sudo_auth.c +plugins/sudoers/auth/sudo_auth.h +plugins/sudoers/boottime.c +plugins/sudoers/bsm_audit.c +plugins/sudoers/bsm_audit.h +plugins/sudoers/check.c +plugins/sudoers/def_data.c +plugins/sudoers/def_data.h +plugins/sudoers/def_data.in +plugins/sudoers/defaults.c +plugins/sudoers/defaults.h +plugins/sudoers/env.c +plugins/sudoers/find_path.c +plugins/sudoers/getdate.c +plugins/sudoers/getdate.y +plugins/sudoers/getspwuid.c +plugins/sudoers/goodpath.c +plugins/sudoers/gram.c +plugins/sudoers/gram.h +plugins/sudoers/gram.y +plugins/sudoers/group_plugin.c +plugins/sudoers/ins_2001.h +plugins/sudoers/ins_classic.h +plugins/sudoers/ins_csops.h +plugins/sudoers/ins_goons.h +plugins/sudoers/insults.h +plugins/sudoers/interfaces.c +plugins/sudoers/interfaces.h +plugins/sudoers/iolog.c +plugins/sudoers/iolog_path.c +plugins/sudoers/ldap.c +plugins/sudoers/linux_audit.c +plugins/sudoers/linux_audit.h +plugins/sudoers/logging.c +plugins/sudoers/logging.h +plugins/sudoers/logwrap.c +plugins/sudoers/match.c +plugins/sudoers/match_addr.c +plugins/sudoers/mkdefaults +plugins/sudoers/parse.c +plugins/sudoers/parse.h +plugins/sudoers/plugin_error.c +plugins/sudoers/po/README +plugins/sudoers/po/da.mo +plugins/sudoers/po/da.po +plugins/sudoers/po/eo.mo +plugins/sudoers/po/eo.po +plugins/sudoers/po/eu.mo +plugins/sudoers/po/eu.po +plugins/sudoers/po/fi.mo +plugins/sudoers/po/fi.po +plugins/sudoers/po/hr.mo +plugins/sudoers/po/hr.po +plugins/sudoers/po/ja.mo +plugins/sudoers/po/ja.po +plugins/sudoers/po/lt.mo +plugins/sudoers/po/lt.po +plugins/sudoers/po/pl.mo +plugins/sudoers/po/pl.po +plugins/sudoers/po/sudoers.pot +plugins/sudoers/po/sv.mo +plugins/sudoers/po/sv.po +plugins/sudoers/po/uk.mo +plugins/sudoers/po/uk.po +plugins/sudoers/po/zh_CN.mo +plugins/sudoers/po/zh_CN.po +plugins/sudoers/pwutil.c +plugins/sudoers/redblack.c +plugins/sudoers/redblack.h +plugins/sudoers/regress/iolog_path/check_iolog_path.c +plugins/sudoers/regress/iolog_path/data +plugins/sudoers/regress/logging/check_wrap.c +plugins/sudoers/regress/logging/check_wrap.in +plugins/sudoers/regress/logging/check_wrap.out.ok +plugins/sudoers/regress/parser/check_addr.c +plugins/sudoers/regress/parser/check_addr.in +plugins/sudoers/regress/parser/check_fill.c +plugins/sudoers/regress/sudoers/test1.in +plugins/sudoers/regress/sudoers/test1.out.ok +plugins/sudoers/regress/sudoers/test1.toke.ok +plugins/sudoers/regress/sudoers/test2.in +plugins/sudoers/regress/sudoers/test2.out.ok +plugins/sudoers/regress/sudoers/test2.toke.ok +plugins/sudoers/regress/sudoers/test3.in +plugins/sudoers/regress/sudoers/test3.out.ok +plugins/sudoers/regress/sudoers/test3.toke.ok +plugins/sudoers/regress/sudoers/test4.in +plugins/sudoers/regress/sudoers/test4.out.ok +plugins/sudoers/regress/sudoers/test4.toke.ok +plugins/sudoers/regress/sudoers/test5.in +plugins/sudoers/regress/sudoers/test5.out.ok +plugins/sudoers/regress/sudoers/test5.toke.ok +plugins/sudoers/regress/sudoers/test6.in +plugins/sudoers/regress/sudoers/test6.out.ok +plugins/sudoers/regress/sudoers/test6.toke.ok +plugins/sudoers/regress/sudoers/test7.in +plugins/sudoers/regress/sudoers/test7.out.ok +plugins/sudoers/regress/sudoers/test7.toke.ok +plugins/sudoers/regress/sudoers/test8.in +plugins/sudoers/regress/sudoers/test8.out.ok +plugins/sudoers/regress/sudoers/test8.toke.ok +plugins/sudoers/regress/testsudoers/test1.out.ok +plugins/sudoers/regress/testsudoers/test1.sh +plugins/sudoers/set_perms.c +plugins/sudoers/sudo_nss.c +plugins/sudoers/sudo_nss.h +plugins/sudoers/sudoers.c +plugins/sudoers/sudoers.h +plugins/sudoers/sudoers.in +plugins/sudoers/sudoers.sym +plugins/sudoers/sudoers2ldif +plugins/sudoers/sudoers_version.h +plugins/sudoers/sudoreplay.c +plugins/sudoers/testsudoers.c +plugins/sudoers/timestr.c +plugins/sudoers/toke.c +plugins/sudoers/toke.h +plugins/sudoers/toke.l +plugins/sudoers/toke_util.c +plugins/sudoers/tsgetgrpw.c +plugins/sudoers/tsgetgrpw.h +plugins/sudoers/visudo.c +pp +src/Makefile.in +src/conversation.c +src/env_hooks.c +src/error.c +src/exec.c +src/exec_common.c +src/exec_pty.c +src/get_pty.c +src/hooks.c +src/load_plugins.c +src/net_ifs.c +src/parse_args.c +src/po/README +src/po/da.mo +src/po/da.po +src/po/de.mo +src/po/de.po +src/po/eo.mo +src/po/eo.po +src/po/es.mo +src/po/es.po +src/po/eu.mo +src/po/eu.po +src/po/fi.mo +src/po/fi.po +src/po/gl.mo +src/po/gl.po +src/po/hr.mo +src/po/hr.po +src/po/it.mo +src/po/it.po +src/po/ja.mo +src/po/ja.po +src/po/pl.mo +src/po/pl.po +src/po/ru.mo +src/po/ru.po +src/po/sr.mo +src/po/sr.po +src/po/sudo.pot +src/po/sv.mo +src/po/sv.po +src/po/uk.mo +src/po/uk.po +src/po/vi.mo +src/po/vi.po +src/po/zh_CN.mo +src/po/zh_CN.po +src/preload.c +src/selinux.c +src/sesh.c +src/sudo.c +src/sudo.h +src/sudo_edit.c +src/sudo_exec.h +src/sudo_noexec.c +src/sudo_plugin_int.h +src/sudo_usage.h.in +src/tgetpass.c +src/ttyname.c +src/utmp.c +sudo.pp +zlib/Makefile.in +zlib/adler32.c +zlib/compress.c +zlib/crc32.c +zlib/crc32.h +zlib/deflate.c +zlib/deflate.h +zlib/gzclose.c +zlib/gzguts.h +zlib/gzlib.c +zlib/gzread.c +zlib/gzwrite.c +zlib/infback.c +zlib/inffast.c +zlib/inffast.h +zlib/inffixed.h +zlib/inflate.c +zlib/inflate.h +zlib/inftrees.c +zlib/inftrees.h +zlib/trees.c +zlib/trees.h +zlib/uncompr.c +zlib/zconf.h.in +zlib/zlib.h +zlib/zutil.c +zlib/zutil.h diff --git a/Makefile.in b/Makefile.in index 0114ca7..1fbed4c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,5 @@ # -# Copyright (c) 1996, 1998-2005, 2007-2010 -# Todd C. Miller +# Copyright (c) 2010-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 @@ -15,529 +14,246 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # -# Sponsored in part by the Defense Advanced Research Projects -# Agency (DARPA) and Air Force Research Laboratory, Air Force -# Materiel Command, USAF, under agreement number F39502-99-1-0512. -# -# @configure_input@ -# - -#### Start of system configuration section. #### srcdir = @srcdir@ devdir = @devdir@ -authdir = $(srcdir)/auth -top_builddir = . - -# Compiler & tools to use -CC = @CC@ -FLEX = @FLEX@ -YACC = @YACC@ -NROFF = @NROFFPROG@ -Tascii -LIBTOOL = @LIBTOOL@ -AR=@AR@ -RANLIB=@RANLIB@ - -# Our install program supports extra flags... -INSTALL = $(SHELL) $(srcdir)/install-sh -c - -# Libraries -LIBS = @LIBS@ -NET_LIBS = @NET_LIBS@ -SUDO_LIBS = @SUDO_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(LIBS) $(NET_LIBS) - -# C preprocessor flags -CPPFLAGS = -I. -I$(srcdir) @CPPFLAGS@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ -# Usually -O and/or -g -CFLAGS = @CFLAGS@ - -# Flags to pass to the link stage -LDFLAGS = -L. @LDFLAGS@ -SUDO_LDFLAGS = @SUDO_LDFLAGS@ $(LDFLAGS) - -# Where to install things... +# Installation paths for package building prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ sbindir = @sbindir@ sysconfdir = @sysconfdir@ libexecdir = @libexecdir@ +includedir = @includedir@ datarootdir = @datarootdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ docdir = @docdir@ mandir = @mandir@ timedir = @timedir@ -noexecfile = @NOEXECFILE@ -noexecdir = @NOEXECDIR@ - -# Directory in which to install sudo. -sudodir = $(bindir) - -# Directory in which to install visudo -visudodir = $(sbindir) - -# Directory in which to install the sudoers file -sudoersdir = $(sysconfdir) - -# Directory in which to install the man page -mantype = @MANTYPE@ -mansectsu = @mansectsu@ -mansectform = @mansectform@ -mandirsu = $(mandir)/$(mantype)$(mansectsu) -mandirform = $(mandir)/$(mantype)$(mansectform) # User and group ids the installed files should be "owned" by install_uid = 0 install_gid = 0 -# User, group, and mode the sudoers file should be "owned" by (configure) +# sudoers owner and mode for package building +sudoersdir = $(sysconfdir) sudoers_uid = @SUDOERS_UID@ sudoers_gid = @SUDOERS_GID@ sudoers_mode = @SUDOERS_MODE@ -# Pass in paths and uid/gid + OS dependent defined -DEFS = @OSDEFS@ -D_PATH_SUDOERS=\"$(sudoersdir)/sudoers\" -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) -DSUDOERS_MODE=$(sudoers_mode) - -#### End of system configuration section. #### - -SHELL = @SHELL@ - -PROGS = @PROGS@ - -SRCS = aix.c alias.c alloc.c audit.c boottime.c bsm_audit.c check.c \ - closefrom.c def_data.c defaults.c env.c error.c exec.c exec_pty.c \ - fileops.c find_path.c fnmatch.c get_pty.c getcwd.c getprogname.c \ - getspwuid.c gettime.c glob.c goodpath.c gram.c gram.y interfaces.c \ - iolog.c isblank.c lbuf.c ldap.c linux_audit.c list.c logging.c match.c \ - mksiglist.c mkstemps.c memrchr.c nanosleep.c parse.c parse_args.c \ - pwutil.c set_perms.c setsid.c sigaction.c snprintf.c strcasecmp.c \ - strerror.c strlcat.c strlcpy.c strsignal.c sudo.c sudo_noexec.c \ - sudo_edit.c sudo_nss.c term.c testsudoers.c tgetpass.c toke.c toke.l \ - tsgetgrpw.c utimes.c vasgroups.c visudo.c zero_bytes.c redblack.c \ - selinux.c sesh.c sudoreplay.c getdate.c getdate.y getline.c \ - timestr.c $(AUTH_SRCS) - -AUTH_SRCS = auth/afs.c auth/aix_auth.c auth/bsdauth.c auth/dce.c auth/fwtk.c \ - auth/kerb4.c auth/kerb5.c auth/pam.c auth/passwd.c auth/rfc1938.c \ - auth/secureware.c auth/securid.c auth/securid5.c auth/sia.c \ - auth/sudo_auth.c - -HDRS = alloc.h bsm_audit.h compat.h def_data.h defaults.h error.h ins_2001.h \ - ins_classic.h ins_csops.h ins_goons.h insults.h interfaces.h lbuf.h \ - 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 \ - 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 \ - 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 \ - interfaces.o lbuf.o logging.o parse.o parse_args.o set_perms.o \ - sudo.o sudo_edit.o sudo_nss.o tgetpass.o +SUBDIRS = compat common @ZLIB_SRC@ plugins/sudoers src include doc -VISUDO_OBJS = visudo.o fileops.o gettime.o goodpath.o find_path.o +SAMPLES = plugins/sample plugins/sample_group plugins/system_group -REPLAY_OBJS = getdate.o sudoreplay.o +VERSION = @PACKAGE_VERSION@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ -TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o +LIBTOOL_DEPS = @LIBTOOL_DEPS@ -LIB_OBJS = @LIBOBJS@ +SHELL = @SHELL@ -VERSION = @PACKAGE_VERSION@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +ECHO_N = @ECHO_N@ +ECHO_C = @ECHO_C@ + +# Message catalog support +NLS = @SUDO_NLS@ +POTFILES = src/po/sudo.pot plugins/sudoers/po/sudoers.pot +MSGFMT = msgfmt +MSGMERGE = msgmerge +XGETTEXT = xgettext +XGETTEXT_OPTS = -F -k_ -kN_ --copyright-holder="Todd C. Miller" \ + "--msgid-bugs-address=http://www.sudo.ws/bugs" \ + --package-name=@PACKAGE_NAME@ --package-version=$(VERSION) \ + --flag warning:1:c-format --flag warningx:1:c-format \ + --flag error:2:c-format --flag errorx:2:c-format \ + --flag easprintf:3:c-format --flag lbuf_append:2:c-format \ + --flag lbuf_append_quoted:3:c-format --foreign-user + +all: config.status + for d in $(SUBDIRS) $(SAMPLES); \ + do (cd $$d && exec $(MAKE) $@) && continue; \ + exit $$?; \ + done + +check pre-install: config.status + for d in $(SUBDIRS); \ + do (cd $$d && exec $(MAKE) $@) && continue; \ + exit $$?; \ + done + +install-dirs install-binaries install-includes install-plugin: config.status pre-install + for d in $(SUBDIRS); \ + do (cd $$d && exec $(MAKE) $@) && continue; \ + exit $$?; \ + done + +install-doc: config.status ChangeLog + for d in $(SUBDIRS); \ + do (cd $$d && exec $(MAKE) $@) && continue; \ + exit $$?; \ + done + +install: config.status ChangeLog pre-install install-nls + for d in $(SUBDIRS); \ + do (cd $$d && exec $(MAKE) $@) && continue; \ + exit $$?; \ + done + +uninstall: uninstall-nls + for d in $(SUBDIRS); \ + do (cd $$d && exec $(MAKE) $@) && continue; \ + exit $$?; \ + done + +uninstall-nls: + for pot in $(POTFILES); do \ + domain=`basename $$pot .pot`; \ + rm -f $(DESTDIR)$(localedir)/*/LC_MESSAGES/$$domain.mo; \ + done + +autoconf: + autoconf -I m4 + +siglist.c: + (cd compat && exec $(MAKE) $@) + +depend: siglist.c + @if test "$(srcdir)" != "."; then \ + echo "make depend only supported in the source directory"; \ + exit 1; \ + fi; \ + $(srcdir)/mkdep.pl $(srcdir)/common/Makefile.in \ + $(srcdir)/compat/Makefile.in $(srcdir)/plugins/sample/Makefile.in \ + $(srcdir)/plugins/sample_group/Makefile.in \ + $(srcdir)/plugins/sudoers/Makefile.in \ + $(srcdir)/plugins/system_group/Makefile.in \ + $(srcdir)/src/Makefile.in $(srcdir)/zlib/Makefile.in; \ + ./config.status --file $(srcdir)/common/Makefile \ + --file $(srcdir)/compat/Makefile \ + --file $(srcdir)/plugins/sample/Makefile \ + --file $(srcdir)/plugins/sample_group/Makefile \ + --file $(srcdir)/plugins/sudoers/Makefile \ + --file $(srcdir)/plugins/system_group/Makefile \ + --file $(srcdir)/src/Makefile --file $(srcdir)/zlib/Makefile -DISTFILES = $(SRCS) $(HDRS) ChangeLog HISTORY INSTALL INSTALL.configure \ - LICENSE Makefile.in NEWS PORTING README README.LDAP \ - TROUBLESHOOTING UPGRADE aclocal.m4 aixcrypt.exp config.guess \ - config.h.in config.sub configure configure.in def_data.in \ - indent.pro install-sh ltmain.sh m4 mkdefaults mkinstalldirs \ - mkpkg pathnames.h.in pp sample.pam sample.syslog.conf \ - sample.sudoers schema.ActiveDirectory schema.OpenLDAP \ - schema.iPlanet siglist.in sudo.cat sudo.man.in sudo.pod sudo.pp \ - sudo_usage.h.in sudoers.in sudoers.cat sudoers.man.in sudoers.pod \ - sudoers.ldap.cat sudoers.ldap.man.in sudoers.ldap.pod \ - sudoers2ldif sudoreplay.cat sudoreplay.man.in sudoreplay.pod \ - visudo.cat visudo.man.in visudo.pod auth/API sudo.man.pl \ - sudoers.man.pl - -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 - -AUTHDEP = $(SUDODEP) $(authdir)/sudo_auth.h - -INSDEP = $(srcdir)/ins_2001.h $(srcdir)/ins_classic.h $(srcdir)/ins_csops.h \ - $(srcdir)/ins_goons.h $(srcdir)/insults.h - -all: $(PROGS) - -.SUFFIXES: .o .c .h .l .y .lo - -.c.o: - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $< - -.c.lo: - $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $< - -libsudo.a: $(LIB_OBJS) $(COMMON_OBJS) - $(AR) rv $@ $(LIB_OBJS) $(COMMON_OBJS) - $(RANLIB) $@ - -sudo: libsudo.a $(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) - $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) -lsudo $(LIBS) @ZLIB@ - -testsudoers: $(TEST_OBJS) - $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS) -lsudo $(LIBS) $(NET_LIBS) - -sudo_noexec.lo: $(srcdir)/sudo_noexec.c - $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c - -libsudo_noexec.la: sudo_noexec.lo - $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ sudo_noexec.lo -avoid-version -rpath $(noexecdir) - -# Uncomment the following if you want "make distclean" to clean the parser -@DEV@GENERATED = gram.h gram.c toke.c def_data.c def_data.h getdate - -# Uncomment the lines before -@true if you intend to modify gram.y -$(devdir)/gram.c $(devdir)/gram.h: $(srcdir)/gram.y -@DEV@ $(YACC) -d $(srcdir)/gram.y -@DEV@ mv -f y.tab.c gram.c -@DEV@ if cmp -s y.tab.h gram.h; then rm -f y.tab.h; else mv -f y.tab.h gram.h; fi - -@true - -# Uncomment the 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 - -@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 - -@true - -# Uncomment the following if you intend to modify def_data.in -@DEV@$(devdir)/def_data.h $(devdir)/def_data.c: $(srcdir)/def_data.in -@DEV@ perl $(srcdir)/mkdefaults -o def_data $(srcdir)/def_data.in - -siglist.c: mksiglist - ./mksiglist > $@ - -mksiglist: $(srcdir)/mksiglist.c $(srcdir)/mksiglist.h $(srcdir)/compat.h $(top_builddir)/config.h - $(CC) $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mksiglist.c -o $@ - -@DEV@$(srcdir)/mksiglist.h: $(srcdir)/siglist.in -@DEV@ awk 'BEGIN {print "/* public domain */\n"} /^ [A-Z]/ {printf("#ifdef SIG%s\n if (my_sys_siglist[SIG%s] == NULL)\n\tmy_sys_siglist[SIG%s] = \"%s\";\n#endif\n", $$1, $$1, $$1, substr($$0, 13))}' < $(srcdir)/siglist.in > $@ - -# Dependencies (not counting auth functions) -aix.o: $(srcdir)/aix.c - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/aix.c -alias.o: $(srcdir)/alias.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/redblack.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alias.c -alloc.o: $(srcdir)/alloc.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/alloc.c -audit.o: $(srcdir)/audit.c $(SUDODEP) $(srcdir)/bsm_audit.h $(srcdir)/linux_audit.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/audit.c -boottime.o: $(srcdir)/boottime.c config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/boottime.c -bsm_audit.o: $(srcdir)/bsm_audit.c $(SUDODEP) $(srcdir)/bsm_audit.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/bsm_audit.c -check.o: $(srcdir)/check.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/check.c -closefrom.o: $(srcdir)/closefrom.c config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/closefrom.c -defaults.o: $(srcdir)/defaults.c $(SUDODEP) $(srcdir)/def_data.c $(authdir)/sudo_auth.h $(devdir)/gram.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/defaults.c -env.o: $(srcdir)/env.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/env.c -error.o: $(srcdir)/error.c $(srcdir)/compat.h $(srcdir)/error.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/error.c -exec.o: $(srcdir)/exec.c $(SUDODEP) $(srcdir)/sudo_exec.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/exec.c -exec_pty.o: $(srcdir)/exec.c $(SUDODEP) $(srcdir)/sudo_exec.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/exec_pty.c -fileops.o: $(srcdir)/fileops.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/fileops.c -find_path.o: $(srcdir)/find_path.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/find_path.c -fnmatch.o: $(srcdir)/fnmatch.c $(srcdir)/emul/fnmatch.h $(srcdir)/compat.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 - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getcwd.c -getdate.o: $(srcdir)/getdate.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getdate.c -getline.o: $(srcdir)/getline.c config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getline.c -getprogname.o: $(srcdir)/getprogname.c config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getprogname.c -getspwuid.o: $(srcdir)/getspwuid.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/getspwuid.c -gettime.o: $(srcdir)/gettime.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/gettime.c -glob.o: $(srcdir)/glob.c $(srcdir)/emul/glob.h $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/glob.c -goodpath.o: $(srcdir)/goodpath.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/goodpath.c -gram.o: $(devdir)/gram.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/gram.c -interfaces.o: $(srcdir)/interfaces.c $(SUDODEP) $(srcdir)/interfaces.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/interfaces.c -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 - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/isblank.c -lbuf.o: $(srcdir)/lbuf.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/lbuf.c -ldap.o: $(srcdir)/ldap.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/ldap.c -linux_audit.o: $(srcdir)/linux_audit.c $(SUDODEP) $(srcdir)/linux_audit.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/linux_audit.c -list.o: $(srcdir)/list.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/list.c -logging.o: $(srcdir)/logging.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/logging.c -match.o: $(srcdir)/match.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/match.c -memrchr.o: $(srcdir)/memrchr.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/memrchr.c -mkstemps.o: $(srcdir)/mkstemps.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/mkstemps.c -nanosleep.o: $(srcdir)/nanosleep.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/nanosleep.c -parse.o: $(srcdir)/parse.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(devdir)/gram.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse.c -parse_args.o: $(srcdir)/parse_args.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/parse_args.c -pwutil.o: $(srcdir)/pwutil.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/pwutil.c -redblack.o: $(srcdir)/redblack.c $(SUDODEP) $(srcdir)/redblack.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/redblack.c -set_perms.o: $(srcdir)/set_perms.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/set_perms.c -setsid.o: $(srcdir)/setsid.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/setsid.c -sigaction.o: $(srcdir)/sigaction.c $(srcdir)/compat.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sigaction.c -siglist.o: siglist.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/siglist.c -snprintf.o: $(srcdir)/snprintf.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/snprintf.c -strcasecmp.o: $(srcdir)/strcasecmp.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strcasecmp.c -strerror.o: $(srcdir)/strerror.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strerror.c -strlcat.o: $(srcdir)/strlcat.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcat.c -strlcpy.o: $(srcdir)/strlcpy.c $(srcdir)/compat.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/strlcpy.c -strsignal.o: $(srcdir)/strsignal.c $(srcdir)/compat.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 - $(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 - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_noexec.c -sudo_nss.o: $(srcdir)/sudo_nss.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/sudo_nss.c -term.o: $(srcdir)/term.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/term.c -testsudoers.o: $(srcdir)/testsudoers.c $(SUDODEP) $(srcdir)/parse.h $(srcdir)/list.h $(srcdir)/interfaces.h $(devdir)/gram.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/testsudoers.c -tgetpass.o: $(srcdir)/tgetpass.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tgetpass.c -timestr.o: $(srcdir)/timestr.c $(srcdir)/compat.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 - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(devdir)/toke.c -tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(SUDODEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/tsgetgrpw.c -utimes.o: $(srcdir)/utimes.c $(srcdir)/compat.h $(srcdir)/emul/utime.h config.h - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/utimes.c -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 - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(srcdir)/zero_bytes.c -sudo_auth.o: $(authdir)/sudo_auth.c $(AUTHDEP) $(INSDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/sudo_auth.c -afs.o: $(authdir)/afs.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/afs.c -aix_auth.o: $(authdir)/aix_auth.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/aix_auth.c -bsdauth.o: $(authdir)/bsdauth.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/bsdauth.c -dce.o: $(authdir)/dce.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/dce.c -fwtk.o: $(authdir)/fwtk.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/fwtk.c -kerb4.o: $(authdir)/kerb4.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/kerb4.c -kerb5.o: $(authdir)/kerb5.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/kerb5.c -pam.o: $(authdir)/pam.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/pam.c -passwd.o: $(authdir)/passwd.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/passwd.c -rfc1938.o: $(authdir)/rfc1938.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/rfc1938.c -secureware.o: $(authdir)/secureware.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/secureware.c -securid.o: $(authdir)/securid.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/securid.c -securid5.o: $(authdir)/securid5.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/securid5.c -sia.o: $(authdir)/sia.c $(AUTHDEP) - $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(OPTIONS) $(authdir)/sia.c - -@DEV@varsub: $(srcdir)/configure.in -@DEV@ printf 's#@%s@#1#\ns#@%s@#1#\ns#@%s@#1#\ns#@%s@#/etc#g\ns#@%s@#/usr/local#g\ns#@%s@#4#g\ns#@%s@#1m#g\n' SEMAN BAMAN LCMAN sysconfdir prefix mansectform mansectsu > $@; sed -n '/Begin initial values for man page substitution/,/End initial values for man page substitution/{;p;}' $(srcdir)/configure.in | sed -e '/^#/d' -e 's/^/s#@/' -e 's/=[\\"]*/@#/' -e 's/[\\"]*$$/#g/' >> $@ - -@DEV@$(srcdir)/sudo.man.in: $(srcdir)/sudo.pod -@DEV@ mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudo.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudo.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" | perl -p $(srcdir)/sudo.man.pl >> $@ - -sudo.man: $(srcdir)/sudo.man.in - $(SHELL) config.status --file=$@ - -@DEV@$(srcdir)/sudo.cat: varsub $(srcdir)/sudo.man.in -@DEV@ sed -f varsub $(srcdir)/sudo.man.in | $(NROFF) -man > $@ - -@DEV@$(srcdir)/visudo.man.in: $(srcdir)/visudo.pod -@DEV@ mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/visudo.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/visudo.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@ - -visudo.man: $(srcdir)/visudo.man.in - $(SHELL) config.status --file=$@ - -@DEV@$(srcdir)/visudo.cat: varsub $(srcdir)/visudo.man.in -@DEV@ sed -f varsub $(srcdir)/visudo.man.in | $(NROFF) -man > $@ - -@DEV@$(srcdir)/sudoers.man.in: $(srcdir)/sudoers.pod -@DEV@ mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" | perl -p $(srcdir)/sudoers.man.pl >> $@ - -sudoers.man: $(srcdir)/sudoers.man.in - $(SHELL) config.status --file=$@ - -@DEV@$(srcdir)/sudoers.cat: varsub $(srcdir)/sudoers.man.in -@DEV@ sed -f varsub $(srcdir)/sudoers.man.in | $(NROFF) -man > $@ - -@DEV@$(srcdir)/sudoers.ldap.man.in: $(srcdir)/sudoers.ldap.pod -@DEV@ mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.ldap.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.ldap.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@ - -sudoers.ldap.man: $(srcdir)/sudoers.ldap.man.in - $(SHELL) config.status --file=$@ - -@DEV@$(srcdir)/sudoers.ldap.cat: varsub $(srcdir)/sudoers.ldap.man.in -@DEV@ sed -f varsub $(srcdir)/sudoers.ldap.man.in | $(NROFF) -man > $@ - -@DEV@$(srcdir)/sudoreplay.man.in: $(srcdir)/sudoreplay.pod -@DEV@ mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoreplay.pod > $@; pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoreplay.pod | sed -e "s/(5)/($$mansectform)/" -e "s/(8)/($$mansectsu)/" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@ - -sudoreplay.man: $(srcdir)/sudoreplay.man.in - $(SHELL) config.status --file=$@ - -@DEV@$(srcdir)/sudoreplay.cat: varsub $(srcdir)/sudoreplay.man.in -@DEV@ sed -f varsub $(srcdir)/sudoreplay.man.in | $(NROFF) -man > $@ - -@DEV@HISTORY: $(srcdir)/history.pod -@DEV@ pod2text -l -i0 $(srcdir)/history.pod > $@ -@DEV@ -@DEV@LICENSE: $(srcdir)/license.pod -@DEV@ pod2text -l -i0 $(srcdir)/license.pod | sed '1,2d' > $@ - -sudoers: $(srcdir)/sudoers.in - (cd $(top_builddir) && $(SHELL) config.status --file=plugins/sudoers/$@) - -# 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 default > $@.tmp; then \ + mv -f $@.tmp $@; \ + else \ + rm -f $@.tmp; \ + fi; \ fi -install: install-dirs install-binaries @INSTALL_NOEXEC@ install-sudoers install-doc - -install-dirs: - $(SHELL) $(srcdir)/mkinstalldirs $(DESTDIR)$(sudodir) \ - $(DESTDIR)$(visudodir) $(DESTDIR)$(noexecdir) \ - $(DESTDIR)$(sudoersdir) $(DESTDIR)$(docdir) \ - $(DESTDIR)$(mandirsu) $(DESTDIR)$(mandirform) - $(SHELL) $(srcdir)/mkinstalldirs -m 0700 $(DESTDIR)$(timedir) - -install-binaries: install-dirs $(PROGS) - $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 04111 sudo $(DESTDIR)$(sudodir)/sudo - rm -f $(DESTDIR)$(sudodir)/sudoedit - ln $(DESTDIR)$(sudodir)/sudo $(DESTDIR)$(sudodir)/sudoedit - if [ -f sudoreplay ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sudoreplay $(DESTDIR)$(sudodir)/sudoreplay; fi - $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 visudo $(DESTDIR)$(visudodir)/visudo - if [ -f sesh ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sesh $(DESTDIR)$(libexecdir)/sesh; fi - -install-noexec: install-dirs libsudo_noexec.la - if [ -f .libs/lib$(noexecfile) ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0755 .libs/lib$(noexecfile) $(DESTDIR)$(noexecdir)/$(noexecfile); fi - -install-sudoers: install-dirs - $(INSTALL) -d -O $(sudoers_uid) -G $(sudoers_gid) -M 0750 \ - $(DESTDIR)$(sudoersdir)/sudoers.d - test -f $(DESTDIR)$(sudoersdir)/sudoers || \ - $(INSTALL) -O $(sudoers_uid) -G $(sudoers_gid) -M $(sudoers_mode) \ - sudoers $(DESTDIR)$(sudoersdir)/sudoers - -install-doc: install-dirs ChangeLog - (cd $(srcdir) && for f in ChangeLog HISTORY LICENSE NEWS README TROUBLESHOOTING UPGRADE sample.*; do $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $$f $(DESTDIR)$(docdir); done) - @LDAP@(cd $(srcdir) && for f in README.LDAP schema.* sudoers2ldif; do $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 $$f $(DESTDIR)$(docdir); done) - $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudo.$(mantype) $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) - @rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) - ln $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) - @REPLAY@$(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoreplay.$(mantype) $(DESTDIR)$(mandirsu)/sudoreplay.$(mansectsu) - $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/visudo.$(mantype) $(DESTDIR)$(mandirsu)/visudo.$(mansectsu) - $(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoers.$(mantype) $(DESTDIR)$(mandirform)/sudoers.$(mansectform) - @LDAP@$(INSTALL) -O $(install_uid) -G $(install_gid) -M 0444 @mansrcdir@/sudoers.ldap.$(mantype) $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform) -@MAN_POSTINSTALL@ - -check: - @echo nothing to check - -clean: - -rm -f *.a *.o *.lo stamp-* varsub $(PROGS) testsudoers core *.core core.* +config.status: + @if [ ! -s config.status ]; then \ + echo "Please run configure first"; \ + exit 1; \ + fi -mostlyclean: clean +libtool: $(LIBTOOL_DEPS) + $(SHELL) ./config.status --recheck + +Makefile: $(srcdir)/Makefile.in + ./config.status --file Makefile + +sync-po: rsync-po compile-po + +rsync-po: + rsync -Lrtvz translationproject.org::tp/latest/sudo/ src/po/ + rsync -Lrtvz translationproject.org::tp/latest/sudoers/ plugins/sudoers/po/ + +update-pot: + @if $(XGETTEXT) --help >/dev/null 2>&1; then \ + cd $(top_srcdir); \ + for pot in $(POTFILES); do \ + echo "Updating $$pot"; \ + domain=`basename $$pot .pot`; \ + case "$$domain" in \ + sudo) cfiles="src/*c common/*c compat/*c";; \ + sudoers) cfiles="plugins/sudoers/*.c plugins/sudoers/auth/*.c";; \ + *) echo unknown domain $$domain; continue;; \ + esac; \ + $(XGETTEXT) $(XGETTEXT_OPTS) -d$$domain $$cfiles -o $$pot.tmp; \ + if diff -I'^.POT-Creation-Date' -I'^.Project-Id-Version' -I'^#' $$pot.tmp $$pot >/dev/null; then \ + rm -f $$pot.tmp; \ + else \ + mv -f $$pot.tmp $$pot; \ + fi; \ + done; \ + fi -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 +update-po: update-pot + @if $(MSGFMT) --help >/dev/null 2>&1; then \ + cd $(top_srcdir); \ + for pot in $(POTFILES); do \ + podir=`dirname $$pot`; \ + for po in $$podir/*.po; do \ + echo $(ECHO_N) "Updating $$po$(ECHO_C)"; \ + $(MSGMERGE) --update $$po $$pot; \ + $(MSGFMT) --output /dev/null --check-format $$po || exit 1; \ + done; \ + done; \ + fi -clobber: distclean +compile-po: + @if $(MSGFMT) --help >/dev/null 2>&1; then \ + cd $(top_srcdir); \ + rm -f Makefile.$$$$; \ + POFILES=""; \ + for pot in $(POTFILES); do \ + podir=`dirname $$pot`; \ + for po in $$podir/*.po; do \ + POFILES="$$POFILES $$po"; \ + done; \ + done; \ + echo "all: `echo $$POFILES | sed 's/\.po/.mo/g'`" >> Makefile.$$$$; \ + echo "" >> Makefile.$$$$; \ + for po in $$POFILES; do \ + mo=`echo $$po | sed 's/po$$/mo/'`; \ + echo "$$mo: $$po" >> Makefile.$$$$; \ + echo " $(MSGFMT) --statistics -c -o $$mo $$po" >> Makefile.$$$$; \ + done; \ + make -f Makefile.$$$$; \ + rm -f Makefile.$$$$; \ + fi -realclean: distclean - rm -f TAGS tags +install-nls: + @if test "$(NLS)" = "enabled"; then \ + cd $(top_srcdir); \ + for pot in $(POTFILES); do \ + podir=`dirname $$pot`; \ + domain=`basename $$pot .pot`; \ + SUDO_LINGUAS=$${LINGUAS-"`echo $$podir/*.mo|sed 's:'$$podir'/\([^ ]*\).mo:\1:g'`"}; \ + echo $(ECHO_N) "Installing $$domain message catalogs:$(ECHO_C)"; \ + for lang in $$SUDO_LINGUAS; do \ + test -s $$podir/$$lang.mo || continue; \ + echo $(ECHO_N) " $$lang$(ECHO_C)"; \ + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 $$podir/$$lang.mo $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$$domain.mo; \ + done; \ + echo ""; \ + done; \ + fi -cleandir: realclean +check-dist: update-pot compile-po + @if [ -d .hg ]; then \ + if hg stat -am | grep '\.[mp]ot*$$'; then \ + echo "Uncommitted message catalog changes" 1>&2; \ + false; \ + fi; \ + fi -dist: ChangeLog +dist: check-dist ChangeLog $(srcdir)/MANIFEST pax -w -x ustar -s '/^/$(PACKAGE_TARNAME)-$(VERSION)\//' \ - -f ../$(PACKAGE_TARNAME)-$(VERSION).tar $(DISTFILES) + -f ../$(PACKAGE_TARNAME)-$(VERSION).tar \ + `sed 's/[ ].*//' $(srcdir)/MANIFEST` gzip -9f ../$(PACKAGE_TARNAME)-$(VERSION).tar ls -l ../$(PACKAGE_TARNAME)-$(VERSION).tar.gz @@ -550,8 +266,10 @@ package: sudo.pp bindir=$(bindir) \ sbindir=$(sbindir) \ libexecdir=$(libexecdir) \ + includedir=$(includedir) \ timedir=$(timedir) \ mandir=$(mandir) \ + localedir=$(localedir) \ docdir=$(docdir) \ sysconfdir=$(sysconfdir) \ sudoersdir=$(sudoersdir) \ @@ -560,4 +278,24 @@ package: sudo.pp sudoers_mode=$(sudoers_mode) \ version=$(VERSION) $(PPVARS) -.PHONY: ChangeLog +clean: config.status + for d in $(SUBDIRS) $(SAMPLES); do \ + (cd $$d && exec $(MAKE) $@); \ + done + +mostlyclean: clean + +distclean: config.status + for d in $(SUBDIRS) $(SAMPLES); do \ + (cd $$d && exec $(MAKE) $@); \ + done + -rm -rf Makefile pathnames.h config.h config.status config.cache \ + config.log libtool stamp-* autom4te.cache + +cleandir: distclean + +clobber: distclean + +realclean: distclean + +.PHONY: ChangeLog diff --git a/NEWS b/NEWS index 21d4e61..34e7b9a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,609 @@ +What's new in Sudo 1.8.5p2? + + * Fixed use of the SUDO_ASKPASS environment variable which was + broken in Sudo 1.8.5. + + * Fixed a problem reading the sudoers file when the file mode is + more restrictive than the expected mode. For example, when the + expected sudoers file mode is 0440 but the actual mode is 0400. + +What's new in Sudo 1.8.5p1? + + * Fixed a bug that prevented files in an include directory from + being evaluated. + +What's new in Sudo 1.8.5? + + * When "noexec" is enabled, sudo_noexec.so will now be prepended + to any existing LD_PRELOAD variable instead of replacing it. + + * The sudo_noexec.so shared library now wraps the execvpe(), + exect(), posix_spawn() and posix_spawnp() functions. + + * The user/group/mode checks on sudoers files have been relaxed. + As long as the file is owned by the sudoers uid, not world-writable + and not writable by a group other than the sudoers gid, the file + is considered OK. Note that visudo will still set the mode to + the value specified at configure time. + + * It is now possible to specify the sudoers path, uid, gid and + file mode as options to the plugin in the sudo.conf file. + + * Croatian, Galician, German, Lithuanian, Swedish and Vietnamese + translations from translationproject.org. + + * /etc/environment is no longer read directly on Linux systems + when PAM is used. Sudo now merges the PAM environment into the + user's environment which is typically set by the pam_env module. + + * The initial evironment created when env_reset is in effect now + includes the contents of /etc/environment on AIX systems and the + "setenv" and "path" entries from /etc/login.conf on BSD systems. + + * The plugin API has been extended in three ways. First, options + specified in sudo.conf after the plugin pathname are passed to + the plugin's open function. Second, sudo has limited support + for hooks that can be used by plugins. Currently, the hooks are + limited to environment handling functions. Third, the init_session + policy plugin function is passed a pointer to the user environment + which can be updated during session setup. The plugin API version + has been incremented to version 1.2. See the sudo_plugin manual + for more information. + + * The policy plugin's init_session function is now called by the + parent sudo process, not the child process that executes the + command. This allows the PAM session to be open and closed in + the same process, which some PAM modules require. + + * Fixed parsing of "Path askpass" and "Path noexec" in sudo.conf, + which was broken in version 1.8.4. + + * On systems with an SVR4-style /proc file system, the /proc/pid/psinfo + file is now uses to determine the controlling terminal, if possible. + This allows tty-based tickets to work properly even when, e.g. + standard input, output and error are redirected to /dev/null. + + * The output of "sudoreplay -l" is now sorted by file name (or + sequence number). Previously, entries were displayed in the + order in which they were found on the file system. + + * Sudo now behaves properly when I/O logging is enabled and the + controlling terminal is revoked (e.g. the running sshd is killed). + Previously, sudo may have exited without calling the I/O plugin's + close function which can lead to an incomplete I/O log. + + * Sudo can now detect when a user has logged out and back in again + on Solaris 11, just like it can on Solaris 10. + + * The built-in zlib included with Sudo has been upgraded to version + 1.2.6. + + * Setting the SSL parameter to start_tls in ldap.conf now works + properly when using Mozilla-based SDKs that support the + ldap_start_tls_s() function. + + * The TLS_CHECKPEER parameter in ldap.conf now works when the + Mozilla NSS crypto backend is used with OpenLDAP. + + * A new group provider plugin, system_group, is included which + performs group look ups by name using the system groups database. + This can be used to restore the pre-1.7.3 sudo group lookup + behavior. + +What's new in Sudo 1.8.4p5? + + * Fixed a bug when matching against an IP address with an associated + netmask in the sudoers file. In certain circumstances, this + could allow users to run commands on hosts they are not authorized + for. + +What's new in Sudo 1.8.4p4? + + * Fixed a bug introduced in Sudo 1.8.4 which prevented "sudo -v" + from working. + +What's new in Sudo 1.8.4p3? + + * Fixed a crash on FreeBSD when no tty is present. + + * Fixed a bug introduced in Sudo 1.8.4 that allowed users to + specify environment variables to set on the command line without + having sudo "ALL" permissions or the "SETENV" tag. + + * When visudo is run with the -c (check) option, the sudoers + file(s) owner and mode are now also checked unless the -f option + was specified. + +What's new in Sudo 1.8.4p2? + + * Fixed a bug introduced in Sudo 1.8.4 where insufficient space + was allocated for group IDs in the LDAP filter. + + * Fixed a bug introduced in Sudo 1.8.4 where the path to sudo.conf + was "/sudo.conf" instead of "/etc/sudo.conf". + + * Fixed a bug introduced in Sudo 1.8.4 which could cause a hang + when I/O logging is enabled and input is from a pipe or file. + +What's new in Sudo 1.8.4p1? + + * Fixed a bug introduced in sudo 1.8.4 that broke adding to or + deleting from the env_keep, env_check and env_delete lists in + sudoers on some platforms. + +What's new in Sudo 1.8.4? + + * The -D flag in sudo has been replaced with a more general debugging + framework that is configured in sudo.conf. + + * Fixed a false positive in visudo strict mode when aliases are + in use. + + * Fixed a crash with "sudo -i" when a runas group was specified + without a runas user. + + * The line on which a syntax error is reported in the sudoers file + is now more accurate. Previously it was often off by a line. + + * Fixed a bug where stack garbage could be printed at the end of + the lecture when the "lecture_file" option was enabled. + + * "make install" now honors the LINGUAS environment variable. + + * The #include and #includedir directives in sudoers now support + relative paths. If the path is not fully qualified it is expected + to be located in the same directory of the sudoers file that is + including it. + + * Serbian and Spanish translations for sudo from translationproject.org. + + * LDAP-based sudoers may now access by group ID in addition to + group name. + + * visudo will now fix the mode on the sudoers file even if no changes + are made unless the -f option is specified. + + * The "use_loginclass" sudoers option works properly again. + + * On systems that use login.conf, "sudo -i" now sets environment + variables based on login.conf. + + * For LDAP-based sudoers, values in the search expression are now + escaped as per RFC 4515. + + * The plugin close function is now properly called when a login + session is killed (as opposed to the actual command being killed). + This can happen when an ssh session is disconnected or the + terminal window is closed. + + * The deprecated "noexec_file" sudoers option is no longer supported. + + * Fixed a race condition when I/O logging is not enabled that could + result in tty-generated signals (e.g. control-C) being received + by the command twice. + + * If none of the standard input, output or error are connected to + a tty device, sudo will now check its parent's standard input, + output or error for the tty name on systems with /proc and BSD + systems that support the KERN_PROC_PID sysctl. This allows + tty-based tickets to work properly even when, e.g. standard + input, output and error are redirected to /dev/null. + + * Added the --enable-kerb5-instance configure option to allow + people using Kerberos V authentication to specify a custom + instance so the principal name can be, e.g. "username/sudo" + similar to how ksu uses "username/root". + + * Fixed a bug where a pattern like "/usr/*" included /usr/bin/ in + the results, which would be incorrectly be interpreted as if the + sudoers file had specified a directory. + + * "visudo -c" will now list any include files that were checked + in addition to the main sudoers file when everything parses OK. + + * Users that only have read-only access to the sudoers file may + now run "visudo -c". Previously, write permissions were required + even though no writing is down in check-only mode. + + * It is now possible to prevent the disabling of core dumps from + within sudo itself by adding a line to the sudo.conf file like + "Set disable_coredump false". + +What's new in Sudo 1.8.3p2? + + * Fixed a format string vulnerability when the sudo binary (or a + symbolic link to the sudo binary) contains printf format escapes + and the -D (debugging) flag is used. + +What's new in Sudo 1.8.3p1? + + * Fixed a crash in the monitor process on Solaris when NOPASSWD + was specified or when authentication was disabled. + + * Fixed matching of a Runas_Alias in the group section of a + Runas_Spec. + +What's new in Sudo 1.8.3? + + * Fixed expansion of strftime() escape sequences in the "log_dir" + sudoers setting. + + * Esperanto, Italian and Japanese translations from translationproject.org. + + * Sudo will now use PAM by default on AIX 6 and higher. + + * Added --enable-werror configure option for gcc's -Werror flag. + + * Visudo no longer assumes all editors support the +linenumber + command line argument. It now uses a whitelist of editors known + to support the option. + + * Fixed matching of network addresses when a netmask is specified + but the address is not the first one in the CIDR block. + + * The configure script now check whether or not errno.h declares + the errno variable. Previously, sudo would always declare errno + itself for older systems that don't declare it in errno.h. + + * The NOPASSWD tag is now honored for denied commands too, which + matches historic sudo behavior (prior to sudo 1.7.0). + + * Sudo now honors the "DEREF" setting in ldap.conf which controls + how alias dereferencing is done during an LDAP search. + + * A symbol conflict with the pam_ssh_agent_auth PAM module that + would cause a crash been resolved. + + * The inability to load a group provider plugin is no longer + a fatal error. + + * A potential crash in the utmp handling code has been fixed. + + * Two PAM session issues have been resolved. In previous versions + of sudo, the PAM session was opened as one user and closed as + another. Additionally, if no authentication was performed, the + PAM session would never be closed. + + * Sudo will now work correctly with LDAP-based sudoers using TLS + or SSL on Debian systems. + + * The LOGNAME, USER and USERNAME environment variables are preserved + correctly again in sudoedit mode. + +What's new in Sudo 1.8.2? + + * Sudo, visudo, sudoreplay and the sudoers plug-in now have natural + language support (NLS). This can be disabled by passing configure + the --disable-nls option. Sudo will use gettext(), if available, + to display translated messages. All translations are coordinated + via The Translation Project, http://translationproject.org/. + + * Plug-ins are now loaded with the RTLD_GLOBAL flag instead of + RTLD_LOCAL. This fixes missing symbol problems in PAM modules + on certain platforms, such as FreeBSD and SuSE Linux Enterprise. + + * I/O logging is now supported for commands run in background mode + (using sudo's -b flag). + + * Group ownership of the sudoers file is now only enforced when + the file mode on sudoers allows group readability or writability. + + * Visudo now checks the contents of an alias and warns about cycles + when the alias is expanded. + + * If the user specifies a group via sudo's -g option that matches + the target user's group in the password database, it is now + allowed even if no groups are present in the Runas_Spec. + + * The sudo Makefiles now have more complete dependencies which are + automatically generated instead of being maintained manually. + + * The "use_pty" sudoers option is now correctly passed back to the + sudo front end. This was missing in previous versions of sudo + 1.8 which prevented "use_pty" from being honored. + + * "sudo -i command" now works correctly with the bash version + 2.0 and higher. Previously, the .bash_profile would not be + sourced prior to running the command unless bash was built with + NON_INTERACTIVE_LOGIN_SHELLS defined. + + * When matching groups in the sudoers file, sudo will now match + based on the name of the group instead of the group ID. This can + substantially reduce the number of group lookups for sudoers + files that contain a large number of groups. + + * Multi-factor authentication is now supported on AIX. + + * Added support for non-RFC 4517 compliant LDAP servers that require + that seconds be present in a timestamp, such as Tivoli Directory Server. + + * If the group vector is to be preserved, the PATH search for the + command is now done with the user's original group vector. + + * For LDAP-based sudoers, the "runas_default" sudoOption now works + properly in a sudoRole that contains a sudoCommand. + + * Spaces in command line arguments for "sudo -s" and "sudo -i" are + now escaped with a backslash when checking the security policy. + +What's new in Sudo 1.8.1p2? + + * Two-character CIDR-style IPv4 netmasks are now matched correctly + in the sudoers file. + + * A build error with MIT Kerberos V has been resolved. + + * A crash on HP-UX in the sudoers plugin when wildcards are + present in the sudoers file has been resolved. + + * Sudo now works correctly on Tru64 Unix again. + +What's new in Sudo 1.8.1p1? + + * Fixed a problem on AIX where sudo was unable to set the final + uid if the PAM module modified the effective uid. + + * A non-existent includedir is now treated the same as an empty + directory and not reported as an error. + + * Removed extraneous parens in LDAP filter when sudoers_search_filter + is enabled that can cause an LDAP search error. + + * Fixed a "make -j" problem for "make install". + +What's new in Sudo 1.8.1? + + * A new LDAP setting, sudoers_search_filter, has been added to + ldap.conf. This setting can be used to restrict the set of + 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. + + * Sudo will now create an entry in the utmp (or utmpx) file when + allocating a pseudo-tty (e.g. when logging I/O). The "set_utmp" + and "utmp_runas" sudoers file options can be used to control this. + Other policy plugins may use the "set_utmp" and "utmp_user" + entries in the command_info list. + + * The sudoers policy now stores the TSID field in the logs + even when the "iolog_file" sudoers option is defined to a value + other than %{sessid}. Previously, the TSID field was only + included in the log file when the "iolog_file" option was set + to its default value. + + * The sudoreplay utility now supports arbitrary session IDs. + Previously, it would only work with the base-36 session IDs + that the sudoers plugin uses by default. + + * Sudo now passes "run_shell=true" to the policy plugin in the + settings list when sudo's -s command line option is specified. + The sudoers policy plugin uses this to implement the "set_home" + sudoers option which was missing from sudo 1.8.0. + + * The "noexec" functionality has been moved out of the sudoers + policy plugin and into the sudo front-end, which matches the + behavior documented in the plugin writer's guide. As a result, + the path to the noexec file is now specified in the sudo.conf + file instead of the sudoers file. + + * On Solaris 10, the PRIV_PROC_EXEC privilege is now used to + implement the "noexec" feature. Previously, this was implemented + via the LD_PRELOAD environment variable. + + * The exit values for "sudo -l", "sudo -v" and "sudo -l command" + have been fixed in the sudoers policy plugin. + + * The sudoers policy plugin now passes the login class, if any, + back to the sudo front-end. + + * The sudoers policy plugin was not being linked with requisite + libraries in certain configurations. + + * Sudo now parses command line arguments before loading any plugins. + This allows "sudo -V" or "sudo -h" to work even if there is a problem + with sudo.conf + + * Plugins are now linked with the static version of libgcc to allow + the plugin to run on a system where no shared libgcc is installed, + or where it is installed in a different location. + +What's new in Sudo 1.8.0? + + * Sudo has been refactored to use a modular framework that can + support third-party policy and I/O logging plugins. The default + plugin is "sudoers" which provides the traditional sudo functionality. + See the sudo_plugin manual for details on the plugin API and the + sample in the plugins directory for a simple example. + +What's new in Sudo 1.7.5? + + * When using visudo in check mode, a file named "-" may be used to + 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 + visual artifacts in full-screen programs such as text editors. + +What's new in Sudo 1.7.4p5? + + * A bug has been fixed that would allow a command to be run without the + user entering a password when sudo's -g flag is used without the -u flag. + + * If user has no supplementary groups, sudo will now fall back on checking + the group file explicitly, which restores historic sudo behavior. + + * A crash has been fixed when sudo's -g flag is used without the -u flag + and the sudoers file contains an entry with no runas user or group listed. + + * A crash has been fixed when the Solaris project support is enabled + and sudo's -g flag is used without the -u flag. + + * Sudo no longer exits with an error when support for auditing is + compiled in but auditing is not enabled. + + * Fixed a bug introduced in sudo 1.7.3 where the ticket file was not + being honored when the "targetpw" sudoers Defaults option was enabled. + + * The LOG_INPUT and LOG_OUTPUT tags in sudoers are now parsed correctly. + + * A crash has been fixed in "sudo -l" when sudo is built with auditing + support and the user is not allowed to run any commands on the host. + +What's new in Sudo 1.7.4p4? + + * A potential security issue has been fixed with respect to the handling + of sudo's -g command line option when -u is also specified. The flaw + may allow an attacker to run commands as a user that is not authorized + by the sudoers file. + + * A bug has been fixed where "sudo -l" output was incomplete if multiple + sudoers sources were defined in nsswitch.conf and there was an error + querying one of the sources. + + * The log_input, log_output, and use_pty sudoers options now work correctly + on AIX. Previously, sudo would hang if they were enabled. + + * The "make install" target now works correctly when sudo is built in a + directory other than the source directory. + + * The "runas_default" sudoers setting now works properly in a per-command + Defaults line. + + * Suspending and resuming the bash shell when PAM is in use now works + correctly. The SIGCONT signal was not propagated to the child process. + +What's new in Sudo 1.7.4p3? + + * A bug has been fixed where duplicate HOME environment variables could be + present when the env_reset setting was disabled and the always_set_home + setting was enabled in sudoers. + + * The value of sysconfdir is now substituted into the path to the sudoers.d + directory in the installed sudoers file. + + * Compilation problems on IRIX and other platforms have been fixed. + + * If multiple PAM "auth" actions are specified and the user enters ^C at + the password prompt, sudo will no longer prompt for a password for any + subsequent "auth" actions. Previously it was necessary to enter ^C for + each "auth" action. + +What's new in Sudo 1.7.4p2? + + * A bug where sudo could spin in a busy loop waiting for the child process + has been fixed. + +What's new in Sudo 1.7.4p1? + + * A bug introduced in sudo 1.7.3 that prevented the -k and -K options from + functioning when the tty_tickets sudoers option is enabled has been fixed. + + * Sudo no longer prints a warning when the -k or -K options are specified + and the ticket file does not exist. + + * It is now easier to cross-compile sudo. + What's new in Sudo 1.7.4? * Sudoedit will now preserve the file extension in the name of the diff --git a/PORTING b/PORTING deleted file mode 100644 index 861e0c0..0000000 --- a/PORTING +++ /dev/null @@ -1,85 +0,0 @@ -Sudo porting hints -================== - -Before trying to port sudo to a new architecture, please join the -sudo-workers mailing list (see the README file) and ask if anyone -has a port working or in-progress. Sudo should be fairly easy to -port. Since it uses a configure script, most of the work is often -done for you. As long as your operating system is reasonably POSIX -compliant porting should be easy. If your operating system has a -separate library for POSIX compatibility you may need to add it by -using configure's --with-libraries option. - -If your OS is an SVR4 derivative (or some approximation thereof), it may -be sufficient to tell configure you are runnng SVR4, something like: - configure foo-bar-sysv4 -where foo is the hardware architecture and bar is the vendor. - -A possible pitfall is getdtablesize(2) which is used to get the -maximum number of open files the process can have. If an OS has -the POSIX sysconf(2) it will be used instead of getdtablesize(2). -ulimit(2) or getrlimit(2) can also be used on some OS's. If all -else fails you can use the value of NOFILE in . - -Sudo tries to clear the environment of dangerous environment variables -such as LD_* to prevent shared library spoofing. If you are porting -sudo to a new OS that has shared libraries you'll want to mask out -the variables that allow one to change the shared library path. -See initial_badenv_table() in env.c to see how this is done for -various operating systems. - -It is possible that on a really weird system, tgetpass() may not -compile. (The most common cause for this is that the "fd_set" type -is not defined in a place that sudo expects it to be. If you can -find the header file where "fd_set" is typedef'd, have tgetpass.c -include it and send in a bug report.) -Alternately, tgetpass.c may compile but not work (nothing happens -at the Password: prompt). It is possible that your C library -contains a broken or unusable crypt() function--try linking with --lcrypt if that exists. Another possibility is that select() is -not fully functional; running configure with --with-password-timeout=0 -will disable the use of select(). If sudo prompts you for a -password but never accepts it, see below. - -Sudo detects and recognizes most common shadow password schemes -automatically. If you find that sudo is not accepting your password -and you are sure that it has been typed in correctly there are two -likely problems. One possibility is that your C library has a -broken crypt() function (see above). The other is that your operating -system is using shadow passwords and sudo has not detected that -fact. Look in config.h to see what, if any, shadow password scheme -was detected. The most common are SVR4 (HAVE_GETSPNAM will be -defined) and SecureWare (HAVE_GETPRPWNAM will be defined). Check -the manual pages on your system for "getspnam" and "getprpwnam". -If one of those exist but the appropriate define does not exist in -config.h then the problem is most likely that those routines live -in a library that sudo does not know to link against. The manual -page should tell you what library this is. You can then use the ---with-libraries option to configure to tell sudo to link with the -library in question. For example: - --with-libraries='-lgen' -would cause sudo to link in libgen which contains "getspnam" on SCO -systems. - -If you are trying to port to a system without standard Berkeley -networking you may find that interfaces.c will not compile. This -is most likely on OS's with STREAMS-based networking. It should -be possible to make it work by modifying the ISC streams support -(see the _ISC #ifdef's). However, if you don't care about ip address -and network address support, you can just run configure with the ---without-interfaces flag to get a do-nothing load_interfaces() -stub function. - -Sudo wants POSIX signals (sigaction and friends). If your system -lacks sigaction but has the 4.3BSD sigvec() function, sigvec() will -be used instead via the wrapper functions in sigaction.c. It is -not currently possible to use the old SVR3 and 4.2BSD signals, but -this is due more to my lack of a test machine than anything else. - -If you port sudo to a new architecture, please send the output of -"configure", the config.log file and your changes to: - sudo@courtesan.com - -If you are unable to get sudo working, and you are willing to -give me an account on a machine, send mail to sudo@courtesan.com. -Note, however, that I can't make any promises. diff --git a/README b/README index 4f6f454..d5a0b22 100644 --- a/README +++ b/README @@ -1,5 +1,3 @@ -This is Sudo version 1.7.4 - The sudo philosophy =================== Sudo is a program designed to allow a sysadmin to give limited root privileges @@ -13,11 +11,10 @@ version. The latest sudo may always be gotten via anonymous ftp from ftp.sudo.ws in the directory /pub/sudo/ or from the sudo web site, http://www.sudo.ws/ -The distribution is sudo-M.m.tar.gz where `M' is the major -version number and `m' is the minor version number. -BETA versions of sudo may also be available. If you join -the `sudo-workers' mailing list you will get the BETA announcements -(see the `Mailing lists' section below). +The distribution is sudo-M.m.tar.gz where `M' is the major version +number and `m' is the minor version number. BETA versions of sudo may +also be available. If you join the `sudo-workers' mailing list you +will get the BETA announcements (see the `Mailing lists' section below). What's new ========== @@ -27,24 +24,25 @@ summary of major changes to the current stable release, see the web page, http://www.sudo.ws/sudo/stable.html. If you are upgrading from an earlier version of Sudo, please see -the UPGRADE file. +the UPGRADE file in the doc directory. -For a history of sudo please see the HISTORY file. +For a history of sudo please see the HISTORY file in the doc directory. +You can find a list of contributors to sudo in the doc/CONTRIBUTORS file. 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. +To build sudo from the source distribution you need a POSIX-compliant +operating system (any modern version of BSD, Linux or Unix should +work), an ANSI/ISO C compiler that supports variadic marcos (a C99 +feature) 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 tokenizer and pre-yacc'd grammar parser). You'll also have to uncomment a few lines from the Makefile or run configure with the ---with-devel option. You can get flex via anonymous ftp from -ftp://ftp.ee.lbl.gov/pub/flex* as well as any GNU mirror. You can -get GNU bison from ftp://ftp.gnu.org/pub/gnu/bison/ or any GNU -mirror. +--with-devel option. You can get flex from http://flex.sourceforge.net/. +You can get GNU bison from ftp://ftp.gnu.org/pub/gnu/bison/ or any +GNU mirror. Building the release ==================== @@ -92,6 +90,7 @@ Bug reports If you have found what you believe to be a bug, you can file a bug report in the sudo bug database, on the web at http://www.sudo.ws/bugs/. -Please read over the `TROUBLESHOOTING' file *before* submitting a bug -report. When reporting bugs, please be sure to include the version of -sudo you are using as well as the platform you are running it on. +Please read over the `TROUBLESHOOTING' file in the doc directory *before* +submitting a bug report. When reporting bugs, please be sure to include +the version of sudo you are using as well as the platform you are running +it on. diff --git a/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 deleted file mode 100644 index 57e2012..0000000 --- a/TROUBLESHOOTING +++ /dev/null @@ -1,191 +0,0 @@ -Troubleshooting tips and FAQ for Sudo -===================================== - -Q) When I run configure, it says "C compiler cannot create executables". -A) This usually means you either don't have a working compiler. This - could be due to the lack of a license or that some component of the - compiler suite could not be found. Check config.log for clues as - to why this is happening. On many systems, compiler components live - in /usr/ccs/bin which may not be in your PATH environment variable. - -Q) Sudo compiles but when I run it I get "Sorry, sudo must be setuid root." - and sudo quits. -A) Sudo must be setuid root to do its work. You need to do something like - `chmod 4111 /usr/local/bin/sudo'. Also, the file system sudo resides - on must *not* be mounted (or exported) with the nosuid option or sudo - will not be able to work. Another possibility is you may have '.' in - your $PATH before the directory containing sudo. If you are going - to have '.' in your path you should make sure it is at the end. - -Q) Sudo never gives me a chance to enter a password using PAM, it just - says 'Sorry, try again.' three times and exits. -A) You didn't setup PAM to work with sudo. On Redhat Linux or Fedora - Core this generally means installing sample.pam as /etc/pam.d/sudo. - See the sample.pam file for hints on what to use for other Linux - systems. - -Q) Sudo says 'Account expired or PAM config lacks an "account" - section for sudo, contact your system administrator' and exits - but I know my account has not expired. -A) Your PAM config lacks an "account" specification. On Linux this - usually means you are missing a line like: - account required pam_unix.so - in /etc/pam.d/sudo. - -Q) Sudo is setup to log via syslog(3) but I'm not getting any log - messages. -A) Make sure you have an entry in your syslog.conf file to save - the sudo messages (see the sample.syslog.conf file). The default - log facility is authpriv (changeable via configure or in sudoers). - Don't forget to send a SIGHUP to your syslogd so that it re-reads - its conf file. Also, remember that syslogd does *not* create - log files, you need to create the file before syslogd will log - to it (ie: touch /var/log/sudo). - Note: the facility (e.g. "auth.debug") must be separated from the - destination (e.g. "/var/log/auth" or "@loghost") by - tabs, *not* spaces. This is a common error. - -Q) When sudo asks me for my password it never accepts what I enter even - though I know I entered my password correctly. -A) If your system uses shadow passwords, it is possible that sudo - didn't detect this. Take a look at the generated config.h file - and verify that the C function used for shadow password lookups - was detected. For instance, for SVR4-style shadow passwords, - HAVE_GETSPNAM should be defined (you can search for the string - "shadow passwords" in config.h with your editor). Note that - there is no define for 4.4BSD-based shadow passwords since that - just uses the standard getpw* routines. - -Q) I don't want the sudoers file in /etc, how can I specify where it - should go? -A) Use the --sysconfdir option to configure. Ie: - configure --sysconfdir=/dir/you/want/sudoers/in - -Q) Can I put the sudoers file in NIS/NIS+ or do I have to have a - copy on each machine? -A) There is no support for making an NIS/NIS+ map/table out of - the sudoers file at this time. A good way to distribute the - sudoers file is via rdist(1). It is also possible to NFS-mount - the sudoers file. - -Q) I don't run sendmail on my machine. Does this mean that I cannot - use sudo? -A) No, you just need to run use the --without-sendmail argument to configure - or add "!mailerpath" to the Defaults line in /etc/sudoers. - -Q) When I run visudo it uses vi as the editor and I hate vi. How - can I make it use another editor? -A) Your best bet is to run configure with the --with-env-editor switch. - This will make visudo use the editor specified by the user's - EDITOR environment variable. Alternately, you can run configure - with the --with-editor=/path/to/another/editor. - -Q) Sudo appears to be removing some variables from my environment, why? -A) Sudo removes the following "dangerous" environment variables - to guard against shared library spoofing, shell voodoo, and - kerberos server spoofing. - IFS - LOCALDOMAIN - RES_OPTIONS - HOSTALIASES - NLSPATH - PATH_LOCALE - TERMINFO - TERMINFO_DIRS - TERMPATH - TERMCAP - ENV - BASH_ENV - LC_ (if it contains a '/' or '%') - LANG (if it contains a '/' or '%') - LANGUAGE (if it contains a '/' or '%') - LD_* - _RLD_* - SHLIB_PATH (HP-UX only) - LIBPATH (AIX only) - KRB_CONF (kerb4 only) - KRBCONFDIR (kerb4 only) - KRBTKFILE (kerb4 only) - KRB5_CONFIG (kerb5 only) - VAR_ACE (SecurID only) - USR_ACE (SecurID only) - DLC_ACE (SecurID only) - -Q) How can I keep sudo from asking for a password? -A) To specify this on a per-user (and per-command) basis, use the 'NOPASSWD' - tag right before the command list in sudoers. See the sudoers man page - and sample.sudoers for details. To disable passwords completely, - run configure with the --without-passwd option or add "!authenticate" - to the Defaults line in /etc/sudoers. You can also turn off authentication - on a per-user or per-host basis using a user or host-specific Defaults - entry in sudoers. - -Q) When I run configure, it dies with the following error: - "no acceptable cc found in $PATH". -A) /usr/ucb/cc was the only C compiler that configure could find. - You need to tell configure the path to the "real" C compiler - via the --with-CC option. On Solaris, the path is probably - something like "/opt/SUNWspro/SC4.0/bin/cc". If you have gcc - that will also work. - -Q) When I run configure, it dies with the following error: - Fatal Error: config.cache exists from another platform! - Please remove it and re-run configure. -A) configure caches the results of its tests in a file called - config.cache to make re-running configure speedy. However, - if you are building sudo for a different platform the results - in config.cache will be wrong so you need to remove config.cache. - You can do this by "rm config.cache" or "make realclean". - Note that "make realclean" will also remove any object files - and configure temp files that are laying around as well. - -Q) I built sudo on a Solaris >= 2.6 machine but the resulting binary - doesn't work on Solaris <= 2.5.1. Why? -A) Starting with Solaris 2.6, snprintf(3) is included in the standard - C library. To build a version of sudo on a >= 2.6 machine that - will run on a <= 2.5.1 machine, edit config.h and comment out the lines: - #define HAVE_SNPRINTF 1 - #define HAVE_VSNPRINTF 1 - and run make. - -Q) When I run "visudo" it says "sudoers file busy, try again later." - and doesn't do anything. -A) Someone else is currently editing the sudoers file with visudo. - -Q) When I try to use "cd" with sudo it says "cd: command not found". -A) "cd" is a shell built-in command, you can't run it as a command - since a child process (sudo) cannot affect the current working - directory of the parent (your shell). - -Q) When I try to use "cd" with sudo the command completes without - errors but nothing happens. -A) Even though "cd" is a shell built-in command, some operating systems - include a /usr/bin/cd command for some reason. A standalone - "cd" command is totally useless since a child process (cd) cannot - affect the current working directory of the parent (your shell). - Thus, "sudo cd /foo" will start a child process, change the - directory and immediately exit without doing anything useful. - -Q) When I run sudo it says I am not allowed to run the command as root - but I don't want to run it as root, I want to run it as another user. - My sudoers file entry looks like: - bob ALL=(oracle) ALL -A) The default user sudo tries to run things as is always root, even if - the invoking user can only run commands as a single, specific user. - This may change in the future but at the present time you have to - work around this using the 'runas_default' option in sudoers. - For example: - Defaults:bob runas_default=oracle - would achieve the desired result ofr the preceding sudoers fragment. - -Q) When I try to run sudo via ssh, I get the error: - sudo: no tty present and no askpass program specified -A) ssh does not allocate a tty by default when running a remote command. - Without a tty, sudo cannot disable echo when prompting for a password. - You can use ssh's "-t" option to force it to allocate a tty. - Alternately, if you do not mind your password being echoed to the - screen, you can use the "visiblepw" sudoers option to allow this. - -Q) How do you pronounce `sudo'? -A) The official pronunciation is soo-doo (for su "do"). However, an - alternate pronunciation, a homophone of "pseudo", is also common. diff --git a/UPGRADE b/UPGRADE deleted file mode 100644 index fb27119..0000000 --- a/UPGRADE +++ /dev/null @@ -1,176 +0,0 @@ -Notes on upgrading from an older release -======================================== - -o Upgrading from a version prior to 1.7.4: - - Starting with sudo 1.7.4, the time stamp files have moved from - /var/run/sudo to either /var/db/sudo, /var/lib/sudo or /var/adm/sudo. - The directories are checked for existence in that order. This - prevents users from receiving the sudo lecture every time the - system reboots. Time stamp files older than the boot time are - ignored on systems where it is possible to determine this. - - Additionally, the tty_tickets sudoers option is now enabled by - default. To restore the old behavior (single time stamp per user), - add a line like: - Defaults !tty_tickets - to sudoers or use the --without-tty-tickets configure option. - - The HOME and MAIL environment variables are now reset based on the - target user's password database entry when the env_reset sudoers option - is enabled (which is the case in the default configuration). Users - wishing to preserve the original values should use a sudoers entry like: - Defaults env_keep += HOME - to preserve the old value of HOME and - Defaults env_keep += MAIL - to preserve the old value of MAIL. - - NOTE: preserving HOME has security implications since many programs - use when searching for configuration files. Adding HOME to env_keep - may enable a user to run unrestricted commands via sudo. - - The default syslog facility has changed from "local2" to "authpriv" - (or "auth" if the operating system doesn't have "authpriv"). - The --with-logfac configure option can be used to change this - or it can be changed in the sudoers file. - -o Upgrading from a version prior to 1.7.0: - - Starting with sudo 1.7.0, comments in the sudoers file must not - have a digit or minus sign immediately after the comment character - ('#'). Otherwise, the comment may be interpreted as a user or - group ID. - - When sudo is build with LDAP support the /etc/nsswitch.conf file is - now used to determine the sudoers seach order. sudo will default to - only using /etc/sudoers unless /etc/nsswitch.conf says otherwise. - This can be changed with an nsswitch.conf line, e.g.: - sudoers: ldap files - Would case LDAP to be searched first, then the sudoers file. - To restore the pre-1.7.0 behavior, run configure with the - --with-nsswitch=no flag. - - Sudo now ignores user .ldaprc files as well as system LDAP defaults. - All LDAP configuration is now in /etc/ldap.conf (or whichever file - was specified by configure's --with-ldap-conf-file option). - If you are using TLS, you may now need to specify: - tls_checkpeer no - in sudo's ldap.conf unless ldap.conf references a valid certificate - authority file(s). - - Please also see the NEWS file for a list of new features in - sudo 1.7.0. - -o Upgrading from a version prior to 1.6.9: - - Starting with sudo 1.6.9, if an OS supports a modular authentication - method such as PAM, it will be used by default by configure. - - Environment variable handling has changed significantly in sudo - 1.6.9. Prior to version 1.6.9, sudo would preserve the user's - environment, pruning out potentially dangerous variables. - Beginning with sudo 1.6.9, the envionment is reset to a default - set of values with only a small number of "safe" variables - preserved. To preserve specific environment variables, add - them to the "env_keep" list in sudoers. E.g. - - Defaults env_keep += "EDITOR" - - The old behavior can be restored by negating the "env_reset" - option in sudoers. E.g. - - Defaults !env_reset - - There have also been changes to how the "env_keep" and - "env_check" options behave. - - Prior to sudo 1.6.9, the TERM and PATH environment variables - would always be preserved even if the env_keep option was - redefined. That is no longer the case. Consequently, if - env_keep is set with "=" and not simply appended to (i.e. using - "+="), PATH and TERM must be explicitly included in the list - of environment variables to keep. The LOGNAME, SHELL, USER, - and USERNAME environment variables are still always set. - - Additionally, the env_check setting previously had no effect - when env_reset was set (which is now on by default). Starting - with sudo 1.6.9, environment variables listed in env_check are - also preserved in the env_reset case, provided that they do not - contain a '/' or '%' character. Note that it is not necessary - to also list a variable in env_keep--having it in env_check is - sufficent. - - The default lists of variables to be preserved and/or checked - are displayed when sudo is run by root with the -V flag. - -o Upgrading from a version prior to 1.6.8: - - Prior to sudo 1.6.8, if /var/run did not exist, sudo would put - the time stamp files in /tmp/.odus. As of sudo 1.6.8, the - time stamp files will be placed in /var/adm/sudo or /usr/adm/sudo - if there is no /var/run directory. This directory will be - created if it does not already exist. - - Previously, a sudoers entry that explicitly prohibited running - a command as a certain user did not override a previous entry - allowing the same command. This has been fixed in sudo 1.6.8 - such that the last match is now used (as it is documented). - Hopefully no one was depending on the previous (buggy) beghavior. - -o Upgrading from a version prior to 1.6: - - As of sudo 1.6, parsing of runas entries and the NOPASSWD tag - has changed. Prior to 1.6, a runas specifier applied only to - a single command directly following it. Likewise, the NOPASSWD - tag only allowed the command directly following it to be run - without a password. Starting with sudo 1.6, both the runas - specifier and the NOPASSWD tag are "sticky" for an entire - command list. So, given the following line in sudo < 1.6 - - millert ALL=(daemon) NOPASSWD:/usr/bin/whoami,/bin/ls - - millert would be able to run /usr/bin/whoami as user daemon - without a password and /bin/ls as root with a password. - - As of sudo 1.6, the same line now means that millert is able - to run run both /usr/bin/whoami and /bin/ls as user daemon - without a password. To expand on this, take the following - example: - - millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, (root) /bin/ls, \ - /sbin/dump - - millert can run /usr/bin/whoami as daemon and /bin/ls and - /sbin/dump as root. No password need be given for either - command. In other words, the "(root)" sets the default runas - user to root for the rest of the list. If we wanted to require - a password for /bin/ls and /sbin/dump the line could be written - thusly: - - millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, \ - (root) PASSWD:/bin/ls, /sbin/dump - - Additionally, sudo now uses a per-user time stamp directory - instead of a time stamp file. This allows tty time stamps to - simply be files within the user's time stamp dir. For the - default, non-tty case, the time stamp on the directory itself - is used. - - Also, the temporary file used by visudo is now /etc/sudoers.tmp - since some versions of vipw on systems with shadow passwords use - /etc/stmp for the temporary shadow file. - -o Upgrading from a version prior to 1.5: - - By default, sudo expects the sudoers file to be mode 0440 and - to be owned by user and group 0. This differs from version 1.4 - and below which expected the sudoers file to be mode 0400 and - to be owned by root. Doing a `make install' will set the sudoers - file to the new mode and group. If sudo encounters a sudoers - file with the old permissions it will attempt to update it to - the new scheme. You cannot, however, use a sudoers file with - the new permissions with an old sudo binary. It is suggested - that if have a means of distributing sudo you distribute the - new binaries first, then the new sudoers file (or you can leave - sudoers as is and sudo will fix the permissions itself as long - as sudoers is on a local file system). diff --git a/aclocal.m4 b/aclocal.m4 index 1276746..1a8f205 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 @@ -79,10 +79,28 @@ if test X"$found" != X"yes"; then fi ])dnl +dnl +dnl check for utmp file +dnl +AC_DEFUN([SUDO_PATH_UTMP], [AC_MSG_CHECKING([for utmp file path]) +found=no +for p in "/var/run/utmp" "/var/adm/utmp" "/etc/utmp"; do + if test -r "$p"; then + found=yes + AC_MSG_RESULT([$p]) + SUDO_DEFINE_UNQUOTED(_PATH_UTMP, "$p") + break + fi +done +if test X"$found" != X"yes"; then + AC_MSG_RESULT([not found]) +fi +])dnl + dnl dnl Where the log file goes, use /var/log if it exists, else /{var,usr}/adm dnl -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 +121,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,73 +139,27 @@ 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_REQUIRE([AC_HEADER_STDC])dnl -AC_MSG_CHECKING(for $1) -AC_CACHE_VAL(sudo_cv_type_$1, -[AC_EGREP_CPP($1, [#include -#include -#if STDC_HEADERS -#include -#endif -#if HAVE_UNISTD_H -#include -#endif], sudo_cv_type_$1=yes, sudo_cv_type_$1=no)])dnl -AC_MSG_RESULT($sudo_cv_type_$1) -if test $sudo_cv_type_$1 = no; then - AC_DEFINE($1, $2, [Define if your system lacks the $1 type.]) -fi -]) - -dnl -dnl Check for size_t declation -dnl -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, -[SUDO_CHECK_TYPE(ssize_t, int)]) - -dnl -dnl Check for dev_t declation -dnl -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, -[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 @@ -213,6 +185,28 @@ AC_DEFUN([SUDO_FUNC_ISBLANK], fi ]) +AC_DEFUN([SUDO_CHECK_LIB], [ + _sudo_check_lib_extras=`echo "$5"|sed -e 's/[ ]*//g' -e 's/-l/_/g'` + AC_MSG_CHECKING([for $2 in -l$1${5+ }$5]) + AC_CACHE_VAL([sudo_cv_lib_$1''_$2$_sudo_check_lib_extras], [ + SUDO_CHECK_LIB_OLIBS="$LIBS" + LIBS="$LIBS -l$1${5+ }$5" + AC_LINK_IFELSE( + [AC_LANG_CALL([], [$2])], + [eval sudo_cv_lib_$1''_$2$_sudo_check_lib_extras=yes], + [eval sudo_cv_lib_$1''_$2$_sudo_check_lib_extras=no] + ) + LIBS="$SUDO_CHECK_LIB_OLIBS" + ]) + if eval test \$sudo_cv_lib_$1''_$2$_sudo_check_lib_extras = "yes"; then + AC_MSG_RESULT([yes]) + $3 + else + AC_MSG_RESULT([no]) + $4 + fi +]) + dnl dnl check unsetenv() return value dnl @@ -238,7 +232,7 @@ dnl dnl check putenv() argument for const dnl AC_DEFUN([SUDO_FUNC_PUTENV_CONST], -[AC_CACHE_CHECK([whether putenv has a const argument], +[AC_CACHE_CHECK([whether putenv takes a const argument], sudo_cv_func_putenv_const, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT int putenv(const char *string) {return 0;}], [])], @@ -246,16 +240,18 @@ int putenv(const char *string) {return 0;}], [])], [sudo_cv_func_putenv_const=no]) ]) if test $sudo_cv_func_putenv_const = yes; then - AC_DEFINE(PUTENV_CONST, 1, [Define to 1 if the `putenv' has a const argument.]) + AC_DEFINE(PUTENV_CONST, const, [Define to const if the `putenv' takes a const argument.]) + else + AC_DEFINE(PUTENV_CONST, []) fi ]) 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.])], + [AC_DEFINE(HAVE_STRUCT_SOCKADDR_SA_LEN, 1, [Define if your struct sockadr has an sa_len field.])], [], [ #include #include ] @@ -266,7 +262,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 +295,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 +315,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 deleted file mode 100644 index 5735ec9..0000000 --- a/aix.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include - -#include -#include - -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#include -#include - -#include "compat.h" -#include "alloc.h" -#include "error.h" - -#ifdef HAVE_GETUSERATTR - -#ifndef HAVE_SETRLIMIT64 -# define setrlimit64(a, b) setrlimit(a, b) -# define rlimit64 rlimit -# define rlim64_t rlim_t -# define RLIM64_INFINITY RLIM_INFINITY -#endif /* HAVE_SETRLIMIT64 */ - -#ifndef RLIM_SAVED_MAX -# define RLIM_SAVED_MAX RLIM64_INFINITY -#endif - -struct aix_limit { - int resource; - char *soft; - char *hard; - int factor; -}; - -static struct aix_limit aix_limits[] = { - { RLIMIT_FSIZE, S_UFSIZE, S_UFSIZE_HARD, 512 }, - { RLIMIT_CPU, S_UCPU, S_UCPU_HARD, 1 }, - { RLIMIT_DATA, S_UDATA, S_UDATA_HARD, 512 }, - { RLIMIT_STACK, S_USTACK, S_USTACK_HARD, 512 }, - { RLIMIT_RSS, S_URSS, S_URSS_HARD, 512 }, - { RLIMIT_CORE, S_UCORE, S_UCORE_HARD, 512 }, - { RLIMIT_NOFILE, S_UNOFILE, S_UNOFILE_HARD, 1 } -}; - -static int -aix_getlimit(user, lim, valp) - char *user; - char *lim; - rlim64_t *valp; -{ - int val; - - if (getuserattr(user, lim, &val, SEC_INT) != 0 && - getuserattr("default", lim, &val, SEC_INT) != 0) { - return(-1); - } - *valp = val; - return(0); -} - -static void -aix_setlimits(user) - char *user; -{ - struct rlimit64 rlim; - rlim64_t val; - int n; - - if (setuserdb(S_READ) != 0) - error(1, "unable to open userdb"); - - /* - * For each resource limit, get the soft/hard values for the user - * and set those values via setrlimit64(). Must be run as euid 0. - */ - for (n = 0; n < sizeof(aix_limits) / sizeof(aix_limits[0]); n++) { - /* - * We have two strategies, depending on whether or not the - * hard limit has been defined. - */ - if (aix_getlimit(user, aix_limits[n].hard, &val) == 0) { - rlim.rlim_max = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor; - if (aix_getlimit(user, aix_limits[n].soft, &val) == 0) - rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor; - else - rlim.rlim_cur = rlim.rlim_max; /* soft not specd, use hard */ - } else { - /* No hard limit set, try soft limit. */ - if (aix_getlimit(user, aix_limits[n].soft, &val) == 0) - rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor; - - /* Set hard limit per AIX /etc/security/limits documentation. */ - switch (aix_limits[n].resource) { - case RLIMIT_CPU: - case RLIMIT_FSIZE: - rlim.rlim_max = rlim.rlim_cur; - break; - case RLIMIT_STACK: - rlim.rlim_max = RLIM_SAVED_MAX; - break; - default: - rlim.rlim_max = RLIM64_INFINITY; - break; - } - } - (void)setrlimit64(aix_limits[n].resource, &rlim); - } - enduserdb(); -} - -#ifdef HAVE_SETAUTHDB -/* - * Look up administrative domain for user (SYSTEM in /etc/security/user) and - * set it as the default for the process. This ensures that password and - * group lookups are made against the correct source (files, NIS, LDAP, etc). - */ -void -aix_setauthdb(user) - char *user; -{ - char *registry; - - if (user != NULL) { - if (setuserdb(S_READ) != 0) - error(1, "unable to open userdb"); - if (getuserattr(user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { - if (setauthdb(registry, NULL) != 0) - error(1, "unable to switch to registry \"%s\" for %s", - registry, user); - } - enduserdb(); - } -} - -/* - * Restore the saved administrative domain, if any. - */ -void -aix_restoreauthdb() -{ - if (setauthdb(NULL, NULL) != 0) - error(1, "unable to restore registry"); -} -#endif - -void -aix_prep_user(user, tty) - char *user; - char *tty; -{ - char *info; - int len; - - /* set usrinfo, like login(1) does */ - len = easprintf(&info, "NAME=%s%cLOGIN=%s%cLOGNAME=%s%cTTY=%s%c", - user, '\0', user, '\0', user, '\0', tty ? tty : "", '\0'); - (void)usrinfo(SETUINFO, info, len); - efree(info); - -#ifdef HAVE_SETAUTHDB - /* set administrative domain */ - aix_setauthdb(user); -#endif - - /* set resource limits */ - aix_setlimits(user); -} -#endif /* HAVE_GETUSERATTR */ diff --git a/aixcrypt.exp b/aixcrypt.exp deleted file mode 100644 index 5ee024e..0000000 --- a/aixcrypt.exp +++ /dev/null @@ -1,4 +0,0 @@ -#! -__setkey -__encrypt -__crypt diff --git a/alias.c b/alias.c deleted file mode 100644 index b1f57e7..0000000 --- a/alias.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007-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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ - -#include "sudo.h" -#include "parse.h" -#include "redblack.h" -#include - -/* - * Globals - */ -struct rbtree *aliases; -unsigned int alias_seqno; - -/* - * Comparison function for the red-black tree. - * Aliases are sorted by name with the type used as a tie-breaker. - */ -int -alias_compare(v1, v2) - const void *v1, *v2; -{ - const struct alias *a1 = (const struct alias *)v1; - const struct alias *a2 = (const struct alias *)v2; - int res; - - if (v1 == NULL) - res = -1; - else if (v2 == NULL) - res = 1; - else if ((res = strcmp(a1->name, a2->name)) == 0) - res = a1->type - a2->type; - return(res); -} - -/* - * Search the tree for an alias with the specified name and type. - * Returns a pointer to the alias structure or NULL if not found. - */ -struct alias * -alias_find(name, type) - char *name; - int type; -{ - struct alias key; - struct rbnode *node; - struct alias *a = NULL; - - key.name = name; - key.type = type; - if ((node = rbfind(aliases, &key)) != NULL) { - /* - * Compare the global sequence number with the one stored - * in the alias. If they match then we've seen this alias - * before and found a loop. - */ - a = node->data; - if (a->seqno == alias_seqno) - return(NULL); - a->seqno = alias_seqno; - } - return(a); -} - -/* - * Add an alias to the aliases redblack tree. - * Returns NULL on success and an error string on failure. - */ -char * -alias_add(name, type, members) - char *name; - int type; - struct member *members; -{ - static char errbuf[512]; - struct alias *a; - - a = emalloc(sizeof(*a)); - a->name = name; - a->type = type; - a->seqno = 0; - list2tq(&a->members, members); - if (rbinsert(aliases, a)) { - snprintf(errbuf, sizeof(errbuf), "Alias `%s' already defined", name); - alias_free(a); - return(errbuf); - } - return(NULL); -} - -/* - * Apply a function to each alias entry and pass in a cookie. - */ -void -alias_apply(func, cookie) - int (*func) __P((void *, void *)); - void *cookie; -{ - rbapply(aliases, func, cookie, inorder); -} - -/* - * Returns TRUE if there are no aliases, else FALSE. - */ -int -no_aliases() -{ - return(rbisempty(aliases)); -} - -/* - * Free memory used by an alias struct and its members. - */ -void -alias_free(v) - void *v; -{ - struct alias *a = (struct alias *)v; - struct member *m; - struct sudo_command *c; - void *next; - - efree(a->name); - for (m = a->members.first; m != NULL; m = next) { - next = m->next; - if (m->type == COMMAND) { - c = (struct sudo_command *) m->name; - efree(c->cmnd); - efree(c->args); - } - efree(m->name); - efree(m); - } - efree(a); -} - -/* - * Find the named alias, remove it from the tree and return it. - */ -struct alias * -alias_remove(name, type) - char *name; - int type; -{ - struct rbnode *node; - struct alias key, *a; - - key.name = name; - key.type = type; - if ((node = rbfind(aliases, &key)) == NULL) - return(NULL); - a = rbdelete(aliases, node); - return(a); -} - -void -init_aliases() -{ - if (aliases != NULL) - rbdestroy(aliases, alias_free); - aliases = rbcreate(alias_compare); -} diff --git a/alloc.c b/alloc.c deleted file mode 100644 index 8e6a7e2..0000000 --- a/alloc.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007, 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. - */ - -#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_STRING_H */ -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ -#ifdef HAVE_INTTYPES_H -# include -#endif - -#include "sudo.h" - -/* - * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t - * could be signed (as it is on SunOS 4.x). This just means that - * emalloc2() and erealloc3() cannot allocate huge amounts on such a - * platform but that is OK since sudo doesn't need to do so anyway. - */ -#ifndef SIZE_MAX -# ifdef SIZE_T_MAX -# define SIZE_MAX SIZE_T_MAX -# else -# define SIZE_MAX INT_MAX -# endif /* SIZE_T_MAX */ -#endif /* SIZE_MAX */ - -/* - * emalloc() calls the system malloc(3) and exits with an error if - * malloc(3) fails. - */ -void * -emalloc(size) - size_t size; -{ - void *ptr; - - if (size == 0) - errorx(1, "internal error, tried to emalloc(0)"); - - if ((ptr = malloc(size)) == NULL) - errorx(1, "unable to allocate memory"); - return(ptr); -} - -/* - * emalloc2() allocates nmemb * size bytes and exits with an error - * if overflow would occur or if the system malloc(3) fails. - */ -void * -emalloc2(nmemb, size) - size_t nmemb; - size_t size; -{ - void *ptr; - - if (nmemb == 0 || size == 0) - errorx(1, "internal error, tried to emalloc2(0)"); - if (nmemb > SIZE_MAX / size) - errorx(1, "internal error, emalloc2() overflow"); - - size *= nmemb; - if ((ptr = malloc(size)) == NULL) - errorx(1, "unable to allocate memory"); - return(ptr); -} - -/* - * erealloc() calls the system realloc(3) and exits with an error if - * realloc(3) fails. You can call erealloc() with a NULL pointer even - * if the system realloc(3) does not support this. - */ -void * -erealloc(ptr, size) - void *ptr; - size_t size; -{ - - if (size == 0) - errorx(1, "internal error, tried to erealloc(0)"); - - ptr = ptr ? realloc(ptr, size) : malloc(size); - if (ptr == NULL) - errorx(1, "unable to allocate memory"); - return(ptr); -} - -/* - * erealloc3() realloc(3)s nmemb * size bytes and exits with an error - * if overflow would occur or if the system malloc(3)/realloc(3) fails. - * You can call erealloc() with a NULL pointer even if the system realloc(3) - * does not support this. - */ -void * -erealloc3(ptr, nmemb, size) - void *ptr; - size_t nmemb; - size_t size; -{ - - if (nmemb == 0 || size == 0) - errorx(1, "internal error, tried to erealloc3(0)"); - if (nmemb > SIZE_MAX / size) - errorx(1, "internal error, erealloc3() overflow"); - - size *= nmemb; - ptr = ptr ? realloc(ptr, size) : malloc(size); - if (ptr == NULL) - errorx(1, "unable to allocate memory"); - return(ptr); -} - -/* - * estrdup() is like strdup(3) except that it exits with an error if - * malloc(3) fails. NOTE: unlike strdup(3), estrdup(NULL) is legal. - */ -char * -estrdup(src) - const char *src; -{ - char *dst = NULL; - size_t size; - - if (src != NULL) { - size = strlen(src) + 1; - dst = (char *) emalloc(size); - (void) memcpy(dst, src, size); - } - return(dst); -} - -/* - * easprintf() calls vasprintf() and exits with an error if vasprintf() - * returns -1 (out of memory). - */ -int -#ifdef __STDC__ -easprintf(char **ret, const char *fmt, ...) -#else -easprintf(ret, fmt, va_alist) - char **ret; - const char *fmt; - va_dcl -#endif -{ - int len; - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - len = vasprintf(ret, fmt, ap); - va_end(ap); - - if (len == -1) - errorx(1, "unable to allocate memory"); - return(len); -} - -/* - * evasprintf() calls vasprintf() and exits with an error if vasprintf() - * returns -1 (out of memory). - */ -int -evasprintf(ret, format, args) - char **ret; - const char *format; - va_list args; -{ - int len; - - if ((len = vasprintf(ret, format, args)) == -1) - errorx(1, "unable to allocate memory"); - return(len); -} - -/* - * Wrapper for free(3) so we can depend on C89 semantics. - */ -void -efree(ptr) - void *ptr; -{ - if (ptr != NULL) - free(ptr); -} diff --git a/alloc.h b/alloc.h deleted file mode 100644 index d3e1b07..0000000 --- a/alloc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#ifndef _SUDO_ALLOC_H -#define _SUDO_ALLOC_H - -#ifdef __STDC__ -# include -int easprintf(char **, const char *, ...) __printflike(2, 3); -int evasprintf(char **, const char *, va_list) __printflike(2, 0); -void efree(void *); -void *emalloc(size_t); -void *emalloc2(size_t, size_t); -void *erealloc(void *, size_t); -void *erealloc3(void *, size_t, size_t); -char *estrdup(const char *); -#else -# include -int easprintf(); -int evasprintf(); -void efree(); -void *emalloc(); -void *emalloc2(); -void *erealloc(); -void *erealloc3(); -char *estrdup(); -#endif /* __STDC__ */ - -#endif /* _SUDO_ALLOC_H */ diff --git a/audit.c b/audit.c deleted file mode 100644 index 9226d30..0000000 --- a/audit.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2009 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. - */ - -#include - -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#ifdef __STDC__ -# include -#else -# include -#endif - -#include "compat.h" -#include "logging.h" - -#ifdef HAVE_BSM_AUDIT -# include "bsm_audit.h" -#endif -#ifdef HAVE_LINUX_AUDIT -# include "linux_audit.h" -#endif - -void -#ifdef __STDC__ -audit_success(char *exec_args[]) -#else -audit_success(exec_args) - const char *exec_args[]; -#endif -{ -#ifdef HAVE_BSM_AUDIT - bsm_audit_success(exec_args); -#endif -#ifdef HAVE_LINUX_AUDIT - linux_audit_command(exec_args, 1); -#endif -} - -void -#ifdef __STDC__ -audit_failure(char *exec_args[], char const *const fmt, ...) -#else -audit_failure(exec_args, fmt, va_alist) - const char *exec_args[]; - char const *const fmt; - va_dcl -#endif -{ - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif -#ifdef HAVE_BSM_AUDIT - bsm_audit_failure(exec_args, fmt, ap); -#endif -#ifdef HAVE_LINUX_AUDIT - linux_audit_command(exec_args, 0); -#endif - va_end(ap); -} diff --git a/auth/API b/auth/API deleted file mode 100644 index fd183fe..0000000 --- a/auth/API +++ /dev/null @@ -1,128 +0,0 @@ -NOTE: the Sudo auth API is subject to change - -Purpose: to provide a simple API for authentication methods that - encapsulates things nicely without turning into a maze - of #ifdef's - -The sudo_auth struct looks like this: - -typedef struct sudo_auth { - short flags; /* various flags, see below */ - short status; /* status from verify routine */ - char *name; /* name of the method in string form */ - void *data; /* method-specific data pointer */ - - int (*init) __P((struct passwd *pw, char **prompt, sudo_auth *auth)); - int (*setup) __P((struct passwd *pw, char **prompt, sudo_auth *auth)); - int (*verify) __P((struct passwd *pw, char *p, sudo_auth *auth)); - int (*cleanup) __P((struct passwd *pw, sudo_auth *auth)); -} sudo_auth; - -The variables in the struct are as follows: - flags Bitwise binary flags, see below. - - status Contains the return value from the last run of - the "verify" function. Starts out as AUTH_FAILURE. - - name The name of the authentication method as a C string. - - data A pointer to method-specific data. This is passed to - all the functions of an auth method and is usually - initialized in the "init" or "setup" routines. - -Possible values of sudo_auth.flags: - FLAG_USER Whether or not the auth functions should run with - the euid of the invoking user instead of 0. - - FLAG_CONFIGURED If set then the auth method is assumed to have been - configured successfully. All auth methods start out - with this set. If an "init" or "setup" function - fails, this bit is cleared. - - FLAG_ONEANDONLY If set, this indicates that the method is the - only one in use. Can be used by auth functions - to determine whether to return a fatal or nonfatal - error. - -The member functions can return the following values: - AUTH_SUCCESS Function succeeded. For a ``verify'' function - this means the user correctly authenticated. - - AUTH_FAILURE Function failed. If this is an ``init'' or - ``setup'' routine, the auth method will be - marked as !configured. - - AUTH_FATAL A fatal error occurred. The routine should have - written an error message to stderr and optionally - sent mail to the administrator. (If log_error() - is called to do this, the NO_EXIT flag must be used.) - When verify_user() gets AUTH_FATAL from an auth - function it does an exit(1). - -The functions in the struct are as follows: - - int init(struct passwd *pw, char **prompt, sudo_auth *auth) - Function to do any one-time initialization for the auth - method. All of the "init" functions are run before anything - else. A pointer to the prompt string may be used to add - method-specific info to the prompt. - - int setup(struct passwd *pw, char **prompt, sudo_auth *auth) - Function to do method-specific setup. All the "setup" - routines are run before any of the "verify" routines. A - pointer to the prompt string may be used to add method-specific - info to the prompt. - - int verify(struct passwd *pw, char *p, sudo_auth *auth) - Function to do user verification for this auth method. For - standalone auth methods ``p'' is the prompt string. For - normal auth methods, ``p'' is the password the user entered. - Note that standalone auth methods are responsible for - rerading the password themselves. - - int cleanup(struct passwd *pw, sudo_auth *auth) - Function to do per-auth method cleanup. This is only run - at the end of the authentication process, after the user - has completely failed or succeeded to authenticate. - The ``auth->status'' variable contains the result of the - last authentication attempt which may be interesting. - -A note about standalone methods. Some authentication methods can't -coexist with any others. This may be because they encapsulate other -methods (pam, sia) or because they have a special way of interacting -with the user (securid). - -Adding a new authentication method: - -Each method should live in its own file. Add prototypes for the functions -in sudo_auth.h. - -If this is a standalone method, add it to the standalone #if cascade -in sudo_auth.h. For instance, for a method, ``fooauth'', add: - -#elif defined(HAVE_FOOAUTH) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "foo", \ - foo_init, foo_setup, foo_verify, foo_cleanup) - -If the method needs to run as the user, not root, replace the first -parameter to AUTH_ENTRY (0) with FLAG_USER. If you don't have a -init/setup/cleanup routine, just use a NULL for that field. - -For a normal authentication method, add it to the ``auth_switch'' in -sudo_auth.c. If ``fooauth'' is a normal auth method, its entry -would look like: - -# ifdef HAVE_FOOAUTH - AUTH_ENTRY(0, "foo", foo_init, foo_setup, foo_verify, foo_cleanup) -# endif - -Again, if the method doesn't need to run as root, replace the 0 with -FLAG_USER. Likewise, if you don't have a init/setup/cleanup routine, -just use a NULL for that field. - -NOTE: You should not make a method both ``standalone'' and - ``normal''. Just use the --without-passwd configure argument - to disable passwd/shadow file checking and then have your - auth routines check the FLAG_ONEANDONLY flag to see if - they are running standalone and act accordingly. diff --git a/auth/afs.c b/auth/afs.c deleted file mode 100644 index 2b9d7b9..0000000 --- a/auth/afs.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 1999, 2001-2005, 2007, 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. - */ - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include - -#include "sudo.h" -#include "sudo_auth.h" - -#include -#include - -int -afs_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - struct ktc_encryptionKey afs_key; - struct ktc_token afs_token; - - /* Try to just check the password */ - ka_StringToKey(pass, NULL, &afs_key); - if (ka_GetAdminToken(pw->pw_name, /* name */ - NULL, /* instance */ - NULL, /* realm */ - &afs_key, /* key (contains password) */ - 0, /* lifetime */ - &afs_token, /* token */ - 0) == 0) /* new */ - return(AUTH_SUCCESS); - - /* Fall back on old method XXX - needed? */ - setpag(); - if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG, - pw->pw_name, /* name */ - NULL, /* instance */ - NULL, /* realm */ - pass, /* password */ - 0, /* lifetime */ - NULL, /* expiration ptr (unused) */ - 0, /* spare */ - NULL) == 0) /* reason */ - return(AUTH_SUCCESS); - - return(AUTH_FAILURE); -} diff --git a/auth/aix_auth.c b/auth/aix_auth.c deleted file mode 100644 index 7a776be..0000000 --- a/auth/aix_auth.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007-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. - */ - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -/* - * For a description of the AIX authentication API, see - * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm - */ -int -aixauth_verify(pw, prompt, auth) - struct passwd *pw; - char *prompt; - sudo_auth *auth; -{ - char *pass; - char *message = NULL; - int reenter = 1; - int rval = AUTH_FAILURE; - - pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags); - if (pass) { - /* XXX - should probably print message on failure. */ - if (authenticate(pw->pw_name, pass, &reenter, &message) == 0) - rval = AUTH_SUCCESS; - free(message); - zero_bytes(pass, strlen(pass)); - } - return(rval); -} - -int -aixauth_cleanup(pw, auth) - struct passwd *pw; - sudo_auth *auth; -{ - /* Unset AUTHSTATE as it may not be correct for the runas user. */ - unsetenv("AUTHSTATE"); - - return(AUTH_SUCCESS); -} diff --git a/auth/bsdauth.c b/auth/bsdauth.c deleted file mode 100644 index 2539713..0000000 --- a/auth/bsdauth.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2000-2005, 2007-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. - */ - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include -#include - -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -extern char *login_style; /* from sudo.c */ - -int -bsdauth_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - static auth_session_t *as; - extern login_cap_t *lc; /* from sudo.c */ - - if ((as = auth_open()) == NULL) { - log_error(USE_ERRNO|NO_EXIT|NO_MAIL, - "unable to begin bsd authentication"); - return(AUTH_FATAL); - } - - /* XXX - maybe sanity check the auth style earlier? */ - login_style = login_getstyle(lc, login_style, "auth-sudo"); - if (login_style == NULL) { - log_error(NO_EXIT|NO_MAIL, "invalid authentication type"); - auth_close(as); - return(AUTH_FATAL); - } - - if (auth_setitem(as, AUTHV_STYLE, login_style) < 0 || - auth_setitem(as, AUTHV_NAME, pw->pw_name) < 0 || - auth_setitem(as, AUTHV_CLASS, login_class) < 0) { - log_error(NO_EXIT|NO_MAIL, "unable to setup authentication"); - auth_close(as); - return(AUTH_FATAL); - } - - auth->data = (void *) as; - return(AUTH_SUCCESS); -} - -int -bsdauth_verify(pw, prompt, auth) - struct passwd *pw; - char *prompt; - sudo_auth *auth; -{ - char *pass; - char *s; - size_t len; - int authok = 0; - sigaction_t sa, osa; - auth_session_t *as = (auth_session_t *) auth->data; - - /* save old signal handler */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = SIG_DFL; - (void) sigaction(SIGCHLD, &sa, &osa); - - /* - * If there is a challenge then print that instead of the normal - * prompt. If the user just hits return we prompt again with echo - * turned on, which is useful for challenge/response things like - * S/Key. - */ - if ((s = auth_challenge(as)) == NULL) { - pass = tgetpass(prompt, def_passwd_timeout * 60, tgetpass_flags); - } else { - pass = tgetpass(s, def_passwd_timeout * 60, tgetpass_flags); - if (pass && *pass == '\0') { - if ((prompt = strrchr(s, '\n'))) - prompt++; - else - prompt = s; - - /* - * Append '[echo on]' to the last line of the challenge and - * reprompt with echo turned on. - */ - len = strlen(prompt) - 1; - while (isspace(prompt[len]) || prompt[len] == ':') - prompt[len--] = '\0'; - easprintf(&s, "%s [echo on]: ", prompt); - pass = tgetpass(s, def_passwd_timeout * 60, - tgetpass_flags | TGP_ECHO); - free(s); - } - } - - if (pass) { - authok = auth_userresponse(as, pass, 1); - zero_bytes(pass, strlen(pass)); - } - - /* restore old signal handler */ - (void) sigaction(SIGCHLD, &osa, NULL); - - if (authok) - return(AUTH_SUCCESS); - - if (!pass) - return(AUTH_INTR); - - if ((s = auth_getvalue(as, "errormsg")) != NULL) - log_error(NO_EXIT|NO_MAIL, "%s", s); - return(AUTH_FAILURE); -} - -int -bsdauth_cleanup(pw, auth) - struct passwd *pw; - sudo_auth *auth; -{ - auth_session_t *as = (auth_session_t *) auth->data; - - auth_close(as); - - return(AUTH_SUCCESS); -} diff --git a/auth/dce.c b/auth/dce.c deleted file mode 100644 index 76b43b3..0000000 --- a/auth/dce.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 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. - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ -/* - * The code below basically comes from the examples supplied on - * the OSF DCE 1.0.3 manpages for the sec_login routines, with - * enough additional polishing to make the routine work with the - * rest of sudo. - * - * This code is known to work on HP 700 and 800 series systems - * running HP-UX 9.X and 10.X, with either HP's version 1.2.1 of DCE. - * (aka, OSF DCE 1.0.3) or with HP's version 1.4 of DCE (aka, OSF - * DCE 1.1). - */ - -#include - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include - -#include -#include -#include /* required to call dce_error_inq_text routine */ - -#include "sudo.h" -#include "sudo_auth.h" - -static int check_dce_status __P((error_status_t, char *)); - -int -dce_verify(pw, plain_pw, auth) - struct passwd *pw; - char *plain_pw; - sudo_auth *auth; -{ - struct passwd temp_pw; - sec_passwd_rec_t password_rec; - sec_login_handle_t login_context; - boolean32 reset_passwd; - sec_login_auth_src_t auth_src; - error_status_t status; - - /* - * Create the local context of the DCE principal necessary - * to perform authenticated network operations. The network - * identity set up by this operation cannot be used until it - * is validated via sec_login_validate_identity(). - */ - if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name, - sec_login_no_flags, &login_context, &status)) { - - if (check_dce_status(status, "sec_login_setup_identity(1):")) - return(AUTH_FAILURE); - - password_rec.key.key_type = sec_passwd_plain; - password_rec.key.tagged_union.plain = (idl_char *) plain_pw; - password_rec.pepper = NULL; - password_rec.version_number = sec_passwd_c_version_none; - - /* Validate the login context with the password */ - if (sec_login_validate_identity(login_context, &password_rec, - &reset_passwd, &auth_src, &status)) { - - if (check_dce_status(status, "sec_login_validate_identity(1):")) - return(AUTH_FAILURE); - - /* - * Certify that the DCE Security Server used to set - * up and validate a login context is legitimate. Makes - * sure that we didn't get spoofed by another DCE server. - */ - if (!sec_login_certify_identity(login_context, &status)) { - (void) fprintf(stderr, "Whoa! Bogus authentication server!\n"); - (void) check_dce_status(status,"sec_login_certify_identity(1):"); - return(AUTH_FAILURE); - } - if (check_dce_status(status, "sec_login_certify_identity(2):")) - return(AUTH_FAILURE); - - /* - * Sets the network credentials to those specified - * by the now validated login context. - */ - sec_login_set_context(login_context, &status); - if (check_dce_status(status, "sec_login_set_context:")) - return(AUTH_FAILURE); - - /* - * Oops, your credentials were no good. Possibly - * caused by clock times out of adjustment between - * DCE client and DCE security server... - */ - if (auth_src != sec_login_auth_src_network) { - (void) fprintf(stderr, - "You have no network credentials.\n"); - return(AUTH_FAILURE); - } - /* Check if the password has aged and is thus no good */ - if (reset_passwd) { - (void) fprintf(stderr, - "Your DCE password needs resetting.\n"); - return(AUTH_FAILURE); - } - - /* - * We should be a valid user by this point. Pull the - * user's password structure from the DCE security - * server just to make sure. If we get it with no - * problems, then we really are legitimate... - */ - sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw, - &status); - if (check_dce_status(status, "sec_login_get_pwent:")) - return(AUTH_FAILURE); - - /* - * If we get to here, then the pwent above properly fetched - * the password structure from the DCE registry, so the user - * must be valid. We don't really care what the user's - * registry password is, just that the user could be - * validated. In fact, if we tried to compare the local - * password to the DCE entry at this point, the operation - * would fail if the hidden password feature is turned on, - * because the password field would contain an asterisk. - * Also go ahead and destroy the user's DCE login context - * before we leave here (and don't bother checking the - * status), in order to clean up credentials files in - * /opt/dcelocal/var/security/creds. By doing this, we are - * assuming that the user will not need DCE authentication - * later in the program, only local authentication. If this - * is not true, then the login_context will have to be - * returned to the calling program, and the context purged - * somewhere later in the program. - */ - sec_login_purge_context(&login_context, &status); - return(AUTH_SUCCESS); - } else { - if(check_dce_status(status, "sec_login_validate_identity(2):")) - return(AUTH_FAILURE); - sec_login_purge_context(&login_context, &status); - if(check_dce_status(status, "sec_login_purge_context:")) - return(AUTH_FAILURE); - } - } - (void) check_dce_status(status, "sec_login_setup_identity(2):"); - return(AUTH_FAILURE); -} - -/* Returns 0 for DCE "ok" status, 1 otherwise */ -static int -check_dce_status(input_status, comment) - error_status_t input_status; - char *comment; -{ - int error_stat; - unsigned char error_string[dce_c_error_string_len]; - - if (input_status == rpc_s_ok) - return(0); - dce_error_inq_text(input_status, error_string, &error_stat); - (void) fprintf(stderr, "%s %s\n", comment, error_string); - return(1); -} diff --git a/auth/fwtk.c b/auth/fwtk.c deleted file mode 100644 index fba99e8..0000000 --- a/auth/fwtk.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 1999-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. - */ - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include - -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -int -fwtk_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - static Cfg *confp; /* Configuration entry struct */ - char resp[128]; /* Response from the server */ - - if ((confp = cfg_read("sudo")) == (Cfg *)-1) { - warningx("cannot read fwtk config"); - return(AUTH_FATAL); - } - - if (auth_open(confp)) { - warningx("cannot connect to authentication server"); - return(AUTH_FATAL); - } - - /* Get welcome message from auth server */ - if (auth_recv(resp, sizeof(resp))) { - warningx("lost connection to authentication server"); - return(AUTH_FATAL); - } - if (strncmp(resp, "Authsrv ready", 13) != 0) { - warningx("authentication server error:\n%s", resp); - return(AUTH_FATAL); - } - - return(AUTH_SUCCESS); -} - -int -fwtk_verify(pw, prompt, auth) - struct passwd *pw; - char *prompt; - sudo_auth *auth; -{ - char *pass; /* Password from the user */ - char buf[SUDO_PASS_MAX + 12]; /* General prupose buffer */ - char resp[128]; /* Response from the server */ - int error; - - /* Send username to authentication server. */ - (void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name); -restart: - if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { - warningx("lost connection to authentication server"); - return(AUTH_FATAL); - } - - /* Get the password/response from the user. */ - if (strncmp(resp, "challenge ", 10) == 0) { - (void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]); - pass = tgetpass(buf, def_passwd_timeout * 60, tgetpass_flags); - if (pass && *pass == '\0') { - pass = tgetpass("Response [echo on]: ", - def_passwd_timeout * 60, tgetpass_flags | TGP_ECHO); - } - } else if (strncmp(resp, "chalnecho ", 10) == 0) { - pass = tgetpass(&resp[10], def_passwd_timeout * 60, tgetpass_flags); - } else if (strncmp(resp, "password", 8) == 0) { - pass = tgetpass(prompt, def_passwd_timeout * 60, - tgetpass_flags); - } else if (strncmp(resp, "display ", 8) == 0) { - fprintf(stderr, "%s\n", &resp[8]); - strlcpy(buf, "response dummy", sizeof(buf)); - goto restart; - } else { - warningx("%s", resp); - return(AUTH_FATAL); - } - if (!pass) { /* ^C or error */ - return(AUTH_INTR); - } - - /* Send the user's response to the server */ - (void) snprintf(buf, sizeof(buf), "response '%s'", pass); - if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { - warningx("lost connection to authentication server"); - error = AUTH_FATAL; - goto done; - } - - if (strncmp(resp, "ok", 2) == 0) { - error = AUTH_SUCCESS; - goto done; - } - - /* Main loop prints "Permission Denied" or insult. */ - if (strcmp(resp, "Permission Denied.") != 0) - warningx("%s", resp); - error = AUTH_FAILURE; -done: - zero_bytes(pass, strlen(pass)); - zero_bytes(buf, strlen(buf)); - return(error); -} - -int -fwtk_cleanup(pw, auth) - struct passwd *pw; - sudo_auth *auth; -{ - - auth_close(); - return(AUTH_SUCCESS); -} diff --git a/auth/kerb4.c b/auth/kerb4.c deleted file mode 100644 index f3107a0..0000000 --- a/auth/kerb4.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007, 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. - */ - -#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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -int -kerb4_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - static char realm[REALM_SZ]; - - /* Don't try to verify root */ - if (pw->pw_uid == 0) - return(AUTH_FAILURE); - - /* Get the local realm, or retrun failure (no krb.conf) */ - if (krb_get_lrealm(realm, 1) != KSUCCESS) - return(AUTH_FAILURE); - - /* Stash a pointer to the realm (used in kerb4_verify) */ - auth->data = (void *) realm; - - return(AUTH_SUCCESS); -} - -int -kerb4_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - char tkfile[sizeof(_PATH_SUDO_TIMEDIR) + 4 + MAX_UID_T_LEN]; - char *realm = (char *) auth->data; - int error; - - /* - * Set the ticket file to be in sudo sudo timedir so we don't - * wipe out other (real) kerberos tickets. - */ - (void) snprintf(tkfile, sizeof(tkfile), "%s/tkt%lu", - _PATH_SUDO_TIMEDIR, (unsigned long) pw->pw_uid); - (void) krb_set_tkt_string(tkfile); - - /* Convert the password to a ticket given. */ - error = krb_get_pw_in_tkt(pw->pw_name, "", realm, "krbtgt", realm, - DEFAULT_TKT_LIFE, pass); - - switch (error) { - case INTK_OK: - dest_tkt(); /* we are done with the temp ticket */ - return(AUTH_SUCCESS); - break; - case INTK_BADPW: - case KDC_PR_UNKNOWN: - break; - default: - (void) fprintf(stderr, "Warning: Kerberos error: %s\n", - krb_err_txt[error]); - } - - return(AUTH_FAILURE); -} diff --git a/auth/kerb5.c b/auth/kerb5.c deleted file mode 100644 index 230898f..0000000 --- a/auth/kerb5.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007-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. - * 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_STRING_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include -#ifdef HAVE_HEIMDAL -#include -#endif - -#include "sudo.h" -#include "sudo_auth.h" - -#ifdef HAVE_HEIMDAL -# define extract_name(c, p) krb5_principal_get_comp_string(c, p, 1) -# define krb5_free_data_contents(c, d) krb5_data_free(d) -#else -# define extract_name(c, p) (krb5_princ_component(c, p, 1)->data) -#endif - -#ifndef HAVE_KRB5_VERIFY_USER -static int verify_krb_v5_tgt __P((krb5_context, krb5_creds *, char *)); -#endif -static struct _sudo_krb5_data { - krb5_context sudo_context; - krb5_principal princ; - krb5_ccache ccache; -} sudo_krb5_data = { NULL, NULL, NULL }; -typedef struct _sudo_krb5_data *sudo_krb5_datap; - -#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC -static krb5_error_code -krb5_get_init_creds_opt_alloc(context, opts) - krb5_context context; - krb5_get_init_creds_opt **opts; -{ - *opts = emalloc(sizeof(krb5_get_init_creds_opt)); - krb5_get_init_creds_opt_init(*opts); - return 0; -} - -static void -krb5_get_init_creds_opt_free(opts) - krb5_get_init_creds_opt *opts; -{ - free(opts); -} -#endif - -int -kerb5_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - krb5_context sudo_context; - krb5_ccache ccache; - krb5_principal princ; - krb5_error_code error; - char cache_name[64]; - char *pname; - - auth->data = (void *) &sudo_krb5_data; /* Stash all our data here */ - -#ifdef HAVE_KRB5_INIT_SECURE_CONTEXT - error = krb5_init_secure_context(&(sudo_krb5_data.sudo_context)); -#else - error = krb5_init_context(&(sudo_krb5_data.sudo_context)); -#endif - if (error) - return(AUTH_FAILURE); - sudo_context = sudo_krb5_data.sudo_context; - - if ((error = krb5_parse_name(sudo_context, pw->pw_name, - &(sudo_krb5_data.princ)))) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to parse '%s': %s", auth->name, pw->pw_name, - error_message(error)); - return(AUTH_FAILURE); - } - princ = sudo_krb5_data.princ; - - /* - * Really, we need to tell the caller not to prompt for password. - * The API does not currently provide this unless the auth is standalone. - */ -#if 1 - if ((error = krb5_unparse_name(sudo_context, princ, &pname))) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to unparse princ ('%s'): %s", auth->name, - pw->pw_name, error_message(error)); - return(AUTH_FAILURE); - } - - /* Only rewrite prompt if user didn't specify their own. */ - /*if (!strcmp(prompt, PASSPROMPT)) { */ - easprintf(promptp, "Password for %s: ", pname); - /*}*/ - free(pname); -#endif - - (void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld", - (long) getpid()); - if ((error = krb5_cc_resolve(sudo_context, cache_name, - &(sudo_krb5_data.ccache)))) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to resolve ccache: %s", auth->name, - error_message(error)); - return(AUTH_FAILURE); - } - ccache = sudo_krb5_data.ccache; - - return(AUTH_SUCCESS); -} - -#ifdef HAVE_KRB5_VERIFY_USER -int -kerb5_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - krb5_context sudo_context; - krb5_principal princ; - krb5_ccache ccache; - krb5_error_code error; - - sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; - princ = ((sudo_krb5_datap) auth->data)->princ; - ccache = ((sudo_krb5_datap) auth->data)->ccache; - - error = krb5_verify_user(sudo_context, princ, ccache, pass, 1, NULL); - return (error ? AUTH_FAILURE : AUTH_SUCCESS); -} -#else -int -kerb5_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - krb5_context sudo_context; - krb5_principal princ; - krb5_creds credbuf, *creds = NULL; - krb5_ccache ccache; - krb5_error_code error; - krb5_get_init_creds_opt *opts = NULL; - - sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; - princ = ((sudo_krb5_datap) auth->data)->princ; - ccache = ((sudo_krb5_datap) auth->data)->ccache; - - /* Set default flags based on the local config file. */ - error = krb5_get_init_creds_opt_alloc(sudo_context, &opts); - if (error) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to allocate options: %s", auth->name, - error_message(error)); - goto done; - } -#ifdef HAVE_HEIMDAL - krb5_get_init_creds_opt_set_default_flags(sudo_context, NULL, - krb5_principal_get_realm(sudo_context, princ), opts); -#endif - - /* Note that we always obtain a new TGT to verify the user */ - if ((error = krb5_get_init_creds_password(sudo_context, &credbuf, princ, - pass, krb5_prompter_posix, - NULL, 0, NULL, opts))) { - /* Don't print error if just a bad password */ - if (error != KRB5KRB_AP_ERR_BAD_INTEGRITY) - log_error(NO_EXIT|NO_MAIL, - "%s: unable to get credentials: %s", auth->name, - error_message(error)); - goto done; - } - creds = &credbuf; - - /* Verify the TGT to prevent spoof attacks. */ - if ((error = verify_krb_v5_tgt(sudo_context, creds, auth->name))) - goto done; - - /* Store cred in cred cache. */ - if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to initialize ccache: %s", auth->name, - error_message(error)); - } else if ((error = krb5_cc_store_cred(sudo_context, ccache, creds))) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to store cred in ccache: %s", auth->name, - error_message(error)); - } - -done: - if (opts) { -#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS - krb5_get_init_creds_opt_free(sudo_context, opts); -#else - krb5_get_init_creds_opt_free(opts); -#endif - } - if (creds) - krb5_free_cred_contents(sudo_context, creds); - return (error ? AUTH_FAILURE : AUTH_SUCCESS); -} -#endif - -int -kerb5_cleanup(pw, auth) - struct passwd *pw; - sudo_auth *auth; -{ - krb5_context sudo_context; - krb5_principal princ; - krb5_ccache ccache; - - sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; - princ = ((sudo_krb5_datap) auth->data)->princ; - ccache = ((sudo_krb5_datap) auth->data)->ccache; - - if (sudo_context) { - if (ccache) - krb5_cc_destroy(sudo_context, ccache); - if (princ) - krb5_free_principal(sudo_context, princ); - krb5_free_context(sudo_context); - } - - return(AUTH_SUCCESS); -} - -#ifndef HAVE_KRB5_VERIFY_USER -/* - * Verify the Kerberos ticket-granting ticket just retrieved for the - * user. If the Kerberos server doesn't respond, assume the user is - * trying to fake us out (since we DID just get a TGT from what is - * supposedly our KDC). - * - * Returns 0 for successful authentication, non-zero for failure. - */ -static int -verify_krb_v5_tgt(sudo_context, cred, auth_name) - krb5_context sudo_context; - krb5_creds *cred; - char *auth_name; /* For error reporting */ -{ - krb5_error_code error; - krb5_principal server; - krb5_verify_init_creds_opt vopt; - - /* - * Get the server principal for the local host. - * (Use defaults of "host" and canonicalized local name.) - */ - if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL, - KRB5_NT_SRV_HST, &server))) { - log_error(NO_EXIT|NO_MAIL, - "%s: unable to get host principal: %s", auth_name, - error_message(error)); - return(-1); - } - - /* Initialize verify opts and set secure mode */ - krb5_verify_init_creds_opt_init(&vopt); - krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, 1); - - /* verify the Kerberos ticket-granting ticket we just retrieved */ - error = krb5_verify_init_creds(sudo_context, cred, server, NULL, - NULL, &vopt); - krb5_free_principal(sudo_context, server); - if (error) - log_error(NO_EXIT|NO_MAIL, - "%s: Cannot verify TGT! Possible attack!: %s", auth_name, - error_message(error)); - return(error); -} -#endif diff --git a/auth/pam.c b/auth/pam.c deleted file mode 100644 index ca2ef10..0000000 --- a/auth/pam.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007-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. - */ - -#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 */ -#include -#include - -#ifdef HAVE_PAM_PAM_APPL_H -# include -#else -# include -#endif - -#ifdef HAVE_DGETTEXT -# include -# if defined(__LINUX_PAM__) -# define PAM_TEXT_DOMAIN "Linux-PAM" -# elif defined(__sun__) -# define PAM_TEXT_DOMAIN "SUNW_OST_SYSOSPAM" -# endif -#endif - -#include "sudo.h" -#include "sudo_auth.h" - -/* Only OpenPAM and Linux PAM use const qualifiers. */ -#if defined(_OPENPAM) || defined(OPENPAM_VERSION) || \ - defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__) -# define PAM_CONST const -#else -# define PAM_CONST -#endif - -static int sudo_conv __P((int, PAM_CONST struct pam_message **, - struct pam_response **, void *)); -static char *def_prompt = "Password:"; -static int gotintr; - -#ifndef PAM_DATA_SILENT -#define PAM_DATA_SILENT 0 -#endif - -static pam_handle_t *pamh; /* global due to pam_prep_user() */ - -int -pam_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - static struct pam_conv pam_conv; - static int pam_status; - - /* Initial PAM setup */ - if (auth != NULL) - auth->data = (void *) &pam_status; - pam_conv.conv = sudo_conv; -#ifdef HAVE_PAM_LOGIN - if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) - pam_status = pam_start("sudo-i", pw->pw_name, &pam_conv, &pamh); - else -#endif - pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh); - - if (pam_status != PAM_SUCCESS) { - log_error(USE_ERRNO|NO_EXIT|NO_MAIL, "unable to initialize PAM"); - return(AUTH_FATAL); - } - - /* - * Set PAM_RUSER to the invoking user (the "from" user). - * We set PAM_RHOST to avoid a bug in Solaris 7 and below. - */ - (void) pam_set_item(pamh, PAM_RUSER, user_name); -#ifdef __sun__ - (void) pam_set_item(pamh, PAM_RHOST, user_host); -#endif - - /* - * Some versions of pam_lastlog have a bug that - * will cause a crash if PAM_TTY is not set so if - * there is no tty, set PAM_TTY to the empty string. - */ - if (user_ttypath == NULL) - (void) pam_set_item(pamh, PAM_TTY, ""); - else - (void) pam_set_item(pamh, PAM_TTY, user_ttypath); - - return(AUTH_SUCCESS); -} - -int -pam_verify(pw, prompt, auth) - struct passwd *pw; - char *prompt; - sudo_auth *auth; -{ - const char *s; - int *pam_status = (int *) auth->data; - - def_prompt = prompt; /* for sudo_conv */ - - /* PAM_SILENT prevents the authentication service from generating output. */ - *pam_status = pam_authenticate(pamh, PAM_SILENT); - switch (*pam_status) { - case PAM_SUCCESS: - *pam_status = pam_acct_mgmt(pamh, PAM_SILENT); - switch (*pam_status) { - case PAM_SUCCESS: - return(AUTH_SUCCESS); - case PAM_AUTH_ERR: - log_error(NO_EXIT|NO_MAIL, "pam_acct_mgmt: %d", - *pam_status); - return(AUTH_FAILURE); - case PAM_NEW_AUTHTOK_REQD: - log_error(NO_EXIT|NO_MAIL, "%s, %s", - "Account or password is expired", - "reset your password and try again"); - *pam_status = pam_chauthtok(pamh, - PAM_CHANGE_EXPIRED_AUTHTOK); - if (*pam_status == PAM_SUCCESS) - return(AUTH_SUCCESS); - if ((s = pam_strerror(pamh, *pam_status))) - log_error(NO_EXIT|NO_MAIL, "pam_chauthtok: %s", s); - return(AUTH_FAILURE); - case PAM_AUTHTOK_EXPIRED: - log_error(NO_EXIT|NO_MAIL, - "Password expired, contact your system administrator"); - return(AUTH_FATAL); - case PAM_ACCT_EXPIRED: - log_error(NO_EXIT|NO_MAIL, "%s %s", - "Account expired or PAM config lacks an \"account\"", - "section for sudo, contact your system administrator"); - return(AUTH_FATAL); - } - /* FALLTHROUGH */ - case PAM_AUTH_ERR: - if (gotintr) { - /* error or ^C from tgetpass() */ - return(AUTH_INTR); - } - case PAM_MAXTRIES: - case PAM_PERM_DENIED: - return(AUTH_FAILURE); - default: - if ((s = pam_strerror(pamh, *pam_status))) - log_error(NO_EXIT|NO_MAIL, "pam_authenticate: %s", s); - return(AUTH_FATAL); - } -} - -int -pam_cleanup(pw, auth) - struct passwd *pw; - sudo_auth *auth; -{ - int *pam_status = (int *) auth->data; - - /* If successful, we can't close the session until pam_prep_user() */ - if (auth->status == AUTH_SUCCESS) - return(AUTH_SUCCESS); - - *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT); - return(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); -} - -int -pam_begin_session(pw) - struct passwd *pw; -{ - int status = PAM_SUCCESS; - - /* If the user did not have to authenticate there is no pam handle yet. */ - if (pamh == NULL) - pam_init(pw, NULL, NULL); - - /* - * Update PAM_USER to reference the user we are running the command - * as, as opposed to the user we authenticated as. - */ - (void) pam_set_item(pamh, PAM_USER, pw->pw_name); - - /* - * Set credentials (may include resource limits, device ownership, etc). - * We don't check the return value here because in Linux-PAM 0.75 - * it returns the last saved return code, not the return code - * for the setcred module. Because we haven't called pam_authenticate(), - * this is not set and so pam_setcred() returns PAM_PERM_DENIED. - * We can't call pam_acct_mgmt() with Linux-PAM for a similar reason. - */ - (void) pam_setcred(pamh, PAM_ESTABLISH_CRED); - -#ifndef NO_PAM_SESSION - status = pam_open_session(pamh, 0); - if (status != PAM_SUCCESS) { - (void) pam_end(pamh, status | PAM_DATA_SILENT); - pamh = NULL; - } -#endif - return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); -} - -int -pam_end_session() -{ - int status = PAM_SUCCESS; - - if (pamh != NULL) { -#ifndef NO_PAM_SESSION - (void) pam_close_session(pamh, 0); -#endif - status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); - } - return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); -} - -/* - * ``Conversation function'' for PAM. - * XXX - does not handle PAM_BINARY_PROMPT - */ -static int -sudo_conv(num_msg, msg, response, appdata_ptr) - int num_msg; - PAM_CONST struct pam_message **msg; - struct pam_response **response; - void *appdata_ptr; -{ - struct pam_response *pr; - PAM_CONST struct pam_message *pm; - const char *prompt; - char *pass; - int n, flags, std_prompt; - - if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) - return(PAM_SYSTEM_ERR); - zero_bytes(*response, num_msg * sizeof(struct pam_response)); - - for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { - flags = tgetpass_flags; - switch (pm->msg_style) { - case PAM_PROMPT_ECHO_ON: - SET(flags, TGP_ECHO); - case PAM_PROMPT_ECHO_OFF: - prompt = def_prompt; - - /* Error out if the last password read was interrupted. */ - if (gotintr) - goto err; - - /* Is the sudo prompt standard? (If so, we'l just use PAM's) */ - std_prompt = strncmp(def_prompt, "Password:", 9) == 0 && - (def_prompt[9] == '\0' || - (def_prompt[9] == ' ' && def_prompt[10] == '\0')); - - /* Only override PAM prompt if it matches /^Password: ?/ */ -#if defined(PAM_TEXT_DOMAIN) && defined(HAVE_DGETTEXT) - if (!def_passprompt_override && (std_prompt || - (strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) && - strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:"))))) - prompt = pm->msg; -#else - if (!def_passprompt_override && (std_prompt || - strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0' - && (pm->msg[9] != ' ' || pm->msg[10] != '\0')))) - prompt = pm->msg; -#endif - /* Read the password unless interrupted. */ - pass = tgetpass(prompt, def_passwd_timeout * 60, flags); - if (pass == NULL) { - /* We got ^C instead of a password; abort quickly. */ - if (errno == EINTR) - gotintr = 1; -#if defined(__darwin__) || defined(__APPLE__) - pass = ""; -#else - goto err; -#endif - } - pr->resp = estrdup(pass); - zero_bytes(pass, strlen(pass)); - break; - case PAM_TEXT_INFO: - if (pm->msg) - (void) puts(pm->msg); - break; - case PAM_ERROR_MSG: - if (pm->msg) { - (void) fputs(pm->msg, stderr); - (void) fputc('\n', stderr); - } - break; - default: - goto err; - } - } - - return(PAM_SUCCESS); - -err: - /* Zero and free allocated memory and return an error. */ - for (pr = *response, n = num_msg; n--; pr++) { - if (pr->resp != NULL) { - zero_bytes(pr->resp, strlen(pr->resp)); - free(pr->resp); - pr->resp = NULL; - } - } - zero_bytes(*response, num_msg * sizeof(struct pam_response)); - free(*response); - *response = NULL; - return(gotintr ? PAM_AUTH_ERR : PAM_CONV_ERR); -} diff --git a/auth/passwd.c b/auth/passwd.c deleted file mode 100644 index 4f9efb8..0000000 --- a/auth/passwd.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 1999-2005, 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. - */ - -#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 */ -#include - -#include "sudo.h" -#include "sudo_auth.h" - -#define DESLEN 13 -#define HAS_AGEINFO(p, l) (l == 18 && p[DESLEN] == ',') - -int -passwd_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ -#ifdef HAVE_SKEYACCESS - if (skeyaccess(pw, user_tty, NULL, NULL) == 0) - return(AUTH_FAILURE); -#endif - return(AUTH_SUCCESS); -} - -int -passwd_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - char sav, *epass; - size_t pw_len; - int error; - - pw_len = strlen(pw->pw_passwd); - -#ifdef HAVE_GETAUTHUID - /* Ultrix shadow passwords may use crypt16() */ - error = strcmp(pw->pw_passwd, (char *) crypt16(pass, pw->pw_passwd)); - if (!error) - return(AUTH_SUCCESS); -#endif /* HAVE_GETAUTHUID */ - - /* - * Truncate to 8 chars if standard DES since not all crypt()'s do this. - * If this turns out not to be safe we will have to use OS #ifdef's (sigh). - */ - sav = pass[8]; - if (pw_len == DESLEN || HAS_AGEINFO(pw->pw_passwd, pw_len)) - pass[8] = '\0'; - - /* - * Normal UN*X password check. - * HP-UX may add aging info (separated by a ',') at the end so - * only compare the first DESLEN characters in that case. - */ - epass = (char *) crypt(pass, pw->pw_passwd); - pass[8] = sav; - if (HAS_AGEINFO(pw->pw_passwd, pw_len) && strlen(epass) == DESLEN) - error = strncmp(pw->pw_passwd, epass, DESLEN); - else - error = strcmp(pw->pw_passwd, epass); - - return(error ? AUTH_FAILURE : AUTH_SUCCESS); -} diff --git a/auth/rfc1938.c b/auth/rfc1938.c deleted file mode 100644 index 3bc39c3..0000000 --- a/auth/rfc1938.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 1994-1996, 1998-2005, 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. - */ - -#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 */ -#include - -#if defined(HAVE_SKEY) -# include -# define RFC1938 skey -# ifdef __NetBSD__ -# define rfc1938challenge(a,b,c,d) skeychallenge((a),(b),(c),(d)) -# else -# define rfc1938challenge(a,b,c,d) skeychallenge((a),(b),(c)) -# endif -# define rfc1938verify(a,b) skeyverify((a),(b)) -#elif defined(HAVE_OPIE) -# include -# define RFC1938 opie -# define rfc1938challenge(a,b,c,d) opiechallenge((a),(b),(c)) -# define rfc1938verify(a,b) opieverify((a),(b)) -#endif - -#include "sudo.h" -#include "sudo_auth.h" - -int -rfc1938_setup(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - char challenge[256]; - static char *orig_prompt = NULL, *new_prompt = NULL; - static int op_len, np_size; - static struct RFC1938 rfc1938; - - /* Stash a pointer to the rfc1938 struct if we have not initialized */ - if (!auth->data) - auth->data = &rfc1938; - - /* Save the original prompt */ - if (orig_prompt == NULL) { - orig_prompt = *promptp; - op_len = strlen(orig_prompt); - - /* Ignore trailing colon (we will add our own) */ - if (orig_prompt[op_len - 1] == ':') - op_len--; - else if (op_len >= 2 && orig_prompt[op_len - 1] == ' ' - && orig_prompt[op_len - 2] == ':') - op_len -= 2; - } - -#ifdef HAVE_SKEY - /* Close old stream */ - if (rfc1938.keyfile) - (void) fclose(rfc1938.keyfile); -#endif - - /* - * Look up the user and get the rfc1938 challenge. - * If the user is not in the OTP db, only post a fatal error if - * we are running alone (since they may just use a normal passwd). - */ - if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) { - if (IS_ONEANDONLY(auth)) { - warningx("you do not exist in the %s database", auth->name); - return(AUTH_FATAL); - } else { - return(AUTH_FAILURE); - } - } - - /* Get space for new prompt with embedded challenge */ - if (np_size < op_len + strlen(challenge) + 7) { - np_size = op_len + strlen(challenge) + 7; - new_prompt = (char *) erealloc(new_prompt, np_size); - } - - if (def_long_otp_prompt) - (void) snprintf(new_prompt, np_size, "%s\n%s", challenge, orig_prompt); - else - (void) snprintf(new_prompt, np_size, "%.*s [ %s ]:", op_len, - orig_prompt, challenge); - - *promptp = new_prompt; - return(AUTH_SUCCESS); -} - -int -rfc1938_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - - if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0) - return(AUTH_SUCCESS); - else - return(AUTH_FAILURE); -} diff --git a/auth/secureware.c b/auth/secureware.c deleted file mode 100644 index e7148d3..0000000 --- a/auth/secureware.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) 1998-2005, 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. - */ - -#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 */ -#include -#ifdef __hpux -# undef MAXINT -# include -#else -# include -#endif /* __hpux */ -#include - -#include "sudo.h" -#include "sudo_auth.h" - -int -secureware_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ -#ifdef __alpha - extern int crypt_type; - - if (crypt_type == INT_MAX) - return(AUTH_FAILURE); /* no shadow */ -#endif - return(AUTH_SUCCESS); -} - -int -secureware_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ -#ifdef __alpha - extern int crypt_type; - -# ifdef HAVE_DISPCRYPT - if (strcmp(user_passwd, dispcrypt(pass, user_passwd, 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); - } else if (crypt_type == AUTH_CRYPT_CRYPT16) { - if (strcmp(user_passwd, crypt(pass, user_passwd)) == 0) - return(AUTH_SUCCESS); - } -# endif /* HAVE_DISPCRYPT */ -#elif defined(HAVE_BIGCRYPT) - if (strcmp(user_passwd, bigcrypt(pass, user_passwd)) == 0) - return(AUTH_SUCCESS); -#endif /* __alpha */ - - return(AUTH_FAILURE); -} diff --git a/auth/securid.c b/auth/securid.c deleted file mode 100644 index 6aec109..0000000 --- a/auth/securid.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007, 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. - * 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 */ -#include - -#include -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -union config_record configure; - -int -securid_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - static struct SD_CLIENT sd_dat; /* SecurID data block */ - - auth->data = (void *) &sd_dat; /* For method-specific data */ - - if (creadcfg() == 0) - return(AUTH_SUCCESS); - else - return(AUTH_FATAL); -} - -int -securid_setup(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data; - - /* Re-initialize SecurID every time. */ - if (sd_init(sd) == 0) { - /* The programmer's guide says username is 32 bytes */ - strlcpy(sd->username, pw->pw_name, 32); - return(AUTH_SUCCESS); - } else { - warningx("unable to contact the SecurID server"); - return(AUTH_FATAL); - } -} - -int -securid_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - struct SD_CLIENT *sd = (struct SD_CLIENT *) auth->data; - int rval; - - rval = sd_auth(sd); - sd_close(); - if (rval == ACM_OK) - return(AUTH_SUCCESS); - else - return(AUTH_FAILURE); -} diff --git a/auth/securid5.c b/auth/securid5.c deleted file mode 100644 index ef9e228..0000000 --- a/auth/securid5.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007, 2010 - * Todd C. Miller - * Copyright (c) 2002 Michael Stroucken - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 */ -#include - -/* Needed for SecurID v5.0 Authentication on UNIX */ -#define UNIX 1 -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -/* - * securid_init - Initialises communications with ACE server - * Arguments in: - * pw - UNUSED - * promptp - UNUSED - * auth - sudo authentication structure - * - * Results out: - * auth - auth->data contains pointer to new SecurID handle - * return code - Fatal if initialization unsuccessful, otherwise - * success. - */ -int -securid_init(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - static SDI_HANDLE sd_dat; /* SecurID handle */ - - auth->data = (void *) &sd_dat; /* For method-specific data */ - - /* Start communications */ - if (AceInitialize() != SD_FALSE) - return(AUTH_SUCCESS); - - warningx("failed to initialise the ACE API library"); - return(AUTH_FATAL); -} - -/* - * securid_setup - Initialises a SecurID transaction and locks out other - * ACE servers - * - * Arguments in: - * pw - struct passwd for username - * promptp - UNUSED - * auth - sudo authentication structure for SecurID handle - * - * Results out: - * return code - Success if transaction started correctly, fatal - * otherwise - */ -int -securid_setup(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - SDI_HANDLE *sd = (SDI_HANDLE *) auth->data; - int retval; - - /* Re-initialize SecurID every time. */ - if (SD_Init(sd) != ACM_OK) { - warningx("unable to contact the SecurID server"); - return(AUTH_FATAL); - } - - /* Lock new PIN code */ - retval = SD_Lock(*sd, pw->pw_name); - - switch (retval) { - case ACM_OK: - warningx("User ID locked for SecurID Authentication"); - return(AUTH_SUCCESS); - - case ACE_UNDEFINED_USERNAME: - warningx("invalid username length for SecurID"); - return(AUTH_FATAL); - - case ACE_ERR_INVALID_HANDLE: - warningx("invalid Authentication Handle for SecurID"); - return(AUTH_FATAL); - - case ACM_ACCESS_DENIED: - warningx("SecurID communication failed"); - return(AUTH_FATAL); - - default: - warningx("unknown SecurID error"); - return(AUTH_FATAL); - } -} - -/* - * securid_verify - Authenticates user and handles ACE responses - * - * Arguments in: - * pw - struct passwd for username - * pass - UNUSED - * auth - sudo authentication structure for SecurID handle - * - * Results out: - * return code - Success on successful authentication, failure on - * incorrect authentication, fatal on errors - */ -int -securid_verify(pw, pass, auth) - struct passwd *pw; - char *pass; - sudo_auth *auth; -{ - SDI_HANDLE *sd = (SDI_HANDLE *) auth->data; - int rval; - - pass = (char *) tgetpass("Enter your PASSCODE: ", - def_passwd_timeout * 60, tgetpass_flags); - - /* Have ACE verify password */ - switch (SD_Check(*sd, pass, pw->pw_name)) { - case ACM_OK: - rval = AUTH_SUCESS; - break; - - case ACE_UNDEFINED_PASSCODE: - warningx("invalid passcode length for SecurID"); - rval = AUTH_FATAL; - break; - - case ACE_UNDEFINED_USERNAME: - warningx("invalid username length for SecurID"); - rval = AUTH_FATAL; - break; - - case ACE_ERR_INVALID_HANDLE: - warningx("invalid Authentication Handle for SecurID"); - rval = AUTH_FATAL; - break; - - case ACM_ACCESS_DENIED: - rval = AUTH_FAILURE; - break; - - case ACM_NEXT_CODE_REQUIRED: - /* Sometimes (when current token close to expire?) - ACE challenges for the next token displayed - (entered without the PIN) */ - pass = (char *) tgetpass("\ -!!! ATTENTION !!!\n\ -Wait for the token code to change, \n\ -then enter the new token code.\n", \ - def_passwd_timeout * 60, tgetpass_flags); - - if (SD_Next(*sd, pass) == ACM_OK) { - rval = AUTH_SUCCESS; - break; - } - - rval = AUTH_FAILURE; - break; - - case ACM_NEW_PIN_REQUIRED: - /* - * This user's SecurID has not been activated yet, - * or the pin has been reset - */ - /* XXX - Is setting up a new PIN within sudo's scope? */ - SD_Pin(*sd, ""); - fprintf(stderr, "Your SecurID access has not yet been set up.\n"); - fprintf(stderr, "Please set up a PIN before you try to authenticate.\n"); - rval = AUTH_FATAL; - break; - - default: - warningx("unknown SecurID error"); - rval = AUTH_FATAL; - break; - } - - /* Free resources */ - SD_Close(*sd); - - /* Return stored state to calling process */ - return(rval); -} diff --git a/auth/sia.c b/auth/sia.c deleted file mode 100644 index 188676a..0000000 --- a/auth/sia.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007, 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. - * 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 */ -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" - -static int sudo_collect __P((int, int, uchar_t *, int, prompt_t *)); - -static char *def_prompt; - -/* - * Collection routine (callback) for limiting the timeouts in SIA - * prompts and (possibly) setting a custom prompt. - */ -static int -sudo_collect(timeout, rendition, title, nprompts, prompts) - int timeout; - int rendition; - uchar_t *title; - int nprompts; - prompt_t *prompts; -{ - switch (rendition) { - case SIAFORM: - case SIAONELINER: - if (timeout <= 0 || timeout > def_passwd_timeout * 60) - timeout = def_passwd_timeout * 60; - /* - * Substitute custom prompt if a) the sudo prompt is not "Password:" - * and b) the SIA prompt is "Password:" (so we know it is safe). - * This keeps us from overwriting things like S/Key challenges. - */ - if (strcmp((char *)prompts[0].prompt, "Password:") == 0 && - strcmp(def_prompt, "Password:") != 0) - prompts[0].prompt = (unsigned char *)def_prompt; - break; - default: - break; - } - - return sia_collect_trm(timeout, rendition, title, nprompts, prompts); -} - -int -sia_setup(pw, promptp, auth) - struct passwd *pw; - char **promptp; - sudo_auth *auth; -{ - SIAENTITY *siah = NULL; - extern int Argc; - extern char **Argv; - - if (sia_ses_init(&siah, Argc, Argv, NULL, pw->pw_name, ttyname(0), 1, NULL) - != SIASUCCESS) { - - log_error(USE_ERRNO|NO_EXIT|NO_MAIL, - "unable to initialize SIA session"); - return(AUTH_FATAL); - } - - auth->data = (void *) siah; - return(AUTH_SUCCESS); -} - -int -sia_verify(pw, prompt, auth) - struct passwd *pw; - char *prompt; - sudo_auth *auth; -{ - SIAENTITY *siah = (SIAENTITY *) auth->data; - - def_prompt = prompt; /* for sudo_collect */ - - /* XXX - need a way to detect user hitting return or EOF at prompt */ - if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS) - return(AUTH_SUCCESS); - else - return(AUTH_FAILURE); -} - -int -sia_cleanup(pw, auth) - struct passwd *pw; - sudo_auth *auth; -{ - SIAENTITY *siah = (SIAENTITY *) auth->data; - - (void) sia_ses_release(&siah); - return(AUTH_SUCCESS); -} diff --git a/auth/sudo_auth.c b/auth/sudo_auth.c deleted file mode 100644 index 69b0a3a..0000000 --- a/auth/sudo_auth.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 1999-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. - */ - -#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 */ -#include -#include -#include - -#include "sudo.h" -#include "sudo_auth.h" -#include "insults.h" - -sudo_auth auth_switch[] = { -#ifdef AUTH_STANDALONE - AUTH_STANDALONE -#else -# ifndef WITHOUT_PASSWD - AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL) -# endif -# if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD) - AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL) -# endif -# ifdef HAVE_AFS - AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL) -# endif -# ifdef HAVE_DCE - AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL) -# endif -# ifdef HAVE_KERB4 - AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL) -# endif -# ifdef HAVE_KERB5 - AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup) -# endif -# ifdef HAVE_SKEY - AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL) -# endif -# ifdef HAVE_OPIE - AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL) -# endif -#endif /* AUTH_STANDALONE */ - AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL) -}; - -void -verify_user(pw, prompt) - struct passwd *pw; - char *prompt; -{ - int counter = def_passwd_tries + 1; - int success = AUTH_FAILURE; - int status; - int flags; - char *p; - sudo_auth *auth; - sigaction_t sa, osa; -#ifdef HAVE_BSM_AUDIT - extern char **NewArgv; -#endif - - /* Enable suspend during password entry. */ - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = SIG_DFL; - (void) sigaction(SIGTSTP, &sa, &osa); - - /* Make sure we have at least one auth method. */ - if (auth_switch[0].name == NULL) { -#ifdef HAVE_BSM_AUDIT - audit_failure(NewArgv, "no authentication methods"); -#endif - log_error(0, "%s %s %s", - "There are no authentication methods compiled into sudo!", - "If you want to turn off authentication, use the", - "--disable-authentication configure option."); - } - - /* Set FLAG_ONEANDONLY if there is only one auth method. */ - if (auth_switch[1].name == NULL) - SET(auth_switch[0].flags, FLAG_ONEANDONLY); - - /* Initialize auth methods and unconfigure the method if necessary. */ - for (auth = auth_switch; auth->name; auth++) { - if (auth->init && IS_CONFIGURED(auth)) { - if (NEEDS_USER(auth)) - set_perms(PERM_USER); - - status = (auth->init)(pw, &prompt, auth); - if (status == AUTH_FAILURE) - CLR(auth->flags, FLAG_CONFIGURED); - else if (status == AUTH_FATAL) { /* XXX log */ -#ifdef HAVE_BSM_AUDIT - audit_failure(NewArgv, "authentication failure"); -#endif - exit(1); /* assume error msg already printed */ - } - - if (NEEDS_USER(auth)) - set_perms(PERM_ROOT); - } - } - - while (--counter) { - /* Do any per-method setup and unconfigure the method if needed */ - for (auth = auth_switch; auth->name; auth++) { - if (auth->setup && IS_CONFIGURED(auth)) { - if (NEEDS_USER(auth)) - set_perms(PERM_USER); - - status = (auth->setup)(pw, &prompt, auth); - if (status == AUTH_FAILURE) - CLR(auth->flags, FLAG_CONFIGURED); - else if (status == AUTH_FATAL) {/* XXX log */ -#ifdef HAVE_BSM_AUDIT - audit_failure(NewArgv, "authentication failure"); -#endif - exit(1); /* assume error msg already printed */ - } - - if (NEEDS_USER(auth)) - set_perms(PERM_ROOT); - } - } - - /* Get the password unless the auth function will do it for us */ -#ifdef AUTH_STANDALONE - p = prompt; -#else - p = (char *) tgetpass(prompt, def_passwd_timeout * 60, - tgetpass_flags); -#endif /* AUTH_STANDALONE */ - - /* Call authentication functions. */ - for (auth = auth_switch; p && auth->name; auth++) { - if (!IS_CONFIGURED(auth)) - continue; - - if (NEEDS_USER(auth)) - set_perms(PERM_USER); - - success = auth->status = (auth->verify)(pw, (char *)p, auth); - - if (NEEDS_USER(auth)) - set_perms(PERM_ROOT); - - if (auth->status != AUTH_FAILURE) - goto cleanup; - } -#ifndef AUTH_STANDALONE - if (p == NULL) - break; - zero_bytes(p, strlen(p)); -#endif - if (!ISSET(tgetpass_flags, TGP_ASKPASS)) - pass_warn(stderr); - } - -cleanup: - /* Call cleanup routines. */ - for (auth = auth_switch; auth->name; auth++) { - if (auth->cleanup && IS_CONFIGURED(auth)) { - if (NEEDS_USER(auth)) - set_perms(PERM_USER); - - status = (auth->cleanup)(pw, auth); - if (status == AUTH_FATAL) { /* XXX log */ -#ifdef HAVE_BSM_AUDIT - audit_failure(NewArgv, "authentication failure"); -#endif - exit(1); /* assume error msg already printed */ - } - - if (NEEDS_USER(auth)) - set_perms(PERM_ROOT); - } - } - - switch (success) { - case AUTH_SUCCESS: - (void) sigaction(SIGTSTP, &osa, NULL); - return; - case AUTH_INTR: - case AUTH_FAILURE: - if (counter != def_passwd_tries) { - if (def_mail_badpass || def_mail_always) - flags = 0; - else - flags = NO_MAIL; -#ifdef HAVE_BSM_AUDIT - audit_failure(NewArgv, "authentication failure"); -#endif - log_error(flags, "%d incorrect password attempt%s", - def_passwd_tries - counter, - (def_passwd_tries - counter == 1) ? "" : "s"); - } - /* FALLTHROUGH */ - case AUTH_FATAL: -#ifdef HAVE_BSM_AUDIT - audit_failure(NewArgv, "authentication failure"); -#endif - exit(1); - } - /* NOTREACHED */ -} - -void -pass_warn(fp) - FILE *fp; -{ - -#ifdef INSULT - if (def_insults) - (void) fprintf(fp, "%s\n", INSULT); - else -#endif - (void) fprintf(fp, "%s\n", def_badpass_message); -} - -void -dump_auth_methods() -{ - sudo_auth *auth; - - (void) fputs("Authentication methods:", stdout); - for (auth = auth_switch; auth->name; auth++) - (void) printf(" '%s'", auth->name); - (void) putchar('\n'); -} diff --git a/auth/sudo_auth.h b/auth/sudo_auth.h deleted file mode 100644 index a4efe14..0000000 --- a/auth/sudo_auth.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007-2009 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_AUTH_H -#define SUDO_AUTH_H - -/* Auth function return values. */ -#define AUTH_SUCCESS 0 -#define AUTH_FAILURE 1 -#define AUTH_INTR 2 -#define AUTH_FATAL 3 - -typedef struct sudo_auth { - short flags; /* various flags, see below */ - short status; /* status from verify routine */ - char *name; /* name of the method as a string */ - void *data; /* method-specific data pointer */ - int (*init) __P((struct passwd *pw, char **prompt, struct sudo_auth *auth)); - int (*setup) __P((struct passwd *pw, char **prompt, struct sudo_auth *auth)); - int (*verify) __P((struct passwd *pw, char *p, struct sudo_auth *auth)); - int (*cleanup) __P((struct passwd *pw, struct sudo_auth *auth)); -} sudo_auth; - -/* Values for sudo_auth.flags. */ -/* XXX - these names are too long for my liking */ -#define FLAG_USER 0x01 /* functions must run as the user, not root */ -#define FLAG_CONFIGURED 0x02 /* method configured ok */ -#define FLAG_ONEANDONLY 0x04 /* one and only auth method */ - -/* Shortcuts for using the flags above. */ -#define NEEDS_USER(x) ((x)->flags & FLAG_USER) -#define IS_CONFIGURED(x) ((x)->flags & FLAG_CONFIGURED) -#define IS_ONEANDONLY(x) ((x)->flags & FLAG_ONEANDONLY) - -/* Prototypes for standalone methods */ -int fwtk_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int fwtk_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth)); -int fwtk_cleanup __P((struct passwd *pw, sudo_auth *auth)); -int pam_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int pam_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth)); -int pam_cleanup __P((struct passwd *pw, sudo_auth *auth)); -int sia_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int sia_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth)); -int sia_cleanup __P((struct passwd *pw, sudo_auth *auth)); -int aixauth_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int aixauth_cleanup __P((struct passwd *pw, sudo_auth *auth)); -int bsdauth_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int bsdauth_verify __P((struct passwd *pw, char *prompt, sudo_auth *auth)); -int bsdauth_cleanup __P((struct passwd *pw, sudo_auth *auth)); - -/* Prototypes for normal methods */ -int passwd_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int passwd_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int secureware_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int secureware_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int rfc1938_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int rfc1938_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int afs_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int dce_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int kerb4_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int kerb4_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int kerb5_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int kerb5_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); -int kerb5_cleanup __P((struct passwd *pw, sudo_auth *auth)); -int securid_init __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int securid_setup __P((struct passwd *pw, char **prompt, sudo_auth *auth)); -int securid_verify __P((struct passwd *pw, char *pass, sudo_auth *auth)); - -/* Fields: need_root, name, init, setup, verify, cleanup */ -#define AUTH_ENTRY(r, n, i, s, v, c) \ - { (r|FLAG_CONFIGURED), AUTH_FAILURE, n, NULL, i, s, v, c }, - -/* Some methods cannots (or should not) interoperate with any others */ -#if defined(HAVE_PAM) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "pam", \ - pam_init, NULL, pam_verify, pam_cleanup) -#elif defined(HAVE_SECURID) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "SecurId", \ - securid_init, securid_setup, securid_verify, NULL) -#elif defined(HAVE_SIA_SES_INIT) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "sia", \ - NULL, sia_setup, sia_verify, sia_cleanup) -#elif defined(HAVE_AIXAUTH) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "aixauth", \ - NULL, NULL, aixauth_verify, aixauth_cleanup) -#elif defined(HAVE_FWTK) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "fwtk", \ - fwtk_init, NULL, fwtk_verify, fwtk_cleanup) -#elif defined(HAVE_BSD_AUTH_H) -# define AUTH_STANDALONE \ - AUTH_ENTRY(0, "bsdauth", \ - bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup) -#endif - -#endif /* SUDO_AUTH_H */ diff --git a/boottime.c b/boottime.c deleted file mode 100644 index f75af3e..0000000 --- a/boottime.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#include - -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#include -#if TIME_WITH_SYS_TIME -# include -#endif - -#ifdef HAVE_SYSCTL -# include -#endif - -#include "compat.h" -#include "missing.h" - -/* - * Fill in a struct timeval with the time the system booted. - * Returns 1 on success and 0 on failure. - */ - -#if defined(__linux__) -int -get_boottime(tv) - struct timeval *tv; -{ - char *line = NULL; - size_t linesize = 0; - ssize_t len; - FILE * fp; - - /* read btime from /proc/stat */ - fp = fopen("/proc/stat", "r"); - if (fp != NULL) { - while ((len = getline(&line, &linesize, fp)) != -1) { - if (strncmp(line, "btime ", 6) == 0) { - tv->tv_sec = atoi(line + 6); - tv->tv_usec = 0; - return 1; - } - } - fclose(fp); - free(line); - } - - return 0; -} - -#elif defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME) - -int -get_boottime(tv) - struct timeval *tv; -{ - size_t size; - int mib[2]; - - mib[0] = CTL_KERN; - mib[1] = KERN_BOOTTIME; - size = sizeof(*tv); - if (sysctl(mib, 2, tv, &size, NULL, 0) != -1) - return 1; - - return 0; -} - -#elif defined(HAVE_GETUTXID) - -#include -int -get_boottime(tv) - struct timeval *tv; -{ - struct utmpx *ut, key; - - memset(&key, 0, sizeof(key)); - key.ut_type = BOOT_TIME; - if ((ut = getutxid(&key)) != NULL) { - tv->tv_sec = ut->ut_tv.tv_sec; - tv->tv_usec = ut->ut_tv.tv_usec; - endutxent(); - } - return ut != NULL; -} - -#elif defined(HAVE_GETUTID) - -#include -int -get_boottime(tv) - struct timeval *tv; -{ - struct utmp *ut, key; - - memset(&key, 0, sizeof(key)); - key.ut_type = BOOT_TIME; - if ((ut = getutid(&key)) != NULL) { - tv->tv_sec = ut->ut_time; - tv->tv_usec = 0; - endutent(); - } - return ut != NULL; -} - -#else - -int -get_boottime(tv) - struct timeval *tv; -{ - return 0; -} -#endif diff --git a/bsm_audit.c b/bsm_audit.c deleted file mode 100644 index b388b86..0000000 --- a/bsm_audit.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2009 Christian S.J. Peron - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "bsm_audit.h" - -void log_error(int flags, const char *fmt, ...) __attribute__((__noreturn__)); - -static int -audit_sudo_selected(int sf) -{ - auditinfo_addr_t ainfo_addr; - struct au_mask *mask; - auditinfo_t ainfo; - int rc, sorf; - - if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) { - if (errno == ENOSYS) { - if (getaudit(&ainfo) < 0) - log_error(0, "getaudit: failed"); - mask = &ainfo.ai_mask; - } else - log_error(0, "getaudit: failed"); - } else - mask = &ainfo_addr.ai_mask; - sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE; - rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD); - return (rc); -} - -void -bsm_audit_success(char **exec_args) -{ - auditinfo_addr_t ainfo_addr; - auditinfo_t ainfo; - token_t *tok; - au_id_t auid; - long au_cond; - int aufd; - pid_t pid; - - pid = getpid(); - /* - * If we are not auditing, don't cut an audit record; just return. - */ - if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) { - if (errno == ENOSYS) - return; - log_error(0, "Could not determine audit condition"); - } - if (au_cond == AUC_NOAUDIT) - return; - /* - * Check to see if the preselection masks are interested in seeing - * this event. - */ - if (!audit_sudo_selected(0)) - return; - if (getauid(&auid) < 0) - log_error(0, "getauid failed"); - if ((aufd = au_open()) == -1) - log_error(0, "au_open: failed"); - if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { - tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(), - getuid(), pid, pid, &ainfo_addr.ai_termid); - } else if (errno == ENOSYS) { - /* - * NB: We should probably watch out for ERANGE here. - */ - if (getaudit(&ainfo) < 0) - log_error(0, "getaudit: failed"); - tok = au_to_subject(auid, geteuid(), getegid(), getuid(), - getuid(), pid, pid, &ainfo.ai_termid); - } else - log_error(0, "getaudit: failed"); - if (tok == NULL) - log_error(0, "au_to_subject: failed"); - au_write(aufd, tok); - tok = au_to_exec_args(exec_args); - if (tok == NULL) - log_error(0, "au_to_exec_args: failed"); - au_write(aufd, tok); - tok = au_to_return32(0, 0); - if (tok == NULL) - log_error(0, "au_to_return32: failed"); - au_write(aufd, tok); - if (au_close(aufd, 1, AUE_sudo) == -1) - log_error(0, "unable to commit audit record"); -} - -void -bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap) -{ - auditinfo_addr_t ainfo_addr; - auditinfo_t ainfo; - char text[256]; - token_t *tok; - long au_cond; - au_id_t auid; - pid_t pid; - int aufd; - - pid = getpid(); - /* - * If we are not auditing, don't cut an audit record; just return. - */ - if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { - if (errno == ENOSYS) - return; - log_error(0, "Could not determine audit condition"); - } - if (au_cond == AUC_NOAUDIT) - return; - if (!audit_sudo_selected(1)) - return; - if (getauid(&auid) < 0) - log_error(0, "getauid: failed"); - if ((aufd = au_open()) == -1) - log_error(0, "au_open: failed"); - if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { - tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(), - getuid(), pid, pid, &ainfo_addr.ai_termid); - } else if (errno == ENOSYS) { - if (getaudit(&ainfo) < 0) - log_error(0, "getaudit: failed"); - tok = au_to_subject(auid, geteuid(), getegid(), getuid(), - getuid(), pid, pid, &ainfo.ai_termid); - } else - log_error(0, "getaudit: failed"); - if (tok == NULL) - log_error(0, "au_to_subject: failed"); - au_write(aufd, tok); - tok = au_to_exec_args(exec_args); - if (tok == NULL) - log_error(0, "au_to_exec_args: failed"); - au_write(aufd, tok); - (void) vsnprintf(text, sizeof(text), fmt, ap); - tok = au_to_text(text); - if (tok == NULL) - log_error(0, "au_to_text: failed"); - au_write(aufd, tok); - tok = au_to_return32(EPERM, 1); - if (tok == NULL) - log_error(0, "au_to_return32: failed"); - au_write(aufd, tok); - if (au_close(aufd, 1, AUE_sudo) == -1) - log_error(0, "unable to commit audit record"); -} diff --git a/bsm_audit.h b/bsm_audit.h deleted file mode 100644 index 37be345..0000000 --- a/bsm_audit.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2009 Todd C. Miller - * Copyright (c) 2009 Christian S.J. Peron - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _SUDO_BSM_AUDIT_H -#define _SUDO_BSM_AUDIT_H - -void bsm_audit_success(char **); -void bsm_audit_failure(char **, char const * const, va_list); - -#endif /* _SUDO_BSM_AUDIT_H */ diff --git a/check.c b/check.c deleted file mode 100644 index b2c44e1..0000000 --- a/check.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (c) 1993-1996,1998-2005, 2007-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. - */ - -#include - -#include -#include -#include -#include -#ifdef __linux__ -# include -#endif -#if defined(__sun) && defined(__SVR4) -# include -#endif -#ifndef __TANDEM -# include -#endif -#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 TIME_WITH_SYS_TIME -# include -#endif -#include -#include -#include -#include -#include - -#include "sudo.h" - -/* Status codes for timestamp_status() */ -#define TS_CURRENT 0 -#define TS_OLD 1 -#define TS_MISSING 2 -#define TS_NOFILE 3 -#define TS_ERROR 4 - -/* Flags for timestamp_status() */ -#define TS_MAKE_DIRS 1 -#define TS_REMOVE 2 - -/* - * Info stored in tty ticket from stat(2) to help with tty matching. - */ -static struct tty_info { - dev_t dev; /* ID of device tty resides on */ - dev_t rdev; /* tty device ID */ - ino_t ino; /* tty inode number */ - struct timeval ctime; /* tty inode change time */ -} tty_info; - -static void build_timestamp __P((char **, char **)); -static int timestamp_status __P((char *, char *, char *, int)); -static char *expand_prompt __P((char *, char *, char *)); -static void lecture __P((int)); -static void update_timestamp __P((char *, char *)); -static int tty_is_devpts __P((const char *)); - -/* - * This function only returns if the user can successfully - * verify who he/she is. - */ -void -check_user(validated, mode) - int validated; - int mode; -{ - char *timestampdir = NULL; - char *timestampfile = NULL; - char *prompt; - struct stat sb; - int status; - - /* Stash the tty's ctime for tty ticket comparison. */ - if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) { - tty_info.dev = sb.st_dev; - tty_info.ino = sb.st_ino; - tty_info.rdev = sb.st_rdev; - if (tty_is_devpts(user_ttypath)) - ctim_get(&sb, &tty_info.ctime); - } - - /* Always prompt for a password when -k was specified with the command. */ - if (ISSET(mode, MODE_INVALIDATE)) { - SET(validated, FLAG_CHECK_USER); - } else { - /* - * Don't prompt for the root passwd or if the user is exempt. - * If the user is not changing uid/gid, no need for a password. - */ - if (user_uid == 0 || (user_uid == runas_pw->pw_uid && - (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) || - user_is_exempt()) - return; - } - - build_timestamp(×tampdir, ×tampfile); - status = timestamp_status(timestampdir, timestampfile, user_name, - TS_MAKE_DIRS); - - if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) { - /* Bail out if we are non-interactive and a password is required */ - if (ISSET(mode, MODE_NONINTERACTIVE)) - errorx(1, "sorry, a password is required to run %s", getprogname()); - - /* If user specified -A, make sure we have an askpass helper. */ - if (ISSET(tgetpass_flags, TGP_ASKPASS)) { - if (user_askpass == NULL) - log_error(NO_MAIL, - "no askpass program specified, try setting SUDO_ASKPASS"); - } else if (!ISSET(tgetpass_flags, TGP_STDIN)) { - /* If no tty but DISPLAY is set, use askpass if we have it. */ - if (!user_ttypath && !tty_present()) { - if (user_askpass && user_display && *user_display != '\0') { - SET(tgetpass_flags, TGP_ASKPASS); - } else if (!def_visiblepw) { - log_error(NO_MAIL, - "no tty present and no askpass program specified"); - } - } - } - - if (!ISSET(tgetpass_flags, TGP_ASKPASS)) - lecture(status); - - /* Expand any escapes in the prompt. */ - prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, - user_name, user_shost); - - verify_user(auth_pw, prompt); - } - /* Only update timestamp if user was validated. */ - if (ISSET(validated, VALIDATE_OK) && !ISSET(mode, MODE_INVALIDATE) && status != TS_ERROR) - update_timestamp(timestampdir, timestampfile); - efree(timestampdir); - efree(timestampfile); -} - -/* - * Standard sudo lecture. - */ -static void -lecture(status) - int status; -{ - FILE *fp; - char buf[BUFSIZ]; - ssize_t nread; - - if (def_lecture == never || - (def_lecture == once && status != TS_MISSING && status != TS_ERROR)) - return; - - if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) { - while ((nread = fread(buf, sizeof(char), sizeof(buf), fp)) != 0) - fwrite(buf, nread, 1, stderr); - fclose(fp); - } else { - (void) fputs("\n\ -We trust you have received the usual lecture from the local System\n\ -Administrator. It usually boils down to these three things:\n\ -\n\ - #1) Respect the privacy of others.\n\ - #2) Think before you type.\n\ - #3) With great power comes great responsibility.\n\n", - stderr); - } -} - -/* - * Update the time on the timestamp file/dir or create it if necessary. - */ -static void -update_timestamp(timestampdir, timestampfile) - char *timestampdir; - char *timestampfile; -{ - /* If using tty timestamps but we have no tty there is nothing to do. */ - if (timestampfile && !user_ttypath) - return; - - if (timestamp_uid != 0) - set_perms(PERM_TIMESTAMP); - if (timestampfile) { - /* - * Store tty info in timestamp file - */ - int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600); - if (fd == -1) - log_error(NO_EXIT|USE_ERRNO, "Can't open %s", timestampfile); - else { - lock_file(fd, SUDO_LOCK); - write(fd, &tty_info, sizeof(tty_info)); - close(fd); - } - } else { - if (touch(-1, timestampdir, NULL) == -1) { - if (mkdir(timestampdir, 0700) == -1) - log_error(NO_EXIT|USE_ERRNO, "Can't mkdir %s", timestampdir); - } - } - if (timestamp_uid != 0) - set_perms(PERM_ROOT); -} - -/* - * Expand %h and %u escapes in the prompt and pass back the dynamically - * allocated result. Returns the same string if there are no escapes. - */ -static char * -expand_prompt(old_prompt, user, host) - char *old_prompt; - char *user; - char *host; -{ - size_t len, n; - int subst; - char *p, *np, *new_prompt, *endp; - - /* How much space do we need to malloc for the prompt? */ - subst = 0; - for (p = old_prompt, len = strlen(old_prompt); *p; p++) { - if (p[0] =='%') { - switch (p[1]) { - case 'h': - p++; - len += strlen(user_shost) - 2; - subst = 1; - break; - case 'H': - p++; - len += strlen(user_host) - 2; - subst = 1; - break; - case 'p': - p++; - if (def_rootpw) - len += 2; - else if (def_targetpw || def_runaspw) - len += strlen(runas_pw->pw_name) - 2; - else - len += strlen(user_name) - 2; - subst = 1; - break; - case 'u': - p++; - len += strlen(user_name) - 2; - subst = 1; - break; - case 'U': - p++; - len += strlen(runas_pw->pw_name) - 2; - subst = 1; - break; - case '%': - p++; - len--; - subst = 1; - break; - default: - break; - } - } - } - - if (subst) { - new_prompt = (char *) emalloc(++len); - endp = new_prompt + len; - for (p = old_prompt, np = new_prompt; *p; p++) { - if (p[0] =='%') { - switch (p[1]) { - case 'h': - p++; - n = strlcpy(np, user_shost, np - endp); - if (n >= np - endp) - goto oflow; - np += n; - continue; - case 'H': - p++; - n = strlcpy(np, user_host, np - endp); - if (n >= np - endp) - goto oflow; - np += n; - continue; - case 'p': - p++; - if (def_rootpw) - n = strlcpy(np, "root", np - endp); - else if (def_targetpw || def_runaspw) - n = strlcpy(np, runas_pw->pw_name, np - endp); - else - n = strlcpy(np, user_name, np - endp); - if (n >= np - endp) - goto oflow; - np += n; - continue; - case 'u': - p++; - n = strlcpy(np, user_name, np - endp); - if (n >= np - endp) - goto oflow; - np += n; - continue; - case 'U': - p++; - n = strlcpy(np, runas_pw->pw_name, np - endp); - if (n >= np - endp) - goto oflow; - np += n; - continue; - case '%': - /* convert %% -> % */ - p++; - break; - default: - /* no conversion */ - break; - } - } - *np++ = *p; - if (np >= endp) - goto oflow; - } - *np = '\0'; - } else - new_prompt = old_prompt; - - return(new_prompt); - -oflow: - /* We pre-allocate enough space, so this should never happen. */ - errorx(1, "internal error, expand_prompt() overflow"); -} - -/* - * Checks if the user is exempt from supplying a password. - */ -int -user_is_exempt() -{ - if (!def_exempt_group) - return(FALSE); - return(user_in_group(sudo_user.pw, def_exempt_group)); -} - -/* - * Fills in timestampdir as well as timestampfile if using tty tickets. - */ -static void -build_timestamp(timestampdir, timestampfile) - char **timestampdir; - char **timestampfile; -{ - char *dirparent; - int len; - - dirparent = def_timestampdir; - len = easprintf(timestampdir, "%s/%s", dirparent, user_name); - if (len >= PATH_MAX) - log_error(0, "timestamp path too long: %s", *timestampdir); - - /* - * Timestamp file may be a file in the directory or NUL to use - * the directory as the timestamp. - */ - if (def_tty_tickets) { - char *p; - - if ((p = strrchr(user_tty, '/'))) - p++; - else - p = user_tty; - if (def_targetpw) - len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name, - p, runas_pw->pw_name); - else - len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, p); - if (len >= PATH_MAX) - log_error(0, "timestamp path too long: %s", *timestampfile); - } else if (def_targetpw) { - len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, - runas_pw->pw_name); - if (len >= PATH_MAX) - log_error(0, "timestamp path too long: %s", *timestampfile); - } else - *timestampfile = NULL; -} - -/* - * Check the timestamp file and directory and return their status. - */ -static int -timestamp_status(timestampdir, timestampfile, user, flags) - char *timestampdir; - char *timestampfile; - char *user; - int flags; -{ - struct stat sb; - struct timeval boottime, mtime; - time_t now; - char *dirparent = def_timestampdir; - int status = TS_ERROR; /* assume the worst */ - - if (timestamp_uid != 0) - set_perms(PERM_TIMESTAMP); - - /* - * Sanity check dirparent and make it if it doesn't already exist. - * We start out assuming the worst (that the dir is not sane) and - * if it is ok upgrade the status to ``no timestamp file''. - * Note that we don't check the parent(s) of dirparent for - * sanity since the sudo dir is often just located in /tmp. - */ - if (lstat(dirparent, &sb) == 0) { - if (!S_ISDIR(sb.st_mode)) - log_error(NO_EXIT, "%s exists but is not a directory (0%o)", - dirparent, (unsigned int) sb.st_mode); - else if (sb.st_uid != timestamp_uid) - log_error(NO_EXIT, "%s owned by uid %lu, should be uid %lu", - dirparent, (unsigned long) sb.st_uid, - (unsigned long) timestamp_uid); - else if ((sb.st_mode & 0000022)) - log_error(NO_EXIT, - "%s writable by non-owner (0%o), should be mode 0700", - dirparent, (unsigned int) sb.st_mode); - else { - if ((sb.st_mode & 0000777) != 0700) - (void) chmod(dirparent, 0700); - status = TS_MISSING; - } - } else if (errno != ENOENT) { - log_error(NO_EXIT|USE_ERRNO, "can't stat %s", dirparent); - } else { - /* No dirparent, try to make one. */ - if (ISSET(flags, TS_MAKE_DIRS)) { - if (mkdir(dirparent, S_IRWXU)) - log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s", - dirparent); - else - status = TS_MISSING; - } - } - if (status == TS_ERROR) { - if (timestamp_uid != 0) - set_perms(PERM_ROOT); - return(status); - } - - /* - * Sanity check the user's ticket dir. We start by downgrading - * the status to TS_ERROR. If the ticket dir exists and is sane - * this will be upgraded to TS_OLD. If the dir does not exist, - * it will be upgraded to TS_MISSING. - */ - status = TS_ERROR; /* downgrade status again */ - if (lstat(timestampdir, &sb) == 0) { - if (!S_ISDIR(sb.st_mode)) { - if (S_ISREG(sb.st_mode)) { - /* convert from old style */ - if (unlink(timestampdir) == 0) - status = TS_MISSING; - } else - log_error(NO_EXIT, "%s exists but is not a directory (0%o)", - timestampdir, (unsigned int) sb.st_mode); - } else if (sb.st_uid != timestamp_uid) - log_error(NO_EXIT, "%s owned by uid %lu, should be uid %lu", - timestampdir, (unsigned long) sb.st_uid, - (unsigned long) timestamp_uid); - else if ((sb.st_mode & 0000022)) - log_error(NO_EXIT, - "%s writable by non-owner (0%o), should be mode 0700", - timestampdir, (unsigned int) sb.st_mode); - else { - if ((sb.st_mode & 0000777) != 0700) - (void) chmod(timestampdir, 0700); - status = TS_OLD; /* do date check later */ - } - } else if (errno != ENOENT) { - log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampdir); - } else - status = TS_MISSING; - - /* - * If there is no user ticket dir, AND we are in tty ticket mode, - * AND the TS_MAKE_DIRS flag is set, create the user ticket dir. - */ - if (status == TS_MISSING && timestampfile && ISSET(flags, TS_MAKE_DIRS)) { - if (mkdir(timestampdir, S_IRWXU) == -1) { - status = TS_ERROR; - log_error(NO_EXIT|USE_ERRNO, "can't mkdir %s", timestampdir); - } - } - - /* - * Sanity check the tty ticket file if it exists. - */ - if (timestampfile && status != TS_ERROR) { - if (status != TS_MISSING) - status = TS_NOFILE; /* dir there, file missing */ - if (!user_ttypath) - goto done; /* no tty, always prompt */ - if (lstat(timestampfile, &sb) == 0) { - if (!S_ISREG(sb.st_mode)) { - status = TS_ERROR; - log_error(NO_EXIT, "%s exists but is not a regular file (0%o)", - timestampfile, (unsigned int) sb.st_mode); - } else { - /* If bad uid or file mode, complain and kill the bogus file. */ - if (sb.st_uid != timestamp_uid) { - log_error(NO_EXIT, - "%s owned by uid %lu, should be uid %lu", - timestampfile, (unsigned long) sb.st_uid, - (unsigned long) timestamp_uid); - (void) unlink(timestampfile); - } else if ((sb.st_mode & 0000022)) { - log_error(NO_EXIT, - "%s writable by non-owner (0%o), should be mode 0600", - timestampfile, (unsigned int) sb.st_mode); - (void) unlink(timestampfile); - } else { - /* If not mode 0600, fix it. */ - if ((sb.st_mode & 0000777) != 0600) - (void) chmod(timestampfile, 0600); - - /* - * Check for stored tty info. If the file is zero-sized - * it is an old-style timestamp with no tty info in it. - * If removing, we don't care about the contents. - * The actual mtime check is done later. - */ - if (ISSET(flags, TS_REMOVE)) { - status = TS_OLD; - } else if (sb.st_size != 0) { - struct tty_info info; - int fd = open(timestampfile, O_RDONLY, 0644); - if (fd != -1) { - if (read(fd, &info, sizeof(info)) == sizeof(info) && - memcmp(&info, &tty_info, sizeof(info)) == 0) { - status = TS_OLD; - } - close(fd); - } - } - } - } - } else if (errno != ENOENT) { - log_error(NO_EXIT|USE_ERRNO, "can't stat %s", timestampfile); - status = TS_ERROR; - } - } - - /* - * If the file/dir exists and we are not removing it, check its mtime. - */ - if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) { - mtim_get(&sb, &mtime); - /* Negative timeouts only expire manually (sudo -k). */ - if (def_timestamp_timeout < 0 && mtime.tv_sec != 0) - status = TS_CURRENT; - else { - now = time(NULL); - if (def_timestamp_timeout && - now - mtime.tv_sec < 60 * def_timestamp_timeout) { - /* - * Check for bogus time on the stampfile. The clock may - * have been set back or someone could be trying to spoof us. - */ - if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) { - time_t tv_sec = (time_t)mtime.tv_sec; - log_error(NO_EXIT, - "timestamp too far in the future: %20.20s", - 4 + ctime(&tv_sec)); - if (timestampfile) - (void) unlink(timestampfile); - else - (void) rmdir(timestampdir); - status = TS_MISSING; - } else if (get_boottime(&boottime) && timevalcmp(&mtime, &boottime, <)) { - status = TS_OLD; - } else { - status = TS_CURRENT; - } - } - } - } - -done: - if (timestamp_uid != 0) - set_perms(PERM_ROOT); - return(status); -} - -/* - * Remove the timestamp ticket file/dir. - */ -void -remove_timestamp(remove) - int remove; -{ - struct timeval tv; - char *timestampdir, *timestampfile, *path; - int status; - - build_timestamp(×tampdir, ×tampfile); - status = timestamp_status(timestampdir, timestampfile, user_name, - TS_REMOVE); - if (status == TS_OLD || status == TS_CURRENT) { - path = timestampfile ? timestampfile : timestampdir; - if (remove) { - if (timestampfile) - status = unlink(timestampfile); - else - status = rmdir(timestampdir); - if (status == -1 && errno != ENOENT) { - log_error(NO_EXIT, "can't remove %s (%s), will reset to Epoch", - path, strerror(errno)); - remove = FALSE; - } - } else { - timevalclear(&tv); - if (touch(-1, path, &tv) == -1 && errno != ENOENT) - error(1, "can't reset %s to Epoch", path); - } - } - - efree(timestampdir); - efree(timestampfile); -} - -/* - * Returns TRUE if tty lives on a devpts or /devices filesystem, else FALSE. - * Unlike most filesystems, the ctime of devpts nodes is not updated when - * the device node is written to, only when the inode's status changes, - * typically via the chmod, chown, link, rename, or utimes system calls. - * Since the ctime is "stable" in this case, we can stash it the tty ticket - * file and use it to determine whether the tty ticket file is stale. - */ -static int -tty_is_devpts(tty) - const char *tty; -{ - int retval = FALSE; -#ifdef __linux__ - struct statfs sfs; - -#ifndef DEVPTS_SUPER_MAGIC -# define DEVPTS_SUPER_MAGIC 0x1cd1 -#endif - - if (statfs(tty, &sfs) == 0) { - if (sfs.f_type == DEVPTS_SUPER_MAGIC) - retval = TRUE; - } -#elif defined(__sun) && defined(__SVR4) - struct statvfs sfs; - - if (statvfs(tty, &sfs) == 0) { - if (strcmp(sfs.f_fstr, "devices") == 0) - retval = TRUE; - } -#endif /* __linux__ */ - return retval; -} diff --git a/closefrom.c b/closefrom.c deleted file mode 100644 index fb9958e..0000000 --- a/closefrom.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007 - * 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. - */ - -#include - -#include -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#include -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif - -#include "sudo.h" - -#ifndef HAVE_FCNTL_CLOSEM -# ifndef HAVE_DIRFD -# define closefrom_fallback closefrom -# endif -#endif - -/* - * Close all file descriptors greater than or equal to lowfd. - * This is the expensive (ballback) method. - */ -void -closefrom_fallback(lowfd) - int lowfd; -{ - long fd, maxfd; - - /* - * Fall back on sysconf() or getdtablesize(). We avoid checking - * resource limits since it is possible to open a file descriptor - * and then drop the rlimit such that it is below the open fd. - */ -#ifdef HAVE_SYSCONF - maxfd = sysconf(_SC_OPEN_MAX); -#else - maxfd = getdtablesize(); -#endif /* HAVE_SYSCONF */ - if (maxfd < 0) - maxfd = OPEN_MAX; - - for (fd = lowfd; fd < maxfd; fd++) - (void) close((int) fd); -} - -/* - * Close all file descriptors greater than or equal to lowfd. - * We try the fast way first, falling back on the slow method. - */ -#ifdef HAVE_FCNTL_CLOSEM -void -closefrom(lowfd) - int lowfd; -{ - if (fcntl(lowfd, F_CLOSEM, 0) == -1) - closefrom_fallback(lowfd); -} -#else -# ifdef HAVE_DIRFD -void -closefrom(lowfd) - int lowfd; -{ - struct dirent *dent; - DIR *dirp; - char *endp; - long fd; - - /* Use /proc/self/fd directory if it exists. */ - if ((dirp = opendir("/proc/self/fd")) != NULL) { - while ((dent = readdir(dirp)) != NULL) { - fd = strtol(dent->d_name, &endp, 10); - if (dent->d_name != endp && *endp == '\0' && - fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) - (void) close((int) fd); - } - (void) closedir(dirp); - } else - closefrom_fallback(lowfd); -} -#endif /* HAVE_DIRFD */ -#endif /* HAVE_FCNTL_CLOSEM */ diff --git a/common/Makefile.in b/common/Makefile.in new file mode 100644 index 0000000..aff4c54 --- /dev/null +++ b/common/Makefile.in @@ -0,0 +1,157 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# OS dependent defines +DEFS = @OSDEFS@ -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\" + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +LTOBJS = alloc.lo atobool.lo fileops.lo fmt_string.lo lbuf.lo list.lo \ + secure_path.lo setgroups.lo sudo_conf.lo sudo_debug.lo term.lo \ + ttysize.lo zero_bytes.lo @COMMON_OBJS@ + +all: libcommon.la + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file common/Makefile) + +.SUFFIXES: .c .h .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +libcommon.la: $(LTOBJS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(LTOBJS) -no-install + +pre-install: + +install: + +install-dirs: + +install-binaries: + +install-includes: + +install-doc: + +install-plugin: + +uninstall: + +check: + +clean: + -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +aix.lo: $(srcdir)/aix.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/aix.c +alloc.lo: $(srcdir)/alloc.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/alloc.c +atobool.lo: $(srcdir)/atobool.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/atobool.c +fileops.lo: $(srcdir)/fileops.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(top_srcdir)/compat/timespec.h \ + $(incdir)/missing.h $(incdir)/fileops.h $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/fileops.c +fmt_string.lo: $(srcdir)/fmt_string.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/fmt_string.c +lbuf.lo: $(srcdir)/lbuf.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/lbuf.h \ + $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/lbuf.c +list.lo: $(srcdir)/list.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/list.h $(incdir)/error.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/list.c +secure_path.lo: $(srcdir)/secure_path.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/sudo_debug.h \ + $(incdir)/secure_path.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/secure_path.c +setgroups.lo: $(srcdir)/setgroups.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/setgroups.c +sudo_conf.lo: $(srcdir)/sudo_conf.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/fileops.h \ + $(top_builddir)/pathnames.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_conf.h $(incdir)/list.h $(incdir)/sudo_debug.h \ + $(incdir)/secure_path.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_conf.c +sudo_debug.lo: $(srcdir)/sudo_debug.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_debug.c +term.lo: $(srcdir)/term.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/term.c +ttysize.lo: $(srcdir)/ttysize.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ttysize.c +zero_bytes.lo: $(srcdir)/zero_bytes.c $(top_builddir)/config.h \ + $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/zero_bytes.c diff --git a/common/aix.c b/common/aix.c new file mode 100644 index 0000000..bd20b26 --- /dev/null +++ b/common/aix.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2008, 2010-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. + */ + +#include + +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include +#include + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "sudo_debug.h" + +#define DEFAULT_TEXT_DOMAIN "sudo" +#include "gettext.h" + +#ifdef HAVE_GETUSERATTR + +#ifndef HAVE_SETRLIMIT64 +# define setrlimit64(a, b) setrlimit(a, b) +# define rlimit64 rlimit +# define rlim64_t rlim_t +# define RLIM64_INFINITY RLIM_INFINITY +#endif /* HAVE_SETRLIMIT64 */ + +#ifndef RLIM_SAVED_MAX +# define RLIM_SAVED_MAX RLIM64_INFINITY +#endif + +struct aix_limit { + int resource; + char *soft; + char *hard; + int factor; +}; + +static struct aix_limit aix_limits[] = { + { RLIMIT_FSIZE, S_UFSIZE, S_UFSIZE_HARD, 512 }, + { RLIMIT_CPU, S_UCPU, S_UCPU_HARD, 1 }, + { RLIMIT_DATA, S_UDATA, S_UDATA_HARD, 512 }, + { RLIMIT_STACK, S_USTACK, S_USTACK_HARD, 512 }, + { RLIMIT_RSS, S_URSS, S_URSS_HARD, 512 }, + { RLIMIT_CORE, S_UCORE, S_UCORE_HARD, 512 }, + { RLIMIT_NOFILE, S_UNOFILE, S_UNOFILE_HARD, 1 } +}; + +static int +aix_getlimit(char *user, char *lim, rlim64_t *valp) +{ + int val; + debug_decl(aix_getlimit, SUDO_DEBUG_UTIL) + + if (getuserattr(user, lim, &val, SEC_INT) != 0) + debug_return_int(-1); + *valp = val; + debug_return_int(0); +} + +static void +aix_setlimits(char *user) +{ + struct rlimit64 rlim; + rlim64_t val; + int n; + debug_decl(aix_setlimits, SUDO_DEBUG_UTIL) + + if (setuserdb(S_READ) != 0) + error(1, "unable to open userdb"); + + /* + * For each resource limit, get the soft/hard values for the user + * and set those values via setrlimit64(). Must be run as euid 0. + */ + for (n = 0; n < sizeof(aix_limits) / sizeof(aix_limits[0]); n++) { + /* + * We have two strategies, depending on whether or not the + * hard limit has been defined. + */ + if (aix_getlimit(user, aix_limits[n].hard, &val) == 0) { + rlim.rlim_max = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor; + if (aix_getlimit(user, aix_limits[n].soft, &val) == 0) + rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor; + else + rlim.rlim_cur = rlim.rlim_max; /* soft not specd, use hard */ + } else { + /* No hard limit set, try soft limit. */ + if (aix_getlimit(user, aix_limits[n].soft, &val) == 0) + rlim.rlim_cur = val == -1 ? RLIM64_INFINITY : val * aix_limits[n].factor; + + /* Set hard limit per AIX /etc/security/limits documentation. */ + switch (aix_limits[n].resource) { + case RLIMIT_CPU: + case RLIMIT_FSIZE: + rlim.rlim_max = rlim.rlim_cur; + break; + case RLIMIT_STACK: + rlim.rlim_max = RLIM_SAVED_MAX; + break; + default: + rlim.rlim_max = RLIM64_INFINITY; + break; + } + } + (void)setrlimit64(aix_limits[n].resource, &rlim); + } + enduserdb(); + debug_return; +} + +#ifdef HAVE_SETAUTHDB +/* + * Look up administrative domain for user (SYSTEM in /etc/security/user) and + * set it as the default for the process. This ensures that password and + * group lookups are made against the correct source (files, NIS, LDAP, etc). + */ +void +aix_setauthdb(char *user) +{ + char *registry; + debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL) + + if (user != NULL) { + if (setuserdb(S_READ) != 0) + error(1, _("unable to open userdb")); + if (getuserattr(user, S_REGISTRY, ®istry, SEC_CHAR) == 0) { + if (setauthdb(registry, NULL) != 0) + error(1, _("unable to switch to registry \"%s\" for %s"), + registry, user); + } + enduserdb(); + } + debug_return; +} + +/* + * Restore the saved administrative domain, if any. + */ +void +aix_restoreauthdb(void) +{ + debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL) + + if (setauthdb(NULL, NULL) != 0) + error(1, _("unable to restore registry")); + + debug_return; +} +#endif + +void +aix_prep_user(char *user, const char *tty) +{ + char *info; + int len; + debug_decl(aix_setauthdb, SUDO_DEBUG_UTIL) + + /* set usrinfo, like login(1) does */ + len = easprintf(&info, "NAME=%s%cLOGIN=%s%cLOGNAME=%s%cTTY=%s%c", + user, '\0', user, '\0', user, '\0', tty ? tty : "", '\0'); + (void)usrinfo(SETUINFO, info, len); + efree(info); + +#ifdef HAVE_SETAUTHDB + /* set administrative domain */ + aix_setauthdb(user); +#endif + + /* set resource limits */ + aix_setlimits(user); + + debug_return; +} +#endif /* HAVE_GETUSERATTR */ diff --git a/common/alloc.c b/common/alloc.c new file mode 100644 index 0000000..cbf8f62 --- /dev/null +++ b/common/alloc.c @@ -0,0 +1,282 @@ +/* + * Copyright (c) 1999-2005, 2007, 2010-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. + * + * 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 +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRING_H */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#ifdef HAVE_INTTYPES_H +# include +#endif + +#include "missing.h" +#include "alloc.h" +#include "error.h" + +#define DEFAULT_TEXT_DOMAIN "sudo" +#include "gettext.h" + +/* + * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t + * could be signed (as it is on SunOS 4.x). This just means that + * emalloc2() and erealloc3() cannot allocate huge amounts on such a + * platform but that is OK since sudo doesn't need to do so anyway. + */ +#ifndef SIZE_MAX +# ifdef SIZE_T_MAX +# define SIZE_MAX SIZE_T_MAX +# else +# define SIZE_MAX INT_MAX +# endif /* SIZE_T_MAX */ +#endif /* SIZE_MAX */ + +/* + * emalloc() calls the system malloc(3) and exits with an error if + * malloc(3) fails. + */ +void * +emalloc(size_t size) +{ + void *ptr; + + if (size == 0) + errorx2(1, _("internal error, tried to emalloc(0)")); + + if ((ptr = malloc(size)) == NULL) + errorx2(1, _("unable to allocate memory")); + return ptr; +} + +/* + * emalloc2() allocates nmemb * size bytes and exits with an error + * if overflow would occur or if the system malloc(3) fails. + */ +void * +emalloc2(size_t nmemb, size_t size) +{ + void *ptr; + + if (nmemb == 0 || size == 0) + errorx2(1, _("internal error, tried to emalloc2(0)")); + if (nmemb > SIZE_MAX / size) + errorx2(1, _("internal error, emalloc2() overflow")); + + size *= nmemb; + if ((ptr = malloc(size)) == NULL) + errorx2(1, _("unable to allocate memory")); + return ptr; +} + +/* + * ecalloc() allocates nmemb * size bytes and exits with an error + * if overflow would occur or if the system malloc(3) fails. + * On success, the allocated space is zero-filled. + */ +void * +ecalloc(size_t nmemb, size_t size) +{ + void *ptr; + + if (nmemb == 0 || size == 0) + errorx2(1, _("internal error, tried to ecalloc(0)")); + if (nmemb != 1) { + if (nmemb > SIZE_MAX / size) + errorx2(1, _("internal error, ecalloc() overflow")); + size *= nmemb; + } + if ((ptr = malloc(size)) == NULL) + errorx2(1, _("unable to allocate memory")); + memset(ptr, 0, size); + return ptr; +} + +/* + * erealloc() calls the system realloc(3) and exits with an error if + * realloc(3) fails. You can call erealloc() with a NULL pointer even + * if the system realloc(3) does not support this. + */ +void * +erealloc(void *ptr, size_t size) +{ + + if (size == 0) + errorx2(1, _("internal error, tried to erealloc(0)")); + + ptr = ptr ? realloc(ptr, size) : malloc(size); + if (ptr == NULL) + errorx2(1, _("unable to allocate memory")); + return ptr; +} + +/* + * erealloc3() realloc(3)s nmemb * size bytes and exits with an error + * if overflow would occur or if the system malloc(3)/realloc(3) fails. + * You can call erealloc() with a NULL pointer even if the system realloc(3) + * does not support this. + */ +void * +erealloc3(void *ptr, size_t nmemb, size_t size) +{ + + if (nmemb == 0 || size == 0) + errorx2(1, _("internal error, tried to erealloc3(0)")); + if (nmemb > SIZE_MAX / size) + errorx2(1, _("internal error, erealloc3() overflow")); + + size *= nmemb; + ptr = ptr ? realloc(ptr, size) : malloc(size); + if (ptr == NULL) + errorx2(1, _("unable to allocate memory")); + return ptr; +} + +#ifdef notyet +/* + * erecalloc() realloc(3)s nmemb * msize bytes and exits with an error + * if overflow would occur or if the system malloc(3)/realloc(3) fails. + * On success, the new space is zero-filled. You can call ereallocz() + * with a NULL pointer even if the system realloc(3) does not support this. + */ +void * +erecalloc(void *ptr, size_t onmemb, size_t nmemb, size_t msize) +{ + size_t size; + + if (nmemb == 0 || msize == 0) + errorx2(1, _("internal error, tried to erealloc3(0)")); + if (nmemb > SIZE_MAX / msize) + errorx2(1, _("internal error, erealloc3() overflow")); + + size = nmemb * msize; + ptr = ptr ? realloc(ptr, size) : malloc(size); + if (ptr == NULL) + errorx2(1, _("unable to allocate memory")); + if (nmemb > onmemb) { + size = (nmemb - onmemb) * msize; + memset((char *)ptr + (onmemb * msize), 0, size); + } + return ptr; +} +#endif + +/* + * estrdup() is like strdup(3) except that it exits with an error if + * malloc(3) fails. NOTE: unlike strdup(3), estrdup(NULL) is legal. + */ +char * +estrdup(const char *src) +{ + char *dst = NULL; + size_t len; + + if (src != NULL) { + len = strlen(src); + dst = (char *) emalloc(len + 1); + (void) memcpy(dst, src, len); + dst[len] = '\0'; + } + return dst; +} + +/* + * estrdup() is like strndup(3) except that it exits with an error if + * malloc(3) fails. NOTE: unlike strdup(3), estrdup(NULL) is legal. + */ +char * +estrndup(const char *src, size_t maxlen) +{ + char *dst = NULL; + size_t len = 0; + + if (src != NULL) { + while (maxlen != 0 && src[len] != '\0') { + len++; + maxlen--; + } + dst = (char *) emalloc(len + 1); + (void) memcpy(dst, src, len); + dst[len] = '\0'; + } + return dst; +} + +/* + * easprintf() calls vasprintf() and exits with an error if vasprintf() + * returns -1 (out of memory). + */ +int +easprintf(char **ret, const char *fmt, ...) +{ + int len; + va_list ap; + va_start(ap, fmt); + len = vasprintf(ret, fmt, ap); + va_end(ap); + + if (len == -1) + errorx2(1, _("unable to allocate memory")); + return len; +} + +/* + * evasprintf() calls vasprintf() and exits with an error if vasprintf() + * returns -1 (out of memory). + */ +int +evasprintf(char **ret, const char *format, va_list args) +{ + int len; + + if ((len = vasprintf(ret, format, args)) == -1) + errorx2(1, _("unable to allocate memory")); + return len; +} + +/* + * Wrapper for free(3) so we can depend on C89 semantics. + */ +void +efree(void *ptr) +{ + if (ptr != NULL) + free(ptr); +} diff --git a/common/atobool.c b/common/atobool.c new file mode 100644 index 0000000..6d6b502 --- /dev/null +++ b/common/atobool.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ + +#include "missing.h" +#include "sudo_debug.h" + +int +atobool(const char *str) +{ + debug_decl(atobool, SUDO_DEBUG_UTIL) + + switch (*str) { + case '0': + case '1': + if (str[1] == '\0') + return *str - '0'; + break; + case 'y': + case 'Y': + if (strcasecmp(str, "yes") == 0) + return 1; + break; + case 't': + case 'T': + if (strcasecmp(str, "true") == 0) + return 1; + break; + case 'o': + case 'O': + if (strcasecmp(str, "on") == 0) + return 1; + if (strcasecmp(str, "off") == 0) + return 0; + break; + case 'n': + case 'N': + if (strcasecmp(str, "no") == 0) + return 0; + break; + case 'f': + case 'F': + if (strcasecmp(str, "false") == 0) + return 0; + break; + } + debug_return_int(-1); +} diff --git a/common/fileops.c b/common/fileops.c new file mode 100644 index 0000000..f99710c --- /dev/null +++ b/common/fileops.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1999-2005, 2007, 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#include + +#include +#include +#include +#ifdef HAVE_FLOCK +# include +#endif /* HAVE_FLOCK */ +#include +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#if TIME_WITH_SYS_TIME +# include +#endif +#ifndef HAVE_STRUCT_TIMESPEC +# include "compat/timespec.h" +#endif + +#include "missing.h" +#include "fileops.h" +#include "sudo_debug.h" + +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + +/* + * Update the access and modify times on an fd or file. + */ +int +touch(int fd, char *path, struct timeval *tvp) +{ + struct timeval times[2]; + int rval = -1; + debug_decl(touch, SUDO_DEBUG_UTIL) + + if (tvp != NULL) { + times[0].tv_sec = times[1].tv_sec = tvp->tv_sec; + times[0].tv_usec = times[1].tv_usec = tvp->tv_usec; + } + +#if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES) + if (fd != -1) + rval = futimes(fd, tvp ? times : NULL); + else +#endif + if (path != NULL) + rval = utimes(path, tvp ? times : NULL); + debug_return_int(rval); +} + +/* + * Lock/unlock a file. + */ +#ifdef HAVE_LOCKF +bool +lock_file(int fd, int lockit) +{ + int op = 0; + debug_decl(lock_file, SUDO_DEBUG_UTIL) + + switch (lockit) { + case SUDO_LOCK: + op = F_LOCK; + break; + case SUDO_TLOCK: + op = F_TLOCK; + break; + case SUDO_UNLOCK: + op = F_ULOCK; + break; + } + debug_return_bool(lockf(fd, op, 0) == 0); +} +#elif HAVE_FLOCK +bool +lock_file(int fd, int lockit) +{ + int op = 0; + debug_decl(lock_file, SUDO_DEBUG_UTIL) + + switch (lockit) { + case SUDO_LOCK: + op = LOCK_EX; + break; + case SUDO_TLOCK: + op = LOCK_EX | LOCK_NB; + break; + case SUDO_UNLOCK: + op = LOCK_UN; + break; + } + debug_return_bool(flock(fd, op) == 0); +} +#else +bool +lock_file(int fd, int lockit) +{ +#ifdef F_SETLK + int func; + struct flock lock; + debug_decl(lock_file, SUDO_DEBUG_UTIL) + + lock.l_start = 0; + lock.l_len = 0; + lock.l_pid = getpid(); + lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK; + lock.l_whence = SEEK_SET; + func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK; + + debug_return_bool(fcntl(fd, func, &lock) == 0); +#else + return true; +#endif +} +#endif + +/* + * Read a line of input, remove comments and strip off leading + * and trailing spaces. Returns static storage that is reused. + */ +char * +sudo_parseln(FILE *fp) +{ + size_t len; + char *cp = NULL; + static char buf[LINE_MAX]; + debug_decl(sudo_parseln, SUDO_DEBUG_UTIL) + + if (fgets(buf, sizeof(buf), fp) != NULL) { + /* Remove comments */ + if ((cp = strchr(buf, '#')) != NULL) + *cp = '\0'; + + /* Trim leading and trailing whitespace/newline */ + len = strlen(buf); + while (len > 0 && isspace((unsigned char)buf[len - 1])) + buf[--len] = '\0'; + for (cp = buf; isblank((unsigned char)*cp); cp++) + continue; + } + debug_return_str(cp); +} diff --git a/common/fmt_string.c b/common/fmt_string.c new file mode 100644 index 0000000..23bc5f7 --- /dev/null +++ b/common/fmt_string.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010-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. + */ + +#include + +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ + +#include "missing.h" +#include "sudo_debug.h" + +/* + * Allocate storage for a name=value string and return it. + */ +char * +fmt_string(const char *var, const char *val) +{ + size_t var_len = strlen(var); + size_t val_len = strlen(val); + char *cp, *str; + debug_decl(fmt_string, SUDO_DEBUG_UTIL) + + cp = str = malloc(var_len + 1 + val_len + 1); + if (str != NULL) { + memcpy(cp, var, var_len); + cp += var_len; + *cp++ = '='; + memcpy(cp, val, val_len); + cp += val_len; + *cp = '\0'; + } + + debug_return_str(str); +} diff --git a/common/lbuf.c b/common/lbuf.c new file mode 100644 index 0000000..4618b94 --- /dev/null +++ b/common/lbuf.c @@ -0,0 +1,274 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "lbuf.h" +#include "sudo_debug.h" + +void +lbuf_init(struct lbuf *lbuf, int (*output)(const char *), + int indent, const char *continuation, int cols) +{ + debug_decl(lbuf_init, SUDO_DEBUG_UTIL) + + lbuf->output = output; + lbuf->continuation = continuation; + lbuf->indent = indent; + lbuf->cols = cols; + lbuf->len = 0; + lbuf->size = 0; + lbuf->buf = NULL; + + debug_return; +} + +void +lbuf_destroy(struct lbuf *lbuf) +{ + debug_decl(lbuf_destroy, SUDO_DEBUG_UTIL) + + efree(lbuf->buf); + lbuf->buf = NULL; + + debug_return; +} + +/* + * Parse the format and append strings, only %s and %% escapes are supported. + * Any characters in set are quoted with a backslash. + */ +void +lbuf_append_quoted(struct lbuf *lbuf, const char *set, const char *fmt, ...) +{ + va_list ap; + int len; + char *cp, *s = NULL; + debug_decl(lbuf_append_quoted, SUDO_DEBUG_UTIL) + + va_start(ap, fmt); + while (*fmt != '\0') { + len = 1; + if (fmt[0] == '%' && fmt[1] == 's') { + s = va_arg(ap, char *); + len = strlen(s); + } + /* Assume worst case that all chars must be escaped. */ + if (lbuf->len + (len * 2) + 1 >= lbuf->size) { + do { + lbuf->size += 256; + } while (lbuf->len + len + 1 >= lbuf->size); + lbuf->buf = erealloc(lbuf->buf, lbuf->size); + } + if (*fmt == '%') { + if (*(++fmt) == 's') { + while ((cp = strpbrk(s, set)) != NULL) { + len = (int)(cp - s); + memcpy(lbuf->buf + lbuf->len, s, len); + lbuf->len += len; + lbuf->buf[lbuf->len++] = '\\'; + lbuf->buf[lbuf->len++] = *cp; + s = cp + 1; + } + if (*s != '\0') { + len = strlen(s); + memcpy(lbuf->buf + lbuf->len, s, len); + lbuf->len += len; + } + fmt++; + continue; + } + } + if (strchr(set, *fmt) != NULL) + lbuf->buf[lbuf->len++] = '\\'; + lbuf->buf[lbuf->len++] = *fmt++; + } + lbuf->buf[lbuf->len] = '\0'; + va_end(ap); + + debug_return; +} + +/* + * Parse the format and append strings, only %s and %% escapes are supported. + */ +void +lbuf_append(struct lbuf *lbuf, const char *fmt, ...) +{ + va_list ap; + int len; + char *s = NULL; + debug_decl(lbuf_append, SUDO_DEBUG_UTIL) + + va_start(ap, fmt); + while (*fmt != '\0') { + len = 1; + if (fmt[0] == '%' && fmt[1] == 's') { + s = va_arg(ap, char *); + len = strlen(s); + } + if (lbuf->len + len + 1 >= lbuf->size) { + do { + lbuf->size += 256; + } while (lbuf->len + len + 1 >= lbuf->size); + lbuf->buf = erealloc(lbuf->buf, lbuf->size); + } + if (*fmt == '%') { + if (*(++fmt) == 's') { + memcpy(lbuf->buf + lbuf->len, s, len); + lbuf->len += len; + fmt++; + continue; + } + } + lbuf->buf[lbuf->len++] = *fmt++; + } + lbuf->buf[lbuf->len] = '\0'; + va_end(ap); + + debug_return; +} + +static void +lbuf_println(struct lbuf *lbuf, char *line, int len) +{ + char *cp, save; + int i, have, contlen; + debug_decl(lbuf_println, SUDO_DEBUG_UTIL) + + contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0; + + /* + * Print the buffer, splitting the line as needed on a word + * boundary. + */ + cp = line; + have = lbuf->cols; + while (cp != NULL && *cp != '\0') { + char *ep = NULL; + int need = len - (int)(cp - line); + + if (need > have) { + have -= contlen; /* subtract for continuation char */ + if ((ep = memrchr(cp, ' ', have)) == NULL) + ep = memchr(cp + have, ' ', need - have); + if (ep != NULL) + need = (int)(ep - cp); + } + if (cp != line) { + /* indent continued lines */ + /* XXX - build up string instead? */ + for (i = 0; i < lbuf->indent; i++) + lbuf->output(" "); + } + /* NUL-terminate cp for the output function and restore afterwards */ + save = cp[need]; + cp[need] = '\0'; + lbuf->output(cp); + cp[need] = save; + cp = ep; + + /* + * If there is more to print, reset have, incremement cp past + * the whitespace, and print a line continuaton char if needed. + */ + if (cp != NULL) { + have = lbuf->cols - lbuf->indent; + ep = line + len; + while (cp < ep && isblank((unsigned char)*cp)) { + cp++; + } + if (contlen) + lbuf->output(lbuf->continuation); + } + lbuf->output("\n"); + } + + debug_return; +} + +/* + * Print the buffer with word wrap based on the tty width. + * The lbuf is reset on return. + */ +void +lbuf_print(struct lbuf *lbuf) +{ + char *cp, *ep; + int len; + debug_decl(lbuf_print, SUDO_DEBUG_UTIL) + + if (lbuf->buf == NULL || lbuf->len == 0) + goto done; + + /* For very small widths just give up... */ + len = lbuf->continuation ? strlen(lbuf->continuation) : 0; + if (lbuf->cols <= lbuf->indent + len + 20) { + lbuf->buf[lbuf->len] = '\0'; + lbuf->output(lbuf->buf); + goto done; + } + + /* Print each line in the buffer */ + for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) { + if (*cp == '\n') { + lbuf->output("\n"); + cp++; + } else { + len = lbuf->len - (cp - lbuf->buf); + if ((ep = memchr(cp, '\n', len)) != NULL) + len = (int)(ep - cp); + if (len) + lbuf_println(lbuf, cp, len); + cp = ep ? ep + 1 : NULL; + } + } + +done: + lbuf->len = 0; /* reset the buffer for re-use. */ + + debug_return; +} diff --git a/common/list.c b/common/list.c new file mode 100644 index 0000000..a656a6e --- /dev/null +++ b/common/list.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2007-2008, 2010-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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ + +#include "missing.h" +#include "list.h" +#ifdef DEBUG +# include "error.h" +#endif + +struct list_proto { + struct list_proto *prev; + struct list_proto *next; +}; + +struct list_head_proto { + struct list_proto *first; + struct list_proto *last; +}; + +/* + * Pop the last element off the end of vh. + * Returns the popped element. + */ +void * +tq_pop(void *vh) +{ + struct list_head_proto *h = (struct list_head_proto *)vh; + void *last = NULL; + + if (!tq_empty(h)) { + last = (void *)h->last; + if (h->first == h->last) { + h->first = NULL; + h->last = NULL; + } else { + h->last = h->last->prev; + h->last->next = NULL; + } + } + return last; +} + +/* + * Convert from a semi-circle queue to normal doubly-linked list + * with a head node. + */ +void +list2tq(void *vh, void *vl) +{ + struct list_head_proto *h = (struct list_head_proto *)vh; + struct list_proto *l = (struct list_proto *)vl; + + if (l != NULL) { +#ifdef DEBUG + if (l->prev == NULL) { + warningx2("list2tq called with non-semicircular list"); + abort(); + } +#endif + h->first = l; + h->last = l->prev; /* l->prev points to the last member of l */ + l->prev = NULL; /* zero last ptr now that we have a head */ + } else { + h->first = NULL; + h->last = NULL; + } +} + +/* + * Append one queue (or single entry) to another using the + * circular properties of the prev pointer to simplify the logic. + */ +void +list_append(void *vl1, void *vl2) +{ + struct list_proto *l1 = (struct list_proto *)vl1; + struct list_proto *l2 = (struct list_proto *)vl2; + void *tail = l2->prev; + + l1->prev->next = l2; + l2->prev = l1->prev; + l1->prev = tail; +} + +/* + * Append the list of entries to the head node and convert + * e from a semi-circle queue to normal doubly-linked list. + */ +void +tq_append(void *vh, void *vl) +{ + struct list_head_proto *h = (struct list_head_proto *)vh; + struct list_proto *l = (struct list_proto *)vl; + void *tail = l->prev; + + if (h->first == NULL) + h->first = l; + else + h->last->next = l; + l->prev = h->last; + h->last = tail; +} + +/* + * Remove element from the tail_queue + */ +void +tq_remove(void *vh, void *vl) +{ + struct list_head_proto *h = (struct list_head_proto *)vh; + struct list_proto *l = (struct list_proto *)vl; + + if (h->first == l && h->last == l) { + /* Single element in the list. */ + h->first = NULL; + h->last = NULL; + } else { + /* At least two elements in the list. */ + if (h->first == l) { + h->first = l->next; + h->first->prev = h->first; + } else if (h->last == l) { + h->last = l->prev; + h->last->next = NULL; + } else { + l->prev->next = l->next; + l->next->prev = l->prev; + } + } +} diff --git a/common/secure_path.c b/common/secure_path.c new file mode 100644 index 0000000..bbc38a2 --- /dev/null +++ b/common/secure_path.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012 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. + */ + +#include + +#include +#include +#include +#include +#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 */ +#include + +#include "missing.h" +#include "sudo_debug.h" +#include "secure_path.h" + +/* + * Verify that path is the right type and not writable by other users. + */ +int +sudo_secure_path(const char *path, int type, uid_t uid, gid_t gid, struct stat *sbp) +{ + struct stat sb; + int rval = SUDO_PATH_MISSING; + debug_decl(sudo_secure_path, SUDO_DEBUG_UTIL) + + if (path != NULL && stat_sudoers(path, &sb) == 0) { + if ((sb.st_mode & _S_IFMT) != type) { + rval = SUDO_PATH_BAD_TYPE; + } else if (uid != (uid_t)-1 && sb.st_uid != uid) { + rval = SUDO_PATH_WRONG_OWNER; + } else if (sb.st_mode & S_IWOTH) { + rval = SUDO_PATH_WORLD_WRITABLE; + } else if (ISSET(sb.st_mode, S_IWGRP) && + (gid == (gid_t)-1 || sb.st_gid != gid)) { + rval = SUDO_PATH_GROUP_WRITABLE; + } else { + rval = SUDO_PATH_SECURE; + } + if (sbp) + (void) memcpy(sbp, &sb, sizeof(struct stat)); + } + + debug_return_int(rval); +} + +/* + * Verify that path is a regular file and not writable by other users. + */ +int +sudo_secure_file(const char *path, uid_t uid, gid_t gid, struct stat *sbp) +{ + return sudo_secure_path(path, _S_IFREG, uid, gid, sbp); +} + +/* + * Verify that path is a directory and not writable by other users. + */ +int +sudo_secure_dir(const char *path, uid_t uid, gid_t gid, struct stat *sbp) +{ + return sudo_secure_path(path, _S_IFDIR, uid, gid, sbp); +} diff --git a/common/setgroups.c b/common/setgroups.c new file mode 100644 index 0000000..f34bb5f --- /dev/null +++ b/common/setgroups.c @@ -0,0 +1,59 @@ +/* + * 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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include + +#include "missing.h" +#include "sudo_debug.h" + +int +sudo_setgroups(int ngids, const GETGROUPS_T *gids) +{ + int maxgids, rval; + debug_decl(sudo_setgroups, SUDO_DEBUG_UTIL) + + rval = setgroups(ngids, (GETGROUPS_T *)gids); + if (rval == -1 && errno == EINVAL) { + /* Too many groups, try again with fewer. */ +#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) + maxgids = (int)sysconf(_SC_NGROUPS_MAX); + if (maxgids == -1) +#endif + maxgids = NGROUPS_MAX; + if (ngids > maxgids) + rval = setgroups(maxgids, (GETGROUPS_T *)gids); + } + debug_return_int(rval); +} diff --git a/common/sudo_conf.c b/common/sudo_conf.c new file mode 100644 index 0000000..238d21f --- /dev/null +++ b/common/sudo_conf.c @@ -0,0 +1,370 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif +#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 */ +#include +#include + +#define SUDO_ERROR_WRAP 0 + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "fileops.h" +#include "pathnames.h" +#include "sudo_plugin.h" +#include "sudo_conf.h" +#include "sudo_debug.h" +#include "secure_path.h" +#include "gettext.h" + +#ifdef __TANDEM +# define ROOT_UID 65535 +#else +# define ROOT_UID 0 +#endif + +#ifndef _PATH_SUDO_ASKPASS +# define _PATH_SUDO_ASKPASS NULL +#endif + +extern bool atobool(const char *str); /* atobool.c */ + +struct sudo_conf_table { + const char *name; + unsigned int namelen; + bool (*setter)(const char *entry); +}; + +struct sudo_conf_paths { + const char *pname; + unsigned int pnamelen; + const char *pval; +}; + +static bool set_debug(const char *entry); +static bool set_path(const char *entry); +static bool set_plugin(const char *entry); +static bool set_variable(const char *entry); + +static struct sudo_conf_table sudo_conf_table[] = { + { "Debug", sizeof("Debug") - 1, set_debug }, + { "Path", sizeof("Path") - 1, set_path }, + { "Plugin", sizeof("Plugin") - 1, set_plugin }, + { "Set", sizeof("Set") - 1, set_variable }, + { NULL } +}; + +static struct sudo_conf_data { + bool disable_coredump; + const char *debug_flags; + struct sudo_conf_paths paths[3]; + struct plugin_info_list plugins; +} sudo_conf_data = { + true, + NULL, + { +#define SUDO_CONF_ASKPASS_IDX 0 + { "askpass", sizeof("askpass") - 1, _PATH_SUDO_ASKPASS }, +#ifdef _PATH_SUDO_NOEXEC +#define SUDO_CONF_NOEXEC_IDX 1 + { "noexec", sizeof("noexec") - 1, _PATH_SUDO_NOEXEC }, +#endif + { NULL } + } +}; + +/* + * "Set variable_name value" + */ +static bool +set_variable(const char *entry) +{ +#undef DC_LEN +#define DC_LEN (sizeof("disable_coredump") - 1) + /* Currently the only variable supported is "disable_coredump". */ + if (strncmp(entry, "disable_coredump", DC_LEN) == 0 && + isblank((unsigned char)entry[DC_LEN])) { + entry += DC_LEN + 1; + while (isblank((unsigned char)*entry)) + entry++; + sudo_conf_data.disable_coredump = atobool(entry); + } +#undef DC_LEN + return true; +} + +/* + * "Debug progname debug_file debug_flags" + */ +static bool +set_debug(const char *entry) +{ + size_t filelen, proglen; + const char *progname; + char *debug_file, *debug_flags; + + /* Is this debug setting for me? */ + progname = getprogname(); + if (strcmp(progname, "sudoedit") == 0) + progname = "sudo"; + proglen = strlen(progname); + if (strncmp(entry, progname, proglen) != 0 || + !isblank((unsigned char)entry[proglen])) + return false; + entry += proglen + 1; + while (isblank((unsigned char)*entry)) + entry++; + + debug_flags = strpbrk(entry, " \t"); + if (debug_flags == NULL) + return false; + filelen = (size_t)(debug_flags - entry); + while (isblank((unsigned char)*debug_flags)) + debug_flags++; + + /* Set debug file and parse the flags (init debug as soon as possible). */ + debug_file = estrndup(entry, filelen); + debug_flags = estrdup(debug_flags); + sudo_debug_init(debug_file, debug_flags); + efree(debug_file); + + sudo_conf_data.debug_flags = debug_flags; + + return true; +} + +static bool +set_path(const char *entry) +{ + const char *name, *path; + struct sudo_conf_paths *cur; + + /* Parse Path line */ + name = entry; + path = strpbrk(entry, " \t"); + if (path == NULL) + return false; + while (isblank((unsigned char)*path)) + path++; + + /* Match supported paths, ignore the rest. */ + for (cur = sudo_conf_data.paths; cur->pname != NULL; cur++) { + if (strncasecmp(name, cur->pname, cur->pnamelen) == 0 && + isblank((unsigned char)name[cur->pnamelen])) { + cur->pval = estrdup(path); + break; + } + } + + return true; +} + +static bool +set_plugin(const char *entry) +{ + struct plugin_info *info; + const char *name, *path, *cp, *ep; + char **options = NULL; + size_t namelen, pathlen; + unsigned int nopts; + + /* Parse Plugin line */ + name = entry; + path = strpbrk(entry, " \t"); + if (path == NULL) + return false; + namelen = (size_t)(path - name); + while (isblank((unsigned char)*path)) + path++; + if ((cp = strpbrk(path, " \t")) != NULL) { + /* Convert any options to an array. */ + pathlen = (size_t)(cp - path); + while (isblank((unsigned char)*cp)) + cp++; + /* Count number of options and allocate array. */ + for (ep = cp, nopts = 1; (ep = strpbrk(ep, " \t")) != NULL; nopts++) { + while (isblank((unsigned char)*ep)) + ep++; + } + options = emalloc2(nopts + 1, sizeof(*options)); + /* Fill in options array, there is at least one element. */ + for (nopts = 0; (ep = strpbrk(cp, " \t")) != NULL; ) { + options[nopts++] = estrndup(cp, (size_t)(ep - cp)); + while (isblank((unsigned char)*ep)) + ep++; + cp = ep; + } + options[nopts++] = estrdup(cp); + options[nopts] = NULL; + } else { + /* No extra options. */ + pathlen = strlen(path); + } + + info = ecalloc(1, sizeof(*info)); + info->symbol_name = estrndup(name, namelen); + info->path = estrndup(path, pathlen); + info->options = options; + info->prev = info; + /* info->next = NULL; */ + tq_append(&sudo_conf_data.plugins, info); + + return true; +} + +const char * +sudo_conf_askpass_path(void) +{ + return sudo_conf_data.paths[SUDO_CONF_ASKPASS_IDX].pval; +} + +#ifdef _PATH_SUDO_NOEXEC +const char * +sudo_conf_noexec_path(void) +{ + return sudo_conf_data.paths[SUDO_CONF_NOEXEC_IDX].pval; +} +#endif + +const char * +sudo_conf_debug_flags(void) +{ + return sudo_conf_data.debug_flags; +} + +struct plugin_info_list * +sudo_conf_plugins(void) +{ + return &sudo_conf_data.plugins; +} + +bool +sudo_conf_disable_coredump(void) +{ + return sudo_conf_data.disable_coredump; +} + +/* + * Reads in /etc/sudo.conf and populates sudo_conf_data. + */ +void +sudo_conf_read(void) +{ + struct sudo_conf_table *cur; + struct plugin_info *info; + struct stat sb; + FILE *fp; + char *cp; + + switch (sudo_secure_file(_PATH_SUDO_CONF, ROOT_UID, -1, &sb)) { + case SUDO_PATH_SECURE: + break; + case SUDO_PATH_MISSING: + /* Root should always be able to read sudo.conf. */ + if (errno != ENOENT && geteuid() == ROOT_UID) + warning(_("unable to stat %s"), _PATH_SUDO_CONF); + goto done; + case SUDO_PATH_BAD_TYPE: + warningx(_("%s is not a regular file"), _PATH_SUDO_CONF); + goto done; + case SUDO_PATH_WRONG_OWNER: + warningx(_("%s is owned by uid %u, should be %u"), + _PATH_SUDO_CONF, (unsigned int) sb.st_uid, ROOT_UID); + goto done; + case SUDO_PATH_WORLD_WRITABLE: + warningx(_("%s is world writable"), _PATH_SUDO_CONF); + goto done; + case SUDO_PATH_GROUP_WRITABLE: + warningx(_("%s is group writable"), _PATH_SUDO_CONF); + goto done; + default: + /* NOTREACHED */ + goto done; + } + + if ((fp = fopen(_PATH_SUDO_CONF, "r")) == NULL) { + if (errno != ENOENT && geteuid() == ROOT_UID) + warning(_("unable to open %s"), _PATH_SUDO_CONF); + goto done; + } + + while ((cp = sudo_parseln(fp)) != NULL) { + /* Skip blank or comment lines */ + if (*cp == '\0') + continue; + + for (cur = sudo_conf_table; cur->name != NULL; cur++) { + if (strncasecmp(cp, cur->name, cur->namelen) == 0 && + isblank((unsigned char)cp[cur->namelen])) { + cp += cur->namelen; + while (isblank((unsigned char)*cp)) + cp++; + if (cur->setter(cp)) + break; + } + } + } + fclose(fp); + +done: + if (tq_empty(&sudo_conf_data.plugins)) { + /* Default policy plugin */ + info = ecalloc(1, sizeof(*info)); + info->symbol_name = "sudoers_policy"; + info->path = SUDOERS_PLUGIN; + /* info->options = NULL; */ + info->prev = info; + /* info->next = NULL; */ + tq_append(&sudo_conf_data.plugins, info); + + /* Default I/O plugin */ + info = ecalloc(1, sizeof(*info)); + info->symbol_name = "sudoers_io"; + info->path = SUDOERS_PLUGIN; + /* info->options = NULL; */ + info->prev = info; + /* info->next = NULL; */ + tq_append(&sudo_conf_data.plugins, info); + } +} diff --git a/common/sudo_debug.c b/common/sudo_debug.c new file mode 100644 index 0000000..f41fa8b --- /dev/null +++ b/common/sudo_debug.c @@ -0,0 +1,552 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif +#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 */ +#include +#include +#include +#include + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "gettext.h" +#include "sudo_plugin.h" +#include "sudo_debug.h" + +/* + * The debug priorities and subsystems are currently hard-coded. + * In the future we might consider allowing plugins to register their + * own subsystems and provide direct access to the debugging API. + */ + +/* Note: this must match the order in sudo_debug.h */ +const char *const sudo_debug_priorities[] = { + "crit", + "err", + "warn", + "notice", + "diag", + "info", + "trace", + "debug", + NULL +}; + +/* Note: this must match the order in sudo_debug.h */ +const char *const sudo_debug_subsystems[] = { + "main", + "args", + "exec", + "pty", + "utmp", + "conv", + "pcomm", + "util", + "netif", + "audit", + "edit", + "selinux", + "ldap", + "match", + "parser", + "alias", + "defaults", + "auth", + "env", + "logging", + "nss", + "rbtree", + "perms", + "plugin", + "hooks", + NULL +}; + +#define NUM_SUBSYSTEMS (sizeof(sudo_debug_subsystems) / sizeof(sudo_debug_subsystems[0]) - 1) + +/* Values for sudo_debug_mode */ +#define SUDO_DEBUG_MODE_DISABLED 0 +#define SUDO_DEBUG_MODE_FILE 1 +#define SUDO_DEBUG_MODE_CONV 2 + +static int sudo_debug_settings[NUM_SUBSYSTEMS]; +static int sudo_debug_fd = -1; +static int sudo_debug_mode; +static char sudo_debug_pidstr[(((sizeof(int) * 8) + 2) / 3) + 3]; +static size_t sudo_debug_pidlen; + +extern sudo_conv_t sudo_conv; + +/* + * Parse settings string from sudo.conf and open debugfile. + * Returns 1 on success, 0 if cannot open debugfile. + * Unsupported subsystems and priorities are silently ignored. + */ +int sudo_debug_init(const char *debugfile, const char *settings) +{ + char *buf, *cp, *subsys, *pri; + int i, j; + + /* Init per-subsystems settings to -1 since 0 is a valid priority. */ + for (i = 0; i < NUM_SUBSYSTEMS; i++) + sudo_debug_settings[i] = -1; + + /* Open debug file if specified. */ + if (debugfile != NULL) { + if (sudo_debug_fd != -1) + close(sudo_debug_fd); + sudo_debug_fd = open(debugfile, O_WRONLY|O_APPEND|O_CREAT, + S_IRUSR|S_IWUSR); + if (sudo_debug_fd == -1) + return 0; + (void)fcntl(sudo_debug_fd, F_SETFD, FD_CLOEXEC); + sudo_debug_mode = SUDO_DEBUG_MODE_FILE; + } else { + /* Called from the plugin, no debug file. */ + sudo_debug_mode = SUDO_DEBUG_MODE_CONV; + } + + /* Parse settings string. */ + buf = estrdup(settings); + for ((cp = strtok(buf, ",")); cp != NULL; (cp = strtok(NULL, ","))) { + /* Should be in the form subsys@pri. */ + subsys = cp; + if ((pri = strchr(cp, '@')) == NULL) + continue; + *pri++ = '\0'; + + /* Look up priority and subsystem, fill in sudo_debug_settings[]. */ + for (i = 0; sudo_debug_priorities[i] != NULL; i++) { + if (strcasecmp(pri, sudo_debug_priorities[i]) == 0) { + for (j = 0; sudo_debug_subsystems[j] != NULL; j++) { + if (strcasecmp(subsys, "all") == 0) { + sudo_debug_settings[j] = i; + continue; + } + if (strcasecmp(subsys, sudo_debug_subsystems[j]) == 0) { + sudo_debug_settings[j] = i; + break; + } + } + break; + } + } + } + efree(buf); + + (void)snprintf(sudo_debug_pidstr, sizeof(sudo_debug_pidstr), "[%d] ", + (int)getpid()); + sudo_debug_pidlen = strlen(sudo_debug_pidstr); + + return 1; +} + +pid_t +sudo_debug_fork(void) +{ + pid_t pid; + + if ((pid = fork()) == 0) { + (void)snprintf(sudo_debug_pidstr, sizeof(sudo_debug_pidstr), "[%d] ", + (int)getpid()); + sudo_debug_pidlen = strlen(sudo_debug_pidstr); + } + + return pid; +} + +void +sudo_debug_enter(const char *func, const char *file, int line, + int subsys) +{ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "-> %s @ %s:%d", func, file, line); +} + +void sudo_debug_exit(const char *func, const char *file, int line, + int subsys) +{ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d", func, file, line); +} + +void sudo_debug_exit_int(const char *func, const char *file, int line, + int subsys, int rval) +{ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %d", func, file, line, rval); +} + +void sudo_debug_exit_long(const char *func, const char *file, int line, + int subsys, long rval) +{ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %ld", func, file, line, rval); +} + +void sudo_debug_exit_size_t(const char *func, const char *file, int line, + int subsys, size_t rval) +{ + /* XXX - should use %zu but our snprintf.c doesn't support it */ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %lu", func, file, line, (unsigned long)rval); +} + +/* We use int, not bool, here for functions that return -1 on error. */ +void sudo_debug_exit_bool(const char *func, const char *file, int line, + int subsys, int rval) +{ + if (rval == true || rval == false) { + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %s", func, file, line, rval ? "true" : "false"); + } else { + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %d", func, file, line, rval); + } +} + +void sudo_debug_exit_str(const char *func, const char *file, int line, + int subsys, const char *rval) +{ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %s", func, file, line, rval ? rval : "(null)"); +} + +void sudo_debug_exit_str_masked(const char *func, const char *file, int line, + int subsys, const char *rval) +{ + static const char stars[] = "********************************************************************************"; + int len = rval ? strlen(rval) : sizeof("(null)") - 1; + + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %.*s", func, file, line, len, rval ? stars : "(null)"); +} + +void sudo_debug_exit_ptr(const char *func, const char *file, int line, + int subsys, const void *rval) +{ + sudo_debug_printf2(NULL, NULL, 0, subsys | SUDO_DEBUG_TRACE, + "<- %s @ %s:%d := %p", func, file, line, rval); +} + +static void +sudo_debug_write_conv(const char *func, const char *file, int lineno, + const char *str, int len, int errno_val) +{ + struct sudo_conv_message msg; + struct sudo_conv_reply repl; + char *buf = NULL; + + /* Call conversation function */ + if (sudo_conv != NULL) { + /* Remove the newline at the end if appending extra info. */ + if (str[len - 1] == '\n') + len--; + + if (func != NULL && file != NULL && lineno != 0) { + if (errno_val) { + easprintf(&buf, "%.*s: %s @ %s() %s:%d", len, str, + strerror(errno_val), func, file, lineno); + } else { + easprintf(&buf, "%.*s @ %s() %s:%d", len, str, + func, file, lineno); + } + str = buf; + } else if (errno_val) { + easprintf(&buf, "%.*s: %s", len, str, strerror(errno_val)); + str = buf; + } + memset(&msg, 0, sizeof(msg)); + memset(&repl, 0, sizeof(repl)); + msg.msg_type = SUDO_CONV_DEBUG_MSG; + msg.msg = str; + sudo_conv(1, &msg, &repl); + if (buf != NULL) + efree(buf); + } +} + +static void +sudo_debug_write_file(const char *func, const char *file, int lineno, + const char *str, int len, int errno_val) +{ + char *timestr, numbuf[(((sizeof(int) * 8) + 2) / 3) + 2]; + time_t now; + struct iovec iov[12]; + int iovcnt = 4; + bool need_newline = false; + + /* Prepend program name and pid with a trailing space. */ + iov[1].iov_base = (char *)getprogname(); + iov[1].iov_len = strlen(iov[1].iov_base); + iov[2].iov_base = sudo_debug_pidstr; + iov[2].iov_len = sudo_debug_pidlen; + + /* Add string along with newline if it doesn't have one. */ + iov[3].iov_base = (char *)str; + iov[3].iov_len = len; + if (str[len - 1] != '\n') + need_newline = true; + + /* Append error string if errno is specified. */ + if (errno_val) { + iov[iovcnt].iov_base = ": "; + iov[iovcnt].iov_len = 2; + iovcnt++; + iov[iovcnt].iov_base = strerror(errno_val); + iov[iovcnt].iov_len = strlen(iov[iovcnt].iov_base); + iovcnt++; + + /* Move newline to the end. */ + if (!need_newline) { + need_newline = true; + iov[3].iov_len--; + } + } + + /* If function, file and lineno are specified, append them. */ + if (func != NULL && file != NULL && lineno != 0) { + iov[iovcnt].iov_base = " @ "; + iov[iovcnt].iov_len = 3; + iovcnt++; + + iov[iovcnt].iov_base = (char *)func; + iov[iovcnt].iov_len = strlen(func); + iovcnt++; + + iov[iovcnt].iov_base = "() "; + iov[iovcnt].iov_len = 3; + iovcnt++; + + iov[iovcnt].iov_base = (char *)file; + iov[iovcnt].iov_len = strlen(file); + iovcnt++; + + (void)snprintf(numbuf, sizeof(numbuf), ":%d", lineno); + iov[iovcnt].iov_base = numbuf; + iov[iovcnt].iov_len = strlen(numbuf); + iovcnt++; + + /* Move newline to the end. */ + if (!need_newline) { + need_newline = true; + iov[3].iov_len--; + } + } + + /* Append newline as needed. */ + if (need_newline) { + /* force newline */ + iov[iovcnt].iov_base = "\n"; + iov[iovcnt].iov_len = 1; + iovcnt++; + } + + /* Do timestamp last due to ctime's static buffer. */ + now = time(NULL); + timestr = ctime(&now) + 4; + timestr[15] = ' '; /* replace year with a space */ + timestr[16] = '\0'; + iov[0].iov_base = timestr; + iov[0].iov_len = 16; + + /* Write message in a single syscall */ + ignore_result(writev(sudo_debug_fd, iov, iovcnt)); +} + +void +sudo_debug_write2(const char *func, const char *file, int lineno, + const char *str, int len, int errno_val) +{ + if (len <= 0) + return; + + switch (sudo_debug_mode) { + case SUDO_DEBUG_MODE_CONV: + sudo_debug_write_conv(func, file, lineno, str, len, errno_val); + break; + case SUDO_DEBUG_MODE_FILE: + sudo_debug_write_file(func, file, lineno, str, len, errno_val); + break; + } +} + +/* XXX - turn into a macro */ +void +sudo_debug_write(const char *str, int len, int errno_val) +{ + sudo_debug_write2(NULL, NULL, 0, str, len, errno_val); +} + +void +sudo_debug_printf2(const char *func, const char *file, int lineno, int level, + const char *fmt, ...) +{ + int buflen, pri, subsys, saved_errno = errno; + va_list ap; + char *buf; + + if (!sudo_debug_mode) + return; + + /* Extract pri and subsystem from level. */ + pri = SUDO_DEBUG_PRI(level); + subsys = SUDO_DEBUG_SUBSYS(level); + + /* Make sure we want debug info at this level. */ + if (subsys < NUM_SUBSYSTEMS && sudo_debug_settings[subsys] >= pri) { + va_start(ap, fmt); + buflen = vasprintf(&buf, fmt, ap); + va_end(ap); + if (buflen != -1) { + int errcode = ISSET(level, SUDO_DEBUG_ERRNO) ? saved_errno : 0; + if (ISSET(level, SUDO_DEBUG_LINENO)) + sudo_debug_write2(func, file, lineno, buf, buflen, errcode); + else + sudo_debug_write2(NULL, NULL, 0, buf, buflen, errcode); + free(buf); + } + } + + errno = saved_errno; +} + +void +sudo_debug_execve2(int level, const char *path, char *const argv[], char *const envp[]) +{ + char * const *av; + char *buf, *cp; + int buflen, pri, subsys, log_envp = 0; + size_t plen; + + if (!sudo_debug_mode) + return; + + /* Extract pri and subsystem from level. */ + pri = SUDO_DEBUG_PRI(level); + subsys = SUDO_DEBUG_SUBSYS(level); + + /* Make sure we want debug info at this level. */ + if (subsys >= NUM_SUBSYSTEMS || sudo_debug_settings[subsys] < pri) + return; + + /* Log envp for debug level "debug". */ + if (sudo_debug_settings[subsys] >= SUDO_DEBUG_DEBUG - 1 && envp[0] != NULL) + log_envp = 1; + +#define EXEC_PREFIX "exec " + + /* Alloc and build up buffer. */ + plen = strlen(path); + buflen = sizeof(EXEC_PREFIX) -1 + plen; + if (argv[0] != NULL) { + buflen += sizeof(" []") - 1; + for (av = argv; *av; av++) + buflen += strlen(*av) + 1; + buflen--; + } + if (log_envp) { + buflen += sizeof(" []") - 1; + for (av = envp; *av; av++) + buflen += strlen(*av) + 1; + buflen--; + } + buf = malloc(buflen + 1); + if (buf == NULL) + return; + + /* Copy prefix and command. */ + memcpy(buf, EXEC_PREFIX, sizeof(EXEC_PREFIX) - 1); + cp = buf + sizeof(EXEC_PREFIX) - 1; + memcpy(cp, path, plen); + cp += plen; + + /* Copy argv. */ + if (argv[0] != NULL) { + *cp++ = ' '; + *cp++ = '['; + for (av = argv; *av; av++) { + size_t avlen = strlen(*av); + memcpy(cp, *av, avlen); + cp += avlen; + *cp++ = ' '; + } + cp[-1] = ']'; + } + + if (log_envp) { + *cp++ = ' '; + *cp++ = '['; + for (av = envp; *av; av++) { + size_t avlen = strlen(*av); + memcpy(cp, *av, avlen); + cp += avlen; + *cp++ = ' '; + } + cp[-1] = ']'; + } + + *cp = '\0'; + + sudo_debug_write(buf, buflen, 0); + free(buf); +} + +/* + * Dup sudo_debug_fd to the specified value so we don't + * close it when calling closefrom(). + */ +int +sudo_debug_fd_set(int fd) +{ + if (sudo_debug_fd != -1 && fd != sudo_debug_fd) { + if (dup2(sudo_debug_fd, fd) == -1) + return -1; + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); + close(sudo_debug_fd); + sudo_debug_fd = fd; + } + return sudo_debug_fd; +} diff --git a/common/term.c b/common/term.c new file mode 100644 index 0000000..e9c4a49 --- /dev/null +++ b/common/term.c @@ -0,0 +1,164 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#include + +#include "missing.h" +#include "sudo_debug.h" + +#ifndef TCSASOFT +# define TCSASOFT 0 +#endif +#ifndef ECHONL +# define ECHONL 0 +#endif +#ifndef IEXTEN +# define IEXTEN 0 +#endif +#ifndef IUCLC +# define IUCLC 0 +#endif + +#ifndef _POSIX_VDISABLE +# ifdef VDISABLE +# define _POSIX_VDISABLE VDISABLE +# else +# define _POSIX_VDISABLE 0 +# endif +#endif + +static struct termios term, oterm; +static int changed; +int term_erase; +int term_kill; + +int +term_restore(int fd, int flush) +{ + debug_decl(term_restore, SUDO_DEBUG_UTIL) + + if (changed) { + int flags = TCSASOFT; + flags |= flush ? TCSAFLUSH : TCSADRAIN; + if (tcsetattr(fd, flags, &oterm) != 0) + debug_return_int(0); + changed = 0; + } + debug_return_int(1); +} + +int +term_noecho(int fd) +{ + debug_decl(term_noecho, SUDO_DEBUG_UTIL) + + if (!changed && tcgetattr(fd, &oterm) != 0) + debug_return_int(0); + (void) memcpy(&term, &oterm, sizeof(term)); + CLR(term.c_lflag, ECHO|ECHONL); +#ifdef VSTATUS + term.c_cc[VSTATUS] = _POSIX_VDISABLE; +#endif + if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { + changed = 1; + debug_return_int(1); + } + debug_return_int(0); +} + +int +term_raw(int fd, int isig) +{ + struct termios term; + debug_decl(term_raw, SUDO_DEBUG_UTIL) + + if (!changed && tcgetattr(fd, &oterm) != 0) + return 0; + (void) memcpy(&term, &oterm, sizeof(term)); + /* Set terminal to raw mode */ + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON); + CLR(term.c_oflag, OPOST); + CLR(term.c_lflag, ECHO | ICANON | ISIG | IEXTEN); + if (isig) + SET(term.c_lflag, ISIG); + if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { + changed = 1; + debug_return_int(1); + } + debug_return_int(0); +} + +int +term_cbreak(int fd) +{ + debug_decl(term_cbreak, SUDO_DEBUG_UTIL) + + if (!changed && tcgetattr(fd, &oterm) != 0) + return 0; + (void) memcpy(&term, &oterm, sizeof(term)); + /* Set terminal to half-cooked mode */ + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; + CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN); + SET(term.c_lflag, ISIG); +#ifdef VSTATUS + term.c_cc[VSTATUS] = _POSIX_VDISABLE; +#endif + if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { + term_erase = term.c_cc[VERASE]; + term_kill = term.c_cc[VKILL]; + changed = 1; + debug_return_int(1); + } + debug_return_int(0); +} + +int +term_copy(int src, int dst) +{ + struct termios tt; + debug_decl(term_copy, SUDO_DEBUG_UTIL) + + if (tcgetattr(src, &tt) != 0) + debug_return_int(0); + if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0) + debug_return_int(0); + debug_return_int(1); +} diff --git a/common/ttysize.c b/common/ttysize.c new file mode 100644 index 0000000..d3ac78b --- /dev/null +++ b/common/ttysize.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include "missing.h" +#include "sudo_debug.h" + +/* Compatibility with older tty systems. */ +#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE) +# define TIOCGWINSZ TIOCGSIZE +# define winsize ttysize +# define ws_col ts_cols +# define ws_row ts_lines +#endif + +#ifdef TIOCGWINSZ +static int +get_ttysize_ioctl(int *rowp, int *colp) +{ + struct winsize wsize; + debug_decl(get_ttysize_ioctl, SUDO_DEBUG_EXEC) + + if (ioctl(STDERR_FILENO, TIOCGWINSZ, &wsize) == 0 && + wsize.ws_row != 0 && wsize.ws_col != 0) { + *rowp = wsize.ws_row; + *colp = wsize.ws_col; + debug_return_int(0); + } + debug_return_int(-1); +} +#else +static int +get_ttysize_ioctl(int *rowp, int *colp) +{ + return -1; +} +#endif /* TIOCGWINSZ */ + +void +get_ttysize(int *rowp, int *colp) +{ + debug_decl(fork_cmnd, SUDO_DEBUG_EXEC) + + if (get_ttysize_ioctl(rowp, colp) == -1) { + char *p; + + /* Fall back on $LINES and $COLUMNS. */ + if ((p = getenv("LINES")) == NULL || (*rowp = atoi(p)) <= 0) + *rowp = 24; + if ((p = getenv("COLUMNS")) == NULL || (*colp = atoi(p)) <= 0) + *colp = 80; + } + + debug_return; +} diff --git a/common/zero_bytes.c b/common/zero_bytes.c new file mode 100644 index 0000000..f6f22bc --- /dev/null +++ b/common/zero_bytes.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2003-2005, 2007, 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. + */ + +#include + +#include + +#include "missing.h" + +/* + * Like bzero(3) but with a volatile pointer. The hope is that + * the compiler will not be able to optimize away this function. + */ +void +zero_bytes(volatile void *v, size_t n) +{ + volatile char *p, *ep; + + for (p = v, ep = p + n; p < ep; p++) + *p = 0; + return; +} diff --git a/compat.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/compat/Makefile.in b/compat/Makefile.in new file mode 100644 index 0000000..d0361ce --- /dev/null +++ b/compat/Makefile.in @@ -0,0 +1,199 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# OS dependent defines +DEFS = @OSDEFS@ + +# Set to non-empty for development mode +DEVEL = @DEVEL@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +TEST_PROGS = @COMPAT_TEST_PROGS@ + +LIBOBJDIR = + +LTLIBOBJS = @LTLIBOBJS@ + +all: libreplace.la + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file compat/Makefile) + +.SUFFIXES: .o .c .h .lo + +.c.o: + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +libreplace.la: $(LTLIBOBJS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(LTLIBOBJS) -no-install + +siglist.c: mksiglist + ./mksiglist > $@ + +mksiglist: $(srcdir)/mksiglist.c $(srcdir)/mksiglist.h $(incdir)/missing.h $(top_builddir)/config.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mksiglist.c -o $@ + +fnm_test: fnm_test.o libreplace.la + $(LIBTOOL) --mode=link $(CC) -o $@ fnm_test.o libreplace.la + +globtest: globtest.o libreplace.la + $(LIBTOOL) --mode=link $(CC) -o $@ globtest.o libreplace.la + +$(srcdir)/mksiglist.h: $(srcdir)/siglist.in + if [ -n "$(DEVEL)" ]; then \ + awk 'BEGIN {print "/* public domain */\n"} /^ [A-Z]/ {printf("#ifdef SIG%s\n if (my_sys_siglist[SIG%s] == NULL)\n\tmy_sys_siglist[SIG%s] = \"%s\";\n#endif\n", $$1, $$1, $$1, substr($$0, 13))}' < $(srcdir)/siglist.in > $@; \ + fi + +pre-install: + +install: + +install-dirs: + +install-binaries: + +install-includes: + +install-doc: + +install-plugin: + +uninstall: + +check: $(TEST_PROGS) + @if [ -f fnm_test ]; then \ + ./fnm_test $(srcdir)/regress/fnmatch/fnm_test.in; \ + fi + @if [ -f globtest ]; then \ + mkdir -p `sed 's@/[^/]*$$@@' $(srcdir)/regress/glob/files | sort -u`; \ + touch `cat $(srcdir)/regress/glob/files`; \ + chmod 0755 `grep '/r[^/]*$$' $(srcdir)/regress/glob/files`; \ + chmod 0444 `grep '/s[^/]*$$' $(srcdir)/regress/glob/files`; \ + chmod 0711 `grep '/t[^/]*$$' $(srcdir)/regress/glob/files`; \ + ./globtest $(srcdir)/regress/glob/globtest.in; \ + rval=$$?; \ + rm -rf fake; \ + exit $$rval; \ + fi + +clean: + -$(LIBTOOL) --mode=clean rm -f $(TEST_PROGS) mksiglist siglist.c *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +closefrom.lo: $(srcdir)/closefrom.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/closefrom.c +dlopen.lo: $(srcdir)/dlopen.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/dlfcn.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/dlopen.c +fnm_test.o: $(srcdir)/regress/fnmatch/fnm_test.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/fnmatch.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/fnmatch/fnm_test.c +fnmatch.lo: $(srcdir)/fnmatch.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(top_srcdir)/compat/charclass.h $(top_srcdir)/compat/fnmatch.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/fnmatch.c +getcwd.lo: $(srcdir)/getcwd.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getcwd.c +getgrouplist.lo: $(srcdir)/getgrouplist.c $(top_builddir)/config.h \ + $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getgrouplist.c +getline.lo: $(srcdir)/getline.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getline.c +getprogname.lo: $(srcdir)/getprogname.c $(top_builddir)/config.h \ + $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getprogname.c +glob.lo: $(srcdir)/glob.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(top_srcdir)/compat/glob.h $(top_srcdir)/compat/charclass.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/glob.c +globtest.o: $(srcdir)/regress/glob/globtest.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/glob.h $(incdir)/missing.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/glob/globtest.c +isblank.lo: $(srcdir)/isblank.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/isblank.c +memrchr.lo: $(srcdir)/memrchr.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/memrchr.c +mksiglist.lo: $(srcdir)/mksiglist.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(top_srcdir)/compat/mksiglist.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mksiglist.c +mktemp.lo: $(srcdir)/mktemp.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mktemp.c +nanosleep.lo: $(srcdir)/nanosleep.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/timespec.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/nanosleep.c +pw_dup.lo: $(srcdir)/pw_dup.c $(top_builddir)/config.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/pw_dup.c +siglist.lo: siglist.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) siglist.c +snprintf.lo: $(srcdir)/snprintf.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/snprintf.c +strlcat.lo: $(srcdir)/strlcat.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strlcat.c +strlcpy.lo: $(srcdir)/strlcpy.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strlcpy.c +strsignal.lo: $(srcdir)/strsignal.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/strsignal.c +utimes.lo: $(srcdir)/utimes.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/utime.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/utimes.c diff --git a/compat/charclass.h b/compat/charclass.h new file mode 100644 index 0000000..4fcf15e --- /dev/null +++ b/compat/charclass.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 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. + */ + +/* + * POSIX character class support for fnmatch() and glob(). + */ +static struct cclass { + const char *name; + int (*isctype)(int); +} cclasses[] = { + { "alnum", isalnum }, + { "alpha", isalpha }, + { "blank", isblank }, + { "cntrl", iscntrl }, + { "digit", isdigit }, + { "graph", isgraph }, + { "lower", islower }, + { "print", isprint }, + { "punct", ispunct }, + { "space", isspace }, + { "upper", isupper }, + { "xdigit", isxdigit }, + { NULL, NULL } +}; + +#define NCCLASSES (sizeof(cclasses) / sizeof(cclasses[0]) - 1) diff --git a/compat/closefrom.c b/compat/closefrom.c new file mode 100644 index 0000000..71777e7 --- /dev/null +++ b/compat/closefrom.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004-2005, 2007, 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. + */ + +#include + +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#include "missing.h" + +#ifndef HAVE_FCNTL_CLOSEM +# ifndef HAVE_DIRFD +# define closefrom_fallback closefrom +# endif +#endif + +/* + * Close all file descriptors greater than or equal to lowfd. + * This is the expensive (ballback) method. + */ +void +closefrom_fallback(int lowfd) +{ + long fd, maxfd; + + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); +} + +/* + * Close all file descriptors greater than or equal to lowfd. + * We try the fast way first, falling back on the slow method. + */ +#ifdef HAVE_FCNTL_CLOSEM +void +closefrom(int lowfd) +{ + if (fcntl(lowfd, F_CLOSEM, 0) == -1) + closefrom_fallback(lowfd); +} +#else +# ifdef HAVE_DIRFD +void +closefrom(int lowfd) +{ + struct dirent *dent; + DIR *dirp; + char *endp; + long fd; + + /* Use /proc/self/fd directory if it exists. */ + if ((dirp = opendir("/proc/self/fd")) != NULL) { + while ((dent = readdir(dirp)) != NULL) { + fd = strtol(dent->d_name, &endp, 10); + if (dent->d_name != endp && *endp == '\0' && + fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) + (void) close((int) fd); + } + (void) closedir(dirp); + } else + closefrom_fallback(lowfd); +} +#endif /* HAVE_DIRFD */ +#endif /* HAVE_FCNTL_CLOSEM */ diff --git a/compat/dlfcn.h b/compat/dlfcn.h new file mode 100644 index 0000000..922c755 --- /dev/null +++ b/compat/dlfcn.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _DLFCN_H_ +#define _DLFCN_H_ + +/* Emulated functions. */ +void *sudo_dlopen(const char *path, int mode); +int sudo_dlclose(void *handle); +void *sudo_dlsym(void *handle, const char *symbol); +char *sudo_dlerror(void); + +/* Map emulated functions to standard names. */ +#define dlopen(p, m) sudo_dlopen(p, m) +#define dlclose(h) sudo_dlclose(h) +#define dlsym(h, s) sudo_dlsym(h, s) +#define dlerror() sudo_dlerror() + +/* Values for dlopen() mode. */ +#define RTLD_LAZY 0x1 +#define RTLD_NOW 0x2 +#define RTLD_GLOBAL 0x4 +#define RTLD_LOCAL 0x8 + +/* Special handle arguments for dlsym(). */ +#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */ +#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */ +#define RTLD_SELF ((void *) -3) /* Search the caller itself. */ + +#endif /* !_DLFCN_H_ */ diff --git a/compat/dlopen.c b/compat/dlopen.c new file mode 100644 index 0000000..f5f62fe --- /dev/null +++ b/compat/dlopen.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 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. + */ + +#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 */ +#include + +#include "compat/dlfcn.h" +#include "missing.h" + +#ifdef HAVE_SHL_LOAD +/* + * Emulate dlopen() using shl_load(). + */ +#include + +#ifndef DYNAMIC_PATH +# define DYNAMIC_PATH 0 +#endif + +void * +sudo_dlopen(const char *path, int mode) +{ + int flags = DYNAMIC_PATH; + + if (mode == 0) + mode = RTLD_LAZY; /* default behavior */ + + /* We don't support RTLD_GLOBAL or RTLD_LOCAL yet. */ + if (ISSET(mode, RTLD_LAZY)) + flags |= BIND_DEFERRED; + if (ISSET(mode, RTLD_NOW)) + flags |= BIND_IMMEDIATE; + + return (void *)shl_load(path, flags, 0L); +} + +int +sudo_dlclose(void *handle) +{ + return shl_unload((shl_t)handle); +} + +void * +sudo_dlsym(void *vhandle, const char *symbol) +{ + shl_t handle = vhandle; + void *value = NULL; + + /* + * Note that the behavior of of RTLD_NEXT and RTLD_SELF + * differs from most implementations when called from + * a shared library. + */ + if (vhandle == RTLD_NEXT) { + /* Iterate over all shared libs looking for symbol. */ + struct shl_descriptor *desc; + int idx = 0; + while (shl_get(idx++, &desc) == 0) { + if (shl_findsym(&desc->handle, symbol, TYPE_UNDEFINED, &value) == 0) + break; + } + } else { + if (vhandle == RTLD_DEFAULT) + handle = NULL; + else if (vhandle == RTLD_SELF) + handle = PROG_HANDLE; + (void)shl_findsym(&handle, symbol, TYPE_UNDEFINED, &value); + } + + return value; +} + +char * +sudo_dlerror(void) +{ + return strerror(errno); +} + +#else /* !HAVE_SHL_LOAD */ + +/* + * Emulate dlopen() using a static list of symbols compiled into sudo. + */ + +struct sudo_preload_table { + const char *name; + void *address; +}; +extern struct sudo_preload_table sudo_preload_table[]; + +void * +sudo_dlopen(const char *path, int mode) +{ + return (void *)path; +} + +int +sudo_dlclose(void *handle) +{ + return 0; +} + +void * +sudo_dlsym(void *handle, const char *symbol) +{ + struct sudo_preload_table *sym; + + if (symbol != RTLD_NEXT && symbol != RTLD_DEFAULT && symbol != RTLD_SELF) { + for (sym = sudo_preload_table; sym->name != NULL; sym++) { + if (strcmp(symbol, sym->name) == 0) + return sym->address; + } + } + return NULL; +} + +char * +sudo_dlerror(void) +{ + return strerror(errno); +} + +#endif /* HAVE_SHL_LOAD */ diff --git a/compat/fnmatch.c b/compat/fnmatch.c new file mode 100644 index 0000000..54a3142 --- /dev/null +++ b/compat/fnmatch.c @@ -0,0 +1,474 @@ +/* $OpenBSD: fnmatch.c,v 1.15 2011/02/10 21:31:59 stsp Exp $ */ + +/* Copyright (c) 2011, VMware, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the VMware, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Authored by William A. Rowe Jr. , April 2011 + * + * Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008 + * as described in; + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html + * + * Filename pattern matches defined in section 2.13, "Pattern Matching Notation" + * from chapter 2. "Shell Command Language" + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 + * where; 1. A bracket expression starting with an unquoted '^' + * character CONTINUES to specify a non-matching list; 2. an explicit '.' + * in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading + * in a filename; 3. a '[' which does not introduce + * a valid bracket expression is treated as an ordinary character; 4. a differing + * number of consecutive slashes within pattern and string will NOT match; + * 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character. + * + * Bracket expansion defined in section 9.3.5, "RE Bracket Expression", + * from chapter 9, "Regular Expressions" + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05 + * with no support for collating symbols, equivalence class expressions or + * character class expressions. A partial range expression with a leading + * hyphen following a valid range expression will match only the ordinary + * and the ending character (e.g. "[a-m-z]" will match characters + * 'a' through 'm', a '-', or a 'z'). + * + * Supports BSD extensions FNM_LEADING_DIR to match pattern to the end of one + * path segment of string, and FNM_CASEFOLD to ignore alpha case. + * + * NOTE: Only POSIX/C single byte locales are correctly supported at this time. + * Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results, + * particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and + * nonalpha characters within a range. + * + * XXX comments below indicate porting required for multi-byte character sets + * and non-POSIX locale collation orders; requires mbr* APIs to track shift + * state of pattern and string (rewinding pattern and string repeatedly). + * + * Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g. + * UTF-8, SHIFT-JIS, etc). Any implementation allowing '\' as an alternate + * path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS. + */ + +#include + +#include + +#include +#include +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include + +#include "missing.h" +#include "compat/charclass.h" +#include "compat/fnmatch.h" + +#define RANGE_MATCH 1 +#define RANGE_NOMATCH 0 +#define RANGE_ERROR (-1) + +static int +classmatch(const char *pattern, char test, int foldcase, const char **ep) +{ + const char * const mismatch = pattern; + const char *colon; + struct cclass *cc; + int rval = RANGE_NOMATCH; + size_t len; + + if (pattern[0] != '[' || pattern[1] != ':') { + *ep = mismatch; + return RANGE_ERROR; + } + pattern += 2; + + if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') { + *ep = mismatch; + return RANGE_ERROR; + } + *ep = colon + 2; + len = (size_t)(colon - pattern); + + if (foldcase && strncmp(pattern, "upper:]", 7) == 0) + pattern = "lower:]"; + for (cc = cclasses; cc->name != NULL; cc++) { + if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') { + if (cc->isctype((unsigned char)test)) + rval = RANGE_MATCH; + break; + } + } + if (cc->name == NULL) { + /* invalid character class, treat as normal text */ + *ep = mismatch; + rval = RANGE_ERROR; + } + return rval; +} + +/* Most MBCS/collation/case issues handled here. Wildcard '*' is not handled. + * EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over, + * however the "\/" sequence is advanced to '/'. + * + * Both pattern and string are **char to support pointer increment of arbitrary + * multibyte characters for the given locale, in a later iteration of this code + */ +static int fnmatch_ch(const char **pattern, const char **string, int flags) +{ + const char * const mismatch = *pattern; + const int nocase = !!(flags & FNM_CASEFOLD); + const int escape = !(flags & FNM_NOESCAPE); + const int slash = !!(flags & FNM_PATHNAME); + int result = FNM_NOMATCH; + const char *startch; + int negate; + + if (**pattern == '[') + { + ++*pattern; + + /* Handle negation, either leading ! or ^ operators (never both) */ + negate = ((**pattern == '!') || (**pattern == '^')); + if (negate) + ++*pattern; + + /* ']' is an ordinary character at the start of the range pattern */ + if (**pattern == ']') + goto leadingclosebrace; + + while (**pattern) + { + if (**pattern == ']') { + ++*pattern; + /* XXX: Fix for MBCS character width */ + ++*string; + return (result ^ negate); + } + + if (escape && (**pattern == '\\')) { + ++*pattern; + + /* Patterns must be terminated with ']', not EOS */ + if (!**pattern) + break; + } + + /* Patterns must be terminated with ']' not '/' */ + if (slash && (**pattern == '/')) + break; + + /* Match character classes. */ + if (classmatch(*pattern, **string, nocase, pattern) + == RANGE_MATCH) { + result = 0; + continue; + } + +leadingclosebrace: + /* Look at only well-formed range patterns; + * "x-]" is not allowed unless escaped ("x-\]") + * XXX: Fix for locale/MBCS character width + */ + if (((*pattern)[1] == '-') && ((*pattern)[2] != ']')) + { + startch = *pattern; + *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2; + + /* NOT a properly balanced [expr] pattern, EOS terminated + * or ranges containing a slash in FNM_PATHNAME mode pattern + * fall out to to the rewind and test '[' literal code path + */ + if (!**pattern || (slash && (**pattern == '/'))) + break; + + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ + if ((**string >= *startch) && (**string <= **pattern)) + result = 0; + else if (nocase && (isupper((unsigned char)**string) || + isupper((unsigned char)*startch) || + isupper((unsigned char)**pattern)) + && (tolower((unsigned char)**string) >= tolower((unsigned char)*startch)) + && (tolower((unsigned char)**string) <= tolower((unsigned char)**pattern))) + result = 0; + + ++*pattern; + continue; + } + + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ + if ((**string == **pattern)) + result = 0; + else if (nocase && (isupper((unsigned char)**string) || + isupper((unsigned char)**pattern)) + && (tolower((unsigned char)**string) == tolower((unsigned char)**pattern))) + result = 0; + + ++*pattern; + } + + /* NOT a properly balanced [expr] pattern; Rewind + * and reset result to test '[' literal + */ + *pattern = mismatch; + result = FNM_NOMATCH; + } + else if (**pattern == '?') { + /* Optimize '?' match before unescaping **pattern */ + if (!**string || (slash && (**string == '/'))) + return FNM_NOMATCH; + result = 0; + goto fnmatch_ch_success; + } + else if (escape && (**pattern == '\\') && (*pattern)[1]) { + ++*pattern; + } + + /* XXX: handle locale/MBCS comparison, advance by the MBCS char width */ + if (**string == **pattern) + result = 0; + else if (nocase && (isupper((unsigned char)**string) || isupper((unsigned char)**pattern)) + && (tolower((unsigned char)**string) == tolower((unsigned char)**pattern))) + result = 0; + + /* Refuse to advance over trailing slash or nulls + */ + if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/')))) + return result; + +fnmatch_ch_success: + ++*pattern; + ++*string; + return result; +} + +int rpl_fnmatch(const char *pattern, const char *string, int flags) +{ + static const char dummystring[2] = {' ', 0}; + const int escape = !(flags & FNM_NOESCAPE); + const int slash = !!(flags & FNM_PATHNAME); + const int leading_dir = !!(flags & FNM_LEADING_DIR); + const char *strendseg; + const char *dummyptr; + const char *matchptr; + int wild; + /* For '*' wild processing only; surpress 'used before initialization' + * warnings with dummy initialization values; + */ + const char *strstartseg = NULL; + const char *mismatch = NULL; + int matchlen = 0; + + if (strlen(pattern) > PATH_MAX || strlen(string) > PATH_MAX) + return FNM_NOMATCH; + + if (*pattern == '*') + goto firstsegment; + + while (*pattern && *string) + { + /* Pre-decode "\/" which has no special significance, and + * match balanced slashes, starting a new segment pattern + */ + if (slash && escape && (*pattern == '\\') && (pattern[1] == '/')) + ++pattern; + if (slash && (*pattern == '/') && (*string == '/')) { + ++pattern; + ++string; + } + +firstsegment: + /* At the beginning of each segment, validate leading period behavior. + */ + if ((flags & FNM_PERIOD) && (*string == '.')) + { + if (*pattern == '.') + ++pattern; + else if (escape && (*pattern == '\\') && (pattern[1] == '.')) + pattern += 2; + else + return FNM_NOMATCH; + ++string; + } + + /* Determine the end of string segment + * + * Presumes '/' character is unique, not composite in any MBCS encoding + */ + if (slash) { + strendseg = strchr(string, '/'); + if (!strendseg) + strendseg = strchr(string, '\0'); + } + else { + strendseg = strchr(string, '\0'); + } + + /* Allow pattern '*' to be consumed even with no remaining string to match + */ + while (*pattern) + { + if ((string > strendseg) + || ((string == strendseg) && (*pattern != '*'))) + break; + + if (slash && ((*pattern == '/') + || (escape && (*pattern == '\\') + && (pattern[1] == '/')))) + break; + + /* Reduce groups of '*' and '?' to n '?' matches + * followed by one '*' test for simplicity + */ + for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern) + { + if (*pattern == '*') { + wild = 1; + } + else if (string < strendseg) { /* && (*pattern == '?') */ + /* XXX: Advance 1 char for MBCS locale */ + ++string; + } + else { /* (string >= strendseg) && (*pattern == '?') */ + return FNM_NOMATCH; + } + } + + if (wild) + { + strstartseg = string; + mismatch = pattern; + + /* Count fixed (non '*') char matches remaining in pattern + * excluding '/' (or "\/") and '*' + */ + for (matchptr = pattern, matchlen = 0; 1; ++matchlen) + { + if ((*matchptr == '\0') + || (slash && ((*matchptr == '/') + || (escape && (*matchptr == '\\') + && (matchptr[1] == '/'))))) + { + /* Compare precisely this many trailing string chars, + * the resulting match needs no wildcard loop + */ + /* XXX: Adjust for MBCS */ + if (string + matchlen > strendseg) + return FNM_NOMATCH; + + string = strendseg - matchlen; + wild = 0; + break; + } + + if (*matchptr == '*') + { + /* Ensure at least this many trailing string chars remain + * for the first comparison + */ + /* XXX: Adjust for MBCS */ + if (string + matchlen > strendseg) + return FNM_NOMATCH; + + /* Begin first wild comparison at the current position */ + break; + } + + /* Skip forward in pattern by a single character match + * Use a dummy fnmatch_ch() test to count one "[range]" escape + */ + /* XXX: Adjust for MBCS */ + if (escape && (*matchptr == '\\') && matchptr[1]) { + matchptr += 2; + } + else if (*matchptr == '[') { + dummyptr = dummystring; + fnmatch_ch(&matchptr, &dummyptr, flags); + } + else { + ++matchptr; + } + } + } + + /* Incrementally match string against the pattern + */ + while (*pattern && (string < strendseg)) + { + /* Success; begin a new wild pattern search + */ + if (*pattern == '*') + break; + + if (slash && ((*string == '/') + || (*pattern == '/') + || (escape && (*pattern == '\\') + && (pattern[1] == '/')))) + break; + + /* Compare ch's (the pattern is advanced over "\/" to the '/', + * but slashes will mismatch, and are not consumed) + */ + if (!fnmatch_ch(&pattern, &string, flags)) + continue; + + /* Failed to match, loop against next char offset of string segment + * until not enough string chars remain to match the fixed pattern + */ + if (wild) { + /* XXX: Advance 1 char for MBCS locale */ + string = ++strstartseg; + if (string + matchlen > strendseg) + return FNM_NOMATCH; + + pattern = mismatch; + continue; + } + else + return FNM_NOMATCH; + } + } + + if (*string && !((slash || leading_dir) && (*string == '/'))) + return FNM_NOMATCH; + + if (*pattern && !(slash && ((*pattern == '/') + || (escape && (*pattern == '\\') + && (pattern[1] == '/'))))) + return FNM_NOMATCH; + + if (leading_dir && !*pattern && *string == '/') + return 0; + } + + /* Where both pattern and string are at EOS, declare success + */ + if (!*string && !*pattern) + return 0; + + /* pattern didn't match to the end of string */ + return FNM_NOMATCH; +} diff --git a/compat/fnmatch.h b/compat/fnmatch.h new file mode 100644 index 0000000..8cdaeed --- /dev/null +++ b/compat/fnmatch.h @@ -0,0 +1,32 @@ +/* + * 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 _FNMATCH_H +#define _FNMATCH_H + +#define FNM_NOMATCH 1 /* String does not match pattern */ + +#define FNM_PATHNAME (1 << 0) /* Globbing chars don't match '/' */ +#define FNM_PERIOD (1 << 1) /* Leading '.' in string must exactly */ +#define FNM_NOESCAPE (1 << 2) /* Backslash treated as ordinary char */ +#define FNM_LEADING_DIR (1 << 3) /* Only match the leading directory */ +#define FNM_CASEFOLD (1 << 4) /* Case insensitive matching */ + +int rpl_fnmatch(const char *pattern, const char *string, int flags); + +#define fnmatch(_a, _b, _c) rpl_fnmatch((_a), (_b), (_c)) + +#endif /* _FNMATCH_H */ diff --git a/compat/getaddrinfo.c b/compat/getaddrinfo.c new file mode 100644 index 0000000..9927587 --- /dev/null +++ b/compat/getaddrinfo.c @@ -0,0 +1,438 @@ +/* + * Replacement for a missing getaddrinfo. + * + * This is an implementation of getaddrinfo for systems that don't have one so + * that networking code can use a consistant interface without #ifdef. It is + * a fairly minimal implementation, with the following limitations: + * + * - IPv4 support only. IPv6 is not supported. + * - AI_ADDRCONFIG is ignored. + * - Not thread-safe due to gethostbyname and getservbyname. + * - SOCK_DGRAM and SOCK_STREAM only. + * - Multiple possible socket types only generate one addrinfo struct. + * - Protocol hints aren't used correctly. + * + * The last four issues could probably be easily remedied, but haven't been + * needed to date. Adding IPv6 support isn't worth it; systems with IPv6 + * support should already support getaddrinfo natively. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at . + * + * Written by Russ Allbery + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work. + */ + +#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 */ +#include +#include + +#include + +#include "compat/getaddrinfo.h" +#include "missing.h" + +/* We need access to h_errno to map errors from gethostbyname. */ +#if !HAVE_DECL_H_ERRNO +extern int h_errno; +#endif + +/* + * The netdb constants, which aren't always defined (particularly if h_errno + * isn't declared). We also make sure that a few of the less-used ones are + * defined so that we can deal with them in case statements. + */ +#ifndef HOST_NOT_FOUND +# define HOST_NOT_FOUND 1 +# define TRY_AGAIN 2 +# define NO_RECOVERY 3 +# define NO_DATA 4 +#endif +#ifndef NETDB_INTERNAL +# define NETDB_INTERNAL -1 +#endif + +/* + * If we're running the test suite, rename the functions to avoid conflicts + * with the system version. Note that we don't rename the structures and + * constants, but that should be okay (except possibly for gai_strerror). + */ +#if TESTING +# define gai_strerror test_gai_strerror +# define freeaddrinfo test_freeaddrinfo +# define getaddrinfo test_getaddrinfo +const char *test_gai_strerror(int); +void test_freeaddrinfo(struct addrinfo *); +int test_getaddrinfo(const char *, const char *, const struct addrinfo *, + struct addrinfo **); +#endif + +/* + * If the native platform doesn't support AI_NUMERICSERV or AI_NUMERICHOST, + * pick some other values for them. + */ +#if TESTING +# if AI_NUMERICSERV == 0 +# undef AI_NUMERICSERV +# define AI_NUMERICSERV 0x0080 +# endif +# if AI_NUMERICHOST == 0 +# undef AI_NUMERICHOST +# define AI_NUMERICHOST 0x0100 +# endif +#endif + +/* + * Value representing all of the hint flags set. Linux uses flags up to + * 0x0400, so be sure not to break when testing on that platform. + */ +#if TESTING +# ifdef HAVE_GETADDRINFO +# define AI_INTERNAL_ALL 0x04ff +# else +# define AI_INTERNAL_ALL 0x01ff +# endif +#else +# define AI_INTERNAL_ALL 0x007f +#endif + +/* Table of strings corresponding to the EAI_* error codes. */ +static const char * const gai_errors[] = { + "Host name lookup failure", /* 1 EAI_AGAIN */ + "Invalid flag value", /* 2 EAI_BADFLAGS */ + "Unknown server error", /* 3 EAI_FAIL */ + "Unsupported address family", /* 4 EAI_FAMILY */ + "Memory allocation failure", /* 5 EAI_MEMORY */ + "Host unknown or not given", /* 6 EAI_NONAME */ + "Service not supported for socket", /* 7 EAI_SERVICE */ + "Unsupported socket type", /* 8 EAI_SOCKTYPE */ + "System error", /* 9 EAI_SYSTEM */ + "Supplied buffer too small", /* 10 EAI_OVERFLOW */ +}; + +/* Macro to set the len attribute of sockaddr_in. */ +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN +# define sin_set_length(s) ((s)->sin_len = sizeof(struct sockaddr_in)) +#else +# define sin_set_length(s) /* empty */ +#endif + +/* + * Used for iterating through arrays. ARRAY_SIZE returns the number of + * elements in the array (useful for a < upper bound in a for loop). + */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + + +/* + * Return a constant string for a given EAI_* error code or a string + * indicating an unknown error. + */ +const char * +gai_strerror(int ecode) +{ + if (ecode < 1 || (size_t) ecode > ARRAY_SIZE(gai_errors)) + return "Unknown error"; + else + return gai_errors[ecode - 1]; +} + + +/* + * Free a linked list of addrinfo structs. + */ +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + while (ai != NULL) { + next = ai->ai_next; + if (ai->ai_addr != NULL) + free(ai->ai_addr); + if (ai->ai_canonname != NULL) + free(ai->ai_canonname); + free(ai); + ai = next; + } +} + + +/* + * Convert a numeric service string to a number with error checking, returning + * true if the number was parsed correctly and false otherwise. Stores the + * converted number in the second argument. Equivalent to calling strtol, but + * with the base always fixed at 10, with checking of errno, ensuring that all + * of the string is consumed, and checking that the resulting number is + * positive. + */ +static int +convert_service(const char *string, long *result) +{ + char *end; + + if (*string == '\0') + return 0; + errno = 0; + *result = strtol(string, &end, 10); + if (errno != 0 || *end != '\0' || *result < 0) + return 0; + return 1; +} + + +/* + * Allocate a new addrinfo struct, setting some defaults given that this + * implementation is IPv4 only. Also allocates an attached sockaddr_in and + * zeroes it, per the requirement for getaddrinfo. Takes the socktype, + * canonical name (which is copied if not NULL), address, and port. Returns + * NULL on a memory allocation failure. + */ +static struct addrinfo * +gai_addrinfo_new(int socktype, const char *canonical, struct in_addr addr, + unsigned short port) +{ + struct addrinfo *ai; + + ai = malloc(sizeof(*ai)); + if (ai == NULL) + return NULL; + ai->ai_addr = malloc(sizeof(struct sockaddr_in)); + if (ai->ai_addr == NULL) { + free(ai); + return NULL; + } + ai->ai_next = NULL; + if (canonical == NULL) + ai->ai_canonname = NULL; + else { + ai->ai_canonname = strdup(canonical); + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + return NULL; + } + } + memset(ai->ai_addr, 0, sizeof(struct sockaddr_in)); + ai->ai_flags = 0; + ai->ai_family = AF_INET; + ai->ai_socktype = socktype; + ai->ai_protocol = (socktype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP; + ai->ai_addrlen = sizeof(struct sockaddr_in); + ((struct sockaddr_in *) ai->ai_addr)->sin_family = AF_INET; + ((struct sockaddr_in *) ai->ai_addr)->sin_addr = addr; + ((struct sockaddr_in *) ai->ai_addr)->sin_port = htons(port); + sin_set_length((struct sockaddr_in *) ai->ai_addr); + return ai; +} + + +/* + * Look up a service. Takes the service name (which may be numeric), the hint + * flags, a pointer to the socket type (used to determine whether TCP or UDP + * services are of interest and, if 0, is filled in with the result of + * getservbyname if the service was not numeric), and a pointer to the + * addrinfo struct to fill in. Returns 0 on success or an EAI_* error on + * failure. + */ +static int +gai_service(const char *servname, int flags, int *type, unsigned short *port) +{ + struct servent *servent; + const char *protocol; + long value; + + if (convert_service(servname, &value)) { + if (value > (1L << 16) - 1) + return EAI_SERVICE; + *port = value; + } else { + if (flags & AI_NUMERICSERV) + return EAI_NONAME; + if (*type != 0) + protocol = (*type == SOCK_DGRAM) ? "udp" : "tcp"; + else + protocol = NULL; + + /* + * We really technically should be generating an addrinfo struct for + * each possible protocol unless type is set, but this works well + * enough for what I need this for. + */ + servent = getservbyname(servname, protocol); + if (servent == NULL) + return EAI_NONAME; + if (strcmp(servent->s_proto, "udp") == 0) + *type = SOCK_DGRAM; + else if (strcmp(servent->s_proto, "tcp") == 0) + *type = SOCK_STREAM; + else + return EAI_SERVICE; + *port = htons(servent->s_port); + } + return 0; +} + + +/* + * Look up a host and fill in a linked list of addrinfo structs with the + * results, one per IP address of the returned host. Takes the name or IP + * address of the host as a string, the lookup flags, the type of socket (to + * fill into the addrinfo structs), the port (likewise), and a pointer to + * where the head of the linked list should be put. Returns 0 on success or + * the appropriate EAI_* error. + */ +static int +gai_lookup(const char *nodename, int flags, int socktype, unsigned short port, + struct addrinfo **res) +{ + struct addrinfo *ai, *first, *prev; + struct in_addr addr; + struct hostent *host; + const char *canonical; + int i; + + if (inet_aton(nodename, &addr)) { + canonical = (flags & AI_CANONNAME) ? nodename : NULL; + ai = gai_addrinfo_new(socktype, canonical, addr, port); + if (ai == NULL) + return EAI_MEMORY; + *res = ai; + return 0; + } else { + if (flags & AI_NUMERICHOST) + return EAI_NONAME; + host = gethostbyname(nodename); + if (host == NULL) + switch (h_errno) { + case HOST_NOT_FOUND: + return EAI_NONAME; + case TRY_AGAIN: + case NO_DATA: + return EAI_AGAIN; + case NO_RECOVERY: + return EAI_FAIL; + case NETDB_INTERNAL: + default: + return EAI_SYSTEM; + } + if (host->h_addr_list[0] == NULL) + return EAI_FAIL; + canonical = (flags & AI_CANONNAME) + ? ((host->h_name != NULL) ? host->h_name : nodename) + : NULL; + first = NULL; + prev = NULL; + for (i = 0; host->h_addr_list[i] != NULL; i++) { + if (host->h_length != sizeof(addr)) { + freeaddrinfo(first); + return EAI_FAIL; + } + memcpy(&addr, host->h_addr_list[i], sizeof(addr)); + ai = gai_addrinfo_new(socktype, canonical, addr, port); + if (ai == NULL) { + freeaddrinfo(first); + return EAI_MEMORY; + } + if (first == NULL) { + first = ai; + prev = ai; + } else { + prev->ai_next = ai; + prev = ai; + } + } + *res = first; + return 0; + } +} + + +/* + * The actual getaddrinfo implementation. + */ +int +getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct addrinfo *ai; + struct in_addr addr; + int flags, socktype, status; + unsigned short port; + + /* Take the hints into account and check them for validity. */ + if (hints != NULL) { + flags = hints->ai_flags; + socktype = hints->ai_socktype; + if ((flags & AI_INTERNAL_ALL) != flags) + return EAI_BADFLAGS; + if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET) + return EAI_FAMILY; + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + + /* EAI_SOCKTYPE isn't quite right, but there isn't anything better. */ + if (hints->ai_protocol != 0) { + int protocol = hints->ai_protocol; + if (protocol != IPPROTO_TCP && protocol != IPPROTO_UDP) + return EAI_SOCKTYPE; + } + } else { + flags = 0; + socktype = 0; + } + + /* + * See what we're doing. If nodename is null, either AI_PASSIVE is set or + * we're getting information for connecting to a service on the loopback + * address. Otherwise, we're getting information for connecting to a + * remote system. + */ + if (servname == NULL) + port = 0; + else { + status = gai_service(servname, flags, &socktype, &port); + if (status != 0) + return status; + } + if (nodename != NULL) + return gai_lookup(nodename, flags, socktype, port, res); + else { + if (servname == NULL) + return EAI_NONAME; + if ((flags & AI_PASSIVE) == AI_PASSIVE) + addr.s_addr = INADDR_ANY; + else + addr.s_addr = htonl(0x7f000001UL); + ai = gai_addrinfo_new(socktype, NULL, addr, port); + if (ai == NULL) + return EAI_MEMORY; + *res = ai; + return 0; + } +} diff --git a/compat/getaddrinfo.h b/compat/getaddrinfo.h new file mode 100644 index 0000000..a8a4b69 --- /dev/null +++ b/compat/getaddrinfo.h @@ -0,0 +1,75 @@ +/* + * Replacement implementation of getaddrinfo. + * + * This is an implementation of the getaddrinfo family of functions for + * systems that lack it, so that code can use getaddrinfo always. It provides + * IPv4 support only; for IPv6 support, a native getaddrinfo implemenation is + * required. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at . + * + * Written by Russ Allbery + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work. + */ + +#ifndef _COMPAT_GETADDRINFO_H +#define _COMPAT_GETADDRINFO_H + +#include + +/* Skip this entire file if a system getaddrinfo was detected. */ +#ifndef HAVE_GETADDRINFO + +/* OpenBSD likes to have sys/types.h included before sys/socket.h. */ +#include +#include + +/* The struct returned by getaddrinfo, from RFC 3493. */ +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME, .. */ + int ai_family; /* AF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + socklen_t ai_addrlen; /* Length of ai_addr */ + char *ai_canonname; /* Canonical name for nodename */ + struct sockaddr *ai_addr; /* Binary address */ + struct addrinfo *ai_next; /* Next structure in linked list */ +}; + +/* Constants for ai_flags from RFC 3493, combined with binary or. */ +#define AI_PASSIVE 0x0001 +#define AI_CANONNAME 0x0002 +#define AI_NUMERICHOST 0x0004 +#define AI_NUMERICSERV 0x0008 +#define AI_V4MAPPED 0x0010 +#define AI_ALL 0x0020 +#define AI_ADDRCONFIG 0x0040 + +/* Error return codes from RFC 3493. */ +#define EAI_AGAIN 1 /* Temporary name resolution failure */ +#define EAI_BADFLAGS 2 /* Invalid value in ai_flags parameter */ +#define EAI_FAIL 3 /* Permanent name resolution failure */ +#define EAI_FAMILY 4 /* Address family not recognized */ +#define EAI_MEMORY 5 /* Memory allocation failure */ +#define EAI_NONAME 6 /* nodename or servname unknown */ +#define EAI_SERVICE 7 /* Service not recognized for socket type */ +#define EAI_SOCKTYPE 8 /* Socket type not recognized */ +#define EAI_SYSTEM 9 /* System error occurred, see errno */ +#define EAI_OVERFLOW 10 /* An argument buffer overflowed */ + +/* Function prototypes. */ +int getaddrinfo(const char *nodename, const char *servname, + const struct addrinfo *hints, struct addrinfo **res); +void freeaddrinfo(struct addrinfo *ai); +const char *gai_strerror(int ecode); + +#endif /* !HAVE_GETADDRINFO */ +#endif /* _COMPAT_GETADDRINFO_H */ diff --git a/compat/getcwd.c b/compat/getcwd.c new file mode 100644 index 0000000..3185504 --- /dev/null +++ b/compat/getcwd.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#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 */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#include "missing.h" + +#define ISDOT(dp) \ + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + +char * +getcwd(char *pt, size_t size) +{ + struct dirent *dp; + DIR *dir = NULL; + dev_t dev; + ino_t ino; + int first; + char *bpt, *bup; + struct stat s; + dev_t root_dev; + ino_t root_ino; + size_t ptsize, upsize; + int save_errno; + char *ept, *eup, *up; + + /* + * If no buffer specified by the user, allocate one as necessary. + * If a buffer is specified, the size has to be non-zero. The path + * is built from the end of the buffer backwards. + */ + if (pt) { + ptsize = 0; + if (!size) { + errno = EINVAL; + return NULL; + } + ept = pt + size; + } else { + if ((pt = malloc(ptsize = 1024 - 4)) == NULL) + return NULL; + ept = pt + ptsize; + } + bpt = ept - 1; + *bpt = '\0'; + + /* + * Allocate bytes (1024 - malloc space) for the string of "../"'s. + * Should always be enough (it's 340 levels). If it's not, allocate + * as necessary. Special * case the first stat, it's ".", not "..". + */ + if ((up = malloc(upsize = 1024 - 4)) == NULL) + goto err; + eup = up + PATH_MAX; + bup = up; + up[0] = '.'; + up[1] = '\0'; + + /* Save root values, so know when to stop. */ + if (stat("/", &s)) + goto err; + root_dev = s.st_dev; + root_ino = s.st_ino; + + errno = 0; /* XXX readdir has no error return. */ + + for (first = 1;; first = 0) { + /* Stat the current level. */ + if (lstat(up, &s)) + goto err; + + /* Save current node values. */ + ino = s.st_ino; + dev = s.st_dev; + + /* Check for reaching root. */ + if (root_dev == dev && root_ino == ino) { + *--bpt = '/'; + /* + * It's unclear that it's a requirement to copy the + * path to the beginning of the buffer, but it's always + * been that way and stuff would probably break. + */ + bcopy(bpt, pt, ept - bpt); + free(up); + return pt; + } + + /* + * Build pointer to the parent directory, allocating memory + * as necessary. Max length is 3 for "../", the largest + * possible component name, plus a trailing NULL. + */ + if (bup + 3 + MAXNAMLEN + 1 >= eup) { + char *nup; + + if ((nup = realloc(up, upsize *= 2)) == NULL) + goto err; + up = nup; + bup = up; + eup = up + upsize; + } + *bup++ = '.'; + *bup++ = '.'; + *bup = '\0'; + + /* Open and stat parent directory. */ + if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) + goto err; + + /* Add trailing slash for next directory. */ + *bup++ = '/'; + + /* + * If it's a mount point, have to stat each element because + * the inode number in the directory is for the entry in the + * parent directory, not the inode number of the mounted file. + */ + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (ISDOT(dp)) + continue; + bcopy(dp->d_name, bup, NAMLEN(dp) + 1); + + /* Save the first error for later. */ + if (lstat(up, &s)) { + if (!save_errno) + save_errno = errno; + errno = 0; + continue; + } + if (s.st_dev == dev && s.st_ino == ino) + break; + } + + /* + * Check for length of the current name, preceding slash, + * leading slash. + */ + if (bpt - pt <= NAMLEN(dp) + (first ? 1 : 2)) { + size_t len, off; + char *npt; + + if (!ptsize) { + errno = ERANGE; + goto err; + } + off = bpt - pt; + len = ept - bpt; + if ((npt = realloc(pt, ptsize *= 2)) == NULL) + goto err; + pt = npt; + bpt = pt + off; + ept = pt + ptsize; + bcopy(bpt, ept - len, len); + bpt = ept - len; + } + if (!first) + *--bpt = '/'; + bpt -= NAMLEN(dp); + bcopy(dp->d_name, bpt, NAMLEN(dp)); + (void)closedir(dir); + + /* Truncate any file name. */ + *bup = '\0'; + } + +notfound: + /* + * If readdir set errno, use it, not any saved error; otherwise, + * didn't find the current directory in its parent directory, set + * errno to ENOENT. + */ + if (!errno) + errno = save_errno ? save_errno : ENOENT; + /* FALLTHROUGH */ +err: + if (ptsize) + free(pt); + if (up) + free(up); + if (dir) + (void)closedir(dir); + return NULL; +} diff --git a/compat/getgrouplist.c b/compat/getgrouplist.c new file mode 100644 index 0000000..2d22714 --- /dev/null +++ b/compat/getgrouplist.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 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. + */ + +#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 */ +#include + +#include "missing.h" + +#ifdef HAVE_GETGRSET +/* + * BSD-compatible getgrouplist(3) using getgrset(3) + */ +int +getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp) +{ + char *cp, *grset = NULL; + int i, ngroups = 1; + int grpsize = *ngroupsp; + int rval = -1; + gid_t gid; + + /* We support BSD semantics where the first element is the base gid */ + if (grpsize <= 0) + return -1; + groups[0] = basegid; + +#ifdef HAVE_SETAUTHDB + aix_setauthdb((char *) name); +#endif + if ((grset = getgrset(name)) != NULL) { + for (cp = strtok(grset, ","); cp != NULL; cp = strtok(NULL, ",")) { + gid = atoi(cp); + if (gid != basegid) { + if (ngroups == grpsize) + goto done; + groups[ngroups++] = gid; + } + } + } + rval = 0; + +done: + efree(grset); +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif + *ngroupsp = ngroups; + + return rval; +} + +#else /* HAVE_GETGRSET */ + +/* + * BSD-compatible getgrouplist(3) using getgrent(3) + */ +int +getgrouplist(const char *name, gid_t basegid, gid_t *groups, int *ngroupsp) +{ + int i, ngroups = 1; + int grpsize = *ngroupsp; + int rval = -1; + struct group *grp; + + /* We support BSD semantics where the first element is the base gid */ + if (grpsize <= 0) + return -1; + groups[0] = basegid; + + setgrent(); + while ((grp = getgrent()) != NULL) { + if (grp->gr_gid == basegid) + continue; + + for (i = 0; grp->gr_mem[i] != NULL; i++) { + if (strcmp(name, grp->gr_mem[i]) == 0) + break; + } + if (grp->gr_mem[i] == NULL) + continue; /* user not found */ + + /* Only add if it is not the same as an existing gid */ + for (i = 0; i < ngroups; i++) { + if (grp->gr_gid == groups[i]) + break; + } + if (i == ngroups) { + if (ngroups == grpsize) + goto done; + groups[ngroups++] = grp->gr_gid; + } + } + rval = 0; + +done: + endgrent(); + *ngroupsp = ngroups; + + return rval; +} +#endif /* HAVE_GETGRSET */ diff --git a/compat/getline.c b/compat/getline.c new file mode 100644 index 0000000..606fd0e --- /dev/null +++ b/compat/getline.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009-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. + */ + +#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 */ +#include + +#include "missing.h" + +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + +#ifdef HAVE_FGETLN +ssize_t +getline(char **bufp, size_t *bufsizep, FILE *fp) +{ + char *buf, *cp; + size_t bufsize; + size_t len; + + buf = fgetln(fp, &len); + if (buf) { + bufsize = *bufp ? *bufsizep : 0; + if (bufsize < len + 1) { + bufsize = len + 1; + cp = *bufp ? realloc(*bufp, bufsize) : malloc(bufsize); + if (cp == NULL) + return -1; + *bufp = cp; + *bufsizep = bufsize; + } + memcpy(*bufp, buf, len); + (*bufp)[len] = '\0'; + } + return buf ? len : -1; +} +#else +ssize_t +getline(char **bufp, size_t *bufsizep, FILE *fp) +{ + char *buf, *cp; + size_t bufsize; + ssize_t len = 0; + + buf = *bufp; + bufsize = *bufsizep; + if (buf == NULL || bufsize == 0) { + bufsize = LINE_MAX; + cp = buf ? realloc(buf, bufsize) : malloc(bufsize); + if (cp == NULL) + return -1; + buf = cp; + } + + for (;;) { + if (fgets(buf + len, bufsize - len, fp) == NULL) { + len = -1; + break; + } + len = strlen(buf); + if (!len || buf[len - 1] == '\n' || feof(fp)) + break; + bufsize *= 2; + cp = realloc(buf, bufsize); + if (cp == NULL) + return -1; + buf = cp; + } + *bufp = buf; + *bufsizep = bufsize; + return len; +} +#endif diff --git a/compat/getprogname.c b/compat/getprogname.c new file mode 100644 index 0000000..34673f5 --- /dev/null +++ b/compat/getprogname.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include + +#include +#include + +#include "missing.h" + +static const char *progname = "sudo"; + +void +setprogname(const char *name) +{ + const char *base; + + if ((base = strrchr(name, '/')) != NULL) { + base++; + } else { + base = name; + } + if (strcmp(progname, base) != 0) + progname = base; +} + +const char * +getprogname(void) +{ + return progname; +} diff --git a/compat/glob.c b/compat/glob.c new file mode 100644 index 0000000..cf9a4e2 --- /dev/null +++ b/compat/glob.c @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2008-2010 Todd C. Miller + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)glob.c 8.3 (Berkeley) 10/13/93 + */ + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + +#include + +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !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 */ +#include +#ifdef HAVE_DIRENT_H +# include +#else +# define dirent direct +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif +#include +#include +#include + +#include "missing.h" +#include "compat/glob.h" +#include "compat/charclass.h" + +#define DOLLAR '$' +#define DOT '.' +#define EOS '\0' +#define LBRACKET '[' +#define NOT '!' +#define QUESTION '?' +#define QUOTE '\\' +#define RANGE '-' +#define RBRACKET ']' +#define SEP '/' +#define STAR '*' +#define TILDE '~' +#define UNDERSCORE '_' +#define LBRACE '{' +#define RBRACE '}' +#define SLASH '/' +#define COMMA ',' + +#ifndef DEBUG + +#define M_QUOTE 0x8000 +#define M_PROTECT 0x4000 +#define M_MASK 0xffff +#define M_ASCII 0x00ff + +typedef unsigned short Char; + +#else + +#define M_QUOTE 0x80 +#define M_PROTECT 0x40 +#define M_MASK 0xff +#define M_ASCII 0x7f + +typedef char Char; + +#endif + + +#define CHAR(c) ((Char)((c)&M_ASCII)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define M_ALL META('*') +#define M_END META(']') +#define M_NOT META('!') +#define M_ONE META('?') +#define M_RNG META('-') +#define M_SET META('[') +#define M_CLASS META(':') +#define ismeta(c) (((c)&M_QUOTE) != 0) + + +static int compare(const void *, const void *); +static int g_Ctoc(const Char *, char *, unsigned int); +static int g_lstat(Char *, struct stat *, glob_t *); +static DIR *g_opendir(Char *, glob_t *); +static Char *g_strchr(const Char *, int); +static int g_strncmp(const Char *, const char *, size_t); +static int g_stat(Char *, struct stat *, glob_t *); +static int glob0(const Char *, glob_t *); +static int glob1(Char *, Char *, glob_t *); +static int glob2(Char *, Char *, Char *, Char *, Char *, Char *, + glob_t *); +static int glob3(Char *, Char *, Char *, Char *, Char *, Char *, + Char *, Char *, glob_t *); +static int globextend(const Char *, glob_t *); +static const Char * + globtilde(const Char *, Char *, size_t, glob_t *); +static int globexp1(const Char *, glob_t *); +static int globexp2(const Char *, const Char *, glob_t *, int *); +static int match(Char *, Char *, Char *); +#ifdef DEBUG +static void qprintf(const char *, Char *); +#endif + +int +rpl_glob(const char *pattern, int flags, int (*errfunc)(const char *, int), + glob_t *pglob) +{ + const unsigned char *patnext; + int c; + Char *bufnext, *bufend, patbuf[PATH_MAX]; + + patnext = (unsigned char *) pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + PATH_MAX - 1; + if (flags & GLOB_NOESCAPE) + while (bufnext < bufend && (c = *patnext++) != EOS) + *bufnext++ = c; + else { + /* Protect the quoted characters. */ + while (bufnext < bufend && (c = *patnext++) != EOS) + if (c == QUOTE) { + if ((c = *patnext++) == EOS) { + c = QUOTE; + --patnext; + } + *bufnext++ = c | M_PROTECT; + } else + *bufnext++ = c; + } + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return globexp1(patbuf, pglob); + else + return glob0(patbuf, pglob); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int +globexp1(const Char *pattern, glob_t *pglob) +{ + const Char* ptr = pattern; + int rv; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) + return glob0(pattern, pglob); + + while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) + if (!globexp2(ptr, pattern, pglob, &rv)) + return rv; + + return glob0(pattern, pglob); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int +globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv) +{ + int i; + Char *lm, *ls; + const Char *pe, *pm, *pl; + Char patbuf[PATH_MAX]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + *lm = EOS; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) { + *rv = glob0(patbuf, pglob); + return 0; + } + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) { + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pl; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS; ) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + *rv = globexp1(patbuf, pglob); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + } + *rv = 0; + return 0; +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) +{ + struct passwd *pwd; + char *h; + const Char *p; + Char *b, *eb; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return pattern; + + /* Copy up to the end of the string or / */ + eb = &patbuf[patbuf_len - 1]; + for (p = pattern + 1, h = (char *) patbuf; + h < (char *)eb && *p && *p != SLASH; *h++ = *p++) + continue; + + *h = EOS; + + if (((char *) patbuf)[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME + * first and then trying the password file + */ + if ((h = getenv("HOME")) == NULL) { + if ((pwd = getpwuid(getuid())) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + } else { + /* + * Expand a ~user + */ + if ((pwd = getpwnam((char*) patbuf)) == NULL) + return pattern; + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + for (b = patbuf; b < eb && *h; *b++ = *h++) + continue; + + /* Append the rest of the pattern */ + while (b < eb && (*b++ = *p++) != EOS) + continue; + *b = EOS; + + return patbuf; +} + +static int +g_strncmp(const Char *s1, const char *s2, size_t n) +{ + int rv = 0; + + while (n--) { + rv = *(Char *)s1 - *(const unsigned char *)s2++; + if (rv) + break; + if (*s1++ == '\0') + break; + } + return rv; +} + +static int +g_charclass(const Char **patternp, Char **bufnextp) +{ + const Char *pattern = *patternp + 1; + Char *bufnext = *bufnextp; + const Char *colon; + struct cclass *cc; + size_t len; + + if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']') + return 1; /* not a character class */ + + len = (size_t)(colon - pattern); + for (cc = cclasses; cc->name != NULL; cc++) { + if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0') + break; + } + if (cc->name == NULL) + return -1; /* invalid character class */ + *bufnext++ = M_CLASS; + *bufnext++ = (Char)(cc - &cclasses[0]); + *bufnextp = bufnext; + *patternp += len + 3; + + return 0; +} + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. It is not an error + * to find no matches. + */ +static int +glob0(const Char *pattern, glob_t *pglob) +{ + const Char *qpatnext; + int c, err, oldpathc; + Char *bufnext, patbuf[PATH_MAX]; + + qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob); + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr(qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + if (c == LBRACKET && *qpatnext == ':') { + do { + err = g_charclass(&qpatnext, + &bufnext); + if (err) + break; + c = *qpatnext++; + } while (c == LBRACKET && *qpatnext == ':'); + if (err == -1 && + !(pglob->gl_flags & GLOB_NOCHECK)) + return GLOB_NOMATCH; + if (c == RBRACKET) + break; + } + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0) + return err; + + /* + * If there was no match we are going to append the pattern + * if GLOB_NOCHECK was specified. + */ + if (pglob->gl_pathc == oldpathc) { + if (pglob->gl_flags & GLOB_NOCHECK) + return globextend(pattern, pglob); + else + return GLOB_NOMATCH; + } + if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return 0; +} + +static int +compare(const void *p, const void *q) +{ + return strcmp(*(char **)p, *(char **)q); +} + +static int +glob1(Char *pattern, Char *pattern_last, glob_t *pglob) +{ + Char pathbuf[PATH_MAX]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return 0; + return glob2(pathbuf, pathbuf + PATH_MAX - 1, + pathbuf, pathbuf + PATH_MAX - 1, + pattern, pattern_last, pglob); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, + Char *pattern, Char *pattern_last, glob_t *pglob) +{ + struct stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return 0; + + if (((pglob->gl_flags & GLOB_MARK) && + pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || + (S_ISLNK(sb.st_mode) && + (g_stat(pathbuf, &sb, pglob) == 0) && + S_ISDIR(sb.st_mode)))) { + if (pathend+1 > pathend_last) + return 1; + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return globextend(pathbuf, pglob); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && *p != SEP) { + if (ismeta(*p)) + anymeta = 1; + if (q+1 > pathend_last) + return 1; + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (*pattern == SEP) { + if (pathend+1 > pathend_last) + return 1; + *pathend++ = *pattern++; + } + } else + /* Need expansion, recurse. */ + return glob3(pathbuf, pathbuf_last, pathend, + pathend_last, pattern, pattern_last, + p, pattern_last, pglob); + } + /* NOTREACHED */ +} + +static int +glob3(Char *pathbuf, Char *pathbuf_last, Char *pathend, Char *pathend_last, + Char *pattern, Char *pattern_last, Char *restpattern, + Char *restpattern_last, glob_t *pglob) +{ + struct dirent *dp; + DIR *dirp; + int err; + char buf[PATH_MAX]; + + if (pathend > pathend_last) + return 1; + *pathend = EOS; + errno = 0; + + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + /* TODO: don't call for ENOENT or ENOTDIR? */ + if (pglob->gl_errfunc) { + if (g_Ctoc(pathbuf, buf, sizeof(buf))) + return GLOB_ABORTED; + if (pglob->gl_errfunc(buf, errno) || + pglob->gl_flags & GLOB_ERR) + return GLOB_ABORTED; + } + return 0; + } + + err = 0; + + /* Search directory for matching names. */ + while ((dp = readdir(dirp))) { + unsigned char *sc; + Char *dc; + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == DOT && *pattern != DOT) + continue; + dc = pathend; + sc = (unsigned char *) dp->d_name; + while (dc < pathend_last && (*dc++ = *sc++) != EOS) + continue; + if (dc >= pathend_last) { + *dc = EOS; + err = 1; + break; + } + + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, + restpattern, restpattern_last, pglob); + if (err) + break; + } + + closedir(dirp); + return err; +} + +/* + * Extend the gl_pathv member of a glob_t structure to accommodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(const Char *path, glob_t *pglob) +{ + char **pathv; + int i; + unsigned int newsize, len; + char *copy; + const Char *p; + + newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + pathv = pglob->gl_pathv ? + (char **)realloc((char *)pglob->gl_pathv, newsize) : + (char **)malloc(newsize); + if (pathv == NULL) { + if (pglob->gl_pathv) { + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } + return GLOB_NOSPACE; + } + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs; --i >= 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + for (p = path; *p++;) + continue; + len = (size_t)(p - path); + if ((copy = malloc(len)) != NULL) { + if (g_Ctoc(path, copy, len)) { + free(copy); + return GLOB_NOSPACE; + } + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + return copy == NULL ? GLOB_NOSPACE : 0; +} + +/* + * pattern matching function for filenames. Each occurrence of the * + * pattern causes a recursion level. + */ +static int +match(Char *name, Char *pat, Char *patend) +{ + int ok, negate_range; + Char c, k; + + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return 1; + do { + if (match(name, pat, patend)) + return 1; + } while (*name++ != EOS); + return 0; + case M_ONE: + if (*name++ == EOS) + return 0; + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + return 0; + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) { + if ((c & M_MASK) == M_CLASS) { + int idx = *pat & M_MASK; + if (idx < NCCLASSES && + cclasses[idx].isctype(k)) + ok = 1; + ++pat; + } + if ((*pat & M_MASK) == M_RNG) { + if (c <= k && k <= pat[1]) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + } + if (ok == negate_range) + return 0; + break; + default: + if (*name++ != c) + return 0; + break; + } + } + return *name == EOS; +} + +/* Free allocated data belonging to a glob_t structure. */ +void +rpl_globfree(glob_t *pglob) +{ + int i; + char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} + +static DIR * +g_opendir(Char *str, glob_t *pglob) +{ + char buf[PATH_MAX]; + + if (!*str) { + buf[0] = '.'; + buf[1] = '\0'; + } else { + if (g_Ctoc(str, buf, sizeof(buf))) + return NULL; + } + return opendir(buf); +} + +static int +g_lstat(Char *fn, struct stat *sb, glob_t *pglob) +{ + char buf[PATH_MAX]; + + if (g_Ctoc(fn, buf, sizeof(buf))) + return -1; + return lstat(buf, sb); +} + +static int +g_stat(Char *fn, struct stat *sb, glob_t *pglob) +{ + char buf[PATH_MAX]; + + if (g_Ctoc(fn, buf, sizeof(buf))) + return -1; + return stat(buf, sb); +} + +static Char * +g_strchr(const Char *str, int ch) +{ + do { + if (*str == ch) + return (Char *)str; + } while (*str++); + return NULL; +} + +static int +g_Ctoc(const Char *str, char *buf, unsigned int len) +{ + + while (len--) { + if ((*buf++ = *str++) == EOS) + return 0; + } + return 1; +} + +#ifdef DEBUG +static void +qprintf(const char *str, Char *s) +{ + Char *p; + + (void)printf("%s:\n", str); + for (p = s; *p; p++) + (void)printf("%c", CHAR(*p)); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", *p & M_PROTECT ? '"' : ' '); + (void)printf("\n"); + for (p = s; *p; p++) + (void)printf("%c", ismeta(*p) ? '_' : ' '); + (void)printf("\n"); +} +#endif diff --git a/compat/glob.h b/compat/glob.h new file mode 100644 index 0000000..7e7153b --- /dev/null +++ b/compat/glob.h @@ -0,0 +1,78 @@ +/* $OpenBSD: glob.h,v 1.8 2003/06/02 19:34:12 millert Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _GLOB_H_ +#define _GLOB_H_ + +struct stat; +typedef struct { + int gl_pathc; /* Count of total paths so far. */ + int gl_matchc; /* Count of paths matching pattern. */ + int gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); +} glob_t; + +/* Flags */ +#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ +#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ +#define GLOB_ERR 0x0004 /* Return on error. */ +#define GLOB_MARK 0x0008 /* Append / to matching directories. */ +#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ +#define GLOB_NOSORT 0x0020 /* Don't sort. */ +#define GLOB_NOESCAPE 0x0040 /* Disable backslash escaping. */ + +/* Non-POSIX extensions */ +#define GLOB_MAGCHAR 0x0080 /* Pattern had globbing characters. */ +#define GLOB_BRACE 0x0100 /* Expand braces ala csh. */ +#define GLOB_TILDE 0x0200 /* Expand tilde names from the passwd file. */ + +/* Error values returned by glob(3) */ +#define GLOB_NOSPACE (-1) /* Malloc call failed. */ +#define GLOB_ABORTED (-2) /* Unignored error. */ +#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */ +#define GLOB_NOSYS (-4) /* Function not supported. */ +#define GLOB_ABEND GLOB_ABORTED + +int rpl_glob(const char *, int, int (*)(const char *, int), glob_t *); +void rpl_globfree(glob_t *); + +#define glob(_a, _b, _c, _d) rpl_glob((_a), (_b), (_c), (_d)) +#define globfree(_a) rpl_globfree((_a)) + +#endif /* !_GLOB_H_ */ diff --git a/compat/isblank.c b/compat/isblank.c new file mode 100644 index 0000000..083d805 --- /dev/null +++ b/compat/isblank.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2008, 2010-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. + */ + +#include + +#include + +#include "missing.h" + +#undef isblank +int +isblank(int ch) +{ + return ch == ' ' || ch == '\t'; +} diff --git a/compat/memrchr.c b/compat/memrchr.c new file mode 100644 index 0000000..0b1e3a5 --- /dev/null +++ b/compat/memrchr.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2007, 2010-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. + */ + +#include + +#include + +#include "missing.h" + +/* + * Reverse memchr() + * Find the last occurrence of 'c' in the buffer 's' of size 'n'. + */ +void * +memrchr(const void *s, int c, size_t n) +{ + const unsigned char *cp; + + if (n != 0) { + cp = (unsigned char *)s + n; + do { + if (*(--cp) == (unsigned char)c) + return (void *)cp; + } while (--n != 0); + } + return (void *)0; +} diff --git a/compat/mksiglist.c b/compat/mksiglist.c new file mode 100644 index 0000000..ce88919 --- /dev/null +++ b/compat/mksiglist.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010-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. + */ + + +#include + +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include + +#include "missing.h" + +int +main(int argc, char *argv[]) +{ + static char *my_sys_siglist[NSIG]; + int i; + +#include "compat/mksiglist.h" + + printf("#include \n"); + printf("#include \n"); + printf("#include \"missing.h\"\n\n"); + printf("const char *const my_sys_siglist[NSIG] = {\n"); + for (i = 0; i < NSIG; i++) { + if (my_sys_siglist[i] != NULL) { + printf(" \"%s\",\n", my_sys_siglist[i]); + } else { + printf(" \"Signal %d\",\n", i); + } + } + printf("};\n"); + + exit(0); +} diff --git a/compat/mksiglist.h b/compat/mksiglist.h new file mode 100644 index 0000000..f9f3294 --- /dev/null +++ b/compat/mksiglist.h @@ -0,0 +1,174 @@ +/* public domain */ + +#ifdef SIGHUP + if (my_sys_siglist[SIGHUP] == NULL) + my_sys_siglist[SIGHUP] = "Hangup"; +#endif +#ifdef SIGINT + if (my_sys_siglist[SIGINT] == NULL) + my_sys_siglist[SIGINT] = "Interrupt"; +#endif +#ifdef SIGQUIT + if (my_sys_siglist[SIGQUIT] == NULL) + my_sys_siglist[SIGQUIT] = "Quit"; +#endif +#ifdef SIGILL + if (my_sys_siglist[SIGILL] == NULL) + my_sys_siglist[SIGILL] = "Illegal instruction"; +#endif +#ifdef SIGTRAP + if (my_sys_siglist[SIGTRAP] == NULL) + my_sys_siglist[SIGTRAP] = "Trace trap"; +#endif +#ifdef SIGABRT + if (my_sys_siglist[SIGABRT] == NULL) + my_sys_siglist[SIGABRT] = "Abort"; +#endif +#ifdef SIGIOT + if (my_sys_siglist[SIGIOT] == NULL) + my_sys_siglist[SIGIOT] = "IOT instruction"; +#endif +#ifdef SIGEMT + if (my_sys_siglist[SIGEMT] == NULL) + my_sys_siglist[SIGEMT] = "EMT trap"; +#endif +#ifdef SIGFPE + if (my_sys_siglist[SIGFPE] == NULL) + my_sys_siglist[SIGFPE] = "Floating point exception"; +#endif +#ifdef SIGKILL + if (my_sys_siglist[SIGKILL] == NULL) + my_sys_siglist[SIGKILL] = "Killed"; +#endif +#ifdef SIGUNUSED + if (my_sys_siglist[SIGUNUSED] == NULL) + my_sys_siglist[SIGUNUSED] = "Unused"; +#endif +#ifdef SIGBUS + if (my_sys_siglist[SIGBUS] == NULL) + my_sys_siglist[SIGBUS] = "Bus error"; +#endif +#ifdef SIGSEGV + if (my_sys_siglist[SIGSEGV] == NULL) + my_sys_siglist[SIGSEGV] = "Memory fault"; +#endif +#ifdef SIGSYS + if (my_sys_siglist[SIGSYS] == NULL) + my_sys_siglist[SIGSYS] = "Bad system call"; +#endif +#ifdef SIGPIPE + if (my_sys_siglist[SIGPIPE] == NULL) + my_sys_siglist[SIGPIPE] = "Broken pipe"; +#endif +#ifdef SIGALRM + if (my_sys_siglist[SIGALRM] == NULL) + my_sys_siglist[SIGALRM] = "Alarm clock"; +#endif +#ifdef SIGTERM + if (my_sys_siglist[SIGTERM] == NULL) + my_sys_siglist[SIGTERM] = "Terminated"; +#endif +#ifdef SIGSTKFLT + if (my_sys_siglist[SIGSTKFLT] == NULL) + my_sys_siglist[SIGSTKFLT] = "Stack fault"; +#endif +#ifdef SIGIO + if (my_sys_siglist[SIGIO] == NULL) + my_sys_siglist[SIGIO] = "I/O possible"; +#endif +#ifdef SIGXCPU + if (my_sys_siglist[SIGXCPU] == NULL) + my_sys_siglist[SIGXCPU] = "CPU time limit exceeded"; +#endif +#ifdef SIGXFSZ + if (my_sys_siglist[SIGXFSZ] == NULL) + my_sys_siglist[SIGXFSZ] = "File size limit exceeded"; +#endif +#ifdef SIGVTALRM + if (my_sys_siglist[SIGVTALRM] == NULL) + my_sys_siglist[SIGVTALRM] = "Virtual timer expired"; +#endif +#ifdef SIGPROF + if (my_sys_siglist[SIGPROF] == NULL) + my_sys_siglist[SIGPROF] = "Profiling timer expired"; +#endif +#ifdef SIGWINCH + if (my_sys_siglist[SIGWINCH] == NULL) + my_sys_siglist[SIGWINCH] = "Window size change"; +#endif +#ifdef SIGLOST + if (my_sys_siglist[SIGLOST] == NULL) + my_sys_siglist[SIGLOST] = "File lock lost"; +#endif +#ifdef SIGUSR1 + if (my_sys_siglist[SIGUSR1] == NULL) + my_sys_siglist[SIGUSR1] = "User defined signal 1"; +#endif +#ifdef SIGUSR2 + if (my_sys_siglist[SIGUSR2] == NULL) + my_sys_siglist[SIGUSR2] = "User defined signal 2"; +#endif +#ifdef SIGPWR + if (my_sys_siglist[SIGPWR] == NULL) + my_sys_siglist[SIGPWR] = "Power-fail/Restart"; +#endif +#ifdef SIGPOLL + if (my_sys_siglist[SIGPOLL] == NULL) + my_sys_siglist[SIGPOLL] = "Pollable event occurred"; +#endif +#ifdef SIGSTOP + if (my_sys_siglist[SIGSTOP] == NULL) + my_sys_siglist[SIGSTOP] = "Stopped (signal)"; +#endif +#ifdef SIGTSTP + if (my_sys_siglist[SIGTSTP] == NULL) + my_sys_siglist[SIGTSTP] = "Stopped"; +#endif +#ifdef SIGCONT + if (my_sys_siglist[SIGCONT] == NULL) + my_sys_siglist[SIGCONT] = "Continued"; +#endif +#ifdef SIGCHLD + if (my_sys_siglist[SIGCHLD] == NULL) + my_sys_siglist[SIGCHLD] = "Child exited"; +#endif +#ifdef SIGCLD + if (my_sys_siglist[SIGCLD] == NULL) + my_sys_siglist[SIGCLD] = "Child exited"; +#endif +#ifdef SIGTTIN + if (my_sys_siglist[SIGTTIN] == NULL) + my_sys_siglist[SIGTTIN] = "Stopped (tty input)"; +#endif +#ifdef SIGTTOU + if (my_sys_siglist[SIGTTOU] == NULL) + my_sys_siglist[SIGTTOU] = "Stopped (tty output)"; +#endif +#ifdef SIGINFO + if (my_sys_siglist[SIGINFO] == NULL) + my_sys_siglist[SIGINFO] = "Information request"; +#endif +#ifdef SIGURG + if (my_sys_siglist[SIGURG] == NULL) + my_sys_siglist[SIGURG] = "Urgent I/O condition"; +#endif +#ifdef SIGWAITING + if (my_sys_siglist[SIGWAITING] == NULL) + my_sys_siglist[SIGWAITING] = "No runnable LWPs"; +#endif +#ifdef SIGLWP + if (my_sys_siglist[SIGLWP] == NULL) + my_sys_siglist[SIGLWP] = "Inter-LWP signal"; +#endif +#ifdef SIGFREEZE + if (my_sys_siglist[SIGFREEZE] == NULL) + my_sys_siglist[SIGFREEZE] = "Checkpoint freeze"; +#endif +#ifdef SIGTHAW + if (my_sys_siglist[SIGTHAW] == NULL) + my_sys_siglist[SIGTHAW] = "Checkpoint thaw"; +#endif +#ifdef SIGCANCEL + if (my_sys_siglist[SIGCANCEL] == NULL) + my_sys_siglist[SIGCANCEL] = "Thread cancellation"; +#endif diff --git a/compat/mktemp.c b/compat/mktemp.c new file mode 100644 index 0000000..ce7a4e5 --- /dev/null +++ b/compat/mktemp.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2001, 2003, 2004, 2008-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. + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_STDLIB_H +# include +#endif /* HAVE_STDLIB_H */ +#include +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif + +#include "missing.h" + +#define MKTEMP_FILE 1 +#define MKTEMP_DIR 2 + +#define TEMPCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" +#define NUM_CHARS (sizeof(TEMPCHARS) - 1) + +#ifndef INT_MAX +#define INT_MAX 0x7fffffff +#endif + +#ifdef HAVE_RANDOM +# define RAND random +# define SRAND srandom +# define SEED_T unsigned int +#else +# ifdef HAVE_LRAND48 +# define RAND lrand48 +# define SRAND srand48 +# define SEED_T long +# else +# define RAND rand +# define SRAND srand +# define SEED_T unsigned int +# endif +#endif + +static void +seed_random(void) +{ + SEED_T seed; + struct timeval tv; + + /* + * Seed from time of day and process id multiplied by small primes. + */ + (void) gettimeofday(&tv, NULL); + seed = (tv.tv_sec % 10000) * 523 + tv.tv_usec * 13 + + (getpid() % 1000) * 983; + SRAND(seed); +} + +static unsigned int +get_random(void) +{ + static int initialized; + + if (!initialized) { + seed_random(); + initialized = 1; + } + + return RAND() & 0xffffffff; +} + +static int +mktemp_internal(char *path, int slen, int mode) +{ + char *start, *cp, *ep; + const char *tempchars = TEMPCHARS; + unsigned int r, tries; + int fd; + + for (ep = path; *ep; ep++) + ; + if (path + slen >= ep) { + errno = EINVAL; + return -1; + } + ep -= slen; + + tries = 1; + for (start = ep; start > path && start[-1] == 'X'; start--) { + if (tries < INT_MAX / NUM_CHARS) + tries *= NUM_CHARS; + } + tries *= 2; + + do { + for (cp = start; *cp; cp++) { + r = get_random() % NUM_CHARS; + *cp = tempchars[r]; + } + + switch (mode) { + case MKTEMP_FILE: + fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); + if (fd != -1 || errno != EEXIST) + return fd; + break; + case MKTEMP_DIR: + if (mkdir(path, S_IRWXU) == 0) + return 0; + if (errno != EEXIST) + return -1; + break; + } + } while (--tries); + + errno = EEXIST; + return -1; +} + +#ifndef HAVE_MKSTEMPS +int +mkstemps(char *path, int slen) +{ + return mktemp_internal(path, slen, MKTEMP_FILE); +} +#endif /* HAVE_MKSTEMPS */ + +#ifndef HAVE_MKDTEMP +char * +mkdtemp(char *path) +{ + if (mktemp_internal(path, 0, MKTEMP_DIR) == -1) + return NULL; + return path; +} +#endif /* HAVE_MKDTEMP */ diff --git a/compat/nanosleep.c b/compat/nanosleep.c new file mode 100644 index 0000000..23e3b9e --- /dev/null +++ b/compat/nanosleep.c @@ -0,0 +1,54 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#ifndef HAVE_STRUCT_TIMESPEC +# include "compat/timespec.h" +#endif +#include + +#include "missing.h" + +int +nanosleep(const struct timespec *ts, struct timespec *rts) +{ + struct timeval timeout, endtime, now; + int rval; + + timeout.tv_sec = ts->tv_sec; + timeout.tv_usec = ts->tv_nsec / 1000; + if (rts != NULL) { + gettimeofday(&endtime, NULL); + timevaladd(&endtime, &timeout); + } + rval = select(0, NULL, NULL, NULL, &timeout); + if (rts != NULL && rval == -1 && errno == EINTR) { + gettimeofday(&now, NULL); + timevalsub(&endtime, &now); + rts->tv_sec = endtime.tv_sec; + rts->tv_nsec = endtime.tv_usec * 1000; + } + return rval; +} diff --git a/compat/pw_dup.c b/compat/pw_dup.c new file mode 100644 index 0000000..f43153e --- /dev/null +++ b/compat/pw_dup.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 2002, 2012 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. + */ + +#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 */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#include + +#define PW_SIZE(name, size) \ +do { \ + if (pw->name) { \ + size = strlen(pw->name) + 1; \ + total += size; \ + } \ +} while (0) + +#define PW_COPY(name, size) \ +do { \ + if (pw->name) { \ + (void)memcpy(cp, pw->name, size); \ + newpw->name = cp; \ + cp += size; \ + } \ +} while (0) + +struct passwd * +pw_dup(const struct passwd *pw) +{ + size_t nsize = 0, psize = 0, gsize = 0, dsize = 0, ssize = 0, total; +#ifdef HAVE_LOGIN_CAP_H + size_t csize; +#endif + struct passwd *newpw; + char *cp; + + /* Allocate in one big chunk for easy freeing */ + total = sizeof(struct passwd); + PW_SIZE(pw_name, nsize); + PW_SIZE(pw_passwd, psize); +#ifdef HAVE_LOGIN_CAP_H + PW_SIZE(pw_class, csize); +#endif + PW_SIZE(pw_gecos, gsize); + PW_SIZE(pw_dir, dsize); + PW_SIZE(pw_shell, ssize); + + if ((cp = malloc(total)) == NULL) + return NULL; + newpw = (struct passwd *)cp; + + /* + * Copy in passwd contents and make strings relative to space + * at the end of the buffer. + */ + (void)memcpy(newpw, pw, sizeof(struct passwd)); + cp += sizeof(struct passwd); + + PW_COPY(pw_name, nsize); + PW_COPY(pw_passwd, psize); +#ifdef HAVE_LOGIN_CAP_H + PW_COPY(pw_class, csize); +#endif + PW_COPY(pw_gecos, gsize); + PW_COPY(pw_dir, dsize); + PW_COPY(pw_shell, ssize); + + return newpw; +} diff --git a/compat/regress/fnmatch/fnm_test.c b/compat/regress/fnmatch/fnm_test.c new file mode 100644 index 0000000..2079e3b --- /dev/null +++ b/compat/regress/fnmatch/fnm_test.c @@ -0,0 +1,76 @@ +/* $OpenBSD: fnm_test.c,v 1.1 2008/10/01 23:04:58 millert Exp $ */ + +/* + * Public domain, 2008, Todd C. Miller + */ + +#include + +#include +#include +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_FNMATCH +# include +#else +# include "compat/fnmatch.h" +#endif + +int +main(int argc, char *argv[]) +{ + FILE *fp = stdin; + char pattern[1024], string[1024], flagstr[1024]; + int errors = 0, tests = 0, flags, got, want; + + if (argc > 1) { + if ((fp = fopen(argv[1], "r")) == NULL) { + perror(argv[1]); + exit(1); + } + } + + /* + * Read in test file, which is formatted thusly: + * + * pattern string flags expected_result + * + */ + for (;;) { + got = fscanf(fp, "%s %s %s %d\n", pattern, string, flagstr, + &want); + if (got == EOF) + break; + if (got == 4) { + flags = 0; + if (strcmp(flagstr, "FNM_NOESCAPE") == 0) + flags |= FNM_NOESCAPE; + else if (strcmp(flagstr, "FNM_PATHNAME") == 0) + flags |= FNM_PATHNAME; + else if (strcmp(flagstr, "FNM_PERIOD") == 0) + flags |= FNM_PERIOD; + else if (strcmp(flagstr, "FNM_LEADING_DIR") == 0) + flags |= FNM_LEADING_DIR; + else if (strcmp(flagstr, "FNM_CASEFOLD") == 0) + flags |= FNM_CASEFOLD; + got = fnmatch(pattern, string, flags); + if (got != want) { + fprintf(stderr, + "fnmatch: %s %s %d: want %d, got %d\n", + pattern, string, flags, want, got); + errors++; + } + tests++; + } + } + if (tests != 0) { + printf("fnmatch: %d test%s run, %d errors, %d%% success rate\n", + tests, tests == 1 ? "" : "s", errors, + (tests - errors) * 100 / tests); + } + exit(errors); +} diff --git a/compat/regress/fnmatch/fnm_test.in b/compat/regress/fnmatch/fnm_test.in new file mode 100644 index 0000000..5d452ef --- /dev/null +++ b/compat/regress/fnmatch/fnm_test.in @@ -0,0 +1,5 @@ +/bin/[[:alpha:][:alnum:]]* /bin/ls FNM_PATHNAME 0 +/bin/[[:alpha:][:alnum:]]* /bin/LS FNM_CASEFOLD 0 +/bin/[[:opper:][:alnum:]]* /bin/ls NONE 1 +[[:alpha:][:alnum:]]*.c foo1.c FNM_PERIOD 0 +[[:upper:]]* FOO NONE 0 diff --git a/compat/regress/glob/files b/compat/regress/glob/files new file mode 100644 index 0000000..c5e92aa --- /dev/null +++ b/compat/regress/glob/files @@ -0,0 +1,47 @@ +fake/bin/[ +fake/bin/cat +fake/bin/chgrp +fake/bin/chio +fake/bin/chmod +fake/bin/cksum +fake/bin/cp +fake/bin/cpio +fake/bin/csh +fake/bin/date +fake/bin/dd +fake/bin/df +fake/bin/domainname +fake/bin/echo +fake/bin/ed +fake/bin/eject +fake/bin/expr +fake/bin/hostname +fake/bin/kill +fake/bin/ksh +fake/bin/ln +fake/bin/ls +fake/bin/md5 +fake/bin/mkdir +fake/bin/mt +fake/bin/mv +fake/bin/pax +fake/bin/ps +fake/bin/pwd +fake/bin/rcp +fake/bin/rksh +fake/bin/rm +fake/bin/rmail +fake/bin/rmd160 +fake/bin/rmdir +fake/bin/sh +fake/bin/sha1 +fake/bin/sha256 +fake/bin/sha384 +fake/bin/sha512 +fake/bin/sleep +fake/bin/stty +fake/bin/sum +fake/bin/sync +fake/bin/systrace +fake/bin/tar +fake/bin/test diff --git a/compat/regress/glob/globtest.c b/compat/regress/glob/globtest.c new file mode 100644 index 0000000..b4f61f2 --- /dev/null +++ b/compat/regress/glob/globtest.c @@ -0,0 +1,211 @@ +/* $OpenBSD: globtest.c,v 1.1 2008/10/01 23:04:36 millert Exp $ */ + +/* + * Public domain, 2008, Todd C. Miller + */ + +#include + +#include +#include +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_GLOB +# include +#else +# include "compat/glob.h" +#endif +#include + +#include "missing.h" + +#define MAX_RESULTS 256 + +struct gl_entry { + int flags; + int nresults; + char pattern[1024]; + char *results[MAX_RESULTS]; +}; + +int test_glob(struct gl_entry *); + +int +main(int argc, char **argv) +{ + FILE *fp = stdin; + char buf[2048], *cp, *ep; + int errors = 0, tests = 0, lineno; + struct gl_entry entry; + size_t len; + + if (argc > 1) { + if ((fp = fopen(argv[1], "r")) == NULL) { + perror(argv[1]); + exit(1); + } + } + + /* + * Read in test file, which is formatted thusly: + * + * [pattern] + * result1 + * result2 + * result3 + * ... + * + */ + lineno = 0; + memset(&entry, 0, sizeof(entry)); + while (fgets(buf, sizeof(buf), fp) != NULL) { + lineno++; + len = strlen(buf); + if (len > 0) { + if (buf[len - 1] != '\n') { + fprintf(stderr, + "globtest: missing newline at EOF\n"); + exit(1); + } + buf[--len] = '\0'; + } + if (len == 0) + continue; /* blank line */ + + if (buf[0] == '[') { + /* check previous pattern */ + if (entry.pattern[0]) { + errors += test_glob(&entry); + tests++; + } + + /* start new entry */ + if ((cp = strrchr(buf + 1, ']')) == NULL) { + fprintf(stderr, + "globtest: invalid entry on line %d\n", + lineno); + exit(1); + } + len = cp - buf - 1; + if (len >= sizeof(entry.pattern)) { + fprintf(stderr, + "globtest: pattern too big on line %d\n", + lineno); + exit(1); + } + memcpy(entry.pattern, buf + 1, len); + entry.pattern[len] = '\0'; + + cp += 2; + if (*cp++ != '<') { + fprintf(stderr, + "globtest: invalid entry on line %d\n", + lineno); + exit(1); + } + ep = strchr(cp, '>'); + if (ep == NULL) { + fprintf(stderr, + "globtest: invalid entry on line %d\n", + lineno); + exit(1); + } + *ep = '\0'; + entry.flags = 0; + for ((cp = strtok(cp, "|")); cp != NULL; (cp = strtok(NULL, "|"))) { + if (strcmp(cp, "GLOB_APPEND") == 0) + entry.flags |= GLOB_APPEND; + else if (strcmp(cp, "GLOB_DOOFFS") == 0) + entry.flags |= GLOB_DOOFFS; + else if (strcmp(cp, "GLOB_ERR") == 0) + entry.flags |= GLOB_ERR; + else if (strcmp(cp, "GLOB_MARK") == 0) + entry.flags |= GLOB_MARK; + else if (strcmp(cp, "GLOB_NOCHECK") == 0) + entry.flags |= GLOB_NOCHECK; + else if (strcmp(cp, "GLOB_NOSORT") == 0) + entry.flags |= GLOB_NOSORT; + else if (strcmp(cp, "GLOB_NOESCAPE") == 0) + entry.flags |= GLOB_NOESCAPE; + else if (strcmp(cp, "GLOB_BRACE") == 0) + entry.flags |= GLOB_BRACE; + else if (strcmp(cp, "GLOB_TILDE") == 0) + entry.flags |= GLOB_TILDE; + else if (strcmp(cp, "NONE") != 0) { + fprintf(stderr, + "globtest: invalid flags on line %d\n", + lineno); + exit(1); + } + } + entry.nresults = 0; + continue; + } + if (!entry.pattern[0]) { + fprintf(stderr, "globtest: missing entry on line %d\n", + lineno); + exit(1); + } + + if (entry.nresults + 1 > MAX_RESULTS) { + fprintf(stderr, + "globtest: too many results for %s, max %d\n", + entry.pattern, MAX_RESULTS); + exit(1); + } + entry.results[entry.nresults++] = strdup(buf); + } + if (entry.pattern[0]) { + errors += test_glob(&entry); /* test last pattern */ + tests++; + } + if (tests != 0) { + printf("glob: %d test%s run, %d errors, %d%% success rate\n", + tests, tests == 1 ? "" : "s", errors, + (tests - errors) * 100 / tests); + } + exit(errors); +} + +int test_glob(struct gl_entry *entry) +{ + glob_t gl; + char **ap; + int nmatches = 0, i = 0; + + if (glob(entry->pattern, entry->flags, NULL, &gl) != 0) { + fprintf(stderr, "glob failed: %s: %s\n", entry->pattern, + strerror(errno)); + exit(1); + } + + for (ap = gl.gl_pathv; *ap != NULL; ap++) + nmatches++; + + if (nmatches != entry->nresults) + goto mismatch; + + for (i = 0; i < entry->nresults; i++) { + if (strcmp(gl.gl_pathv[i], entry->results[i]) != 0) + goto mismatch; + free(entry->results[i]); + } + return 0; + mismatch: + if (nmatches != entry->nresults) { + fprintf(stderr, + "globtest: mismatch in number of results (found %d, expected %d) for pattern %s\n", + nmatches, entry->nresults, entry->pattern); + } else { + fprintf(stderr, "globtest: mismatch for pattern %s, flags 0x%x " + "(found \"%s\", expected \"%s\")\n", entry->pattern, entry->flags, + gl.gl_pathv[i], entry->results[i]); + while (i < entry->nresults) + free(entry->results[i++]); + } + return 1; +} diff --git a/compat/regress/glob/globtest.in b/compat/regress/glob/globtest.in new file mode 100644 index 0000000..20a86c1 --- /dev/null +++ b/compat/regress/glob/globtest.in @@ -0,0 +1,64 @@ +[fake/bin/[[:alpha:]]*] +fake/bin/cat +fake/bin/chgrp +fake/bin/chio +fake/bin/chmod +fake/bin/cksum +fake/bin/cp +fake/bin/cpio +fake/bin/csh +fake/bin/date +fake/bin/dd +fake/bin/df +fake/bin/domainname +fake/bin/echo +fake/bin/ed +fake/bin/eject +fake/bin/expr +fake/bin/hostname +fake/bin/kill +fake/bin/ksh +fake/bin/ln +fake/bin/ls +fake/bin/md5 +fake/bin/mkdir +fake/bin/mt +fake/bin/mv +fake/bin/pax +fake/bin/ps +fake/bin/pwd +fake/bin/rcp +fake/bin/rksh +fake/bin/rm +fake/bin/rmail +fake/bin/rmd160 +fake/bin/rmdir +fake/bin/sh +fake/bin/sha1 +fake/bin/sha256 +fake/bin/sha384 +fake/bin/sha512 +fake/bin/sleep +fake/bin/stty +fake/bin/sum +fake/bin/sync +fake/bin/systrace +fake/bin/tar +fake/bin/test + +[fake/bin/rm{,dir,ail}] +fake/bin/rm +fake/bin/rmdir +fake/bin/rmail + +[fake/bin/sha[[:digit:]]] +fake/bin/sha1 + +[fake/bin/sha[[:digit:]]*] +fake/bin/sha1 +fake/bin/sha256 +fake/bin/sha384 +fake/bin/sha512 + +[fake/bin/ca[a-z]] +fake/bin/cat diff --git a/compat/siglist.in b/compat/siglist.in new file mode 100644 index 0000000..f149eb5 --- /dev/null +++ b/compat/siglist.in @@ -0,0 +1,56 @@ +# +# List of signals used to build sys_siglist (see mksiglist.c) +# Adapted from pdksh; public domain +# +# Note that if a system has multiple defines for the same signal +# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one +# will be seen, so the order in this list is important. +# + HUP Hangup + INT Interrupt + QUIT Quit + ILL Illegal instruction + TRAP Trace trap +# before IOT (ABRT is posix and ABRT is sometimes the same as IOT) + ABRT Abort + IOT IOT instruction + EMT EMT trap + FPE Floating point exception + KILL Killed +# before BUS (Older Linux doesn't really have a BUS, but defines it to UNUSED) + UNUSED Unused + BUS Bus error + SEGV Memory fault + SYS Bad system call + PIPE Broken pipe + ALRM Alarm clock + TERM Terminated + STKFLT Stack fault +# before POLL (POLL is sometimes the same as IO) + IO I/O possible + XCPU CPU time limit exceeded + XFSZ File size limit exceeded + VTALRM Virtual timer expired + PROF Profiling timer expired + WINCH Window size change + LOST File lock lost + USR1 User defined signal 1 + USR2 User defined signal 2 + PWR Power-fail/Restart + POLL Pollable event occurred + STOP Stopped (signal) + TSTP Stopped + CONT Continued +# before CLD (CHLD is posix and CHLD is sometimes the same as CLD) + CHLD Child exited + CLD Child exited + TTIN Stopped (tty input) + TTOU Stopped (tty output) + INFO Information request + URG Urgent I/O condition +# Solaris (svr4?) signals + WAITING No runnable LWPs + LWP Inter-LWP signal + FREEZE Checkpoint freeze + THAW Checkpoint thaw + CANCEL Thread cancellation diff --git a/compat/snprintf.c b/compat/snprintf.c new file mode 100644 index 0000000..8a77a5b --- /dev/null +++ b/compat/snprintf.c @@ -0,0 +1,707 @@ +/* + * Copyright (c) 1999-2005, 2008, 2010-2011 + * Todd C. Miller + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * From: @(#)vfprintf.c 8.1 (Berkeley) 6/4/93 + */ + +/* + * v?snprintf/v?asprintf based on 4.4BSD stdio. + * NOTE: does not support floating point. + */ + +#include + +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#include +#include + +#include "missing.h" + +static int xxxprintf(char **, size_t, int, const char *, va_list); + +/* + * Some systems may not have these defined in + */ +#ifndef ULONG_MAX +# define ULONG_MAX ((unsigned long)-1) +#endif +#ifndef LONG_MAX +# define LONG_MAX (ULONG_MAX / 2) +#endif +#ifdef HAVE_LONG_LONG_INT +# ifndef ULLONG_MAX +# ifdef UQUAD_MAX +# define ULLONG_MAX UQUAD_MAX +# else +# define ULLONG_MAX ((unsigned long long)-1) +# endif +# endif +# ifndef LLONG_MAX +# ifdef QUAD_MAX +# define LLONG_MAX QUAD_MAX +# else +# define LLONG_MAX (ULLONG_MAX / 2) +# endif +# endif +#endif /* HAVE_LONG_LONG_INT */ + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned int)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +/* + * Flags used during conversion. + */ +#define ALT 0x001 /* alternate form */ +#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ +#define LADJUST 0x004 /* left adjustment */ +#define LONGDBL 0x008 /* long double; unimplemented */ +#define LONGINT 0x010 /* long integer */ +#define QUADINT 0x020 /* quad integer */ +#define SHORTINT 0x040 /* short integer */ +#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ + +#define BUF 68 + +/* + * Convert an unsigned long to ASCII for printf purposes, returning + * a pointer to the first character of the string representation. + * Octal numbers can be forced to have a leading zero; hex numbers + * use the given digits. + */ +static char * +__ultoa(unsigned long val, char *endp, int base, int octzero, char *xdigs) +{ + char *cp = endp; + long sval; + + /* + * Handle the three cases separately, in the hope of getting + * better/faster code. + */ + switch (base) { + case 10: + if (val < 10) { /* many numbers are 1 digit */ + *--cp = to_char(val); + return cp; + } + /* + * On many machines, unsigned arithmetic is harder than + * signed arithmetic, so we do at most one unsigned mod and + * divide; this is sufficient to reduce the range of + * the incoming value to where signed arithmetic works. + */ + if (val > LONG_MAX) { + *--cp = to_char(val % 10); + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: /* oops */ + abort(); + } + return cp; +} + +/* Identical to __ultoa, but for quads. */ +#ifdef HAVE_LONG_LONG_INT +# if SIZEOF_LONG_INT == 8 +# define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x)) +# else +static char * +__uqtoa(unsigned long long val, char *endp, int base, int octzero, char *xdigs) +{ + char *cp = endp; + long long sval; + + /* quick test for small values; __ultoa is typically much faster */ + /* (perhaps instead we should run until small, then call __ultoa?) */ + if (val <= (unsigned long long)ULONG_MAX) + return __ultoa((unsigned long)val, endp, base, octzero, xdigs); + switch (base) { + case 10: + if (val < 10) { + *--cp = to_char(val % 10); + return cp; + } + if (val > LLONG_MAX) { + *--cp = to_char(val % 10); + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: /* oops */ + abort(); + } + return cp; +} +# endif /* !SIZEOF_LONG_INT */ +#endif /* HAVE_LONG_LONG_INT */ + +/* + * Actual printf innards. + */ +static int +xxxprintf(char **strp, size_t strsize, int alloc, const char *fmt0, va_list ap) +{ + char *fmt; /* format string */ + int ch; /* character from fmt */ + int n; /* handy integer (short term usage) */ + char *cp; /* handy char pointer (short term usage) */ + int flags; /* flags as above */ + int ret; /* return value accumulator */ + int width; /* width from format (%8d), or 0 */ + int prec; /* precision from format (%.3d), or -1 */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + unsigned long ulval = 0; /* integer arguments %[diouxX] */ +#ifdef HAVE_LONG_LONG_INT + unsigned long long uqval = 0; /* %q (quad) integers */ +#endif + int base; /* base for [diouxX] conversion */ + int dprec; /* a copy of prec if [diouxX], 0 otherwise */ + int fieldsz; /* field size expanded by sign, etc */ + int realsz; /* field size expanded by dprec */ + int size; /* size of converted field or string */ + char *xdigs = ""; /* digits for [xX] conversion */ + char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ + char ox[2]; /* space for 0x hex-prefix */ + char *str; /* pointer to string to fill */ + char *estr; /* pointer to last char in str */ + + /* + * Choose PADSIZE to trade efficiency vs. size. If larger printf + * fields occur frequently, increase PADSIZE and make the initialisers + * below longer. + */ +#define PADSIZE 16 /* pad chunk size */ + static char blanks[PADSIZE] = + {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; + static char zeroes[PADSIZE] = + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + + /* Print chars to "str", (allocate as needed if alloc is set). */ +#define PRINT(ptr, len) do { \ + const char *p = ptr; \ + const char *endp = ptr + len; \ + while (p < endp && (str < estr || alloc)) { \ + if (alloc && str >= estr) { \ + char *t; \ + strsize = (strsize << 1) + 1; \ + if (!(t = (char *)realloc(*strp, strsize))) { \ + free(str); \ + *strp = NULL; \ + ret = -1; \ + goto done; \ + } \ + str = t + (str - *strp); \ + estr = t + strsize - 1; \ + *strp = t; \ + } \ + *str++ = *p++; \ + } \ +} while (0) + + /* BEWARE, PAD uses `n'. */ +#define PAD(plen, pstr) do { \ + if ((n = (plen)) > 0) { \ + while (n > PADSIZE) { \ + PRINT(pstr, PADSIZE); \ + n -= PADSIZE; \ + } \ + PRINT(pstr, n); \ + } \ +} while (0) + + /* + * To extend shorts properly, we need both signed and unsigned + * argument extraction methods. + */ +#define SARG() \ + (flags&LONGINT ? va_arg(ap, long) : \ + flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ + (long)va_arg(ap, int)) +#define UARG() \ + (flags&LONGINT ? va_arg(ap, unsigned long) : \ + flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \ + (unsigned long)va_arg(ap, unsigned int)) + + fmt = (char *)fmt0; + ret = 0; + + if (alloc) { + strsize = 128; + *strp = str = (char *)malloc(strsize); + if (str == NULL) { + ret = -1; + goto done; + } + estr = str + 127; + } else { + str = *strp; + if (strsize) + estr = str + strsize - 1; + else + estr = NULL; + } + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) + /* void */; + if ((n = fmt - cp) != 0) { + PRINT(cp, n); + ret += n; + } + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + dprec = 0; + width = 0; + prec = -1; + sign = '\0'; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + /* + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /* + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if ((width = va_arg(ap, int)) >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + n = va_arg(ap, int); + prec = n < 0 ? -1 : n; + goto rflag; + } + n = 0; + while (is_digit(ch)) { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } + prec = n < 0 ? -1 : n; + goto reswitch; + case '0': + /* + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + width = n; + goto reswitch; + case 'h': + flags |= SHORTINT; + goto rflag; + case 'l': + flags |= LONGINT; + goto rflag; +#ifdef HAVE_LONG_LONG_INT + case 'q': + flags |= QUADINT; + goto rflag; +#endif /* HAVE_LONG_LONG_INT */ + case 'c': + *(cp = buf) = va_arg(ap, int); + size = 1; + sign = '\0'; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': +#ifdef HAVE_LONG_LONG_INT + if (flags & QUADINT) { + uqval = va_arg(ap, long long); + if ((long long)uqval < 0) { + uqval = -uqval; + sign = '-'; + } + } + else +#endif /* HAVE_LONG_LONG_INT */ + { + ulval = SARG(); + if ((long)ulval < 0) { + ulval = -ulval; + sign = '-'; + } + } + base = 10; + goto number; + case 'n': +#ifdef HAVE_LONG_LONG_INT + if (flags & QUADINT) + *va_arg(ap, long long *) = ret; + else +#endif /* HAVE_LONG_LONG_INT */ + if (flags & LONGINT) + *va_arg(ap, long *) = ret; + else if (flags & SHORTINT) + *va_arg(ap, short *) = ret; + else + *va_arg(ap, int *) = ret; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': +#ifdef HAVE_LONG_LONG_INT + if (flags & QUADINT) + uqval = va_arg(ap, unsigned long long); + else +#endif /* HAVE_LONG_LONG_INT */ + ulval = UARG(); + base = 8; + goto nosign; + case 'p': + /* + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + ulval = (unsigned long)va_arg(ap, void *); + base = 16; + xdigs = "0123456789abcdef"; + flags = (flags & ~QUADINT) | HEXPREFIX; + ch = 'x'; + goto nosign; + case 's': + if ((cp = va_arg(ap, char *)) == NULL) + cp = "(null)"; + if (prec >= 0) { + /* + * can't use strlen; can only look for the + * NUL in the first `prec' characters, and + * strlen() will go further. + */ + char *p = memchr(cp, 0, prec); + + if (p != NULL) { + size = p - cp; + if (size > prec) + size = prec; + } else + size = prec; + } else + size = strlen(cp); + sign = '\0'; + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': +#ifdef HAVE_LONG_LONG_INT + if (flags & QUADINT) + uqval = va_arg(ap, unsigned long long); + else +#endif /* HAVE_LONG_LONG_INT */ + ulval = UARG(); + base = 10; + goto nosign; + case 'X': + xdigs = "0123456789ABCDEF"; + goto hex; + case 'x': + xdigs = "0123456789abcdef"; +hex: +#ifdef HAVE_LONG_LONG_INT + if (flags & QUADINT) + uqval = va_arg(ap, unsigned long long); + else +#endif /* HAVE_LONG_LONG_INT */ + ulval = UARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && +#ifdef HAVE_LONG_LONG_INT + (flags & QUADINT ? uqval != 0 : ulval != 0)) +#else + ulval != 0) +#endif /* HAVE_LONG_LONG_INT */ + flags |= HEXPREFIX; + + /* unsigned conversions */ +nosign: sign = '\0'; + /* + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /* + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + */ + cp = buf + BUF; +#ifdef HAVE_LONG_LONG_INT + if (flags & QUADINT) { + if (uqval != 0 || prec != 0) + cp = __uqtoa(uqval, cp, base, + flags & ALT, xdigs); + } + else +#endif /* HAVE_LONG_LONG_INT */ + { + if (ulval != 0 || prec != 0) + cp = __ultoa(ulval, cp, base, + flags & ALT, xdigs); + } + size = buf + BUF - cp; + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + /* pretend it was %c with argument ch */ + cp = buf; + *cp = ch; + size = 1; + sign = '\0'; + break; + } + + /* + * All reasonable formats wind up here. At this point, `cp' + * points to a string which (if not flags&LADJUST) should be + * padded out to `width' places. If flags&ZEROPAD, it should + * first be prefixed by any sign or other prefix; otherwise, + * it should be blank padded before the prefix is emitted. + * After any left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print the + * string proper, then emit zeroes required by any leftover + * floating precision; finally, if LADJUST, pad with blanks. + * + * Compute actual size, so we know how much to pad. + * fieldsz excludes decimal prec; realsz includes it. + */ + fieldsz = size; + if (sign) + fieldsz++; + else if (flags & HEXPREFIX) + fieldsz += 2; + realsz = dprec > fieldsz ? dprec : fieldsz; + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0) + PAD(width - realsz, blanks); + + /* prefix */ + if (sign) { + PRINT(&sign, 1); + } else if (flags & HEXPREFIX) { + ox[0] = '0'; + ox[1] = ch; + PRINT(ox, 2); + } + + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + PAD(width - realsz, zeroes); + + /* leading zeroes from decimal precision */ + PAD(dprec - fieldsz, zeroes); + + /* the string or number proper */ + PRINT(cp, size); + + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD(width - realsz, blanks); + + /* finally, adjust ret */ + ret += width > realsz ? width : realsz; + } +done: + if (strsize) + *str = '\0'; + return ret; + /* NOTREACHED */ +} + +#ifndef HAVE_VSNPRINTF +int +vsnprintf(char *str, size_t n, const char *fmt, va_list ap) +{ + + return xxxprintf(&str, n, 0, fmt, ap); +} +#endif /* HAVE_VSNPRINTF */ + +#ifndef HAVE_SNPRINTF +int +snprintf(char *str, size_t n, char const *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = xxxprintf(&str, n, 0, fmt, ap); + va_end(ap); + return ret; +} +#endif /* HAVE_SNPRINTF */ + +#ifndef HAVE_VASPRINTF +int +vasprintf(char **str, const char *fmt, va_list ap) +{ + + return xxxprintf(str, 0, 1, fmt, ap); +} +#endif /* HAVE_VASPRINTF */ + +#ifndef HAVE_ASPRINTF +int +asprintf(char **str, char const *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = xxxprintf(str, 0, 1, fmt, ap); + va_end(ap); + return ret; +} +#endif /* HAVE_ASPRINTF */ diff --git a/compat/stdbool.h b/compat/stdbool.h new file mode 100644 index 0000000..a6e65ea --- /dev/null +++ b/compat/stdbool.h @@ -0,0 +1,44 @@ +/* $OpenBSD: stdbool.h,v 1.5 2010/07/24 22:17:03 guenther Exp $ */ + +/* + * Written by Marc Espie, September 25, 1999 + * Public domain. + */ + +#ifndef _COMPAT_STDBOOL_H_ +#define _COMPAT_STDBOOL_H_ + +#ifndef __cplusplus + +#if (defined(HAVE__BOOL) && HAVE__BOOL > 0) || defined(lint) +/* Support for _C99: type _Bool is already built-in. */ +#define false 0 +#define true 1 + +#else +/* `_Bool' type must promote to `int' or `unsigned int'. */ +typedef enum { + false = 0, + true = 1 +} _Bool; + +/* And those constants must also be available as macros. */ +#define false false +#define true true + +#endif + +/* User visible type `bool' is provided as a macro which may be redefined */ +#define bool _Bool + +#else /* __cplusplus */ +#define _Bool bool +#define bool bool +#define false false +#define true true +#endif /* __cplusplus */ + +/* Inform that everything is fine */ +#define __bool_true_false_are_defined 1 + +#endif /* _COMPAT_STDBOOL_H_ */ diff --git a/compat/strlcat.c b/compat/strlcat.c new file mode 100644 index 0000000..57e3ca5 --- /dev/null +++ b/compat/strlcat.c @@ -0,0 +1,60 @@ +/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ + +/* + * Copyright (c) 1998, 2003-2005, 2010-2011 + * Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include + +#include "missing.h" + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return dlen + strlen(s); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return dlen + (s - src); /* count does not include NUL */ +} diff --git a/compat/strlcpy.c b/compat/strlcpy.c new file mode 100644 index 0000000..89fb01b --- /dev/null +++ b/compat/strlcpy.c @@ -0,0 +1,55 @@ +/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ + +/* + * Copyright (c) 1998, 2003-2005, 2010-2011 + * Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "missing.h" + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, const char *src, size_t siz) +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return s - src - 1; /* count does not include NUL */ +} diff --git a/compat/strsignal.c b/compat/strsignal.c new file mode 100644 index 0000000..a13346c --- /dev/null +++ b/compat/strsignal.c @@ -0,0 +1,48 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include +#include + +#include "missing.h" + +#define DEFAULT_TEXT_DOMAIN "sudo" +#include "gettext.h" + +#if defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST == 1 +# define my_sys_siglist sys_siglist +#elif defined(HAVE_DECL__SYS_SIGLIST) && HAVE_DECL__SYS_SIGLIST == 1 +# define my_sys_siglist _sys_siglist +#elif defined(HAVE_DECL___SYS_SIGLIST) && HAVE_DECL___SYS_SIGLIST == 1 +# define my_sys_siglist __sys_siglist +#else +extern const char *const my_sys_siglist[NSIG]; +#endif + +/* + * Get signal description string + */ +char * +strsignal(int signo) +{ + if (signo > 0 && signo < NSIG) + return (char *)my_sys_siglist[signo]; + return _("Unknown signal"); +} diff --git a/compat/timespec.h b/compat/timespec.h new file mode 100644 index 0000000..4c9dedc --- /dev/null +++ b/compat/timespec.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2005, 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. + */ + +#ifndef _SUDO_TIMESPEC_H +#define _SUDO_TIMESPEC_H + +struct timespec { + time_t tv_sec; + long tv_nsec; +}; + +#endif /* _SUDO_TIMESPEC_H */ diff --git a/compat/utime.h b/compat/utime.h new file mode 100644 index 0000000..0a1eb86 --- /dev/null +++ b/compat/utime.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 1996, 1998-2005, 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. + */ + +#ifndef _UTIME_H +#define _UTIME_H + +struct utimbuf { + time_t actime; /* access time */ + time_t modtime; /* mod time */ +}; + +int utime(const char *, const struct utimbuf *); + +#endif /* _UTIME_H */ diff --git a/compat/utimes.c b/compat/utimes.c new file mode 100644 index 0000000..455ecd2 --- /dev/null +++ b/compat/utimes.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004-2005, 2007, 2010-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. + */ + +#include + +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +#endif + +#ifdef HAVE_UTIME_H +# include +#else +# include "compat/utime.h" +#endif + +#include "missing.h" + +#ifndef HAVE_UTIMES +/* + * Emulate utimes() via utime() + */ +int +utimes(const char *file, const struct timeval *times) +{ + if (times != NULL) { + struct utimbuf utb; + + utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000); + utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000); + return utime(file, &utb); + } else + return utime(file, NULL); +} +#endif /* !HAVE_UTIMES */ + +#ifdef HAVE_FUTIME +/* + * Emulate futimes() via futime() + */ +int +futimes(int fd, const struct timeval *times) +{ + if (times != NULL) { + struct utimbuf utb; + + utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000); + utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000); + return futime(fd, &utb); + } else + return futime(fd, NULL); +} +#endif /* HAVE_FUTIME */ diff --git a/config.guess b/config.guess index d53e309..43f0cdb 100644 --- a/config.guess +++ b/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 -# Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011 Free Software Foundation, Inc. -timestamp='2009-11-19' +timestamp='2011-10-01' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -56,8 +56,9 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free +Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -180,7 +181,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release @@ -223,7 +224,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on @@ -269,7 +270,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead @@ -295,7 +299,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo s390-ibm-zvmoe exit ;; *:OS400:*:*) - echo powerpc-ibm-os400 + echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} @@ -333,6 +337,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" @@ -391,23 +398,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; @@ -477,8 +484,8 @@ EOF echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ @@ -491,7 +498,7 @@ EOF else echo i586-dg-dgux${UNAME_RELEASE} fi - exit ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; @@ -548,7 +555,7 @@ EOF echo rs6000-ibm-aix3.2 fi exit ;; - *:AIX:*:[456]) + *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 @@ -591,52 +598,52 @@ EOF 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + sed 's/^ //' << EOF >$dummy.c - #define _HPUX_SOURCE - #include - #include + #define _HPUX_SOURCE + #include + #include - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa @@ -727,22 +734,22 @@ EOF exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; @@ -766,14 +773,14 @@ EOF exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} @@ -785,13 +792,12 @@ EOF echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) @@ -801,14 +807,14 @@ EOF echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; @@ -863,7 +869,7 @@ EOF EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; - esac + esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} @@ -875,7 +881,13 @@ EOF then echo ${UNAME_MACHINE}-unknown-linux-gnu else - echo ${UNAME_MACHINE}-unknown-linux-gnueabi + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi fi exit ;; avr32*:Linux:*:*) @@ -888,7 +900,10 @@ EOF echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) - echo frv-unknown-linux-gnu + echo frv-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo hexagon-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu @@ -956,7 +971,7 @@ EOF echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -964,6 +979,9 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; @@ -971,7 +989,7 @@ EOF echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -980,11 +998,11 @@ EOF echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) @@ -1016,7 +1034,7 @@ EOF fi exit ;; i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; @@ -1044,13 +1062,13 @@ EOF exit ;; pc:*:*:*) # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp - exit ;; + exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; @@ -1085,8 +1103,8 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ @@ -1129,10 +1147,10 @@ EOF echo ns32k-sni-sysv fi exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm @@ -1158,11 +1176,11 @@ EOF exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; @@ -1227,6 +1245,9 @@ EOF *:QNX:*:4*) echo i386-pc-qnx exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; @@ -1272,13 +1293,13 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; @@ -1318,11 +1339,11 @@ main () #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 - "4" + "4" #else - "" + "" #endif - ); exit (0); + ); exit (0); #endif #endif diff --git a/config.h.in b/config.h.in index af5653b..252c1f4 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 @@ -76,6 +79,14 @@ /* Define to 1 if your `DIR' contains dd_fd. */ #undef HAVE_DD_FD +/* Define to 1 if you have the declaration of `errno', and to 0 if you don't. + */ +#undef HAVE_DECL_ERRNO + +/* Define to 1 if you have the declaration of `h_errno', and to 0 if you + don't. */ +#undef HAVE_DECL_H_ERRNO + /* Define to 1 if you have the declaration of `sys_siglist', and to 0 if you don't. */ #undef HAVE_DECL_SYS_SIGLIST @@ -88,9 +99,6 @@ don't. */ #undef HAVE_DECL___SYS_SIGLIST -/* Define to 1 if you have the `dgettext' function. */ -#undef HAVE_DGETTEXT - /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H @@ -104,8 +112,8 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H -/* Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags. */ -#undef HAVE_EXTENDED_GLOB +/* Define to 1 if you have the `dlopen' function. */ +#undef HAVE_DLOPEN /* Define to 1 if your system has the F_CLOSEM fcntl. */ #undef HAVE_FCNTL_CLOSEM @@ -122,9 +130,6 @@ /* Define to 1 if you have the `freeifaddrs' function. */ #undef HAVE_FREEIFADDRS -/* Define to 1 if you have the `fstat' function. */ -#undef HAVE_FSTAT - /* Define to 1 if you have the `futime' function. */ #undef HAVE_FUTIME @@ -150,9 +155,15 @@ /* Define to 1 if you have the `getdomainname' function. */ #undef HAVE_GETDOMAINNAME -/* Define to 1 if you have the `getgroups' function. */ +/* Define to 1 if you have the `getgrouplist' function. */ +#undef HAVE_GETGROUPLIST + +/* Define to 1 if your system has a working `getgroups' function. */ #undef HAVE_GETGROUPS +/* Define to 1 if you have the `getgrset' function. */ +#undef HAVE_GETGRSET + /* Define to 1 if you have the `getifaddrs' function. */ #undef HAVE_GETIFADDRS @@ -170,6 +181,9 @@ passwords) */ #undef HAVE_GETPWANAM +/* Define to 1 if you have the `getresuid' function. */ +#undef HAVE_GETRESUID + /* Define to 1 if you have the `getspnam' function (SVR4-style shadow passwords) */ #undef HAVE_GETSPNAM @@ -178,8 +192,8 @@ passwords) */ #undef HAVE_GETSPWUID -/* Define to 1 if you have the `gettimeofday' function. */ -#undef HAVE_GETTIMEOFDAY +/* Define to 1 if you have the `getttyent' function. */ +#undef HAVE_GETTTYENT /* Define to 1 if you have the `getuserattr' function. */ #undef HAVE_GETUSERATTR @@ -205,12 +219,6 @@ /* Define to 1 if your Kerberos is Heimdal. */ #undef HAVE_HEIMDAL -/* Define to 1 if contains struct in6_addr. */ -#undef HAVE_IN6_ADDR - -/* Define to 1 if you have the `initgroups' function. */ -#undef HAVE_INITGROUPS - /* Define to 1 if you have the `initprivs' function. */ #undef HAVE_INITPRIVS @@ -231,9 +239,6 @@ shadow enabled) */ #undef HAVE_ISSECURE -/* Define to 1 if you use Kerberos IV. */ -#undef HAVE_KERB4 - /* Define to 1 if you use Kerberos V. */ #undef HAVE_KERB5 @@ -280,6 +285,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 @@ -298,8 +306,11 @@ /* Define to 1 if you have the `ldap_unbind_ext_s' function. */ #undef HAVE_LDAP_UNBIND_EXT_S -/* Define to 1 if you have the `dl' library (-ldl). */ -#undef HAVE_LIBDL +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBUTIL_H /* Define to 1 to enable Linux audit support. */ #undef HAVE_LINUX_AUDIT @@ -325,20 +336,14 @@ /* Define to 1 if you have the `mbr_check_membership' function. */ #undef HAVE_MBR_CHECK_MEMBERSHIP -/* Define to 1 if you have the `memchr' function. */ -#undef HAVE_MEMCHR - -/* Define to 1 if you have the `memcpy' function. */ -#undef HAVE_MEMCPY - /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memrchr' function. */ #undef HAVE_MEMRCHR -/* Define to 1 if you have the `memset' function. */ -#undef HAVE_MEMSET +/* Define to 1 if you have the `mkdtemp' function. */ +#undef HAVE_MKDTEMP /* Define to 1 if you have the `mkstemps' function. */ #undef HAVE_MKSTEMPS @@ -355,6 +360,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 @@ -364,6 +372,9 @@ /* Define to 1 if you use PAM authentication. */ #undef HAVE_PAM +/* Define to 1 if you have the `pam_getenvlist' function. */ +#undef HAVE_PAM_GETENVLIST + /* Define to 1 if you use a specific PAM session for sudo -i. */ #undef HAVE_PAM_LOGIN @@ -376,12 +387,21 @@ /* Define to 1 if you have the `posix_openpt' function. */ #undef HAVE_POSIX_OPENPT +/* Define to 1 if you have the `priv_set' function. */ +#undef HAVE_PRIV_SET + +/* Define to 1 if you have the header file. */ +#undef HAVE_PROCFS_H + /* Define to 1 if you have the header file. */ #undef HAVE_PROJECT_H /* Define to 1 if you have the header file. */ #undef HAVE_PTY_H +/* Define to 1 if you have the `pw_dup' function. */ +#undef HAVE_PW_DUP + /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM @@ -391,15 +411,16 @@ /* Define to 1 if you have the `revoke' function. */ #undef HAVE_REVOKE +/* Define to 1 if the skeychallenge() function is RFC1938-compliant and takes + 4 arguments */ +#undef HAVE_RFC1938_SKEYCHALLENGE + /* Define to 1 if you have the header file. */ #undef HAVE_SASL_H /* Define to 1 if you have the header file. */ #undef HAVE_SASL_SASL_H -/* Define if your struct sockadr has an sa_len field. */ -#undef HAVE_SA_LEN - /* Define to 1 if you use SecurID for authentication. */ #undef HAVE_SECURID @@ -430,25 +451,19 @@ /* Define to 1 if you have the `setreuid' function. */ #undef HAVE_SETREUID -/* Define to 1 if you have the `setrlimit' function. */ -#undef HAVE_SETRLIMIT - /* Define to 1 if you have the `setrlimit64' function. */ #undef HAVE_SETRLIMIT64 -/* Define to 1 if you have the `setsid' function. */ -#undef HAVE_SETSID - /* Define to 1 if you have the `set_auth_parameters' function. */ #undef HAVE_SET_AUTH_PARAMETERS +/* Define to 1 if you have the `shl_load' function. */ +#undef HAVE_SHL_LOAD + /* Define to 1 if you have the `sia_ses_init' function. */ #undef HAVE_SIA_SES_INIT -/* Define to 1 if you have the `sigaction' function. */ -#undef HAVE_SIGACTION - -/* Define to 1 if has the sigaction_t typedef. */ +/* Define to 1 if the system has the type `sigaction_t'. */ #undef HAVE_SIGACTION_T /* Define to 1 if you use S/Key. */ @@ -460,21 +475,18 @@ /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF +/* Define to 1 if you have the header file. */ +#undef HAVE_SPAWN_H + +/* Define to 1 if stdbool.h conforms to C99. */ +#undef HAVE_STDBOOL_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define to 1 if you have the `strcasecmp' function. */ -#undef HAVE_STRCASECMP - -/* Define to 1 if you have the `strchr' function. */ -#undef HAVE_STRCHR - -/* Define to 1 if you have the `strerror' function. */ -#undef HAVE_STRERROR - /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME @@ -496,9 +508,78 @@ /* Define to 1 if you have the `strsignal' function. */ #undef HAVE_STRSIGNAL +/* Define to 1 if `d_type' is a member of `struct dirent'. */ +#undef HAVE_STRUCT_DIRENT_D_TYPE + /* Define to 1 if the system has the type `struct in6_addr'. */ #undef HAVE_STRUCT_IN6_ADDR +/* Define to 1 if `p_tdev' is a member of `struct kinfo_proc2'. */ +#undef HAVE_STRUCT_KINFO_PROC2_P_TDEV + +/* Define to 1 if `ki_tdev' is a member of `struct kinfo_proc'. */ +#undef HAVE_STRUCT_KINFO_PROC_KI_TDEV + +/* Define to 1 if `kp_eproc.e_tdev' is a member of `struct kinfo_proc'. */ +#undef HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV + +/* Define to 1 if `p_tdev' is a member of `struct kinfo_proc'. */ +#undef HAVE_STRUCT_KINFO_PROC_P_TDEV + +/* Define to 1 if `pr_ttydev' is a member of `struct psinfo'. */ +#undef HAVE_STRUCT_PSINFO_PR_TTYDEV + +/* Define if your struct sockadr has an sa_len field. */ +#undef HAVE_STRUCT_SOCKADDR_SA_LEN + +/* Define to 1 if the system has the type `struct timespec'. */ +#undef HAVE_STRUCT_TIMESPEC + +/* Define to 1 if `ut_exit' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_EXIT + +/* Define to 1 if `ut_exit.e_termination' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION + +/* Define to 1 if `ut_exit.__e_termination' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_EXIT___E_TERMINATION + +/* Define to 1 if `ut_id' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_ID + +/* Define to 1 if `ut_pid' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_PID + +/* Define to 1 if `ut_tv' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_TV + +/* Define to 1 if `ut_type' is a member of `struct utmpx'. */ +#undef HAVE_STRUCT_UTMPX_UT_TYPE + +/* Define to 1 if `ut_exit' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_EXIT + +/* Define to 1 if `ut_exit.e_termination' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION + +/* Define to 1 if `ut_exit.__e_termination' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_EXIT___E_TERMINATION + +/* Define to 1 if `ut_id' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_ID + +/* Define to 1 if `ut_pid' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_PID + +/* Define to 1 if `ut_tv' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_TV + +/* Define to 1 if `ut_type' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_TYPE + +/* Define to 1 if `ut_user' is a member of `struct utmp'. */ +#undef HAVE_STRUCT_UTMP_UT_USER + /* Define to 1 if your struct stat has an st_mtim member */ #undef HAVE_ST_MTIM @@ -525,6 +606,9 @@ */ #undef HAVE_SYS_NDIR_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PROCFS_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H @@ -537,21 +621,14 @@ /* 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 -/* Define to 1 if you have the `tcsetpgrp' function. */ -#undef HAVE_TCSETPGRP - -/* Define to 1 if you have the header file and the `tcgetattr' - function. */ -#undef HAVE_TERMIOS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_TERMIO_H - -/* Define to 1 if you have struct timespec in sys/time.h */ -#undef HAVE_TIMESPEC +/* Define to 1 if you have the `ttyslot' function. */ +#undef HAVE_TTYSLOT /* Define to 1 if you have the `tzset' function. */ #undef HAVE_TZSET @@ -571,30 +648,33 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H +/* Define to 1 if you have the header file. */ +#undef HAVE_UTMPX_H + /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF -/* Define to 1 if you have the `vhangup' function. */ -#undef HAVE_VHANGUP - /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF -/* Define to 1 if you have the `wait3' function. */ -#undef HAVE_WAIT3 - -/* Define to 1 if you have the `waitpid' function. */ -#undef HAVE_WAITPID - /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + /* Define to 1 if you have the `_getpty' function. */ #undef HAVE__GETPTY /* Define to 1 if you have the `_innetgr' function. */ #undef HAVE__INNETGR +/* Define to 1 if you have the `_ttyname_dev' function. */ +#undef HAVE__TTYNAME_DEV + +/* Define to 1 if the compiler supports the C99 __func__ variable. */ +#undef HAVE___FUNC__ + /* Define to 1 if your crt0.o defines the __progname symbol for you. */ #undef HAVE___PROGNAME @@ -607,9 +687,6 @@ /* The message given when a bad password is entered. */ #undef INCORRECT_PASSWORD -/* The name of libvas.so */ -#undef LIBVAS_SO - /* The syslog facility sudo will use. */ #undef LOGFAC @@ -629,6 +706,14 @@ /* The user or email address that sudo mail is sent to. */ #undef MAILTO +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +#undef MAJOR_IN_MKDEV + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +#undef MAJOR_IN_SYSMACROS + /* The max number of chars per log file line (for line wrapping). */ #undef MAXLOGFILELEN @@ -689,11 +774,21 @@ /* The syslog priority sudo will use for successful attempts. */ #undef PRI_SUCCESS -/* Define to 1 if the `putenv' has a const argument. */ +/* Define to const if the `putenv' takes a const argument. */ #undef PUTENV_CONST -/* Define as the return type of signal handlers (`int' or `void'). */ -#undef RETSIGTYPE +/* The default value of preloaded objects (if any). */ +#undef RTLD_PRELOAD_DEFAULT + +/* The delimiter to use when defining multiple preloaded objects. */ +#undef RTLD_PRELOAD_DELIM + +/* An extra environment variable that is required to enable preloading (if + any). */ +#undef RTLD_PRELOAD_ENABLE_VAR + +/* The environment variable that controls preloading of dynamic objects. */ +#undef RTLD_PRELOAD_VAR /* The user sudo should run commands as by default. */ #undef RUNAS_DEFAULT @@ -711,9 +806,6 @@ /* Define to 1 to send mail when the user is not in the sudoers file. */ #undef SEND_MAIL_WHEN_NO_USER -/* Define to 1 if the `setpgrp' function takes no argument. */ -#undef SETPGRP_VOID - /* Define to 1 if you want sudo to start a shell if given no arguments. */ #undef SHELL_IF_NO_ARGS @@ -729,7 +821,14 @@ /* 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 name of the sudoers plugin, including extension. */ +#undef SUDOERS_PLUGIN + +/* An instance string to append to the username (separated by a slash) for + Kerberos V authentication */ +#undef SUDO_KRB5_INSTANCE + +/* 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 +840,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 @@ -755,12 +858,19 @@ /* Define to 1 if you use GNU stow packaging. */ #undef USE_STOW -/* Define to 1 if using a non-Unix group lookup implementation. */ -#undef USING_NONUNIX_GROUPS - /* Define to avoid using the passwd/shadow file for authentication. */ #undef WITHOUT_PASSWD +/* 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 __FUNCTION__ if your compiler support __FUNCTION__ but not + __func__ */ +#undef __func__ + /* Define to `signed' or nothing if compiler does not support a signed type qualifier. */ #undef __signed @@ -768,13 +878,13 @@ /* Define to empty if `const' does not conform to ANSI C. */ #undef const -/* Define if your system lacks the dev_t type. */ +/* Define to `int' if does not define. */ #undef dev_t /* Define to `int' if doesn't define. */ #undef gid_t -/* Define if your system lacks the ino_t type. */ +/* Define to `unsigned int' if does not define. */ #undef ino_t /* Define to `int' if does not define. */ @@ -786,7 +896,10 @@ /* Define to `unsigned int' if does not define. */ #undef size_t -/* Define if your system lacks the ssize_t type. */ +/* Define to `unsigned int' if doesn't define. */ +#undef socklen_t + +/* Define to `int' if does not define. */ #undef ssize_t /* Define to `int' if doesn't define. */ @@ -822,15 +935,13 @@ # endif /* HAVE_ST_MTIMESPEC */ #endif /* HAVE_ST_MTIM */ -/* - * Emulate a subset of waitpid() if we don't have it. - */ -#ifdef HAVE_WAITPID -# define sudo_waitpid(p, s, o) waitpid(p, s, o) +#ifdef __GNUC__ +# define ignore_result(x) do { \ + __typeof__(x) y = (x); \ + (void)y; \ +} while(0) #else -# ifdef HAVE_WAIT3 -# define sudo_waitpid(p, s, o) wait3(s, o, NULL) -# endif +# define ignore_result(x) (void)(x) #endif /* GNU stow needs /etc/sudoers to be a symlink. */ @@ -848,7 +959,7 @@ #undef ISSET #define ISSET(t, f) ((t) & (f)) -/* New ANSI-style OS defs for HP-UX and ConvexOS. */ +/* ANSI-style OS defs for HP-UX and ConvexOS. */ #if defined(hpux) && !defined(__hpux) # define __hpux 1 #endif /* hpux */ diff --git a/config.sub b/config.sub index acb095a..a97ae69 100755 --- a/config.sub +++ b/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 -# Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011 Free Software Foundation, Inc. -timestamp='2009-11-07' +timestamp='2011-10-08' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -75,8 +75,9 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free +Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -123,8 +124,9 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os @@ -156,8 +158,8 @@ case $os in os= basic_machine=$1 ;; - -bluegene*) - os=-cnk + -bluegene*) + os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= @@ -173,10 +175,10 @@ case $os in os=-chorusos basic_machine=$1 ;; - -chorusrdb) - os=-chorusrdb + -chorusrdb) + os=-chorusrdb basic_machine=$1 - ;; + ;; -hiux*) os=-hiuxwe2 ;; @@ -249,13 +251,17 @@ case $basic_machine in | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ + | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep | metag \ @@ -281,11 +287,13 @@ case $basic_machine in | moxie \ | mt \ | msp430 \ + | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ + | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rx \ | score \ @@ -293,15 +301,24 @@ case $basic_machine in | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ - | v850 | v850e \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; m6811 | m68hc11 | m6812 | m68hc12 | picochip) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown @@ -313,6 +330,18 @@ case $basic_machine in basic_machine=mt-unknown ;; + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. @@ -332,16 +361,19 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | be32-* | be64-* \ | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ + | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ @@ -367,25 +399,29 @@ case $basic_machine in | mmix-* \ | mt-* \ | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ | tron-* \ | ubicom32-* \ - | v850-* | v850e-* | vax-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) @@ -410,7 +446,7 @@ case $basic_machine in basic_machine=a29k-amd os=-udi ;; - abacus) + abacus) basic_machine=abacus-unknown ;; adobe68k) @@ -480,11 +516,20 @@ case $basic_machine in basic_machine=powerpc-ibm os=-cnk ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; c90) basic_machine=c90-cray os=-unicos ;; - cegcc) + cegcc) basic_machine=arm-unknown os=-cegcc ;; @@ -516,7 +561,7 @@ case $basic_machine in basic_machine=craynv-cray os=-unicosmp ;; - cr16) + cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; @@ -736,7 +781,7 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; - microblaze) + microblaze) basic_machine=microblaze-xilinx ;; mingw32) @@ -779,6 +824,10 @@ case $basic_machine in basic_machine=i370-ibm os=-mvs ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -843,6 +892,12 @@ case $basic_machine in np1) basic_machine=np1-gould ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -925,9 +980,10 @@ case $basic_machine in ;; power) basic_machine=power-ibm ;; - ppc) basic_machine=powerpc-unknown + ppc | ppcbe) basic_machine=powerpc-unknown ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown @@ -1021,6 +1077,9 @@ case $basic_machine in basic_machine=i860-stratus os=-sysv4 ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; sun2) basic_machine=m68000-sun ;; @@ -1077,20 +1136,8 @@ case $basic_machine in basic_machine=t90-cray os=-unicos ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff - ;; tile*) - basic_machine=tile-unknown + basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) @@ -1160,6 +1207,9 @@ case $basic_machine in xps | xps100) basic_machine=xps100-honeywell ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; ymp) basic_machine=ymp-cray os=-unicos @@ -1257,9 +1307,12 @@ esac if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # First match some system type aliases + # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; @@ -1281,8 +1334,8 @@ case $os in # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -kopensolaris* \ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ @@ -1295,7 +1348,8 @@ case $os in | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ @@ -1342,7 +1396,7 @@ case $os in -opened*) os=-openedition ;; - -os400*) + -os400*) os=-os400 ;; -wince*) @@ -1391,7 +1445,7 @@ case $os in -sinix*) os=-sysv4 ;; - -tpf*) + -tpf*) os=-tpf ;; -triton*) @@ -1436,6 +1490,8 @@ case $os in -dicos*) os=-dicos ;; + -nacl*) + ;; -none) ;; *) @@ -1458,10 +1514,10 @@ else # system, and we'll never get to this point. case $basic_machine in - score-*) + score-*) os=-elf ;; - spu-*) + spu-*) os=-elf ;; *-acorn) @@ -1473,8 +1529,17 @@ case $basic_machine in arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1501,7 +1566,7 @@ case $basic_machine in m68*-cisco) os=-aout ;; - mep-*) + mep-*) os=-elf ;; mips*-cisco) @@ -1528,7 +1593,7 @@ case $basic_machine in *-ibm) os=-aix ;; - *-knuth) + *-knuth) os=-mmixware ;; *-wec) diff --git a/configure b/configure index e66f189..4d12595 100755 --- a/configure +++ b/configure @@ -1,13 +1,13 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.65 for sudo 1.7.4p4. +# Generated by GNU Autoconf 2.68 for sudo 1.8.5p2. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, -# Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -91,6 +91,7 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -173,6 +174,14 @@ test x\$exitcode = x0 || exit 1" as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes @@ -216,11 +225,18 @@ IFS=$as_save_IFS # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : @@ -319,7 +335,7 @@ $as_echo X"$as_dir" | test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p @@ -359,19 +375,19 @@ else fi # as_fn_arith -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. +# script with STATUS, using 1 if that was 0. as_fn_error () { - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -528,161 +544,14 @@ as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -# Check that we are running under the correct shell. SHELL=${CONFIG_SHELL-/bin/sh} -case X$lt_ECHO in -X*--fallback-echo) - # Remove one level of quotation (which was required for Make). - ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','` - ;; -esac - -ECHO=${lt_ECHO-echo} -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then - # Yippee, $ECHO works! - : -else - # Restart under the correct shell. - exec $SHELL "$0" --no-reexec ${1+"$@"} -fi - -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat <<_LT_EOF -$* -_LT_EOF - exit 0 -fi - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -if test -z "$lt_ECHO"; then - if test "X${echo_test_string+set}" != Xset; then - # find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... - if { echo_test_string=`eval $cmd`; } 2>/dev/null && - { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null - then - break - fi - done - fi - - if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && - echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : - else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - ECHO="$dir/echo" - break - fi - done - IFS="$lt_save_ifs" - - if test "X$ECHO" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && - echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - ECHO='print -r' - elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"} - else - # Try using printf. - ECHO='printf %s\n' - if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && - echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - ECHO="$CONFIG_SHELL $0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - ECHO="$CONFIG_SHELL $0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do - if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null - then - break - fi - prev="$cmd" - done - - if test "$prev" != 'sed 50q "$0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"} - else - # Oops. We lost completely, so just stick with echo. - ECHO=echo - fi - fi - fi - fi - fi -fi - -# Copy echo and quote the copy suitably for passing to libtool from -# the Makefile, instead of quoting the original, which is used later. -lt_ECHO=$ECHO -if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then - lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo" -fi - - - test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -701,11 +570,12 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sudo' PACKAGE_TARNAME='sudo' -PACKAGE_VERSION='1.7.4p4' -PACKAGE_STRING='sudo 1.7.4p4' +PACKAGE_VERSION='1.8.5p2' +PACKAGE_STRING='sudo 1.8.5p2' PACKAGE_BUGREPORT='http://www.sudo.ws/bugs/' PACKAGE_URL='' +ac_config_libobj_dir=compat # Factoring default headers for most tests. ac_includes_default="\ #include @@ -756,8 +626,11 @@ OTOOL LIPO NMEDIT DSYMUTIL -lt_ECHO +MANIFEST_TOOL +AWK STRIP +ac_ct_AR +DLLTOOL OBJDUMP LN_S NM @@ -794,6 +667,7 @@ root_sudo insults tty_tickets passwd_tries +env_reset env_editor runas_default fqdn @@ -811,20 +685,31 @@ logfac lecture long_otp_prompt passprompt +umask_override sudo_umask password_timeout timeout timedir +iolog_dir +COMPAT_TEST_PROGS +SUDO_NLS +LIBINTL +LT_STATIC +LIBDL CONFIGURE_ARGS +ac_config_libobj_dir +LIBTOOL_DEPS +ZLIB_SRC ZLIB LOGINCAP_USAGE -REPLAY LDAP SELINUX_USAGE BSDAUTH_USAGE DONT_LEAK_PATH_INFO INSTALL_NOEXEC noexec_file +SOEXT +PLUGINDIR NOEXECDIR NOEXECFILE mansrcdir @@ -834,7 +719,7 @@ devdir SEMAN LCMAN BAMAN -DEV +DEVEL SUDOERS_GID SUDOERS_UID SUDOERS_MODE @@ -843,12 +728,16 @@ MANTYPE AUTH_OBJS OSDEFS GETGROUPS_LIB +REPLAY_LIBS AFS_LIBS NET_LIBS +SUDOERS_LIBS SUDO_LIBS SUDO_OBJS -SUDO_LDFLAGS +SUDOERS_OBJS COMMON_OBJS +LTLDFLAGS +SUDOERS_LDFLAGS LDFLAGS CPPFLAGS PROGS @@ -915,7 +804,6 @@ with_opie with_long_otp_prompt with_SecurID with_fwtk -with_kerb4 with_kerb5 with_aixauth with_pam @@ -947,6 +835,7 @@ with_sudoers_mode with_sudoers_uid with_sudoers_gid with_umask +with_umask_override with_runas_default with_exempt with_editor @@ -970,8 +859,7 @@ with_secure_path with_interfaces with_stow with_askpass -with_libvas -with_libvas_rpath +with_plugindir enable_authentication enable_root_mailer enable_setreuid @@ -983,8 +871,12 @@ enable_noargs_shell enable_shell_sets_home enable_path_info enable_env_debug +enable_zlib +enable_env_reset enable_warnings +enable_werror enable_admin_flag +enable_nls with_selinux enable_gss_krb5_ccache_name enable_shared @@ -992,13 +884,15 @@ enable_static with_pic enable_fast_install with_gnu_ld +with_sysroot enable_libtool_lock with_noexec with_netsvc enable_sia +enable_largefile with_pam_login enable_pam_session -enable_zlib +enable_kerb5_instance ' ac_precious_vars='build_alias host_alias @@ -1073,8 +967,9 @@ do fi case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -1119,7 +1014,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1145,7 +1040,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" + as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1349,7 +1244,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1365,7 +1260,7 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" + as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1395,8 +1290,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information." + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" ;; *=*) @@ -1404,7 +1299,7 @@ Try \`$0 --help' for more information." # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1414,7 +1309,7 @@ Try \`$0 --help' for more information." $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac @@ -1422,13 +1317,13 @@ done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error "missing argument to $ac_option" + as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; - fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1451,7 +1346,7 @@ do [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac - as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -1465,8 +1360,8 @@ target=$target_alias if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1481,9 +1376,9 @@ test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error "working directory cannot be determined" + as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error "pwd does not report name of working directory" + as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. @@ -1522,11 +1417,11 @@ else fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then @@ -1552,7 +1447,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.4p4 to adapt to many kinds of systems. +\`configure' configures sudo 1.8.5p2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1566,7 +1461,7 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages + -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files @@ -1617,7 +1512,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sudo 1.7.4p4:";; + short | recursive ) echo "Configuration of sudo 1.8.5p2:";; esac cat <<\_ACEOF @@ -1638,8 +1533,12 @@ Optional Features: Set $HOME to target user in shell mode --disable-path-info Print 'command not allowed' not 'command not found' --enable-env-debug Whether to enable environment debugging. + --enable-zlib[=PATH] Whether to enable or disable zlib + --enable-env-reset Whether to enable environment resetting by default. --enable-warnings Whether to enable compiler warnings + --enable-werror Whether to enable the -Werror compiler option --enable-admin-flag Whether to create a Ubuntu-style admin flag file + --disable-nls Disable natural language support using gettext --enable-gss-krb5-ccache-name Use GSS-API to set the Kerberos V cred cache name --enable-shared[=PKGS] build shared libraries [default=yes] @@ -1648,8 +1547,10 @@ 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 + --enable-kerb5-instance instance string to append to the username (separated + by a slash) Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1673,7 +1574,6 @@ Optional Packages: --with-long-otp-prompt use a two line OTP (skey/opie) prompt --with-SecurID[=DIR] enable SecurID support --with-fwtk[=DIR] enable FWTK AuthSRV support - --with-kerb4[=DIR] enable Kerberos IV support --with-kerb5[=DIR] enable Kerberos V support --with-aixauth enable AIX general authentication support --with-pam enable PAM support @@ -1709,6 +1609,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) @@ -1735,14 +1637,13 @@ Optional Packages: --without-interfaces don't try to read the ip addr of ether interfaces --with-stow properly handle GNU stow packaging --with-askpass=PATH Fully qualified pathname of askpass helper - --with-libvas=NAME Name of the libvas shared library - (default=libvas.so) - --with-libvas-rpath=PATH - Path to look for libvas in [default=/opt/quest/lib] + --with-plugindir set directory to load plugins from --with-selinux enable SELinux support - --with-pic try to use only PIC/non-PIC objects [default=use + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). --with-noexec=PATH fully qualified pathname of sudo_noexec.so --with-netsvc[=PATH] path to netsvc.conf --with-pam-login enable specific PAM session for sudo -i @@ -1756,8 +1657,9 @@ Some influential environment variables: CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor - YACC The `Yet Another C Compiler' implementation to use. Defaults to - the first program found out of: `bison -y', `byacc', `yacc'. + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. @@ -1828,10 +1730,10 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sudo configure 1.7.4p4 -generated by GNU Autoconf 2.65 +sudo configure 1.8.5p2 +generated by GNU Autoconf 2.68 -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1875,7 +1777,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile @@ -1921,7 +1823,7 @@ fi # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link @@ -1947,7 +1849,7 @@ $as_echo "$ac_try_echo"; } >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } >/dev/null && { + test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : @@ -1958,7 +1860,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp @@ -1972,7 +1874,7 @@ ac_fn_c_check_header_compile () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1990,7 +1892,7 @@ fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -2031,7 +1933,7 @@ sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run @@ -2044,7 +1946,7 @@ ac_fn_c_check_func () as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2099,10 +2001,64 @@ fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +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 +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using @@ -2111,10 +2067,10 @@ $as_echo "$ac_res" >&6; } ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -2150,7 +2106,7 @@ if ac_fn_c_try_cpp "$LINENO"; then : else ac_header_preproc=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } @@ -2173,17 +2129,15 @@ $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( cat <<\_ASBOX -## --------------------------------------- ## +( $as_echo "## --------------------------------------- ## ## Report this to http://www.sudo.ws/bugs/ ## -## --------------------------------------- ## -_ASBOX +## --------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -2192,63 +2146,66 @@ eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () +# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES +# ---------------------------------------------------- +# Tries to find if the field MEMBER exists in type AGGR, after including +# INCLUDES, setting cache variable VAR accordingly. +ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 +$as_echo_n "checking for $2.$3... " >&6; } +if eval \${$4+:} false; then : $as_echo_n "(cached) " >&6 else - eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -$4 +$5 int main () { -if (sizeof ($2)) - return 0; +static $2 ac_aggr; +if (ac_aggr.$3) +return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : + eval "$4=yes" +else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -$4 +$5 int main () { -if (sizeof (($2))) - return 0; +static $2 ac_aggr; +if (sizeof ac_aggr.$3) +return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : - + eval "$4=yes" else - eval "$3=yes" + eval "$4=no" 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 -eval ac_res=\$$3 +eval ac_res=\$$4 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno -} # ac_fn_c_check_type +} # ac_fn_c_check_member # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- @@ -2423,77 +2380,23 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ rm -f conftest.val fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_compute_int -# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES -# ---------------------------------------------------- -# Tries to find if the field MEMBER exists in type AGGR, after including -# INCLUDES, setting cache variable VAR accordingly. -ac_fn_c_check_member () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 -$as_echo_n "checking for $2.$3... " >&6; } -if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$5 -int -main () -{ -static $2 ac_aggr; -if (sizeof ac_aggr.$3) -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$4=yes" -else - eval "$4=no" -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 -eval ac_res=\$$4 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - -} # ac_fn_c_check_member - -# ac_fn_c_check_decl LINENO SYMBOL VAR -# ------------------------------------ -# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 -$as_echo_n "checking whether $2 is declared... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2502,8 +2405,12 @@ $4 int main () { -#ifndef $2 - (void) $2; +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif #endif ; @@ -2520,15 +2427,15 @@ fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_decl 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.4p4, which was -generated by GNU Autoconf 2.65. Invocation command line was +It was created by sudo $as_me 1.8.5p2, which was +generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2638,11 +2545,9 @@ trap 'exit_status=$? { echo - cat <<\_ASBOX -## ---------------- ## + $as_echo "## ---------------- ## ## Cache variables. ## -## ---------------- ## -_ASBOX +## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( @@ -2676,11 +2581,9 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - cat <<\_ASBOX -## ----------------- ## + $as_echo "## ----------------- ## ## Output variables. ## -## ----------------- ## -_ASBOX +## ----------------- ##" echo for ac_var in $ac_subst_vars do @@ -2693,11 +2596,9 @@ _ASBOX echo if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## + $as_echo "## ------------------- ## ## File substitutions. ## -## ------------------- ## -_ASBOX +## ------------------- ##" echo for ac_var in $ac_subst_files do @@ -2711,11 +2612,9 @@ _ASBOX fi if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## + $as_echo "## ----------- ## ## confdefs.h. ## -## ----------- ## -_ASBOX +## ----------- ##" echo cat confdefs.h echo @@ -2770,7 +2669,12 @@ _ACEOF ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -2785,7 +2689,11 @@ do { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } fi done @@ -2861,7 +2769,7 @@ if $ac_cache_corrupted; then $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -2935,6 +2843,21 @@ $as_echo "$as_me: Configuring Sudo version $PACKAGE_VERSION" >&6;} + + + + + + + + + + + + + + + @@ -2954,10 +2877,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 +2900,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 @@ -2992,33 +2918,41 @@ secure_path="not set" # INSTALL_NOEXEC= devdir='$(srcdir)' -PROGS="sudo visudo" +PROGS="sudo" : ${MANTYPE='man'} : ${mansrcdir='.'} : ${SUDOERS_MODE='0440'} : ${SUDOERS_UID='0'} : ${SUDOERS_GID='0'} -DEV="#" +DEVEL= LDAP="#" -REPLAY="#" BAMAN=0 LCMAN=0 SEMAN=0 +LIBINTL= ZLIB= +ZLIB_SRC= AUTH_OBJS= AUTH_REG= AUTH_EXCL= AUTH_EXCL_DEF= AUTH_DEF=passwd +SUDO_NLS=disabled CHECKSHADOW=true shadow_defs= shadow_funcs= shadow_libs= shadow_libs_optional= - CONFIGURE_ARGS="$@" +RTLD_PRELOAD_VAR="LD_PRELOAD" +RTLD_PRELOAD_ENABLE_VAR= +RTLD_PRELOAD_DELIM=":" +RTLD_PRELOAD_DEFAULT= + + + # Check whether --with-otp-only was given. @@ -3051,9 +2985,8 @@ if test "${with_devel+set}" = set; then : withval=$with_devel; case $with_devel in yes) { $as_echo "$as_me:${as_lineno-$LINENO}: Setting up for development: -Wall, flex, yacc" >&5 $as_echo "$as_me: Setting up for development: -Wall, flex, yacc" >&6;} - PROGS="${PROGS} testsudoers" OSDEFS="${OSDEFS} -DSUDO_DEVEL" - DEV="" + DEVEL="true" devdir=. ;; no) ;; @@ -3063,19 +2996,12 @@ $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. if test "${with_CC+set}" = set; then : withval=$with_CC; case $with_CC in - yes) as_fn_error "\"must give --with-CC an argument.\"" "$LINENO" 5 - ;; - no) as_fn_error "\"illegal argument: --without-CC.\"" "$LINENO" 5 - ;; - *) CC=$with_CC + *) as_fn_error $? "the --with-CC option is no longer supported, please set the CC environment variable instead." "$LINENO" 5 ;; esac fi @@ -3086,7 +3012,7 @@ fi if test "${with_rpath+set}" = set; then : withval=$with_rpath; case $with_rpath in yes|no) ;; - *) as_fn_error "\"--with-rpath does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-rpath does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -3110,11 +3036,11 @@ if test "${with_bsm_audit+set}" = set; then : withval=$with_bsm_audit; case $with_bsm_audit in yes) $as_echo "#define HAVE_BSM_AUDIT 1" >>confdefs.h - SUDO_LIBS="${SUDO_LIBS} -lbsm" - SUDO_OBJS="${SUDO_OBJS} bsm_audit.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lbsm" + SUDOERS_OBJS="${SUDOERS_OBJS} bsm_audit.lo" ;; no) ;; - *) as_fn_error "\"--with-bsm-audit does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-bsm-audit does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -3130,7 +3056,7 @@ if test -n "$ac_tool_prefix"; then set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3170,7 +3096,7 @@ if test -z "$ac_cv_prog_CC"; then set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3223,7 +3149,7 @@ if test -z "$CC"; then set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3263,7 +3189,7 @@ if test -z "$CC"; then set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3322,7 +3248,7 @@ if test -z "$CC"; then set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : +if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then @@ -3366,7 +3292,7 @@ do set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : +if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then @@ -3420,8 +3346,8 @@ fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "no acceptable C compiler found in \$PATH -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3535,9 +3461,8 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "C compiler cannot create executables -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -3579,8 +3504,8 @@ done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3637,9 +3562,9 @@ $as_echo "$ac_try_echo"; } >&5 else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot run C compiled programs. +as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details." "$LINENO" 5; } +See \`config.log' for more details" "$LINENO" 5; } fi fi fi @@ -3650,7 +3575,7 @@ rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : +if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3690,8 +3615,8 @@ sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of object files: cannot compile -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -3701,7 +3626,7 @@ OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : +if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3738,7 +3663,7 @@ ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : +if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag @@ -3816,7 +3741,7 @@ else fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : +if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no @@ -3916,8 +3841,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 @@ -3933,17 +3857,18 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "#define HAVE_LINUX_AUDIT 1" >>confdefs.h SUDO_LIBS="${SUDO_LIBS} -laudit" - SUDO_OBJS="${SUDO_OBJS} linux_audit.o" + SUDOERS_LIBS="${SUDO_LIBS} -laudit" + SUDOERS_OBJS="${SUDOERS_OBJS} linux_audit.lo" else - as_fn_error "unable to find AUDIT_USER_CMD in libaudit.h for --with-linux-audit" "$LINENO" 5 + as_fn_error $? "unable to find AUDIT_USER_CMD in libaudit.h for --with-linux-audit" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ;; no) ;; - *) as_fn_error "\"--with-linux-audit does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-linux-audit does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -3953,9 +3878,9 @@ fi # Check whether --with-incpath was given. if test "${with_incpath+set}" = set; then : withval=$with_incpath; case $with_incpath in - yes) as_fn_error "\"must give --with-incpath an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-incpath an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-incpath not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-incpath not supported.\"" "$LINENO" 5 ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: Adding ${with_incpath} to CPPFLAGS" >&5 $as_echo "$as_me: Adding ${with_incpath} to CPPFLAGS" >&6;} @@ -3971,9 +3896,9 @@ fi # Check whether --with-libpath was given. if test "${with_libpath+set}" = set; then : withval=$with_libpath; case $with_libpath in - yes) as_fn_error "\"must give --with-libpath an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-libpath an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-libpath not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-libpath not supported.\"" "$LINENO" 5 ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: Adding ${with_libpath} to LDFLAGS" >&5 $as_echo "$as_me: Adding ${with_libpath} to LDFLAGS" >&6;} @@ -3986,9 +3911,9 @@ fi # Check whether --with-libraries was given. if test "${with_libraries+set}" = set; then : withval=$with_libraries; case $with_libraries in - yes) as_fn_error "\"must give --with-libraries an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-libraries an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-libraries not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-libraries not supported.\"" "$LINENO" 5 ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: Adding ${with_libraries} to LIBS" >&5 $as_echo "$as_me: Adding ${with_libraries} to LIBS" >&6;} @@ -4050,7 +3975,7 @@ $as_echo "$with_passwd" >&6; } AUTH_DEF="" test "$with_passwd" = "yes" && AUTH_REG="$AUTH_REG passwd" ;; - *) as_fn_error "\"Sorry, --with-passwd does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"Sorry, --with-passwd does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4060,8 +3985,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 +4002,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 @@ -4106,7 +4029,7 @@ $as_echo "yes" >&6; } ;; no) long_otp_prompt=off ;; - *) as_fn_error "\"--with-long-otp-prompt does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-long-otp-prompt does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4116,7 +4039,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 +4056,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 @@ -4147,25 +4070,10 @@ fi -# Check whether --with-kerb4 was given. -if test "${with_kerb4+set}" = set; then : - withval=$with_kerb4; case $with_kerb4 in - no) with_kerb4="";; - *) { $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 -$as_echo "yes" >&6; } - AUTH_REG="$AUTH_REG kerb4" - ;; -esac -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 @@ -4182,7 +4090,7 @@ if test "${with_aixauth+set}" = set; then : withval=$with_aixauth; case $with_aixauth in yes) AUTH_EXCL="$AUTH_EXCL AIX_AUTH";; no) ;; - *) as_fn_error "\"--with-aixauth does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-aixauth does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4194,7 +4102,7 @@ if test "${with_pam+set}" = set; then : withval=$with_pam; case $with_pam in yes) AUTH_EXCL="$AUTH_EXCL PAM";; no) ;; - *) as_fn_error "\"--with-pam does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-pam does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4213,7 +4121,7 @@ $as_echo "yes" >&6; } AUTH_REG="$AUTH_REG AFS" ;; no) ;; - *) as_fn_error "\"--with-AFS does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-AFS does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4232,7 +4140,7 @@ $as_echo "yes" >&6; } AUTH_REG="$AUTH_REG DCE" ;; no) ;; - *) as_fn_error "\"--with-DCE does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-DCE does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4243,7 +4151,7 @@ fi if test "${with_logincap+set}" = set; then : withval=$with_logincap; case $with_logincap in yes|no) ;; - *) as_fn_error "\"--with-logincap does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-logincap does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4255,7 +4163,7 @@ if test "${with_bsdauth+set}" = set; then : withval=$with_bsdauth; case $with_bsdauth in yes) AUTH_EXCL="$AUTH_EXCL BSD_AUTH";; no) ;; - *) as_fn_error "\"--with-bsdauth does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-bsdauth does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4267,7 +4175,7 @@ if test "${with_project+set}" = set; then : withval=$with_project; case $with_project in yes|no) ;; no) ;; - *) as_fn_error "\"--with-project does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-project does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4283,7 +4191,7 @@ if test "${with_lecture+set}" = set; then : ;; no|none|never) lecture=never ;; - *) as_fn_error "\"unknown argument to --with-lecture: $with_lecture\"" "$LINENO" 5 + *) as_fn_error $? "\"unknown argument to --with-lecture: $with_lecture\"" "$LINENO" 5 ;; esac fi @@ -4304,9 +4212,9 @@ $as_echo_n "checking whether sudo should log via syslog or to a file by default. # Check whether --with-logging was given. if test "${with_logging+set}" = set; then : withval=$with_logging; case $with_logging in - yes) as_fn_error "\"must give --with-logging an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-logging an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-logging not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-logging not supported.\"" "$LINENO" 5 ;; syslog) $as_echo "#define LOGGING SLOG_SYSLOG" >>confdefs.h @@ -4323,7 +4231,7 @@ $as_echo "file" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: both" >&5 $as_echo "both" >&6; } ;; - *) as_fn_error "\"unknown argument to --with-logging: $with_logging\"" "$LINENO" 5 + *) as_fn_error $? "\"unknown argument to --with-logging: $with_logging\"" "$LINENO" 5 ;; esac else @@ -4337,13 +4245,13 @@ fi # Check whether --with-logfac was given. if test "${with_logfac+set}" = set; then : withval=$with_logfac; case $with_logfac in - yes) as_fn_error "\"must give --with-logfac an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-logfac an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-logfac not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-logfac not supported.\"" "$LINENO" 5 ;; authpriv|auth|daemon|user|local0|local1|local2|local3|local4|local5|local6|local7) logfac=$with_logfac ;; - *) as_fn_error "\"$with_logfac is not a supported syslog facility.\"" "$LINENO" 5 + *) as_fn_error $? "\"$with_logfac is not a supported syslog facility.\"" "$LINENO" 5 ;; esac fi @@ -4355,14 +4263,14 @@ $as_echo_n "checking at which syslog priority to log commands... " >&6; } # Check whether --with-goodpri was given. if test "${with_goodpri+set}" = set; then : withval=$with_goodpri; case $with_goodpri in - yes) as_fn_error "\"must give --with-goodpri an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-goodpri an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-goodpri not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-goodpri not supported.\"" "$LINENO" 5 ;; alert|crit|debug|emerg|err|info|notice|warning) goodpri=$with_goodpri ;; - *) as_fn_error "\"$with_goodpri is not a supported syslog priority.\"" "$LINENO" 5 + *) as_fn_error $? "\"$with_goodpri is not a supported syslog priority.\"" "$LINENO" 5 ;; esac fi @@ -4381,14 +4289,14 @@ $as_echo_n "checking at which syslog priority to log failures... " >&6; } # Check whether --with-badpri was given. if test "${with_badpri+set}" = set; then : withval=$with_badpri; case $with_badpri in - yes) as_fn_error "\"must give --with-badpri an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-badpri an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-badpri not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-badpri not supported.\"" "$LINENO" 5 ;; alert|crit|debug|emerg|err|info|notice|warning) badpri=$with_badpri ;; - *) as_fn_error "$with_badpri is not a supported syslog priority." "$LINENO" 5 + *) as_fn_error $? "$with_badpri is not a supported syslog priority." "$LINENO" 5 ;; esac fi @@ -4405,9 +4313,9 @@ $as_echo "$badpri" >&6; } # Check whether --with-logpath was given. if test "${with_logpath+set}" = set; then : withval=$with_logpath; case $with_logpath in - yes) as_fn_error "\"must give --with-logpath an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-logpath an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-logpath not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-logpath not supported.\"" "$LINENO" 5 ;; esac fi @@ -4419,13 +4327,13 @@ $as_echo_n "checking how long a line in the log file should be... " >&6; } # Check whether --with-loglen was given. if test "${with_loglen+set}" = set; then : withval=$with_loglen; case $with_loglen in - yes) as_fn_error "\"must give --with-loglen an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-loglen an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-loglen not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-loglen not supported.\"" "$LINENO" 5 ;; [0-9]*) loglen=$with_loglen ;; - *) as_fn_error "\"you must enter a number, not $with_loglen\"" "$LINENO" 5 + *) as_fn_error $? "\"you must enter a number, not $with_loglen\"" "$LINENO" 5 ;; esac fi @@ -4448,7 +4356,7 @@ if test "${with_ignore_dot+set}" = set; then : ;; no) ignore_dot=off ;; - *) as_fn_error "\"--with-ignore-dot does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-ignore-dot does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4473,7 +4381,7 @@ if test "${with_mail_if_no_user+set}" = set; then : ;; no) mail_no_user=off ;; - *) as_fn_error "\"--with-mail-if-no-user does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-mail-if-no-user does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4498,7 +4406,7 @@ if test "${with_mail_if_no_host+set}" = set; then : ;; no) mail_no_host=off ;; - *) as_fn_error "\"--with-mail-if-no-host does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-mail-if-no-host does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4523,7 +4431,7 @@ if test "${with_mail_if_noperms+set}" = set; then : ;; no) mail_noperms=off ;; - *) as_fn_error "\"--with-mail-if-noperms does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-mail-if-noperms does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4544,9 +4452,9 @@ $as_echo_n "checking who should get the mail that sudo sends... " >&6; } # Check whether --with-mailto was given. if test "${with_mailto+set}" = set; then : withval=$with_mailto; case $with_mailto in - yes) as_fn_error "\"must give --with-mailto an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-mailto an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-mailto not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-mailto not supported.\"" "$LINENO" 5 ;; *) mailto=$with_mailto ;; @@ -4565,7 +4473,7 @@ $as_echo "$mailto" >&6; } # Check whether --with-mailsubject was given. if test "${with_mailsubject+set}" = set; then : withval=$with_mailsubject; case $with_mailsubject in - yes) as_fn_error "\"must give --with-mailsubject an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-mailsubject an argument.\"" "$LINENO" 5 ;; no) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, --without-mailsubject not supported." >&5 $as_echo "$as_me: WARNING: Sorry, --without-mailsubject not supported." >&2;} @@ -4591,7 +4499,7 @@ $as_echo_n "checking for bad password prompt... " >&6; } # Check whether --with-passprompt was given. if test "${with_passprompt+set}" = set; then : withval=$with_passprompt; case $with_passprompt in - yes) as_fn_error "\"must give --with-passprompt an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-passprompt an argument.\"" "$LINENO" 5 ;; no) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, --without-passprompt not supported." >&5 $as_echo "$as_me: WARNING: Sorry, --without-passprompt not supported." >&2;} @@ -4614,7 +4522,7 @@ $as_echo_n "checking for bad password message... " >&6; } # Check whether --with-badpass-message was given. if test "${with_badpass_message+set}" = set; then : withval=$with_badpass_message; case $with_badpass_message in - yes) as_fn_error "\"Must give --with-badpass-message an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"Must give --with-badpass-message an argument.\"" "$LINENO" 5 ;; no) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Sorry, --without-badpass-message not supported." >&5 $as_echo "$as_me: WARNING: Sorry, --without-badpass-message not supported." >&2;} @@ -4642,7 +4550,7 @@ if test "${with_fqdn+set}" = set; then : ;; no) fqdn=off ;; - *) as_fn_error "\"--with-fqdn does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-fqdn does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4661,9 +4569,9 @@ fi # Check whether --with-timedir was given. if test "${with_timedir+set}" = set; then : withval=$with_timedir; case $with_timedir in - yes) as_fn_error "\"must give --with-timedir an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-timedir an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-timedir not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-timedir not supported.\"" "$LINENO" 5 ;; esac fi @@ -4673,8 +4581,9 @@ fi # Check whether --with-iologdir was given. if test "${with_iologdir+set}" = set; then : withval=$with_iologdir; case $with_iologdir in - yes) ;; - no) ;; + yes) ;; + no) as_fn_error $? "\"--without-iologdir not supported.\"" "$LINENO" 5 + ;; esac fi @@ -4699,15 +4608,15 @@ fi # Check whether --with-sudoers-mode was given. if test "${with_sudoers_mode+set}" = set; then : withval=$with_sudoers_mode; case $with_sudoers_mode in - yes) as_fn_error "\"must give --with-sudoers-mode an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-sudoers-mode an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-sudoers-mode not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-sudoers-mode not supported.\"" "$LINENO" 5 ;; [1-9]*) SUDOERS_MODE=0${with_sudoers_mode} ;; 0*) SUDOERS_MODE=$with_sudoers_mode ;; - *) as_fn_error "\"you must use an octal mode, not a name.\"" "$LINENO" 5 + *) as_fn_error $? "\"you must use an octal mode, not a name.\"" "$LINENO" 5 ;; esac fi @@ -4717,13 +4626,13 @@ fi # Check whether --with-sudoers-uid was given. if test "${with_sudoers_uid+set}" = set; then : withval=$with_sudoers_uid; case $with_sudoers_uid in - yes) as_fn_error "\"must give --with-sudoers-uid an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-sudoers-uid an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-sudoers-uid not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-sudoers-uid not supported.\"" "$LINENO" 5 ;; [0-9]*) SUDOERS_UID=$with_sudoers_uid ;; - *) as_fn_error "\"you must use an unsigned numeric uid, not a name.\"" "$LINENO" 5 + *) as_fn_error $? "\"you must use an unsigned numeric uid, not a name.\"" "$LINENO" 5 ;; esac fi @@ -4733,13 +4642,13 @@ fi # Check whether --with-sudoers-gid was given. if test "${with_sudoers_gid+set}" = set; then : withval=$with_sudoers_gid; case $with_sudoers_gid in - yes) as_fn_error "\"must give --with-sudoers-gid an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-sudoers-gid an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-sudoers-gid not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-sudoers-gid not supported.\"" "$LINENO" 5 ;; [0-9]*) SUDOERS_GID=$with_sudoers_gid ;; - *) as_fn_error "\"you must use an unsigned numeric gid, not a name.\"" "$LINENO" 5 + *) as_fn_error $? "\"you must use an unsigned numeric gid, not a name.\"" "$LINENO" 5 ;; esac fi @@ -4751,13 +4660,13 @@ $as_echo_n "checking for umask programs should be run with... " >&6; } # Check whether --with-umask was given. if test "${with_umask+set}" = set; then : withval=$with_umask; case $with_umask in - yes) as_fn_error "\"must give --with-umask an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-umask an argument.\"" "$LINENO" 5 ;; no) sudo_umask=0777 ;; [0-9]*) sudo_umask=$with_umask ;; - *) as_fn_error "\"you must enter a numeric mask.\"" "$LINENO" 5 + *) as_fn_error $? "\"you must enter a numeric mask.\"" "$LINENO" 5 ;; esac fi @@ -4775,15 +4684,31 @@ 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; } # Check whether --with-runas-default was given. if test "${with_runas_default+set}" = set; then : withval=$with_runas_default; case $with_runas_default in - yes) as_fn_error "\"must give --with-runas-default an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-runas-default an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-runas-default not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-runas-default not supported.\"" "$LINENO" 5 ;; *) runas_default="$with_runas_default" ;; @@ -4802,9 +4727,9 @@ $as_echo "$runas_default" >&6; } # Check whether --with-exempt was given. if test "${with_exempt+set}" = set; then : withval=$with_exempt; case $with_exempt in - yes) as_fn_error "\"must give --with-exempt an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-exempt an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-exempt not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-exempt not supported.\"" "$LINENO" 5 ;; *) cat >>confdefs.h <<_ACEOF @@ -4826,9 +4751,9 @@ $as_echo_n "checking for editor that visudo should use... " >&6; } # Check whether --with-editor was given. if test "${with_editor+set}" = set; then : withval=$with_editor; case $with_editor in - yes) as_fn_error "\"must give --with-editor an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"must give --with-editor an argument.\"" "$LINENO" 5 ;; - no) as_fn_error "\"--without-editor not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-editor not supported.\"" "$LINENO" 5 ;; *) cat >>confdefs.h <<_ACEOF @@ -4857,7 +4782,7 @@ if test "${with_env_editor+set}" = set; then : ;; no) env_editor=off ;; - *) as_fn_error "\"--with-env-editor does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-env-editor does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4879,11 +4804,11 @@ $as_echo_n "checking number of tries a user gets to enter their password... " >& if test "${with_passwd_tries+set}" = set; then : withval=$with_passwd_tries; case $with_passwd_tries in yes) ;; - no) as_fn_error "\"--without-editor not supported.\"" "$LINENO" 5 + no) as_fn_error $? "\"--without-editor not supported.\"" "$LINENO" 5 ;; [1-9]*) passwd_tries=$with_passwd_tries ;; - *) as_fn_error "\"you must enter the numer of tries, > 0\"" "$LINENO" 5 + *) as_fn_error $? "\"you must enter the numer of tries, > 0\"" "$LINENO" 5 ;; esac fi @@ -4907,7 +4832,7 @@ if test "${with_timeout+set}" = set; then : ;; [0-9]*) timeout=$with_timeout ;; - *) as_fn_error "\"you must enter the numer of minutes.\"" "$LINENO" 5 + *) as_fn_error $? "\"you must enter the numer of minutes.\"" "$LINENO" 5 ;; esac fi @@ -4931,7 +4856,7 @@ if test "${with_password_timeout+set}" = set; then : ;; [0-9]*) password_timeout=$with_password_timeout ;; - *) as_fn_error "\"you must enter the numer of minutes.\"" "$LINENO" 5 + *) as_fn_error $? "\"you must enter the numer of minutes.\"" "$LINENO" 5 ;; esac fi @@ -4954,7 +4879,7 @@ if test "${with_tty_tickets+set}" = set; then : ;; no) tty_tickets=off ;; - *) as_fn_error "\"--with-tty-tickets does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-tty-tickets does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -4985,7 +4910,7 @@ if test "${with_insults+set}" = set; then : ;; no) insults=off ;; - *) as_fn_error "\"--with-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5010,7 +4935,7 @@ if test "${with_all_insults+set}" = set; then : with_goons_insults=yes ;; no) ;; - *) as_fn_error "\"--with-all-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-all-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5024,7 +4949,7 @@ if test "${with_classic_insults+set}" = set; then : ;; no) ;; - *) as_fn_error "\"--with-classic-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-classic-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5038,7 +4963,7 @@ if test "${with_csops_insults+set}" = set; then : ;; no) ;; - *) as_fn_error "\"--with-csops-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-csops-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5052,7 +4977,7 @@ if test "${with_hal_insults+set}" = set; then : ;; no) ;; - *) as_fn_error "\"--with-hal-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-hal-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5066,7 +4991,7 @@ if test "${with_goons_insults+set}" = set; then : ;; no) ;; - *) as_fn_error "\"--with-goons-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-goons-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5132,7 +5057,7 @@ if test "${with_pc_insults+set}" = set; then : ;; no) ;; - *) as_fn_error "\"--with-pc-insults does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-pc-insults does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5197,7 +5122,7 @@ $as_echo "yes" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; - *) as_fn_error "\"--with-interfaces does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-interfaces does not take an argument.\"" "$LINENO" 5 ;; esac else @@ -5220,7 +5145,7 @@ $as_echo "yes" >&6; } no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; - *) as_fn_error "\"--with-stow does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-stow does not take an argument.\"" "$LINENO" 5 ;; esac else @@ -5235,7 +5160,7 @@ $as_echo_n "checking whether to use an askpass helper... " >&6; } # Check whether --with-askpass was given. if test "${with_askpass+set}" = set; then : withval=$with_askpass; case $with_askpass in - yes) as_fn_error "\"--with-askpass takes a path as an argument.\"" "$LINENO" 5 + yes) as_fn_error $? "\"--with-askpass takes a path as an argument.\"" "$LINENO" 5 ;; no) ;; *) cat >>confdefs.h <>confdefs.h <<_ACEOF -#define LIBVAS_SO "$with_libvas" -_ACEOF - +# Check whether --with-plugindir was given. +if test "${with_plugindir+set}" = set; then : + withval=$with_plugindir; case $with_plugindir in + no) as_fn_error $? "\"illegal argument: --without-plugindir.\"" "$LINENO" 5 ;; + *) ;; esac -if test X"$with_libvas" != X"no"; then - -cat >>confdefs.h <<_ACEOF -#define LIBVAS_SO "$with_libvas" -_ACEOF - - $as_echo "#define USING_NONUNIX_GROUPS 1" >>confdefs.h - - COMMON_OBJS="$COMMON_OBJS vasgroups.o" - -# Check whether --with-libvas-rpath was given. -if test "${with_libvas_rpath+set}" = set; then : - withval=$with_libvas_rpath; LIBVAS_RPATH=$withval -else - LIBVAS_RPATH=/opt/quest/lib -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5 -$as_echo_n "checking for main in -ldl... " >&6; } -if test "${ac_cv_lib_dl_main+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - - -int -main () -{ -return main (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_main=yes else - ac_cv_lib_dl_main=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5 -$as_echo "$ac_cv_lib_dl_main" >&6; } -if test "x$ac_cv_lib_dl_main" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBDL 1 -_ACEOF - - LIBS="-ldl $LIBS" - -fi - -fi - + with_plugindir="$libexecdir" fi @@ -5439,7 +5302,7 @@ $as_echo "yes" >&6; } $as_echo "no" >&6; } root_sudo=off ;; - *) as_fn_error "\"--enable-root-sudo does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--enable-root-sudo does not take an argument.\"" "$LINENO" 5 ;; esac @@ -5580,13 +5443,47 @@ $as_echo "no" >&6; } fi +# Check whether --enable-zlib was given. +if test "${enable_zlib+set}" = set; then : + enableval=$enable_zlib; +else + enable_zlib=yes +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 1" >>confdefs.h + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + $as_echo "#define ENV_RESET 0" >>confdefs.h + +fi + # Check whether --enable-warnings was given. if test "${enable_warnings+set}" = set; then : enableval=$enable_warnings; case "$enableval" in - yes) if test X"$with_devel" != X"yes" -a -n "$GCC"; then - CFLAGS="${CFLAGS} -Wall" - fi - ;; + yes) ;; no) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unknown argument to --enable-warnings: $enableval" >&5 $as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-warnings: $enableval" >&2;} @@ -5596,6 +5493,19 @@ $as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-warnings: $enab fi +# Check whether --enable-werror was given. +if test "${enable_werror+set}" = set; then : + enableval=$enable_werror; case "$enableval" in + yes) ;; + no) ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unknown argument to --enable-werror: $enableval" >&5 +$as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-werror: $enableval" >&2;} + ;; + esac + +fi + + # Check whether --enable-admin-flag was given. if test "${enable_admin_flag+set}" = set; then : enableval=$enable_admin_flag; case "$enableval" in @@ -5611,6 +5521,14 @@ $as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-admin-flag: $en fi +# Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; +else + enable_nls=yes +fi + + # Check whether --with-selinux was given. if test "${with_selinux+set}" = set; then : @@ -5624,7 +5542,7 @@ if test "${with_selinux+set}" = set; then : SEMAN=1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setkeycreatecon in -lselinux" >&5 $as_echo_n "checking for setkeycreatecon in -lselinux... " >&6; } -if test "${ac_cv_lib_selinux_setkeycreatecon+set}" = set; then : +if ${ac_cv_lib_selinux_setkeycreatecon+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -5658,14 +5576,14 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_setkeycreatecon" >&5 $as_echo "$ac_cv_lib_selinux_setkeycreatecon" >&6; } -if test "x$ac_cv_lib_selinux_setkeycreatecon" = x""yes; then : +if test "x$ac_cv_lib_selinux_setkeycreatecon" = xyes; then : $as_echo "#define HAVE_SETKEYCREATECON 1" >>confdefs.h fi ;; no) ;; - *) as_fn_error "\"--with-selinux does not take an argument.\"" "$LINENO" 5 + *) as_fn_error $? "\"--with-selinux does not take an argument.\"" "$LINENO" 5 ;; esac fi @@ -5681,7 +5599,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 $as_echo_n "checking for library containing strerror... " >&6; } -if test "${ac_cv_search_strerror+set}" = set; then : +if ${ac_cv_search_strerror+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -5715,11 +5633,11 @@ for ac_lib in '' cposix; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_strerror+set}" = set; then : + if ${ac_cv_search_strerror+:} false; then : break fi done -if test "${ac_cv_search_strerror+set}" = set; then : +if ${ac_cv_search_strerror+:} false; then : else ac_cv_search_strerror=no @@ -5747,7 +5665,7 @@ if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : + if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded @@ -5777,7 +5695,7 @@ else # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -5793,11 +5711,11 @@ else ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi @@ -5836,7 +5754,7 @@ else # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -5852,18 +5770,18 @@ else ac_preproc_ok=: break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext +rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." "$LINENO" 5; } +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c @@ -5877,7 +5795,7 @@ if test -n "$ac_tool_prefix"; then set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : +if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then @@ -5917,7 +5835,7 @@ if test -z "$ac_cv_prog_AR"; then set dummy ar; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : +if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then @@ -5969,7 +5887,7 @@ if test -n "$ac_tool_prefix"; then set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : +if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -6009,7 +5927,7 @@ if test -z "$ac_cv_prog_RANLIB"; then set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -6056,19 +5974,38 @@ 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 + +if test "x$ac_cv_prog_cc_c89" = "xno"; then + as_fn_error $? "Sudo version $PACKAGE_VERSION requires an ANSI C compiler to build." "$LINENO" 5 +fi + +if test "$enable_static" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring --disable-static, sudo does not install static libs" >&5 +$as_echo "$as_me: WARNING: Ignoring --disable-static, sudo does not install static libs" >&2;} + enable_static=yes +fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - for ac_t in install-sh install.sh shtool; do - if test -f "$ac_dir/$ac_t"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/$ac_t -c" - break 2 - fi - done + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi done if test -z "$ac_aux_dir"; then - as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, @@ -6082,27 +6019,27 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } -if test "${ac_cv_build+set}" = set; then : +if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && - as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; -*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' @@ -6120,14 +6057,14 @@ case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then : +if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi @@ -6135,7 +6072,7 @@ fi $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; -*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' @@ -6161,8 +6098,8 @@ esac -macro_version='2.2.6b' -macro_revision='1.3017' +macro_version='2.4.2' +macro_revision='1.3337' @@ -6178,9 +6115,78 @@ macro_revision='1.3017' ltmain="$ac_aux_dir/ltmain.sh" +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } -if test "${ac_cv_path_SED+set}" = set; then : +if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ @@ -6235,7 +6241,7 @@ esac done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then - as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5 + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED @@ -6262,7 +6268,7 @@ Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : +if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then @@ -6311,7 +6317,7 @@ esac done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then - as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP @@ -6325,7 +6331,7 @@ $as_echo "$ac_cv_path_GREP" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : +if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 @@ -6377,7 +6383,7 @@ esac done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then - as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP @@ -6392,7 +6398,7 @@ $as_echo "$ac_cv_path_EGREP" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } -if test "${ac_cv_path_FGREP+set}" = set; then : +if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 @@ -6444,7 +6450,7 @@ esac done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then - as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP @@ -6523,7 +6529,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi -if test "${lt_cv_path_LD+set}" = set; then : +if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then @@ -6560,10 +6566,10 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi -test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if test "${lt_cv_prog_gnu_ld+set}" = set; then : +if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. @@ -6590,7 +6596,7 @@ with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test "${lt_cv_path_NM+set}" = set; then : +if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then @@ -6643,14 +6649,17 @@ if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$ac_tool_prefix"; then - for ac_prog in "dumpbin -symbols" "link -dump -symbols" + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DUMPBIN+set}" = set; then : +if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then @@ -6688,13 +6697,13 @@ fi fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in "dumpbin -symbols" "link -dump -symbols" + for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then @@ -6743,6 +6752,15 @@ esac fi fi + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" @@ -6757,18 +6775,18 @@ test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } -if test "${lt_cv_nm_interface+set}" = set; then : +if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 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:$LINENO: $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:$LINENO: $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:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -6792,7 +6810,7 @@ fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } -if test "${lt_cv_sys_max_cmd_len+set}" = set; then : +if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 @@ -6825,6 +6843,11 @@ else lt_cv_sys_max_cmd_len=8192; ;; + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. @@ -6850,6 +6873,11 @@ else lt_cv_sys_max_cmd_len=196608 ;; + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not @@ -6889,8 +6917,8 @@ else # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. - while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ - = "XX$teststring$teststring"; } >/dev/null 2>&1 && + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` @@ -6932,8 +6960,8 @@ $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" - test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ - = c,a/b,, \ + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes @@ -6982,9 +7010,83 @@ esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } -if test "${lt_cv_ld_reload_flag+set}" = set; then : +if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' @@ -6998,6 +7100,11 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' @@ -7020,7 +7127,7 @@ if test -n "$ac_tool_prefix"; then set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJDUMP+set}" = set; then : +if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then @@ -7060,7 +7167,7 @@ if test -z "$ac_cv_prog_OBJDUMP"; then set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then @@ -7119,7 +7226,7 @@ test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } -if test "${lt_cv_deplibs_check_method+set}" = set; then : +if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' @@ -7161,16 +7268,18 @@ mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; -cegcc) +cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' @@ -7200,6 +7309,10 @@ gnu*) lt_cv_deplibs_check_method=pass_all ;; +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in @@ -7208,11 +7321,11 @@ hpux10.20* | hpux11*) lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]' + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library' + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac @@ -7233,8 +7346,8 @@ irix5* | irix6* | nonstopux*) lt_cv_deplibs_check_method=pass_all ;; -# This must be Linux ELF. -linux* | k*bsd*-gnu) +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; @@ -7315,6 +7428,21 @@ esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown @@ -7328,18 +7456,28 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : +if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -7348,7 +7486,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AR="${ac_tool_prefix}ar" + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -7358,10 +7496,10 @@ IFS=$as_save_IFS fi fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -7369,17 +7507,17 @@ fi fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -7388,7 +7526,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_AR="ar" + ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -7398,17 +7536,17 @@ IFS=$as_save_IFS fi fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi - if test "x$ac_ct_AR" = x; then - AR="false" + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) @@ -7416,15 +7554,13 @@ yes:) $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac - AR=$ac_ct_AR + DLLTOOL=$ac_ct_DLLTOOL fi else - AR="$ac_cv_prog_AR" + DLLTOOL="$ac_cv_prog_DLLTOOL" fi -test -z "$AR" && AR=ar -test -z "$AR_FLAGS" && AR_FLAGS=cru - +test -z "$DLLTOOL" && DLLTOOL=dlltool @@ -7435,25 +7571,234 @@ test -z "$AR_FLAGS" && AR_FLAGS=cru -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -7480,7 +7825,7 @@ if test -z "$ac_cv_prog_STRIP"; then set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then @@ -7539,7 +7884,7 @@ if test -n "$ac_tool_prefix"; then set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : +if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then @@ -7579,7 +7924,7 @@ if test -z "$ac_cv_prog_RANLIB"; then set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then @@ -7641,15 +7986,24 @@ old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + @@ -7667,6 +8021,51 @@ fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + + + @@ -7696,7 +8095,7 @@ compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } -if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : +if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else @@ -7757,8 +8156,8 @@ esac lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= @@ -7782,6 +8181,7 @@ for ac_symprfx in "" "_"; do # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ @@ -7794,6 +8194,7 @@ for ac_symprfx in "" "_"; do else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no @@ -7819,8 +8220,8 @@ _LT_EOF test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\""; } >&5 - (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then @@ -7835,6 +8236,18 @@ _LT_EOF if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + #ifdef __cplusplus extern "C" { #endif @@ -7846,7 +8259,7 @@ _LT_EOF cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ -const struct { +LT_DLSYM_CONST struct { const char *name; void *address; } @@ -7872,8 +8285,8 @@ static const void *lt_preloaded_setup() { _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext - lt_save_LIBS="$LIBS" - lt_save_CFLAGS="$CFLAGS" + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 @@ -7883,8 +8296,8 @@ _LT_EOF test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi - LIBS="$lt_save_LIBS" - CFLAGS="$lt_save_CFLAGS" + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi @@ -7921,6 +8334,13 @@ else $as_echo "ok" >&6; } fi +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + @@ -7940,6 +8360,48 @@ fi + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + # Check whether --enable-libtool-lock was given. @@ -7973,7 +8435,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 7976 "configure"' > conftest.$ac_ext + echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -8067,7 +8529,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } -if test "${lt_cv_cc_needs_belf+set}" = set; then : +if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c @@ -8108,7 +8570,7 @@ $as_echo "$lt_cv_cc_needs_belf" >&6; } CFLAGS="$SAVE_CFLAGS" fi ;; -sparc*-*solaris*) +*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 @@ -8119,7 +8581,20 @@ sparc*-*solaris*) case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in - yes*) LD="${LD-ld} -m elf64_sparc" ;; + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" @@ -8135,19 +8610,16 @@ esac need_locks="$enable_libtool_lock" - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else - if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH @@ -8156,7 +8628,7 @@ do test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi @@ -8166,8 +8638,128 @@ IFS=$as_save_IFS fi fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else @@ -8183,7 +8775,7 @@ if test -z "$ac_cv_prog_DSYMUTIL"; then set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then @@ -8235,7 +8827,7 @@ fi set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_NMEDIT+set}" = set; then : +if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then @@ -8275,7 +8867,7 @@ if test -z "$ac_cv_prog_NMEDIT"; then set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then @@ -8327,7 +8919,7 @@ fi set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_LIPO+set}" = set; then : +if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then @@ -8367,7 +8959,7 @@ if test -z "$ac_cv_prog_LIPO"; then set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then @@ -8419,7 +9011,7 @@ fi set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL+set}" = set; then : +if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then @@ -8459,7 +9051,7 @@ if test -z "$ac_cv_prog_OTOOL"; then set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then @@ -8511,7 +9103,7 @@ fi set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL64+set}" = set; then : +if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then @@ -8551,7 +9143,7 @@ if test -z "$ac_cv_prog_OTOOL64"; then set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then @@ -8626,7 +9218,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } -if test "${lt_cv_apple_cc_single_mod+set}" = set; then : +if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no @@ -8642,7 +9234,13 @@ else $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? - if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 @@ -8653,9 +9251,10 @@ else fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } -if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : +if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no @@ -8685,6 +9284,41 @@ rm -f core conftest.err conftest.$ac_objext \ fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; @@ -8712,7 +9346,7 @@ $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi - if test "$DSYMUTIL" != ":"; then + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= @@ -8723,7 +9357,7 @@ $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -8840,8 +9474,7 @@ do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -8855,7 +9488,7 @@ for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " -if test "x$ac_cv_header_dlfcn_h" = x""yes; then : +if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF @@ -8866,11 +9499,12 @@ done -# Set options +# Set options +enable_dlopen=yes + - enable_dlopen=no enable_win32_dll=no @@ -8941,7 +9575,22 @@ fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : - withval=$with_pic; pic_mode="$withval" + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac else pic_mode=default fi @@ -9012,6 +9661,11 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + @@ -9039,7 +9693,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } -if test "${lt_cv_objdir+set}" = set; then : +if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null @@ -9067,19 +9721,6 @@ _ACEOF - - - - - - - - - - - - - case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some @@ -9092,23 +9733,6 @@ aix3*) ;; esac -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - # Global variables: ofile=libtool can_build_shared=yes @@ -9137,7 +9761,7 @@ for cc_temp in $compiler""; do *) break;; esac done -cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it @@ -9147,7 +9771,7 @@ file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : +if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in @@ -9213,7 +9837,7 @@ if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : +if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in @@ -9346,11 +9970,16 @@ if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then - lt_prog_compiler_no_builtin_flag=' -fno-builtin' + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no @@ -9366,15 +9995,15 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:9369: $lt_compile\"" >&5) + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:9373: \$? = $ac_status" >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. - $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes @@ -9403,8 +10032,6 @@ fi lt_prog_compiler_pic= lt_prog_compiler_static= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' @@ -9452,6 +10079,12 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; } lt_prog_compiler_pic='-fno-common' ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag @@ -9494,6 +10127,15 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; } lt_prog_compiler_pic='-fPIC' ;; esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in @@ -9535,7 +10177,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; } lt_prog_compiler_static='-non_shared' ;; - linux* | k*bsd*-gnu) + linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) @@ -9556,7 +10198,13 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; } lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; - pgcc* | pgf77* | pgf90* | pgf95*) + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' @@ -9568,25 +10216,40 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; } # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; - xl*) - # IBM XL C 8.0/Fortran 10.1 on PPC + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; - *Sun\ F*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' ;; esac ;; @@ -9618,7 +10281,7 @@ $as_echo_n "checking for $compiler option to produce PIC... " >&6; } lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in - f77* | f90* | f95*) + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; @@ -9675,13 +10338,17 @@ case $host_os in lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 -$as_echo "$lt_prog_compiler_pic" >&6; } - - - - +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. @@ -9689,7 +10356,7 @@ $as_echo "$lt_prog_compiler_pic" >&6; } if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : +if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no @@ -9705,15 +10372,15 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:9708: $lt_compile\"" >&5) + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:9712: \$? = $ac_status" >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. - $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes @@ -9742,13 +10409,18 @@ fi + + + + + # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test "${lt_cv_prog_compiler_static_works+set}" = set; then : +if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no @@ -9761,7 +10433,7 @@ else if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 - $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes @@ -9791,7 +10463,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then : +if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no @@ -9810,16 +10482,16 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:9813: $lt_compile\"" >&5) + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:9817: \$? = $ac_status" >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings - $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes @@ -9846,7 +10518,7 @@ $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then : +if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no @@ -9865,16 +10537,16 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:9868: $lt_compile\"" >&5) + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:9872: \$? = $ac_status" >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings - $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes @@ -9940,7 +10612,6 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= - hardcode_libdir_flag_spec_ld= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported @@ -9987,7 +10658,33 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie esac ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' @@ -10005,6 +10702,7 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie fi supports_anon_versioning=no case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... @@ -10020,11 +10718,12 @@ $as_echo_n "checking whether the $compiler linker ($LD) supports shared librarie ld_shlibs=no cat <<_LT_EOF 1>&2 -*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. _LT_EOF fi @@ -10060,10 +10759,12 @@ _LT_EOF # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' @@ -10081,6 +10782,11 @@ _LT_EOF fi ;; + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no @@ -10096,7 +10802,7 @@ _LT_EOF archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; - gnu* | linux* | tpf* | k*bsd*-gnu) + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in @@ -10106,15 +10812,16 @@ _LT_EOF if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then - tmp_addflag= + tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; - pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; @@ -10125,13 +10832,17 @@ _LT_EOF lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; - xl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 @@ -10147,17 +10858,16 @@ _LT_EOF fi case $cc_basename in - xlf*) + xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec= - hardcode_libdir_flag_spec_ld='-rpath $libdir' - archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac @@ -10171,8 +10881,8 @@ _LT_EOF archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; @@ -10190,8 +10900,8 @@ _LT_EOF _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi @@ -10237,8 +10947,8 @@ _LT_EOF *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi @@ -10278,8 +10988,10 @@ _LT_EOF else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi @@ -10366,7 +11078,13 @@ _LT_EOF allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -10379,25 +11097,32 @@ main () _ACEOF if ac_fn_c_try_link "$LINENO"; then : -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' @@ -10406,7 +11131,13 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi else # Determine the default libpath from the value encoded in an # empty executable. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -10419,30 +11150,42 @@ main () _ACEOF if ac_fn_c_try_link "$LINENO"; then : -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' @@ -10474,20 +11217,64 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - fix_srcfile_path='`cygpath -w "$srcfile"`' - enable_shared_with_static_runtimes=yes + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac ;; darwin* | rhapsody*) @@ -10497,7 +11284,12 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported - whole_archive_flag_spec='' + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in @@ -10505,7 +11297,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=echo + output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" @@ -10523,10 +11315,6 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hardcode_shlibpath_var=no ;; - freebsd1*) - ld_shlibs=no - ;; - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little @@ -10539,7 +11327,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) + freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes @@ -10548,7 +11336,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) - archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no @@ -10556,7 +11344,7 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi hpux9*) if test "$GCC" = yes; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi @@ -10571,14 +11359,13 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ;; hpux10*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_flag_spec_ld='+b $libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes @@ -10590,16 +11377,16 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi ;; hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then + if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else @@ -10611,15 +11398,54 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - case $host_cpu in + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no @@ -10639,26 +11465,39 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -int foo(void) {} +int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' - + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' @@ -10720,17 +11559,17 @@ rm -f core conftest.err conftest.$ac_objext \ hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported - archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' @@ -10740,13 +11579,13 @@ rm -f core conftest.err conftest.$ac_objext \ osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' @@ -10759,9 +11598,9 @@ rm -f core conftest.err conftest.$ac_objext \ no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' - archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) @@ -10949,44 +11788,50 @@ x|xyes) # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } - then - archive_cmds_need_lc=no - else - archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $archive_cmds_need_lc" >&5 -$as_echo "$archive_cmds_need_lc" >&6; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi @@ -11138,11 +11983,6 @@ esac - - - - - @@ -11157,16 +11997,23 @@ if test "$GCC" = yes; then darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` - else - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= @@ -11179,7 +12026,7 @@ if test "$GCC" = yes; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done - lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; @@ -11199,7 +12046,13 @@ BEGIN {RS=" "; FS="/|\n";} { if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` - sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi @@ -11225,7 +12078,7 @@ need_version=unknown case $host_os in aix3*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH @@ -11234,7 +12087,7 @@ aix3*) ;; aix[4-9]*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes @@ -11287,7 +12140,7 @@ amigaos*) m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; @@ -11299,7 +12152,7 @@ beos*) ;; bsdi[45]*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' @@ -11318,8 +12171,9 @@ cygwin* | mingw* | pw32* | cegcc*) need_version=no need_lib_prefix=no - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + case $GCC,$cc_basename in + yes,*) + # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ @@ -11340,36 +12194,83 @@ cygwin* | mingw* | pw32* | cegcc*) cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' ;; *) + # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' ;; esac - dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; @@ -11390,7 +12291,7 @@ darwin* | rhapsody*) ;; dgux*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' @@ -11398,10 +12299,6 @@ dgux*) shlibpath_var=LD_LIBRARY_PATH ;; -freebsd1*) - dynamic_linker=no - ;; - freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. @@ -11409,7 +12306,7 @@ freebsd* | dragonfly*) objformat=`/usr/bin/objformat` else case $host_os in - freebsd[123]*) objformat=aout ;; + freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi @@ -11427,7 +12324,7 @@ freebsd* | dragonfly*) esac shlibpath_var=LD_LIBRARY_PATH case $host_os in - freebsd2*) + freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) @@ -11447,12 +12344,26 @@ freebsd* | dragonfly*) ;; gnu*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; @@ -11498,12 +12409,14 @@ hpux9* | hpux10* | hpux11*) soname_spec='${libname}${release}${shared_ext}$major' ;; esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 ;; interix[3-9]*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' @@ -11519,7 +12432,7 @@ irix5* | irix6* | nonstopux*) nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; @@ -11556,9 +12469,9 @@ linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' @@ -11566,12 +12479,17 @@ linux* | k*bsd*-gnu) finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -11584,13 +12502,17 @@ main () _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - shlibpath_overrides_runpath=yes + lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install @@ -11599,7 +12521,7 @@ rm -f core conftest.err conftest.$ac_objext \ # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi @@ -11631,7 +12553,7 @@ netbsd*) ;; newsos6) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes @@ -11700,7 +12622,7 @@ rdos*) ;; solaris*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' @@ -11725,7 +12647,7 @@ sunos4*) ;; sysv4 | sysv4.3*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH @@ -11749,7 +12671,7 @@ sysv4 | sysv4.3*) sysv4*MP*) if test -d /usr/nec ;then - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH @@ -11780,7 +12702,7 @@ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' @@ -11790,7 +12712,7 @@ tpf*) ;; uts4*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH @@ -11896,6 +12818,11 @@ fi + + + + + @@ -11974,7 +12901,7 @@ else # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12008,7 +12935,7 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else @@ -12022,12 +12949,12 @@ fi *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = x""yes; then : +if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then : +if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12061,16 +12988,16 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = x""yes; then : +if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : +if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12104,12 +13031,12 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } -if test "${ac_cv_lib_svld_dlopen+set}" = set; then : +if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12143,12 +13070,12 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } -if test "${ac_cv_lib_dld_dld_link+set}" = set; then : +if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -12182,7 +13109,7 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi @@ -12223,7 +13150,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self+set}" = set; then : +if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12232,7 +13159,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 $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12273,7 +13200,13 @@ else # endif #endif -void fnord() { int i=42;} +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); @@ -12282,7 +13215,11 @@ int main () if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } /* dlclose (self); */ } else @@ -12319,7 +13256,7 @@ $as_echo "$lt_cv_dlopen_self" >&6; } wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self_static+set}" = set; then : +if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -12328,7 +13265,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 $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12369,7 +13306,13 @@ else # endif #endif -void fnord() { int i=42;} +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); @@ -12378,7 +13321,11 @@ int main () if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } /* dlclose (self); */ } else @@ -12547,6 +13494,8 @@ CC="$lt_save_CC" + + ac_config_commands="$ac_config_commands libtool" @@ -12558,8 +13507,18 @@ CC="$lt_save_CC" if test "$enable_shared" = "no"; then with_noexec=no + enable_dlopen=no + lt_cv_dlopen=none + lt_cv_dlopen_libs= + ac_cv_func_dlopen=no else eval _shrext="$shrext_cmds" + # Darwin uses .dylib for libraries but .so for modules + if test X"$_shrext" = X".dylib"; then + SOEXT=".so" + else + SOEXT="$_shrext" + fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking path to sudo_noexec.so" >&5 $as_echo_n "checking path to sudo_noexec.so... " >&6; } @@ -12581,15 +13540,11 @@ $as_echo "$with_noexec" >&6; } NOEXECFILE="sudo_noexec$_shrext" NOEXECDIR="`echo $with_noexec|sed 's:^\(.*\)/[^/]*:\1:'`" -if test X"$with_devel" = X"yes" -a -n "$GCC"; then - CFLAGS="${CFLAGS} -Wall" -fi - # Extract the first word of "uname", so it can be a program name with args. set dummy uname; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_UNAMEPROG+set}" = set; then : +if ${ac_cv_prog_UNAMEPROG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$UNAMEPROG"; then @@ -12626,7 +13581,7 @@ fi set dummy tr; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_TRPROG+set}" = set; then : +if ${ac_cv_prog_TRPROG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$TRPROG"; then @@ -12665,7 +13620,7 @@ do set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_NROFFPROG+set}" = set; then : +if ${ac_cv_prog_NROFFPROG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NROFFPROG"; then @@ -12701,18 +13656,53 @@ fi test -n "$NROFFPROG" && break done -if test -z "$NROFFPROG"; then +if test -n "$NROFFPROG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $NROFFPROG supports the -c option" >&5 +$as_echo_n "checking whether $NROFFPROG supports the -c option... " >&6; } +if ${sudo_cv_var_nroff_opt_c+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $NROFFPROG -c /dev/null 2>&1; then + sudo_cv_var_nroff_opt_c=yes + else + sudo_cv_var_nroff_opt_c=no + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_var_nroff_opt_c" >&5 +$as_echo "$sudo_cv_var_nroff_opt_c" >&6; } + if test "$sudo_cv_var_nroff_opt_c" = "yes"; then + NROFFPROG="$NROFFPROG -c" + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $NROFFPROG supports the -Tascii option" >&5 +$as_echo_n "checking whether $NROFFPROG supports the -Tascii option... " >&6; } +if ${sudo_cv_var_nroff_opt_Tascii+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $NROFFPROG -Tascii /dev/null 2>&1; then + sudo_cv_var_nroff_opt_Tascii=yes + else + sudo_cv_var_nroff_opt_Tascii=no + fi + if test "$sudo_cv_var_nroff_opt_Tascii" = "yes"; then + NROFFPROG="$NROFFPROG -Tascii" + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_var_nroff_opt_Tascii" >&5 +$as_echo "$sudo_cv_var_nroff_opt_Tascii" >&6; } +else MANTYPE="cat" mansrcdir='$(srcdir)' fi if test -n "$sudo_cv_prev_host"; then if test "$sudo_cv_prev_host" != "$host"; then - as_fn_error "config.cache was created on a different host; remove it and re-run configure." "$LINENO" 5 + as_fn_error $? "config.cache was created on a different host; remove it and re-run configure." "$LINENO" 5 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking previous host type" >&5 $as_echo_n "checking previous host type... " >&6; } - if test "${sudo_cv_prev_host+set}" = set; then : + if ${sudo_cv_prev_host+:} false; then : $as_echo_n "(cached) " >&6 else sudo_cv_prev_host="$host" @@ -12723,7 +13713,7 @@ $as_echo "$sudo_cv_prev_host" >&6; } fi else # this will produce no output since there is no cached value - if test "${sudo_cv_prev_host+set}" = set; then : + if ${sudo_cv_prev_host+:} false; then : $as_echo_n "(cached) " >&6 else sudo_cv_prev_host="$host" @@ -12743,6 +13733,9 @@ fi case "$host" in *-*-sunos4*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # getcwd(3) opens a pipe to getpwd(1)!?! BROKEN_GETCWD=1 @@ -12754,6 +13747,9 @@ case "$host" in shadow_funcs="getpwanam issecure" ;; *-*-solaris2*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # To get the crypt(3) prototype (so we pass -Wall) OSDEFS="${OSDEFS} -D__EXTENSIONS__" # AFS support needs -lucb @@ -12764,11 +13760,22 @@ case "$host" in : ${mansectform='4'} : ${with_rpath='yes'} test -z "$with_pam" && AUTH_EXCL_DEF="PAM" + for ac_func in priv_set +do : + ac_fn_c_check_func "$LINENO" "priv_set" "ac_cv_func_priv_set" +if test "x$ac_cv_func_priv_set" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PRIV_SET 1 +_ACEOF + +fi +done + ;; *-*-aix*) # To get all prototypes (so we pass -Wall) OSDEFS="${OSDEFS} -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT" - SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp" if test X"$with_blibpath" != X"no"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if linker accepts -Wl,-blibpath" >&5 $as_echo_n "checking if linker accepts -Wl,-blibpath... " >&6; } @@ -12806,12 +13813,17 @@ rm -f core conftest.err conftest.$ac_objext \ fi LDFLAGS="$O_LDFLAGS" - # Use authenticate(3) as the default authentication method - if test X"$with_aixauth" = X""; then - for ac_func in authenticate + # On AIX 6 and higher default to PAM, else default to LAM + if test $OSMAJOR -ge 6; then + if test X"$with_pam" = X""; then + AUTH_EXCL_DEF="PAM" + fi + else + if test X"$with_aixauth" = X""; then + for ac_func in authenticate do : ac_fn_c_check_func "$LINENO" "authenticate" "ac_cv_func_authenticate" -if test "x$ac_cv_func_authenticate" = x""yes; then : +if test "x$ac_cv_func_authenticate" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_AUTHENTICATE 1 _ACEOF @@ -12819,6 +13831,7 @@ _ACEOF fi done + fi fi # AIX analog of nsswitch.conf, enabled by default @@ -12837,13 +13850,32 @@ fi with_netsvc="/etc/netsvc.conf" fi + # For implementing getgrouplist() + for ac_func in getgrset +do : + ac_fn_c_check_func "$LINENO" "getgrset" "ac_cv_func_getgrset" +if test "x$ac_cv_func_getgrset" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETGRSET 1 +_ACEOF + +fi +done + + + # LDR_PRELOAD is only supported in AIX 5.3 and later + if test $OSMAJOR -lt 5; then + with_noexec=no + else + RTLD_PRELOAD_VAR="LDR_PRELOAD" + fi + # AIX-specific functions for ac_func in getuserattr setauthdb 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -12851,7 +13883,7 @@ _ACEOF fi done - COMMON_OBJS="$COMMON_OBJS aix.o" + COMMON_OBJS="$COMMON_OBJS aix.lo" ;; *-*-hiuxmpp*) : ${mansectsu='1m'} @@ -12865,20 +13897,40 @@ done : ${mansectsu='1m'} : ${mansectform='4'} + # The HP bundled compiler cannot generate shared libs if test -z "$GCC"; then - # HP-UX bundled compiler can't generate shared objects - if -z "$pic_flag"; then - with_noexec=no + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for HP bundled C compiler" >&5 +$as_echo_n "checking for HP bundled C compiler... " >&6; } +if ${sudo_cv_var_hpccbundled+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $CC -V 2>&1 | grep '^(Bundled)' >/dev/null 2>&1; then + sudo_cv_var_hpccbundled=yes + else + sudo_cv_var_hpccbundled=no + fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_var_hpccbundled" >&5 +$as_echo "$sudo_cv_var_hpccbundled" >&6; } + if test "$sudo_cv_var_hpccbundled" = "yes"; then + as_fn_error $? "The HP bundled C compiler is unable to build Sudo, you must use gcc or the HP ANSI C compiler instead." "$LINENO" 5 fi + fi - # Use the +DAportable flag on hppa if it is supported - case "$host_cpu" in - hppa*) + # Build PA-RISC1.1 objects for better portability + case "$host_cpu" in + hppa[2-9]*) _CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS +DAportable" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands +DAportable" >&5 -$as_echo_n "checking whether $CC understands +DAportable... " >&6; } -if test "${sudo_cv_var_daportable+set}" = set; then : + if test -n "$GCC"; then + portable_flag="-march=1.1" + else + portable_flag="+DAportable" + fi + CFLAGS="$CFLAGS $portable_flag" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands $portable_flag" >&5 +$as_echo_n "checking whether $CC understands $portable_flag... " >&6; } +if ${sudo_cv_var_daportable+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12909,20 +13961,12 @@ $as_echo "$sudo_cv_var_daportable" >&6; } CFLAGS="$_CFLAGS" fi ;; - esac - fi + esac case "$host" in - *-*-hpux1-8.*) + *-*-hpux[1-8].*) $as_echo "#define BROKEN_SYSLOG 1" >>confdefs.h - - # Not sure if setuid binaries are safe in < 9.x - if test -n "$GCC"; then - SUDO_LDFLAGS="${SUDO_LDFLAGS} -static" - else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-a,archive" - fi ;; *-*-hpux9.*) $as_echo "#define BROKEN_SYSLOG 1" >>confdefs.h @@ -12933,7 +13977,7 @@ $as_echo "$sudo_cv_var_daportable" >&6; } # DCE support (requires ANSI C compiler) if test "$with_DCE" = "yes"; then # order of libs in 9.X is important. -lc_r must be last - SUDO_LIBS="${SUDO_LIBS} -ldce -lM -lc_r" + SUDOERS_LIBS="${SUDOERS_LIBS} -ldce -lM -lc_r" LIBS="${LIBS} -ldce -lM -lc_r" CPPFLAGS="${CPPFLAGS} -D_REENTRANT -I/usr/include/reentrant" fi @@ -12941,6 +13985,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" @@ -12951,7 +13997,7 @@ $as_echo "$sudo_cv_var_daportable" >&6; } ;; *-dec-osf*) # ignore envariables wrt dynamic lib path - SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-no_library_replacement" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-no_library_replacement" : ${CHECKSIA='true'} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to disable sia support on Digital UNIX" >&5 @@ -13023,6 +14069,9 @@ $as_echo "yes, fixing locally" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='8'} : ${mansectform='4'} ;; @@ -13050,7 +14099,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test "$OSMAJOR" -le 4; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getpwnam in -lsun" >&5 $as_echo_n "checking for getpwnam in -lsun... " >&6; } -if test "${ac_cv_lib_sun_getpwnam+set}" = set; then : +if ${ac_cv_lib_sun_getpwnam+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13084,11 +14133,14 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sun_getpwnam" >&5 $as_echo "$ac_cv_lib_sun_getpwnam" >&6; } -if test "x$ac_cv_lib_sun_getpwnam" = x""yes; then : +if test "x$ac_cv_lib_sun_getpwnam" = xyes; then : LIBS="${LIBS} -lsun" fi fi + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='1m'} : ${mansectform='4'} ;; @@ -13124,8 +14176,7 @@ fi *-*-isc*) OSDEFS="${OSDEFS} -D_ISC" LIB_CRYPT=1 - SUDO_LIBS="${SUDO_LIBS} -lcrypt" - LIBS="${LIBS} -lcrypt" + SUDOERS_LIBS="${SUDOERS_LIBS} -lcrypt" shadow_funcs="getspnam" shadow_libs="-lsec" @@ -13155,7 +14206,7 @@ fi *-ncr-sysv4*|*-ncr-sysvr4*) { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strcasecmp in -lc89" >&5 $as_echo_n "checking for strcasecmp in -lc89... " >&6; } -if test "${ac_cv_lib_c89_strcasecmp+set}" = set; then : +if ${ac_cv_lib_c89_strcasecmp+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -13189,9 +14240,8 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c89_strcasecmp" >&5 $as_echo "$ac_cv_lib_c89_strcasecmp" >&6; } -if test "x$ac_cv_lib_c89_strcasecmp" = x""yes; then : - $as_echo "#define HAVE_STRCASECMP 1" >>confdefs.h - LIBS="${LIBS} -lc89"; ac_cv_func_strcasecmp=yes +if test "x$ac_cv_lib_c89_strcasecmp" = xyes; then : + LIBS="${LIBS} -lc89" fi : ${mansectsu='1m'} @@ -13200,29 +14250,18 @@ fi ;; *-ccur-sysv4*|*-ccur-sysvr4*) LIBS="${LIBS} -lgen" - SUDO_LIBS="${SUDO_LIBS} -lgen" : ${mansectsu='1m'} : ${mansectform='4'} : ${with_rpath='yes'} ;; *-*-bsdi*) SKIP_SETREUID=yes - # Use shlicc for BSD/OS [23].x unless asked to do otherwise - if test "${with_CC+set}" != set -a "$ac_cv_prog_CC" = gcc; then - case "$OSMAJOR" in - 2|3) { $as_echo "$as_me:${as_lineno-$LINENO}: using shlicc as CC" >&5 -$as_echo "$as_me: using shlicc as CC" >&6;} - ac_cv_prog_CC=shlicc - CC="$ac_cv_prog_CC" - ;; - esac - fi - # Check for newer BSD auth API (just check for >= 3.0?) + # Check for newer BSD auth API if test -z "$with_bsdauth"; then for ac_func in auth_challenge do : ac_fn_c_check_func "$LINENO" "auth_challenge" "ac_cv_func_auth_challenge" -if test "x$ac_cv_func_auth_challenge" = x""yes; then : +if test "x$ac_cv_func_auth_challenge" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_AUTH_CHALLENGE 1 _ACEOF @@ -13240,8 +14279,9 @@ done SKIP_SETREUID=yes ;; esac - if test "$with_skey" = "yes"; then - SUDO_LIBS="${SUDO_LIBS} -lmd" + OSDEFS="${OSDEFS} -D_BSD_SOURCE" + if test "${with_skey-'no'}" = "yes"; then + SUDOERS_LIBS="${SUDOERS_LIBS} -lmd" fi CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" @@ -13249,25 +14289,22 @@ done ;; *-*-*openbsd*) # OpenBSD has a real setreuid(2) starting with 3.3 but - # we will use setreuid(2) instead. + # we will use setresuid(2) instead. SKIP_SETREUID=yes + OSDEFS="${OSDEFS} -D_BSD_SOURCE" CHECKSHADOW="false" # OpenBSD >= 3.0 supports BSD auth if test -z "$with_bsdauth"; then - case "$OSREV" in - 0-2.*) - ;; - *) + if test "$OSMAJOR" -ge 3; then AUTH_EXCL_DEF="BSD_AUTH" - ;; - esac + fi fi : ${with_logincap='maybe'} ;; *-*-*netbsd*) # NetBSD has a real setreuid(2) starting with 1.3.2 case "$OSREV" in - 0.9*|1.012*|1.3|1.3.1) + 0.9*|1.[012]*|1.3|1.3.1) SKIP_SETREUID=yes ;; esac @@ -13276,8 +14313,9 @@ done : ${with_logincap='maybe'} ;; *-*-dragonfly*) - if test "$with_skey" = "yes"; then - SUDO_LIBS="${SUDO_LIBS} -lmd" + OSDEFS="${OSDEFS} -D_BSD_SOURCE" + if test "${with_skey-'no'}" = "yes"; then + SUDOERS_LIBS="${SUDOERS_LIBS} -lmd" fi CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" @@ -13294,11 +14332,15 @@ done CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" : ${with_logincap='yes'} + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-nextstep*) # lockf() on is broken on the NeXT -- use flock instead ac_cv_func_lockf=no ac_cv_func_flock=yes + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-*sysv4*) : ${mansectsu='1m'} @@ -13314,19 +14356,42 @@ done ;; esac +if test -n "$with_noexec"; then + cat >>confdefs.h <>confdefs.h <>confdefs.h <>confdefs.h <&5 $as_echo_n "checking whether $CC needs -traditional... " >&6; } -if test "${ac_cv_prog_gcc_traditional+set}" = set; then : +if ${ac_cv_prog_gcc_traditional+:} false; then : $as_echo_n "(cached) " >&6 else ac_pattern="Autoconf.*'x'" @@ -13407,7 +14472,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 $as_echo_n "checking for an ANSI C-conforming const... " >&6; } -if test "${ac_cv_c_const+set}" = set; then : +if ${ac_cv_c_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13487,7 +14552,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working volatile" >&5 $as_echo_n "checking for working volatile... " >&6; } -if test "${ac_cv_c_volatile+set}" = set; then : +if ${ac_cv_c_volatile+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13519,13 +14584,75 @@ $as_echo "#define volatile /**/" >>confdefs.h fi +# Check for variadic macro support in cpp +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +$ac_includes_default +#if defined(__GNUC__) && __GNUC__ == 2 +# define sudo_fprintf(fp, fmt...) fprintf((fp), (fmt)) +#else +# define sudo_fprintf(fp, ...) fprintf((fp), __VA_ARGS__) +#endif + +int +main () +{ +sudo_fprintf(stderr, "a %s", "test"); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + as_fn_error $? "Your C compiler doesn't support variadic macros, try building with gcc instead" "$LINENO" 5 +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +if test X"$with_gnu_ld" != "yes" -a -n "$GCC"; then + _CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -static-libgcc" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -static-libgcc" >&5 +$as_echo_n "checking whether $CC understands -static-libgcc... " >&6; } +if ${sudo_cv_var_gcc_static_libgcc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + sudo_cv_var_gcc_static_libgcc=yes +else + sudo_cv_var_gcc_static_libgcc=no + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_var_gcc_static_libgcc" >&5 +$as_echo "$sudo_cv_var_gcc_static_libgcc" >&6; } + CFLAGS="$_CFLAGS" + if test "$sudo_cv_var_gcc_static_libgcc" = "yes"; then + LTLDFLAGS="$LTLDFLAGS -Wc,-static-libgcc" + fi +fi for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_YACC+set}" = set; then : +if ${ac_cv_prog_YACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$YACC"; then @@ -13566,7 +14693,7 @@ test -n "$YACC" || YACC="yacc" set dummy flex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_path_FLEX+set}" = set; then : +if ${ac_cv_path_FLEX+:} false; then : $as_echo_n "(cached) " >&6 else case $FLEX in @@ -13665,8 +14792,7 @@ $as_echo "not found" >&6; } fi fi -if test -z "$with_editor"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vi" >&5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for vi" >&5 $as_echo_n "checking for vi... " >&6; } found=no for editor in "/usr/bin/vi" "/bin/vi" "/usr/ucb/vi" "/usr/bsd/vi" "/usr/local/bin/vi"; do @@ -13686,7 +14812,6 @@ if test X"$found" != X"yes"; then $as_echo "not found" >&6; } fi -fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking which syslog facility sudo should log with" >&5 $as_echo_n "checking which syslog facility sudo should log with... " >&6; } if test X"$with_logfac" = X""; then @@ -13715,7 +14840,7 @@ _ACEOF $as_echo "$logfac" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : +if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13830,7 +14955,7 @@ for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : +if eval \${$as_ac_Header+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13857,8 +14982,7 @@ fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF @@ -13871,7 +14995,7 @@ done if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -13905,11 +15029,11 @@ for ac_lib in '' dir; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -13928,7 +15052,7 @@ fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -13962,11 +15086,11 @@ for ac_lib in '' x; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_opendir+set}" = set; then : + if ${ac_cv_search_opendir+:} false; then : break fi done -if test "${ac_cv_search_opendir+set}" = set; then : +if ${ac_cv_search_opendir+:} false; then : else ac_cv_search_opendir=no @@ -13986,7 +15110,7 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } -if test "${ac_cv_header_time+set}" = set; then : +if ${ac_cv_header_time+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -14019,310 +15143,777 @@ $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 -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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - -{ $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 : +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +$as_echo_n "checking for stdbool.h that conforms to C99... " >&6; } +if ${ac_cv_header_stdbool_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -#include + +#include +#ifndef bool + "error: bool is not defined" +#endif +#ifndef false + "error: false is not defined" +#endif +#if false + "error: false is not 0" +#endif +#ifndef true + "error: true is not defined" +#endif +#if true != 1 + "error: true is not 1" +#endif +#ifndef __bool_true_false_are_defined + "error: __bool_true_false_are_defined is not defined" +#endif + + struct s { _Bool s: 1; _Bool t; } s; + + char a[true == 1 ? 1 : -1]; + char b[false == 0 ? 1 : -1]; + char c[__bool_true_false_are_defined == 1 ? 1 : -1]; + char d[(bool) 0.5 == true ? 1 : -1]; + /* See body of main program for 'e'. */ + char f[(_Bool) 0.0 == false ? 1 : -1]; + char g[true]; + char h[sizeof (_Bool)]; + char i[sizeof s.t]; + enum { j = false, k = true, l = false * true, m = true * 256 }; + /* The following fails for + HP aC++/ANSI C B3910B A.05.55 [Dec 04 2003]. */ + _Bool n[m]; + char o[sizeof n == m * sizeof n[0] ? 1 : -1]; + char p[-1 - (_Bool) 0 < 0 && -1 - (bool) 0 < 0 ? 1 : -1]; + /* Catch a bug in an HP-UX C compiler. See + http://gcc.gnu.org/ml/gcc-patches/2003-12/msg02303.html + http://lists.gnu.org/archive/html/bug-coreutils/2005-11/msg00161.html + */ + _Bool q = true; + _Bool *pq = &q; int main () { -/* SunOS 4.0.3 has termios.h but not the library calls. */ - tcgetattr(0, 0); + + bool e = &s; + *pq |= q; + *pq |= ! q; + /* Refer to every declared value, to avoid compiler optimizations. */ + return (!a + !b + !c + !d + !e + !f + !g + !h + !i + !!j + !k + !!l + + !m + !n + !o + !p + !q + !pq); + ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_sys_posix_termios=yes +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdbool_h=yes else - ac_cv_sys_posix_termios=no + ac_cv_header_stdbool_h=no fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_posix_termios" >&5 -$as_echo "$ac_cv_sys_posix_termios" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 +$as_echo "$ac_cv_header_stdbool_h" >&6; } +ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" +if test "x$ac_cv_type__Bool" = xyes; then : -if test "$ac_cv_sys_posix_termios" = "yes"; then - $as_echo "#define HAVE_TERMIOS_H 1" >>confdefs.h - -else - for ac_header in termio.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "termio.h" "ac_cv_header_termio_h" "$ac_includes_default" -if test "x$ac_cv_header_termio_h" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_TERMIO_H 1 +cat >>confdefs.h <<_ACEOF +#define HAVE__BOOL 1 _ACEOF + fi -done +if test $ac_cv_header_stdbool_h = yes; then + +$as_echo "#define HAVE_STDBOOL_H 1" >>confdefs.h fi -maildir=no -if test X"$ac_cv_header_paths_h" = X"yes"; then -cat confdefs.h - <<_ACEOF >conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 +$as_echo_n "checking whether sys/types.h defines makedev... " >&6; } +if ${ac_cv_header_sys_types_h_makedev+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -$ac_includes_default -#include -int main() {char *p = _PATH_MAILDIR;} +#include int main () { - +return makedev(0, 0); ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - maildir=yes +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_header_sys_types_h_makedev=yes +else + ac_cv_header_sys_types_h_makedev=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + fi -if test $maildir = no; then - # Solaris has maillock.h which defines MAILDIR - for ac_header in maillock.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "maillock.h" "ac_cv_header_maillock_h" "$ac_includes_default" -if test "x$ac_cv_header_maillock_h" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_MAILLOCK_H 1 -_ACEOF +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 +$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; } - cat >>confdefs.h <<\EOF -#define _PATH_MAILDIR MAILDIR -EOF +if test $ac_cv_header_sys_types_h_makedev = no; then +ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : - maildir=yes +$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h fi -done - if test $maildir = no; then - for d in /var/mail /var/spool/mail /usr/spool/mail; do - if test -d "$d"; then - maildir=yes - cat >>confdefs.h <>confdefs.h <>confdefs.h - fi - fi fi -if test ${with_logincap-'no'} != "no"; then - for ac_header in login_cap.h + + fi +fi + +for ac_header in malloc.h netgroup.h paths.h spawn.h utime.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h do : - ac_fn_c_check_header_mongrel "$LINENO" "login_cap.h" "ac_cv_header_login_cap_h" "$ac_includes_default" -if test "x$ac_cv_header_login_cap_h" = x""yes; then : + 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" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_LOGIN_CAP_H 1 +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF - LOGINCAP_USAGE='[-c class|-] '; LCMAN=1 - case "$OS" in - freebsd|netbsd) SUDO_LIBS="${SUDO_LIBS} -lutil" - ;; - esac fi done -fi -if test ${with_project-'no'} != "no"; then - ac_fn_c_check_header_mongrel "$LINENO" "project.h" "ac_cv_header_project_h" "$ac_includes_default" -if test "x$ac_cv_header_project_h" = x""yes; then : - $as_echo "#define HAVE_PROJECT_H 1" >>confdefs.h - - SUDO_LIBS="${SUDO_LIBS} -lproject" -else - - -fi - - -fi -ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" -if test "x$ac_cv_type_mode_t" = x""yes; then : +for ac_header in procfs.h sys/procfs.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" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + ac_fn_c_check_member "$LINENO" "struct psinfo" "pr_ttydev" "ac_cv_member_struct_psinfo_pr_ttydev" "$ac_includes_default +#ifdef HAVE_PROCFS_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include +#endif -else +" +if test "x$ac_cv_member_struct_psinfo_pr_ttydev" = xyes; then : cat >>confdefs.h <<_ACEOF -#define mode_t int +#define HAVE_STRUCT_PSINFO_PR_TTYDEV 1 _ACEOF -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 -$as_echo_n "checking for uid_t in sys/types.h... " >&6; } -if test "${ac_cv_type_uid_t+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - +for ac_func in _ttyname_dev +do : + ac_fn_c_check_func "$LINENO" "_ttyname_dev" "ac_cv_func__ttyname_dev" +if test "x$ac_cv_func__ttyname_dev" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE__TTYNAME_DEV 1 _ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1; then : - ac_cv_type_uid_t=yes -else - ac_cv_type_uid_t=no -fi -rm -f conftest* fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 -$as_echo "$ac_cv_type_uid_t" >&6; } -if test $ac_cv_type_uid_t = no; then - -$as_echo "#define uid_t int" >>confdefs.h - - -$as_echo "#define gid_t int" >>confdefs.h +done fi -ac_fn_c_check_type "$LINENO" "__signed char" "ac_cv_type___signed_char" "$ac_includes_default" -if test "x$ac_cv_type___signed_char" = x""yes; then : - -else - ac_fn_c_check_type "$LINENO" "signed char" "ac_cv_type_signed_char" "$ac_includes_default" -if test "x$ac_cv_type_signed_char" = x""yes; then : - $as_echo "#define __signed signed" >>confdefs.h - -else - $as_echo "#define __signed /**/" >>confdefs.h - +break fi +done + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; fi -ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include -#include -" -if test "x$ac_cv_type_sig_atomic_t" = x""yes; then : +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 ${ac_cv_sys_largefile_CC+:} false; then : + $as_echo_n "(cached) " >&6 else - $as_echo "#define sig_atomic_t int" >>confdefs.h - -fi - -ac_fn_c_check_type "$LINENO" "sigaction_t" "ac_cv_type_sigaction_t" "#include -#include -" -if test "x$ac_cv_type_sigaction_t" = x""yes; then : + 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 () +{ -cat >>confdefs.h <<_ACEOF -#define HAVE_SIGACTION_T 1 + ; + return 0; +} _ACEOF - -$as_echo "#define HAVE_SIGACTION_T 1" >>confdefs.h - + if ac_fn_c_try_compile "$LINENO"; then : + break fi - -ac_fn_c_check_type "$LINENO" "struct timespec" "ac_cv_type_struct_timespec" "#include -#if TIME_WITH_SYS_TIME -# include -#endif -#include -" -if test "x$ac_cv_type_struct_timespec" = x""yes; then : - $as_echo "#define HAVE_TIMESPEC 1" >>confdefs.h - +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 - -ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "#include -#include -" -if test "x$ac_cv_type_struct_in6_addr" = x""yes; then : - -cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_IN6_ADDR 1 -_ACEOF - -$as_echo "#define HAVE_IN6_ADDR 1" >>confdefs.h - +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 long long int" >&5 -$as_echo_n "checking for long long int... " >&6; } -if test "${ac_cv_type_long_long_int+set}" = set; then : + { $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 ${ac_cv_sys_file_offset_bits+:} false; then : $as_echo_n "(cached) " >&6 else + while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - - /* For now, do not test the preprocessor; as of 2007 there are too many - implementations with broken preprocessors. Perhaps this can - be revisited in 2012. In the meantime, code should not expect - #if to work with literals wider than 32 bits. */ - /* Test literals. */ - long long int ll = 9223372036854775807ll; - long long int nll = -9223372036854775807LL; - unsigned long long int ull = 18446744073709551615ULL; - /* Test constant expressions. */ - typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) - ? 1 : -1)]; - typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 - ? 1 : -1)]; - int i = 63; +#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 () { -/* Test availability of runtime routines for shift and division. */ - long long int llmax = 9223372036854775807ll; - unsigned long long int ullmax = 18446744073709551615ull; - return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) - | (llmax / ll) | (llmax % ll) - | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) - | (ullmax / ull) | (ullmax % ull)); + ; return 0; } - _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - if test "$cross_compiling" = yes; then : - ac_cv_type_long_long_int=yes -else +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. */ -#include - #ifndef LLONG_MAX +#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 ${ac_cv_sys_large_files+:} false; 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 ${sudo_cv_xopen_source_extended+:} false; 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 ${ac_cv_sys_posix_termios+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +/* SunOS 4.0.3 has termios.h but not the library calls. */ + tcgetattr(0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_sys_posix_termios=yes +else + ac_cv_sys_posix_termios=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_posix_termios" >&5 +$as_echo "$ac_cv_sys_posix_termios" >&6; } + +if test "$ac_cv_sys_posix_termios" != "yes"; then + as_fn_error $? "Must have POSIX termios to build sudo" "$LINENO" 5 +fi + +maildir=no +if test X"$ac_cv_header_paths_h" = X"yes"; then +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +#include +int +main () +{ +char *p = _PATH_MAILDIR; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + maildir=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +if test $maildir = no; then + # Solaris has maillock.h which defines MAILDIR + for ac_header in maillock.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "maillock.h" "ac_cv_header_maillock_h" "$ac_includes_default" +if test "x$ac_cv_header_maillock_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MAILLOCK_H 1 +_ACEOF + + cat >>confdefs.h <<\EOF +#define _PATH_MAILDIR MAILDIR +EOF + + maildir=yes + +fi + +done + + if test $maildir = no; then + for d in /var/mail /var/spool/mail /usr/spool/mail; do + if test -d "$d"; then + maildir=yes + cat >>confdefs.h <>confdefs.h <>confdefs.h <<_ACEOF +#define HAVE_LOGIN_CAP_H 1 +_ACEOF + LOGINCAP_USAGE='[-c class|-] '; LCMAN=1 + case "$OS" in + freebsd|netbsd) + SUDO_LIBS="${SUDO_LIBS} -lutil" + SUDOERS_LIBS="${SUDOERS_LIBS} -lutil" + ;; + esac + +fi + +done + +fi +if test ${with_project-'no'} != "no"; then + ac_fn_c_check_header_mongrel "$LINENO" "project.h" "ac_cv_header_project_h" "$ac_includes_default" +if test "x$ac_cv_header_project_h" = xyes; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for setproject in -lproject" >&5 +$as_echo_n "checking for setproject in -lproject... " >&6; } +if ${ac_cv_lib_project_setproject+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lproject $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char setproject (); +int +main () +{ +return setproject (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_project_setproject=yes +else + ac_cv_lib_project_setproject=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_project_setproject" >&5 +$as_echo "$ac_cv_lib_project_setproject" >&6; } +if test "x$ac_cv_lib_project_setproject" = xyes; then : + + $as_echo "#define HAVE_PROJECT_H 1" >>confdefs.h + + SUDO_LIBS="${SUDO_LIBS} -lproject" + +fi + + +fi + + +fi +ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" +if test "x$ac_cv_type_mode_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 +$as_echo_n "checking for uid_t in sys/types.h... " >&6; } +if ${ac_cv_type_uid_t+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "uid_t" >/dev/null 2>&1; then : + ac_cv_type_uid_t=yes +else + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 +$as_echo "$ac_cv_type_uid_t" >&6; } +if test $ac_cv_type_uid_t = no; then + +$as_echo "#define uid_t int" >>confdefs.h + + +$as_echo "#define gid_t int" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "__signed char" "ac_cv_type___signed_char" "$ac_includes_default" +if test "x$ac_cv_type___signed_char" = xyes; then : + +else + ac_fn_c_check_type "$LINENO" "signed char" "ac_cv_type_signed_char" "$ac_includes_default" +if test "x$ac_cv_type_signed_char" = xyes; then : + $as_echo "#define __signed signed" >>confdefs.h + +else + $as_echo "#define __signed /**/" >>confdefs.h + +fi + +fi + +ac_fn_c_check_type "$LINENO" "sig_atomic_t" "ac_cv_type_sig_atomic_t" "#include +#include +" +if test "x$ac_cv_type_sig_atomic_t" = xyes; then : + +else + $as_echo "#define sig_atomic_t int" >>confdefs.h + +fi + +ac_fn_c_check_type "$LINENO" "sigaction_t" "ac_cv_type_sigaction_t" "#include +#include +" +if test "x$ac_cv_type_sigaction_t" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_SIGACTION_T 1 +_ACEOF + + +fi + +ac_fn_c_check_type "$LINENO" "struct timespec" "ac_cv_type_struct_timespec" "#include +#if TIME_WITH_SYS_TIME +# include +#endif +#include +" +if test "x$ac_cv_type_struct_timespec" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_TIMESPEC 1 +_ACEOF + + +fi + +ac_fn_c_check_type "$LINENO" "struct in6_addr" "ac_cv_type_struct_in6_addr" "#include +#include +" +if test "x$ac_cv_type_struct_in6_addr" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_IN6_ADDR 1 +_ACEOF + + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long long int" >&5 +$as_echo_n "checking for long long int... " >&6; } +if ${ac_cv_type_long_long_int+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + /* For now, do not test the preprocessor; as of 2007 there are too many + implementations with broken preprocessors. Perhaps this can + be revisited in 2012. In the meantime, code should not expect + #if to work with literals wider than 32 bits. */ + /* Test literals. */ + long long int ll = 9223372036854775807ll; + long long int nll = -9223372036854775807LL; + unsigned long long int ull = 18446744073709551615ULL; + /* Test constant expressions. */ + typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) + ? 1 : -1)]; + typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63; +int +main () +{ +/* Test availability of runtime routines for shift and division. */ + long long int llmax = 9223372036854775807ll; + unsigned long long int ullmax = 18446744073709551615ull; + return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) + | (llmax / ll) | (llmax % ll) + | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) + | (ullmax / ull) | (ullmax % ull)); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if test "$cross_compiling" = yes; then : + ac_cv_type_long_long_int=yes +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #ifndef LLONG_MAX # define HALF \ (1LL << (sizeof (long long int) * CHAR_BIT - 2)) # define LLONG_MAX (HALF - 1 + HALF) @@ -14374,7 +15965,7 @@ $as_echo "#define HAVE_LONG_LONG_INT 1" >>confdefs.h # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long int" >&5 $as_echo_n "checking size of long int... " >&6; } -if test "${ac_cv_sizeof_long_int+set}" = set; then : +if ${ac_cv_sizeof_long_int+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long int))" "ac_cv_sizeof_long_int" "$ac_includes_default"; then : @@ -14383,9 +15974,8 @@ else if test "$ac_cv_type_long_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (long int) -See \`config.log' for more details." "$LINENO" 5; }; } +as_fn_error 77 "cannot compute sizeof (long int) +See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_long_int=0 fi @@ -14402,241 +15992,320 @@ cat >>confdefs.h <<_ACEOF _ACEOF -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for size_t" >&5 -$as_echo_n "checking for size_t... " >&6; } -if test "${sudo_cv_type_size_t+set}" = set; then : - $as_echo_n "(cached) " >&6 +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if STDC_HEADERS -#include -#endif -#if HAVE_UNISTD_H -#include -#endif + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int _ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "size_t" >/dev/null 2>&1; then : - sudo_cv_type_size_t=yes + +fi + +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "dev_t" "ac_cv_type_dev_t" "$ac_includes_default" +if test "x$ac_cv_type_dev_t" = xyes; then : + else - sudo_cv_type_size_t=no + +cat >>confdefs.h <<_ACEOF +#define dev_t int +_ACEOF + fi -rm -f conftest* + +ac_fn_c_check_type "$LINENO" "ino_t" "ac_cv_type_ino_t" "$ac_includes_default" +if test "x$ac_cv_type_ino_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ino_t unsigned int +_ACEOF fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_type_size_t" >&5 -$as_echo "$sudo_cv_type_size_t" >&6; } -if test $sudo_cv_type_size_t = no; then -$as_echo "#define size_t int" >>confdefs.h +ac_fn_c_check_type "$LINENO" "socklen_t" "ac_cv_type_socklen_t" " +$ac_includes_default +#include +" +if test "x$ac_cv_type_socklen_t" = xyes; then : + +else + $as_echo "#define socklen_t unsigned int" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5 -$as_echo_n "checking for ssize_t... " >&6; } -if test "${sudo_cv_type_ssize_t+set}" = set; then : + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking max length of uid_t" >&5 +$as_echo_n "checking max length of uid_t... " >&6; } +if ${sudo_cv_uid_t_len+:} false; then : $as_echo_n "(cached) " >&6 +else + rm -f conftestdata +if test "$cross_compiling" = yes; then : + sudo_cv_uid_t_len=10 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include #include -#if STDC_HEADERS -#include -#endif -#if HAVE_UNISTD_H -#include -#endif +#include +#include +#include +#include +main() { + FILE *f; + char b[1024]; + uid_t u = (uid_t) -1; + + if ((f = fopen("conftestdata", "w")) == NULL) + exit(1); + + (void) sprintf(b, "%lu", (unsigned long) u); + (void) fprintf(f, "%d\n", strlen(b)); + (void) fclose(f); + exit(0); +} _ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "ssize_t" >/dev/null 2>&1; then : - sudo_cv_type_ssize_t=yes +if ac_fn_c_try_run "$LINENO"; then : + sudo_cv_uid_t_len=`cat conftestdata` else - sudo_cv_type_ssize_t=no + sudo_cv_uid_t_len=10 fi -rm -f conftest* +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + +fi + +rm -f conftestdata +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_uid_t_len" >&5 +$as_echo "$sudo_cv_uid_t_len" >&6; } + +cat >>confdefs.h <<_ACEOF +#define MAX_UID_T_LEN $sudo_cv_uid_t_len +_ACEOF + + + + ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " #include + #include + +" +if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then : + +$as_echo "#define HAVE_STRUCT_SOCKADDR_SA_LEN 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_type_ssize_t" >&5 -$as_echo "$sudo_cv_type_ssize_t" >&6; } -if test $sudo_cv_type_ssize_t = no; then -$as_echo "#define ssize_t int" >>confdefs.h + +_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $OSDEFS" +if test $ac_cv_header_utmpx_h = "yes"; then + ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_id" "ac_cv_member_struct_utmpx_ut_id" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmpx_ut_id" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMPX_UT_ID 1 +_ACEOF + fi +ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_pid" "ac_cv_member_struct_utmpx_ut_pid" " + #include + #include -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dev_t" >&5 -$as_echo_n "checking for dev_t... " >&6; } -if test "${sudo_cv_type_dev_t+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if STDC_HEADERS -#include -#endif -#if HAVE_UNISTD_H -#include -#endif +" +if test "x$ac_cv_member_struct_utmpx_ut_pid" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMPX_UT_PID 1 _ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "dev_t" >/dev/null 2>&1; then : - sudo_cv_type_dev_t=yes -else - sudo_cv_type_dev_t=no + + fi -rm -f conftest* +ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_tv" "ac_cv_member_struct_utmpx_ut_tv" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmpx_ut_tv" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMPX_UT_TV 1 +_ACEOF + + +fi +ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_type" "ac_cv_member_struct_utmpx_ut_type" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmpx_ut_type" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMPX_UT_TYPE 1 +_ACEOF + + +fi + + ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_exit.__e_termination" "ac_cv_member_struct_utmpx_ut_exit___e_termination" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmpx_ut_exit___e_termination" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMPX_UT_EXIT___E_TERMINATION 1 +_ACEOF + +$as_echo "#define HAVE_STRUCT_UTMPX_UT_EXIT 1" >>confdefs.h + +else + + ac_fn_c_check_member "$LINENO" "struct utmpx" "ut_exit.e_termination" "ac_cv_member_struct_utmpx_ut_exit_e_termination" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmpx_ut_exit_e_termination" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION 1 +_ACEOF + +$as_echo "#define HAVE_STRUCT_UTMPX_UT_EXIT 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_type_dev_t" >&5 -$as_echo "$sudo_cv_type_dev_t" >&6; } -if test $sudo_cv_type_dev_t = no; then -$as_echo "#define dev_t int" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ino_t" >&5 -$as_echo_n "checking for ino_t... " >&6; } -if test "${sudo_cv_type_ino_t+set}" = set; then : - $as_echo_n "(cached) " >&6 else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if STDC_HEADERS -#include -#endif -#if HAVE_UNISTD_H -#include -#endif + ac_fn_c_check_member "$LINENO" "struct utmp" "ut_id" "ac_cv_member_struct_utmp_ut_id" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmp_ut_id" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMP_UT_ID 1 _ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "ino_t" >/dev/null 2>&1; then : - sudo_cv_type_ino_t=yes -else - sudo_cv_type_ino_t=no -fi -rm -f conftest* + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_type_ino_t" >&5 -$as_echo "$sudo_cv_type_ino_t" >&6; } -if test $sudo_cv_type_ino_t = no; then +ac_fn_c_check_member "$LINENO" "struct utmp" "ut_pid" "ac_cv_member_struct_utmp_ut_pid" " + #include + #include -$as_echo "#define ino_t unsigned int" >>confdefs.h +" +if test "x$ac_cv_member_struct_utmp_ut_pid" = xyes; then : -fi +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMP_UT_PID 1 +_ACEOF -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking max length of uid_t" >&5 -$as_echo_n "checking max length of uid_t... " >&6; } -if test "${sudo_cv_uid_t_len+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - rm -f conftestdata -if test "$cross_compiling" = yes; then : - sudo_cv_uid_t_len=10 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -#include -main() { - FILE *f; - char b[1024]; - uid_t u = (uid_t) -1; +fi +ac_fn_c_check_member "$LINENO" "struct utmp" "ut_tv" "ac_cv_member_struct_utmp_ut_tv" " + #include + #include - if ((f = fopen("conftestdata", "w")) == NULL) - exit(1); +" +if test "x$ac_cv_member_struct_utmp_ut_tv" = xyes; then : - (void) sprintf(b, "%lu", (unsigned long) u); - (void) fprintf(f, "%d\n", strlen(b)); - (void) fclose(f); - exit(0); -} +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMP_UT_TV 1 _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - sudo_cv_uid_t_len=`cat conftestdata` -else - sudo_cv_uid_t_len=10 -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi fi +ac_fn_c_check_member "$LINENO" "struct utmp" "ut_type" "ac_cv_member_struct_utmp_ut_type" " + #include + #include -rm -f conftestdata -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv_uid_t_len" >&5 -$as_echo "$sudo_cv_uid_t_len" >&6; } +" +if test "x$ac_cv_member_struct_utmp_ut_type" = xyes; then : cat >>confdefs.h <<_ACEOF -#define MAX_UID_T_LEN $sudo_cv_uid_t_len +#define HAVE_STRUCT_UTMP_UT_TYPE 1 _ACEOF - - ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" " #include - #include +fi +ac_fn_c_check_member "$LINENO" "struct utmp" "ut_user" "ac_cv_member_struct_utmp_ut_user" " + #include + #include " -if test "x$ac_cv_member_struct_sockaddr_sa_len" = x""yes; then : +if test "x$ac_cv_member_struct_utmp_ut_user" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMP_UT_USER 1 +_ACEOF -$as_echo "#define HAVE_SA_LEN 1" >>confdefs.h fi + ac_fn_c_check_member "$LINENO" "struct utmp" "ut_exit.__e_termination" "ac_cv_member_struct_utmp_ut_exit___e_termination" " + #include + #include -case "$DEFS" in - *"RETSIGTYPE"*) ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of signal handlers" >&5 -$as_echo_n "checking return type of signal handlers... " >&6; } -if test "${ac_cv_type_signal+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include +" +if test "x$ac_cv_member_struct_utmp_ut_exit___e_termination" = xyes; then : -int -main () -{ -return *(signal (0, 0)) (0) == 1; - ; - return 0; -} +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_UTMP_UT_EXIT___E_TERMINATION 1 _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_type_signal=int + +$as_echo "#define HAVE_STRUCT_UTMP_UT_EXIT 1" >>confdefs.h + else - ac_cv_type_signal=void -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_signal" >&5 -$as_echo "$ac_cv_type_signal" >&6; } + + ac_fn_c_check_member "$LINENO" "struct utmp" "ut_exit.e_termination" "ac_cv_member_struct_utmp_ut_exit_e_termination" " + #include + #include + +" +if test "x$ac_cv_member_struct_utmp_ut_exit_e_termination" = xyes; then : cat >>confdefs.h <<_ACEOF -#define RETSIGTYPE $ac_cv_type_signal +#define HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION 1 _ACEOF -;; -esac +$as_echo "#define HAVE_STRUCT_UTMP_UT_EXIT 1" >>confdefs.h + +fi + + +fi + +fi +CFLAGS="$_CFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking type of array argument to getgroups" >&5 $as_echo_n "checking type of array argument to getgroups... " >&6; } -if test "${ac_cv_type_getgroups+set}" = set; then : +if ${ac_cv_type_getgroups+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -14702,7 +16371,7 @@ _ACEOF ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" -if test "x$ac_cv_type_size_t" = x""yes; then : +if test "x$ac_cv_type_size_t" = xyes; then : else @@ -14713,7 +16382,7 @@ _ACEOF fi ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups" -if test "x$ac_cv_func_getgroups" = x""yes; then : +if test "x$ac_cv_func_getgroups" = xyes; then : fi @@ -14724,7 +16393,7 @@ ac_save_LIBS=$LIBS if test $ac_cv_func_getgroups = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getgroups in -lbsd" >&5 $as_echo_n "checking for getgroups in -lbsd... " >&6; } -if test "${ac_cv_lib_bsd_getgroups+set}" = set; then : +if ${ac_cv_lib_bsd_getgroups+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -14758,7 +16427,7 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_getgroups" >&5 $as_echo "$ac_cv_lib_bsd_getgroups" >&6; } -if test "x$ac_cv_lib_bsd_getgroups" = x""yes; then : +if test "x$ac_cv_lib_bsd_getgroups" = xyes; then : GETGROUPS_LIB=-lbsd fi @@ -14769,7 +16438,7 @@ fi if test $ac_cv_func_getgroups = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working getgroups" >&5 $as_echo_n "checking for working getgroups... " >&6; } -if test "${ac_cv_func_getgroups_works+set}" = set; then : +if ${ac_cv_func_getgroups_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -14810,15 +16479,13 @@ $as_echo "#define HAVE_GETGROUPS 1" >>confdefs.h fi LIBS=$ac_save_LIBS -for ac_func in strchr strrchr memchr memcpy memset sysconf tzset \ - strftime setrlimit initgroups getgroups fstat gettimeofday \ - regcomp setlocale getaddrinfo setenv vhangup \ - mbr_check_membership setrlimit64 +for ac_func in glob strrchr sysconf tzset strftime setenv \ + regcomp setlocale nl_langinfo mbr_check_membership \ + setrlimit64 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -14826,10 +16493,24 @@ _ACEOF fi done +ac_fn_c_check_func "$LINENO" "getgrouplist" "ac_cv_func_getgrouplist" +if test "x$ac_cv_func_getgrouplist" = xyes; then : + $as_echo "#define HAVE_GETGROUPLIST 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" getgrouplist.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS getgrouplist.$ac_objext" + ;; +esac + +fi + + for ac_func in getline do : ac_fn_c_check_func "$LINENO" "getline" "ac_cv_func_getline" -if test "x$ac_cv_func_getline" = x""yes; then : +if test "x$ac_cv_func_getline" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETLINE 1 _ACEOF @@ -14845,7 +16526,7 @@ esac for ac_func in fgetln do : ac_fn_c_check_func "$LINENO" "fgetln" "ac_cv_func_fgetln" -if test "x$ac_cv_func_fgetln" = x""yes; then : +if test "x$ac_cv_func_fgetln" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FGETLN 1 _ACEOF @@ -14857,73 +16538,51 @@ done fi done -for ac_func in setsid -do : - ac_fn_c_check_func "$LINENO" "setsid" "ac_cv_func_setsid" -if test "x$ac_cv_func_setsid" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SETSID 1 -_ACEOF - -else - - case " $LIBOBJS " in - *" setsid.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS setsid.$ac_objext" - ;; -esac +O_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" +ac_fn_c_check_func "$LINENO" "__sprintf_chk" "ac_cv_func___sprintf_chk" +if test "x$ac_cv_func___sprintf_chk" = xyes; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether setpgrp takes no argument" >&5 -$as_echo_n "checking whether setpgrp takes no argument... " >&6; } -if test "${ac_cv_func_setpgrp_void+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - as_fn_error "cannot check setpgrp when cross compiling" "$LINENO" 5 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -$ac_includes_default + int main () { -/* If this system has a BSD-style setpgrp which takes arguments, - setpgrp(1, 1) will fail with ESRCH and return -1, in that case - exit successfully. */ - return setpgrp (1,1) != -1; +char buf[4]; (void)sprintf(buf, "%s", "foo"); ; return 0; } _ACEOF -if ac_fn_c_try_run "$LINENO"; then : - ac_cv_func_setpgrp_void=no -else - ac_cv_func_setpgrp_void=yes -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - +if ac_fn_c_try_link "$LINENO"; then : + OSDEFS="${OSDEFS} -D_FORTIFY_SOURCE=2" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_setpgrp_void" >&5 -$as_echo "$ac_cv_func_setpgrp_void" >&6; } -if test $ac_cv_func_setpgrp_void = yes; then - -$as_echo "#define SETPGRP_VOID 1" >>confdefs.h +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext fi +CPPFLAGS="$O_CPPFLAGS" +utmp_style=LEGACY +for ac_func in 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" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + utmp_style=POSIX; break fi done - -for ac_func in sysctl getutid getutxid +if test "$utmp_style" = "LEGACY"; then + for ac_func in getttyent ttyslot do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -14931,20 +16590,98 @@ _ACEOF fi done +fi + +for ac_func in sysctl +do : + ac_fn_c_check_func "$LINENO" "sysctl" "ac_cv_func_sysctl" +if test "x$ac_cv_func_sysctl" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYSCTL 1 +_ACEOF + ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "ki_tdev" "ac_cv_member_struct_kinfo_proc_ki_tdev" " + #include + #include + #include + +" +if test "x$ac_cv_member_struct_kinfo_proc_ki_tdev" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_KINFO_PROC_KI_TDEV 1 +_ACEOF + + +else + + ac_fn_c_check_member "$LINENO" "struct kinfo_proc2" "p_tdev" "ac_cv_member_struct_kinfo_proc2_p_tdev" " + #include + #include + +" +if test "x$ac_cv_member_struct_kinfo_proc2_p_tdev" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_KINFO_PROC2_P_TDEV 1 +_ACEOF + + +else + + ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "p_tdev" "ac_cv_member_struct_kinfo_proc_p_tdev" " + #include + #include + +" +if test "x$ac_cv_member_struct_kinfo_proc_p_tdev" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_KINFO_PROC_P_TDEV 1 +_ACEOF + + +else + + ac_fn_c_check_member "$LINENO" "struct kinfo_proc" "kp_eproc.e_tdev" "ac_cv_member_struct_kinfo_proc_kp_eproc_e_tdev" " + #include + #include + +" +if test "x$ac_cv_member_struct_kinfo_proc_kp_eproc_e_tdev" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV 1 +_ACEOF + + +fi + + +fi + + +fi + + +fi + + +fi +done + for ac_func in openpty do : ac_fn_c_check_func "$LINENO" "openpty" "ac_cv_func_openpty" -if test "x$ac_cv_func_openpty" = x""yes; then : +if test "x$ac_cv_func_openpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_OPENPTY 1 _ACEOF - for ac_header in util.h pty.h + for ac_header in libutil.h util.h pty.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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -14957,7 +16694,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openpty in -lutil" >&5 $as_echo_n "checking for openpty in -lutil... " >&6; } -if test "${ac_cv_lib_util_openpty+set}" = set; then : +if ${ac_cv_lib_util_openpty+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -14991,14 +16728,13 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_openpty" >&5 $as_echo "$ac_cv_lib_util_openpty" >&6; } -if test "x$ac_cv_lib_util_openpty" = x""yes; then : +if test "x$ac_cv_lib_util_openpty" = xyes; then : - for ac_header in util.h pty.h + for ac_header in libutil.h util.h pty.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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -15007,7 +16743,10 @@ fi done - SUDO_LIBS="${SUDO_LIBS} -lutil" + case "$SUDO_LIBS" in + *-lutil*) ;; + *) SUDO_LIBS="${SUDO_LIBS} -lutil";; + esac $as_echo "#define HAVE_OPENPTY 1" >>confdefs.h @@ -15016,7 +16755,7 @@ else for ac_func in _getpty do : ac_fn_c_check_func "$LINENO" "_getpty" "ac_cv_func__getpty" -if test "x$ac_cv_func__getpty" = x""yes; then : +if test "x$ac_cv_func__getpty" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE__GETPTY 1 _ACEOF @@ -15026,7 +16765,7 @@ else for ac_func in grantpt do : ac_fn_c_check_func "$LINENO" "grantpt" "ac_cv_func_grantpt" -if test "x$ac_cv_func_grantpt" = x""yes; then : +if test "x$ac_cv_func_grantpt" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GRANTPT 1 _ACEOF @@ -15034,7 +16773,7 @@ _ACEOF for ac_func in posix_openpt do : ac_fn_c_check_func "$LINENO" "posix_openpt" "ac_cv_func_posix_openpt" -if test "x$ac_cv_func_posix_openpt" = x""yes; then : +if test "x$ac_cv_func_posix_openpt" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSIX_OPENPT 1 _ACEOF @@ -15048,7 +16787,7 @@ else for ac_func in revoke do : ac_fn_c_check_func "$LINENO" "revoke" "ac_cv_func_revoke" -if test "x$ac_cv_func_revoke" = x""yes; then : +if test "x$ac_cv_func_revoke" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_REVOKE 1 _ACEOF @@ -15074,13 +16813,13 @@ done for ac_func in unsetenv do : ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv" -if test "x$ac_cv_func_unsetenv" = x""yes; then : +if test "x$ac_cv_func_unsetenv" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UNSETENV 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether unsetenv returns void" >&5 $as_echo_n "checking whether unsetenv returns void... " >&6; } -if test "${sudo_cv_func_unsetenv_void+set}" = set; then : +if ${sudo_cv_func_unsetenv_void+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : @@ -15123,9 +16862,9 @@ $as_echo "#define UNSETENV_VOID 1" >>confdefs.h fi done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether putenv has a const argument" >&5 -$as_echo_n "checking whether putenv has a const argument... " >&6; } -if test "${sudo_cv_func_putenv_const+set}" = set; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether putenv takes a const argument" >&5 +$as_echo_n "checking whether putenv takes a const argument... " >&6; } +if ${sudo_cv_func_putenv_const+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15152,7 +16891,10 @@ fi $as_echo "$sudo_cv_func_putenv_const" >&6; } if test $sudo_cv_func_putenv_const = yes; then -$as_echo "#define PUTENV_CONST 1" >>confdefs.h +$as_echo "#define PUTENV_CONST const" >>confdefs.h + + else + $as_echo "#define PUTENV_CONST /**/" >>confdefs.h fi @@ -15160,11 +16902,24 @@ if test -z "$SKIP_SETRESUID"; then for ac_func in setresuid do : ac_fn_c_check_func "$LINENO" "setresuid" "ac_cv_func_setresuid" -if test "x$ac_cv_func_setresuid" = x""yes; then : +if test "x$ac_cv_func_setresuid" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETRESUID 1 _ACEOF - SKIP_SETREUID=yes + + SKIP_SETREUID=yes + for ac_func in getresuid +do : + ac_fn_c_check_func "$LINENO" "getresuid" "ac_cv_func_getresuid" +if test "x$ac_cv_func_getresuid" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETRESUID 1 +_ACEOF + +fi +done + + fi done @@ -15173,7 +16928,7 @@ if test -z "$SKIP_SETREUID"; then for ac_func in setreuid do : ac_fn_c_check_func "$LINENO" "setreuid" "ac_cv_func_setreuid" -if test "x$ac_cv_func_setreuid" = x""yes; then : +if test "x$ac_cv_func_setreuid" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETREUID 1 _ACEOF @@ -15186,7 +16941,7 @@ if test -z "$SKIP_SETEUID"; then for ac_func in seteuid do : ac_fn_c_check_func "$LINENO" "seteuid" "ac_cv_func_seteuid" -if test "x$ac_cv_func_seteuid" = x""yes; then : +if test "x$ac_cv_func_seteuid" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SETEUID 1 _ACEOF @@ -15199,111 +16954,46 @@ if test X"$with_interfaces" != X"no"; then for ac_func in getifaddrs do : ac_fn_c_check_func "$LINENO" "getifaddrs" "ac_cv_func_getifaddrs" -if test "x$ac_cv_func_getifaddrs" = x""yes; then : +if test "x$ac_cv_func_getifaddrs" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETIFADDRS 1 _ACEOF for ac_func in freeifaddrs do : - ac_fn_c_check_func "$LINENO" "freeifaddrs" "ac_cv_func_freeifaddrs" -if test "x$ac_cv_func_freeifaddrs" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_FREEIFADDRS 1 -_ACEOF - -fi -done - -fi -done - -fi -if test -z "$BROKEN_GETCWD"; then - for ac_func in getcwd -do : - ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETCWD 1 -_ACEOF - -else - case " $LIBOBJS " in - *" $ac_func.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" - ;; -esac - -fi -done - - -fi -for ac_func in glob -do : - ac_fn_c_check_func "$LINENO" "glob" "ac_cv_func_glob" -if test "x$ac_cv_func_glob" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GLOB 1 -_ACEOF - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_BRACE and GLOB_TILDE in glob.h" >&5 -$as_echo_n "checking for GLOB_BRACE and GLOB_TILDE in glob.h... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -int i = GLOB_BRACE | GLOB_TILDE; (void)i; - ; - return 0; -} + ac_fn_c_check_func "$LINENO" "freeifaddrs" "ac_cv_func_freeifaddrs" +if test "x$ac_cv_func_freeifaddrs" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_FREEIFADDRS 1 _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - $as_echo "#define HAVE_EXTENDED_GLOB 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - case " $LIBOBJS " in - *" glob.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS glob.$ac_objext" - ;; -esac +fi +done - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done + +fi +if test -z "$BROKEN_GETCWD"; then + ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" +if test "x$ac_cv_func_getcwd" = xyes; then : + $as_echo "#define HAVE_GETCWD 1" >>confdefs.h + else case " $LIBOBJS " in - *" glob.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS glob.$ac_objext" + *" getcwd.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS getcwd.$ac_objext" ;; esac fi -done -for ac_func in lockf flock -do : - as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` -ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 -_ACEOF - break -fi -done -for ac_func in waitpid wait3 +fi +for ac_func in lockf flock 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -15315,15 +17005,14 @@ for ac_func in innetgr _innetgr 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF for ac_func in getdomainname do : ac_fn_c_check_func "$LINENO" "getdomainname" "ac_cv_func_getdomainname" -if test "x$ac_cv_func_getdomainname" = x""yes; then : +if test "x$ac_cv_func_getdomainname" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETDOMAINNAME 1 _ACEOF @@ -15337,7 +17026,7 @@ done for ac_func in utimes do : ac_fn_c_check_func "$LINENO" "utimes" "ac_cv_func_utimes" -if test "x$ac_cv_func_utimes" = x""yes; then : +if test "x$ac_cv_func_utimes" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_UTIMES 1 _ACEOF @@ -15345,8 +17034,7 @@ _ACEOF 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -15358,7 +17046,7 @@ else for ac_func in futime do : ac_fn_c_check_func "$LINENO" "futime" "ac_cv_func_futime" -if test "x$ac_cv_func_futime" = x""yes; then : +if test "x$ac_cv_func_futime" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FUTIME 1 _ACEOF @@ -15377,7 +17065,7 @@ done for ac_func in killpg do : ac_fn_c_check_func "$LINENO" "killpg" "ac_cv_func_killpg" -if test "x$ac_cv_func_killpg" = x""yes; then : +if test "x$ac_cv_func_killpg" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_KILLPG 1 _ACEOF @@ -15394,7 +17082,7 @@ done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fnmatch with FNM_CASEFOLD" >&5 $as_echo_n "checking for working fnmatch with FNM_CASEFOLD... " >&6; } -if test "${sudo_cv_func_fnmatch+set}" = set; then : +if ${sudo_cv_func_fnmatch+:} false; then : $as_echo_n "(cached) " >&6 else rm -f conftestdata; > conftestdata @@ -15430,10 +17118,12 @@ else ;; esac + COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }fnm_test" + fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for isblank" >&5 $as_echo_n "checking for isblank... " >&6; } -if test "${sudo_cv_func_isblank+set}" = set; then : +if ${sudo_cv_func_isblank+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15471,31 +17161,63 @@ esac fi -for ac_func in memrchr strerror strcasecmp sigaction strlcpy strlcat -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 +ac_fn_c_check_func "$LINENO" "memrchr" "ac_cv_func_memrchr" +if test "x$ac_cv_func_memrchr" = xyes; then : + $as_echo "#define HAVE_MEMRCHR 1" >>confdefs.h else case " $LIBOBJS " in - *" $ac_func.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" + *" memrchr.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS memrchr.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "pw_dup" "ac_cv_func_pw_dup" +if test "x$ac_cv_func_pw_dup" = xyes; then : + $as_echo "#define HAVE_PW_DUP 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" pw_dup.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS pw_dup.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "strlcpy" "ac_cv_func_strlcpy" +if test "x$ac_cv_func_strlcpy" = xyes; then : + $as_echo "#define HAVE_STRLCPY 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" strlcpy.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcpy.$ac_objext" + ;; +esac + +fi + +ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat" +if test "x$ac_cv_func_strlcat" = xyes; then : + $as_echo "#define HAVE_STRLCAT 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" strlcat.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strlcat.$ac_objext" ;; esac fi -done for ac_func in nanosleep do : ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep" -if test "x$ac_cv_func_nanosleep" = x""yes; then : +if test "x$ac_cv_func_nanosleep" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_NANOSLEEP 1 _ACEOF @@ -15505,7 +17227,7 @@ else # On Solaris, nanosleep is in librt { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5 $as_echo_n "checking for nanosleep in -lrt... " >&6; } -if test "${ac_cv_lib_rt_nanosleep+set}" = set; then : +if ${ac_cv_lib_rt_nanosleep+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -15539,8 +17261,8 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5 $as_echo "$ac_cv_lib_rt_nanosleep" >&6; } -if test "x$ac_cv_lib_rt_nanosleep" = x""yes; then : - LIBS="${LIBS} -lrt" +if test "x$ac_cv_lib_rt_nanosleep" = xyes; then : + REPLAY_LIBS="${REPLAY_LIBS} -lrt" else case " $LIBOBJS " in *" nanosleep.$ac_objext "* ) ;; @@ -15557,7 +17279,7 @@ done for ac_func in closefrom do : ac_fn_c_check_func "$LINENO" "closefrom" "ac_cv_func_closefrom" -if test "x$ac_cv_func_closefrom" = x""yes; then : +if test "x$ac_cv_func_closefrom" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_CLOSEFROM 1 _ACEOF @@ -15572,7 +17294,7 @@ esac ac_fn_c_check_decl "$LINENO" "F_CLOSEM" "ac_cv_have_decl_F_CLOSEM" " #include #include " -if test "x$ac_cv_have_decl_F_CLOSEM" = x""yes; then : +if test "x$ac_cv_have_decl_F_CLOSEM" = xyes; then : $as_echo "#define HAVE_FCNTL_CLOSEM 1" >>confdefs.h fi @@ -15581,22 +17303,22 @@ fi fi done -for ac_func in mkstemps +for ac_func in mkstemps mkdtemp do : - ac_fn_c_check_func "$LINENO" "mkstemps" "ac_cv_func_mkstemps" -if test "x$ac_cv_func_mkstemps" = x""yes; then : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF -#define HAVE_MKSTEMPS 1 +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else - SUDO_OBJS="${SUDO_OBJS} mkstemps.o" + for ac_func in random lrand48 do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -15604,6 +17326,12 @@ _ACEOF fi done + case " $LIBOBJS " in + *" mktemp.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS mktemp.$ac_objext" + ;; +esac + fi done @@ -15612,8 +17340,7 @@ for ac_func in snprintf vsnprintf asprintf vasprintf 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -15625,18 +17352,18 @@ done if test X"$ac_cv_type_struct_timespec" != X"no"; then ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim" "ac_cv_member_struct_stat_st_mtim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtim" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_mtim" = xyes; then : $as_echo "#define HAVE_ST_MTIM 1" >>confdefs.h ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.st__tim" "ac_cv_member_struct_stat_st_mtim_st__tim" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtim_st__tim" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_mtim_st__tim" = xyes; then : $as_echo "#define HAVE_ST__TIM 1" >>confdefs.h fi else ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimespec" "ac_cv_member_struct_stat_st_mtimespec" "$ac_includes_default" -if test "x$ac_cv_member_struct_stat_st_mtimespec" = x""yes; then : +if test "x$ac_cv_member_struct_stat_st_mtimespec" = xyes; then : $as_echo "#define HAVE_ST_MTIMESPEC 1" >>confdefs.h fi @@ -15681,6 +17408,20 @@ rm -f core conftest.err conftest.$ac_objext \ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext +ac_fn_c_check_member "$LINENO" "struct dirent" "d_type" "ac_cv_member_struct_dirent_d_type" " +$ac_includes_default +#include <$ac_header_dirent> + +" +if test "x$ac_cv_member_struct_dirent_d_type" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_DIRENT_D_TYPE 1 +_ACEOF + + +fi + if test -n "$NEED_SNPRINTF"; then case " $LIBOBJS " in *" snprintf.$ac_objext "* ) ;; @@ -15690,97 +17431,33 @@ esac fi ac_fn_c_check_func "$LINENO" "socket" "ac_cv_func_socket" -if test "x$ac_cv_func_socket" = x""yes; then : +if test "x$ac_cv_func_socket" = xyes; then : else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 -$as_echo_n "checking for socket in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_socket+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char socket (); -int -main () -{ -return socket (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_socket=yes -else - ac_cv_lib_socket_socket=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 -$as_echo "$ac_cv_lib_socket_socket" >&6; } -if test "x$ac_cv_lib_socket_socket" = x""yes; then : - NET_LIBS="${NET_LIBS} -lsocket"; LIBS="${LIBS} -lsocket" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -linet" >&5 -$as_echo_n "checking for socket in -linet... " >&6; } -if test "${ac_cv_lib_inet_socket+set}" = set; then : + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[^ ]*//'`" + + _sudo_check_lib_extras=`echo "$extralibs"|sed -e 's/ *//g' -e 's/-l/_/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -l$lib${5+ }$extralibs" >&5 +$as_echo_n "checking for socket in -l$lib${5+ }$extralibs... " >&6; } + if { as_var=sudo_cv_lib_$lib''_socket$_sudo_check_lib_extras; eval \${$as_var+:} false; }; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-linet $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char socket (); -int -main () -{ -return socket (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_inet_socket=yes -else - ac_cv_lib_inet_socket=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_socket" >&5 -$as_echo "$ac_cv_lib_inet_socket" >&6; } -if test "x$ac_cv_lib_inet_socket" = x""yes; then : - NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to find socket() trying -lsocket -lnsl" >&5 -$as_echo "$as_me: WARNING: unable to find socket() trying -lsocket -lnsl" >&2;} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 -$as_echo_n "checking for socket in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_socket_lnsl+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket -lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + SUDO_CHECK_LIB_OLIBS="$LIBS" + LIBS="$LIBS -l$lib${5+ }$extralibs" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -15799,122 +17476,64 @@ return socket (); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_socket_lnsl=yes + eval sudo_cv_lib_$lib''_socket$_sudo_check_lib_extras=yes else - ac_cv_lib_socket_socket_lnsl=no + eval sudo_cv_lib_$lib''_socket$_sudo_check_lib_extras=no + fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket_lnsl" >&5 -$as_echo "$ac_cv_lib_socket_socket_lnsl" >&6; } -if test "x$ac_cv_lib_socket_socket_lnsl" = x""yes; then : - NET_LIBS="${NET_LIBS} -lsocket -lnsl"; LIBS="${LIBS} -lsocket -lnsl" -fi + LIBS="$SUDO_CHECK_LIB_OLIBS" fi -fi + if eval test \$sudo_cv_lib_$lib''_socket$_sudo_check_lib_extras = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + fi + + done fi ac_fn_c_check_func "$LINENO" "inet_addr" "ac_cv_func_inet_addr" -if test "x$ac_cv_func_inet_addr" = x""yes; then : +if test "x$ac_cv_func_inet_addr" = xyes; then : else - ac_fn_c_check_func "$LINENO" "__inet_addr" "ac_cv_func___inet_addr" -if test "x$ac_cv_func___inet_addr" = x""yes; then : -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_addr in -lnsl" >&5 -$as_echo_n "checking for inet_addr in -lnsl... " >&6; } -if test "${ac_cv_lib_nsl_inet_addr+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + ac_fn_c_check_func "$LINENO" "__inet_addr" "ac_cv_func___inet_addr" +if test "x$ac_cv_func___inet_addr" = xyes; then : -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char inet_addr (); -int -main () -{ -return inet_addr (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_nsl_inet_addr=yes -else - ac_cv_lib_nsl_inet_addr=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_inet_addr" >&5 -$as_echo "$ac_cv_lib_nsl_inet_addr" >&6; } -if test "x$ac_cv_lib_nsl_inet_addr" = x""yes; then : - NET_LIBS="${NET_LIBS} -lnsl"; LIBS="${LIBS} -lnsl" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_addr in -linet" >&5 -$as_echo_n "checking for inet_addr in -linet... " >&6; } -if test "${ac_cv_lib_inet_inet_addr+set}" = set; then : - $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-linet $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char inet_addr (); -int -main () -{ -return inet_addr (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_inet_inet_addr=yes -else - ac_cv_lib_inet_inet_addr=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_inet_addr" >&5 -$as_echo "$ac_cv_lib_inet_inet_addr" >&6; } -if test "x$ac_cv_lib_inet_inet_addr" = x""yes; then : - NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unable to find inet_addr() trying -lsocket -lnsl" >&5 -$as_echo "$as_me: WARNING: unable to find inet_addr() trying -lsocket -lnsl" >&2;} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_addr in -lsocket" >&5 -$as_echo_n "checking for inet_addr in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_inet_addr_lnsl+set}" = set; then : + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[^ ]*//'`" + + _sudo_check_lib_extras=`echo "$extralibs"|sed -e 's/ *//g' -e 's/-l/_/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_addr in -l$lib${5+ }$extralibs" >&5 +$as_echo_n "checking for inet_addr in -l$lib${5+ }$extralibs... " >&6; } + if { as_var=sudo_cv_lib_$lib''_inet_addr$_sudo_check_lib_extras; eval \${$as_var+:} false; }; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket -lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + + SUDO_CHECK_LIB_OLIBS="$LIBS" + LIBS="$LIBS -l$lib${5+ }$extralibs" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -15933,79 +17552,62 @@ return inet_addr (); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_inet_addr_lnsl=yes + eval sudo_cv_lib_$lib''_inet_addr$_sudo_check_lib_extras=yes else - ac_cv_lib_socket_inet_addr_lnsl=no + eval sudo_cv_lib_$lib''_inet_addr$_sudo_check_lib_extras=no + fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_inet_addr_lnsl" >&5 -$as_echo "$ac_cv_lib_socket_inet_addr_lnsl" >&6; } -if test "x$ac_cv_lib_socket_inet_addr_lnsl" = x""yes; then : - NET_LIBS="${NET_LIBS} -lsocket -lnsl"; LIBS="${LIBS} -lsocket -lnsl" -fi - -fi + LIBS="$SUDO_CHECK_LIB_OLIBS" fi -fi - -fi + if eval test \$sudo_cv_lib_$lib''_inet_addr$_sudo_check_lib_extras = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } -ac_fn_c_check_func "$LINENO" "syslog" "ac_cv_func_syslog" -if test "x$ac_cv_func_syslog" = x""yes; then : + fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslog in -lsocket" >&5 -$as_echo_n "checking for syslog in -lsocket... " >&6; } -if test "${ac_cv_lib_socket_syslog+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsocket $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + done -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char syslog (); -int -main () -{ -return syslog (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_socket_syslog=yes -else - ac_cv_lib_socket_syslog=no fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS + + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_syslog" >&5 -$as_echo "$ac_cv_lib_socket_syslog" >&6; } -if test "x$ac_cv_lib_socket_syslog" = x""yes; then : - NET_LIBS="${NET_LIBS} -lsocket"; LIBS="${LIBS} -lsocket" + +ac_fn_c_check_func "$LINENO" "syslog" "ac_cv_func_syslog" +if test "x$ac_cv_func_syslog" = xyes; then : + else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslog in -lnsl" >&5 -$as_echo_n "checking for syslog in -lnsl... " >&6; } -if test "${ac_cv_lib_nsl_syslog+set}" = set; then : + + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[^ ]*//'`" + + _sudo_check_lib_extras=`echo "$extralibs"|sed -e 's/ *//g' -e 's/-l/_/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslog in -l$lib${5+ }$extralibs" >&5 +$as_echo_n "checking for syslog in -l$lib${5+ }$extralibs... " >&6; } + if { as_var=sudo_cv_lib_$lib''_syslog$_sudo_check_lib_extras; eval \${$as_var+:} false; }; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lnsl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + + SUDO_CHECK_LIB_OLIBS="$LIBS" + LIBS="$LIBS -l$lib${5+ }$extralibs" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -16024,27 +17626,65 @@ return syslog (); } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_nsl_syslog=yes + eval sudo_cv_lib_$lib''_syslog$_sudo_check_lib_extras=yes else - ac_cv_lib_nsl_syslog=no + eval sudo_cv_lib_$lib''_syslog$_sudo_check_lib_extras=no + fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS + LIBS="$SUDO_CHECK_LIB_OLIBS" + +fi + + if eval test \$sudo_cv_lib_$lib''_syslog$_sudo_check_lib_extras = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + fi + + done + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_syslog" >&5 -$as_echo "$ac_cv_lib_nsl_syslog" >&6; } -if test "x$ac_cv_lib_nsl_syslog" = x""yes; then : - NET_LIBS="${NET_LIBS} -lnsl"; LIBS="${LIBS} -lnsl" + +for ac_func in getaddrinfo +do : + ac_fn_c_check_func "$LINENO" "getaddrinfo" "ac_cv_func_getaddrinfo" +if test "x$ac_cv_func_getaddrinfo" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETADDRINFO 1 +_ACEOF + else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslog in -linet" >&5 -$as_echo_n "checking for syslog in -linet... " >&6; } -if test "${ac_cv_lib_inet_syslog+set}" = set; then : + + found=no + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[^ ]*//'`" + + _sudo_check_lib_extras=`echo "$extralibs"|sed -e 's/ *//g' -e 's/-l/_/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for getaddrinfo in -l$lib${5+ }$extralibs" >&5 +$as_echo_n "checking for getaddrinfo in -l$lib${5+ }$extralibs... " >&6; } + if { as_var=sudo_cv_lib_$lib''_getaddrinfo$_sudo_check_lib_extras; eval \${$as_var+:} false; }; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-linet $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + + SUDO_CHECK_LIB_OLIBS="$LIBS" + LIBS="$LIBS -l$lib${5+ }$extralibs" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. @@ -16053,40 +17693,50 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char syslog (); +char getaddrinfo (); int main () { -return syslog (); +return getaddrinfo (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_inet_syslog=yes + eval sudo_cv_lib_$lib''_getaddrinfo$_sudo_check_lib_extras=yes else - ac_cv_lib_inet_syslog=no + eval sudo_cv_lib_$lib''_getaddrinfo$_sudo_check_lib_extras=no + fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inet_syslog" >&5 -$as_echo "$ac_cv_lib_inet_syslog" >&6; } -if test "x$ac_cv_lib_inet_syslog" = x""yes; then : - NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet" -fi + LIBS="$SUDO_CHECK_LIB_OLIBS" fi -fi + if eval test \$sudo_cv_lib_$lib''_getaddrinfo$_sudo_check_lib_extras = "yes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; found=yes; break + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + fi + + done + if test X"$found" != X"no"; then + $as_echo "#define HAVE_GETADDRINFO 1" >>confdefs.h + + fi fi +done for ac_func in getprogname do : ac_fn_c_check_func "$LINENO" "getprogname" "ac_cv_func_getprogname" -if test "x$ac_cv_func_getprogname" = x""yes; then : +if test "x$ac_cv_func_getprogname" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETPROGNAME 1 _ACEOF @@ -16095,7 +17745,7 @@ else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __progname" >&5 $as_echo_n "checking for __progname... " >&6; } - if test "${sudo_cv___progname+set}" = set; then : + if ${sudo_cv___progname+:} false; then : $as_echo_n "(cached) " >&6 else @@ -16136,411 +17786,177 @@ $as_echo "$sudo_cv___progname" >&6; } fi done - -for ac_func in strsignal -do : - ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal" -if test "x$ac_cv_func_strsignal" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_STRSIGNAL 1 -_ACEOF - -else - - case " $LIBOBJS " in - *" strsignal.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS strsignal.$ac_objext" - ;; -esac - - HAVE_SIGLIST="false" - ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" " -$ac_includes_default -#include - -" -if test "x$ac_cv_have_decl_sys_siglist" = x""yes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_SYS_SIGLIST $ac_have_decl -_ACEOF -if test $ac_have_decl = 1; then : - - HAVE_SIGLIST="true" - break - -fi -ac_fn_c_check_decl "$LINENO" "_sys_siglist" "ac_cv_have_decl__sys_siglist" " -$ac_includes_default -#include - -" -if test "x$ac_cv_have_decl__sys_siglist" = x""yes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL__SYS_SIGLIST $ac_have_decl -_ACEOF -if test $ac_have_decl = 1; then : - - HAVE_SIGLIST="true" - break - -fi -ac_fn_c_check_decl "$LINENO" "__sys_siglist" "ac_cv_have_decl___sys_siglist" " -$ac_includes_default -#include - -" -if test "x$ac_cv_have_decl___sys_siglist" = x""yes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL___SYS_SIGLIST $ac_have_decl -_ACEOF -if test $ac_have_decl = 1; then : - - HAVE_SIGLIST="true" - break - -fi - - if test "$HAVE_SIGLIST" != "true"; then - case " $LIBOBJS " in - *" siglist.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS siglist.$ac_objext" - ;; -esac - - fi - -fi -done - - -if test ${with_netsvc-"no"} != "no"; then - cat >>confdefs.h <>confdefs.h <&5 -$as_echo_n "checking for main in -ldl... " >&6; } -if test "${ac_cv_lib_dl_main+set}" = set; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __func__" >&5 +$as_echo_n "checking for __func__... " >&6; } +if ${sudo_cv___func__+:} false; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ - int main () { -return main (); +(void)puts(__func__); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_main=yes + sudo_cv___func__=yes else - ac_cv_lib_dl_main=no + sudo_cv___func__=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5 -$as_echo "$ac_cv_lib_dl_main" >&6; } -if test "x$ac_cv_lib_dl_main" = x""yes; then : - SUDO_LIBS="${SUDO_LIBS} -lpam -ldl" -else - SUDO_LIBS="${SUDO_LIBS} -lpam" -fi - - ac_cv_lib_dl=ac_cv_lib_dl_main - ;; - esac - - for ac_header in security/pam_appl.h pam/pam_appl.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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - with_pam=yes; break -fi - -done - - if test "$with_pam" = "yes"; then - $as_echo "#define HAVE_PAM 1" >>confdefs.h - - AUTH_OBJS="$AUTH_OBJS pam.o"; - AUTH_EXCL=PAM - - -# Check whether --with-pam-login was given. -if test "${with_pam_login+set}" = set; then : - withval=$with_pam_login; case $with_pam_login in - yes) $as_echo "#define HAVE_PAM_LOGIN 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use PAM login" >&5 -$as_echo_n "checking whether to use PAM login... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ;; - no) ;; - *) as_fn_error "\"--with-pam-login does not take an argument.\"" "$LINENO" 5 - ;; - esac -fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use PAM session support" >&5 -$as_echo_n "checking whether to use PAM session support... " >&6; } - # Check whether --enable-pam_session was given. -if test "${enable_pam_session+set}" = set; then : - enableval=$enable_pam_session; case "$enableval" in - yes) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - ;; - no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - -$as_echo "#define NO_PAM_SESSION /**/" >>confdefs.h - - ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unknown argument to --enable-pam-session: $enableval" >&5 -$as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-pam-session: $enableval" >&2;} - ;; - esac -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv___func__" >&5 +$as_echo "$sudo_cv___func__" >&6; } +if test "$sudo_cv___func__" = "yes"; then + $as_echo "#define HAVE___FUNC__ 1" >>confdefs.h - case $host in - *-*-linux*|*-*-solaris*) - # dgettext() may be defined to dgettext_libintl in the - # header file, so first check that it links w/ additional - # libs, then try with -lintl - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -(void)dgettext((char *)0, (char *)0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - $as_echo "#define HAVE_DGETTEXT 1" >>confdefs.h - -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dgettext in -lintl" >&5 -$as_echo_n "checking for dgettext in -lintl... " >&6; } -if test "${ac_cv_lib_intl_dgettext+set}" = set; then : +elif test -n "$GCC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for __FUNCTION__" >&5 +$as_echo_n "checking for __FUNCTION__... " >&6; } + if ${sudo_cv___FUNCTION__+:} false; then : $as_echo_n "(cached) " >&6 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lintl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dgettext (); int main () { -return dgettext (); +(void)puts(__FUNCTION__); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_intl_dgettext=yes + sudo_cv___FUNCTION__=yes else - ac_cv_lib_intl_dgettext=no + sudo_cv___FUNCTION__=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_intl_dgettext" >&5 -$as_echo "$ac_cv_lib_intl_dgettext" >&6; } -if test "x$ac_cv_lib_intl_dgettext" = x""yes; then : - LIBS="${LIBS} -lintl" - $as_echo "#define HAVE_DGETTEXT 1" >>confdefs.h -fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sudo_cv___FUNCTION__" >&5 +$as_echo "$sudo_cv___FUNCTION__" >&6; } + if test "$sudo_cv___FUNCTION__" = "yes"; then + $as_echo "#define HAVE___FUNC__ 1" >>confdefs.h -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - ;; - esac - fi -fi -if test ${with_aixauth-'no'} != "no"; then - if test X"$with_aixauth" != X"maybe" -o X"$AUTH_EXCL" = X""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: using AIX general authentication" >&5 -$as_echo "$as_me: using AIX general authentication" >&6;} - $as_echo "#define HAVE_AIXAUTH 1" >>confdefs.h +$as_echo "#define __func__ __FUNCTION__" >>confdefs.h - AUTH_OBJS="$AUTH_OBJS aix_auth.o"; - SUDO_LIBS="${SUDO_LIBS} -ls" - AUTH_EXCL=AIX_AUTH fi fi -if test ${with_bsdauth-'no'} != "no"; then - ac_fn_c_check_header_mongrel "$LINENO" "bsd_auth.h" "ac_cv_header_bsd_auth_h" "$ac_includes_default" -if test "x$ac_cv_header_bsd_auth_h" = x""yes; then : - $as_echo "#define HAVE_BSD_AUTH_H 1" >>confdefs.h +# gettext() and friends may be located in libc (Linux and Solaris) +# or in libintl. However, it is possible to have libintl installed +# even when gettext() is present in libc. In the case of GNU libintl, +# gettext() will be defined to gettext_libintl in libintl.h. +# Since gcc prefers /usr/local/include to /usr/include, we need to +# make sure we use the gettext() that matches the include file. +if test "$enable_nls" != "no"; then + if test "$enable_nls" != "yes"; then + CPPFLAGS="${CPPFLAGS} -I${enable_nls}/include" - AUTH_OBJS="$AUTH_OBJS bsdauth.o" - BSDAUTH_USAGE='[-a auth_type] ' - AUTH_EXCL=BSD_AUTH; BAMAN=1 + if test X"$with_rpath" = X"yes"; then + case "$host" in + *-*-hpux*) LDFLAGS="${LDFLAGS} -L$enable_nls/lib -Wl,+b,$enable_nls/lib" + ;; + *) LDFLAGS="${LDFLAGS} -L$enable_nls/lib -Wl,-R$enable_nls/lib" + ;; + esac + else + LDFLAGS="${LDFLAGS} -L$enable_nls/lib" + fi + if test X"$blibpath" != X"" -a "LDFLAGS" = "SUDO_LDFLAGS"; then + blibpath_add="${blibpath_add}:$enable_nls/lib" + fi + + fi + OLIBS="$LIBS" + for l in "libc" "-lintl" "-lintl -liconv"; do + if test "$l" = "libc"; then + # If user specified a dir for libintl ignore libc + if test "$enable_nls" != "yes"; then + continue + fi + gettext_name=sudo_cv_gettext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettext" >&5 +$as_echo_n "checking for gettext... " >&6; } + else + LIBS="$OLIBS $l" + gettext_name=sudo_cv_gettext"`echo $l|sed -e 's/ //g' -e 's/-/_/g'`" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gettext in $l" >&5 +$as_echo_n "checking for gettext in $l... " >&6; } + fi + if eval \${$gettext_name+:} false; then : + $as_echo_n "(cached) " >&6 else - as_fn_error "BSD authentication was specified but bsd_auth.h could not be found" "$LINENO" 5 -fi + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ -fi + #include +int +main () +{ +(void)gettext((char *)0); + ; + return 0; +} -if test ${CHECKSIA-'false'} = "true"; then - for ac_func in sia_ses_init -do : - ac_fn_c_check_func "$LINENO" "sia_ses_init" "ac_cv_func_sia_ses_init" -if test "x$ac_cv_func_sia_ses_init" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SIA_SES_INIT 1 _ACEOF - found=true +if ac_fn_c_try_link "$LINENO"; then : + eval $gettext_name=yes else - found=false + eval $gettext_name=no + fi -done +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext - if test "$found" = "true"; then - AUTH_EXCL=SIA - AUTH_OBJS="$AUTH_OBJS sia.o" - fi fi -if test ${with_fwtk-'no'} != "no"; then - if test "$with_fwtk" != "yes"; then + eval gettext_result="\$$gettext_name" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gettext_result" >&5 +$as_echo "$gettext_result" >&6; } + test "$gettext_result" = "yes" && break + done + LIBS="$OLIBS" - if test X"$with_rpath" = X"yes"; then - case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_fwtk} -Wl,+b,${with_fwtk}" - ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_fwtk} -Wl,-R${with_fwtk}" - ;; - esac - else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_fwtk}" - fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then - blibpath_add="${blibpath_add}:${with_fwtk}" - fi + if test "$sudo_cv_gettext" = "yes"; then + $as_echo "#define HAVE_LIBINTL_H 1" >>confdefs.h - CPPFLAGS="${CPPFLAGS} -I${with_fwtk}" - with_fwtk=yes - fi - SUDO_LIBS="${SUDO_LIBS} -lauth -lfwall" - AUTH_OBJS="$AUTH_OBJS fwtk.o" -fi + SUDO_NLS=enabled + elif test "$sudo_cv_gettext_lintl" = "yes"; then + $as_echo "#define HAVE_LIBINTL_H 1" >>confdefs.h -if test ${with_SecurID-'no'} != "no"; then - if test "$with_SecurID" != "yes"; then - : - elif test -d /usr/ace/examples; then - with_SecurID=/usr/ace/examples - else - with_SecurID=/usr/ace - fi - CPPFLAGS="${CPPFLAGS} -I${with_SecurID}" - _LDFLAGS="${LDFLAGS}" + SUDO_NLS=enabled + LIBINTL="-lintl" + elif test "$sudo_cv_gettext_lintl_liconv" = "yes"; then + $as_echo "#define HAVE_LIBINTL_H 1" >>confdefs.h - if test X"$with_rpath" = X"yes"; then - case "$host" in - *-*-hpux*) LDFLAGS="${LDFLAGS} -L${with_SecurID} -Wl,+b,${with_SecurID}" - ;; - *) LDFLAGS="${LDFLAGS} -L${with_SecurID} -Wl,-R${with_SecurID}" - ;; - esac - else - LDFLAGS="${LDFLAGS} -L${with_SecurID}" - fi - if test X"$blibpath" != X"" -a "LDFLAGS" = "SUDO_LDFLAGS"; then - blibpath_add="${blibpath_add}:${with_SecurID}" + SUDO_NLS=enabled + LIBINTL="-lintl -liconv" fi +fi - # - # Determine whether to use the new or old SecurID API - # - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SD_Init in -laceclnt" >&5 -$as_echo_n "checking for SD_Init in -laceclnt... " >&6; } -if test "${ac_cv_lib_aceclnt_SD_Init_______lpthread_______+set}" = set; then : +case "$enable_zlib" 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 ${ac_cv_lib_z_gzdopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-laceclnt - -lpthread - - $LIBS" +LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16550,179 +17966,252 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char SD_Init (); +char gzdopen (); int main () { -return SD_Init (); +return gzdopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_aceclnt_SD_Init_______lpthread_______=yes + ac_cv_lib_z_gzdopen=yes else - ac_cv_lib_aceclnt_SD_Init_______lpthread_______=no + ac_cv_lib_z_gzdopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_aceclnt_SD_Init_______lpthread_______" >&5 -$as_echo "$ac_cv_lib_aceclnt_SD_Init_______lpthread_______" >&6; } -if test "x$ac_cv_lib_aceclnt_SD_Init_______lpthread_______" = x""yes; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzdopen" >&5 +$as_echo "$ac_cv_lib_z_gzdopen" >&6; } +if test "x$ac_cv_lib_z_gzdopen" = xyes; then : + + for ac_header in zlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ZLIB_H 1 +_ACEOF + ZLIB="-lz" +else + enable_zlib=builtin +fi - AUTH_OBJS="$AUTH_OBJS securid5.o"; - SUDO_LIBS="${SUDO_LIBS} -laceclnt -lpthread" +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="-I${enable_zlib}/include ${CPPFLAGS}" if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_SecurID} -Wl,+b,${with_SecurID}" + *-*-hpux*) ZLIB="${ZLIB} -L$enable_zlib/lib -Wl,+b,$enable_zlib/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_SecurID} -Wl,-R${with_SecurID}" + *) ZLIB="${ZLIB} -L$enable_zlib/lib -Wl,-R$enable_zlib/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_SecurID}" + ZLIB="${ZLIB} -L$enable_zlib/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then - blibpath_add="${blibpath_add}:${with_SecurID}" + 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='-I$(top_builddir)/zlib -I$(top_srcdir)/zlib '"${CPPFLAGS}" + ZLIB="${ZLIB}"' $(top_builddir)/zlib/libz.la' + ZLIB_SRC=zlib + ac_config_headers="$ac_config_headers zlib/zconf.h" + + ac_config_files="$ac_config_files zlib/Makefile" + +fi + +ac_fn_c_check_decl "$LINENO" "errno" "ac_cv_have_decl_errno" " +$ac_includes_default +#include +" +if test "x$ac_cv_have_decl_errno" = xyes; then : + ac_have_decl=1 else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_ERRNO $ac_have_decl +_ACEOF + - AUTH_OBJS="$AUTH_OBJS securid.o"; - SUDO_LIBS="${SUDO_LIBS} ${with_SecurID}/sdiclient.a" +ac_fn_c_check_decl "$LINENO" "h_errno" "ac_cv_have_decl_h_errno" " +$ac_includes_default +#include +" +if test "x$ac_cv_have_decl_h_errno" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 fi - LDFLAGS="${_LDFLAGS}" +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_H_ERRNO $ac_have_decl +_ACEOF + + +for ac_func in strsignal +do : + ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal" +if test "x$ac_cv_func_strsignal" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STRSIGNAL 1 +_ACEOF + +else + + case " $LIBOBJS " in + *" strsignal.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strsignal.$ac_objext" + ;; +esac + + HAVE_SIGLIST="false" + ac_fn_c_check_decl "$LINENO" "sys_siglist" "ac_cv_have_decl_sys_siglist" " +$ac_includes_default +#include + +" +if test "x$ac_cv_have_decl_sys_siglist" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 fi +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SYS_SIGLIST $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + + HAVE_SIGLIST="true" + break -if test -z "${AUTH_EXCL}" -a -n "$AUTH_DEF"; then - for auth in $AUTH_DEF; do - case $auth in - passwd) : ${with_passwd='maybe'};; - esac - done fi +ac_fn_c_check_decl "$LINENO" "_sys_siglist" "ac_cv_have_decl__sys_siglist" " +$ac_includes_default +#include -if test ${with_kerb4-'no'} != "no"; then - $as_echo "#define HAVE_KERB4 1" >>confdefs.h +" +if test "x$ac_cv_have_decl__sys_siglist" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi - O_LDFLAGS="$LDFLAGS" - if test "$with_kerb4" = "yes"; then - found=no - O_CPPFLAGS="$CPPFLAGS" - for dir in "" "kerberosIV/" "krb4/" "kerberos4/" "kerberosv4/"; do - CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL__SYS_SIGLIST $ac_have_decl _ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - found=yes; break +if test $ac_have_decl = 1; then : + + HAVE_SIGLIST="true" + break + fi -rm -f conftest.err conftest.$ac_ext - done - test X"$found" = X"no" && CPPFLAGS="$O_CPPFLAGS" - else +ac_fn_c_check_decl "$LINENO" "__sys_siglist" "ac_cv_have_decl___sys_siglist" " +$ac_includes_default +#include - if test X"$with_rpath" = X"yes"; then - case "$host" in - *-*-hpux*) LDFLAGS="${LDFLAGS} -L${with_kerb4}/lib -Wl,+b,${with_kerb4}/lib" - ;; - *) LDFLAGS="${LDFLAGS} -L${with_kerb4}/lib -Wl,-R${with_kerb4}/lib" - ;; - esac - else - LDFLAGS="${LDFLAGS} -L${with_kerb4}/lib" - fi - if test X"$blibpath" != X"" -a "LDFLAGS" = "SUDO_LDFLAGS"; then - blibpath_add="${blibpath_add}:${with_kerb4}/lib" - fi +" +if test "x$ac_cv_have_decl___sys_siglist" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL___SYS_SIGLIST $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + + HAVE_SIGLIST="true" + break + +fi + if test "$HAVE_SIGLIST" != "true"; then + case " $LIBOBJS " in + *" siglist.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS siglist.$ac_objext" + ;; +esac - if test X"$with_rpath" = X"yes"; then - case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb4}/lib -Wl,+b,${with_kerb4}/lib" - ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb4}/lib -Wl,-R${with_kerb4}/lib" - ;; - esac - else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb4}/lib" - fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then - blibpath_add="${blibpath_add}:${with_kerb4}/lib" fi - CPPFLAGS="$CPPFLAGS -I${with_kerb4}/include" - ac_fn_c_check_header_mongrel "$LINENO" "krb.h" "ac_cv_header_krb_h" "$ac_includes_default" -if test "x$ac_cv_header_krb_h" = x""yes; then : - found=yes -else - found=no fi +done - fi - if test X"$found" = X"no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos IV include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&5 -$as_echo "$as_me: WARNING: Unable to locate Kerberos IV include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&2;} - fi +if test ${with_netsvc-"no"} != "no"; then + cat >>confdefs.h <&5 -$as_echo_n "checking for des_cbc_encrypt in -ldes... " >&6; } -if test "${ac_cv_lib_des_des_cbc_encrypt+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldes $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + netsvc_conf=${with_netsvc-/etc/netsvc.conf} +elif test ${with_nsswitch-"yes"} != "no"; then + cat >>confdefs.h <&5 -$as_echo "$ac_cv_lib_des_des_cbc_encrypt" >&6; } -if test "x$ac_cv_lib_des_des_cbc_encrypt" = x""yes; then : - K4LIBS="-ldes" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for des_cbc_encrypt in -ldes425" >&5 -$as_echo_n "checking for des_cbc_encrypt in -ldes425... " >&6; } -if test "${ac_cv_lib_des425_des_cbc_encrypt+set}" = set; then : +if test ${with_pam-"no"} != "no"; then + # + # Check for pam_start() in libpam first, then for pam_appl.h. + # + found_pam_lib=no + as_ac_Lib=`$as_echo "ac_cv_lib_pam_pam_start$lt_cv_dlopen_libs" | $as_tr_sh` +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pam_start in -lpam" >&5 +$as_echo_n "checking for pam_start in -lpam... " >&6; } +if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-ldes425 $LIBS" +LIBS="-lpam $lt_cv_dlopen_libs $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -16732,181 +18221,243 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char des_cbc_encrypt (); +char pam_start (); int main () { -return des_cbc_encrypt (); +return pam_start (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_des425_des_cbc_encrypt=yes + eval "$as_ac_Lib=yes" else - ac_cv_lib_des425_des_cbc_encrypt=no + eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_des425_des_cbc_encrypt" >&5 -$as_echo "$ac_cv_lib_des425_des_cbc_encrypt" >&6; } -if test "x$ac_cv_lib_des425_des_cbc_encrypt" = x""yes; then : - K4LIBS="-ldes425" -else - K4LIBS="" -fi - - +eval ac_res=\$$as_ac_Lib + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : + found_pam_lib=yes fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using KTH Kerberos IV" >&5 -$as_echo_n "checking whether we are using KTH Kerberos IV... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -const char *tmp = krb4_version; - ; - return 0; -} + # + # Some PAM implementations (MacOS X for example) put the PAM headers + # in /usr/include/pam instead of /usr/include/security... + # + found_pam_hdrs=no + for ac_header in security/pam_appl.h pam/pam_appl.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" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : + found_pam_hdrs=yes; break +fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - K4LIBS="${K4LIBS} -lcom_err" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lroken" >&5 -$as_echo_n "checking for main in -lroken... " >&6; } -if test "${ac_cv_lib_roken_main+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lroken $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ +done + if test "$found_pam_lib" = "yes" -a "$found_pam_hdrs" = "yes"; then + # Found both PAM libs and headers + with_pam=yes + elif test "$with_pam" = "yes"; then + if test "$found_pam_lib" = "no"; then + as_fn_error $? "\"--with-pam specified but unable to locate PAM development library.\"" "$LINENO" 5 + fi + if test "$found_pam_hdrs" = "no"; then + as_fn_error $? "\"--with-pam specified but unable to locate PAM development headers.\"" "$LINENO" 5 + fi + elif test "$found_pam_lib" != "$found_pam_hdrs"; then + if test "$found_pam_lib" = "no"; then + as_fn_error $? "\"found PAM headers but no PAM development library; specify --without-pam to build without PAM\"" "$LINENO" 5 + fi + if test "$found_pam_hdrs" = "no"; then + as_fn_error $? "\"found PAM library but no PAM development headers; specify --without-pam to build without PAM\"" "$LINENO" 5 + fi + fi -int -main () -{ -return main (); - ; - return 0; -} + if test "$with_pam" = "yes"; then + # Older PAM implementations lack pam_getenvlist + OLIBS="$LIBS" + LIBS="$LIBS -lpam $lt_cv_dlopen_libs" + for ac_func in pam_getenvlist +do : + ac_fn_c_check_func "$LINENO" "pam_getenvlist" "ac_cv_func_pam_getenvlist" +if test "x$ac_cv_func_pam_getenvlist" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PAM_GETENVLIST 1 _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_roken_main=yes -else - ac_cv_lib_roken_main=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_roken_main" >&5 -$as_echo "$ac_cv_lib_roken_main" >&6; } -if test "x$ac_cv_lib_roken_main" = x""yes; then : - K4LIBS="${K4LIBS} -lroken" + fi +done + LIBS="$OLIBS" -else + # We already link with -ldl if needed (see LIBDL below) + SUDOERS_LIBS="${SUDOERS_LIBS} -lpam" + $as_echo "#define HAVE_PAM 1" >>confdefs.h - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + AUTH_OBJS="$AUTH_OBJS pam.lo"; + AUTH_EXCL=PAM +# Check whether --with-pam-login was given. +if test "${with_pam_login+set}" = set; then : + withval=$with_pam_login; case $with_pam_login in + yes) $as_echo "#define HAVE_PAM_LOGIN 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use PAM login" >&5 +$as_echo_n "checking whether to use PAM login... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ;; + no) ;; + *) as_fn_error $? "\"--with-pam-login does not take an argument.\"" "$LINENO" 5 + ;; + esac fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - as_ac_Lib=`$as_echo "ac_cv_lib_krb_main$K4LIBS" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkrb" >&5 -$as_echo_n "checking for main in -lkrb... " >&6; } -if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lkrb $K4LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int -main () -{ -return main (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$as_ac_Lib=yes" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use PAM session support" >&5 +$as_echo_n "checking whether to use PAM session support... " >&6; } + # Check whether --enable-pam_session was given. +if test "${enable_pam_session+set}" = set; then : + enableval=$enable_pam_session; case "$enableval" in + yes) { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + ;; + no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + $as_echo "#define NO_PAM_SESSION 1" >>confdefs.h + + ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unknown argument to --enable-pam-session: $enableval" >&5 +$as_echo "$as_me: WARNING: Ignoring unknown argument to --enable-pam-session: $enableval" >&2;} + ;; + esac else - eval "$as_ac_Lib=no" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS + + fi fi -eval ac_res=\$$as_ac_Lib - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Lib - if test "x$as_val" = x""yes; then : - K4LIBS="-lkrb $K4LIBS" -else - as_ac_Lib=`$as_echo "ac_cv_lib_krb4_main$K4LIBS" | $as_tr_sh` -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkrb4" >&5 -$as_echo_n "checking for main in -lkrb4... " >&6; } -if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 +if test ${with_aixauth-'no'} != "no"; then + if test X"$with_aixauth" != X"maybe" -o X"$AUTH_EXCL" = X""; then + { $as_echo "$as_me:${as_lineno-$LINENO}: using AIX general authentication" >&5 +$as_echo "$as_me: using AIX general authentication" >&6;} + $as_echo "#define HAVE_AIXAUTH 1" >>confdefs.h + + AUTH_OBJS="$AUTH_OBJS aix_auth.lo"; + SUDOERS_LIBS="${SUDOERS_LIBS} -ls" + AUTH_EXCL=AIX_AUTH + fi +fi + +if test ${with_bsdauth-'no'} != "no"; then + ac_fn_c_check_header_mongrel "$LINENO" "bsd_auth.h" "ac_cv_header_bsd_auth_h" "$ac_includes_default" +if test "x$ac_cv_header_bsd_auth_h" = xyes; then : + $as_echo "#define HAVE_BSD_AUTH_H 1" >>confdefs.h + + AUTH_OBJS="$AUTH_OBJS bsdauth.lo" + BSDAUTH_USAGE='[-a auth_type] ' + AUTH_EXCL=BSD_AUTH; BAMAN=1 else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lkrb4 $K4LIBS $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ + as_fn_error $? "BSD authentication was specified but bsd_auth.h could not be found" "$LINENO" 5 +fi -int -main () -{ -return main (); - ; - return 0; -} +fi + +if test ${CHECKSIA-'false'} = "true"; then + for ac_func in sia_ses_init +do : + ac_fn_c_check_func "$LINENO" "sia_ses_init" "ac_cv_func_sia_ses_init" +if test "x$ac_cv_func_sia_ses_init" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SIA_SES_INIT 1 _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$as_ac_Lib=yes" + found=true else - eval "$as_ac_Lib=no" + found=false fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +done + + if test "$found" = "true"; then + AUTH_EXCL=SIA + AUTH_OBJS="$AUTH_OBJS sia.lo" + fi fi -eval ac_res=\$$as_ac_Lib - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -eval as_val=\$$as_ac_Lib - if test "x$as_val" = x""yes; then : - K4LIBS="-lkrb4 $K4LIBS" -else - K4LIBS="-lkrb $K4LIBS" - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDO_LDFLAGS and possibly add Kerberos libs to SUDO_LIBS" >&5 -$as_echo "$as_me: WARNING: Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDO_LDFLAGS and possibly add Kerberos libs to SUDO_LIBS" >&2;} +if test ${with_fwtk-'no'} != "no"; then + if test "$with_fwtk" != "yes"; then + + if test X"$with_rpath" = X"yes"; then + case "$host" in + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_fwtk} -Wl,+b,${with_fwtk}" + ;; + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_fwtk} -Wl,-R${with_fwtk}" + ;; + esac + else + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_fwtk}" + fi + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then + blibpath_add="${blibpath_add}:${with_fwtk}" + fi + + CPPFLAGS="${CPPFLAGS} -I${with_fwtk}" + with_fwtk=yes + fi + SUDOERS_LIBS="${SUDOERS_LIBS} -lauth -lfwall" + AUTH_OBJS="$AUTH_OBJS fwtk.lo" fi +if test ${with_SecurID-'no'} != "no"; then + if test "$with_SecurID" != "yes"; then + : + elif test -d /usr/ace/examples; then + with_SecurID=/usr/ace/examples + else + with_SecurID=/usr/ace + fi + CPPFLAGS="${CPPFLAGS} -I${with_SecurID}" + + if test X"$with_rpath" = X"yes"; then + case "$host" in + *-*-hpux*) LDFLAGS="${LDFLAGS} -L${with_SecurID} -Wl,+b,${with_SecurID}" + ;; + *) LDFLAGS="${LDFLAGS} -L${with_SecurID} -Wl,-R${with_SecurID}" + ;; + esac + else + LDFLAGS="${LDFLAGS} -L${with_SecurID}" + fi + if test X"$blibpath" != X"" -a "LDFLAGS" = "SUDO_LDFLAGS"; then + blibpath_add="${blibpath_add}:${with_SecurID}" + fi + SUDOERS_LIBS="${SUDOERS_LIBS} -laceclnt -lpthread" + AUTH_OBJS="$AUTH_OBJS securid5.lo"; fi - LDFLAGS="$O_LDFLAGS" - SUDO_LIBS="${SUDO_LIBS} $K4LIBS" - AUTH_OBJS="$AUTH_OBJS kerb4.o" + +if test -z "${AUTH_EXCL}" -a -n "$AUTH_DEF"; then + for auth in $AUTH_DEF; do + case $auth in + passwd) : ${with_passwd='maybe'};; + esac + done fi if test ${with_kerb5-'no'} != "no"; then @@ -16914,7 +18465,7 @@ if test ${with_kerb5-'no'} != "no"; then set dummy krb5-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_KRB5CONFIG+set}" = set; then : +if ${ac_cv_prog_KRB5CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$KRB5CONFIG"; then @@ -16951,9 +18502,9 @@ fi if test -n "$KRB5CONFIG"; then $as_echo "#define HAVE_KERB5 1" >>confdefs.h - AUTH_OBJS="$AUTH_OBJS kerb5.o" + AUTH_OBJS="$AUTH_OBJS kerb5.lo" CPPFLAGS="$CPPFLAGS `krb5-config --cflags`" - SUDO_LIBS="$SUDO_LIBS `krb5-config --libs`" + SUDOERS_LIBS="$SUDOERS_LIBS `krb5-config --libs`" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5 $as_echo_n "checking whether we are using Heimdal... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16982,52 +18533,57 @@ $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi -fi -if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then - $as_echo "#define HAVE_KERB5 1" >>confdefs.h + else + $as_echo "#define HAVE_KERB5 1" >>confdefs.h - if test "$with_kerb5" = "yes"; then - found=no - O_CPPFLAGS="$CPPFLAGS" - for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do - CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + if test "$with_kerb5" = "yes"; then + found=no + O_CPPFLAGS="$CPPFLAGS" + for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do + CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +int +main () +{ + + ; + return 0; +} _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found=yes; break fi -rm -f conftest.err conftest.$ac_ext - done - if test X"$found" = X"no"; then - CPPFLAGS="$O_CPPFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&5 +rm -f conftest.err conftest.i conftest.$ac_ext + done + if test X"$found" = X"no"; then + CPPFLAGS="$O_CPPFLAGS" + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&5 $as_echo "$as_me: WARNING: Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS" >&2;} - fi - else + fi + else if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb5}/lib -Wl,+b,${with_kerb5}/lib" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb5}/lib -Wl,+b,${with_kerb5}/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb5}/lib -Wl,-R${with_kerb5}/lib" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb5}/lib -Wl,-R${with_kerb5}/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_kerb5}/lib" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_kerb5}/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:${with_kerb5}/lib" fi - CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include" - fi + CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include" + fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using Heimdal" >&5 $as_echo_n "checking whether we are using Heimdal... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -17040,15 +18596,15 @@ const char *tmp = heimdal_version; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } - $as_echo "#define HAVE_HEIMDAL 1" >>confdefs.h + $as_echo "#define HAVE_HEIMDAL 1" >>confdefs.h - # XXX - need to check whether -lcrypo is needed! - SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lroken" >&5 + # XXX - need to check whether -lcrypo is needed! + SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lroken" >&5 $as_echo_n "checking for main in -lroken... " >&6; } -if test "${ac_cv_lib_roken_main+set}" = set; then : +if ${ac_cv_lib_roken_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -17076,19 +18632,19 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_roken_main" >&5 $as_echo "$ac_cv_lib_roken_main" >&6; } -if test "x$ac_cv_lib_roken_main" = x""yes; then : - SUDO_LIBS="${SUDO_LIBS} -lroken" +if test "x$ac_cv_lib_roken_main" = xyes; then : + SUDOERS_LIBS="${SUDOERS_LIBS} -lroken" fi else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } - SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lk5crypto -lcom_err" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkrb5support" >&5 + SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lk5crypto -lcom_err" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkrb5support" >&5 $as_echo_n "checking for main in -lkrb5support... " >&6; } -if test "${ac_cv_lib_krb5support_main+set}" = set; then : +if ${ac_cv_lib_krb5support_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -17116,22 +18672,22 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_krb5support_main" >&5 $as_echo "$ac_cv_lib_krb5support_main" >&6; } -if test "x$ac_cv_lib_krb5support_main" = x""yes; then : - SUDO_LIBS="${SUDO_LIBS} -lkrb5support" +if test "x$ac_cv_lib_krb5support_main" = xyes; then : + SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5support" fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - AUTH_OBJS="$AUTH_OBJS kerb5.o" + AUTH_OBJS="$AUTH_OBJS kerb5.lo" + fi _LIBS="$LIBS" - LIBS="${LIBS} ${SUDO_LIBS}" + LIBS="${LIBS} ${SUDOERS_LIBS}" for ac_func in krb5_verify_user krb5_init_secure_context do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -17142,18 +18698,18 @@ done for ac_func in krb5_get_init_creds_opt_alloc do : ac_fn_c_check_func "$LINENO" "krb5_get_init_creds_opt_alloc" "ac_cv_func_krb5_get_init_creds_opt_alloc" -if test "x$ac_cv_func_krb5_get_init_creds_opt_alloc" = x""yes; then : +if test "x$ac_cv_func_krb5_get_init_creds_opt_alloc" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC 1 _ACEOF { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether krb5_get_init_creds_opt_free takes a context" >&5 $as_echo_n "checking whether krb5_get_init_creds_opt_free takes a context... " >&6; } -if test "${sudo_cv_krb5_get_init_creds_opt_free_two_args+set}" = set; then : +if ${sudo_cv_krb5_get_init_creds_opt_free_two_args+:} false; then : $as_echo_n "(cached) " >&6 else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -17186,6 +18742,29 @@ done fi LIBS="$_LIBS" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use an instance name for Kerberos V" >&5 +$as_echo_n "checking whether to use an instance name for Kerberos V... " >&6; } + # Check whether --enable-kerb5-instance was given. +if test "${enable_kerb5_instance+set}" = set; then : + enableval=$enable_kerb5_instance; case "$enableval" in + yes) as_fn_error $? "\"must give --enable-kerb5-instance an argument.\"" "$LINENO" 5 + ;; + no) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + *) cat >>confdefs.h <&5 +$as_echo "$enableval" >&6; } + ;; + esac +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + fi if test ${with_AFS-'no'} = "yes"; then @@ -17197,15 +18776,15 @@ if test ${with_AFS-'no'} = "yes"; then if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L$i -Wl,+b,$i" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L$i -Wl,+b,$i" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L$i -Wl,-R$i" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L$i -Wl,-R$i" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L$i" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L$i" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:$i" fi @@ -17213,8 +18792,8 @@ if test ${with_AFS-'no'} = "yes"; then fi done if test -z "$FOUND_AFSLIBDIR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDO_LDFLAGS or rerun configure with the --with-libpath options." >&5 -$as_echo "$as_me: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDO_LDFLAGS or rerun configure with the --with-libpath options." >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDOERS_LDFLAGS or rerun configure with the --with-libpath options." >&5 +$as_echo "$as_me: WARNING: Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDOERS_LDFLAGS or rerun configure with the --with-libpath options." >&2;} fi # Order is important here. Note that we build AFS_LIBS from right to left @@ -17245,16 +18824,16 @@ $as_echo "$as_me: WARNING: Unable to locate AFS libraries, you will have to edit $as_echo "$as_me: WARNING: Unable to locate AFS include dir, you may have to edit the Makefile and add -I/path/to/afs/includes to CPPFLAGS or rerun configure with the --with-incpath options." >&2;} fi - AUTH_OBJS="$AUTH_OBJS afs.o" + AUTH_OBJS="$AUTH_OBJS afs.lo" fi if test ${with_DCE-'no'} = "yes"; then DCE_OBJS="${DCE_OBJS} dce_pwent.o" - SUDO_LIBS="${SUDO_LIBS} -ldce" - AUTH_OBJS="$AUTH_OBJS dce.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -ldce" + AUTH_OBJS="$AUTH_OBJS dce.lo" fi -if test ${with_skey-'no'} = "yes"; then +if test "${with_skey-'no'}" = "yes"; then O_LDFLAGS="$LDFLAGS" if test "$with_skey" != "yes"; then CPPFLAGS="${CPPFLAGS} -I${with_skey}/include" @@ -17276,41 +18855,39 @@ if test ${with_skey-'no'} = "yes"; then if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_skey}/lib -Wl,+b,${with_skey}/lib" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_skey}/lib -Wl,+b,${with_skey}/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_skey}/lib -Wl,-R${with_skey}/lib" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_skey}/lib -Wl,-R${with_skey}/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_skey}/lib" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_skey}/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:${with_skey}/lib" fi - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : + ac_fn_c_check_header_compile "$LINENO" "skey.h" "ac_cv_header_skey_h" "#include +" +if test "x$ac_cv_header_skey_h" = xyes; then : found=yes else found=no fi -rm -f conftest.err conftest.$ac_ext + + else found=no O_CPPFLAGS="$CPPFLAGS" for dir in "" "/usr/local" "/usr/contrib"; do test -n "$dir" && CPPFLAGS="$O_CPPFLAGS -I${dir}/include" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : + ac_fn_c_check_header_compile "$LINENO" "skey.h" "ac_cv_header_skey_h" "#include +" +if test "x$ac_cv_header_skey_h" = xyes; then : found=yes; break fi -rm -f conftest.err conftest.$ac_ext + + done if test "$found" = "no" -o -z "$dir"; then CPPFLAGS="$O_CPPFLAGS" @@ -17333,27 +18910,27 @@ rm -f conftest.err conftest.$ac_ext if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:${dir}/lib" fi fi - fi - if test "$found" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS" >&5 + if test "$found" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS" >&5 $as_echo "$as_me: WARNING: Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS" >&2;} + fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lskey" >&5 $as_echo_n "checking for main in -lskey... " >&6; } -if test "${ac_cv_lib_skey_main+set}" = set; then : +if ${ac_cv_lib_skey_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -17381,16 +18958,16 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_skey_main" >&5 $as_echo "$ac_cv_lib_skey_main" >&6; } -if test "x$ac_cv_lib_skey_main" = x""yes; then : +if test "x$ac_cv_lib_skey_main" = xyes; then : found=yes else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDO_LDFLAGS" >&5 -$as_echo "$as_me: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDO_LDFLAGS" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDOERS_LDFLAGS" >&5 +$as_echo "$as_me: WARNING: Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDOERS_LDFLAGS" >&2;} fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for skeyaccess in -lskey" >&5 $as_echo_n "checking for skeyaccess in -lskey... " >&6; } -if test "${ac_cv_lib_skey_skeyaccess+set}" = set; then : +if ${ac_cv_lib_skey_skeyaccess+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -17424,17 +19001,49 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_skey_skeyaccess" >&5 $as_echo "$ac_cv_lib_skey_skeyaccess" >&6; } -if test "x$ac_cv_lib_skey_skeyaccess" = x""yes; then : +if test "x$ac_cv_lib_skey_skeyaccess" = xyes; then : $as_echo "#define HAVE_SKEYACCESS 1" >>confdefs.h fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for RFC1938-compliant skeychallenge" >&5 +$as_echo_n "checking for RFC1938-compliant skeychallenge... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include +int +main () +{ +skeychallenge(NULL, NULL, NULL, 0); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + $as_echo "#define HAVE_RFC1938_SKEYCHALLENGE 1" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + LDFLAGS="$O_LDFLAGS" - SUDO_LIBS="${SUDO_LIBS} -lskey" - AUTH_OBJS="$AUTH_OBJS rfc1938.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lskey" + AUTH_OBJS="$AUTH_OBJS rfc1938.lo" fi -if test ${with_opie-'no'} = "yes"; then +if test "${with_opie-'no'}" = "yes"; then O_LDFLAGS="$LDFLAGS" if test "$with_opie" != "yes"; then CPPFLAGS="${CPPFLAGS} -I${with_opie}/include" @@ -17456,28 +19065,35 @@ if test ${with_opie-'no'} = "yes"; then if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_opie}/lib -Wl,+b,${with_opie}/lib" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_opie}/lib -Wl,+b,${with_opie}/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_opie}/lib -Wl,-R${with_opie}/lib" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_opie}/lib -Wl,-R${with_opie}/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_opie}/lib" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_opie}/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:${with_opie}/lib" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +int +main () +{ + + ; + return 0; +} _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found=yes else found=no fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext else found=no O_CPPFLAGS="$CPPFLAGS" @@ -17486,11 +19102,18 @@ rm -f conftest.err conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +int +main () +{ + + ; + return 0; +} _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found=yes; break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done if test "$found" = "no" -o -z "$dir"; then CPPFLAGS="$O_CPPFLAGS" @@ -17513,27 +19136,27 @@ rm -f conftest.err conftest.$ac_ext if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,+b,${dir}/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib -Wl,-R${dir}/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${dir}/lib" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${dir}/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:${dir}/lib" fi fi - fi - if test "$found" = "no"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS" >&5 + if test "$found" = "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS" >&5 $as_echo "$as_me: WARNING: Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS" >&2;} + fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lopie" >&5 $as_echo_n "checking for main in -lopie... " >&6; } -if test "${ac_cv_lib_opie_main+set}" = set; then : +if ${ac_cv_lib_opie_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -17561,23 +19184,24 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_opie_main" >&5 $as_echo "$ac_cv_lib_opie_main" >&6; } -if test "x$ac_cv_lib_opie_main" = x""yes; then : +if test "x$ac_cv_lib_opie_main" = xyes; then : found=yes else - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDO_LDFLAGS" >&5 -$as_echo "$as_me: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDO_LDFLAGS" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDOERS_LDFLAGS" >&5 +$as_echo "$as_me: WARNING: Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDOERS_LDFLAGS" >&2;} fi LDFLAGS="$O_LDFLAGS" - SUDO_LIBS="${SUDO_LIBS} -lopie" - AUTH_OBJS="$AUTH_OBJS rfc1938.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lopie" + AUTH_OBJS="$AUTH_OBJS rfc1938.lo" fi if test ${with_passwd-'no'} != "no"; then - if test -z "$LIB_CRYPT" -a "$with_passwd" != "no"; then + if test -z "$LIB_CRYPT"; then + _LIBS="$LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing crypt" >&5 $as_echo_n "checking for library containing crypt... " >&6; } -if test "${ac_cv_search_crypt+set}" = set; then : +if ${ac_cv_search_crypt+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -17611,11 +19235,11 @@ for ac_lib in '' crypt crypt_d ufc; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_crypt+set}" = set; then : + if ${ac_cv_search_crypt+:} false; then : break fi done -if test "${ac_cv_search_crypt+set}" = set; then : +if ${ac_cv_search_crypt+:} false; then : else ac_cv_search_crypt=no @@ -17628,9 +19252,10 @@ $as_echo "$ac_cv_search_crypt" >&6; } ac_res=$ac_cv_search_crypt if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res" + test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res" fi + LIBS="$_LIBS" fi if test "$CHECKSHADOW" = "true" -a -n "$shadow_funcs"; then @@ -17641,8 +19266,7 @@ fi 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -17651,15 +19275,14 @@ fi done if test "$found" = "yes"; then - SUDO_LIBS="$SUDO_LIBS $shadow_libs" + SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs" elif test -n "$shadow_libs_optional"; then LIBS="$LIBS $shadow_libs_optional" for ac_func in $shadow_funcs 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -17668,7 +19291,7 @@ fi done if test "$found" = "yes"; then - SUDO_LIBS="$SUDO_LIBS $shadow_libs $shadow_libs_optional" + SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs $shadow_libs_optional" fi fi if test "$found" = "yes"; then @@ -17684,7 +19307,7 @@ done if test "$CHECKSHADOW" = "true"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getspnam" >&5 $as_echo_n "checking for library containing getspnam... " >&6; } -if test "${ac_cv_search_getspnam+set}" = set; then : +if ${ac_cv_search_getspnam+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -17718,11 +19341,11 @@ for ac_lib in '' gen; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_getspnam+set}" = set; then : + if ${ac_cv_search_getspnam+:} false; then : break fi done -if test "${ac_cv_search_getspnam+set}" = set; then : +if ${ac_cv_search_getspnam+:} false; then : else ac_cv_search_getspnam=no @@ -17736,14 +19359,14 @@ ac_res=$ac_cv_search_getspnam if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETSPNAM 1" >>confdefs.h - CHECKSHADOW=false; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res" + CHECKSHADOW=false; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res" fi fi if test "$CHECKSHADOW" = "true"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing getprpwnam" >&5 $as_echo_n "checking for library containing getprpwnam... " >&6; } -if test "${ac_cv_search_getprpwnam+set}" = set; then : +if ${ac_cv_search_getprpwnam+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -17777,11 +19400,11 @@ for ac_lib in '' sec security prot; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_getprpwnam+set}" = set; then : + if ${ac_cv_search_getprpwnam+:} false; then : break fi done -if test "${ac_cv_search_getprpwnam+set}" = set; then : +if ${ac_cv_search_getprpwnam+:} false; then : else ac_cv_search_getprpwnam=no @@ -17795,7 +19418,7 @@ ac_res=$ac_cv_search_getprpwnam if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" $as_echo "#define HAVE_GETPRPWNAM 1" >>confdefs.h - CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res" + CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res" fi fi @@ -17804,8 +19427,7 @@ fi 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 : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -17813,7 +19435,7 @@ _ACEOF fi done - AUTH_OBJS="$AUTH_OBJS secureware.o" + AUTH_OBJS="$AUTH_OBJS secureware.lo" fi fi @@ -17823,15 +19445,15 @@ if test ${with_ldap-'no'} != "no"; then if test X"$with_rpath" = X"yes"; then case "$host" in - *-*-hpux*) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_ldap}/lib -Wl,+b,${with_ldap}/lib" + *-*-hpux*) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_ldap}/lib -Wl,+b,${with_ldap}/lib" ;; - *) SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_ldap}/lib -Wl,-R${with_ldap}/lib" + *) SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_ldap}/lib -Wl,-R${with_ldap}/lib" ;; esac else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -L${with_ldap}/lib" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -L${with_ldap}/lib" fi - if test X"$blibpath" != X"" -a "SUDO_LDFLAGS" = "SUDO_LDFLAGS"; then + if test X"$blibpath" != X"" -a "SUDOERS_LDFLAGS" = "SUDO_LDFLAGS"; then blibpath_add="${blibpath_add}:${with_ldap}/lib" fi @@ -17853,7 +19475,7 @@ if test ${with_ldap-'no'} != "no"; then CPPFLAGS="${CPPFLAGS} -I${with_ldap}/include" with_ldap=yes fi - SUDO_OBJS="${SUDO_OBJS} ldap.o" + SUDOERS_OBJS="${SUDOERS_OBJS} ldap.lo" LDAP="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LDAP libraries" >&5 @@ -17883,6 +19505,32 @@ fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done + if test "$found" = "no"; then + LDAP_LIBS="" + LIBS="$_LIBS" + for l in -libmldap -lidsldif; do + LIBS="${LIBS} $l" + LDAP_LIBS="${LDAP_LIBS} $l" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + #include +int +main () +{ +(void)ldap_init(0, 0) + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + found=yes; break +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done + fi if test "$found" = "no"; then LIBS="${_LIBS} -lldap" LDAP_LIBS="-lldap" @@ -17895,7 +19543,7 @@ $as_echo "$LDAP_LIBS" >&6; } OLIBS="$LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing ber_set_option" >&5 $as_echo_n "checking for library containing ber_set_option... " >&6; } -if test "${ac_cv_search_ber_set_option+set}" = set; then : +if ${ac_cv_search_ber_set_option+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -17929,11 +19577,11 @@ for ac_lib in '' lber; do fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if test "${ac_cv_search_ber_set_option+set}" = set; then : + if ${ac_cv_search_ber_set_option+:} false; then : break fi done -if test "${ac_cv_search_ber_set_option+set}" = set; then : +if ${ac_cv_search_ber_set_option+:} false; then : else ac_cv_search_ber_set_option=no @@ -17985,15 +19633,14 @@ rm -f core conftest.err conftest.$ac_objext \ 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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF for ac_func in ldap_sasl_interactive_bind_s do : ac_fn_c_check_func "$LINENO" "ldap_sasl_interactive_bind_s" "ac_cv_func_ldap_sasl_interactive_bind_s" -if test "x$ac_cv_func_ldap_sasl_interactive_bind_s" = x""yes; then : +if test "x$ac_cv_func_ldap_sasl_interactive_bind_s" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LDAP_SASL_INTERACTIVE_BIND_S 1 _ACEOF @@ -18012,8 +19659,7 @@ do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#include " -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -18022,16 +19668,27 @@ 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" -eval as_val=\$$as_ac_var - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #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" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + break fi done @@ -18039,7 +19696,7 @@ done if test X"$check_gss_krb5_ccache_name" = X"yes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gss_krb5_ccache_name in -lgssapi" >&5 $as_echo_n "checking for gss_krb5_ccache_name in -lgssapi... " >&6; } -if test "${ac_cv_lib_gssapi_gss_krb5_ccache_name+set}" = set; then : +if ${ac_cv_lib_gssapi_gss_krb5_ccache_name+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -18073,14 +19730,14 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gssapi_gss_krb5_ccache_name" >&5 $as_echo "$ac_cv_lib_gssapi_gss_krb5_ccache_name" >&6; } -if test "x$ac_cv_lib_gssapi_gss_krb5_ccache_name" = x""yes; then : +if test "x$ac_cv_lib_gssapi_gss_krb5_ccache_name" = xyes; then : $as_echo "#define HAVE_GSS_KRB5_CCACHE_NAME 1" >>confdefs.h LDAP_LIBS="${LDAP_LIBS} -lgssapi" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gss_krb5_ccache_name in -lgssapi_krb5" >&5 $as_echo_n "checking for gss_krb5_ccache_name in -lgssapi_krb5... " >&6; } -if test "${ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name+set}" = set; then : +if ${ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -18114,7 +19771,7 @@ LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name" >&5 $as_echo "$ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name" >&6; } -if test "x$ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name" = x""yes; then : +if test "x$ac_cv_lib_gssapi_krb5_gss_krb5_ccache_name" = xyes; then : $as_echo "#define HAVE_GSS_KRB5_CCACHE_NAME 1" >>confdefs.h LDAP_LIBS="${LDAP_LIBS} -lgssapi_krb5" @@ -18132,6 +19789,13 @@ fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +int +main () +{ + + ; + return 0; +} _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found="gssapi/gssapi.h"; break @@ -18139,21 +19803,27 @@ else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include +int +main () +{ + + ; + return 0; +} _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : found="gssapi.h"; break fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext fi -rm -f conftest.err conftest.$ac_ext +rm -f conftest.err conftest.i conftest.$ac_ext done if test X"$found" != X"no"; then for ac_header in $found 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" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -18166,7 +19836,7 @@ done for ac_header in gssapi/gssapi_krb5.h do : ac_fn_c_check_header_mongrel "$LINENO" "gssapi/gssapi_krb5.h" "ac_cv_header_gssapi_gssapi_krb5_h" "$ac_includes_default" -if test "x$ac_cv_header_gssapi_gssapi_krb5_h" = x""yes; then : +if test "x$ac_cv_header_gssapi_gssapi_krb5_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GSSAPI_GSSAPI_KRB5_H 1 _ACEOF @@ -18183,32 +19853,134 @@ $as_echo "$as_me: WARNING: Unable to locate gssapi.h, you will have to edit the fi fi - SUDO_LIBS="${SUDO_LIBS} ${LDAP_LIBS}" + SUDOERS_LIBS="${SUDOERS_LIBS} ${LDAP_LIBS}" LIBS="$_LIBS" LDFLAGS="$_LDFLAGS" fi -if test X"$LIBVAS_RPATH" != X""; then - if test -n "$blibpath"; then - blibpath_add="${blibpath_add}:$LIBVAS_RPATH" - else - case "$host" in - *-*-hpux*) LDFLAGS="$LDFLAGS -Wl,+b,$LIBVAS_RPATH" - ;; - *) LDFLAGS="$LDFLAGS -Wl,-R$LIBVAS_RPATH" - ;; - esac - fi +# +# How to do dynamic object loading. +# We support dlopen() and sh_load(), else fall back to static loading. +# +case "$lt_cv_dlopen" in + dlopen) + $as_echo "#define HAVE_DLOPEN 1" >>confdefs.h + + SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo" + LT_STATIC="--tag=disable-static" + ;; + shl_load) + $as_echo "#define HAVE_SHL_LOAD 1" >>confdefs.h + + SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo" + LT_STATIC="--tag=disable-static" + case " $LIBOBJS " in + *" dlopen.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dlopen.$ac_objext" + ;; +esac + + ;; + *) + if test X"${ac_cv_func_dlopen}" = X"yes"; then + as_fn_error $? "\"dlopen present but libtool doesn't appear to support your platform.\"" "$LINENO" 5 + fi + # Preload sudoers module symbols + SUDO_OBJS="${SUDO_OBJS} preload.o" + SUDO_LIBS="${SUDO_LIBS} \$(top_builddir)/plugins/sudoers/sudoers.la" + LT_STATIC="" + case " $LIBOBJS " in + *" dlopen.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS dlopen.$ac_objext" + ;; +esac + + ;; +esac + +# +# Add library needed for dynamic loading, if any. +# +LIBDL="$lt_cv_dlopen_libs" +if test X"$LIBDL" != X""; then + SUDO_LIBS="${SUDO_LIBS} $LIBDL" + SUDOERS_LIBS="${SUDOERS_LIBS} $LIBDL" +fi + +# On HP-UX, you cannot dlopen() a shared object that uses pthreads +# unless the main program is linked against -lpthread. Since we +# have no knowledge what libraries a plugin may depend on, we always +# link against -lpthread on HP-UX if it is available. +# This check should go after all other libraries tests. +case "$host" in + *-*-hpux*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5 +$as_echo_n "checking for main in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_main+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main () +{ +return main (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_main=yes +else + ac_cv_lib_pthread_main=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_main" >&5 +$as_echo "$ac_cv_lib_pthread_main" >&6; } +if test "x$ac_cv_lib_pthread_main" = xyes; then : + SUDO_LIBS="${SUDO_LIBS} -lpthread" fi + ;; +esac + if test -n "$blibpath"; then if test -n "$blibpath_add"; then - SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}" + SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}" elif test -n "$with_blibpath" -a "$with_blibpath" != "yes"; then - SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}" + SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}" + fi +fi + +if test "$utmp_style" = "LEGACY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for utmp file path" >&5 +$as_echo_n "checking for utmp file path... " >&6; } +found=no +for p in "/var/run/utmp" "/var/adm/utmp" "/etc/utmp"; do + if test -r "$p"; then + found=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $p" >&5 +$as_echo "$p" >&6; } + cat >>confdefs.h <&5 +$as_echo "not found" >&6; } fi +fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for log file location" >&5 $as_echo_n "checking for log file location... " >&6; } if test -n "$with_logpath"; then @@ -18266,151 +20038,38 @@ 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; } - - -if test "${with_iologdir-yes}" != "no"; then - # Require POSIX job control for I/O log support - for ac_func in tcsetpgrp -do : - ac_fn_c_check_func "$LINENO" "tcsetpgrp" "ac_cv_func_tcsetpgrp" -if test "x$ac_cv_func_tcsetpgrp" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_TCSETPGRP 1 -_ACEOF - - SUDO_OBJS="${SUDO_OBJS} exec_pty.o get_pty.o iolog.o" - PROGS="$PROGS sudoreplay" - REPLAY="" - - # Check whether --enable-zlib was given. -if test "${enable_zlib+set}" = set; then : - enableval=$enable_zlib; 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 - -fi - - if test X"$enable_zlib" = X""; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gzdopen in -lz" >&5 -$as_echo_n "checking for gzdopen in -lz... " >&6; } -if test "${ac_cv_lib_z_gzdopen+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lz $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char gzdopen (); -int -main () -{ -return gzdopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_z_gzdopen=yes -else - ac_cv_lib_z_gzdopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_gzdopen" >&5 -$as_echo "$ac_cv_lib_z_gzdopen" >&6; } -if test "x$ac_cv_lib_z_gzdopen" = x""yes; then : - - for ac_header in zlib.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" -if test "x$ac_cv_header_zlib_h" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_ZLIB_H 1 -_ACEOF - ZLIB="-lz" -fi - -done - - -fi - - fi - -else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $iolog_dir" >&5 +$as_echo "$iolog_dir" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling I/O log support due to lack of tcsetpgrp function" >&5 -$as_echo "$as_me: WARNING: Disabling I/O log support due to lack of tcsetpgrp function" >&2;} - with_iologdir=no - -fi -done - -fi case "$with_passwd" in yes|maybe) - AUTH_OBJS="$AUTH_OBJS passwd.o" + AUTH_OBJS="$AUTH_OBJS getspwuid.lo passwd.lo" ;; *) $as_echo "#define WITHOUT_PASSWD 1" >>confdefs.h if test -z "$AUTH_OBJS"; then - as_fn_error "no authentication methods defined." "$LINENO" 5 + as_fn_error $? "no authentication methods defined." "$LINENO" 5 fi ;; esac AUTH_OBJS=${AUTH_OBJS# } -_AUTH=`echo "$AUTH_OBJS" | sed 's/\.o//g'` +_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.lo//g' -e 's/getspwuid *//'` { $as_echo "$as_me:${as_lineno-$LINENO}: using the following authentication methods: $_AUTH" >&5 $as_echo "$as_me: using the following authentication methods: $_AUTH" >&6;} @@ -18419,13 +20078,22 @@ if test -n "$LIBS"; then LIBS= for l in ${L}; do dupe=0 - for sl in ${SUDO_LIBS} ${NET_LIBS}; do + for sl in ${SUDO_LIBS} ${SUDOERS_LIBS} ${NET_LIBS}; do test $l = $sl && dupe=1 done test $dupe = 0 && LIBS="${LIBS} $l" done fi +if test -n "$GCC"; then + if test X"$enable_warnings" = X"yes" -o X"$with_devel" = X"yes"; then + CFLAGS="${CFLAGS} -Wall" + fi + if test X"$enable_werror" = X"yes"; then + CFLAGS="${CFLAGS} -Werror" + fi +fi + test "$exec_prefix" = "NONE" && exec_prefix='$(prefix)' if test X"$with_noexec" != X"no" -o X"$with_selinux" != X"no"; then @@ -18441,19 +20109,43 @@ if test X"$with_noexec" != X"no" -o X"$with_selinux" != X"no"; then PROGS="${PROGS} libsudo_noexec.la" INSTALL_NOEXEC="install-noexec" - eval noexec_file="$with_noexec" + noexec_file="$with_noexec" + _noexec_file= + while test X"$noexec_file" != X"$_noexec_file"; do + _noexec_file="$noexec_file" + eval noexec_file="$_noexec_file" + done cat >>confdefs.h <>confdefs.h <>confdefs.h <>confdefs.h <confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -18536,10 +20228,21 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && + if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} @@ -18555,6 +20258,7 @@ DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= +U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' @@ -18570,7 +20274,7 @@ LTLIBOBJS=$ac_ltlibobjs -: ${CONFIG_STATUS=./config.status} +: "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" @@ -18671,6 +20375,7 @@ fi IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. +as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -18716,19 +20421,19 @@ export LANGUAGE (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. +# script with STATUS, using 1 if that was 0. as_fn_error () { - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $1" >&2 + $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -18924,7 +20629,7 @@ $as_echo X"$as_dir" | test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p @@ -18977,8 +20682,8 @@ 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.4p4, which was -generated by GNU Autoconf 2.65. Invocation command line was +This file was extended by sudo $as_me 1.8.5p2, which was +generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -19043,16 +20748,17 @@ _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.4p4 -configured by $0, generated by GNU Autoconf 2.65, +sudo config.status 1.8.5p2 +configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" -Copyright (C) 2009 Free Software Foundation, Inc. +Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' +AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF @@ -19062,11 +20768,16 @@ ac_need_defaults=: while test $# != 0 do case $1 in - --*=*) + --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; *) ac_option=$1 ac_optarg=$2 @@ -19088,6 +20799,7 @@ do $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; @@ -19100,7 +20812,7 @@ do ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error "ambiguous option: \`$1' + as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; @@ -19109,7 +20821,7 @@ Try \`$0 --help' for more information.";; ac_cs_silent=: ;; # This is an error. - -*) as_fn_error "unrecognized option: \`$1' + -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" @@ -19162,131 +20874,154 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`' -macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`' -enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`' -enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`' -pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`' -host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`' -host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`' -host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`' -build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`' -build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`' -build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`' -SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`' -Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`' -GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`' -EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`' -FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`' -LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`' -NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`' -LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`' -ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`' -exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`' -lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`' -reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`' -AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`' -STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`' -RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' -CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`' -compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`' -GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' -objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`' -SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`' -ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`' -need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`' -LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`' -OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`' -libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' -module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`' -fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`' -need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`' -version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`' -runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`' -libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`' -soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`' -finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`' -sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`' -old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`' -striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + # Quote evaled strings. -for var in SED \ +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ GREP \ EGREP \ FGREP \ @@ -19299,8 +21034,13 @@ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ +archiver_list_spec \ STRIP \ RANLIB \ CC \ @@ -19310,14 +21050,14 @@ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -SHELL \ -ECHO \ +nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_wl \ lt_prog_compiler_pic \ +lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ +MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ @@ -19331,9 +21071,7 @@ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ -hardcode_libdir_flag_spec_ld \ hardcode_libdir_separator \ -fix_srcfile_path \ exclude_expsyms \ include_expsyms \ file_list_spec \ @@ -19341,12 +21079,13 @@ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ +install_override_mode \ finish_eval \ old_striplib \ striplib; do - case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -19368,14 +21107,15 @@ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ +postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do - case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -19383,12 +21123,6 @@ sys_lib_dlsearch_path_spec; do esac done -# Fix-up fallback echo if it was mangled by the above quoting rules. -case \$lt_ECHO in -*'\\\$0 --fallback-echo"') lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\` - ;; -esac - ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' @@ -19420,16 +21154,22 @@ do "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "pathnames.h") CONFIG_HEADERS="$CONFIG_HEADERS pathnames.h" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "zlib/zconf.h") CONFIG_HEADERS="$CONFIG_HEADERS zlib/zconf.h" ;; + "zlib/Makefile") CONFIG_FILES="$CONFIG_FILES zlib/Makefile" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "sudo.man") CONFIG_FILES="$CONFIG_FILES sudo.man" ;; - "visudo.man") CONFIG_FILES="$CONFIG_FILES visudo.man" ;; - "sudoers.man") CONFIG_FILES="$CONFIG_FILES sudoers.man" ;; - "sudoers.ldap.man") CONFIG_FILES="$CONFIG_FILES sudoers.ldap.man" ;; - "sudoreplay.man") CONFIG_FILES="$CONFIG_FILES sudoreplay.man" ;; - "sudo_usage.h") CONFIG_FILES="$CONFIG_FILES sudo_usage.h" ;; - "sudoers") CONFIG_FILES="$CONFIG_FILES sudoers" ;; - - *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;; + "compat/Makefile") CONFIG_FILES="$CONFIG_FILES compat/Makefile" ;; + "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "src/sudo_usage.h") CONFIG_FILES="$CONFIG_FILES src/sudo_usage.h" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "plugins/sample/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample/Makefile" ;; + "plugins/sample_group/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sample_group/Makefile" ;; + "plugins/system_group/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/system_group/Makefile" ;; + "plugins/sudoers/Makefile") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/Makefile" ;; + "plugins/sudoers/sudoers") CONFIG_FILES="$CONFIG_FILES plugins/sudoers/sudoers" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -19452,9 +21192,10 @@ fi # after its creation but before its name has been assigned to `$tmp'. $debug || { - tmp= + tmp= ac_tmp= trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } @@ -19462,12 +21203,13 @@ $debug || { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" + test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -19484,12 +21226,12 @@ if test "x$ac_cr" = x; then fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\r' + ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi -echo 'BEGIN {' >"$tmp/subs1.awk" && +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF @@ -19498,18 +21240,18 @@ _ACEOF echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -19517,7 +21259,7 @@ done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h @@ -19565,7 +21307,7 @@ t delim rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" @@ -19597,21 +21339,29 @@ if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error "could not setup config files machinery" "$LINENO" 5 +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// s/^[^=]*=[ ]*$// }' fi @@ -19623,7 +21373,7 @@ fi # test -n "$CONFIG_FILES" # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || +cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF @@ -19635,11 +21385,11 @@ _ACEOF # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then break elif $ac_last_try; then - as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -19724,7 +21474,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error "could not setup config headers machinery" "$LINENO" 5 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -19737,7 +21487,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -19756,7 +21506,7 @@ do for ac_f do case $ac_f in - -) ac_f="$tmp/stdin";; + -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. @@ -19765,7 +21515,7 @@ do [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -19791,8 +21541,8 @@ $as_echo "$as_me: creating $ac_file" >&6;} esac case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -19917,23 +21667,24 @@ s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 +which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} +which seems to be undefined. Please make sure it is defined" >&2;} - rm -f "$tmp/stdin" + rm -f "$ac_tmp/stdin" case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # @@ -19942,21 +21693,21 @@ which seems to be undefined. Please make sure it is defined." >&2;} if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error "could not create -" "$LINENO" 5 + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; @@ -19988,7 +21739,8 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008 Free Software Foundation, Inc. +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. @@ -20036,6 +21788,15 @@ pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + # The host system. host_alias=$host_alias host=$host @@ -20085,9 +21846,11 @@ SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP @@ -20095,13 +21858,30 @@ OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method -# Command to use when deplibs_check_method == "file_magic". +# Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + # The archiver. AR=$lt_AR + +# Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + # A symbol stripping program. STRIP=$lt_STRIP @@ -20110,6 +21890,9 @@ RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + # A C compiler. LTCC=$lt_CC @@ -20128,14 +21911,14 @@ global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix -# The name of the directory that contains temporary libtool files. -objdir=$objdir +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot -# An echo program that does not interpret backslashes. -ECHO=$lt_ECHO +# The name of the directory that contains temporary libtool files. +objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD @@ -20143,6 +21926,9 @@ MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL @@ -20199,6 +21985,9 @@ library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds @@ -20238,6 +22027,10 @@ striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds @@ -20250,12 +22043,12 @@ with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static @@ -20305,10 +22098,6 @@ no_undefined_flag=$lt_no_undefined_flag # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec -# If ld is used when linking, flag to hardcode \$libdir into a binary -# during linking. This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld - # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator @@ -20342,9 +22131,6 @@ inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols @@ -20360,6 +22146,9 @@ include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + # Specify filename containing input files. file_list_spec=$lt_file_list_spec @@ -20392,212 +22181,169 @@ ltmain="$ac_aux_dir/ltmain.sh" # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? - sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - case $xsi_shell in - yes) - cat << \_LT_EOF >> "$cfgfile" - -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - case ${1} in - */*) func_dirname_result="${1%/*}${2}" ;; - * ) func_dirname_result="${3}" ;; - esac -} - -# func_basename file -func_basename () -{ - func_basename_result="${1##*/}" -} - -# func_dirname_and_basename file append nondir_replacement -# perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value retuned in "$func_basename_result" -# Implementation must be kept synchronized with func_dirname -# and func_basename. For efficiency, we do not delegate to -# those functions but instead duplicate the functionality here. -func_dirname_and_basename () -{ - case ${1} in - */*) func_dirname_result="${1%/*}${2}" ;; - * ) func_dirname_result="${3}" ;; - esac - func_basename_result="${1##*/}" -} - -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -func_stripname () -{ - # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are - # positional parameters, so assign one to ordinary parameter first. - func_stripname_result=${3} - func_stripname_result=${func_stripname_result#"${1}"} - func_stripname_result=${func_stripname_result%"${2}"} -} - -# func_opt_split -func_opt_split () -{ - func_opt_split_opt=${1%%=*} - func_opt_split_arg=${1#*=} -} - -# func_lo2o object -func_lo2o () -{ - case ${1} in - *.lo) func_lo2o_result=${1%.lo}.${objext} ;; - *) func_lo2o_result=${1} ;; - esac -} - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=${1%.*}.lo -} - -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=$(( $* )) -} - -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=${#1} -} - -_LT_EOF - ;; - *) # Bourne compatible functions. - cat << \_LT_EOF >> "$cfgfile" - -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - # Extract subdirectory from the argument. - func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi -} - -# func_basename file -func_basename () -{ - func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` -} - - -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -# func_strip_suffix prefix name -func_stripname () -{ - case ${2} in - .*) func_stripname_result=`$ECHO "X${3}" \ - | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; - *) func_stripname_result=`$ECHO "X${3}" \ - | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; - esac -} - -# sed scripts: -my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' -my_sed_long_arg='1s/^-[^=]*=//' - -# func_opt_split -func_opt_split () -{ - func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` - func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` -} - -# func_lo2o object -func_lo2o () -{ - func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` -} - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'` -} - -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=`expr "$@"` -} - -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` -} - -_LT_EOF -esac - -case $lt_shell_append in - yes) - cat << \_LT_EOF >> "$cfgfile" - -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "$1+=\$2" -} -_LT_EOF - ;; - *) - cat << \_LT_EOF >> "$cfgfile" - -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "$1=\$$1\$2" -} - -_LT_EOF - ;; - esac - - - sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" @@ -20612,7 +22358,7 @@ _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || - as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. @@ -20633,7 +22379,7 @@ if test "$no_create" != yes; then exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit $? + $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 @@ -20643,6 +22389,14 @@ fi if test "$with_pam" = "yes"; then case $host in + *-*-hpux*) + if test -f /usr/lib/security/libpam_hpsec.so.1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: You may wish to add the following line to /etc/pam.conf" >&5 +$as_echo "$as_me: You may wish to add the following line to /etc/pam.conf" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: sudo session required libpam_hpsec.so.1 bypass_umask bypass_last_login" >&5 +$as_echo "$as_me: sudo session required libpam_hpsec.so.1 bypass_umask bypass_last_login" >&6;} + fi + ;; *-*-linux*) { $as_echo "$as_me:${as_lineno-$LINENO}: You will need to customize sample.pam and install it as /etc/pam.d/sudo" >&5 $as_echo "$as_me: You will need to customize sample.pam and install it as /etc/pam.d/sudo" >&6;} @@ -20727,6 +22481,14 @@ fi + + + + + + + + diff --git a/configure.in b/configure.in index 4186b88..6ec6016 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-2012 Todd C. Miller dnl -AC_INIT([sudo], [1.7.4p4], [http://www.sudo.ws/bugs/], [sudo]) -AC_CONFIG_HEADER(config.h pathnames.h) +AC_INIT([sudo], [1.8.5p2], [http://www.sudo.ws/bugs/], [sudo]) +AC_CONFIG_HEADER([config.h pathnames.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 @@ -19,13 +19,17 @@ AC_SUBST([CFLAGS]) AC_SUBST([PROGS]) AC_SUBST([CPPFLAGS]) AC_SUBST([LDFLAGS]) +AC_SUBST([SUDOERS_LDFLAGS]) +AC_SUBST([LTLDFLAGS]) AC_SUBST([COMMON_OBJS]) -AC_SUBST([SUDO_LDFLAGS]) +AC_SUBST([SUDOERS_OBJS]) AC_SUBST([SUDO_OBJS]) AC_SUBST([LIBS]) AC_SUBST([SUDO_LIBS]) +AC_SUBST([SUDOERS_LIBS]) AC_SUBST([NET_LIBS]) AC_SUBST([AFS_LIBS]) +AC_SUBST([REPLAY_LIBS]) AC_SUBST([GETGROUPS_LIB]) AC_SUBST([OSDEFS]) AC_SUBST([AUTH_OBJS]) @@ -34,7 +38,7 @@ AC_SUBST([MAN_POSTINSTALL]) AC_SUBST([SUDOERS_MODE]) AC_SUBST([SUDOERS_UID]) AC_SUBST([SUDOERS_GID]) -AC_SUBST([DEV]) +AC_SUBST([DEVEL]) AC_SUBST([BAMAN]) AC_SUBST([LCMAN]) AC_SUBST([SEMAN]) @@ -44,23 +48,34 @@ AC_SUBST([mansectform]) AC_SUBST([mansrcdir]) AC_SUBST([NOEXECFILE]) AC_SUBST([NOEXECDIR]) +AC_SUBST([PLUGINDIR]) +AC_SUBST([SOEXT]) AC_SUBST([noexec_file]) AC_SUBST([INSTALL_NOEXEC]) AC_SUBST([DONT_LEAK_PATH_INFO]) AC_SUBST([BSDAUTH_USAGE]) AC_SUBST([SELINUX_USAGE]) AC_SUBST([LDAP]) -AC_SUBST([REPLAY]) AC_SUBST([LOGINCAP_USAGE]) AC_SUBST([ZLIB]) +AC_SUBST([ZLIB_SRC]) +AC_SUBST([LIBTOOL_DEPS]) +AC_SUBST([ac_config_libobj_dir]) AC_SUBST([CONFIGURE_ARGS]) +AC_SUBST([LIBDL]) +AC_SUBST([LT_STATIC]) +AC_SUBST([LIBINTL]) +AC_SUBST([SUDO_NLS]) +AC_SUBST([COMPAT_TEST_PROGS]) 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 +93,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 +108,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 +131,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 @@ -134,24 +153,26 @@ dnl May be overridden by environment variables.. dnl INSTALL_NOEXEC= devdir='$(srcdir)' -PROGS="sudo visudo" +PROGS="sudo" : ${MANTYPE='man'} : ${mansrcdir='.'} : ${SUDOERS_MODE='0440'} : ${SUDOERS_UID='0'} : ${SUDOERS_GID='0'} -DEV="#" +DEVEL= LDAP="#" -REPLAY="#" BAMAN=0 LCMAN=0 SEMAN=0 +LIBINTL= ZLIB= +ZLIB_SRC= AUTH_OBJS= AUTH_REG= AUTH_EXCL= AUTH_EXCL_DEF= AUTH_DEF=passwd +SUDO_NLS=disabled dnl dnl Other vaiables @@ -161,9 +182,21 @@ shadow_defs= shadow_funcs= shadow_libs= shadow_libs_optional= - CONFIGURE_ARGS="$@" +dnl +dnl LD_PRELOAD equivalents +dnl +RTLD_PRELOAD_VAR="LD_PRELOAD" +RTLD_PRELOAD_ENABLE_VAR= +RTLD_PRELOAD_DELIM=":" +RTLD_PRELOAD_DEFAULT= + +dnl +dnl libc replacement functions live in compat +dnl +AC_CONFIG_LIBOBJ_DIR(compat) + dnl dnl Deprecated --with options (these all warn or generate an error) dnl @@ -189,26 +222,18 @@ dnl AC_ARG_WITH(devel, [AS_HELP_STRING([--with-devel], [add development options])], [case $with_devel in yes) AC_MSG_NOTICE([Setting up for development: -Wall, flex, yacc]) - PROGS="${PROGS} testsudoers" OSDEFS="${OSDEFS} -DSUDO_DEVEL" - DEV="" + DEVEL="true" devdir=. ;; no) ;; *) 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 - yes) AC_MSG_ERROR(["must give --with-CC an argument."]) - ;; - no) AC_MSG_ERROR(["illegal argument: --without-CC."]) - ;; - *) CC=$with_CC + *) AC_MSG_ERROR([the --with-CC option is no longer supported, please set the CC environment variable instead.]) ;; esac]) @@ -232,8 +257,8 @@ dnl AC_ARG_WITH(bsm-audit, [AS_HELP_STRING([--with-bsm-audit], [enable BSM audit support])], [case $with_bsm_audit in yes) AC_DEFINE(HAVE_BSM_AUDIT) - SUDO_LIBS="${SUDO_LIBS} -lbsm" - SUDO_OBJS="${SUDO_OBJS} bsm_audit.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lbsm" + SUDOERS_OBJS="${SUDOERS_OBJS} bsm_audit.lo" ;; no) ;; *) AC_MSG_ERROR(["--with-bsm-audit does not take an argument."]) @@ -245,11 +270,11 @@ 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" + SUDOERS_LIBS="${SUDO_LIBS} -laudit" + SUDOERS_OBJS="${SUDOERS_OBJS} linux_audit.lo" ], [ AC_MSG_ERROR([unable to find AUDIT_USER_CMD in libaudit.h for --with-linux-audit]) ]) @@ -335,8 +360,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 +370,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 +393,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 +403,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) @@ -388,18 +411,9 @@ AC_ARG_WITH(fwtk, [AS_HELP_STRING([--with-fwtk[[=DIR]]], [enable FWTK AuthSRV su ;; esac]) -AC_ARG_WITH(kerb4, [AS_HELP_STRING([--with-kerb4[[=DIR]]], [enable Kerberos IV support])], -[case $with_kerb4 in - no) with_kerb4="";; - *) AC_MSG_CHECKING(whether to try kerberos IV authentication) - AC_MSG_RESULT(yes) - AUTH_REG="$AUTH_REG kerb4" - ;; -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" @@ -719,8 +733,9 @@ esac]) AC_ARG_WITH(iologdir, [AS_HELP_STRING([--with-iologdir=DIR], [directory to store sudo I/O log files in])], [case $with_iologdir in - yes) ;; - no) ;; + yes) ;; + no) AC_MSG_ERROR(["--without-iologdir not supported."]) + ;; esac]) AC_ARG_WITH(sendmail, [AS_HELP_STRING([--with-sendmail], [set path to sendmail]) @@ -784,13 +799,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 @@ -1071,32 +1097,12 @@ AC_ARG_WITH(askpass, [AS_HELP_STRING([--with-askpass=PATH], [Fully qualified pat ;; esac], AC_MSG_RESULT(no)) -dnl -dnl If enabled, set LIBVAS_SO, LIBVAS_RPATH and USING_NONUNIX_GROUPS -dnl -AC_ARG_WITH(libvas, [AS_HELP_STRING([--with-libvas=NAME], [Name of the libvas shared library (default=libvas.so)])], -[case $with_libvas in - yes) with_libvas=libvas.so - ;; - no) ;; - *) AC_DEFINE_UNQUOTED([LIBVAS_SO], ["$with_libvas"], [The name of libvas.so]) +AC_ARG_WITH(plugindir, [AS_HELP_STRING([--with-plugindir], [set directory to load plugins from])], +[case $with_plugindir in + no) AC_MSG_ERROR(["illegal argument: --without-plugindir."]) ;; -esac -if test X"$with_libvas" != X"no"; then - AC_DEFINE_UNQUOTED([LIBVAS_SO], ["$with_libvas"], [The name of libvas.so]) - AC_DEFINE(USING_NONUNIX_GROUPS) - COMMON_OBJS="$COMMON_OBJS vasgroups.o" - AC_ARG_WITH([libvas-rpath], - [AS_HELP_STRING([--with-libvas-rpath=PATH], - [Path to look for libvas in [default=/opt/quest/lib]])], - [LIBVAS_RPATH=$withval], - [LIBVAS_RPATH=/opt/quest/lib]) - dnl - dnl Some platforms require libdl for dlopen() - dnl - AC_CHECK_LIB([dl], [main]) -fi -]) + *) ;; +esac], [with_plugindir="$libexecdir"]) dnl dnl Options for --enable @@ -1256,19 +1262,51 @@ AC_ARG_ENABLE(env_debug, esac ], AC_MSG_RESULT(no)) +AC_ARG_ENABLE(zlib, +[AS_HELP_STRING([--enable-zlib[[=PATH]]], [Whether to enable or disable zlib])], +[], [enable_zlib=yes]) + +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, 1) +else + AC_MSG_RESULT(no) + AC_DEFINE(ENV_RESET, 0) +fi + AC_ARG_ENABLE(warnings, [AS_HELP_STRING([--enable-warnings], [Whether to enable compiler warnings])], [ case "$enableval" in - yes) if test X"$with_devel" != X"yes" -a -n "$GCC"; then - CFLAGS="${CFLAGS} -Wall" - fi - ;; + yes) ;; no) ;; *) AC_MSG_WARN([Ignoring unknown argument to --enable-warnings: $enableval]) ;; esac ]) +AC_ARG_ENABLE(werror, +[AS_HELP_STRING([--enable-werror], [Whether to enable the -Werror compiler option])], +[ case "$enableval" in + yes) ;; + no) ;; + *) AC_MSG_WARN([Ignoring unknown argument to --enable-werror: $enableval]) + ;; + esac +]) + AC_ARG_ENABLE(admin-flag, [AS_HELP_STRING([--enable-admin-flag], [Whether to create a Ubuntu-style admin flag file])], [ case "$enableval" in @@ -1280,6 +1318,10 @@ AC_ARG_ENABLE(admin-flag, esac ]) +AC_ARG_ENABLE(nls, +[AS_HELP_STRING([--disable-nls], [Disable natural language support using gettext])], +[], [enable_nls=yes]) + AC_ARG_WITH(selinux, [AS_HELP_STRING([--with-selinux], [enable SELinux support])], [case $with_selinux in yes) SELINUX_USAGE="[[-r role]] [[-t type]] " @@ -1310,6 +1352,22 @@ 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 + +if test "x$ac_cv_prog_cc_c89" = "xno"; then + AC_MSG_ERROR([Sudo version $PACKAGE_VERSION requires an ANSI C compiler to build.]) +fi + +dnl +dnl If the user specified --disable-static, override them or we'll +dnl be unable to build the executables in the sudoers plugin dir. +dnl +if test "$enable_static" = "no"; then + AC_MSG_WARN([Ignoring --disable-static, sudo does not install static libs]) + enable_static=yes +fi dnl dnl Libtool setup, we require libtool 2.2.6b or higher @@ -1317,15 +1375,25 @@ dnl AC_CANONICAL_HOST AC_CONFIG_MACRO_DIR([m4]) LT_PREREQ([2.2.6b]) -LT_INIT +LT_INIT([dlopen]) dnl dnl Defer with_noexec until after libtool magic runs dnl if test "$enable_shared" = "no"; then with_noexec=no + enable_dlopen=no + lt_cv_dlopen=none + lt_cv_dlopen_libs= + ac_cv_func_dlopen=no else eval _shrext="$shrext_cmds" + # Darwin uses .dylib for libraries but .so for modules + if test X"$_shrext" = X".dylib"; then + SOEXT=".so" + else + SOEXT="$_shrext" + fi fi AC_MSG_CHECKING(path to sudo_noexec.so) AC_ARG_WITH(noexec, [AS_HELP_STRING([--with-noexec[=PATH]], [fully qualified pathname of sudo_noexec.so])], @@ -1339,20 +1407,36 @@ AC_MSG_RESULT($with_noexec) NOEXECFILE="sudo_noexec$_shrext" NOEXECDIR="`echo $with_noexec|sed 's:^\(.*\)/[[^/]]*:\1:'`" -dnl -dnl It is now safe to modify CFLAGS and CPPFLAGS -dnl -if test X"$with_devel" = X"yes" -a -n "$GCC"; then - CFLAGS="${CFLAGS} -Wall" -fi - dnl dnl Find programs we use dnl AC_CHECK_PROG(UNAMEPROG, [uname], [uname]) AC_CHECK_PROG(TRPROG, [tr], [tr]) AC_CHECK_PROGS(NROFFPROG, [nroff mandoc]) -if test -z "$NROFFPROG"; then +if test -n "$NROFFPROG"; then + AC_CACHE_CHECK([whether $NROFFPROG supports the -c option], + [sudo_cv_var_nroff_opt_c], + [if $NROFFPROG -c /dev/null 2>&1; then + sudo_cv_var_nroff_opt_c=yes + else + sudo_cv_var_nroff_opt_c=no + fi] + ) + if test "$sudo_cv_var_nroff_opt_c" = "yes"; then + NROFFPROG="$NROFFPROG -c" + fi + AC_CACHE_CHECK([whether $NROFFPROG supports the -Tascii option], + [sudo_cv_var_nroff_opt_Tascii], + [if $NROFFPROG -Tascii /dev/null 2>&1; then + sudo_cv_var_nroff_opt_Tascii=yes + else + sudo_cv_var_nroff_opt_Tascii=no + fi] + if test "$sudo_cv_var_nroff_opt_Tascii" = "yes"; then + NROFFPROG="$NROFFPROG -Tascii" + fi + ) +else MANTYPE="cat" mansrcdir='$(srcdir)' fi @@ -1389,6 +1473,9 @@ fi case "$host" in *-*-sunos4*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # getcwd(3) opens a pipe to getpwd(1)!?! BROKEN_GETCWD=1 @@ -1400,6 +1487,9 @@ case "$host" in shadow_funcs="getpwanam issecure" ;; *-*-solaris2*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # To get the crypt(3) prototype (so we pass -Wall) OSDEFS="${OSDEFS} -D__EXTENSIONS__" # AFS support needs -lucb @@ -1410,11 +1500,12 @@ case "$host" in : ${mansectform='4'} : ${with_rpath='yes'} test -z "$with_pam" && AUTH_EXCL_DEF="PAM" + AC_CHECK_FUNCS(priv_set) ;; *-*-aix*) # To get all prototypes (so we pass -Wall) OSDEFS="${OSDEFS} -D_ALL_SOURCE -D_LINUX_SOURCE_COMPAT" - SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-bI:\$(srcdir)/aixcrypt.exp" if test X"$with_blibpath" != X"no"; then AC_MSG_CHECKING([if linker accepts -Wl,-blibpath]) O_LDFLAGS="$LDFLAGS" @@ -1432,9 +1523,15 @@ case "$host" in fi LDFLAGS="$O_LDFLAGS" - # Use authenticate(3) as the default authentication method - if test X"$with_aixauth" = X""; then - AC_CHECK_FUNCS(authenticate, [AUTH_EXCL_DEF="AIX_AUTH"]) + # On AIX 6 and higher default to PAM, else default to LAM + if test $OSMAJOR -ge 6; then + if test X"$with_pam" = X""; then + AUTH_EXCL_DEF="PAM" + fi + else + if test X"$with_aixauth" = X""; then + AC_CHECK_FUNCS(authenticate, [AUTH_EXCL_DEF="AIX_AUTH"]) + fi fi # AIX analog of nsswitch.conf, enabled by default @@ -1449,9 +1546,19 @@ case "$host" in with_netsvc="/etc/netsvc.conf" fi + # For implementing getgrouplist() + AC_CHECK_FUNCS(getgrset) + + # LDR_PRELOAD is only supported in AIX 5.3 and later + if test $OSMAJOR -lt 5; then + with_noexec=no + else + RTLD_PRELOAD_VAR="LDR_PRELOAD" + fi + # AIX-specific functions AC_CHECK_FUNCS(getuserattr setauthdb) - COMMON_OBJS="$COMMON_OBJS aix.o" + COMMON_OBJS="$COMMON_OBJS aix.lo" ;; *-*-hiuxmpp*) : ${mansectsu='1m'} @@ -1465,18 +1572,32 @@ case "$host" in : ${mansectsu='1m'} : ${mansectform='4'} + # The HP bundled compiler cannot generate shared libs if test -z "$GCC"; then - # HP-UX bundled compiler can't generate shared objects - if -z "$pic_flag"; then - with_noexec=no + AC_CACHE_CHECK([for HP bundled C compiler], + [sudo_cv_var_hpccbundled], + [if $CC -V 2>&1 | grep '^(Bundled)' >/dev/null 2>&1; then + sudo_cv_var_hpccbundled=yes + else + sudo_cv_var_hpccbundled=no + fi] + ) + if test "$sudo_cv_var_hpccbundled" = "yes"; then + AC_MSG_ERROR([The HP bundled C compiler is unable to build Sudo, you must use gcc or the HP ANSI C compiler instead.]) fi + fi - # Use the +DAportable flag on hppa if it is supported - case "$host_cpu" in - hppa*) + # Build PA-RISC1.1 objects for better portability + case "$host_cpu" in + hppa[[2-9]]*) _CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS +DAportable" - AC_CACHE_CHECK([whether $CC understands +DAportable], + if test -n "$GCC"; then + portable_flag="-march=1.1" + else + portable_flag="+DAportable" + fi + CFLAGS="$CFLAGS $portable_flag" + AC_CACHE_CHECK([whether $CC understands $portable_flag], [sudo_cv_var_daportable], [AC_LINK_IFELSE( [AC_LANG_PROGRAM([[]], [[]])], @@ -1489,19 +1610,11 @@ case "$host" in CFLAGS="$_CFLAGS" fi ;; - esac - fi + esac case "$host" in - *-*-hpux[1-8].*) + *-*-hpux[[1-8]].*) AC_DEFINE(BROKEN_SYSLOG) - - # Not sure if setuid binaries are safe in < 9.x - if test -n "$GCC"; then - SUDO_LDFLAGS="${SUDO_LDFLAGS} -static" - else - SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-a,archive" - fi ;; *-*-hpux9.*) AC_DEFINE(BROKEN_SYSLOG) @@ -1511,7 +1624,7 @@ case "$host" in # DCE support (requires ANSI C compiler) if test "$with_DCE" = "yes"; then # order of libs in 9.X is important. -lc_r must be last - SUDO_LIBS="${SUDO_LIBS} -ldce -lM -lc_r" + SUDOERS_LIBS="${SUDOERS_LIBS} -ldce -lM -lc_r" LIBS="${LIBS} -ldce -lM -lc_r" CPPFLAGS="${CPPFLAGS} -D_REENTRANT -I/usr/include/reentrant" fi @@ -1519,6 +1632,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" @@ -1529,7 +1644,7 @@ case "$host" in ;; *-dec-osf*) # ignore envariables wrt dynamic lib path - SUDO_LDFLAGS="${SUDO_LDFLAGS} -Wl,-no_library_replacement" + SUDOERS_LDFLAGS="${SUDOERS_LDFLAGS} -Wl,-no_library_replacement" : ${CHECKSIA='true'} AC_MSG_CHECKING(whether to disable sia support on Digital UNIX) @@ -1572,6 +1687,9 @@ case "$host" in ]], [[exit(0);]])], [AC_MSG_RESULT(no)], [AC_MSG_RESULT([yes, fixing locally]) sed 's:::g' < /usr/include/prot.h > prot.h ]) + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='8'} : ${mansectform='4'} ;; @@ -1599,6 +1717,9 @@ case "$host" in if test "$OSMAJOR" -le 4; then AC_CHECK_LIB(sun, getpwnam, [LIBS="${LIBS} -lsun"]) fi + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='1m'} : ${mansectform='4'} ;; @@ -1634,8 +1755,7 @@ case "$host" in *-*-isc*) OSDEFS="${OSDEFS} -D_ISC" LIB_CRYPT=1 - SUDO_LIBS="${SUDO_LIBS} -lcrypt" - LIBS="${LIBS} -lcrypt" + SUDOERS_LIBS="${SUDOERS_LIBS} -lcrypt" shadow_funcs="getspnam" shadow_libs="-lsec" @@ -1663,30 +1783,20 @@ case "$host" in : ${with_rpath='yes'} ;; *-ncr-sysv4*|*-ncr-sysvr4*) - AC_CHECK_LIB(c89, strcasecmp, AC_DEFINE(HAVE_STRCASECMP) [LIBS="${LIBS} -lc89"; ac_cv_func_strcasecmp=yes]) + AC_CHECK_LIB(c89, strcasecmp, [LIBS="${LIBS} -lc89"]) : ${mansectsu='1m'} : ${mansectform='4'} : ${with_rpath='yes'} ;; *-ccur-sysv4*|*-ccur-sysvr4*) LIBS="${LIBS} -lgen" - SUDO_LIBS="${SUDO_LIBS} -lgen" : ${mansectsu='1m'} : ${mansectform='4'} : ${with_rpath='yes'} ;; *-*-bsdi*) SKIP_SETREUID=yes - # Use shlicc for BSD/OS [23].x unless asked to do otherwise - if test "${with_CC+set}" != set -a "$ac_cv_prog_CC" = gcc; then - case "$OSMAJOR" in - 2|3) AC_MSG_NOTICE([using shlicc as CC]) - ac_cv_prog_CC=shlicc - CC="$ac_cv_prog_CC" - ;; - esac - fi - # Check for newer BSD auth API (just check for >= 3.0?) + # Check for newer BSD auth API if test -z "$with_bsdauth"; then AC_CHECK_FUNCS(auth_challenge, [AUTH_EXCL_DEF="BSD_AUTH"]) fi @@ -1699,8 +1809,9 @@ case "$host" in SKIP_SETREUID=yes ;; esac - if test "$with_skey" = "yes"; then - SUDO_LIBS="${SUDO_LIBS} -lmd" + OSDEFS="${OSDEFS} -D_BSD_SOURCE" + if test "${with_skey-'no'}" = "yes"; then + SUDOERS_LIBS="${SUDOERS_LIBS} -lmd" fi CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" @@ -1708,25 +1819,22 @@ case "$host" in ;; *-*-*openbsd*) # OpenBSD has a real setreuid(2) starting with 3.3 but - # we will use setreuid(2) instead. + # we will use setresuid(2) instead. SKIP_SETREUID=yes + OSDEFS="${OSDEFS} -D_BSD_SOURCE" CHECKSHADOW="false" # OpenBSD >= 3.0 supports BSD auth if test -z "$with_bsdauth"; then - case "$OSREV" in - [0-2].*) - ;; - *) + if test "$OSMAJOR" -ge 3; then AUTH_EXCL_DEF="BSD_AUTH" - ;; - esac + fi fi : ${with_logincap='maybe'} ;; *-*-*netbsd*) # NetBSD has a real setreuid(2) starting with 1.3.2 case "$OSREV" in - 0.9*|1.[012]*|1.3|1.3.1) + 0.9*|1.[[012]]*|1.3|1.3.1) SKIP_SETREUID=yes ;; esac @@ -1735,8 +1843,9 @@ case "$host" in : ${with_logincap='maybe'} ;; *-*-dragonfly*) - if test "$with_skey" = "yes"; then - SUDO_LIBS="${SUDO_LIBS} -lmd" + OSDEFS="${OSDEFS} -D_BSD_SOURCE" + if test "${with_skey-'no'}" = "yes"; then + SUDOERS_LIBS="${SUDOERS_LIBS} -lmd" fi CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" @@ -1753,11 +1862,15 @@ case "$host" in CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" : ${with_logincap='yes'} + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-nextstep*) # lockf() on is broken on the NeXT -- use flock instead ac_cv_func_lockf=no ac_cv_func_flock=yes + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-*sysv4*) : ${mansectsu='1m'} @@ -1773,6 +1886,20 @@ case "$host" in ;; esac +dnl +dnl Library preloading to support NOEXEC +dnl +if test -n "$with_noexec"; then + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_VAR, "$RTLD_PRELOAD_VAR") + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_DELIM, "$RTLD_PRELOAD_DELIM") + if test -n "$RTLD_PRELOAD_DEFAULT"; then + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_DEFAULT, "$RTLD_PRELOAD_DEFAULT") + fi + if test -n "$RTLD_PRELOAD_ENABLE_VAR"; then + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_ENABLE_VAR, "$RTLD_PRELOAD_ENABLE_VAR") + fi +fi + dnl dnl Check for mixing mutually exclusive and regular auth methods dnl @@ -1826,6 +1953,32 @@ dnl AC_PROG_GCC_TRADITIONAL AC_C_CONST AC_C_VOLATILE +# Check for variadic macro support in cpp +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +AC_INCLUDES_DEFAULT +#if defined(__GNUC__) && __GNUC__ == 2 +# define sudo_fprintf(fp, fmt...) fprintf((fp), (fmt)) +#else +# define sudo_fprintf(fp, ...) fprintf((fp), __VA_ARGS__) +#endif +], [sudo_fprintf(stderr, "a %s", "test");])], [], [AC_MSG_ERROR([Your C compiler doesn't support variadic macros, try building with gcc instead])]) +if test X"$with_gnu_ld" != "yes" -a -n "$GCC"; then + _CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -static-libgcc" + AC_CACHE_CHECK([whether $CC understands -static-libgcc], + [sudo_cv_var_gcc_static_libgcc], + [AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[]], [[]])], + [sudo_cv_var_gcc_static_libgcc=yes], + [sudo_cv_var_gcc_static_libgcc=no] + ) + ] + ) + CFLAGS="$_CFLAGS" + if test "$sudo_cv_var_gcc_static_libgcc" = "yes"; then + LTLDFLAGS="$LTLDFLAGS -Wc,-static-libgcc" + fi +fi dnl dnl Program checks dnl @@ -1836,9 +1989,7 @@ SUDO_PROG_BSHELL if test -z "$with_sendmail"; then SUDO_PROG_SENDMAIL fi -if test -z "$with_editor"; then - SUDO_PROG_VI -fi +SUDO_PROG_VI dnl dnl Check for authpriv support in syslog dnl @@ -1854,25 +2005,61 @@ 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_HEADER_STDBOOL +AC_HEADER_MAJOR +AC_CHECK_HEADERS(malloc.h netgroup.h paths.h spawn.h utime.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h) +AC_CHECK_HEADERS([procfs.h] [sys/procfs.h], [AC_CHECK_MEMBERS(struct psinfo.pr_ttydev, [AC_CHECK_FUNCS(_ttyname_dev)], [], [AC_INCLUDES_DEFAULT +#ifdef HAVE_PROCFS_H +#include +#endif +#ifdef HAVE_SYS_PROCFS_H +#include +#endif +])] +break) +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) -else - AC_CHECK_HEADERS(termio.h) +if test "$ac_cv_sys_posix_termios" != "yes"; then + AC_MSG_ERROR([Must have POSIX termios to build sudo]) fi SUDO_MAILDIR if test ${with_logincap-'no'} != "no"; then AC_CHECK_HEADERS(login_cap.h, [LOGINCAP_USAGE='[[-c class|-]] '; LCMAN=1 case "$OS" in - freebsd|netbsd) SUDO_LIBS="${SUDO_LIBS} -lutil" - ;; + freebsd|netbsd) + SUDO_LIBS="${SUDO_LIBS} -lutil" + SUDOERS_LIBS="${SUDOERS_LIBS} -lutil" + ;; esac ]) fi if test ${with_project-'no'} != "no"; then - AC_CHECK_HEADER(project.h, AC_DEFINE(HAVE_PROJECT_H) - [SUDO_LIBS="${SUDO_LIBS} -lproject"], -) + AC_CHECK_HEADER(project.h, [ + AC_CHECK_LIB(project, setproject, [ + AC_DEFINE(HAVE_PROJECT_H) + SUDO_LIBS="${SUDO_LIBS} -lproject" + ]) + ], []) fi dnl dnl typedef checks @@ -1882,53 +2069,130 @@ AC_TYPE_UID_T AC_CHECK_TYPE([__signed char], [], [AC_CHECK_TYPE([signed char], [AC_DEFINE(__signed, signed)], [AC_DEFINE(__signed, [])])]) AC_CHECK_TYPE([sig_atomic_t], [], [AC_DEFINE(sig_atomic_t, int)], [#include #include ]) -AC_CHECK_TYPES([sigaction_t], [AC_DEFINE(HAVE_SIGACTION_T)], [], [#include +AC_CHECK_TYPES([sigaction_t], [], [], [#include #include ]) -AC_CHECK_TYPE([struct timespec], [AC_DEFINE(HAVE_TIMESPEC)], [], [#include +AC_CHECK_TYPES([struct timespec], [], [], [#include #if TIME_WITH_SYS_TIME # include #endif #include ]) -AC_CHECK_TYPES([struct in6_addr], [AC_DEFINE(HAVE_IN6_ADDR)], [], [#include +AC_CHECK_TYPES([struct in6_addr], [], [], [#include #include ]) AC_TYPE_LONG_LONG_INT AC_CHECK_SIZEOF([long int]) -SUDO_TYPE_SIZE_T -SUDO_TYPE_SSIZE_T -SUDO_TYPE_DEV_T -SUDO_TYPE_INO_T +AC_CHECK_TYPE(size_t, unsigned int) +AC_CHECK_TYPE(ssize_t, int) +AC_CHECK_TYPE(dev_t, int) +AC_CHECK_TYPE(ino_t, unsigned int) +AC_CHECK_TYPE(socklen_t, [], [AC_DEFINE(socklen_t, unsigned int)], [ +AC_INCLUDES_DEFAULT +#include ]) SUDO_UID_T_LEN SUDO_SOCK_SA_LEN dnl -dnl only set RETSIGTYPE if it is not set already +dnl Check for utmp/utmpx struct members. +dnl We need to include OSDEFS for glibc which only has __e_termination +dnl visible when _GNU_SOURCE is *not* defined. dnl -case "$DEFS" in - *"RETSIGTYPE"*) ;; - *) AC_TYPE_SIGNAL;; -esac +_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $OSDEFS" +if test $ac_cv_header_utmpx_h = "yes"; then + AC_CHECK_MEMBERS([struct utmpx.ut_id, struct utmpx.ut_pid, struct utmpx.ut_tv, struct utmpx.ut_type], [], [], [ + #include + #include + ]) + dnl + dnl Check for ut_exit.__e_termination first, then ut_exit.e_termination + dnl + AC_CHECK_MEMBERS([struct utmpx.ut_exit.__e_termination], [AC_DEFINE(HAVE_STRUCT_UTMPX_UT_EXIT)], [ + AC_CHECK_MEMBERS([struct utmpx.ut_exit.e_termination], [AC_DEFINE(HAVE_STRUCT_UTMPX_UT_EXIT)], [], [ + #include + #include + ]) + ], [ + #include + #include + ]) +else + AC_CHECK_MEMBERS([struct utmp.ut_id, struct utmp.ut_pid, struct utmp.ut_tv, struct utmp.ut_type, struct utmp.ut_user], [], [], [ + #include + #include + ]) + dnl + dnl Check for ut_exit.__e_termination first, then ut_exit.e_termination + dnl + AC_CHECK_MEMBERS([struct utmp.ut_exit.__e_termination], [AC_DEFINE(HAVE_STRUCT_UTMP_UT_EXIT)], [ + AC_CHECK_MEMBERS([struct utmp.ut_exit.e_termination], [AC_DEFINE(HAVE_STRUCT_UTMP_UT_EXIT)], [], [ + #include + #include + ]) + ], [ + #include + #include + ]) +fi +CFLAGS="$_CFLAGS" + dnl dnl Function checks dnl AC_FUNC_GETGROUPS -AC_CHECK_FUNCS(strchr strrchr memchr memcpy memset sysconf tzset \ - strftime setrlimit initgroups getgroups fstat gettimeofday \ - regcomp setlocale getaddrinfo setenv vhangup \ - mbr_check_membership setrlimit64) +AC_CHECK_FUNCS(glob strrchr sysconf tzset strftime setenv \ + regcomp setlocale nl_langinfo mbr_check_membership \ + setrlimit64) +AC_REPLACE_FUNCS(getgrouplist) AC_CHECK_FUNCS(getline, [], [ AC_LIBOBJ(getline) AC_CHECK_FUNCS(fgetln) ]) -AC_CHECK_FUNCS(setsid, [], [ - AC_LIBOBJ(setsid) - AC_FUNC_SETPGRP -]) +dnl +dnl If libc supports _FORTIFY_SOURCE check functions, use it. +dnl +O_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" +AC_CHECK_FUNC(__sprintf_chk, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[char buf[4]; (void)sprintf(buf, "%s", "foo");]])], [OSDEFS="${OSDEFS} -D_FORTIFY_SOURCE=2"], []) +], []) +CPPFLAGS="$O_CPPFLAGS" -AC_CHECK_FUNCS(sysctl getutid getutxid, [break]) +utmp_style=LEGACY +AC_CHECK_FUNCS(getutxid getutid, [utmp_style=POSIX; break]) +if test "$utmp_style" = "LEGACY"; then + AC_CHECK_FUNCS(getttyent ttyslot, [break]) +fi -AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(util.h pty.h, [break])], [ +AC_CHECK_FUNCS(sysctl, [AC_CHECK_MEMBERS([struct kinfo_proc.ki_tdev], [], + [ + AC_CHECK_MEMBERS([struct kinfo_proc2.p_tdev], [], [ + AC_CHECK_MEMBERS([struct kinfo_proc.p_tdev], [], [ + AC_CHECK_MEMBERS([struct kinfo_proc.kp_eproc.e_tdev], [], [], [ + #include + #include + ]) + ], [ + #include + #include + ]) + ], + [ + #include + #include + ]) + ], + [ + #include + #include + #include + ]) +]) + +AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(libutil.h util.h pty.h, [break])], [ AC_CHECK_LIB(util, openpty, [ - AC_CHECK_HEADERS(util.h pty.h, [break]) - SUDO_LIBS="${SUDO_LIBS} -lutil" + AC_CHECK_HEADERS(libutil.h util.h pty.h, [break]) + case "$SUDO_LIBS" in + *-lutil*) ;; + *) SUDO_LIBS="${SUDO_LIBS} -lutil";; + esac AC_DEFINE(HAVE_OPENPTY) ], [ AC_CHECK_FUNCS(_getpty, [], [ @@ -1940,10 +2204,13 @@ AC_CHECK_FUNCS(openpty, [AC_CHECK_HEADERS(util.h pty.h, [break])], [ ]) ]) ]) -AC_CHECK_FUNCS(unsetenv, SUDO_FUNC_UNSETENV_VOID) +AC_CHECK_FUNCS(unsetenv, [SUDO_FUNC_UNSETENV_VOID], []) SUDO_FUNC_PUTENV_CONST if test -z "$SKIP_SETRESUID"; then - AC_CHECK_FUNCS(setresuid, [SKIP_SETREUID=yes]) + AC_CHECK_FUNCS(setresuid, [ + SKIP_SETREUID=yes + AC_CHECK_FUNCS(getresuid) + ]) fi if test -z "$SKIP_SETREUID"; then AC_CHECK_FUNCS(setreuid, [SKIP_SETEUID=yes]) @@ -1957,29 +2224,27 @@ fi if test -z "$BROKEN_GETCWD"; then AC_REPLACE_FUNCS(getcwd) fi -AC_CHECK_FUNCS(glob, [AC_MSG_CHECKING(for GLOB_BRACE and GLOB_TILDE in glob.h) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = GLOB_BRACE | GLOB_TILDE; (void)i;]])], [AC_DEFINE(HAVE_EXTENDED_GLOB) - AC_MSG_RESULT(yes)], [AC_LIBOBJ(glob) - AC_MSG_RESULT(no)])], [AC_LIBOBJ(glob)]) AC_CHECK_FUNCS(lockf flock, [break]) -AC_CHECK_FUNCS(waitpid wait3, [break]) AC_CHECK_FUNCS(innetgr _innetgr, [AC_CHECK_FUNCS(getdomainname) [break]]) AC_CHECK_FUNCS(utimes, [AC_CHECK_FUNCS(futimes futimesat, [break])], [AC_CHECK_FUNCS(futime) AC_LIBOBJ(utimes)]) AC_CHECK_FUNCS(killpg, [], [AC_LIBOBJ(killpg)]) -SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch)]) +SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch) + COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }fnm_test" +]) SUDO_FUNC_ISBLANK -AC_REPLACE_FUNCS(memrchr strerror strcasecmp sigaction strlcpy strlcat) +AC_REPLACE_FUNCS(memrchr pw_dup strlcpy strlcat) AC_CHECK_FUNCS(nanosleep, [], [ # On Solaris, nanosleep is in librt - AC_CHECK_LIB(rt, nanosleep, [LIBS="${LIBS} -lrt"], [AC_LIBOBJ(nanosleep)]) + AC_CHECK_LIB(rt, nanosleep, [REPLAY_LIBS="${REPLAY_LIBS} -lrt"], [AC_LIBOBJ(nanosleep)]) ]) AC_CHECK_FUNCS(closefrom, [], [AC_LIBOBJ(closefrom) AC_CHECK_DECL(F_CLOSEM, AC_DEFINE(HAVE_FCNTL_CLOSEM), [], [ #include #include ]) ]) -AC_CHECK_FUNCS(mkstemps, [], [SUDO_OBJS="${SUDO_OBJS} mkstemps.o" +AC_CHECK_FUNCS(mkstemps mkdtemp, [], [ AC_CHECK_FUNCS(random lrand48, [break]) + AC_LIBOBJ(mktemp) ]) AC_CHECK_FUNCS(snprintf vsnprintf asprintf vasprintf, , [NEED_SNPRINTF=1]) if test X"$ac_cv_type_struct_timespec" != X"no"; then @@ -1993,6 +2258,10 @@ dnl AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include #include <$ac_header_dirent>]], [[DIR *d; (void)dirfd(d);]])], [AC_DEFINE(HAVE_DIRFD)], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include #include <$ac_header_dirent>]], [[DIR d; memset(&d, 0, sizeof(d)); return(d.dd_fd);]])], [AC_DEFINE(HAVE_DD_FD)], [])]) +AC_CHECK_MEMBERS([struct dirent.d_type], [], [], [ +AC_INCLUDES_DEFAULT +#include <$ac_header_dirent> +]) dnl dnl If NEED_SNPRINTF is set, add snprintf.c to LIBOBJS dnl (it contains snprintf, vsnprintf, asprintf, and vasprintf) @@ -2003,20 +2272,88 @@ fi dnl dnl If socket(2) not in libc, check -lsocket and -linet dnl May need to link with *both* -lnsl and -lsocket due to unresolved symbols -dnl In this case we look for main(), not socket() to avoid using a cached value dnl -AC_CHECK_FUNC(socket, , [AC_CHECK_LIB(socket, socket, [NET_LIBS="${NET_LIBS} -lsocket"; LIBS="${LIBS} -lsocket"], AC_CHECK_LIB(inet, socket, [NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet"], AC_MSG_WARN(unable to find socket() trying -lsocket -lnsl) -AC_CHECK_LIB(socket, socket, [NET_LIBS="${NET_LIBS} -lsocket -lnsl"; LIBS="${LIBS} -lsocket -lnsl"], , -lnsl)))]) +AC_CHECK_FUNC(socket, [], [ + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[[^ ]]*//'`" + SUDO_CHECK_LIB($lib, socket, [NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; break], [], [$extralibs]) + done +]) dnl dnl If inet_addr(3) not in libc, check -lnsl and -linet dnl May need to link with *both* -lnsl and -lsocket due to unresolved symbols dnl -AC_CHECK_FUNC(inet_addr, , [AC_CHECK_FUNC(__inet_addr, , AC_CHECK_LIB(nsl, inet_addr, [NET_LIBS="${NET_LIBS} -lnsl"; LIBS="${LIBS} -lnsl"], AC_CHECK_LIB(inet, inet_addr, [NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet"], AC_MSG_WARN(unable to find inet_addr() trying -lsocket -lnsl) -AC_CHECK_LIB(socket, inet_addr, [NET_LIBS="${NET_LIBS} -lsocket -lnsl"; LIBS="${LIBS} -lsocket -lnsl"], , -lnsl))))]) +AC_CHECK_FUNC(inet_addr, [], [ + AC_CHECK_FUNC(__inet_addr, [], [ + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[[^ ]]*//'`" + SUDO_CHECK_LIB($lib, inet_addr, [NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; break], [], [$extralibs]) + done + ]) +]) dnl dnl If syslog(3) not in libc, check -lsocket, -lnsl and -linet dnl -AC_CHECK_FUNC(syslog, , [AC_CHECK_LIB(socket, syslog, [NET_LIBS="${NET_LIBS} -lsocket"; LIBS="${LIBS} -lsocket"], AC_CHECK_LIB(nsl, syslog, [NET_LIBS="${NET_LIBS} -lnsl"; LIBS="${LIBS} -lnsl"], AC_CHECK_LIB(inet, syslog, [NET_LIBS="${NET_LIBS} -linet"; LIBS="${LIBS} -linet"])))]) +AC_CHECK_FUNC(syslog, [], [ + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[[^ ]]*//'`" + SUDO_CHECK_LIB($lib, syslog, [NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; break], [], [$extralibs]) + done +]) +dnl +dnl If getaddrinfo(3) not in libc, check -lsocket and -linet +dnl May need to link with *both* -lnsl and -lsocket due to unresolved symbols. +dnl +AC_CHECK_FUNCS(getaddrinfo, [], [ + found=no + for libs in "-lsocket" "-linet" "-lsocket -lnsl"; do + _libs= + for lib in $libs; do + case "$NET_LIBS" in + *"$lib"*) ;; + *) _libs="$_libs $lib";; + esac + done + libs="${_libs# }" + test -z "$libs" && continue + lib="`echo \"$libs\"|sed -e 's/^-l//' -e 's/ .*$//'`" + extralibs="`echo \"$libs\"|sed 's/^-l[[^ ]]*//'`" + SUDO_CHECK_LIB($lib, getaddrinfo, [NET_LIBS="${NET_LIBS} $libs"; LIBS="${LIBS} $libs"; found=yes; break], [], [$extralibs]) + done + if test X"$found" != X"no"; then + AC_DEFINE(HAVE_GETADDRINFO) + fi +]) dnl dnl Check for getprogname() or __progname dnl @@ -2031,6 +2368,130 @@ AC_CHECK_FUNCS(getprogname, , [ fi AC_MSG_RESULT($sudo_cv___progname) ]) +dnl +dnl Check for __func__ or __FUNCTION__ +dnl +AC_MSG_CHECKING([for __func__]) +AC_CACHE_VAL(sudo_cv___func__, [ +AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[(void)puts(__func__);]])], [sudo_cv___func__=yes], [sudo_cv___func__=no])]) +AC_MSG_RESULT($sudo_cv___func__) +if test "$sudo_cv___func__" = "yes"; then + AC_DEFINE(HAVE___FUNC__) +elif test -n "$GCC"; then + AC_MSG_CHECKING([for __FUNCTION__]) + AC_CACHE_VAL(sudo_cv___FUNCTION__, [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[(void)puts(__FUNCTION__);]])], [sudo_cv___FUNCTION__=yes], [sudo_cv___FUNCTION__=no])]) + AC_MSG_RESULT($sudo_cv___FUNCTION__) + if test "$sudo_cv___FUNCTION__" = "yes"; then + AC_DEFINE(HAVE___FUNC__) + AC_DEFINE(__func__, __FUNCTION__, [Define to __FUNCTION__ if your compiler support __FUNCTION__ but not __func__]) + fi +fi + +# gettext() and friends may be located in libc (Linux and Solaris) +# or in libintl. However, it is possible to have libintl installed +# even when gettext() is present in libc. In the case of GNU libintl, +# gettext() will be defined to gettext_libintl in libintl.h. +# Since gcc prefers /usr/local/include to /usr/include, we need to +# make sure we use the gettext() that matches the include file. +if test "$enable_nls" != "no"; then + if test "$enable_nls" != "yes"; then + CPPFLAGS="${CPPFLAGS} -I${enable_nls}/include" + SUDO_APPEND_LIBPATH(LDFLAGS, [$enable_nls/lib]) + fi + OLIBS="$LIBS" + for l in "libc" "-lintl" "-lintl -liconv"; do + if test "$l" = "libc"; then + # If user specified a dir for libintl ignore libc + if test "$enable_nls" != "yes"; then + continue + fi + gettext_name=sudo_cv_gettext + AC_MSG_CHECKING([for gettext]) + else + LIBS="$OLIBS $l" + gettext_name=sudo_cv_gettext"`echo $l|sed -e 's/ //g' -e 's/-/_/g'`" + AC_MSG_CHECKING([for gettext in $l]) + fi + AC_CACHE_VAL($gettext_name, [ + AC_LINK_IFELSE( + [ + AC_LANG_PROGRAM([[#include ]], [(void)gettext((char *)0);]) + ], [eval $gettext_name=yes], [eval $gettext_name=no] + ) + ]) + eval gettext_result="\$$gettext_name" + AC_MSG_RESULT($gettext_result) + test "$gettext_result" = "yes" && break + done + LIBS="$OLIBS" + + if test "$sudo_cv_gettext" = "yes"; then + AC_DEFINE(HAVE_LIBINTL_H) + SUDO_NLS=enabled + elif test "$sudo_cv_gettext_lintl" = "yes"; then + AC_DEFINE(HAVE_LIBINTL_H) + SUDO_NLS=enabled + LIBINTL="-lintl" + elif test "$sudo_cv_gettext_lintl_liconv" = "yes"; then + AC_DEFINE(HAVE_LIBINTL_H) + SUDO_NLS=enabled + LIBINTL="-lintl -liconv" + fi +fi + +dnl +dnl Deferred zlib option processing. +dnl By default we use the system zlib if it is present. +dnl If a directory was specified for zlib (or we are use sudo's version), +dnl prepend the include dir to make sure we get the right zlib header. +dnl +case "$enable_zlib" 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="-I${enable_zlib}/include ${CPPFLAGS}" + 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='-I$(top_builddir)/zlib -I$(top_srcdir)/zlib '"${CPPFLAGS}" + ZLIB="${ZLIB}"' $(top_builddir)/zlib/libz.la' + ZLIB_SRC=zlib + AC_CONFIG_HEADER([zlib/zconf.h]) + AC_CONFIG_FILES([zlib/Makefile]) +fi + +dnl +dnl Check for errno declaration in errno.h +dnl +AC_CHECK_DECLS([errno], [], [], [ +AC_INCLUDES_DEFAULT +#include +]) + +dnl +dnl Check for h_errno declaration in netdb.h +dnl +AC_CHECK_DECLS([h_errno], [], [], [ +AC_INCLUDES_DEFAULT +#include +]) dnl dnl Check for strsignal() or sys_siglist @@ -2086,25 +2547,47 @@ dnl PAM support. Systems that use PAM by default set with_pam=default dnl and we do the actual tests here. dnl if test ${with_pam-"no"} != "no"; then - dnl - dnl Some platforms need libdl for dlopen - dnl - case "$LIBS" in - *-ldl*) SUDO_LIBS="${SUDO_LIBS} -lpam" - ;; - *) AC_CHECK_LIB([dl], [main], [SUDO_LIBS="${SUDO_LIBS} -lpam -ldl"], [SUDO_LIBS="${SUDO_LIBS} -lpam"]) - ac_cv_lib_dl=ac_cv_lib_dl_main - ;; - esac + # + # Check for pam_start() in libpam first, then for pam_appl.h. + # + found_pam_lib=no + AC_CHECK_LIB(pam, pam_start, [found_pam_lib=yes], [], [$lt_cv_dlopen_libs]) + # + # Some PAM implementations (MacOS X for example) put the PAM headers + # in /usr/include/pam instead of /usr/include/security... + # + found_pam_hdrs=no + AC_CHECK_HEADERS([security/pam_appl.h] [pam/pam_appl.h], [found_pam_hdrs=yes; break]) + if test "$found_pam_lib" = "yes" -a "$found_pam_hdrs" = "yes"; then + # Found both PAM libs and headers + with_pam=yes + elif test "$with_pam" = "yes"; then + if test "$found_pam_lib" = "no"; then + AC_MSG_ERROR(["--with-pam specified but unable to locate PAM development library."]) + fi + if test "$found_pam_hdrs" = "no"; then + AC_MSG_ERROR(["--with-pam specified but unable to locate PAM development headers."]) + fi + elif test "$found_pam_lib" != "$found_pam_hdrs"; then + if test "$found_pam_lib" = "no"; then + AC_MSG_ERROR(["found PAM headers but no PAM development library; specify --without-pam to build without PAM"]) + fi + if test "$found_pam_hdrs" = "no"; then + AC_MSG_ERROR(["found PAM library but no PAM development headers; specify --without-pam to build without PAM"]) + fi + fi - dnl - dnl Some PAM implementations (MacOS X for example) put the PAM headers - dnl in /usr/include/pam instead of /usr/include/security... - dnl - AC_CHECK_HEADERS([security/pam_appl.h] [pam/pam_appl.h], [with_pam=yes; break]) if test "$with_pam" = "yes"; then + # Older PAM implementations lack pam_getenvlist + OLIBS="$LIBS" + LIBS="$LIBS -lpam $lt_cv_dlopen_libs" + AC_CHECK_FUNCS(pam_getenvlist) + LIBS="$OLIBS" + + # We already link with -ldl if needed (see LIBDL below) + SUDOERS_LIBS="${SUDOERS_LIBS} -lpam" AC_DEFINE(HAVE_PAM) - AUTH_OBJS="$AUTH_OBJS pam.o"; + AUTH_OBJS="$AUTH_OBJS pam.lo"; AUTH_EXCL=PAM AC_ARG_WITH(pam-login, [AS_HELP_STRING([--with-pam-login], [enable specific PAM session for sudo -i])], @@ -2125,25 +2608,12 @@ if test ${with_pam-"no"} != "no"; then yes) AC_MSG_RESULT(yes) ;; no) AC_MSG_RESULT(no) - AC_DEFINE([NO_PAM_SESSION], [], [PAM session support disabled]) + AC_DEFINE(NO_PAM_SESSION) ;; *) AC_MSG_RESULT(no) AC_MSG_WARN([Ignoring unknown argument to --enable-pam-session: $enableval]) ;; esac], AC_MSG_RESULT(yes)) - - case $host in - *-*-linux*|*-*-solaris*) - # dgettext() may be defined to dgettext_libintl in the - # header file, so first check that it links w/ additional - # libs, then try with -lintl - AC_LINK_IFELSE([AC_LANG_PROGRAM( - [[#include ]], [(void)dgettext((char *)0, (char *)0);])], - [AC_DEFINE(HAVE_DGETTEXT)], - [AC_CHECK_LIB(intl, dgettext, [LIBS="${LIBS} -lintl"] - [AC_DEFINE(HAVE_DGETTEXT)])]) - ;; - esac fi fi @@ -2155,8 +2625,8 @@ if test ${with_aixauth-'no'} != "no"; then if test X"$with_aixauth" != X"maybe" -o X"$AUTH_EXCL" = X""; then AC_MSG_NOTICE([using AIX general authentication]) AC_DEFINE(HAVE_AIXAUTH) - AUTH_OBJS="$AUTH_OBJS aix_auth.o"; - SUDO_LIBS="${SUDO_LIBS} -ls" + AUTH_OBJS="$AUTH_OBJS aix_auth.lo"; + SUDOERS_LIBS="${SUDOERS_LIBS} -ls" AUTH_EXCL=AIX_AUTH fi fi @@ -2167,7 +2637,7 @@ dnl If set to "maybe" only enable if no other exclusive method in use. dnl if test ${with_bsdauth-'no'} != "no"; then AC_CHECK_HEADER(bsd_auth.h, AC_DEFINE(HAVE_BSD_AUTH_H) - [AUTH_OBJS="$AUTH_OBJS bsdauth.o"] + [AUTH_OBJS="$AUTH_OBJS bsdauth.lo"] [BSDAUTH_USAGE='[[-a auth_type]] '] [AUTH_EXCL=BSD_AUTH; BAMAN=1], [AC_MSG_ERROR([BSD authentication was specified but bsd_auth.h could not be found])]) @@ -2180,7 +2650,7 @@ if test ${CHECKSIA-'false'} = "true"; then AC_CHECK_FUNCS(sia_ses_init, [found=true], [found=false]) if test "$found" = "true"; then AUTH_EXCL=SIA - AUTH_OBJS="$AUTH_OBJS sia.o" + AUTH_OBJS="$AUTH_OBJS sia.lo" fi fi @@ -2189,12 +2659,12 @@ dnl extra FWTK libs + includes dnl if test ${with_fwtk-'no'} != "no"; then if test "$with_fwtk" != "yes"; then - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_fwtk}]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_fwtk}]) CPPFLAGS="${CPPFLAGS} -I${with_fwtk}" with_fwtk=yes fi - SUDO_LIBS="${SUDO_LIBS} -lauth -lfwall" - AUTH_OBJS="$AUTH_OBJS fwtk.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lauth -lfwall" + AUTH_OBJS="$AUTH_OBJS fwtk.lo" fi dnl @@ -2209,27 +2679,9 @@ if test ${with_SecurID-'no'} != "no"; then with_SecurID=/usr/ace fi CPPFLAGS="${CPPFLAGS} -I${with_SecurID}" - _LDFLAGS="${LDFLAGS}" SUDO_APPEND_LIBPATH(LDFLAGS, [${with_SecurID}]) - # - # Determine whether to use the new or old SecurID API - # - AC_CHECK_LIB(aceclnt, SD_Init, - [ - AUTH_OBJS="$AUTH_OBJS securid5.o"; - SUDO_LIBS="${SUDO_LIBS} -laceclnt -lpthread" - ] - [ - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_SecurID}]) - ], [ - AUTH_OBJS="$AUTH_OBJS securid.o"; - SUDO_LIBS="${SUDO_LIBS} ${with_SecurID}/sdiclient.a" - ], - [ - -lpthread - ] - ) - LDFLAGS="${_LDFLAGS}" + SUDOERS_LIBS="${SUDOERS_LIBS} -laceclnt -lpthread" + AUTH_OBJS="$AUTH_OBJS securid5.lo"; fi dnl @@ -2249,65 +2701,6 @@ if test -z "${AUTH_EXCL}" -a -n "$AUTH_DEF"; then done fi -dnl -dnl Kerberos IV -dnl -if test ${with_kerb4-'no'} != "no"; then - AC_DEFINE(HAVE_KERB4) - dnl - dnl Use the specified directory, if any, else search for correct inc dir - dnl - O_LDFLAGS="$LDFLAGS" - if test "$with_kerb4" = "yes"; then - found=no - O_CPPFLAGS="$CPPFLAGS" - for dir in "" "kerberosIV/" "krb4/" "kerberos4/" "kerberosv4/"; do - CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" - AC_PREPROC_IFELSE([#include ], [found=yes; break]) - done - test X"$found" = X"no" && CPPFLAGS="$O_CPPFLAGS" - else - SUDO_APPEND_LIBPATH(LDFLAGS, [${with_kerb4}/lib]) - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_kerb4}/lib]) - CPPFLAGS="$CPPFLAGS -I${with_kerb4}/include" - AC_CHECK_HEADER([krb.h], [found=yes], [found=no]) - fi - if test X"$found" = X"no"; then - AC_MSG_WARN([Unable to locate Kerberos IV include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS]) - fi - - dnl - dnl Check for -ldes vs. -ldes425 - dnl - AC_CHECK_LIB(des, des_cbc_encrypt, [K4LIBS="-ldes"], [ - AC_CHECK_LIB(des425, des_cbc_encrypt, [K4LIBS="-ldes425"], [K4LIBS=""]) - ]) - dnl - dnl Try to determine whether we have KTH or MIT/CNS Kerberos IV - dnl - AC_MSG_CHECKING(whether we are using KTH Kerberos IV) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[const char *tmp = krb4_version;]])], [ - AC_MSG_RESULT(yes) - K4LIBS="${K4LIBS} -lcom_err" - AC_CHECK_LIB(roken, main, [K4LIBS="${K4LIBS} -lroken"]) - ], [ - AC_MSG_RESULT(no) - ] - ) - dnl - dnl The actual Kerberos IV lib might be -lkrb or -lkrb4 - dnl - AC_CHECK_LIB(krb, main, [K4LIBS="-lkrb $K4LIBS"], [ - AC_CHECK_LIB(krb4, main, [K4LIBS="-lkrb4 $K4LIBS"], - [K4LIBS="-lkrb $K4LIBS"] - [AC_MSG_WARN([Unable to locate Kerberos IV libraries, you will have to edit the Makefile and add -L/path/to/krb/libs to SUDO_LDFLAGS and possibly add Kerberos libs to SUDO_LIBS])] - , [$K4LIBS]) - ], [$K4LIBS]) - LDFLAGS="$O_LDFLAGS" - SUDO_LIBS="${SUDO_LIBS} $K4LIBS" - AUTH_OBJS="$AUTH_OBJS kerb4.o" -fi - dnl dnl Kerberos V dnl There is an easy way and a hard way... @@ -2316,9 +2709,9 @@ if test ${with_kerb5-'no'} != "no"; then AC_CHECK_PROG(KRB5CONFIG, krb5-config, yes, "") if test -n "$KRB5CONFIG"; then AC_DEFINE(HAVE_KERB5) - AUTH_OBJS="$AUTH_OBJS kerb5.o" + AUTH_OBJS="$AUTH_OBJS kerb5.lo" CPPFLAGS="$CPPFLAGS `krb5-config --cflags`" - SUDO_LIBS="$SUDO_LIBS `krb5-config --libs`" + SUDOERS_LIBS="$SUDOERS_LIBS `krb5-config --libs`" dnl dnl Try to determine whether we have Heimdal or MIT Kerberos dnl @@ -2330,57 +2723,56 @@ if test ${with_kerb5-'no'} != "no"; then AC_MSG_RESULT(no) ] ) - fi -fi -if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then - AC_DEFINE(HAVE_KERB5) - dnl - dnl Use the specified directory, if any, else search for correct inc dir - dnl - if test "$with_kerb5" = "yes"; then - found=no - O_CPPFLAGS="$CPPFLAGS" - for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do - CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" - AC_PREPROC_IFELSE([#include ], [found=yes; break]) - done - if test X"$found" = X"no"; then - CPPFLAGS="$O_CPPFLAGS" - AC_MSG_WARN([Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS]) - fi else - dnl XXX - try to include krb5.h here too - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_kerb5}/lib]) - CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include" - fi + AC_DEFINE(HAVE_KERB5) + dnl + dnl Use the specified directory, if any, else search for correct inc dir + dnl + if test "$with_kerb5" = "yes"; then + found=no + O_CPPFLAGS="$CPPFLAGS" + for dir in "" "kerberosV/" "krb5/" "kerberos5/" "kerberosv5/"; do + CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[#include ]])], [found=yes; break]) + done + if test X"$found" = X"no"; then + CPPFLAGS="$O_CPPFLAGS" + AC_MSG_WARN([Unable to locate Kerberos V include files, you will have to edit the Makefile and add -I/path/to/krb/includes to CPPFLAGS]) + fi + else + dnl XXX - try to include krb5.h here too + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_kerb5}/lib]) + CPPFLAGS="$CPPFLAGS -I${with_kerb5}/include" + fi - dnl - dnl Try to determine whether we have Heimdal or MIT Kerberos - dnl - AC_MSG_CHECKING(whether we are using Heimdal) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[const char *tmp = heimdal_version;]])], [ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_HEIMDAL) - # XXX - need to check whether -lcrypo is needed! - SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1" - AC_CHECK_LIB(roken, main, [SUDO_LIBS="${SUDO_LIBS} -lroken"]) - ], [ - AC_MSG_RESULT(no) - SUDO_LIBS="${SUDO_LIBS} -lkrb5 -lk5crypto -lcom_err" - AC_CHECK_LIB(krb5support, main, [SUDO_LIBS="${SUDO_LIBS} -lkrb5support"]) - ]) - AUTH_OBJS="$AUTH_OBJS kerb5.o" + dnl + dnl Try to determine whether we have Heimdal or MIT Kerberos + dnl + AC_MSG_CHECKING(whether we are using Heimdal) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[const char *tmp = heimdal_version;]])], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_HEIMDAL) + # XXX - need to check whether -lcrypo is needed! + SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lcrypto -ldes -lcom_err -lasn1" + AC_CHECK_LIB(roken, main, [SUDOERS_LIBS="${SUDOERS_LIBS} -lroken"]) + ], [ + AC_MSG_RESULT(no) + SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5 -lk5crypto -lcom_err" + AC_CHECK_LIB(krb5support, main, [SUDOERS_LIBS="${SUDOERS_LIBS} -lkrb5support"]) + ]) + AUTH_OBJS="$AUTH_OBJS kerb5.lo" + fi _LIBS="$LIBS" - LIBS="${LIBS} ${SUDO_LIBS}" + LIBS="${LIBS} ${SUDOERS_LIBS}" AC_CHECK_FUNCS(krb5_verify_user krb5_init_secure_context) AC_CHECK_FUNCS(krb5_get_init_creds_opt_alloc, [ AC_CACHE_CHECK([whether krb5_get_init_creds_opt_free takes a context], sudo_cv_krb5_get_init_creds_opt_free_two_args, [ - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[#include ]], - [[krb5_get_init_creds_opt_free(NULL, NULL);]] - )], + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include ]], + [[krb5_get_init_creds_opt_free(NULL, NULL);]] + )], [sudo_cv_krb5_get_init_creds_opt_free_two_args=yes], [sudo_cv_krb5_get_init_creds_opt_free_two_args=no] ) @@ -2391,6 +2783,18 @@ if test ${with_kerb5-'no'} != "no" -a -z "$KRB5CONFIG"; then AC_DEFINE(HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS) fi LIBS="$_LIBS" + AC_MSG_CHECKING(whether to use an instance name for Kerberos V) + AC_ARG_ENABLE(kerb5-instance, + [AS_HELP_STRING([--enable-kerb5-instance], [instance string to append to the username (separated by a slash)])], + [ case "$enableval" in + yes) AC_MSG_ERROR(["must give --enable-kerb5-instance an argument."]) + ;; + no) AC_MSG_RESULT(no) + ;; + *) SUDO_DEFINE_UNQUOTED(SUDO_KRB5_INSTANCE, "$enableval") + AC_MSG_RESULT([$enableval]) + ;; + esac], AC_MSG_RESULT(no)) fi dnl @@ -2402,12 +2806,12 @@ if test ${with_AFS-'no'} = "yes"; then AFSLIBDIRS="/usr/lib/afs /usr/afsws/lib /usr/afsws/lib/afs" for i in $AFSLIBDIRS; do if test -d ${i}; then - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [$i]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [$i]) FOUND_AFSLIBDIR=true fi done if test -z "$FOUND_AFSLIBDIR"; then - AC_MSG_WARN([Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDO_LDFLAGS or rerun configure with the --with-libpath options.]) + AC_MSG_WARN([Unable to locate AFS libraries, you will have to edit the Makefile and add -L/path/to/afs/libs to SUDOERS_LDFLAGS or rerun configure with the --with-libpath options.]) fi # Order is important here. Note that we build AFS_LIBS from right to left @@ -2437,7 +2841,7 @@ if test ${with_AFS-'no'} = "yes"; then AC_MSG_WARN([Unable to locate AFS include dir, you may have to edit the Makefile and add -I/path/to/afs/includes to CPPFLAGS or rerun configure with the --with-incpath options.]) fi - AUTH_OBJS="$AUTH_OBJS afs.o" + AUTH_OBJS="$AUTH_OBJS afs.lo" fi dnl @@ -2446,75 +2850,91 @@ dnl Order of libs in HP-UX 10.x is important, -ldce must be last. dnl if test ${with_DCE-'no'} = "yes"; then DCE_OBJS="${DCE_OBJS} dce_pwent.o" - SUDO_LIBS="${SUDO_LIBS} -ldce" - AUTH_OBJS="$AUTH_OBJS dce.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -ldce" + AUTH_OBJS="$AUTH_OBJS dce.lo" fi dnl 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" SUDO_APPEND_LIBPATH(LDFLAGS, [${with_skey}/lib]) - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_skey}/lib]) - AC_PREPROC_IFELSE([#include ], [found=yes], [found=no]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_skey}/lib]) + AC_CHECK_HEADER([skey.h], [found=yes], [found=no], [#include ]) else found=no O_CPPFLAGS="$CPPFLAGS" for dir in "" "/usr/local" "/usr/contrib"; do test -n "$dir" && CPPFLAGS="$O_CPPFLAGS -I${dir}/include" - AC_PREPROC_IFELSE([#include ], [found=yes; break]) + AC_CHECK_HEADER([skey.h], [found=yes; break], [], + [#include ]) done if test "$found" = "no" -o -z "$dir"; then CPPFLAGS="$O_CPPFLAGS" else SUDO_APPEND_LIBPATH(LDFLAGS, [${dir}/lib]) - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${dir}/lib]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${dir}/lib]) + fi + if test "$found" = "no"; then + AC_MSG_WARN([Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS]) fi fi - if test "$found" = "no"; then - AC_MSG_WARN([Unable to locate skey.h, you will have to edit the Makefile and add -I/path/to/skey/includes to CPPFLAGS]) - fi - AC_CHECK_LIB(skey, main, [found=yes], [AC_MSG_WARN([Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDO_LDFLAGS])]) + AC_CHECK_LIB(skey, main, [found=yes], [AC_MSG_WARN([Unable to locate libskey.a, you will have to edit the Makefile and add -L/path/to/skey/lib to SUDOERS_LDFLAGS])]) AC_CHECK_LIB(skey, skeyaccess, AC_DEFINE(HAVE_SKEYACCESS)) + + AC_MSG_CHECKING([for RFC1938-compliant skeychallenge]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #include ]], + [[skeychallenge(NULL, NULL, NULL, 0);]] + )], [ + AC_DEFINE(HAVE_RFC1938_SKEYCHALLENGE) + AC_MSG_RESULT([yes]) + ], [ + AC_MSG_RESULT([no]) + ] + ) + LDFLAGS="$O_LDFLAGS" - SUDO_LIBS="${SUDO_LIBS} -lskey" - AUTH_OBJS="$AUTH_OBJS rfc1938.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lskey" + AUTH_OBJS="$AUTH_OBJS rfc1938.lo" fi dnl 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" SUDO_APPEND_LIBPATH(LDFLAGS, [${with_opie}/lib]) - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_opie}/lib]) - AC_PREPROC_IFELSE([#include ], [found=yes], [found=no]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_opie}/lib]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[#include ]])], [found=yes], [found=no]) else found=no O_CPPFLAGS="$CPPFLAGS" for dir in "" "/usr/local" "/usr/contrib"; do test -n "$dir" && CPPFLAGS="$O_CPPFLAGS -I${dir}/include" - AC_PREPROC_IFELSE([#include ], [found=yes; break]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[#include ]])], [found=yes; break]) done if test "$found" = "no" -o -z "$dir"; then CPPFLAGS="$O_CPPFLAGS" else SUDO_APPEND_LIBPATH(LDFLAGS, [${dir}/lib]) - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${dir}/lib]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${dir}/lib]) + fi + if test "$found" = "no"; then + AC_MSG_WARN([Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS]) fi fi - if test "$found" = "no"; then - AC_MSG_WARN([Unable to locate opie.h, you will have to edit the Makefile and add -I/path/to/opie/includes to CPPFLAGS]) - fi - AC_CHECK_LIB(opie, main, [found=yes], [AC_MSG_WARN([Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDO_LDFLAGS])]) + AC_CHECK_LIB(opie, main, [found=yes], [AC_MSG_WARN([Unable to locate libopie.a, you will have to edit the Makefile and add -L/path/to/opie/lib to SUDOERS_LDFLAGS])]) LDFLAGS="$O_LDFLAGS" - SUDO_LIBS="${SUDO_LIBS} -lopie" - AUTH_OBJS="$AUTH_OBJS rfc1938.o" + SUDOERS_LIBS="${SUDOERS_LIBS} -lopie" + AUTH_OBJS="$AUTH_OBJS rfc1938.lo" fi dnl @@ -2526,8 +2946,10 @@ 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 - AC_SEARCH_LIBS([crypt], [crypt crypt_d ufc], [test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"]) + if test -z "$LIB_CRYPT"; then + _LIBS="$LIBS" + AC_SEARCH_LIBS([crypt], [crypt crypt_d ufc], [test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"]) + LIBS="$_LIBS" fi if test "$CHECKSHADOW" = "true" -a -n "$shadow_funcs"; then @@ -2536,12 +2958,12 @@ if test ${with_passwd-'no'} != "no"; then found=no AC_CHECK_FUNCS($shadow_funcs, [found=yes]) if test "$found" = "yes"; then - SUDO_LIBS="$SUDO_LIBS $shadow_libs" + SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs" elif test -n "$shadow_libs_optional"; then LIBS="$LIBS $shadow_libs_optional" AC_CHECK_FUNCS($shadow_funcs, [found=yes]) if test "$found" = "yes"; then - SUDO_LIBS="$SUDO_LIBS $shadow_libs $shadow_libs_optional" + SUDOERS_LIBS="$SUDOERS_LIBS $shadow_libs $shadow_libs_optional" fi fi if test "$found" = "yes"; then @@ -2555,14 +2977,14 @@ if test ${with_passwd-'no'} != "no"; then CHECKSHADOW=false fi if test "$CHECKSHADOW" = "true"; then - AC_SEARCH_LIBS([getspnam], [gen], [AC_DEFINE(HAVE_GETSPNAM)] [CHECKSHADOW=false; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"]) + AC_SEARCH_LIBS([getspnam], [gen], [AC_DEFINE(HAVE_GETSPNAM)] [CHECKSHADOW=false; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"]) fi if test "$CHECKSHADOW" = "true"; then - AC_SEARCH_LIBS([getprpwnam], [sec security prot], [AC_DEFINE(HAVE_GETPRPWNAM)] [CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDO_LIBS="${SUDO_LIBS} $ac_res"]) + AC_SEARCH_LIBS([getprpwnam], [sec security prot], [AC_DEFINE(HAVE_GETPRPWNAM)] [CHECKSHADOW=false; SECUREWARE=1; test -n "$ac_lib" && SUDOERS_LIBS="${SUDOERS_LIBS} $ac_res"]) fi if test -n "$SECUREWARE"; then AC_CHECK_FUNCS(bigcrypt set_auth_parameters initprivs) - AUTH_OBJS="$AUTH_OBJS secureware.o" + AUTH_OBJS="$AUTH_OBJS secureware.lo" fi fi @@ -2572,12 +2994,12 @@ dnl if test ${with_ldap-'no'} != "no"; then _LDFLAGS="$LDFLAGS" if test "$with_ldap" != "yes"; then - SUDO_APPEND_LIBPATH(SUDO_LDFLAGS, [${with_ldap}/lib]) + SUDO_APPEND_LIBPATH(SUDOERS_LDFLAGS, [${with_ldap}/lib]) SUDO_APPEND_LIBPATH(LDFLAGS, [${with_ldap}/lib]) CPPFLAGS="${CPPFLAGS} -I${with_ldap}/include" with_ldap=yes fi - SUDO_OBJS="${SUDO_OBJS} ldap.o" + SUDOERS_OBJS="${SUDOERS_OBJS} ldap.lo" LDAP="" AC_MSG_CHECKING([for LDAP libraries]) @@ -2591,6 +3013,17 @@ if test ${with_ldap-'no'} != "no"; then #include #include ]], [[(void)ldap_init(0, 0)]])], [found=yes; break]) done + if test "$found" = "no"; then + LDAP_LIBS="" + LIBS="$_LIBS" + for l in -libmldap -lidsldif; do + LIBS="${LIBS} $l" + LDAP_LIBS="${LDAP_LIBS} $l" + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include + #include + #include ]], [[(void)ldap_init(0, 0)]])], [found=yes; break]) + done + fi dnl if nothing linked just try with -lldap if test "$found" = "no"; then LIBS="${_LIBS} -lldap" @@ -2614,7 +3047,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, @@ -2630,7 +3064,7 @@ if test ${with_ldap-'no'} != "no"; then O_CPPFLAGS="$CPPFLAGS" for dir in "" "kerberosV" "krb5" "kerberos5" "kerberosv5"; do test X"$dir" != X"" && CPPFLAGS="$O_CPPFLAGS -I/usr/include/${dir}" - AC_PREPROC_IFELSE([#include ], [found="gssapi/gssapi.h"; break], [AC_PREPROC_IFELSE([#include ], [found="gssapi.h"; break])]) + AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[#include ]])], [found="gssapi/gssapi.h"; break], [AC_PREPROC_IFELSE([AC_LANG_PROGRAM([[#include ]])], [found="gssapi.h"; break])]) done if test X"$found" != X"no"; then AC_CHECK_HEADERS([$found]) @@ -2643,88 +3077,87 @@ if test ${with_ldap-'no'} != "no"; then fi fi - SUDO_LIBS="${SUDO_LIBS} ${LDAP_LIBS}" + SUDOERS_LIBS="${SUDOERS_LIBS} ${LDAP_LIBS}" LIBS="$_LIBS" LDFLAGS="$_LDFLAGS" fi -dnl -dnl Add LIBVAS_RPATH to LDFLAGS -dnl GNU ld accepts -R/path/ as an alias for -rpath /path/ -dnl -if test X"$LIBVAS_RPATH" != X""; then - if test -n "$blibpath"; then - blibpath_add="${blibpath_add}:$LIBVAS_RPATH" - else - case "$host" in - *-*-hpux*) LDFLAGS="$LDFLAGS -Wl,+b,$LIBVAS_RPATH" - ;; - *) LDFLAGS="$LDFLAGS -Wl,-R$LIBVAS_RPATH" - ;; - esac - fi +# +# How to do dynamic object loading. +# We support dlopen() and sh_load(), else fall back to static loading. +# +case "$lt_cv_dlopen" in + dlopen) + AC_DEFINE(HAVE_DLOPEN) + SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo" + LT_STATIC="--tag=disable-static" + ;; + shl_load) + AC_DEFINE(HAVE_SHL_LOAD) + SUDOERS_OBJS="$SUDOERS_OBJS plugin_error.lo" + LT_STATIC="--tag=disable-static" + AC_LIBOBJ(dlopen) + ;; + *) + if test X"${ac_cv_func_dlopen}" = X"yes"; then + AC_MSG_ERROR(["dlopen present but libtool doesn't appear to support your platform."]) + fi + # Preload sudoers module symbols + SUDO_OBJS="${SUDO_OBJS} preload.o" + SUDO_LIBS="${SUDO_LIBS} \$(top_builddir)/plugins/sudoers/sudoers.la" + LT_STATIC="" + AC_LIBOBJ(dlopen) + ;; +esac + +# +# Add library needed for dynamic loading, if any. +# +LIBDL="$lt_cv_dlopen_libs" +if test X"$LIBDL" != X""; then + SUDO_LIBS="${SUDO_LIBS} $LIBDL" + SUDOERS_LIBS="${SUDOERS_LIBS} $LIBDL" fi +# On HP-UX, you cannot dlopen() a shared object that uses pthreads +# unless the main program is linked against -lpthread. Since we +# have no knowledge what libraries a plugin may depend on, we always +# link against -lpthread on HP-UX if it is available. +# This check should go after all other libraries tests. +case "$host" in + *-*-hpux*) + AC_CHECK_LIB(pthread, main, [SUDO_LIBS="${SUDO_LIBS} -lpthread"]) + ;; +esac + dnl -dnl Add $blibpath to SUDO_LDFLAGS if specified by the user or if we -dnl added -L dirpaths to SUDO_LDFLAGS. +dnl Add $blibpath to SUDOERS_LDFLAGS if specified by the user or if we +dnl added -L dirpaths to SUDOERS_LDFLAGS. dnl if test -n "$blibpath"; then if test -n "$blibpath_add"; then - SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}" + SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}${blibpath_add}" elif test -n "$with_blibpath" -a "$with_blibpath" != "yes"; then - SUDO_LDFLAGS="$SUDO_LDFLAGS -Wl,-blibpath:${blibpath}" + SUDOERS_LDFLAGS="$SUDOERS_LDFLAGS -Wl,-blibpath:${blibpath}" fi fi dnl dnl Check for log file, timestamp and iolog locations dnl +if test "$utmp_style" = "LEGACY"; then + SUDO_PATH_UTMP +fi SUDO_LOGFILE SUDO_TIMEDIR SUDO_IO_LOGDIR dnl -dnl If I/O logging is enabled, build sudoreplay and exec_pty get_pty.o iolog.o -dnl -if test "${with_iologdir-yes}" != "no"; then - # Require POSIX job control for I/O log support - AC_CHECK_FUNCS(tcsetpgrp, [ - SUDO_OBJS="${SUDO_OBJS} exec_pty.o get_pty.o iolog.o" - PROGS="$PROGS sudoreplay" - REPLAY="" - - AC_ARG_ENABLE(zlib, - [AS_HELP_STRING([--enable-zlib[[=PATH]]], [Whether to enable or disable zlib])], - [ case "$enable_zlib" 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"]) - ]) - fi - ], [ - AC_MSG_WARN([Disabling I/O log support due to lack of tcsetpgrp function]) - with_iologdir=no - ]) -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.lo passwd.lo" ;; *) AC_DEFINE(WITHOUT_PASSWD) @@ -2734,24 +3167,36 @@ yes|maybe) ;; esac AUTH_OBJS=${AUTH_OBJS# } -_AUTH=`echo "$AUTH_OBJS" | sed 's/\.o//g'` +_AUTH=`echo "$AUTH_OBJS" | sed -e 's/\.lo//g' -e 's/getspwuid *//'` AC_MSG_NOTICE([using the following authentication methods: $_AUTH]) dnl -dnl LIBS may contain duplicates from SUDO_LIBS or NET_LIBS so prune it. +dnl LIBS may contain duplicates from SUDO_LIBS, SUDOERS_LIBS, or NET_LIBS dnl if test -n "$LIBS"; then L="$LIBS" LIBS= for l in ${L}; do dupe=0 - for sl in ${SUDO_LIBS} ${NET_LIBS}; do + for sl in ${SUDO_LIBS} ${SUDOERS_LIBS} ${NET_LIBS}; do test $l = $sl && dupe=1 done test $dupe = 0 && LIBS="${LIBS} $l" done fi +dnl +dnl We add -Wall and -Werror after all tests so they don't cause failures +dnl +if test -n "$GCC"; then + if test X"$enable_warnings" = X"yes" -o X"$with_devel" = X"yes"; then + CFLAGS="${CFLAGS} -Wall" + fi + if test X"$enable_werror" = X"yes"; then + CFLAGS="${CFLAGS} -Werror" + fi +fi + dnl dnl Set exec_prefix dnl @@ -2774,13 +3219,31 @@ if test X"$with_noexec" != X"no" -o X"$with_selinux" != X"no"; then PROGS="${PROGS} libsudo_noexec.la" INSTALL_NOEXEC="install-noexec" - eval noexec_file="$with_noexec" + noexec_file="$with_noexec" + _noexec_file= + while test X"$noexec_file" != X"$_noexec_file"; do + _noexec_file="$noexec_file" + eval noexec_file="$_noexec_file" + done SUDO_DEFINE_UNQUOTED(_PATH_SUDO_NOEXEC, "$noexec_file", [The fully qualified pathname of sudo_noexec.so]) fi if test X"$with_selinux" != X"no"; then - eval sesh_file="$libexecdir/sesh" + sesh_file="$libexecdir/sesh" + _sesh_file= + while test X"$sesh_file" != X"$_sesh_file"; do + _sesh_file="$sesh_file" + eval sesh_file="$_sesh_file" + done SUDO_DEFINE_UNQUOTED(_PATH_SUDO_SESH, "$sesh_file", [The fully qualified pathname of sesh]) fi + PLUGINDIR="$with_plugindir" + _PLUGINDIR= + while test X"$PLUGINDIR" != X"$_PLUGINDIR"; do + _PLUGINDIR="$PLUGINDIR" + eval PLUGINDIR="$_PLUGINDIR" + done + SUDO_DEFINE_UNQUOTED(_PATH_SUDO_PLUGIN_DIR, "$PLUGINDIR/") + SUDO_DEFINE_UNQUOTED(SUDOERS_PLUGIN, "sudoers${SOEXT}") exec_prefix="$oexec_prefix" fi @@ -2803,7 +3266,8 @@ test "$sysconfdir" = '${prefix}/etc' -a X"$with_stow" != X"yes" && sysconfdir='/ dnl dnl Substitute into the Makefile and man pages dnl -AC_CONFIG_FILES([Makefile sudo.man visudo.man sudoers.man sudoers.ldap.man sudoreplay.man sudo_usage.h sudoers]) +dnl AC_CONFIG_FILES([doc/sudo.man doc/visudo.man doc/sudoers.man doc/sudoers.ldap.man doc/sudoreplay.man src/Makefile src/sudo_usage.h]) +AC_CONFIG_FILES([Makefile common/Makefile compat/Makefile doc/Makefile include/Makefile src/sudo_usage.h src/Makefile plugins/sample/Makefile plugins/sample_group/Makefile plugins/system_group/Makefile plugins/sudoers/Makefile plugins/sudoers/sudoers]) AC_OUTPUT dnl @@ -2811,6 +3275,12 @@ dnl Spew any text the user needs to know about dnl if test "$with_pam" = "yes"; then case $host in + *-*-hpux*) + if test -f /usr/lib/security/libpam_hpsec.so.1; then + AC_MSG_NOTICE([You may wish to add the following line to /etc/pam.conf]) + AC_MSG_NOTICE([sudo session required libpam_hpsec.so.1 bypass_umask bypass_last_login]) + fi + ;; *-*-linux*) AC_MSG_NOTICE([You will need to customize sample.pam and install it as /etc/pam.d/sudo]) ;; @@ -2823,10 +3293,12 @@ dnl AH_TEMPLATE(BROKEN_SYSLOG, [Define to 1 if the `syslog' function returns a non-zero int to denote failure.]) AH_TEMPLATE(CLASSIC_INSULTS, [Define to 1 if you want the insults from the "classic" version sudo.]) AH_TEMPLATE(CSOPS_INSULTS, [Define to 1 if you want insults culled from the twisted minds of CSOps.]) +AH_TEMPLATE(SUDOERS_PLUGIN, [The name of the sudoers plugin, including extension.]) AH_TEMPLATE(DONT_LEAK_PATH_INFO, [Define to 1 if you want sudo to display "command not allowed" instead of "command not found" when a command cannot be found.]) -AH_TEMPLATE(ENV_EDITOR, [Define to 1 if you want visudo to honor the EDITOR and VISUAL env variables.]) AH_TEMPLATE(ENV_DEBUG, [Define to 1 to enable environment function debugging.]) +AH_TEMPLATE(ENV_EDITOR, [Define to 1 if you want visudo to honor the EDITOR and VISUAL env variables.]) AH_TEMPLATE(FQDN, [Define to 1 if you want to require fully qualified hosts in sudoers.]) +AH_TEMPLATE(ENV_RESET, [Define to 1 to enable environment resetting by default.]) AH_TEMPLATE(GOONS_INSULTS, [Define to 1 if you want insults from the "Goon Show".]) AH_TEMPLATE(HAL_INSULTS, [Define to 1 if you want 2001-like insults.]) AH_TEMPLATE(HAVE_AFS, [Define to 1 if you use AFS.]) @@ -2836,9 +3308,8 @@ AH_TEMPLATE(HAVE_BSM_AUDIT, [Define to 1 to enable BSM audit support.]) AH_TEMPLATE(HAVE_DCE, [Define to 1 if you use OSF DCE.]) AH_TEMPLATE(HAVE_DD_FD, [Define to 1 if your `DIR' contains dd_fd.]) AH_TEMPLATE(HAVE_DIRFD, [Define to 1 if you have the `dirfd' function or macro.]) -AH_TEMPLATE(HAVE_DGETTEXT, [Define to 1 if you have the `dgettext' function.]) AH_TEMPLATE(HAVE_DISPCRYPT, [Define to 1 if you have the `dispcrypt' function.]) -AH_TEMPLATE(HAVE_EXTENDED_GLOB, [Define to 1 if your glob.h defines the GLOB_BRACE and GLOB_TILDE flags.]) +AH_TEMPLATE(HAVE_DLOPEN, [Define to 1 if you have the `dlopen' function.]) AH_TEMPLATE(HAVE_FCNTL_CLOSEM, [Define to 1 if your system has the F_CLOSEM fcntl.]) AH_TEMPLATE(HAVE_FNMATCH, [Define to 1 if you have the `fnmatch' function.]) AH_TEMPLATE(HAVE_FWTK, [Define to 1 if you use the FWTK authsrv daemon.]) @@ -2849,10 +3320,8 @@ AH_TEMPLATE(HAVE_GETSPNAM, [Define to 1 if you have the `getspnam' function (SVR AH_TEMPLATE(HAVE_GETSPWUID, [Define to 1 if you have the `getspwuid' function. (HP-UX <= 9.X shadow passwords)]) AH_TEMPLATE(HAVE_GSS_KRB5_CCACHE_NAME, [Define to 1 if you have the `gss_krb5_ccache_name' function.]) AH_TEMPLATE(HAVE_HEIMDAL, [Define to 1 if your Kerberos is Heimdal.]) -AH_TEMPLATE(HAVE_IN6_ADDR, [Define to 1 if contains struct in6_addr.]) AH_TEMPLATE(HAVE_ISCOMSEC, [Define to 1 if you have the `iscomsec' function. (HP-UX >= 10.x check for shadow enabled)]) AH_TEMPLATE(HAVE_ISSECURE, [Define to 1 if you have the `issecure' function. (SunOS 4.x check for shadow enabled)]) -AH_TEMPLATE(HAVE_KERB4, [Define to 1 if you use Kerberos IV.]) AH_TEMPLATE(HAVE_KERB5, [Define to 1 if you use Kerberos V.]) AH_TEMPLATE(HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC, [Define to 1 if you have the `krb5_get_init_creds_opt_alloc' function.]) AH_TEMPLATE(HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS, [Define to 1 if your `krb5_get_init_creds_opt_free' function takes two arguments.]) @@ -2860,6 +3329,7 @@ AH_TEMPLATE(HAVE_KRB5_INIT_SECURE_CONTEXT, [Define to 1 if you have the `krb5_in AH_TEMPLATE(HAVE_KRB5_VERIFY_USER, [Define to 1 if you have the `krb5_verify_user' function.]) AH_TEMPLATE(HAVE_LBER_H, [Define to 1 if your LDAP needs . (OpenLDAP does not)]) AH_TEMPLATE(HAVE_LDAP, [Define to 1 if you use LDAP for sudoers.]) +AH_TEMPLATE(HAVE_LIBINTL_H, [Define to 1 if you have the header file.]) AH_TEMPLATE(HAVE_LINUX_AUDIT, [Define to 1 to enable Linux audit support.]) AH_TEMPLATE(HAVE_OPIE, [Define to 1 if you use NRL OPIE.]) AH_TEMPLATE(HAVE_PAM, [Define to 1 if you use PAM authentication.]) @@ -2868,14 +3338,13 @@ AH_TEMPLATE(HAVE_PROJECT_H, [Define to 1 if you have the header file AH_TEMPLATE(HAVE_SECURID, [Define to 1 if you use SecurID for authentication.]) AH_TEMPLATE(HAVE_SELINUX, [Define to 1 to enable SELinux RBAC support.]) AH_TEMPLATE(HAVE_SETKEYCREATECON, [Define to 1 if you have the `setkeycreatecon' function.]) -AH_TEMPLATE(HAVE_SIGACTION_T, [Define to 1 if has the sigaction_t typedef.]) +AH_TEMPLATE(HAVE_SHL_LOAD, [Define to 1 if you have the `shl_load' function.]) AH_TEMPLATE(HAVE_SKEY, [Define to 1 if you use S/Key.]) AH_TEMPLATE(HAVE_SKEYACCESS, [Define to 1 if your S/Key library has skeyaccess().]) +AH_TEMPLATE(HAVE_RFC1938_SKEYCHALLENGE, [Define to 1 if the skeychallenge() function is RFC1938-compliant and takes 4 arguments]) AH_TEMPLATE(HAVE_ST__TIM, [Define to 1 if your struct stat uses an st__tim union]) AH_TEMPLATE(HAVE_ST_MTIM, [Define to 1 if your struct stat has an st_mtim member]) AH_TEMPLATE(HAVE_ST_MTIMESPEC, [Define to 1 if your struct stat has an st_mtimespec member]) -AH_TEMPLATE(HAVE_TERMIOS_H, [Define to 1 if you have the header file and the `tcgetattr' function.]) -AH_TEMPLATE(HAVE_TIMESPEC, [Define to 1 if you have struct timespec in sys/time.h]) AH_TEMPLATE(HAVE___PROGNAME, [Define to 1 if your crt0.o defines the __progname symbol for you.]) AH_TEMPLATE(HOST_IN_LOG, [Define to 1 if you want the hostname to be entered into the log file.]) AH_TEMPLATE(IGNORE_DOT_PATH, [Define to 1 if you want to ignore '.' and empty PATH elements]) @@ -2895,13 +3364,22 @@ 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.]) AH_TEMPLATE(WITHOUT_PASSWD, [Define to avoid using the passwd/shadow file for authentication.]) AH_TEMPLATE(sig_atomic_t, [Define to `int' if does not define.]) AH_TEMPLATE(__signed, [Define to `signed' or nothing if compiler does not support a signed type qualifier.]) -AH_TEMPLATE(USING_NONUNIX_GROUPS, [Define to 1 if using a non-Unix group lookup implementation.]) +AH_TEMPLATE(socklen_t, [Define to `unsigned int' if doesn't define.]) +AH_TEMPLATE(HAVE_STRUCT_UTMP_UT_EXIT, [Define to 1 if `ut_exit' is a member of `struct utmp'.]) +AH_TEMPLATE(HAVE_STRUCT_UTMPX_UT_EXIT, [Define to 1 if `ut_exit' is a member of `struct utmpx'.]) +AH_TEMPLATE(HAVE___FUNC__, [Define to 1 if the compiler supports the C99 __func__ variable.]) +AH_TEMPLATE(SUDO_KRB5_INSTANCE, [An instance string to append to the username (separated by a slash) for Kerberos V authentication]) +AH_TEMPLATE(RTLD_PRELOAD_VAR, [The environment variable that controls preloading of dynamic objects.]) +AH_TEMPLATE(RTLD_PRELOAD_ENABLE_VAR, [An extra environment variable that is required to enable preloading (if any).]) +AH_TEMPLATE(RTLD_PRELOAD_DELIM, [The delimiter to use when defining multiple preloaded objects.]) +AH_TEMPLATE(RTLD_PRELOAD_DEFAULT, [The default value of preloaded objects (if any).]) dnl dnl Bits to copy verbatim into config.h.in @@ -2935,15 +3413,13 @@ AH_BOTTOM([/* # endif /* HAVE_ST_MTIMESPEC */ #endif /* HAVE_ST_MTIM */ -/* - * Emulate a subset of waitpid() if we don't have it. - */ -#ifdef HAVE_WAITPID -# define sudo_waitpid(p, s, o) waitpid(p, s, o) +#ifdef __GNUC__ +# define ignore_result(x) do { \ + __typeof__(x) y = (x); \ + (void)y; \ +} while(0) #else -# ifdef HAVE_WAIT3 -# define sudo_waitpid(p, s, o) wait3(s, o, NULL) -# endif +# define ignore_result(x) (void)(x) #endif /* GNU stow needs /etc/sudoers to be a symlink. */ @@ -2961,7 +3437,7 @@ AH_BOTTOM([/* #undef ISSET #define ISSET(t, f) ((t) & (f)) -/* New ANSI-style OS defs for HP-UX and ConvexOS. */ +/* ANSI-style OS defs for HP-UX and ConvexOS. */ #if defined(hpux) && !defined(__hpux) # define __hpux 1 #endif /* hpux */ diff --git a/debian/NEWS b/debian/NEWS index d59d56f..3c0b573 100644 --- a/debian/NEWS +++ b/debian/NEWS @@ -1,3 +1,19 @@ +sudo (1.8.2-1) unstable; urgency=low + + The sudo package is no longer configured using --with-secure-path. + Instead, the provided sudoers file now contains a line declaring + 'Defaults secure_path=' with the same path content that was previously + hard-coded in the binary. A consequence of this change is that if you + do not have such a definition in sudoers, the PATH searched for commands + by sudo may be empty. + + Using explicit paths for each command you want to run with sudo will work + well enough to allow the sudoers file to be updated with a suitable entry + if one is not already present and you choose to not accept the updated + version provided by the package. + + -- Bdale Garbee Wed, 24 Aug 2011 13:33:11 -0600 + sudo (1.7.4p4-2) unstable; urgency=low The HOME and MAIL environment variables are now reset based on the diff --git a/debian/OPTIONS b/debian/OPTIONS index 35710ba..49938d7 100644 --- a/debian/OPTIONS +++ b/debian/OPTIONS @@ -1,5 +1,10 @@ The following options were used to configure sudo for Debian GNU/Linux. + --with-all-insults + + Include all the insults in the binary, won't be enabled unless turned + on in the sudoers file. + --with-devel Force flex and bison runs on each build. @@ -8,18 +13,10 @@ The following options were used to configure sudo for Debian GNU/Linux. Support for pluggable authentication modules. - --with-ldap - - Support for LDAP authentication, in the sudo-ldap package version only. - --with-fqdn Allow use of fully qualified domain names in the sudoers file. - --disable-root-mailer - - Send mail as the invoking user, not as root. - --with-logging=syslog --with-logfac=authpriv @@ -33,27 +30,30 @@ The following options were used to configure sudo for Debian GNU/Linux. --with-timeout=15 --with-password-timeout=0 + --with-passprompt="[sudo] password for %p: " Allow 15 minutes before a user has to re-type their passord, versus the sudo usual default of 5. Never time out while waiting for a - password to be typed, this is a seriously big deal for Debian package - developers using 'dpkg-buildpackage -rsudo'. + password to be typed, this is important to Debian package developers + using 'dpkg-buildpackage -rsudo'. Make it clear which password is + requested. - --with-secure-path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:\ - /sbin:/bin:/usr/X11R6/bin" - - Give a reasonable default path for commands run as root via sudo. - - --with-all-insults + --disable-root-mailer - Include all the insults in the binary, won't be enabled unless turned - on in the sudoers file. + Send mail as the invoking user, not as root. --with-sendmail=/usr/sbin/sendmail Use Debian policy to know the location of sendmail instead of trying to detect it at build time. - --disable-setresuid + --with-timedir=/var/lib/sudo + --mandir=/usr/share/man + --libexecdir=/usr/lib/sudo + + Comply with Debian policy on suitable paths. + + --with-ldap + + Support for LDAP authentication, in the sudo-ldap package version only. - Linux 2.2 kernels don't support setresgid. diff --git a/debian/README b/debian/README index 2429cc7..b5ed892 100644 --- a/debian/README +++ b/debian/README @@ -10,9 +10,12 @@ # Note that there must be at least one file in the sudoers.d directory (this # one will do), and all files in this directory should be mode 0440. # -# Note also, that because the sudoers file is not a 'conffile' in the Debian -# sense, and sudoers contents can vary widely, no attempt is made to add this -# directive to existing sudoers files on upgrade. Feel free to add the above -# directive to the end of your /etc/sudoers file to enable this functionality -# for existing installations if you wish! +# Note also, that because sudoers contents can vary widely, no attempt is +# made to add this directive to existing sudoers files on upgrade. Feel free +# to add the above directive to the end of your /etc/sudoers file to enable +# this functionality for existing installations if you wish! +# +# Finally, please note that using the visudo command is the recommended way +# to update sudoers content, since it protects against many failure modes. +# See the man page for visudo for more information. # diff --git a/debian/README.Debian b/debian/README.Debian index a81d9e3..e1ecb3e 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -2,9 +2,8 @@ The version of sudo that ships with Debian by default resets the environment, as described by the "env_reset" flag in the sudoers file. This implies that all environment variables are removed, except for -HOME, LOGNAME, PATH, SHELL, TERM, DISPLAY, XAUTHORITY, XAUTHORIZATION, -XAPPLRESDIR, XFILESEARCHPATH, XUSERFILESEARCHPATH, LANG, LANGUAGE, LC_*, -and USER. +LOGNAME, PATH, SHELL, TERM, DISPLAY, XAUTHORITY, XAUTHORIZATION, XAPPLRESDIR, +XFILESEARCHPATH, XUSERFILESEARCHPATH, LANG, LANGUAGE, LC_*, and USER. In case you want sudo to preserve more environment variables, you must specify the env_keep variable in the sudoers file. You should edit the diff --git a/debian/changelog b/debian/changelog index 4772750..84dbd04 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,141 @@ +sudo (1.8.5p2-1~bpo60+1) squeeze-backports; urgency=low + + * backport of version targeted for wheezy release by user request + + -- Bdale Garbee Tue, 25 Sep 2012 10:20:29 -0600 + +sudo (1.8.5p2-1) unstable; urgency=low + + * new upstream version + * patch to use flock on hurd, run autoconf in rules, closes: #655883 + * patch to avoid calling unlink with null pointer on hurd, closes: #655948 + * patch to actually use hardening build flags, closes: #655417 + * fix sudo-ldap.postinst syntax issue, closes: #669576 + + -- Bdale Garbee Thu, 28 Jun 2012 12:01:37 -0600 + +sudo (1.8.3p2-1) unstable; urgency=high + + * new upstream version, closes: #657985 (CVE-2012-0809) + * patch from Pino Toscano to only use selinux on Linux, closes: #655894 + + -- Bdale Garbee Mon, 30 Jan 2012 16:11:54 -0700 + +sudo (1.8.3p1-3) unstable; urgency=low + + * patch from Moritz Muehlenhoff enables hardened build flags, closes: #655417 + * replacement postinst script from Mike Beattie using shell instead of Perl + * include systemd service file from Michael Stapelberg, closes: #639633 + * add init.d status support, closes: #641782 + * make sudo-ldap package manage a sudoers entry in nsswitch.conf, + closes: #610600, #639530 + * enable mail_badpass in the default sudoers file, closes: #641218 + * enable selinux support, closes: #655510 + + -- Bdale Garbee Wed, 11 Jan 2012 16:18:13 -0700 + +sudo (1.8.3p1-2) unstable; urgency=low + + * if upgrading from squeeze, and the sudoers file is unmodified, avoid + the packaging system prompting the user about a change they didn't make + now that sudoers is a conffile, closes: #612532, #636049 + * add a recommendation for the use of visudo to the sudoers.d/README file, + closes: #648104 + + -- Bdale Garbee Sat, 12 Nov 2011 16:27:13 -0700 + +sudo (1.8.3p1-1) unstable; urgency=low + + * new upstream version, closes: #646478 + + -- Bdale Garbee Thu, 27 Oct 2011 01:03:44 +0200 + +sudo (1.8.3-1) unstable; urgency=low + + * new upstream version, closes: #639391, #639568 + + -- Bdale Garbee Sat, 22 Oct 2011 23:49:16 -0600 + +sudo (1.8.2-2) unstable; urgency=low + + [ Luca Capello ] + * debian/rules improvements, closes: #642535 + + mv upstream sample.* files to the examples folder. + - do not call dh_installexamples. + + [ Bdale Garbee ] + * patch from upstream for SIGBUS on sparc64, closes: #640304 + * use common-session-noninteractive in the pam config to reduce log noise + when sudo is used in cron, etc, closes: #519700 + * patch from Steven McDonald to fix segfault on startup under certain + conditions, closes: #639568 + * add a NEWS entry regarding the secure_path change made in 1.8.2-1, + closes: #639336 + + -- Bdale Garbee Mon, 26 Sep 2011 21:55:56 -0600 + +sudo (1.8.2-1) unstable; urgency=low + + * new upstream version, closes: #637449, #621830 + * include common-session in pam config, closes: #519700, #607199 + * move secure_path from configure to default sudoers, closes: #85123, 85917 + * improve sudoers self-documentation, closes: #613639 + * drop --disable-setresuid since modern systems should not run 2.2 kernels + * lose the --with-devel configure option since it's breaking builds in + subdirectories for some reason + + -- Bdale Garbee Wed, 24 Aug 2011 13:33:11 -0600 + +sudo (1.7.4p6-1) unstable; urgency=low + + * new upstream version + * touch the right stamp name after configuring, closes: #611287 + * patch from Svante Signell to fix build problem on Hurd, closes: #611290 + + -- Bdale Garbee Wed, 09 Feb 2011 11:32:58 -0700 + +sudo (1.7.4p4-6) unstable; urgency=low + + * update /etc/sudoers.d/README now that sudoers is a conffile + * patch from upstream to fix special case in password checking code + when only the gid is changing, closes: #609641 + + -- Bdale Garbee Tue, 11 Jan 2011 10:22:39 -0700 + +sudo (1.7.4p4-5) unstable; urgency=low + + * patch from Jakub Wilk to add noopt and nostrip build option support, + closes: #605580 + * make sudoers a conffile, closes: #605130 + * add descriptions to LSB init headers, closes: #604619 + * change default sudoers %sudo entry to allow gid changes, closes: #602699 + * add Vcs entries to the control file + * use debhelper install files instead of explicit installs in rules + + -- Bdale Garbee Wed, 01 Dec 2010 20:32:31 -0700 + +sudo (1.7.4p4-4) unstable; urgency=low + + * patch from upstream to resolve problem always prompting for a password + when run without a tty, closes: #599376 + * patch from upstream to resolve interoperability problem between HOME in + env_keep and the -H flag, closes: #596493 + * change path syntax to avoid tar error when /var/run/sudo exists but is + empty, closes: #598877 + + -- Bdale Garbee Thu, 07 Oct 2010 15:59:06 -0600 + +sudo (1.7.4p4-3) unstable; urgency=low + + * make postinst clause for handling /var/run -> /var/lib transition less + fragile, closes: #585514 + * cope with upstream's Makefile trying to install ChangeLog in our doc + directory, closes: #597389 + * fix README.Debian to reflect that HOME is no longer preserved by default, + closes: #596847 + + -- Bdale Garbee Tue, 21 Sep 2010 23:53:08 -0600 + sudo (1.7.4p4-2.squeeze.2) stable; urgency=low * patch from upstream to resolve interoperability problem between HOME in diff --git a/debian/control b/debian/control index 690ac3d..1e5e488 100644 --- a/debian/control +++ b/debian/control @@ -2,8 +2,10 @@ Source: sudo Section: admin Priority: optional Maintainer: Bdale Garbee -Build-Depends: debhelper (>= 7), libpam0g-dev, libldap2-dev, libsasl2-dev, autotools-dev, bison, flex -Standards-Version: 3.9.1 +Build-Depends: debhelper (>= 7), libpam0g-dev, libldap2-dev, libsasl2-dev, libselinux1-dev [linux-any], autoconf, autotools-dev, bison, flex +Standards-Version: 3.9.3 +Vcs-Git: git://git.gag.com/debian/sudo +Vcs-Browser: http://git.gag.com/?p=debian/sudo Package: sudo Architecture: any diff --git a/debian/patches/actually-use-buildflags.diff b/debian/patches/actually-use-buildflags.diff new file mode 100644 index 0000000..84de973 --- /dev/null +++ b/debian/patches/actually-use-buildflags.diff @@ -0,0 +1,84 @@ +diff --git a/common/Makefile.in b/common/Makefile.in +index aff4c54..7f05e4b 100644 +--- a/common/Makefile.in ++++ b/common/Makefile.in +@@ -45,6 +45,9 @@ CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + # Usually -O and/or -g + CFLAGS = @CFLAGS@ + ++# Linker flags ++LDFLAGS = @LDFLAGS@ ++ + # OS dependent defines + DEFS = @OSDEFS@ -D_PATH_SUDO_CONF=\"$(sysconfdir)/sudo.conf\" + +@@ -67,7 +70,7 @@ Makefile: $(srcdir)/Makefile.in + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + + libcommon.la: $(LTOBJS) +- $(LIBTOOL) --mode=link $(CC) -o $@ $(LTOBJS) -no-install ++ $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(LTOBJS) -no-install + + pre-install: + +diff --git a/compat/Makefile.in b/compat/Makefile.in +index d0361ce..93672ac 100644 +--- a/compat/Makefile.in ++++ b/compat/Makefile.in +@@ -45,6 +45,9 @@ CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + # Usually -O and/or -g + CFLAGS = @CFLAGS@ + ++# Linker flags ++LDFLAGS = @LDFLAGS@ ++ + # OS dependent defines + DEFS = @OSDEFS@ + +@@ -75,19 +78,19 @@ Makefile: $(srcdir)/Makefile.in + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + + libreplace.la: $(LTLIBOBJS) +- $(LIBTOOL) --mode=link $(CC) -o $@ $(LTLIBOBJS) -no-install ++ $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(LTLIBOBJS) -no-install + + siglist.c: mksiglist + ./mksiglist > $@ + + mksiglist: $(srcdir)/mksiglist.c $(srcdir)/mksiglist.h $(incdir)/missing.h $(top_builddir)/config.h +- $(CC) $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/mksiglist.c -o $@ ++ $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(DEFS) $(srcdir)/mksiglist.c -o $@ + + fnm_test: fnm_test.o libreplace.la +- $(LIBTOOL) --mode=link $(CC) -o $@ fnm_test.o libreplace.la ++ $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ fnm_test.o libreplace.la + + globtest: globtest.o libreplace.la +- $(LIBTOOL) --mode=link $(CC) -o $@ globtest.o libreplace.la ++ $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ globtest.o libreplace.la + + $(srcdir)/mksiglist.h: $(srcdir)/siglist.in + if [ -n "$(DEVEL)" ]; then \ +diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in +index 8769d38..0eb71e9 100644 +--- a/plugins/sudoers/Makefile.in ++++ b/plugins/sudoers/Makefile.in +@@ -56,6 +56,9 @@ CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(devdir) -I$(srcdir) -I$(top_srcdir) + # Usually -O and/or -g + CFLAGS = @CFLAGS@ + ++# Linker flags ++LDFLAGS = @LDFLAGS@ ++ + # Flags to pass to the link stage + LDFLAGS = @LDFLAGS@ + SUDOERS_LDFLAGS = $(LDFLAGS) @SUDOERS_LDFLAGS@ +@@ -163,7 +166,7 @@ Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file plugins/sudoers/Makefile) + + libparsesudoers.la: $(LIBPARSESUDOERS_OBJS) +- $(LIBTOOL) --mode=link $(CC) -o $@ $(LIBPARSESUDOERS_OBJS) -no-install ++ $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) -o $@ $(LIBPARSESUDOERS_OBJS) -no-install + + sudoers.la: $(SUDOERS_OBJS) $(LT_LIBS) libparsesudoers.la + $(LIBTOOL) @LT_STATIC@ --mode=link $(CC) $(SUDOERS_LDFLAGS) $(LTLDFLAGS) -o $@ $(SUDOERS_OBJS) libparsesudoers.la $(SUDOERS_LIBS) -module -export-symbols $(srcdir)/sudoers.sym -avoid-version -rpath $(plugindir) diff --git a/debian/patches/env.c-safety.diff b/debian/patches/env.c-safety.diff deleted file mode 100644 index 034dfdb..0000000 --- a/debian/patches/env.c-safety.diff +++ /dev/null @@ -1,65 +0,0 @@ ---- /home/bdale/Desktop/sudo-1.7.2p1/env.c 2009-06-23 12:24:42.000000000 -0600 -+++ sudo/env.c 2009-11-20 07:31:58.000000000 -0700 -@@ -120,6 +120,8 @@ - static const char *initial_badenv_table[] = { - "IFS", - "CDPATH", -+ "SHELLOPTS", -+ "PS4", - "LOCALDOMAIN", - "RES_OPTIONS", - "HOSTALIASES", -@@ -602,6 +604,17 @@ - if (keepit == -1) - keepit = matches_env_keep(*ep); - -+ if (!strncmp (*ep, "DISPLAY=",8) -+ || !strncmp (*ep, "XAUTHORITY=", 11) -+ || !strncmp (*ep, "XAUTHORIZATION=", 15) -+ || !strncmp (*ep, "XAPPLRESDIR=", 12) -+ || !strncmp (*ep, "XFILESEARCHPATH=", 16) -+ || !strncmp (*ep, "XUSERFILESEARCHPATH=", 20) -+ || !strncmp (*ep, "LANG=", 5) -+ || !strncmp (*ep, "LANGUAGE=", 9) -+ || !strncmp (*ep, "LC_", 3)) -+ keepit = 1; -+ - /* For SUDO_PS1 -> PS1 conversion. */ - if (strncmp(*ep, "SUDO_PS1=", 8) == 0) - ps1 = *ep + 5; ---- tmp/sudoers.pod 2010-03-11 12:28:58.000000000 -0700 -+++ sudo/sudoers.pod 2010-03-11 12:29:58.000000000 -0700 -@@ -1227,6 +1227,9 @@ - - =item env_delete - -+Not effective due to security issues: only variables listed in -+I or I can be passed through B! -+ - Environment variables to be removed from the user's environment - when the I option is not in effect. The argument may - be a double-quoted, space-separated list or a single value without -@@ -1240,8 +1243,8 @@ - - =item env_keep - --Environment variables to be preserved in the user's environment --when the I option is in effect. This allows fine-grained -+Environment variables to be preserved in the user's environment. -+This allows fine-grained - control over the environment B-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 ---- a/sudo.pod -+++ b/sudo.pod -@@ -456,8 +456,8 @@ and, as such, it is not possible for B to preserve them. - To prevent command spoofing, B checks "." and "" (both denoting - current directory) last when searching for a command in the user's - PATH (if one or both are in the PATH). Note, however, that the --actual C environment variable is I modified and is passed --unchanged to the program that B executes. -+C environment variable is further modified in Debian because of -+the use of the I build option. - - B will check the ownership of its time stamp directory - (F<@timedir@> by default) and ignore the directory's contents if diff --git a/debian/patches/paths-in-samples.diff b/debian/patches/paths-in-samples.diff index 89d4d62..5b95402 100644 --- a/debian/patches/paths-in-samples.diff +++ b/debian/patches/paths-in-samples.diff @@ -1,5 +1,5 @@ ---- /home/bdale/Desktop/sudo-1.7.2p1/sample.sudoers 2008-10-03 13:55:57.000000000 -0600 -+++ sudo/sample.sudoers 2009-11-20 07:31:58.000000000 -0700 +--- /home/bdale/Desktop/sudo-1.7.2p1/doc/sample.sudoers 2008-10-03 13:55:57.000000000 -0600 ++++ sudo/doc/sample.sudoers 2009-11-20 07:31:58.000000000 -0700 @@ -46,8 +46,8 @@ # Cmnd alias specification ## diff --git a/debian/patches/series b/debian/patches/series index 178a4c4..dafb562 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,3 @@ typo-in-classic-insults.diff -env.c-safety.diff paths-in-samples.diff +actually-use-buildflags.diff diff --git a/debian/patches/skip-noedit.diff b/debian/patches/skip-noedit.diff new file mode 100644 index 0000000..569bc13 --- /dev/null +++ b/debian/patches/skip-noedit.diff @@ -0,0 +1,12 @@ +Skip installing/unlinking files without doedit set +--- a/plugins/sudoers/visudo.c ++++ b/plugins/sudoers/visudo.c +@@ -247,6 +247,8 @@ + + /* Install the sudoers temp files. */ + tq_foreach_fwd(&sudoerslist, sp) { ++ if (!sp->doedit) ++ continue; + if (!sp->modified) + (void) unlink(sp->tpath); + else diff --git a/debian/patches/typo-in-classic-insults.diff b/debian/patches/typo-in-classic-insults.diff index 7a7f219..1c321a9 100644 --- a/debian/patches/typo-in-classic-insults.diff +++ b/debian/patches/typo-in-classic-insults.diff @@ -1,5 +1,5 @@ ---- /home/bdale/Desktop/sudo-1.7.2p1/ins_classic.h 2004-02-13 14:36:43.000000000 -0700 -+++ sudo/ins_classic.h 2009-11-20 07:31:58.000000000 -0700 +--- /home/bdale/Desktop/sudo-1.7.2p1/plugins/sudoers/ins_classic.h 2004-02-13 14:36:43.000000000 -0700 ++++ sudo/plugins/sudoers/ins_classic.h 2009-11-20 07:31:58.000000000 -0700 @@ -32,7 +32,7 @@ "Where did you learn to type?", "Are you on drugs?", diff --git a/debian/patches/use-flock-on-hurd.diff b/debian/patches/use-flock-on-hurd.diff new file mode 100644 index 0000000..fb0b81c --- /dev/null +++ b/debian/patches/use-flock-on-hurd.diff @@ -0,0 +1,15 @@ +Use flock instead of lockf for visudo on hurd +Index: sudo-1.8.3p1/configure.in +=================================================================== +--- sudo-1.8.3p1.orig/configure.in 2011-10-25 14:11:40.000000000 +0000 ++++ sudo-1.8.3p1/configure.in 2012-01-08 04:05:23.000000000 +0000 +@@ -1864,6 +1864,9 @@ + ;; + *-gnu*) + OSDEFS="${OSDEFS} -D_GNU_SOURCE" ++ # lockf() isn't implemented on the Hurd -- use flock instead ++ ac_cv_func_lockf=no ++ ac_cv_func_flock=yes + ;; + esac + diff --git a/debian/rules b/debian/rules index 2cfefa9..c27b25f 100755 --- a/debian/rules +++ b/debian/rules @@ -2,24 +2,34 @@ export DH_VERBOSE=1 -CFLAGS = -O2 -Wall -Wno-comment -ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) -CFLAGS += -g +CFLAGS = `dpkg-buildflags --get CFLAGS` +CFLAGS += -Wall -Wno-comment +LDFLAGS = `dpkg-buildflags --get LDFLAGS` +CPPFLAGS = `dpkg-buildflags --get CPPFLAGS` + +DEB_HOST_ARCH_OS ?= $(shell dpkg-architecture -qDEB_HOST_ARCH_OS) +ifeq ($(DEB_HOST_ARCH_OS),linux) + configure_args += --with-selinux endif -export CFLAGS + +reconf-stamp: + cp -f /usr/share/misc/config.sub config.sub + cp -f /usr/share/misc/config.guess config.guess + autoconf -I m4 + touch $@ configure: configure-stamp -configure-stamp: +configure-stamp: reconf-stamp dh_testdir cp -f /usr/share/misc/config.sub config.sub cp -f /usr/share/misc/config.guess config.guess # simple version mkdir -p build-simple - cd build-simple && NROFFPROG=/usr/bin/nroff $(CURDIR)/configure \ + cd build-simple && NROFFPROG=/usr/bin/nroff CFLAGS="$(CFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" $(CURDIR)/configure \ --prefix=/usr -v \ --with-all-insults \ - --with-devel \ --with-pam \ --with-fqdn \ --with-logging=syslog \ @@ -29,20 +39,19 @@ configure-stamp: --with-timeout=15 \ --with-password-timeout=0 \ --with-passprompt="[sudo] password for %p: " \ - --with-timedir=/var/lib/sudo \ --disable-root-mailer \ - --disable-setresuid \ --with-sendmail=/usr/sbin/sendmail \ + --with-timedir=/var/lib/sudo \ --mandir=/usr/share/man \ --libexecdir=/usr/lib/sudo \ - --with-secure-path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin" + $(configure_args) # LDAP version mkdir -p build-ldap - cd build-ldap && NROFFPROG=/usr/bin/nroff $(CURDIR)/configure \ + cd build-ldap && NROFFPROG=/usr/bin/nroff CFLAGS="$(CFLAGS)" \ + CPPFLAGS="$(CPPFLAGS)" LDFLAGS="$(LDFLAGS)" $(CURDIR)/configure \ --prefix=/usr -v \ --with-all-insults \ - --with-devel \ --with-pam \ --with-ldap \ --with-fqdn \ @@ -61,24 +70,28 @@ configure-stamp: --libexecdir=/usr/lib/sudo \ --with-secure-path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin" - touch config-stamp + touch configure-stamp -build: build-stamp +build: build-arch build-indep +build-arch: build-stamp +build-indep: build-stamp build-stamp: configure-stamp dh_testdir # ensure our pod changes get picked up - $(MAKE) sudoers.man.in sudo.man.in visudo.man.in + $(MAKE) -C doc sudoers.man.in sudo.man.in visudo.man.in $(MAKE) -C build-simple $(MAKE) -C build-ldap + $(MAKE) -C build-simple check + touch build-stamp clean: dh_testdir dh_testroot - rm -f config-stamp build-stamp + rm -f configure-stamp build-stamp rm -rf build-simple build-ldap rm -f config.cache dh_clean @@ -93,16 +106,21 @@ install: build-stamp $(MAKE) -C build-ldap install DESTDIR=$(CURDIR)/debian/sudo-ldap # remove stuff we don't want - rm -f debian/sudo/etc/sudoers \ - debian/sudo-ldap/etc/sudoers \ - debian/sudo/usr/share/doc/sudo/LICENSE* \ - debian/sudo-ldap/usr/share/doc/sudo/LICENSE* + rm -f debian/sudo*/etc/sudoers \ + debian/sudo*/usr/share/doc/sudo/LICENSE* \ + debian/sudo*/usr/share/doc/sudo/ChangeLog # move upstream-installed docs to the right place for ldap package mv debian/sudo-ldap/usr/share/doc/sudo/* \ debian/sudo-ldap/usr/share/doc/sudo-ldap/ rmdir debian/sudo-ldap/usr/share/doc/sudo + # move sample files to the examples folder + mv debian/sudo/usr/share/doc/sudo/sample.* \ + debian/sudo/usr/share/doc/sudo/examples/ + mv debian/sudo-ldap/usr/share/doc/sudo-ldap/sample.* \ + debian/sudo-ldap/usr/share/doc/sudo-ldap/examples/ + # and install things we do want that make install doesn't know about install -o root -g root -m 0644 debian/sudo.pam \ debian/sudo/etc/pam.d/sudo @@ -114,18 +132,27 @@ install: build-stamp install -o root -g root -m 0644 debian/sudo-ldap.lintian \ debian/sudo-ldap/usr/share/lintian/overrides/sudo-ldap + install -o root -g root -m 0440 debian/sudoers \ + debian/sudo/etc/sudoers + install -o root -g root -m 0440 debian/sudoers \ + debian/sudo-ldap/etc/sudoers + install -o root -g root -m 0440 debian/README \ debian/sudo/etc/sudoers.d/README install -o root -g root -m 0440 debian/README \ debian/sudo-ldap/etc/sudoers.d/README + install -o root -g root -m 0644 debian/sudo.service \ + debian/sudo/lib/systemd/system/sudo.service + install -o root -g root -m 0644 debian/sudo.service \ + debian/sudo-ldap/lib/systemd/system/sudo.service + binary-indep: build install binary-arch: build install dh_testdir dh_testroot dh_installdocs -A - dh_installexamples -A sample.sudoers dh_installinit -psudo -psudo-ldap --name=sudo dh_installman -A dh_installinfo -A @@ -144,4 +171,4 @@ binary-arch: build install dh_builddeb binary: binary-indep binary-arch -.PHONY: configure build clean binary-indep binary-arch binary install +.PHONY: configure build-indep build-arch build clean binary-indep binary-arch binary install diff --git a/debian/source.lintian-overrides b/debian/source.lintian-overrides deleted file mode 100644 index b747b98..0000000 --- a/debian/source.lintian-overrides +++ /dev/null @@ -1,2 +0,0 @@ -sudo source: maintainer-script-lacks-debhelper-token debian/sudo.postinst -sudo source: maintainer-script-lacks-debhelper-token debian/sudo-ldap.postinst diff --git a/debian/sudo-ldap.dirs b/debian/sudo-ldap.dirs index 83f817c..ae54a52 100644 --- a/debian/sudo-ldap.dirs +++ b/debian/sudo-ldap.dirs @@ -1,5 +1,6 @@ etc/pam.d etc/sudoers.d +lib/systemd/system usr/bin usr/share/man/man8 usr/share/man/man5 diff --git a/debian/sudo-ldap.docs b/debian/sudo-ldap.docs index 76cded0..565ca2d 100644 --- a/debian/sudo-ldap.docs +++ b/debian/sudo-ldap.docs @@ -1,8 +1,8 @@ debian/OPTIONS -UPGRADE -HISTORY +doc/UPGRADE +doc/HISTORY +doc/TROUBLESHOOTING +doc/schema.* +plugins/sudoers/sudoers2ldif README README.LDAP -TROUBLESHOOTING -sudoers2ldif -schema.* diff --git a/debian/sudo-ldap.lintian b/debian/sudo-ldap.lintian index 56e77ef..40c5568 100644 --- a/debian/sudo-ldap.lintian +++ b/debian/sudo-ldap.lintian @@ -1,3 +1,6 @@ sudo-ldap: non-standard-file-perm etc/sudoers.d/README 0440 != 0644 sudo-ldap: setuid-binary usr/bin/sudo 4755 root/root sudo-ldap: setuid-binary usr/bin/sudoedit 4755 root/root +sudo-ldap: read-in-maintainer-script +sudo-ldap: duplicate-updaterc.d-calls-in-postinst +sudo-ldap: hardening-no-stackprotector usr/lib/sudo/sudo_noexec.so diff --git a/debian/sudo-ldap.manpages b/debian/sudo-ldap.manpages index 36a1d59..29ff8eb 100644 --- a/debian/sudo-ldap.manpages +++ b/debian/sudo-ldap.manpages @@ -1,4 +1,4 @@ -build-ldap/sudo.man -build-ldap/sudoers.man -build-ldap/sudoers.ldap.man -build-ldap/visudo.man +build-ldap/doc/sudo.man +build-ldap/doc/sudoers.man +build-ldap/doc/sudoers.ldap.man +build-ldap/doc/visudo.man diff --git a/debian/sudo-ldap.postinst b/debian/sudo-ldap.postinst index 9a539d9..0aa57a9 100644 --- a/debian/sudo-ldap.postinst +++ b/debian/sudo-ldap.postinst @@ -1,82 +1,81 @@ -#!/usr/bin/perl +#!/bin/sh + +set -e # remove old link -unlink ("/etc/alternatives/sudo") if ( -l "/etc/alternatives/sudo"); - -# make sure we have a sudoers file -if ( ! -f "/etc/sudoers") { - - print "No /etc/sudoers found... creating one for you.\n"; - - open (SUDOERS, "> /etc/sudoers"); - print SUDOERS "# /etc/sudoers\n", - "#\n", - "# This file MUST be edited with the 'visudo' command as root.\n", - "#\n", - "# See the man page for details on how to write a sudoers file.\n", - "#\n\nDefaults\tenv_reset\n\n", - "# Host alias specification\n\n", - "# User alias specification\n\n", - "# Cmnd alias specification\n\n", - "# User privilege specification\nroot\tALL=(ALL) ALL\n\n", - "# Allow members of group sudo to execute any command\n", - "# (Note that later entries override this, so you might need to move\n", - "# it further down)\n", - "%sudo ALL=(ALL) ALL\n", - "#\n", - "#includedir /etc/sudoers.d\n"; - close SUDOERS; - -} +if [ -L /etc/alternatives/sudo ]; then + rm /etc/alternatives/sudo +fi + +# complain if no sudoers file is present +if [ ! -f /etc/sudoers ];then + echo "WARNING: /etc/sudoers not present!"; +fi + +# modify nsswitch.conf if needed +if [ -z "`grep \"^sudoers:\" /etc/nsswitch.conf`" ] +then + echo "sudoers: files ldap" >> /etc/nsswitch.conf +fi # handle state directory transition from /var/run/sudo to /var/lib/sudo, # moving any existing content over to avoid re-lecturing existing users -if ( -d "/var/run/sudo") { - system ('mkdir -p /var/lib/sudo'); - system ('mv /var/run/sudo/* /var/lib/sudo/'); - system ('rmdir /var/run/sudo'); -} +if [ -d "/var/run/sudo" ];then + mkdir -p /var/lib/sudo + (cd /var/run/sudo ; tar cf - .) | (cd /var/lib/sudo ; tar xf -) + rm -rf /var/run/sudo +fi # make sure sudoers has the correct permissions and owner/group -system ('chown root:root /etc/sudoers'); -system ('chmod 440 /etc/sudoers'); +chown root:root /etc/sudoers +chmod 440 /etc/sudoers -# must do a remove first to un-do the "bad" links created by previous version -system ('update-rc.d -f sudo remove >/dev/null 2>&1'); +update-rc.d -f sudo remove >/dev/null 2>&1 -system ('update-rc.d sudo start 75 2 3 4 5 . >/dev/null'); +update-rc.d sudo start 75 2 3 4 5 . >/dev/null # create symlink to ease transition to new path for ldap config # if old config file exists and new one doesn't -if (-e "/etc/ldap/ldap.conf" && ! -e "/etc/sudo-ldap.conf") { - system("ln -s ldap/ldap.conf /etc/sudo-ldap.conf"); -} +if [ -e /etc/ldap/ldap.conf -a ! -e /etc/sudo-ldap.conf ];then + ln -s ldap/ldap.conf /etc/sudo-ldap.conf +fi + +# if we've gotten this far .. remove the saved, unchanged old sudoers file +rm -f /etc/sudoers.pre-conffile # make sure we have a sudo group -exit 0 if getgrnam("sudo"); # we're finished if there is a group sudo - -$gid = 27; # start searcg with gid 27 -setgrent; -while (getgrgid($gid)) { - ++$gid; -} -endgrent; - -if ($gid != 27) { - print "On Debian we normally use gid 27 for 'sudo'.\n"; - $gname = getgrgid(27); - print "However, on your system gid 27 is group '$gname'.\n\n"; - print "Would you like me to stop configuring sudo so that you can change this? [n] "; - $ans = ; - if ($ans =~ m/^[yY].*/) { - print "'dpkg --pending --configure' will restart the configuration.\n\n\n"; - exit 1; - } -} - -print "Creating group 'sudo' with gid = $gid\n"; -system("groupadd -g $gid sudo"); - -print ""; +[ -n "`getent group sudo`" ] && exit 0 # we're finished if there is a group sudo: + +# start search with gid 27 +gid="27" +while [ -n "`getent group $gid | cut -d: -f3`" ];do + gid=`expr $gid + 1` +done + + +if [ "$gid" -ne "27" ];then + echo "On Debian we normally use gid 27 for 'sudo'." + gname="`getent group 27 | cut -d: -f1`" + echo "However, on your system gid 27 is group '$gname'." + echo "" + echo "Would you like me to stop configuring sudo so that you can change this?"; + while true;do + echo -n "(Enter 'yes' to stop, enter to continue): " + read ans + [ "$ans" = "" ] && break + if [ "$ans" = "yes" -o "$ans" = "YES" ];then + echo "'dpkg --pending --configure' will restart the configuration." + exit 1; + fi + echo "Please enter exactly 'yes' to stop, or press the enter key to continue without stopping" + done +fi + +echo "Creating group 'sudo' with gid = $gid"; +groupadd -g $gid sudo + +echo "" + +#DEBHELPER# diff --git a/debian/sudo-ldap.postrm b/debian/sudo-ldap.postrm index 58bb84b..246f99d 100644 --- a/debian/sudo-ldap.postrm +++ b/debian/sudo-ldap.postrm @@ -3,18 +3,28 @@ case "$1" in purge) rm -f /etc/sudo-ldap.conf + rm -rf /var/lib/sudo ;; remove|upgrade|deconfigure) ;; - failed-upgrade) + abort-upgrade|failed-upgrade) + if [ -e "/etc/sudoers.pre-conffile" ]; then + mv /etc/sudoers.pre-conffile /etc/sudoers + fi ;; + *) echo "unknown argument --> $1" >&2 exit 0 ;; esac +# remove sudoers entries, if any, from nsswitch.conf +if [ -w /etc/nsswitch.conf ] ; then + sed -i /^sudoers:/d /etc/nsswitch.conf +fi + #DEBHELPER# diff --git a/debian/sudo-ldap.preinst b/debian/sudo-ldap.preinst new file mode 100644 index 0000000..1dfaa02 --- /dev/null +++ b/debian/sudo-ldap.preinst @@ -0,0 +1,20 @@ +#!/bin/sh -e + +case "$1" in + install|upgrade) + if dpkg --compare-versions "$2" le "1.7.4p4-4"; then + + SUDOERS="/etc/sudoers" + + if [ -e "$SUDOERS" ]; then + md5sum="$(md5sum $SUDOERS | sed -e 's/ .*//')" + if [ "$md5sum" = "c5dab0f2771411ed7e67d6dab60a311f" ]; then + # move unchanged sudoers file to avoid conffile question + mv "$SUDOERS" "$SUDOERS.pre-conffile" + fi + fi + fi + ;; +esac + +#DEBHELPER# diff --git a/debian/sudo-ldap.sudo.init b/debian/sudo-ldap.sudo.init index 530fd63..fcff6f7 100644 --- a/debian/sudo-ldap.sudo.init +++ b/debian/sudo-ldap.sudo.init @@ -7,6 +7,8 @@ # X-Start-Before: rmnologin # Default-Start: 2 3 4 5 # Default-Stop: +# Short-Description: Provide limited super user privileges to specific users +# Description: Provide limited super user privileges to specific users. ### END INIT INFO N=/etc/init.d/sudo @@ -21,10 +23,10 @@ case "$1" in find /var/lib/sudo -exec touch -t 198501010000 '{}' \; fi ;; - stop|reload|restart|force-reload) + stop|reload|restart|force-reload|status) ;; *) - echo "Usage: $N {start|stop|restart|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 exit 1 ;; esac diff --git a/debian/sudo.dirs b/debian/sudo.dirs index 4d15db4..f1e6b23 100644 --- a/debian/sudo.dirs +++ b/debian/sudo.dirs @@ -1,5 +1,6 @@ etc/pam.d etc/sudoers.d +lib/systemd/system usr/bin usr/share/man/man8 usr/share/man/man5 diff --git a/debian/sudo.docs b/debian/sudo.docs index e3c9b7b..b590209 100644 --- a/debian/sudo.docs +++ b/debian/sudo.docs @@ -1,5 +1,5 @@ debian/OPTIONS -UPGRADE -HISTORY +doc/UPGRADE +doc/HISTORY +doc/TROUBLESHOOTING README -TROUBLESHOOTING diff --git a/debian/sudo.lintian b/debian/sudo.lintian index 0b4b58c..454a914 100644 --- a/debian/sudo.lintian +++ b/debian/sudo.lintian @@ -1,3 +1,6 @@ sudo: non-standard-file-perm etc/sudoers.d/README 0440 != 0644 sudo: setuid-binary usr/bin/sudo 4755 root/root sudo: setuid-binary usr/bin/sudoedit 4755 root/root +sudo: read-in-maintainer-script +sudo: duplicate-updaterc.d-calls-in-postinst +sudo: hardening-no-stackprotector usr/lib/sudo/sudo_noexec.so diff --git a/debian/sudo.manpages b/debian/sudo.manpages index e22c9d0..7be60ff 100644 --- a/debian/sudo.manpages +++ b/debian/sudo.manpages @@ -1,3 +1,3 @@ -build-simple/sudo.man -build-simple/sudoers.man -build-simple/visudo.man +build-simple/doc/sudo.man +build-simple/doc/sudoers.man +build-simple/doc/visudo.man diff --git a/debian/sudo.pam b/debian/sudo.pam index cef0705..68c261a 100644 --- a/debian/sudo.pam +++ b/debian/sudo.pam @@ -2,6 +2,4 @@ @include common-auth @include common-account - -session required pam_permit.so -session required pam_limits.so +@include common-session-noninteractive diff --git a/debian/sudo.postinst b/debian/sudo.postinst index 10dc14a..a1261b5 100644 --- a/debian/sudo.postinst +++ b/debian/sudo.postinst @@ -1,76 +1,69 @@ -#!/usr/bin/perl +#!/bin/sh + +set -e # remove old link -unlink ("/etc/alternatives/sudo") if ( -l "/etc/alternatives/sudo"); - -# make sure we have a sudoers file -if ( ! -f "/etc/sudoers") { - - print "No /etc/sudoers found... creating one for you.\n"; - - open (SUDOERS, "> /etc/sudoers"); - print SUDOERS "# /etc/sudoers\n", - "#\n", - "# This file MUST be edited with the 'visudo' command as root.\n", - "#\n", - "# See the man page for details on how to write a sudoers file.\n", - "#\n\nDefaults\tenv_reset\n\n", - "# Host alias specification\n\n", - "# User alias specification\n\n", - "# Cmnd alias specification\n\n", - "# User privilege specification\nroot\tALL=(ALL) ALL\n\n", - "# Allow members of group sudo to execute any command\n", - "# (Note that later entries override this, so you might need to move\n", - "# it further down)\n", - "%sudo ALL=(ALL) ALL\n", - "#\n", - "#includedir /etc/sudoers.d\n"; - close SUDOERS; - -} +if [ -L /etc/alternatives/sudo ]; then + rm /etc/alternatives/sudo +fi + +# complain if no sudoers file is present +if [ ! -f /etc/sudoers ];then + echo "WARNING: /etc/sudoers not present!"; +fi # handle state directory transition from /var/run/sudo to /var/lib/sudo, # moving any existing content over to avoid re-lecturing existing users -if ( -d "/var/run/sudo") { - system ('mkdir -p /var/lib/sudo'); - system ('mv /var/run/sudo/* /var/lib/sudo/'); - system ('rmdir /var/run/sudo'); -} +if [ -d "/var/run/sudo" ];then + mkdir -p /var/lib/sudo + (cd /var/run/sudo ; tar cf - .) | (cd /var/lib/sudo ; tar xf -) + rm -rf /var/run/sudo +fi # make sure sudoers has the correct permissions and owner/group -system ('chown root:root /etc/sudoers'); -system ('chmod 440 /etc/sudoers'); +chown root:root /etc/sudoers +chmod 440 /etc/sudoers + +update-rc.d -f sudo remove >/dev/null 2>&1 -# must do a remove first to un-do the "bad" links created by previous version -system ('update-rc.d -f sudo remove >/dev/null 2>&1'); +update-rc.d sudo start 75 2 3 4 5 . >/dev/null -system ('update-rc.d sudo start 75 2 3 4 5 . >/dev/null'); +# if we've gotten this far .. remove the saved, unchanged old sudoers file +rm -f /etc/sudoers.pre-conffile # make sure we have a sudo group -exit 0 if getgrnam("sudo"); # we're finished if there is a group sudo - -$gid = 27; # start searcg with gid 27 -setgrent; -while (getgrgid($gid)) { - ++$gid; -} -endgrent; - -if ($gid != 27) { - print "On Debian we normally use gid 27 for 'sudo'.\n"; - $gname = getgrgid(27); - print "However, on your system gid 27 is group '$gname'.\n\n"; - print "Would you like me to stop configuring sudo so that you can change this? [n] "; - $ans = ; - if ($ans =~ m/^[yY].*/) { - print "'dpkg --pending --configure' will restart the configuration.\n\n\n"; - exit 1; - } -} - -print "Creating group 'sudo' with gid = $gid\n"; -system("groupadd -g $gid sudo"); - -print ""; +[ -n "`getent group sudo`" ] && exit 0 # we're finished if there is a group sudo: + +# start search with gid 27 +gid="27" +while [ -n "`getent group $gid | cut -d: -f3`" ];do + gid=`expr $gid + 1` +done + + +if [ "$gid" -ne "27" ];then + echo "On Debian we normally use gid 27 for 'sudo'." + gname="`getent group 27 | cut -d: -f1`" + echo "However, on your system gid 27 is group '$gname'." + echo "" + echo "Would you like me to stop configuring sudo so that you can change this?"; + while true;do + echo -n "(Enter 'yes' to stop, enter to continue): " + read ans + [ "$ans" = "" ] && break + if [ "$ans" = "yes" -o "$ans" = "YES" ];then + echo "'dpkg --pending --configure' will restart the configuration." + exit 1; + fi + echo "Please enter exactly 'yes' to stop, or press the enter key to continue without stopping" + done +fi + +echo "Creating group 'sudo' with gid = $gid"; +groupadd -g $gid sudo + +echo "" + +#DEBHELPER# diff --git a/debian/sudo.postrm b/debian/sudo.postrm new file mode 100644 index 0000000..ab1425a --- /dev/null +++ b/debian/sudo.postrm @@ -0,0 +1,23 @@ +#!/bin/sh -e + +case "$1" in + purge) + rm -rf /var/lib/sudo + ;; + + remove|upgrade|deconfigure) + ;; + + abort-upgrade|failed-upgrade) + if [ -e "/etc/sudoers.pre-conffile" ]; then + mv /etc/sudoers.pre-conffile /etc/sudoers + fi + ;; + + *) + echo "unknown argument --> $1" >&2 + exit 0 + ;; +esac + +#DEBHELPER# diff --git a/debian/sudo.preinst b/debian/sudo.preinst new file mode 100644 index 0000000..1dfaa02 --- /dev/null +++ b/debian/sudo.preinst @@ -0,0 +1,20 @@ +#!/bin/sh -e + +case "$1" in + install|upgrade) + if dpkg --compare-versions "$2" le "1.7.4p4-4"; then + + SUDOERS="/etc/sudoers" + + if [ -e "$SUDOERS" ]; then + md5sum="$(md5sum $SUDOERS | sed -e 's/ .*//')" + if [ "$md5sum" = "c5dab0f2771411ed7e67d6dab60a311f" ]; then + # move unchanged sudoers file to avoid conffile question + mv "$SUDOERS" "$SUDOERS.pre-conffile" + fi + fi + fi + ;; +esac + +#DEBHELPER# diff --git a/debian/sudo.service b/debian/sudo.service new file mode 100644 index 0000000..664d855 --- /dev/null +++ b/debian/sudo.service @@ -0,0 +1,10 @@ +[Unit] +Description=Provide limited super user privileges to specific users + +[Service] +Type=oneshot +# \073 is ';' which needs to be part of the find parameters +ExecStart=/usr/bin/find /var/lib/sudo -exec /usr/bin/touch -t 198501010000 '{}' \073 + +[Install] +WantedBy=multi-user.target diff --git a/debian/sudo.sudo.init b/debian/sudo.sudo.init index 9300b1e..fea82ec 100644 --- a/debian/sudo.sudo.init +++ b/debian/sudo.sudo.init @@ -7,6 +7,8 @@ # X-Start-Before: rmnologin # Default-Start: 2 3 4 5 # Default-Stop: +# Short-Description: Provide limited super user privileges to specific users +# Description: Provide limited super user privileges to specific users. ### END INIT INFO N=/etc/init.d/sudo @@ -21,10 +23,10 @@ case "$1" in find /var/lib/sudo -exec touch -t 198501010000 '{}' \; fi ;; - stop|reload|restart|force-reload) + stop|reload|restart|force-reload|status) ;; *) - echo "Usage: $N {start|stop|restart|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 exit 1 ;; esac diff --git a/debian/sudoers b/debian/sudoers index 354961e..d4cc632 100644 --- a/debian/sudoers +++ b/debian/sudoers @@ -1,19 +1,27 @@ # # This file MUST be edited with the 'visudo' command as root. # -# See the man page for details on how to write a sudoers file. +# Please consider adding local content in /etc/sudoers.d/ instead of +# directly modifying this file. # -# Note that modifying behavior defined here may also be done by -# adding content in the /etc/sudoers.d directory. +# See the man page for details on how to write a sudoers file. # - Defaults env_reset +Defaults mail_badpass +Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +# Host alias specification -# root can use sudo to do anything -root ALL=(ALL) ALL +# User alias specification + +# Cmnd alias specification + +# User privilege specification +root ALL=(ALL:ALL) ALL # Allow members of group sudo to execute any command -# (Note that later entries may override this) -%sudo ALL=(ALL) ALL +%sudo ALL=(ALL:ALL) ALL + +# See sudoers(5) for more information on "#include" directives: #includedir /etc/sudoers.d diff --git a/def_data.c b/def_data.c deleted file mode 100644 index fbdc0c7..0000000 --- a/def_data.c +++ /dev/null @@ -1,336 +0,0 @@ -static struct def_values def_data_lecture[] = { - { "never", never }, - { "once", once }, - { "always", always }, - { NULL, 0 }, -}; - -static struct def_values def_data_listpw[] = { - { "never", never }, - { "any", any }, - { "all", all }, - { "always", always }, - { NULL, 0 }, -}; - -static struct def_values def_data_verifypw[] = { - { "never", never }, - { "all", all }, - { "any", any }, - { "always", always }, - { NULL, 0 }, -}; - -struct sudo_defs_types sudo_defs_table[] = { - { - "syslog", T_LOGFAC|T_BOOL, - "Syslog facility if syslog is being used for logging: %s", - NULL, - }, { - "syslog_goodpri", T_LOGPRI, - "Syslog priority to use when user authenticates successfully: %s", - NULL, - }, { - "syslog_badpri", T_LOGPRI, - "Syslog priority to use when user authenticates unsuccessfully: %s", - NULL, - }, { - "long_otp_prompt", T_FLAG, - "Put OTP prompt on its own line", - NULL, - }, { - "ignore_dot", T_FLAG, - "Ignore '.' in $PATH", - NULL, - }, { - "mail_always", T_FLAG, - "Always send mail when sudo is run", - NULL, - }, { - "mail_badpass", T_FLAG, - "Send mail if user authentication fails", - NULL, - }, { - "mail_no_user", T_FLAG, - "Send mail if the user is not in sudoers", - NULL, - }, { - "mail_no_host", T_FLAG, - "Send mail if the user is not in sudoers for this host", - NULL, - }, { - "mail_no_perms", T_FLAG, - "Send mail if the user is not allowed to run a command", - NULL, - }, { - "tty_tickets", T_FLAG, - "Use a separate timestamp for each user/tty combo", - NULL, - }, { - "lecture", T_TUPLE|T_BOOL, - "Lecture user the first time they run sudo", - def_data_lecture, - }, { - "lecture_file", T_STR|T_PATH|T_BOOL, - "File containing the sudo lecture: %s", - NULL, - }, { - "authenticate", T_FLAG, - "Require users to authenticate by default", - NULL, - }, { - "root_sudo", T_FLAG, - "Root may run sudo", - NULL, - }, { - "log_host", T_FLAG, - "Log the hostname in the (non-syslog) log file", - NULL, - }, { - "log_year", T_FLAG, - "Log the year in the (non-syslog) log file", - NULL, - }, { - "shell_noargs", T_FLAG, - "If sudo is invoked with no arguments, start a shell", - NULL, - }, { - "set_home", T_FLAG, - "Set $HOME to the target user when starting a shell with -s", - NULL, - }, { - "always_set_home", T_FLAG, - "Always set $HOME to the target user's home directory", - NULL, - }, { - "path_info", T_FLAG, - "Allow some information gathering to give useful error messages", - NULL, - }, { - "fqdn", T_FLAG, - "Require fully-qualified hostnames in the sudoers file", - NULL, - }, { - "insults", T_FLAG, - "Insult the user when they enter an incorrect password", - NULL, - }, { - "requiretty", T_FLAG, - "Only allow the user to run sudo if they have a tty", - NULL, - }, { - "env_editor", T_FLAG, - "Visudo will honor the EDITOR environment variable", - NULL, - }, { - "rootpw", T_FLAG, - "Prompt for root's password, not the users's", - NULL, - }, { - "runaspw", T_FLAG, - "Prompt for the runas_default user's password, not the users's", - NULL, - }, { - "targetpw", T_FLAG, - "Prompt for the target user's password, not the users's", - NULL, - }, { - "use_loginclass", T_FLAG, - "Apply defaults in the target user's login class if there is one", - NULL, - }, { - "set_logname", T_FLAG, - "Set the LOGNAME and USER environment variables", - NULL, - }, { - "stay_setuid", T_FLAG, - "Only set the effective uid to the target user, not the real uid", - NULL, - }, { - "preserve_groups", T_FLAG, - "Don't initialize the group vector to that of the target user", - NULL, - }, { - "loglinelen", T_UINT|T_BOOL, - "Length at which to wrap log file lines (0 for no wrap): %d", - NULL, - }, { - "timestamp_timeout", T_FLOAT|T_BOOL, - "Authentication timestamp timeout: %.1f minutes", - NULL, - }, { - "passwd_timeout", T_FLOAT|T_BOOL, - "Password prompt timeout: %.1f minutes", - NULL, - }, { - "passwd_tries", T_UINT, - "Number of tries to enter a password: %d", - NULL, - }, { - "umask", T_MODE|T_BOOL, - "Umask to use or 0777 to use user's: 0%o", - NULL, - }, { - "logfile", T_STR|T_BOOL|T_PATH, - "Path to log file: %s", - NULL, - }, { - "mailerpath", T_STR|T_BOOL|T_PATH, - "Path to mail program: %s", - NULL, - }, { - "mailerflags", T_STR|T_BOOL, - "Flags for mail program: %s", - NULL, - }, { - "mailto", T_STR|T_BOOL, - "Address to send mail to: %s", - NULL, - }, { - "mailfrom", T_STR|T_BOOL, - "Address to send mail from: %s", - NULL, - }, { - "mailsub", T_STR, - "Subject line for mail messages: %s", - NULL, - }, { - "badpass_message", T_STR, - "Incorrect password message: %s", - NULL, - }, { - "timestampdir", T_STR|T_PATH, - "Path to authentication timestamp dir: %s", - NULL, - }, { - "timestampowner", T_STR, - "Owner of the authentication timestamp dir: %s", - NULL, - }, { - "exempt_group", T_STR|T_BOOL, - "Users in this group are exempt from password and PATH requirements: %s", - NULL, - }, { - "passprompt", T_STR, - "Default password prompt: %s", - NULL, - }, { - "passprompt_override", T_FLAG, - "If set, passprompt will override system prompt in all cases.", - NULL, - }, { - "runas_default", T_STR, - "Default user to run commands as: %s", - NULL, - }, { - "secure_path", T_STR|T_BOOL, - "Value to override user's $PATH with: %s", - NULL, - }, { - "editor", T_STR|T_PATH, - "Path to the editor for use by visudo: %s", - NULL, - }, { - "listpw", T_TUPLE|T_BOOL, - "When to require a password for 'list' pseudocommand: %s", - def_data_listpw, - }, { - "verifypw", T_TUPLE|T_BOOL, - "When to require a password for 'verify' pseudocommand: %s", - def_data_verifypw, - }, { - "noexec", T_FLAG, - "Preload the dummy exec functions contained in 'noexec_file'", - NULL, - }, { - "noexec_file", T_STR|T_PATH, - "File containing dummy exec functions: %s", - NULL, - }, { - "ignore_local_sudoers", T_FLAG, - "If LDAP directory is up, do we ignore local sudoers file", - NULL, - }, { - "closefrom", T_INT, - "File descriptors >= %d will be closed before executing a command", - NULL, - }, { - "closefrom_override", T_FLAG, - "If set, users may override the value of `closefrom' with the -C option", - NULL, - }, { - "setenv", T_FLAG, - "Allow users to set arbitrary environment variables", - NULL, - }, { - "env_reset", T_FLAG, - "Reset the environment to a default set of variables", - NULL, - }, { - "env_check", T_LIST|T_BOOL, - "Environment variables to check for sanity:", - NULL, - }, { - "env_delete", T_LIST|T_BOOL, - "Environment variables to remove:", - NULL, - }, { - "env_keep", T_LIST|T_BOOL, - "Environment variables to preserve:", - NULL, - }, { - "role", T_STR, - "SELinux role to use in the new security context: %s", - NULL, - }, { - "type", T_STR, - "SELinux type to use in the new security context: %s", - NULL, - }, { - "askpass", T_STR|T_PATH|T_BOOL, - "Path to the askpass helper program: %s", - NULL, - }, { - "env_file", T_STR|T_PATH|T_BOOL, - "Path to the sudo-specific environment file: %s", - NULL, - }, { - "sudoers_locale", T_STR, - "Locale to use while parsing sudoers: %s", - NULL, - }, { - "visiblepw", T_FLAG, - "Allow sudo to prompt for a password even if it would be visisble", - NULL, - }, { - "pwfeedback", T_FLAG, - "Provide visual feedback at the password prompt when there is user input", - NULL, - }, { - "fast_glob", T_FLAG, - "Use faster globbing that is less accurate but does not access the filesystem", - NULL, - }, { - "umask_override", T_FLAG, - "The umask specified in sudoers will override the user's, even if it is more permissive", - NULL, - }, { - "log_input", T_FLAG, - "Log user's input for the command being run", - NULL, - }, { - "log_output", T_FLAG, - "Log the output of the command being run", - NULL, - }, { - "compress_io", T_FLAG, - "Compress I/O logs using zlib", - NULL, - }, { - "use_pty", T_FLAG, - "Always run commands in a pseudo-tty", - NULL, - }, { - NULL, 0, NULL - } -}; diff --git a/def_data.h b/def_data.h deleted file mode 100644 index e868d32..0000000 --- a/def_data.h +++ /dev/null @@ -1,162 +0,0 @@ -#define def_syslog (sudo_defs_table[0].sd_un.ival) -#define I_SYSLOG 0 -#define def_syslog_goodpri (sudo_defs_table[1].sd_un.ival) -#define I_SYSLOG_GOODPRI 1 -#define def_syslog_badpri (sudo_defs_table[2].sd_un.ival) -#define I_SYSLOG_BADPRI 2 -#define def_long_otp_prompt (sudo_defs_table[3].sd_un.flag) -#define I_LONG_OTP_PROMPT 3 -#define def_ignore_dot (sudo_defs_table[4].sd_un.flag) -#define I_IGNORE_DOT 4 -#define def_mail_always (sudo_defs_table[5].sd_un.flag) -#define I_MAIL_ALWAYS 5 -#define def_mail_badpass (sudo_defs_table[6].sd_un.flag) -#define I_MAIL_BADPASS 6 -#define def_mail_no_user (sudo_defs_table[7].sd_un.flag) -#define I_MAIL_NO_USER 7 -#define def_mail_no_host (sudo_defs_table[8].sd_un.flag) -#define I_MAIL_NO_HOST 8 -#define def_mail_no_perms (sudo_defs_table[9].sd_un.flag) -#define I_MAIL_NO_PERMS 9 -#define def_tty_tickets (sudo_defs_table[10].sd_un.flag) -#define I_TTY_TICKETS 10 -#define def_lecture (sudo_defs_table[11].sd_un.tuple) -#define I_LECTURE 11 -#define def_lecture_file (sudo_defs_table[12].sd_un.str) -#define I_LECTURE_FILE 12 -#define def_authenticate (sudo_defs_table[13].sd_un.flag) -#define I_AUTHENTICATE 13 -#define def_root_sudo (sudo_defs_table[14].sd_un.flag) -#define I_ROOT_SUDO 14 -#define def_log_host (sudo_defs_table[15].sd_un.flag) -#define I_LOG_HOST 15 -#define def_log_year (sudo_defs_table[16].sd_un.flag) -#define I_LOG_YEAR 16 -#define def_shell_noargs (sudo_defs_table[17].sd_un.flag) -#define I_SHELL_NOARGS 17 -#define def_set_home (sudo_defs_table[18].sd_un.flag) -#define I_SET_HOME 18 -#define def_always_set_home (sudo_defs_table[19].sd_un.flag) -#define I_ALWAYS_SET_HOME 19 -#define def_path_info (sudo_defs_table[20].sd_un.flag) -#define I_PATH_INFO 20 -#define def_fqdn (sudo_defs_table[21].sd_un.flag) -#define I_FQDN 21 -#define def_insults (sudo_defs_table[22].sd_un.flag) -#define I_INSULTS 22 -#define def_requiretty (sudo_defs_table[23].sd_un.flag) -#define I_REQUIRETTY 23 -#define def_env_editor (sudo_defs_table[24].sd_un.flag) -#define I_ENV_EDITOR 24 -#define def_rootpw (sudo_defs_table[25].sd_un.flag) -#define I_ROOTPW 25 -#define def_runaspw (sudo_defs_table[26].sd_un.flag) -#define I_RUNASPW 26 -#define def_targetpw (sudo_defs_table[27].sd_un.flag) -#define I_TARGETPW 27 -#define def_use_loginclass (sudo_defs_table[28].sd_un.flag) -#define I_USE_LOGINCLASS 28 -#define def_set_logname (sudo_defs_table[29].sd_un.flag) -#define I_SET_LOGNAME 29 -#define def_stay_setuid (sudo_defs_table[30].sd_un.flag) -#define I_STAY_SETUID 30 -#define def_preserve_groups (sudo_defs_table[31].sd_un.flag) -#define I_PRESERVE_GROUPS 31 -#define def_loglinelen (sudo_defs_table[32].sd_un.ival) -#define I_LOGLINELEN 32 -#define def_timestamp_timeout (sudo_defs_table[33].sd_un.fval) -#define I_TIMESTAMP_TIMEOUT 33 -#define def_passwd_timeout (sudo_defs_table[34].sd_un.fval) -#define I_PASSWD_TIMEOUT 34 -#define def_passwd_tries (sudo_defs_table[35].sd_un.ival) -#define I_PASSWD_TRIES 35 -#define def_umask (sudo_defs_table[36].sd_un.mode) -#define I_UMASK 36 -#define def_logfile (sudo_defs_table[37].sd_un.str) -#define I_LOGFILE 37 -#define def_mailerpath (sudo_defs_table[38].sd_un.str) -#define I_MAILERPATH 38 -#define def_mailerflags (sudo_defs_table[39].sd_un.str) -#define I_MAILERFLAGS 39 -#define def_mailto (sudo_defs_table[40].sd_un.str) -#define I_MAILTO 40 -#define def_mailfrom (sudo_defs_table[41].sd_un.str) -#define I_MAILFROM 41 -#define def_mailsub (sudo_defs_table[42].sd_un.str) -#define I_MAILSUB 42 -#define def_badpass_message (sudo_defs_table[43].sd_un.str) -#define I_BADPASS_MESSAGE 43 -#define def_timestampdir (sudo_defs_table[44].sd_un.str) -#define I_TIMESTAMPDIR 44 -#define def_timestampowner (sudo_defs_table[45].sd_un.str) -#define I_TIMESTAMPOWNER 45 -#define def_exempt_group (sudo_defs_table[46].sd_un.str) -#define I_EXEMPT_GROUP 46 -#define def_passprompt (sudo_defs_table[47].sd_un.str) -#define I_PASSPROMPT 47 -#define def_passprompt_override (sudo_defs_table[48].sd_un.flag) -#define I_PASSPROMPT_OVERRIDE 48 -#define def_runas_default (sudo_defs_table[49].sd_un.str) -#define I_RUNAS_DEFAULT 49 -#define def_secure_path (sudo_defs_table[50].sd_un.str) -#define I_SECURE_PATH 50 -#define def_editor (sudo_defs_table[51].sd_un.str) -#define I_EDITOR 51 -#define def_listpw (sudo_defs_table[52].sd_un.tuple) -#define I_LISTPW 52 -#define def_verifypw (sudo_defs_table[53].sd_un.tuple) -#define I_VERIFYPW 53 -#define def_noexec (sudo_defs_table[54].sd_un.flag) -#define I_NOEXEC 54 -#define def_noexec_file (sudo_defs_table[55].sd_un.str) -#define I_NOEXEC_FILE 55 -#define def_ignore_local_sudoers (sudo_defs_table[56].sd_un.flag) -#define I_IGNORE_LOCAL_SUDOERS 56 -#define def_closefrom (sudo_defs_table[57].sd_un.ival) -#define I_CLOSEFROM 57 -#define def_closefrom_override (sudo_defs_table[58].sd_un.flag) -#define I_CLOSEFROM_OVERRIDE 58 -#define def_setenv (sudo_defs_table[59].sd_un.flag) -#define I_SETENV 59 -#define def_env_reset (sudo_defs_table[60].sd_un.flag) -#define I_ENV_RESET 60 -#define def_env_check (sudo_defs_table[61].sd_un.list) -#define I_ENV_CHECK 61 -#define def_env_delete (sudo_defs_table[62].sd_un.list) -#define I_ENV_DELETE 62 -#define def_env_keep (sudo_defs_table[63].sd_un.list) -#define I_ENV_KEEP 63 -#define def_role (sudo_defs_table[64].sd_un.str) -#define I_ROLE 64 -#define def_type (sudo_defs_table[65].sd_un.str) -#define I_TYPE 65 -#define def_askpass (sudo_defs_table[66].sd_un.str) -#define I_ASKPASS 66 -#define def_env_file (sudo_defs_table[67].sd_un.str) -#define I_ENV_FILE 67 -#define def_sudoers_locale (sudo_defs_table[68].sd_un.str) -#define I_SUDOERS_LOCALE 68 -#define def_visiblepw (sudo_defs_table[69].sd_un.flag) -#define I_VISIBLEPW 69 -#define def_pwfeedback (sudo_defs_table[70].sd_un.flag) -#define I_PWFEEDBACK 70 -#define def_fast_glob (sudo_defs_table[71].sd_un.flag) -#define I_FAST_GLOB 71 -#define def_umask_override (sudo_defs_table[72].sd_un.flag) -#define I_UMASK_OVERRIDE 72 -#define def_log_input (sudo_defs_table[73].sd_un.flag) -#define I_LOG_INPUT 73 -#define def_log_output (sudo_defs_table[74].sd_un.flag) -#define I_LOG_OUTPUT 74 -#define def_compress_io (sudo_defs_table[75].sd_un.flag) -#define I_COMPRESS_IO 75 -#define def_use_pty (sudo_defs_table[76].sd_un.flag) -#define I_USE_PTY 76 - -enum def_tupple { - never, - once, - always, - any, - all -}; diff --git a/def_data.in b/def_data.in deleted file mode 100644 index d903cfa..0000000 --- a/def_data.in +++ /dev/null @@ -1,246 +0,0 @@ -# -# Format: -# -# var_name -# TYPE -# description (or NULL) -# array of struct def_values if TYPE == T_TUPLE -# -# NOTE: for tuples that can be used in a boolean context the first -# value corresponds to boolean FALSE and the second to TRUE. -# - -syslog - T_LOGFAC|T_BOOL - "Syslog facility if syslog is being used for logging: %s" -syslog_goodpri - T_LOGPRI - "Syslog priority to use when user authenticates successfully: %s" -syslog_badpri - T_LOGPRI - "Syslog priority to use when user authenticates unsuccessfully: %s" -long_otp_prompt - T_FLAG - "Put OTP prompt on its own line" -ignore_dot - T_FLAG - "Ignore '.' in $PATH" -mail_always - T_FLAG - "Always send mail when sudo is run" -mail_badpass - T_FLAG - "Send mail if user authentication fails" -mail_no_user - T_FLAG - "Send mail if the user is not in sudoers" -mail_no_host - T_FLAG - "Send mail if the user is not in sudoers for this host" -mail_no_perms - T_FLAG - "Send mail if the user is not allowed to run a command" -tty_tickets - T_FLAG - "Use a separate timestamp for each user/tty combo" -lecture - T_TUPLE|T_BOOL - "Lecture user the first time they run sudo" - never once always -lecture_file - T_STR|T_PATH|T_BOOL - "File containing the sudo lecture: %s" -authenticate - T_FLAG - "Require users to authenticate by default" -root_sudo - T_FLAG - "Root may run sudo" -log_host - T_FLAG - "Log the hostname in the (non-syslog) log file" -log_year - T_FLAG - "Log the year in the (non-syslog) log file" -shell_noargs - T_FLAG - "If sudo is invoked with no arguments, start a shell" -set_home - T_FLAG - "Set $HOME to the target user when starting a shell with -s" -always_set_home - T_FLAG - "Always set $HOME to the target user's home directory" -path_info - T_FLAG - "Allow some information gathering to give useful error messages" -fqdn - T_FLAG - "Require fully-qualified hostnames in the sudoers file" -insults - T_FLAG - "Insult the user when they enter an incorrect password" -requiretty - T_FLAG - "Only allow the user to run sudo if they have a tty" -env_editor - T_FLAG - "Visudo will honor the EDITOR environment variable" -rootpw - T_FLAG - "Prompt for root's password, not the users's" -runaspw - T_FLAG - "Prompt for the runas_default user's password, not the users's" -targetpw - T_FLAG - "Prompt for the target user's password, not the users's" -use_loginclass - T_FLAG - "Apply defaults in the target user's login class if there is one" -set_logname - T_FLAG - "Set the LOGNAME and USER environment variables" -stay_setuid - T_FLAG - "Only set the effective uid to the target user, not the real uid" -preserve_groups - T_FLAG - "Don't initialize the group vector to that of the target user" -loglinelen - T_UINT|T_BOOL - "Length at which to wrap log file lines (0 for no wrap): %d" -timestamp_timeout - T_FLOAT|T_BOOL - "Authentication timestamp timeout: %.1f minutes" -passwd_timeout - T_FLOAT|T_BOOL - "Password prompt timeout: %.1f minutes" -passwd_tries - T_UINT - "Number of tries to enter a password: %d" -umask - T_MODE|T_BOOL - "Umask to use or 0777 to use user's: 0%o" -logfile - T_STR|T_BOOL|T_PATH - "Path to log file: %s" -mailerpath - T_STR|T_BOOL|T_PATH - "Path to mail program: %s" -mailerflags - T_STR|T_BOOL - "Flags for mail program: %s" -mailto - T_STR|T_BOOL - "Address to send mail to: %s" -mailfrom - T_STR|T_BOOL - "Address to send mail from: %s" -mailsub - T_STR - "Subject line for mail messages: %s" -badpass_message - T_STR - "Incorrect password message: %s" -timestampdir - T_STR|T_PATH - "Path to authentication timestamp dir: %s" -timestampowner - T_STR - "Owner of the authentication timestamp dir: %s" -exempt_group - T_STR|T_BOOL - "Users in this group are exempt from password and PATH requirements: %s" -passprompt - T_STR - "Default password prompt: %s" -passprompt_override - T_FLAG - "If set, passprompt will override system prompt in all cases." -runas_default - T_STR - "Default user to run commands as: %s" -secure_path - T_STR|T_BOOL - "Value to override user's $PATH with: %s" -editor - T_STR|T_PATH - "Path to the editor for use by visudo: %s" -listpw - T_TUPLE|T_BOOL - "When to require a password for 'list' pseudocommand: %s" - never any all always -verifypw - T_TUPLE|T_BOOL - "When to require a password for 'verify' pseudocommand: %s" - never all any always -noexec - T_FLAG - "Preload the dummy exec functions contained in 'noexec_file'" -noexec_file - T_STR|T_PATH - "File containing dummy exec functions: %s" -ignore_local_sudoers - T_FLAG - "If LDAP directory is up, do we ignore local sudoers file" -closefrom - T_INT - "File descriptors >= %d will be closed before executing a command" -closefrom_override - T_FLAG - "If set, users may override the value of `closefrom' with the -C option" -setenv - T_FLAG - "Allow users to set arbitrary environment variables" -env_reset - T_FLAG - "Reset the environment to a default set of variables" -env_check - T_LIST|T_BOOL - "Environment variables to check for sanity:" -env_delete - T_LIST|T_BOOL - "Environment variables to remove:" -env_keep - T_LIST|T_BOOL - "Environment variables to preserve:" -role - T_STR - "SELinux role to use in the new security context: %s" -type - T_STR - "SELinux type to use in the new security context: %s" -askpass - T_STR|T_PATH|T_BOOL - "Path to the askpass helper program: %s" -env_file - T_STR|T_PATH|T_BOOL - "Path to the sudo-specific environment file: %s" -sudoers_locale - T_STR - "Locale to use while parsing sudoers: %s" -visiblepw - T_FLAG - "Allow sudo to prompt for a password even if it would be visisble" -pwfeedback - T_FLAG - "Provide visual feedback at the password prompt when there is user input" -fast_glob - T_FLAG - "Use faster globbing that is less accurate but does not access the filesystem" -umask_override - T_FLAG - "The umask specified in sudoers will override the user's, even if it is more permissive" -log_input - T_FLAG - "Log user's input for the command being run" -log_output - T_FLAG - "Log the output of the command being run" -compress_io - T_FLAG - "Compress I/O logs using zlib" -use_pty - T_FLAG - "Always run commands in a pseudo-tty" diff --git a/defaults.c b/defaults.c deleted file mode 100644 index 10757ee..0000000 --- a/defaults.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007-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. - */ - -#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 */ -#include -#include - -#include "sudo.h" -#include "parse.h" -#include - -/* - * For converting between syslog numbers and strings. - */ -struct strmap { - char *name; - int num; -}; - -#ifdef LOG_NFACILITIES -static struct strmap facilities[] = { -#ifdef LOG_AUTHPRIV - { "authpriv", LOG_AUTHPRIV }, -#endif - { "auth", LOG_AUTH }, - { "daemon", LOG_DAEMON }, - { "user", LOG_USER }, - { "local0", LOG_LOCAL0 }, - { "local1", LOG_LOCAL1 }, - { "local2", LOG_LOCAL2 }, - { "local3", LOG_LOCAL3 }, - { "local4", LOG_LOCAL4 }, - { "local5", LOG_LOCAL5 }, - { "local6", LOG_LOCAL6 }, - { "local7", LOG_LOCAL7 }, - { NULL, -1 } -}; -#endif /* LOG_NFACILITIES */ - -static struct strmap priorities[] = { - { "alert", LOG_ALERT }, - { "crit", LOG_CRIT }, - { "debug", LOG_DEBUG }, - { "emerg", LOG_EMERG }, - { "err", LOG_ERR }, - { "info", LOG_INFO }, - { "notice", LOG_NOTICE }, - { "warning", LOG_WARNING }, - { NULL, -1 } -}; - -/* - * Local prototypes. - */ -static int store_int __P((char *, struct sudo_defs_types *, int)); -static int store_list __P((char *, struct sudo_defs_types *, int)); -static int store_mode __P((char *, struct sudo_defs_types *, int)); -static int store_str __P((char *, struct sudo_defs_types *, int)); -static int store_syslogfac __P((char *, struct sudo_defs_types *, int)); -static int store_syslogpri __P((char *, struct sudo_defs_types *, int)); -static int store_tuple __P((char *, struct sudo_defs_types *, int)); -static int store_uint __P((char *, struct sudo_defs_types *, int)); -static int store_float __P((char *, struct sudo_defs_types *, int)); -static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops)); -static const char *logfac2str __P((int)); -static const char *logpri2str __P((int)); - -/* - * Table describing compile-time and run-time options. - */ -#include - -/* - * Print version and configure info. - */ -void -dump_defaults() -{ - struct sudo_defs_types *cur; - struct list_member *item; - struct def_values *def; - - for (cur = sudo_defs_table; cur->name; cur++) { - if (cur->desc) { - switch (cur->type & T_MASK) { - case T_FLAG: - if (cur->sd_un.flag) - puts(cur->desc); - break; - case T_STR: - if (cur->sd_un.str) { - (void) printf(cur->desc, cur->sd_un.str); - putchar('\n'); - } - break; - case T_LOGFAC: - if (cur->sd_un.ival) { - (void) printf(cur->desc, logfac2str(cur->sd_un.ival)); - putchar('\n'); - } - break; - case T_LOGPRI: - if (cur->sd_un.ival) { - (void) printf(cur->desc, logpri2str(cur->sd_un.ival)); - putchar('\n'); - } - break; - case T_UINT: - case T_INT: - (void) printf(cur->desc, cur->sd_un.ival); - putchar('\n'); - break; - case T_FLOAT: - (void) printf(cur->desc, cur->sd_un.fval); - putchar('\n'); - break; - case T_MODE: - (void) printf(cur->desc, cur->sd_un.mode); - putchar('\n'); - break; - case T_LIST: - if (cur->sd_un.list) { - puts(cur->desc); - for (item = cur->sd_un.list; item; item = item->next) - printf("\t%s\n", item->value); - } - break; - case T_TUPLE: - for (def = cur->values; def->sval; def++) { - if (cur->sd_un.ival == def->ival) { - (void) printf(cur->desc, def->sval); - break; - } - } - putchar('\n'); - break; - } - } - } -} - -/* - * List each option along with its description. - */ -void -list_options() -{ - struct sudo_defs_types *cur; - char *p; - - (void) puts("Available options in a sudoers ``Defaults'' line:\n"); - for (cur = sudo_defs_table; cur->name; cur++) { - if (cur->name && cur->desc) { - switch (cur->type & T_MASK) { - case T_FLAG: - (void) printf("%s: %s\n", cur->name, cur->desc); - break; - default: - p = strrchr(cur->desc, ':'); - if (p) - (void) printf("%s: %.*s\n", cur->name, - (int) (p - cur->desc), cur->desc); - else - (void) printf("%s: %s\n", cur->name, cur->desc); - break; - } - } - } -} - -/* - * Sets/clears an entry in the defaults structure - * If a variable that takes a value is used in a boolean - * context with op == 0, disable that variable. - * Eg. you may want to turn off logging to a file for some hosts. - * This is only meaningful for variables that are *optional*. - */ -int -set_default(var, val, op) - char *var; - char *val; - int op; /* TRUE or FALSE */ -{ - struct sudo_defs_types *cur; - int num; - - for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) { - if (strcmp(var, cur->name) == 0) - break; - } - if (!cur->name) { - warningx("unknown defaults entry `%s'", var); - return(FALSE); - } - - switch (cur->type & T_MASK) { - case T_LOGFAC: - if (!store_syslogfac(val, cur, op)) { - if (val) - warningx("value `%s' is invalid for option `%s'", val, var); - else - warningx("no value specified for `%s'", var); - return(FALSE); - } - break; - case T_LOGPRI: - if (!store_syslogpri(val, cur, op)) { - if (val) - warningx("value `%s' is invalid for option `%s'", val, var); - else - warningx("no value specified for `%s'", var); - return(FALSE); - } - break; - case T_STR: - if (!val) { - /* Check for bogus boolean usage or lack of a value. */ - if (!ISSET(cur->type, T_BOOL) || op != FALSE) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - } - if (ISSET(cur->type, T_PATH) && val && *val != '/') { - warningx("values for `%s' must start with a '/'", var); - return(FALSE); - } - if (!store_str(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - case T_INT: - if (!val) { - /* Check for bogus boolean usage or lack of a value. */ - if (!ISSET(cur->type, T_BOOL) || op != FALSE) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - } - if (!store_int(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - case T_UINT: - if (!val) { - /* Check for bogus boolean usage or lack of a value. */ - if (!ISSET(cur->type, T_BOOL) || op != FALSE) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - } - if (!store_uint(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - case T_FLOAT: - if (!val) { - /* Check for bogus boolean usage or lack of a value. */ - if (!ISSET(cur->type, T_BOOL) || op != FALSE) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - } - if (!store_float(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - case T_MODE: - if (!val) { - /* Check for bogus boolean usage or lack of a value. */ - if (!ISSET(cur->type, T_BOOL) || op != FALSE) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - } - if (!store_mode(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - case T_FLAG: - if (val) { - warningx("option `%s' does not take a value", var); - return(FALSE); - } - cur->sd_un.flag = op; - break; - case T_LIST: - if (!val) { - /* Check for bogus boolean usage or lack of a value. */ - if (!ISSET(cur->type, T_BOOL) || op != FALSE) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - } - if (!store_list(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - case T_TUPLE: - if (!val && !ISSET(cur->type, T_BOOL)) { - warningx("no value specified for `%s'", var); - return(FALSE); - } - if (!store_tuple(val, cur, op)) { - warningx("value `%s' is invalid for option `%s'", val, var); - return(FALSE); - } - break; - } - - return(TRUE); -} - -/* - * Set default options to compiled-in values. - * Any of these may be overridden at runtime by a "Defaults" file. - */ -void -init_defaults() -{ - static int firsttime = 1; - struct sudo_defs_types *def; - - /* Clear any old settings. */ - if (!firsttime) { - for (def = sudo_defs_table; def->name; def++) { - switch (def->type & T_MASK) { - case T_STR: - efree(def->sd_un.str); - def->sd_un.str = NULL; - break; - case T_LIST: - list_op(NULL, 0, def, freeall); - break; - } - zero_bytes(&def->sd_un, sizeof(def->sd_un)); - } - } - - /* First initialize the flags. */ -#ifdef LONG_OTP_PROMPT - def_long_otp_prompt = TRUE; -#endif -#ifdef IGNORE_DOT_PATH - def_ignore_dot = TRUE; -#endif -#ifdef ALWAYS_SEND_MAIL - def_mail_always = TRUE; -#endif -#ifdef SEND_MAIL_WHEN_NO_USER - def_mail_no_user = TRUE; -#endif -#ifdef SEND_MAIL_WHEN_NO_HOST - def_mail_no_host = TRUE; -#endif -#ifdef SEND_MAIL_WHEN_NOT_OK - def_mail_no_perms = TRUE; -#endif -#ifndef NO_TTY_TICKETS - def_tty_tickets = TRUE; -#endif -#ifndef NO_LECTURE - def_lecture = once; -#endif -#ifndef NO_AUTHENTICATION - def_authenticate = TRUE; -#endif -#ifndef NO_ROOT_SUDO - def_root_sudo = TRUE; -#endif -#ifdef HOST_IN_LOG - def_log_host = TRUE; -#endif -#ifdef SHELL_IF_NO_ARGS - def_shell_noargs = TRUE; -#endif -#ifdef SHELL_SETS_HOME - def_set_home = TRUE; -#endif -#ifndef DONT_LEAK_PATH_INFO - def_path_info = TRUE; -#endif -#ifdef FQDN - def_fqdn = TRUE; -#endif -#ifdef USE_INSULTS - def_insults = TRUE; -#endif -#ifdef ENV_EDITOR - def_env_editor = TRUE; -#endif -#ifdef _PATH_SUDO_ASKPASS - def_askpass = estrdup(_PATH_SUDO_ASKPASS); -#endif - def_sudoers_locale = estrdup("C"); - def_env_reset = TRUE; - def_set_logname = TRUE; - def_closefrom = STDERR_FILENO + 1; - - /* Syslog options need special care since they both strings and ints */ -#if (LOGGING & SLOG_SYSLOG) - (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE); - (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI], - TRUE); - (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI], - TRUE); -#endif - - /* Password flags also have a string and integer component. */ - (void) store_tuple("any", &sudo_defs_table[I_LISTPW], TRUE); - (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], TRUE); - - /* Then initialize the int-like things. */ -#ifdef SUDO_UMASK - def_umask = SUDO_UMASK; -#else - def_umask = 0777; -#endif - def_loglinelen = MAXLOGFILELEN; - def_timestamp_timeout = TIMEOUT; - def_passwd_timeout = PASSWORD_TIMEOUT; - def_passwd_tries = TRIES_FOR_PASSWORD; -#ifdef HAVE_ZLIB_H - def_compress_io = TRUE; -#endif - - /* Now do the strings */ - def_mailto = estrdup(MAILTO); - def_mailsub = estrdup(MAILSUBJECT); - def_badpass_message = estrdup(INCORRECT_PASSWORD); - def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR); - def_passprompt = estrdup(PASSPROMPT); - def_runas_default = estrdup(RUNAS_DEFAULT); -#ifdef _PATH_SUDO_SENDMAIL - def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL); - def_mailerflags = estrdup("-t"); -#endif -#if (LOGGING & SLOG_FILE) - def_logfile = estrdup(_PATH_SUDO_LOGFILE); -#endif -#ifdef EXEMPTGROUP - def_exempt_group = estrdup(EXEMPTGROUP); -#endif -#ifdef SECURE_PATH - def_secure_path = estrdup(SECURE_PATH); -#endif - def_editor = estrdup(EDITOR); -#ifdef _PATH_SUDO_NOEXEC - def_noexec_file = estrdup(_PATH_SUDO_NOEXEC); -#endif - - /* Finally do the lists (currently just environment tables). */ - init_envtables(); - - firsttime = 0; -} - -/* - * Update the defaults based on what was set by sudoers. - * Pass in an OR'd list of which default types to update. - */ -int -update_defaults(what) - int what; -{ - struct defaults *def; - int rc = TRUE; - - tq_foreach_fwd(&defaults, def) { - switch (def->type) { - case DEFAULTS: - if (ISSET(what, SETDEF_GENERIC) && - !set_default(def->var, def->val, def->op)) - rc = FALSE; - break; - case DEFAULTS_USER: - if (ISSET(what, SETDEF_USER) && - userlist_matches(sudo_user.pw, &def->binding) == ALLOW && - !set_default(def->var, def->val, def->op)) - rc = FALSE; - break; - case DEFAULTS_RUNAS: - if (ISSET(what, SETDEF_RUNAS) && - runaslist_matches(&def->binding, NULL) == ALLOW && - !set_default(def->var, def->val, def->op)) - rc = FALSE; - break; - case DEFAULTS_HOST: - if (ISSET(what, SETDEF_HOST) && - hostlist_matches(&def->binding) == ALLOW && - !set_default(def->var, def->val, def->op)) - rc = FALSE; - break; - case DEFAULTS_CMND: - if (ISSET(what, SETDEF_CMND) && - cmndlist_matches(&def->binding) == ALLOW && - !set_default(def->var, def->val, def->op)) - rc = FALSE; - break; - } - } - return(rc); -} - -static int -store_int(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - char *endp; - long l; - - if (op == FALSE) { - def->sd_un.ival = 0; - } else { - l = strtol(val, &endp, 10); - if (*endp != '\0') - return(FALSE); - /* XXX - should check against INT_MAX */ - def->sd_un.ival = (int)l; - } - if (def->callback) - return(def->callback(val)); - return(TRUE); -} - -static int -store_uint(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - char *endp; - long l; - - if (op == FALSE) { - def->sd_un.ival = 0; - } else { - l = strtol(val, &endp, 10); - if (*endp != '\0' || l < 0) - return(FALSE); - /* XXX - should check against INT_MAX */ - def->sd_un.ival = (unsigned int)l; - } - if (def->callback) - return(def->callback(val)); - return(TRUE); -} - -static int -store_float(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - char *endp; - double d; - - if (op == FALSE) { - def->sd_un.fval = 0.0; - } else { - d = strtod(val, &endp); - if (*endp != '\0') - return(FALSE); - /* XXX - should check against HUGE_VAL */ - def->sd_un.fval = d; - } - if (def->callback) - return(def->callback(val)); - return(TRUE); -} - -static int -store_tuple(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - struct def_values *v; - - /* - * Since enums are really just ints we store the value as an ival. - * In the future, there may be multiple enums for different tuple - * types we want to avoid and special knowledge of the tuple type. - * This does assume that the first entry in the tuple enum will - * be the equivalent to a boolean "false". - */ - if (!val) { - def->sd_un.ival = (op == FALSE) ? 0 : 1; - } else { - for (v = def->values; v->sval != NULL; v++) { - if (strcmp(v->sval, val) == 0) { - def->sd_un.ival = v->ival; - break; - } - } - if (v->sval == NULL) - return(FALSE); - } - if (def->callback) - return(def->callback(val)); - return(TRUE); -} - -static int -store_str(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - - efree(def->sd_un.str); - if (op == FALSE) - def->sd_un.str = NULL; - else - def->sd_un.str = estrdup(val); - if (def->callback) - return(def->callback(val)); - return(TRUE); -} - -static int -store_list(str, def, op) - char *str; - struct sudo_defs_types *def; - int op; -{ - char *start, *end; - - /* Remove all old members. */ - if (op == FALSE || op == TRUE) - list_op(NULL, 0, def, freeall); - - /* Split str into multiple space-separated words and act on each one. */ - if (op != FALSE) { - end = str; - do { - /* Remove leading blanks, if nothing but blanks we are done. */ - for (start = end; isblank(*start); start++) - ; - if (*start == '\0') - break; - - /* Find end position and perform operation. */ - for (end = start; *end && !isblank(*end); end++) - ; - list_op(start, end - start, def, op == '-' ? delete : add); - } while (*end++ != '\0'); - } - return(TRUE); -} - -static int -store_syslogfac(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - struct strmap *fac; - - if (op == FALSE) { - def->sd_un.ival = FALSE; - return(TRUE); - } -#ifdef LOG_NFACILITIES - if (!val) - return(FALSE); - for (fac = facilities; fac->name && strcmp(val, fac->name); fac++) - ; - if (fac->name == NULL) - return(FALSE); /* not found */ - - def->sd_un.ival = fac->num; -#else - def->sd_un.ival = -1; -#endif /* LOG_NFACILITIES */ - return(TRUE); -} - -static const char * -logfac2str(n) - int n; -{ -#ifdef LOG_NFACILITIES - struct strmap *fac; - - for (fac = facilities; fac->name && fac->num != n; fac++) - ; - return(fac->name); -#else - return("default"); -#endif /* LOG_NFACILITIES */ -} - -static int -store_syslogpri(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - struct strmap *pri; - - if (op == FALSE || !val) - return(FALSE); - - for (pri = priorities; pri->name && strcmp(val, pri->name); pri++) - ; - if (pri->name == NULL) - return(FALSE); /* not found */ - - def->sd_un.ival = pri->num; - return(TRUE); -} - -static const char * -logpri2str(n) - int n; -{ - struct strmap *pri; - - for (pri = priorities; pri->name && pri->num != n; pri++) - ; - return(pri->name); -} - -static int -store_mode(val, def, op) - char *val; - struct sudo_defs_types *def; - int op; -{ - char *endp; - long l; - - if (op == FALSE) { - def->sd_un.mode = (mode_t)0777; - } else { - l = strtol(val, &endp, 8); - if (*endp != '\0' || l < 0 || l > 0777) - return(FALSE); - def->sd_un.mode = (mode_t)l; - } - if (def->callback) - return(def->callback(val)); - return(TRUE); -} - -static void -list_op(val, len, def, op) - char *val; - size_t len; - struct sudo_defs_types *def; - enum list_ops op; -{ - struct list_member *cur, *prev, *tmp; - - if (op == freeall) { - for (cur = def->sd_un.list; cur; ) { - tmp = cur; - cur = tmp->next; - efree(tmp->value); - efree(tmp); - } - def->sd_un.list = NULL; - return; - } - - for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) { - if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) { - - if (op == add) - return; /* already exists */ - - /* Delete node */ - if (prev != NULL) - prev->next = cur->next; - else - def->sd_un.list = cur->next; - efree(cur->value); - efree(cur); - break; - } - } - - /* Add new node to the head of the list. */ - if (op == add) { - cur = emalloc(sizeof(struct list_member)); - cur->value = emalloc(len + 1); - (void) memcpy(cur->value, val, len); - cur->value[len] = '\0'; - cur->next = def->sd_un.list; - def->sd_un.list = cur; - } -} diff --git a/defaults.h b/defaults.h deleted file mode 100644 index eb2188a..0000000 --- a/defaults.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 1999-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_DEFAULTS_H -#define _SUDO_DEFAULTS_H - -#include - -struct list_member { - char *value; - struct list_member *next; -}; - -struct def_values { - char *sval; /* string value */ - int ival; /* actually an enum */ -}; - -enum list_ops { - add, - delete, - freeall -}; - -/* - * Structure describing compile-time and run-time options. - */ -struct sudo_defs_types { - char *name; - int type; - char *desc; - struct def_values *values; - int (*callback) __P((char *)); - union { - int flag; - int ival; - double fval; - enum def_tupple tuple; - char *str; - mode_t mode; - struct list_member *list; - } sd_un; -}; - -/* - * Four types of defaults: strings, integers, and flags. - * Also, T_INT, T_FLOAT or T_STR may be ANDed with T_BOOL to indicate that - * a value is not required. Flags are boolean by nature... - */ -#undef T_INT -#define T_INT 0x001 -#undef T_UINT -#define T_UINT 0x002 -#undef T_STR -#define T_STR 0x003 -#undef T_FLAG -#define T_FLAG 0x004 -#undef T_MODE -#define T_MODE 0x005 -#undef T_LIST -#define T_LIST 0x006 -#undef T_LOGFAC -#define T_LOGFAC 0x007 -#undef T_LOGPRI -#define T_LOGPRI 0x008 -#undef T_TUPLE -#define T_TUPLE 0x009 -#undef T_FLOAT -#define T_FLOAT 0x010 -#undef T_MASK -#define T_MASK 0x0FF -#undef T_BOOL -#define T_BOOL 0x100 -#undef T_PATH -#define T_PATH 0x200 - -/* - * Argument to update_defaults() - */ -#define SETDEF_GENERIC 0x01 -#define SETDEF_HOST 0x02 -#define SETDEF_USER 0x04 -#define SETDEF_RUNAS 0x08 -#define SETDEF_CMND 0x10 -#define SETDEF_ALL (SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS|SETDEF_CMND) - -/* - * Prototypes - */ -int set_default __P((char *, char *, int)); -int update_defaults __P((int)); -void dump_default __P((void)); -void dump_defaults __P((void)); -void init_defaults __P((void)); -void list_options __P((void)); - -extern struct sudo_defs_types sudo_defs_table[]; - -#endif /* _SUDO_DEFAULTS_H */ diff --git a/doc/CONTRIBUTORS b/doc/CONTRIBUTORS new file mode 100644 index 0000000..65ff327 --- /dev/null +++ b/doc/CONTRIBUTORS @@ -0,0 +1,165 @@ +The following list of people, sorted by last name, have contributed +code or patches to this implementation of sudo since I began +maintaining it in 1993. This list is known to be incomplete--if +you believe you should be listed, please send a note to sudo@sudo.ws. + + Matt Ackeret + Mark Adler + Russ Allbery + Nick Andrew + Dimitry Andric + Danny Barron + Tom Bates + Zdenek Behan + Ray Bellis + Elias Benali + Jamie Beverly + Spider Boardman + Jakub Bogusz + P.J. Bostley + Keith Bowes + Keith Garry Boyce + Michael Brantley + Rob Braun + Piete Brooks + Jerry Brown + Michael E Burr + Andreas Bussjaeger + Gary Calvin + Aaron Campbell + Milo Casagrande + Yuri Chornoivan + Vitezslav Cizek + Chris Coleman + Deven T. Corzine + Frank Cusack + Theo de Raadt + Francisco Dieguez + David Dill + Theo Van Dinter + Jeff Earickson + Drew Eckhardt + Ben Edgington + Marc Esipovich + Marc Espie + Ariel Faigon + Brian Farrell + Steve Fobes + Mike Frysinger + Jean-loup Gailly + Simon J. Gerraty + B. Guillory + Joe Hansen + Randy M. Hayman + Joachim Henke + YOSHIFUJI Hideaki + Dave Hieb + Nick Holloway + Adam Hoover + Michael T. Hunter + Eric Irrgang + Brian Jackson + Richard L. Jackson Jr + John R. Jackson + Mark Janssen + Chris Jepeway + Timo Juhani + Ayamura KIKUCHI + Kevin Kadow + Jorma Karvonen + Stepan Kasal + Mike Kienenberger + Dale King + Jim Knoble + Tim Knox + Alek O. Komarnitsky + Daniel Kopecek + Yuri Kozlov + Jakob Kramer + Paul Kranenburg + David Krause + Tomislav Krznar + Eric Lakin + Case Larsen + Dmitry V. Levin + Kendall Libby + Phillip E. Lobbes + Jason McIntyre + David J. MacKenzie + Tom McLaughlin + Jeff Makey + Michael D. Marchionna + Algimantas Margevicius + Paul Markham + Emin Martinian + Pavel Maryanov + Michael Meskes + Todd C. Miller + Loic Minier + Jan Thomas Moldung + Charles Morris + Andreas Mueller + Dworkin Muller + Jeff Nieusma + Peter A. Nikitser + Miroslav Nikolic + Ludwig Nussel + Daniel Nylander + Eric Paquet + Chantal Paradis + Ted Percival + Christian S.J. Peron + Alexander Peslyak + Toby Peterson + Diego Elio Petteno + Joel Pickett + Alex Plotnick + Tran Ngoc Quan + Gudleik Rasch + Matt Richards + Guido van Rossum + John P. Rouillard + William A. Rowe Jr. + Alain Roy + Elan Ruusamae + Eygene Ryabinkin + Yuichi SATO + Wilfredo Sanchez + Jean-Francois Saucier + Patrick Schoenfeld + Arno Schuring + Dougal Scott + Abel Sendón + Nick Sieger + Thor Lancelot Simon + Marc Slemko + Andy Smith + Igor Sobrado + Aaron Spangler + Cloyce D. Spradling + Matthew Stier + Tobias Stoeckmann + Russell Street + Tilo Stritzky + Michael Stroucken + Yasuaki Taniguchi + Robert Tarrall + Matthew Thomas + Giles Todd + Martin Toft + Chris Torek + Darren Tucker + Robert Uhl + Mikel Olasagasti Uranga + Petr Uzel + Reznic Valery + Martynas Venckus + Klaus Wagner + Dan Walsh + Wylmer Wang + John Warburton + Kirk Webb + Timm Wetzel + Marco van Wieringen + David Wood + Gustavo Zacarias diff --git a/doc/HISTORY b/doc/HISTORY new file mode 100644 index 0000000..b265144 --- /dev/null +++ b/doc/HISTORY @@ -0,0 +1,74 @@ +A Brief History of Sudo: + +The Early Years + +Sudo was first conceived and implemented by Bob Coggeshall and Cliff Spencer +around 1980 at the Department of Computer Science at SUNY/Buffalo. It ran on +a VAX-11/750 running 4.1BSD. An updated version, credited to Phil Betchel, +Cliff Spencer, Gretchen Phillips, John LoVerso and Don Gworek, was posted to +the net.sources Usenet newsgroup in December of 1985. + +Sudo at CU-Boulder + +In the Summer of 1986, Garth Snyder released an enhanced version of sudo. +For the next 5 years, sudo was fed and watered by a handful of folks at +CU-Boulder, including Bob Coggeshall, Bob Manchek, and Trent Hein. + +Root Group Sudo + +In 1991, Dave Hieb and Jeff Nieusma wrote a new version of sudo with an +enhanced sudoers format under contract to a consulting firm called "The Root +Group". This version was later released under the GNU public license. + +CU Sudo + +In 1994, after maintaining sudo informally within CU-Boulder for some time, +Todd C. Miller made a public release of "CU sudo" (version 1.3) with bug +fixes and support for more operating systems. The "CU" was added to +differentiate it from the "official" version from "The Root Group". + +In 1995, a new parser for the sudoers file was contributed by Chris Jepeway. +The new parser was a proper grammar (unlike the old one) and could work with +both sudo and visudo (previously they had slightly different parsers). + +In 1996, Todd, who had been maintaining sudo for several years in his spare +time, moved distribution of sudo from a CU-Boulder ftp site to his domain, +courtesan.com. + +Just Plain Sudo + +In 1999, the "CU" prefix was dropped from the name since there had been no +formal release of sudo from "The Root Group" since 1991 (the original +authors now work elsewhere). As of version 1.6, Sudo no longer contains any +of the original "Root Group" code and is available under an ISC-style +license. + +In 2001, the sudo web site, ftp site and mailing lists were moved from +courtesan.com to the sudo.ws domain (sudo.org was already taken). + +LDAP Integration + +In 2003, Nationwide Mutual Insurance Company contributed code written by +Aaron Spangler to store the sudoers data in LDAP. These changes were +incorporated into Sudo 1.6.8. + +New Parser + +In 2005, Todd rewrote the sudoers parser to better support the features that +had been added in the past ten years. This new parser removes some +limitations of the previous one, removes ordering constraints and adds +support for including multiple sudoers files. + +Quest Sponsorship + +In 2010, Quest Software began sponsoring Sudo development by hiring Todd to +work on Sudo as part of his full-time job. + +Present Day + +Sudo, in its current form, is maintained by: + + Todd C. Miller + +Todd continues to enhance sudo and fix bugs. + diff --git a/doc/LICENSE b/doc/LICENSE new file mode 100644 index 0000000..962d959 --- /dev/null +++ b/doc/LICENSE @@ -0,0 +1,121 @@ +Sudo is distributed under the following license: + + Copyright (c) 1994-1996, 1998-2012 + 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. + +The file redblack.c bears the following license: + + Copyright (c) 2001 Emin Martinian + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that neither the name of Emin + Martinian nor the names of any contributors are be used to endorse or + promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The files getcwd.c, glob.c, glob.h and snprintf.c bear the following license: + + Copyright (c) 1989, 1990, 1991, 1993 + The Regents of the University of California. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +The file fnmatch.c bears the following license: + + Copyright (c) 2011, VMware, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the VMware, Inc. nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The embedded copy of zlib bears the following license: + + Copyright (C) 1995-2012 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/doc/Makefile.in b/doc/Makefile.in new file mode 100644 index 0000000..e334fba --- /dev/null +++ b/doc/Makefile.in @@ -0,0 +1,274 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +docdir = @docdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Tools to use +NROFF = @NROFFPROG@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ + +# Directory in which to install the man page +mantype = @MANTYPE@ +mansectsu = @mansectsu@ +mansectform = @mansectform@ +mandirsu = $(mandir)/$(mantype)$(mansectsu) +mandirform = $(mandir)/$(mantype)$(mansectform) + +# User and group ids the installed files should be "owned" by +install_uid = 0 +install_gid = 0 + +# Set to non-empty for development mode +DEVEL = @DEVEL@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +DOCS = sudo.man visudo.man sudoers.man sudoers.ldap.man sudoers.man \ + sudoreplay.man sudo_plugin.man + +DEVDOCS = $(srcdir)/sudo.man.in $(srcdir)/sudo.cat \ + $(srcdir)/visudo.man.in $(srcdir)/visudo.cat \ + $(srcdir)/sudoers.man.in $(srcdir)/sudoers.cat \ + $(srcdir)/sudoers.ldap.man.in $(srcdir)/sudoers.ldap.cat \ + $(srcdir)/sudoers.man.in $(srcdir)/sudoers.cat \ + $(srcdir)/sudoreplay.man.in $(srcdir)/sudoreplay.cat \ + $(srcdir)/sudo_plugin.man.in $(srcdir)/sudo_plugin.cat \ + $(srcdir)/HISTORY $(srcdir)/LICENSE $(srcdir)/CONTRIBUTORS + +OTHER_DOCS = $(top_srcdir)/ChangeLog $(top_srcdir)/README \ + $(top_srcdir)/NEWS $(srcdir)/HISTORY $(srcdir)/CONTRIBUTORS \ + $(srcdir)/LICENSE $(srcdir)/TROUBLESHOOTING $(srcdir)/UPGRADE \ + $(srcdir)/sample.* + +OTHER_DOCS_LDAP = $(top_srcdir)/README.LDAP $(srcdir)/schema.* + +VERSION = @PACKAGE_VERSION@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ + +all: $(DEVDOCS) $(DOCS) + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file doc/Makefile) + +.SUFFIXES: .man + +varsub: $(top_srcdir)/configure.in + @if [ -n "$(DEVEL)" ]; then \ + printf 's#@%s@#1#\ns#@%s@#1#\ns#@%s@#1#\ns#@%s@#/etc#g\ns#@%s@#/usr/local#g\ns#@%s@#4#g\ns#@%s@#1m#g\n' SEMAN BAMAN LCMAN sysconfdir prefix mansectform mansectsu > $@; \ + sed -n '/Begin initial values for man page substitution/,/End initial values for man page substitution/{;p;}' $(top_srcdir)/configure.in | sed -e '/^#/d' -e 's/^/s#@/' -e 's/=[\\"]*/@#/' -e 's/[\\"]*$$/#g/' >> $@; \ + fi + +$(srcdir)/sudo.man.in: $(srcdir)/sudo.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; \ + mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; \ + sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudo.pod > $@; \ + pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudo.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" | perl -p $(srcdir)/sudo.man.pl >> $@; \ + fi + +sudo.man: $(srcdir)/sudo.man.in + (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@) + +$(srcdir)/sudo.cat: varsub $(srcdir)/sudo.man.in + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + sed -f varsub $(srcdir)/sudo.man.in | $(NROFF) -man > $@; \ + fi + +$(srcdir)/visudo.man.in: $(srcdir)/visudo.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; \ + mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; \ + sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/visudo.pod > $@; \ + pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/visudo.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@; \ + fi + +visudo.man: $(srcdir)/visudo.man.in + (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@) + +$(srcdir)/visudo.cat: varsub $(srcdir)/visudo.man.in + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + sed -f varsub $(srcdir)/visudo.man.in | $(NROFF) -man > $@; \ + fi + +$(srcdir)/sudoers.man.in: $(srcdir)/sudoers.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; \ + mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; \ + sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.pod > $@; \ + pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" | perl -p $(srcdir)/sudoers.man.pl >> $@; \ + fi + +sudoers.man: $(srcdir)/sudoers.man.in + (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@) + +$(srcdir)/sudoers.cat: varsub $(srcdir)/sudoers.man.in + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + sed -f varsub $(srcdir)/sudoers.man.in | $(NROFF) -man > $@; \ + fi + +$(srcdir)/sudoers.ldap.man.in: $(srcdir)/sudoers.ldap.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; \ + mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; \ + sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoers.ldap.pod > $@; \ + pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectform --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoers.ldap.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@; \ + fi + +sudoers.ldap.man: $(srcdir)/sudoers.ldap.man.in + (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@) + +$(srcdir)/sudoers.ldap.cat: varsub $(srcdir)/sudoers.ldap.man.in + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + sed -f varsub $(srcdir)/sudoers.ldap.man.in | $(NROFF) -man > $@; \ + fi + +$(srcdir)/sudoreplay.man.in: $(srcdir)/sudoreplay.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; \ + mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; \ + sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudoreplay.pod > $@; \ + pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudoreplay.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@; \ + fi + +sudoreplay.man: $(srcdir)/sudoreplay.man.in + (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@) + +$(srcdir)/sudoreplay.cat: varsub $(srcdir)/sudoreplay.man.in + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + sed -f varsub $(srcdir)/sudoreplay.man.in | $(NROFF) -man > $@; \ + fi + +$(srcdir)/sudo_plugin.man.in: $(srcdir)/sudo_plugin.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + mansectsu=`echo @MANSECTSU@|tr A-Z a-z`; \ + mansectform=`echo @MANSECTFORM@|tr A-Z a-z`; \ + sed -n -e '/^=pod/q' -e 's/^/.\\" /p' $(srcdir)/sudo_plugin.pod > $@; \ + pod2man --quotes=none --date="`date '+%B %e, %Y'`" --section=$$mansectsu --release=$(VERSION) --center="MAINTENANCE COMMANDS" $(srcdir)/sudo_plugin.pod | sed -e "s/(5)/($$mansectform)/g" -e "s/(8)/($$mansectsu)/g" -e 's|\\fI\\f\((CW*\)*I@\([^@]*\)\\fI@|\\fI@\2@|g' >> $@; \ + fi + +sudo_plugin.man: $(srcdir)/sudo_plugin.man.in + (cd $(top_builddir) && $(SHELL) config.status --file=doc/$@) + +$(srcdir)/sudo_plugin.cat: varsub $(srcdir)/sudo_plugin.man.in + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + sed -f varsub $(srcdir)/sudo_plugin.man.in | $(NROFF) -man > $@; \ + fi + +CONTRIBUTORS: $(srcdir)/contributors.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + pod2text -l -i0 $(srcdir)/contributors.pod | sed '1,3d' > $@; \ + fi + +HISTORY: $(srcdir)/history.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + pod2text -l -i0 $(srcdir)/history.pod > $@; \ + fi + +LICENSE: $(srcdir)/license.pod + @if [ -n "$(DEVEL)" ]; then \ + echo "Generating $@"; \ + pod2text -l -i0 $(srcdir)/license.pod | sed '1,3d' > $@; \ + fi + +pre-install: + +install: install-doc + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(docdir) \ + $(DESTDIR)$(mandirsu) $(DESTDIR)$(mandirform) + +install-binaries: + +install-includes: + +install-doc: install-dirs + for f in $(OTHER_DOCS); do $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 $$f $(DESTDIR)$(docdir); done + @LDAP@for f in $(OTHER_DOCS_LDAP); do $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 $$f $(DESTDIR)$(docdir); done + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 @mansrcdir@/sudo.$(mantype) $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) + @rm -f $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) + ln $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 @mansrcdir@/sudo_plugin.$(mantype) $(DESTDIR)$(mandirsu)/sudo_plugin.$(mansectsu) + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 @mansrcdir@/sudoreplay.$(mantype) $(DESTDIR)$(mandirsu)/sudoreplay.$(mansectsu) + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 @mansrcdir@/visudo.$(mantype) $(DESTDIR)$(mandirsu)/visudo.$(mansectsu) + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 @mansrcdir@/sudoers.$(mantype) $(DESTDIR)$(mandirform)/sudoers.$(mansectform) + @LDAP@$(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 @mansrcdir@/sudoers.ldap.$(mantype) $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform) +@MAN_POSTINSTALL@ + +install-plugin: + +uninstall: + -rm -rf $(DESTDIR)$(docdir) + -rm -f $(DESTDIR)$(mandirsu)/sudo.$(mansectsu) \ + $(DESTDIR)$(mandirsu)/sudoedit.$(mansectsu) \ + $(DESTDIR)$(mandirsu)/sudo_plugin.$(mansectsu) \ + $(DESTDIR)$(mandirsu)/sudoreplay.$(mansectsu) \ + $(DESTDIR)$(mandirsu)/visudo.$(mansectsu) \ + $(DESTDIR)$(mandirform)/sudoers.$(mansectform) \ + $(DESTDIR)$(mandirform)/sudoers.ldap.$(mansectform) + +check: + +clean: + -rm -f varsub + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile config.log *.man + +clobber: distclean + +realclean: distclean + +cleandir: distclean diff --git a/doc/TROUBLESHOOTING b/doc/TROUBLESHOOTING new file mode 100644 index 0000000..ecd9854 --- /dev/null +++ b/doc/TROUBLESHOOTING @@ -0,0 +1,265 @@ +Troubleshooting tips and FAQ for Sudo +===================================== + +Q) When I run configure, it says "C compiler cannot create executables". +A) This usually means you either don't have a working compiler. This + could be due to the lack of a license or that some component of the + compiler suite could not be found. Check config.log for clues as + to why this is happening. On many systems, compiler components live + in /usr/ccs/bin which may not be in your PATH environment variable. + +Q) When I run configure, it says "sudo requires the 'ar' utility to build". +A) As part of the build process, sudo creates a temporary library containing + objects that are shared amongst the different sudo executables. + On Unix systems, the "ar" utility is used to do this. This error + indicates that "ar" is missing on your system. On Solaris systems, + you may need to install the SUNWbtool package. On other systems + "ar" may be included in the GNU binutils package. + +Q) Sudo compiles and installs OK but when I try to run it I get: + /usr/local/bin/sudo must be owned by uid 0 and have the setuid bit set +A) Sudo must be setuid root to do its work. Either /usr/local/bin/sudo + is not owned by uid 0 or the setuid bit is not set. This should have + been done for you by "make install" but you can fix it manually by + running the following as root: + # chown root /usr/local/bin/sudo; chmod 4111 /usr/local/bin/sudo + +Q) Sudo compiles and installs OK but when I try to run it I get: + effective uid is not 0, is /usr/local/bin/sudo on a file system with the + 'nosuid' option set or an NFS file system without root privileges? +A) The owner and permissions on the sudo binary appear to be OK but when + sudo ran, the setuid bit did not have an effect. There are two common + causes for this. The first is that the file system the sudo binary + is located on is mounted with the 'nosuid' mount option, which disables + setuid binaries. The other is that sudo is installed on an NFS-mounted + file system that is exported without root privileges. By default, NFS + file systems are exported with uid 0 mapped to a non-privileged uid + (usually -2). + +You need to do something like + `chmod 4111 /usr/local/bin/sudo'. Also, the file system sudo resides + on must *not* be mounted (or exported) with the nosuid option or sudo + will not be able to work. Another possibility is you may have '.' in + your $PATH before the directory containing sudo. If you are going + to have '.' in your path you should make sure it is at the end. + +Q) Sudo never gives me a chance to enter a password using PAM, it just + says 'Sorry, try again.' three times and exits. +A) You didn't setup PAM to work with sudo. On RedHat Linux or Fedora + Core this generally means installing sample.pam as /etc/pam.d/sudo. + See the sample.pam file for hints on what to use for other Linux + systems. + +Q) Sudo says 'Account expired or PAM config lacks an "account" + section for sudo, contact your system administrator' and exits + but I know my account has not expired. +A) Your PAM config lacks an "account" specification. On Linux this + usually means you are missing a line like: + account required pam_unix.so + in /etc/pam.d/sudo. + +Q) Sudo is setup to log via syslog(3) but I'm not getting any log + messages. +A) Make sure you have an entry in your syslog.conf file to save + the sudo messages (see the sample.syslog.conf file). The default + log facility is authpriv (changeable via configure or in sudoers). + Don't forget to send a SIGHUP to your syslogd so that it re-reads + its conf file. Also, remember that syslogd does *not* create + log files, you need to create the file before syslogd will log + to it (ie: touch /var/log/sudo). + Note: the facility (e.g. "auth.debug") must be separated from the + destination (e.g. "/var/log/auth" or "@loghost") by + tabs, *not* spaces. This is a common error. + +Q) When sudo asks me for my password it never accepts what I enter even + though I know I entered my password correctly. +A) If you are not using pam and your system uses shadow passwords, + it is possible that sudo didn't properly detect that shadow + passwords are in use. Take a look at the generated config.h + file and verify that the C function used for shadow password + look ups was detected. For instance, for SVR4-style shadow + passwords, HAVE_GETSPNAM should be defined (you can search for + the string "shadow passwords" in config.h with your editor). + Note that there is no define for 4.4BSD-based shadow passwords + since that just uses the standard getpw* routines. + +Q) Can sudo use the ssh agent for authentication instead of asking + for the user's Unix password? +A) Not directly, but you can use a PAM module like pam_ssh_agent_auth + or pam_ssh for this purpose. + +Q) I don't want the sudoers file in /etc, how can I specify where it + should go? +A) Use the --sysconfdir option to configure. Ie: + configure --sysconfdir=/dir/you/want/sudoers/in + +Q) Can I put the sudoers file in NIS/NIS+ or do I have to have a + copy on each machine? +A) There is no support for making an NIS/NIS+ map/table out of + the sudoers file at this time. You can distribute the sudoers + file via rsync or rdist. It is also possible to NFS-mount the + sudoers file. If you use LDAP at your site you may be interested + in sudo's LDAP sudoers support, see the README.LDAP file and the + sudoers.ldap manual. + +Q) I don't run sendmail on my machine. Does this mean that I cannot + use sudo? +A) No, you just need to disable mailing with a line like: + Defaults !mailerpath + in your sudoers file or run configure with the --without-sendmail + option. + +Q) When I run visudo it uses vi as the editor and I hate vi. How + can I make it use another editor? +A) You can specify the editor to use in visudo in the sudoers file. + See the "editor" and "env_editor" entries in the sudoers manual. + The defaults can also be set at configure time using the + --with-editor and --with-env-editor configure options. + +Q) Sudo appears to be removing some variables from my environment, why? +A) Sudo removes the following "dangerous" environment variables + to guard against shared library spoofing, shell voodoo, and + kerberos server spoofing. + IFS + LOCALDOMAIN + RES_OPTIONS + HOSTALIASES + NLSPATH + PATH_LOCALE + TERMINFO + TERMINFO_DIRS + TERMPATH + TERMCAP + ENV + BASH_ENV + LC_ (if it contains a '/' or '%') + LANG (if it contains a '/' or '%') + LANGUAGE (if it contains a '/' or '%') + LD_* + _RLD_* + SHLIB_PATH (HP-UX only) + LIBPATH (AIX only) + KRB5_CONFIG (kerb5 only) + VAR_ACE (SecurID only) + USR_ACE (SecurID only) + DLC_ACE (SecurID only) + +Q) How can I keep sudo from asking for a password? +A) To specify this on a per-user (and per-command) basis, use the + 'NOPASSWD' tag right before the command list in sudoers. See + the sudoers man page and sample.sudoers for details. To disable + passwords completely, add !authenticate" to the Defaults line + in /etc/sudoers. You can also turn off authentication on a + per-user or per-host basis using a user or host-specific Defaults + entry in sudoers. To hard-code the global default, you can + configure with the --without-passwd option. + +Q) When I run configure, it dies with the following error: + "no acceptable cc found in $PATH". +A) /usr/ucb/cc was the only C compiler that configure could find. + You need to tell configure the path to the "real" C compiler + via the --with-CC option. On Solaris, the path is probably + something like "/opt/SUNWspro/SC4.0/bin/cc". If you have gcc + that will also work. + +Q) When I run configure, it dies with the following error: + Fatal Error: config.cache exists from another platform! + Please remove it and re-run configure. +A) configure caches the results of its tests in a file called + config.cache to make re-running configure speedy. However, + if you are building sudo for a different platform the results + in config.cache will be wrong so you need to remove config.cache. + You can do this by "rm config.cache" or "make realclean". + Note that "make realclean" will also remove any object files + and configure temp files that are laying around as well. + +Q) I built sudo on a Solaris >= 2.6 machine but the resulting binary + doesn't work on Solaris <= 2.5.1. Why? +A) Starting with Solaris 2.6, snprintf(3) is included in the standard + C library. To build a version of sudo on a >= 2.6 machine that + will run on a <= 2.5.1 machine, edit config.h and comment out the lines: + #define HAVE_SNPRINTF 1 + #define HAVE_VSNPRINTF 1 + and run make. + +Q) When I run "visudo" it says "sudoers file busy, try again later." + and doesn't do anything. +A) Someone else is currently editing the sudoers file with visudo. + +Q) When I try to use "cd" with sudo it says "cd: command not found". +A) "cd" is a shell built-in command, you can't run it as a command + since a child process (sudo) cannot affect the current working + directory of the parent (your shell). + +Q) When I try to use "cd" with sudo the command completes without + errors but nothing happens. +A) Even though "cd" is a shell built-in command, some operating systems + include a /usr/bin/cd command for some reason. A standalone + "cd" command is totally useless since a child process (cd) cannot + affect the current working directory of the parent (your shell). + Thus, "sudo cd /foo" will start a child process, change the + directory and immediately exit without doing anything useful. + +Q) When I run sudo it says I am not allowed to run the command as root + but I don't want to run it as root, I want to run it as another user. + My sudoers file entry looks like: + bob ALL=(oracle) ALL +A) The default user sudo tries to run things as is always root, even if + the invoking user can only run commands as a single, specific user. + This may change in the future but at the present time you have to + work around this using the 'runas_default' option in sudoers. + For example: + Defaults:bob runas_default=oracle + would achieve the desired result for the preceding sudoers fragment. + +Q) When I try to run sudo via ssh, I get the error: + sudo: no tty present and no askpass program specified +A) ssh does not allocate a tty by default when running a remote command. + Without a tty, sudo cannot disable echo when prompting for a password. + You can use ssh's "-t" option to force it to allocate a tty. + Alternately, if you do not mind your password being echoed to the + screen, you can use the "visiblepw" sudoers option to allow this. + +Q) When I try to use SSL-enabled LDAP with sudo I get an error: + unable to initialize SSL cert and key db: security library: bad database. + you must set TLS_CERT in /etc/ldap.conf to use SSL +A) On systems that use a Mozilla-derived LDAP SDK there must be a + certificate database in place to use SSL-encrypted LDAP connections. + This file is usually /var/ldap/cert8.db or /etc/ldap/cert8.db. + The actual number after "cert" will vary, depending on the version + of the LDAP SDK that is being used. If you do not have a certificate + database you can either copy one from a mozilla-derived browser, such + as firefox, or create one using the "certutil" command. You can run + "certutil" as follows and press the (or ) key at the + password prompt: + # certutil -N -d /var/ldap + Enter a password which will be used to encrypt your keys. + The password should be at least 8 characters long, + and should contain at least one non-alphabetic character. + + Enter new password: + Re-enter password: + +Q) When I run sudo on AIX I get the following error: + setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID): Operation not permitted. +A) AIX's Enhanced RBAC is preventing sudo from running. To fix + this, add the following entry to /etc/security/privcmds (adjust + the path to sudo as needed) and run the setkst command as root: + + /usr/local/bin/sudo: + accessauths = ALLOW_ALL + innateprivs = PV_DAC_GID,PV_DAC_O,PV_DAC_R,PV_DAC_UID,PV_DAC_W,PV_DAC_X,PV_FS_CHOWN,PV_PROC_ENV,PV_PROC_PRIO,PV_PROC_RAC + secflags = FSF_EPS + +Q) When I run configure I get the following error: + dlopen present but libtool doesn't appear to support your platform. +A) Libtool doesn't know how to support dynamic linking on the operating + system you are building for. If you are cross-compiling, you need to + specify the operating system, not just the CPU type. For example: + --host powerpc-unknown-linux + instead of just: + --host powerpc + +Q) How do you pronounce `sudo'? +A) The official pronunciation is soo-doo (for su "do"). However, an + alternate pronunciation, a homophone of "pseudo", is also common. diff --git a/doc/UPGRADE b/doc/UPGRADE new file mode 100644 index 0000000..8c83aaf --- /dev/null +++ b/doc/UPGRADE @@ -0,0 +1,290 @@ +Notes on upgrading from an older release +======================================== + +o Upgrading from a version prior to 1.8.2: + + When matching Unix groups in the sudoers file, sudo will now + match based on the name of the group as it appears in sudoers + instead of the group ID. This can substantially reduce the + number of group lookups for sudoers files that contain a large + nummber of groups. There are a few side effects of this change. + + 1) Unix groups with different names but the same group ID are + can no longer be used interchangably. Sudo will look up all + of a user's groups by group ID and use the resulting group + names when matching sudoers entries. If there are multiple + groups with the same ID, the group name returned by the + system getgrgid() library function is the name that will be + used when matching sudoers entries. + + 2) Unix group names specified in the sudoers file that are + longer than the system maximum will no longer match. For + instance, if there is a Unix group "fireflie" on a system + where group names are limited to eight characters, "%fireflies" + in sudoers will no longer match "fireflie". Previously, a + lookup by name of the group "fireflies" would have matched + the "fireflie" group on most systems. + +o Upgrading from a version prior to 1.8.1: + + Changes in the sudoers parser could result in parse errors for + existing sudoers file. These changes cause certain erroneous + entries to be flagged as errors where before they allowed. + Changes include: + + Combining multiple Defaults entries with a backslash. E.g. + + Defaults set_path \ + Defaults syslog + + which should be: + + Defaults set_path + Defaults syslog + + Also, double-quoted strings with a missing end-quote are now + detected and result in an error. Previously, text starting a + double quote and ending with a newline was ignored. E.g. + + Defaults set_path"foo + + In previous versions of sudo, the `"foo' portion would have + been ignored. + + To avoid problems, sudo 1.8.1's "make install" will not install + a new sudo binary if the existing sudoers file has errors. + + In Sudo 1.8.1 the "noexec" functionality has moved out of the + sudoers policy plugin and into the sudo front-end. As a result, + the path to the noexec file is now specified in the sudo.conf + file instead of the sudoers file. If you have a sudoers file + that uses the "noexec_file" option, you will need to move the + definition to the sudo.conf file instead. + + Old style in /etc/sudoers: + Defaults noexec_file=/usr/local/libexec/sudo_noexec.so + + New style in /etc/sudo.conf: + Path noexec /usr/local/libexec/sudo_noexec.so + +o Upgrading from a version prior to 1.8.0: + + Starting with version 1.8.0, sudo uses a modular framework to + support policy and I/O logging plugins. The default policy + plugin is "sudoers" which provides the traditional sudoers + evaluation and I/O logging. Plugins are typically located in + /usr/libexec or /usr/local/libexec, though this is system-dependent. + The sudoers plugin is named "sudoers.so" on most systems. + + The sudo.conf file, usually stored in /etc, is used to configure + plugins. This file is optional--if no plugins are specified + in sudo.conf, the "sudoers" plugin is used. See the sample.sudo.conf + file in the doc directory or refer to the updated sudo manual + to see how to configure sudo.conf. + + The "askpass" setting has moved from the sudoers file to the + sudo.conf file. If you have a sudoers file that uses the + "askpass" option, you will need to move the definition to the + sudo.conf file. + + Old style in /etc/sudoers: + Defaults askpass=/usr/X11R6/bin/ssh-askpass + + New style in /etc/sudo.conf: + Path askpass /usr/X11R6/bin/ssh-askpass + +o Upgrading from a version prior to 1.7.5: + + Sudo 1.7.5 includes an updated LDAP schema with support for + the sudoNotBefore, sudoNotAfter and sudoOrder attributes. + + The sudoNotBefore and sudoNotAfter attribute support is only + used when the SUDOERS_TIMED setting is enabled in ldap.conf. + If enabled, those attributes are used directly when constructing + an LDAP filter. As a result, your LDAP server must have the + updated schema if you want to use sudoNotBefore and sudoNotAfter. + + The sudoOrder support does not affect the LDAP filter sudo + constructs and so there is no need to explicitly enable it in + ldap.conf. If the sudoOrder attribute is not present in an + entry, a value of 0 is used. If no entries contain sudoOrder + attributes, the results are in whatever order the LDAP server + returns them, as in past versions of sudo. + + Older versions of sudo will simply ignore the new attributes + if they are present in an entry. There are no compatibility + problems using the updated schema with older versions of sudo. + +o Upgrading from a version prior to 1.7.4: + + Starting with sudo 1.7.4, the time stamp files have moved from + /var/run/sudo to either /var/db/sudo, /var/lib/sudo or /var/adm/sudo. + The directories are checked for existence in that order. This + prevents users from receiving the sudo lecture every time the + system reboots. Time stamp files older than the boot time are + ignored on systems where it is possible to determine this. + + Additionally, the tty_tickets sudoers option is now enabled by + default. To restore the old behavior (single time stamp per user), + add a line like: + Defaults !tty_tickets + to sudoers or use the --without-tty-tickets configure option. + + The HOME and MAIL environment variables are now reset based on the + target user's password database entry when the env_reset sudoers option + is enabled (which is the case in the default configuration). Users + wishing to preserve the original values should use a sudoers entry like: + Defaults env_keep += HOME + to preserve the old value of HOME and + Defaults env_keep += MAIL + to preserve the old value of MAIL. + + NOTE: preserving HOME has security implications since many programs + use it when searching for configuration files. Adding HOME to env_keep + may enable a user to run unrestricted commands via sudo. + + The default syslog facility has changed from "local2" to "authpriv" + (or "auth" if the operating system doesn't have "authpriv"). + The --with-logfac configure option can be used to change this + or it can be changed in the sudoers file. + +o Upgrading from a version prior to 1.7.0: + + Starting with sudo 1.7.0, comments in the sudoers file must not + have a digit or minus sign immediately after the comment character + ('#'). Otherwise, the comment may be interpreted as a user or + group ID. + + When sudo is build with LDAP support the /etc/nsswitch.conf file is + now used to determine the sudoers seach order. sudo will default to + only using /etc/sudoers unless /etc/nsswitch.conf says otherwise. + This can be changed with an nsswitch.conf line, e.g.: + sudoers: ldap files + Would case LDAP to be searched first, then the sudoers file. + To restore the pre-1.7.0 behavior, run configure with the + --with-nsswitch=no flag. + + Sudo now ignores user .ldaprc files as well as system LDAP defaults. + All LDAP configuration is now in /etc/ldap.conf (or whichever file + was specified by configure's --with-ldap-conf-file option). + If you are using TLS, you may now need to specify: + tls_checkpeer no + in sudo's ldap.conf unless ldap.conf references a valid certificate + authority file(s). + + Please also see the NEWS file for a list of new features in + sudo 1.7.0. + +o Upgrading from a version prior to 1.6.9: + + Starting with sudo 1.6.9, if an OS supports a modular authentication + method such as PAM, it will be used by default by configure. + + Environment variable handling has changed significantly in sudo + 1.6.9. Prior to version 1.6.9, sudo would preserve the user's + environment, pruning out potentially dangerous variables. + Beginning with sudo 1.6.9, the envionment is reset to a default + set of values with only a small number of "safe" variables + preserved. To preserve specific environment variables, add + them to the "env_keep" list in sudoers. E.g. + + Defaults env_keep += "EDITOR" + + The old behavior can be restored by negating the "env_reset" + option in sudoers. E.g. + + Defaults !env_reset + + There have also been changes to how the "env_keep" and + "env_check" options behave. + + Prior to sudo 1.6.9, the TERM and PATH environment variables + would always be preserved even if the env_keep option was + redefined. That is no longer the case. Consequently, if + env_keep is set with "=" and not simply appended to (i.e. using + "+="), PATH and TERM must be explicitly included in the list + of environment variables to keep. The LOGNAME, SHELL, USER, + and USERNAME environment variables are still always set. + + Additionally, the env_check setting previously had no effect + when env_reset was set (which is now on by default). Starting + with sudo 1.6.9, environment variables listed in env_check are + also preserved in the env_reset case, provided that they do not + contain a '/' or '%' character. Note that it is not necessary + to also list a variable in env_keep--having it in env_check is + sufficent. + + The default lists of variables to be preserved and/or checked + are displayed when sudo is run by root with the -V flag. + +o Upgrading from a version prior to 1.6.8: + + Prior to sudo 1.6.8, if /var/run did not exist, sudo would put + the time stamp files in /tmp/.odus. As of sudo 1.6.8, the + time stamp files will be placed in /var/adm/sudo or /usr/adm/sudo + if there is no /var/run directory. This directory will be + created if it does not already exist. + + Previously, a sudoers entry that explicitly prohibited running + a command as a certain user did not override a previous entry + allowing the same command. This has been fixed in sudo 1.6.8 + such that the last match is now used (as it is documented). + Hopefully no one was depending on the previous (buggy) beghavior. + +o Upgrading from a version prior to 1.6: + + As of sudo 1.6, parsing of runas entries and the NOPASSWD tag + has changed. Prior to 1.6, a runas specifier applied only to + a single command directly following it. Likewise, the NOPASSWD + tag only allowed the command directly following it to be run + without a password. Starting with sudo 1.6, both the runas + specifier and the NOPASSWD tag are "sticky" for an entire + command list. So, given the following line in sudo < 1.6 + + millert ALL=(daemon) NOPASSWD:/usr/bin/whoami,/bin/ls + + millert would be able to run /usr/bin/whoami as user daemon + without a password and /bin/ls as root with a password. + + As of sudo 1.6, the same line now means that millert is able + to run run both /usr/bin/whoami and /bin/ls as user daemon + without a password. To expand on this, take the following + example: + + millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, (root) /bin/ls, \ + /sbin/dump + + millert can run /usr/bin/whoami as daemon and /bin/ls and + /sbin/dump as root. No password need be given for either + command. In other words, the "(root)" sets the default runas + user to root for the rest of the list. If we wanted to require + a password for /bin/ls and /sbin/dump the line could be written + thusly: + + millert ALL=(daemon) NOPASSWD:/usr/bin/whoami, \ + (root) PASSWD:/bin/ls, /sbin/dump + + Additionally, sudo now uses a per-user time stamp directory + instead of a time stamp file. This allows tty time stamps to + simply be files within the user's time stamp dir. For the + default, non-tty case, the time stamp on the directory itself + is used. + + Also, the temporary file used by visudo is now /etc/sudoers.tmp + since some versions of vipw on systems with shadow passwords use + /etc/stmp for the temporary shadow file. + +o Upgrading from a version prior to 1.5: + + By default, sudo expects the sudoers file to be mode 0440 and + to be owned by user and group 0. This differs from version 1.4 + and below which expected the sudoers file to be mode 0400 and + to be owned by root. Doing a `make install' will set the sudoers + file to the new mode and group. If sudo encounters a sudoers + file with the old permissions it will attempt to update it to + the new scheme. You cannot, however, use a sudoers file with + the new permissions with an old sudo binary. It is suggested + that if have a means of distributing sudo you distribute the + new binaries first, then the new sudoers file (or you can leave + sudoers as is and sudo will fix the permissions itself as long + as sudoers is on a local file system). diff --git a/doc/contributors.pod b/doc/contributors.pod new file mode 100644 index 0000000..7c9c657 --- /dev/null +++ b/doc/contributors.pod @@ -0,0 +1,160 @@ +=head1 Sudo Contributors + +=head4 +The following list of people, sorted by last name, have contributed +code or patches to this implementation of sudo since I began +maintaining it in 1993. This list is known to be incomplete--if +you believe you should be listed, please send a note to sudo@sudo.ws. + + Matt Ackeret + Mark Adler + Russ Allbery + Nick Andrew + Dimitry Andric + Danny Barron + Tom Bates + Zdenek Behan + Ray Bellis + Elias Benali + Jamie Beverly + Spider Boardman + Jakub Bogusz + P.J. Bostley + Keith Bowes + Keith Garry Boyce + Michael Brantley + Rob Braun + Piete Brooks + Jerry Brown + Michael E Burr + Andreas Bussjaeger + Gary Calvin + Aaron Campbell + Milo Casagrande + Yuri Chornoivan + Vitezslav Cizek + Chris Coleman + Deven T. Corzine + Frank Cusack + Theo de Raadt + David Dill + Theo Van Dinter + Jeff Earickson + Drew Eckhardt + Ben Edgington + Marc Esipovich + Marc Espie + Ariel Faigon + Brian Farrell + Steve Fobes + Mike Frysinger + Jean-loup Gailly + Simon J. Gerraty + B. Guillory + Joe Hansen + Randy M. Hayman + Joachim Henke + YOSHIFUJI Hideaki + Dave Hieb + Nick Holloway + Adam Hoover + Michael T. Hunter + Eric Irrgang + Brian Jackson + Richard L. Jackson Jr + John R. Jackson + Mark Janssen + Chris Jepeway + Timo Juhani + Ayamura KIKUCHI + Kevin Kadow + Jorma Karvonen + Stepan Kasal + Mike Kienenberger + Dale King + Jim Knoble + Tim Knox + Alek O. Komarnitsky + Daniel Kopecek + Yuri Kozlov + Paul Kranenburg + David Krause + Case Larsen + Dmitry V. Levin + Kendall Libby + Phillip E. Lobbes + Jason McIntyre + David J. MacKenzie + Tom McLaughlin + Jeff Makey + Michael D. Marchionna + Paul Markham + Emin Martinian + Pavel Maryanov + Michael Meskes + Todd C. Miller + Loic Minier + Jan Thomas Moldung + Charles Morris + Andreas Mueller + Dworkin Muller + Jeff Nieusma + Peter A. Nikitser + Miroslav Nikolic + Ludwig Nussel + Eric Paquet + Chantal Paradis + Ted Percival + Christian S.J. Peron + Alexander Peslyak + Toby Peterson + Diego Elio Petteno + Joel Pickett + Alex Plotnick + Gudleik Rasch + Matt Richards + Guido van Rossum + John P. Rouillard + William A. Rowe Jr. + Alain Roy + Elan Ruusamae + Eygene Ryabinkin + Yuichi SATO + Wilfredo Sanchez + Jean-Francois Saucier + Patrick Schoenfeld + Arno Schuring + Dougal Scott + Abel Sendón + Nick Sieger + Thor Lancelot Simon + Marc Slemko + Andy Smith + Igor Sobrado + Aaron Spangler + Cloyce D. Spradling + Matthew Stier + Tobias Stoeckmann + Russell Street + Tilo Stritzky + Michael Stroucken + Yasuaki Taniguchi + Robert Tarrall + Matthew Thomas + Giles Todd + Martin Toft + Chris Torek + Darren Tucker + Robert Uhl + Mikel Olasagasti Uranga + Petr Uzel + Reznic Valery + Martynas Venckus + Klaus Wagner + Dan Walsh + Wylmer Wang + John Warburton + Kirk Webb + Timm Wetzel + Marco van Wieringen + David Wood diff --git a/doc/history.pod b/doc/history.pod new file mode 100644 index 0000000..506afc0 --- /dev/null +++ b/doc/history.pod @@ -0,0 +1,79 @@ +=head1 A Brief History of Sudo: + +=head3 The Early Years + +Sudo was first conceived and implemented by Bob Coggeshall and Cliff +Spencer around 1980 at the Department of Computer Science at +SUNY/Buffalo. It ran on a VAX-11/750 running 4.1BSD. An updated +version, credited to Phil Betchel, Cliff Spencer, Gretchen Phillips, +John LoVerso and Don Gworek, was posted to the net.sources Usenet +newsgroup in December of 1985. + +=head3 Sudo at CU-Boulder + +In the Summer of 1986, Garth Snyder released an enhanced version +of sudo. For the next 5 years, sudo was fed and watered by a handful +of folks at CU-Boulder, including Bob Coggeshall, Bob Manchek, and +Trent Hein. + +=head3 Root Group Sudo + +In 1991, Dave Hieb and Jeff Nieusma wrote a new version of sudo +with an enhanced sudoers format under contract to a consulting firm +called "The Root Group". This version was later released under the +GNU public license. + +=head3 CU Sudo + +In 1994, after maintaining sudo informally within CU-Boulder for +some time, Todd C. Miller made a public release of "CU sudo" (version +1.3) with bug fixes and support for more operating systems. The +"CU" was added to differentiate it from the "official" version from +"The Root Group". + +In 1995, a new parser for the sudoers file was contributed by Chris +Jepeway. The new parser was a proper grammar (unlike the old one) +and could work with both sudo and visudo (previously they had +slightly different parsers). + +In 1996, Todd, who had been maintaining sudo for several years in +his spare time, moved distribution of sudo from a CU-Boulder ftp +site to his domain, courtesan.com. + +=head3 Just Plain Sudo + +In 1999, the "CU" prefix was dropped from the name since there had +been no formal release of sudo from "The Root Group" since 1991 +(the original authors now work elsewhere). As of version 1.6, Sudo +no longer contains any of the original "Root Group" code and is +available under an ISC-style license. + +In 2001, the sudo web site, ftp site and mailing lists were moved +from courtesan.com to the sudo.ws domain (sudo.org was already +taken). + +=head3 LDAP Integration + +In 2003, Nationwide Mutual Insurance Company contributed code written +by Aaron Spangler to store the sudoers data in LDAP. These changes +were incorporated into Sudo 1.6.8. + +=head3 New Parser + +In 2005, Todd rewrote the sudoers parser to better support the +features that had been added in the past ten years. This new parser +removes some limitations of the previous one, removes ordering +constraints and adds support for including multiple sudoers files. + +=head3 Quest Sponsorship + +In 2010, Quest Software began sponsoring Sudo development by hiring +Todd to work on Sudo as part of his full-time job. + +=head3 Present Day + +Sudo, in its current form, is maintained by: + + Todd C. Miller + +Todd continues to enhance sudo and fix bugs. diff --git a/doc/license.pod b/doc/license.pod new file mode 100644 index 0000000..c3c23a9 --- /dev/null +++ b/doc/license.pod @@ -0,0 +1,78 @@ +=head1 Sudo License + +=head3 +Sudo is distributed under the following ISC-style license: + + Copyright (c) 1994-1996, 1998-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. + + Sponsored in part by the Defense Advanced Research Projects + Agency (DARPA) and Air Force Research Laboratory, Air Force + Materiel Command, USAF, under agreement number F39502-99-1-0512. + +=head3 +The files fnmatch.c, fnmatch.h, getcwd.c, glob.c, glob.h and snprintf.c +bear the following UCB license: + + Copyright (c) 1987, 1989, 1990, 1991, 1992, 1993, 1994 + The Regents of the University of California. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +=head3 +The embedded copy of zlib bears the following license: + + Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/doc/sample.pam b/doc/sample.pam new file mode 100644 index 0000000..d56e712 --- /dev/null +++ b/doc/sample.pam @@ -0,0 +1,30 @@ +#%PAM-1.0 +# Sample /etc/pam.d/sudo file for RedHat 9 / Fedora Core. +# For other Linux distributions you may want to +# use /etc/pam.d/sshd or /etc/pam.d/su as a guide. +# +# There are two basic ways to configure PAM, either via pam_stack +# or by explicitly specifying the various methods to use. +# +# Here we use pam_stack +auth required pam_stack.so service=system-auth +account required pam_stack.so service=system-auth +password required pam_stack.so service=system-auth +session required pam_stack.so service=system-auth +# +# Alternately, you can specify the authentication method directly. +# Here we use pam_unix for normal password authentication. +#auth required pam_env.so +#auth sufficient pam_unix.so +#account required pam_unix.so +#password required pam_cracklib.so retry=3 type= +#password required pam_unix.so nullok use_authtok md5 shadow +#session required pam_limits.so +#session required pam_unix.so +# +# Another option is to use SMB for authentication. +#auth required pam_env.so +#auth sufficient pam_smb_auth.so +#account required pam_smb_auth.so +#password required pam_smb_auth.so +#session required pam_limits.so diff --git a/doc/sample.sudo.conf b/doc/sample.sudo.conf new file mode 100644 index 0000000..3672bcb --- /dev/null +++ b/doc/sample.sudo.conf @@ -0,0 +1,55 @@ +# +# Sample /etc/sudo.conf file +# +# Format: +# Plugin plugin_name plugin_path plugin_options ... +# Path askpass /path/to/askpass +# Path noexec /path/to/sudo_noexec.so +# Debug sudo /var/log/sudo_debug all@warn +# Set disable_coredump true +# +# Sudo plugins: +# +# The plugin_path is relative to ${prefix}/libexec unless fully qualified. +# The plugin_name corresponds to a global symbol in the plugin +# that contains the plugin interface structure. +# The plugin_options are optional. +# +# The sudoers plugin is used by default if no Plugin lines are present. +Plugin sudoers_policy sudoers.so +Plugin sudoers_io sudoers.so + +# +# Sudo askpass: +# +# An askpass helper program may be specified to provide a graphical +# password prompt for "sudo -A" support. Sudo does not ship with its +# own passpass program but can use the OpenSSH askpass. +# +# Use the OpenSSH askpass +#Path askpass /usr/X11R6/bin/ssh-askpass +# +# Use the Gnome OpenSSH askpass +#Path askpass /usr/libexec/openssh/gnome-ssh-askpass + +# +# Sudo noexec: +# +# Path to a shared library containing dummy versions of the execv(), +# execve() and fexecve() library functions that just return an error. +# This is used to implement the "noexec" functionality on systems that +# support C or its equivalent. +# The compiled-in value is usually sufficient and should only be changed +# if you rename or move the sudo_noexec.so file. +# +#Path noexec /usr/libexec/sudo_noexec.so + +# +# Core dumps: +# +# By default, sudo disables core dumps while it is executing (they +# are re-enabled for the command that is run). +# To aid in debugging sudo problems, you may wish to enable core +# dumps by setting "disable_coredump" to false. +# +#Set disable_coredump false diff --git a/doc/sample.sudoers b/doc/sample.sudoers new file mode 100644 index 0000000..0ef1579 --- /dev/null +++ b/doc/sample.sudoers @@ -0,0 +1,131 @@ +# +# Sample /etc/sudoers file. +# +# This file MUST be edited with the 'visudo' command as root. +# +# See the sudoers man page for the details on how to write a sudoers file. + +## +# Override built-in defaults +## +Defaults syslog=auth +Defaults>root !set_logname +Defaults:FULLTIMERS !lecture +Defaults:millert !authenticate +Defaults@SERVERS log_year, logfile=/var/log/sudo.log +Defaults!PAGERS noexec + +## +# User alias specification +## +User_Alias FULLTIMERS = millert, mikef, dowdy +User_Alias PARTTIMERS = bostley, jwfox, crawl +User_Alias WEBMASTERS = will, wendy, wim + +## +# Runas alias specification +## +Runas_Alias OP = root, operator +Runas_Alias DB = oracle, sybase + +## +# Host alias specification +## +Host_Alias SPARC = bigtime, eclipse, moet, anchor:\ + SGI = grolsch, dandelion, black:\ + ALPHA = widget, thalamus, foobar:\ + HPPA = boa, nag, python +Host_Alias CUNETS = 128.138.0.0/255.255.0.0 +Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 +Host_Alias SERVERS = master, mail, www, ns +Host_Alias CDROM = orion, perseus, hercules + +## +# Cmnd alias specification +## +Cmnd_Alias DUMPS = /usr/sbin/dump, /usr/sbin/rdump, /usr/sbin/restore, \ + /usr/sbin/rrestore, /usr/bin/mt +Cmnd_Alias KILL = /usr/bin/kill +Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm +Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown +Cmnd_Alias HALT = /usr/sbin/halt +Cmnd_Alias REBOOT = /usr/sbin/reboot +Cmnd_Alias SHELLS = /sbin/sh, /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \ + /usr/local/bin/tcsh, /usr/bin/rsh, \ + /usr/local/bin/zsh +Cmnd_Alias SU = /usr/bin/su +Cmnd_Alias VIPW = /usr/sbin/vipw, /usr/bin/passwd, /usr/bin/chsh, \ + /usr/bin/chfn +Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less + +## +# User specification +## + +# root and users in group wheel can run anything on any machine as any user +root ALL = (ALL) ALL +%wheel ALL = (ALL) ALL + +# full time sysadmins can run anything on any machine without a password +FULLTIMERS ALL = NOPASSWD: ALL + +# part time sysadmins may run anything but need a password +PARTTIMERS ALL = ALL + +# jack may run anything on machines in CSNETS +jack CSNETS = ALL + +# lisa may run any command on any host in CUNETS (a class B network) +lisa CUNETS = ALL + +# operator may run maintenance commands and anything in /usr/oper/bin/ +operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\ + sudoedit /etc/printcap, /usr/oper/bin/ + +# joe may su only to operator +joe ALL = /usr/bin/su operator + +# pete may change passwords for anyone but root on the hp snakes +pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root + +# bob may run anything on the sparc and sgi machines as any user +# listed in the Runas_Alias "OP" (ie: root and operator) +bob SPARC = (OP) ALL : SGI = (OP) ALL + +# jim may run anything on machines in the biglab netgroup +jim +biglab = ALL + +# users in the secretaries netgroup need to help manage the printers +# as well as add and remove users ++secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser + +# fred can run commands as oracle or sybase without a password +fred ALL = (DB) NOPASSWD: ALL + +# on the alphas, john may su to anyone but root and flags are not allowed +john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* + +# jen can run anything on all machines except the ones +# in the "SERVERS" Host_Alias +jen ALL, !SERVERS = ALL + +# jill can run any commands in the directory /usr/bin/, except for +# those in the SU and SHELLS aliases. +jill SERVERS = /usr/bin/, !SU, !SHELLS + +# steve can run any command in the directory /usr/local/op_commands/ +# as user operator. +steve CSNETS = (operator) /usr/local/op_commands/ + +# matt needs to be able to kill things on his workstation when +# they get hung. +matt valkyrie = KILL + +# users in the WEBMASTERS User_Alias (will, wendy, and wim) +# may run any command as user www (which owns the web pages) +# or simply su to www. +WEBMASTERS www = (www) ALL, (root) /usr/bin/su www + +# anyone can mount/unmount a cd-rom on the machines in the CDROM alias +ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ + /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM diff --git a/doc/sample.syslog.conf b/doc/sample.syslog.conf new file mode 100644 index 0000000..686cd19 --- /dev/null +++ b/doc/sample.syslog.conf @@ -0,0 +1,26 @@ +# This is a sample syslog.conf fragment for use with Sudo. +# +# By default, sudo logs to "authpriv" if your system supports it, else it +# uses "auth". The facility can be set via the --with-logfac configure +# option or in the sudoers file. +# To see what syslog facility a sudo binary uses, run `sudo -V' as *root*. +# +# NOTES: +# The whitespace in the following line is made up of +# characters, *not* spaces. You cannot just cut and paste! +# +# If you edit syslog.conf you need to send syslogd a HUP signal. +# Ie: kill -HUP process_id +# +# Syslogd will not create new log files for you, you must first +# create the file before syslogd will log to it. Eg. +# 'touch /var/log/sudo' + +# This logs successful and failed sudo attempts to the file /var/log/auth +# If your system has the authpriv syslog facility, use authpriv.debug +auth.debug /var/log/auth + +# To log to a remote machine, use something like the following, +# where "loghost" is the name of the remote machine. +# If your system has the authpriv syslog facility, use authpriv.debug +auth.debug @loghost diff --git a/doc/schema.ActiveDirectory b/doc/schema.ActiveDirectory new file mode 100644 index 0000000..cfdc7cb --- /dev/null +++ b/doc/schema.ActiveDirectory @@ -0,0 +1,255 @@ +# +# Active Directory Schema for sudo configuration (sudoers) +# +# To extend your Active Directory schema, run one of the following command +# on your Windows DC (default port - Active Directory): +# +# ldifde -i -f schema.ActiveDirectory -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext +# +# or on your Windows DC if using another port (with Active Directory LightWeight Directory Services / ADAM-Active Directory Application Mode) +# Port 50000 by example (or any other port specified when defining the ADLDS/ADAM instance +# +# ldifde -i -f schema.ActiveDirectory -t 50000 -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext +# +# or +# +# ldifde -i -f schema.ActiveDirectory -s server:port -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext +# +# Can add username domain and password +# +# -b username domain password +# +# Can create Log file in current or any directory +# +# -j . +# + +dn: CN=sudoUser,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoUser +distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.1 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoUser +adminDescription: User(s) who may run sudo +oMSyntax: 22 +searchFlags: 1 +lDAPDisplayName: sudoUser +name: sudoUser +schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=sudoHost,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoHost +distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.2 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoHost +adminDescription: Host(s) who may run sudo +oMSyntax: 22 +lDAPDisplayName: sudoHost +name: sudoHost +schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoCommand +distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.3 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoCommand +adminDescription: Command(s) to be executed by sudo +oMSyntax: 22 +lDAPDisplayName: sudoCommand +name: sudoCommand +schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoRunAs +distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.4 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoRunAs +adminDescription: User(s) impersonated by sudo (deprecated) +oMSyntax: 22 +lDAPDisplayName: sudoRunAs +name: sudoRunAs +schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=sudoOption,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoOption +distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.5 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoOption +adminDescription: Option(s) followed by sudo +oMSyntax: 22 +lDAPDisplayName: sudoOption +name: sudoOption +schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoRunAsUser +distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.6 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoRunAsUser +adminDescription: User(s) impersonated by sudo +oMSyntax: 22 +lDAPDisplayName: sudoRunAsUser +name: sudoRunAsUser +schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: attributeSchema +cn: sudoRunAsGroup +distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +attributeID: 1.3.6.1.4.1.15953.9.1.7 +attributeSyntax: 2.5.5.5 +isSingleValued: FALSE +showInAdvancedViewOnly: TRUE +adminDisplayName: sudoRunAsGroup +adminDescription: Groups(s) impersonated by sudo +oMSyntax: 22 +lDAPDisplayName: sudoRunAsGroup +name: sudoRunAsGroup +schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw== +objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X + +dn: CN=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 +schemaUpdateNow: 1 +- + +dn: CN=sudoRole,CN=Schema,CN=Configuration,DC=X +changetype: add +objectClass: top +objectClass: classSchema +cn: sudoRole +distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,DC=X +instanceType: 4 +possSuperiors: container +possSuperiors: top +subClassOf: top +governsID: 1.3.6.1.4.1.15953.9.2.1 +mayContain: sudoCommand +mayContain: sudoHost +mayContain: sudoOption +mayContain: sudoRunAs +mayContain: sudoRunAsUser +mayContain: sudoRunAsGroup +mayContain: sudoUser +mayContain: sudoNotBefore +mayContain: sudoNotAfter +mayContain: sudoOrder +rDNAttID: cn +showInAdvancedViewOnly: FALSE +adminDisplayName: sudoRole +adminDescription: Sudoer Entries +objectClassCategory: 1 +lDAPDisplayName: sudoRole +name: sudoRole +schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w== +systemOnly: FALSE +objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=X +defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,DC=X diff --git a/doc/schema.OpenLDAP b/doc/schema.OpenLDAP new file mode 100644 index 0000000..d3e95e0 --- /dev/null +++ b/doc/schema.OpenLDAP @@ -0,0 +1,76 @@ +# +# OpenLDAP schema file for Sudo +# Save as /etc/openldap/schema/sudo.schema +# + +attributetype ( 1.3.6.1.4.1.15953.9.1.1 + NAME 'sudoUser' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo (deprecated)' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.8 + NAME 'sudoNotBefore' + DESC 'Start of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.9 + NAME 'sudoNotAfter' + DESC 'End of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +attributeTypes ( 1.3.6.1.4.1.15953.9.1.10 + NAME 'sudoOrder' + DESC 'an integer to order the sudoRole entries' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ + description ) + ) diff --git a/doc/schema.iPlanet b/doc/schema.iPlanet new file mode 100644 index 0000000..e512864 --- /dev/null +++ b/doc/schema.iPlanet @@ -0,0 +1,12 @@ +dn: cn=schema +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) +attributeTypes: ( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) +objectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ description ) X-ORIGIN 'SUDO' ) diff --git a/doc/sudo.cat b/doc/sudo.cat new file mode 100644 index 0000000..c32092b --- /dev/null +++ b/doc/sudo.cat @@ -0,0 +1,627 @@ +SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) + + + +NNAAMMEE + sudo, sudoedit - execute a command as another user + +SSYYNNOOPPSSIISS + ssuuddoo --hh | --KK | --kk | --VV + + ssuuddoo --vv [--AAkknnSS] [--aa _a_u_t_h___t_y_p_e] [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] + [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] + + ssuuddoo --ll[[ll]] [--AAkknnSS] [--aa _a_u_t_h___t_y_p_e] [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] + [--UU _u_s_e_r _n_a_m_e] [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] [_c_o_m_m_a_n_d] + + ssuuddoo [--AAbbEEHHnnPPSS] [--aa _a_u_t_h___t_y_p_e] [--CC _f_d] [--cc _c_l_a_s_s|_-] + [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] [--rr _r_o_l_e] [--tt _t_y_p_e] + [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] [VVAARR=_v_a_l_u_e] [--ii | --ss] [_c_o_m_m_a_n_d] + + ssuuddooeeddiitt [--AAnnSS] [--aa _a_u_t_h___t_y_p_e] [--CC _f_d] [--cc _c_l_a_s_s|_-] + [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] file ... + +DDEESSCCRRIIPPTTIIOONN + ssuuddoo allows a permitted user to execute a _c_o_m_m_a_n_d as the superuser or + another user, as specified by the security policy. The real and + effective uid and gid are set to match those of the target user, as + specified in the password database, and the group vector is initialized + based on the group database (unless the --PP option was specified). + + ssuuddoo supports a plugin architecture for security policies and + input/output logging. Third parties can develop and distribute their + own policy and I/O logging modules to work seamlessly with the ssuuddoo + front end. The default security policy is _s_u_d_o_e_r_s, which is configured + via the file _/_e_t_c_/_s_u_d_o_e_r_s, or via LDAP. See the PLUGINS section for + more information. + + The security policy determines what privileges, if any, a user has to + run ssuuddoo. The policy may require that users authenticate themselves + with a password or another authentication mechanism. If authentication + is required, ssuuddoo will exit if the user's password is not entered + within a configurable time limit. This limit is policy-specific; the + default password prompt timeout for the _s_u_d_o_e_r_s security policy is 5 + minutes. + + Security policies may support credential caching to allow the user to + run ssuuddoo again for a period of time without requiring authentication. + The _s_u_d_o_e_r_s policy caches credentials for 5 minutes, unless overridden + in _s_u_d_o_e_r_s(4). By running ssuuddoo with the --vv option, a user can update + the cached credentials without running a _c_o_m_m_a_n_d. + + When invoked as ssuuddooeeddiitt, the --ee option (described below), is implied. + + Security policies may log successful and failed attempts to use ssuuddoo. + If an I/O plugin is configured, the running command's input and output + may be logged as well. + +OOPPTTIIOONNSS + ssuuddoo accepts the following command line options: + + -A Normally, if ssuuddoo requires a password, it will read it from + the user's terminal. If the --AA (_a_s_k_p_a_s_s) option is + specified, a (possibly graphical) helper program is + executed to read the user's password and output the + password to the standard output. If the SUDO_ASKPASS + environment variable is set, it specifies the path to the + helper program. Otherwise, if _/_e_t_c_/_s_u_d_o_._c_o_n_f contains a + line specifying the askpass program, that value will be + used. For example: + + # Path to askpass helper program + Path askpass /usr/X11R6/bin/ssh-askpass + + If no askpass program is available, sudo will exit with an + error. + + -a _t_y_p_e The --aa (_a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e) option causes ssuuddoo to use the + specified authentication type when validating the user, as + allowed by _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. The system administrator may + specify a list of sudo-specific authentication methods by + adding an "auth-sudo" entry in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. This + option is only available on systems that support BSD + authentication. + + -b The --bb (_b_a_c_k_g_r_o_u_n_d) option tells ssuuddoo to run the given + command in the background. Note that if you use the --bb + option you cannot use shell job control to manipulate the + process. Most interactive commands will fail to work + properly in background mode. + + -C _f_d Normally, ssuuddoo will close all open file descriptors other + than standard input, standard output and standard error. + The --CC (_c_l_o_s_e _f_r_o_m) option allows the user to specify a + starting point above the standard error (file descriptor + three). Values less than three are not permitted. The + security policy may restrict the user's ability to use the + --CC option. The _s_u_d_o_e_r_s policy only permits use of the --CC + option when the administrator has enabled the + _c_l_o_s_e_f_r_o_m___o_v_e_r_r_i_d_e option. + + -c _c_l_a_s_s The --cc (_c_l_a_s_s) option causes ssuuddoo to run the specified + command with resources limited by the specified login + class. The _c_l_a_s_s argument can be either a class name as + defined in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f, or a single '-' character. + Specifying a _c_l_a_s_s of - indicates that the command should + be run restricted by the default login capabilities for the + user the command is run as. If the _c_l_a_s_s argument + specifies an existing user class, the command must be run + as root, or the ssuuddoo command must be run from a shell that + is already root. This option is only available on systems + with BSD login classes. + + -E The --EE (_p_r_e_s_e_r_v_e _e_n_v_i_r_o_n_m_e_n_t) option indicates to the + security policy that the user wishes to preserve their + existing environment variables. The security policy may + return an error if the --EE option is specified and the user + does not have permission to preserve the environment. + + -e The --ee (_e_d_i_t) option indicates that, instead of running a + command, the user wishes to edit one or more files. In + lieu of a command, the string "sudoedit" is used when + consulting the security policy. If the user is authorized + by the policy, the following steps are taken: + + 1. Temporary copies are made of the files to be edited + with the owner set to the invoking user. + + 2. The editor specified by the policy is run to edit the + temporary files. The _s_u_d_o_e_r_s policy uses the + SUDO_EDITOR, VISUAL and EDITOR environment variables + (in that order). If none of SUDO_EDITOR, VISUAL or + EDITOR are set, the first program listed in the _e_d_i_t_o_r + _s_u_d_o_e_r_s(4) option is used. + + 3. If they have been modified, the temporary files are + copied back to their original location and the + temporary versions are removed. + + If the specified file does not exist, it will be created. + Note that unlike most commands run by ssuuddoo, the editor is + run with the invoking user's environment unmodified. If, + for some reason, ssuuddoo is unable to update a file with its + edited version, the user will receive a warning and the + edited copy will remain in a temporary file. + + -g _g_r_o_u_p Normally, ssuuddoo runs a command with the primary group set to + the one specified by the password database for the user the + command is being run as (by default, root). The --gg (_g_r_o_u_p) + option causes ssuuddoo to run the command with the primary + group set to _g_r_o_u_p instead. To specify a _g_i_d instead of a + _g_r_o_u_p _n_a_m_e, use _#_g_i_d. When running commands as a _g_i_d, many + shells require that the '#' be escaped with a backslash + ('\'). If no --uu option is specified, the command will be + run as the invoking user (not root). In either case, the + primary group will be set to _g_r_o_u_p. + + -H The --HH (_H_O_M_E) option requests that the security policy set + the HOME environment variable to the home directory of the + target user (root by default) as specified by the password + database. Depending on the policy, this may be the default + behavior. + + -h The --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 + specified by the password database entry of the target user + as a login shell. This means that login-specific resource + files such as .profile or .login will be read by the shell. + If a command is specified, it is passed to the shell for + execution via the shell's --cc option. If no command is + specified, an interactive shell is executed. ssuuddoo attempts + to change to that user's home directory before running the + shell. The security policy shall initialize the + environment to a minimal set of variables, similar to what + is present when a user logs in. The _C_o_m_m_a_n_d _E_n_v_i_r_o_n_m_e_n_t + section in the _s_u_d_o_e_r_s(4) manual documents how the --ii + option affects the environment in which a command is run + when the _s_u_d_o_e_r_s policy is in use. + + -K The --KK (sure _k_i_l_l) option is like --kk except that it removes + the user's cached credentials entirely and may not be used + in conjunction with a command or other option. This option + does not require a password. Not all security policies + support credential caching. + + -k [command] + When used alone, the --kk (_k_i_l_l) option to ssuuddoo invalidates + the user's cached credentials. The next time ssuuddoo is run a + password will be required. This option does not require a + password and was added to allow a user to revoke ssuuddoo + permissions from a .logout file. Not all security policies + support credential caching. + + When used in conjunction with a command or an option that + may require a password, the --kk option will cause ssuuddoo to + ignore the user's cached credentials. As a result, ssuuddoo + will prompt for a password (if one is required by the + security policy) and will not update the user's cached + credentials. + + -l[l] [_c_o_m_m_a_n_d] + If no _c_o_m_m_a_n_d is specified, the --ll (_l_i_s_t) option will list + the allowed (and forbidden) commands for the invoking user + (or the user specified by the --UU option) on the current + host. If a _c_o_m_m_a_n_d is specified and is permitted by the + security policy, the fully-qualified path to the command is + displayed along with any command line arguments. If + _c_o_m_m_a_n_d is specified but not allowed, ssuuddoo will exit with a + status value of 1. If the --ll option is specified with an ll + argument (i.e. --llll), or if --ll is specified multiple times, + a longer list format is used. + + -n The --nn (_n_o_n_-_i_n_t_e_r_a_c_t_i_v_e) option prevents ssuuddoo from + prompting the user for a password. If a password is + required for the command to run, ssuuddoo will display an error + messages and exit. + + -P The --PP (_p_r_e_s_e_r_v_e _g_r_o_u_p _v_e_c_t_o_r) option causes ssuuddoo to + preserve the invoking user's group vector unaltered. By + default, the _s_u_d_o_e_r_s policy will initialize the group + vector to the list of groups the target user is in. The + real and effective group IDs, however, are still set to + match the target user. + + -p _p_r_o_m_p_t The --pp (_p_r_o_m_p_t) option allows you to override the default + password prompt and use a custom one. The following + percent (`%') escapes are supported by the _s_u_d_o_e_r_s policy: + + %H expanded to the host name including the domain name (on + if the machine's host name is fully qualified or the + _f_q_d_n option is set in _s_u_d_o_e_r_s(4)) + + %h expanded to the local host name without the domain name + + %p expanded to the name of the user whose password is + being requested (respects the _r_o_o_t_p_w, _t_a_r_g_e_t_p_w and + _r_u_n_a_s_p_w flags in _s_u_d_o_e_r_s(4)) + + %U expanded to the login name of the user the command will + be run as (defaults to root unless the -u option is + also specified) + + %u expanded to the invoking user's login name + + %% two consecutive % characters are collapsed into a + single % character + + The prompt specified by the --pp option will override the + system password prompt on systems that support PAM unless + the _p_a_s_s_p_r_o_m_p_t___o_v_e_r_r_i_d_e flag is disabled in _s_u_d_o_e_r_s. + + -r _r_o_l_e The --rr (_r_o_l_e) option causes the new (SELinux) security + context to have the role specified by _r_o_l_e. + + -S The --SS (_s_t_d_i_n) option causes ssuuddoo to read the password from + the standard input instead of the terminal device. The + password must be followed by a newline character. + + -s [command] + The --ss (_s_h_e_l_l) option runs the shell specified by the _S_H_E_L_L + environment variable if it is set or the shell as specified + in the password database. If a command is specified, it is + passed to the shell for execution via the shell's --cc + option. If no command is specified, an interactive shell + is executed. + + -t _t_y_p_e The --tt (_t_y_p_e) option causes the new (SELinux) security + context to have the type specified by _t_y_p_e. If no type is + specified, the default type is derived from the specified + role. + + -U _u_s_e_r The --UU (_o_t_h_e_r _u_s_e_r) option is used in conjunction with the + --ll option to specify the user whose privileges should be + listed. The security policy may restrict listing other + users' privileges. The _s_u_d_o_e_r_s policy only allows root or + a user with the ALL privilege on the current host to use + this option. + + -u _u_s_e_r The --uu (_u_s_e_r) option causes ssuuddoo to run the specified + command as a user other than _r_o_o_t. To specify a _u_i_d + instead of a _u_s_e_r _n_a_m_e, use _#_u_i_d. When running commands as + a _u_i_d, many shells require that the '#' be escaped with a + backslash ('\'). Security policies may restrict _u_i_ds to + those listed in the password database. The _s_u_d_o_e_r_s policy + allows _u_i_ds that are not in the password database as long + as the _t_a_r_g_e_t_p_w option is not set. Other security policies + may not support this. + + -V The --VV (_v_e_r_s_i_o_n) option causes ssuuddoo to print its version + string and the version string of the security policy plugin + and any I/O plugins. If the invoking user is already root + the --VV option will display the arguments passed to + configure when _s_u_d_o was built and plugins may display more + verbose information such as default options. + + -v When given the --vv (_v_a_l_i_d_a_t_e) option, ssuuddoo will update the + user's cached credentials, authenticating the user's + password if necessary. For the _s_u_d_o_e_r_s plugin, this + extends the ssuuddoo timeout for another 5 minutes (or whatever + the timeout is set to in _s_u_d_o_e_r_s) but does not run a + command. Not all security policies support cached + credentials. + + -- The ---- option indicates that ssuuddoo should stop processing + command line arguments. + + Environment variables to be set for the command may also be passed on + the command line in the form of VVAARR=_v_a_l_u_e, e.g. + LLDD__LLIIBBRRAARRYY__PPAATTHH=_/_u_s_r_/_l_o_c_a_l_/_p_k_g_/_l_i_b. Variables passed on the command + line are subject to the same restrictions as normal environment + variables with one important exception. If the _s_e_t_e_n_v option is set in + _s_u_d_o_e_r_s, the command to be run has the SETENV tag set or the command + matched is ALL, the user may set variables that would otherwise be + forbidden. See _s_u_d_o_e_r_s(4) for more information. + +PPLLUUGGIINNSS + Plugins are dynamically loaded based on the contents of the + _/_e_t_c_/_s_u_d_o_._c_o_n_f file. If no _/_e_t_c_/_s_u_d_o_._c_o_n_f file is present, or it + contains no Plugin lines, ssuuddoo will use the traditional _s_u_d_o_e_r_s + security policy and I/O logging, which corresponds to the following + _/_e_t_c_/_s_u_d_o_._c_o_n_f file. + + # + # Default /etc/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_options ... + # Path askpass /path/to/askpass + # Path noexec /path/to/sudo_noexec.so + # Debug sudo /var/log/sudo_debug all@warn + # Set disable_coredump true + # + # The plugin_path is relative to /usr/local/libexec unless + # fully qualified. + # The plugin_name corresponds to a global symbol in the plugin + # that contains the plugin interface structure. + # The plugin_options are optional. + # + Plugin policy_plugin sudoers.so + Plugin io_plugin sudoers.so + + A Plugin line consists of the Plugin keyword, followed by the + _s_y_m_b_o_l___n_a_m_e and the _p_a_t_h to the shared object containing the plugin. + The _s_y_m_b_o_l___n_a_m_e is the name of the struct policy_plugin or struct + io_plugin in the plugin shared object. The _p_a_t_h may be fully qualified + or relative. If not fully qualified it is relative to the + _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c directory. Any additional parameters after the _p_a_t_h + are passed as arguments to the plugin's _o_p_e_n function. Lines that + don't begin with Plugin, Path, Debug or Set are silently ignored. + + For more information, see the _s_u_d_o___p_l_u_g_i_n(1m) manual. + +PPAATTHHSS + A Path line consists of the Path keyword, followed by the name of the + path to set and its value. E.g. + + Path noexec /usr/local/libexec/sudo_noexec.so + Path askpass /usr/X11R6/bin/ssh-askpass + + The following plugin-agnostic paths may be set in the _/_e_t_c_/_s_u_d_o_._c_o_n_f + file. + + askpass The fully qualified path to a helper program used to + read the user's password when no terminal is available. + This may be the case when ssuuddoo is executed from a + graphical (as opposed to text-based) application. The + program specified by _a_s_k_p_a_s_s should display the + argument passed to it as the prompt and write the + user's password to the standard output. The value of + _a_s_k_p_a_s_s may be overridden by the SUDO_ASKPASS + environment variable. + + noexec The fully-qualified path to a shared library containing + dummy versions of 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 LD_PRELOAD or its equivalent. Defaults to + _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c_/_s_u_d_o___n_o_e_x_e_c_._s_o. + +DDEEBBUUGG FFLLAAGGSS + ssuuddoo versions 1.8.4 and higher support a flexible debugging framework + that can help track down what ssuuddoo is doing internally if there is a + problem. + + A Debug line consists of the Debug keyword, followed by the name of the + program to debug (ssuuddoo, vviissuuddoo, ssuuddoorreeppllaayy), the debug file name and a + comma-separated list of debug flags. The debug flag syntax used by + ssuuddoo and the _s_u_d_o_e_r_s plugin is _s_u_b_s_y_s_t_e_m@_p_r_i_o_r_i_t_y but the plugin is + free to use a different format so long as it does not include a command + ,. + + For instance: + + Debug sudo /var/log/sudo_debug all@warn,plugin@info + + would log all debugging statements at the _w_a_r_n level and higher in + addition to those at the _i_n_f_o level for the plugin subsystem. + + Currently, only one Debug entry per program is supported. The sudo + Debug entry is shared by the ssuuddoo front end, ssuuddooeeddiitt and the plugins. + A future release may add support for per-plugin Debug lines and/or + support for multiple debugging files for a single program. + + The priorities used by the ssuuddoo front end, in order of decreasing + severity, are: _c_r_i_t, _e_r_r, _w_a_r_n, _n_o_t_i_c_e, _d_i_a_g, _i_n_f_o, _t_r_a_c_e and _d_e_b_u_g. + Each priority, when specified, also includes all priorities higher than + it. For example, a priority of _n_o_t_i_c_e would include debug messages + logged at _n_o_t_i_c_e and higher. + + The following subsystems are used by ssuuddoo: + + _a_l_l matches every subsystem + + _a_r_g_s command line argument processing + + _c_o_n_v user conversation + + _e_d_i_t sudoedit + + _e_x_e_c command execution + + _m_a_i_n ssuuddoo main function + + _n_e_t_i_f network interface handling + + _p_c_o_m_m communication with the plugin + + _p_l_u_g_i_n plugin configuration + + _p_t_y pseudo-tty related code + + _s_e_l_i_n_u_x SELinux-specific handling + + _u_t_i_l utility functions + + _u_t_m_p utmp handling + +RREETTUURRNN VVAALLUUEESS + Upon successful execution of a program, the exit status from ssuuddoo will + simply be the exit status of the program that was executed. + + Otherwise, ssuuddoo exits with a value of 1 if there is a + configuration/permission problem or if ssuuddoo cannot execute the given + command. In the latter case the error string is printed to the + standard error. If ssuuddoo cannot _s_t_a_t(2) one or more entries in the + user's PATH, an error is printed on stderr. (If the directory does not + exist or if it is not really a directory, the entry is ignored and no + error is printed.) This should not happen under normal circumstances. + The most common reason for _s_t_a_t(2) to return "permission denied" is if + you are running an automounter and one of the directories in your PATH + is on a machine that is currently unreachable. + +SSEECCUURRIITTYY NNOOTTEESS + ssuuddoo tries to be safe when executing external commands. + + To prevent command spoofing, ssuuddoo checks "." and "" (both denoting + current directory) last when searching for a command in the user's PATH + (if one or both are in the PATH). Note, however, that the actual PATH + environment variable is _n_o_t modified and is passed unchanged to the + program that ssuuddoo executes. + + Please note that ssuuddoo will normally only log the command it explicitly + runs. If a user runs a command such as sudo su or sudo sh, subsequent + commands run from that shell are not subject to ssuuddoo's security policy. + The same is true for commands that offer shell escapes (including most + editors). If I/O logging is enabled, subsequent commands will have + their input and/or output logged, but there will not be traditional + logs for those commands. Because of this, care must be taken when + giving users access to commands via ssuuddoo to verify that the command + does not inadvertently give the user an effective root shell. For more + information, please see the PREVENTING SHELL ESCAPES section in + _s_u_d_o_e_r_s(4). + + To prevent the disclosure of potentially sensitive information, ssuuddoo + disables core dumps by default while it is executing (they are re- + enabled for the command that is run). To aid in debugging ssuuddoo + crashes, you may wish to re-enable core dumps by setting + "disable_coredump" to false in the _/_e_t_c_/_s_u_d_o_._c_o_n_f file. + + Set disable_coredump false + + Note that by default, most operating systems disable core dumps from + setuid programs, which includes ssuuddoo. To actually get a ssuuddoo core file + you may need to enable core dumps for setuid processes. On BSD and + Linux systems this is accomplished via the sysctl command, on Solaris + the coreadm command can be used. + +EENNVVIIRROONNMMEENNTT + ssuuddoo utilizes the following environment variables. The security policy + has control over the content of the command's environment. + + EDITOR Default editor to use in --ee (sudoedit) mode if neither + SUDO_EDITOR nor VISUAL is set + + MAIL In --ii mode or when _e_n_v___r_e_s_e_t is enabled in _s_u_d_o_e_r_s, set + to the mail spool of the target user + + HOME Set to the home directory of the target user if --ii or + --HH are specified, _e_n_v___r_e_s_e_t or _a_l_w_a_y_s___s_e_t___h_o_m_e are set + in _s_u_d_o_e_r_s, or when the --ss option is specified and + _s_e_t___h_o_m_e is set in _s_u_d_o_e_r_s + + PATH May be overridden by the security policy. + + SHELL Used to determine shell to run with -s option + + SUDO_ASKPASS Specifies the path to a helper program used to read the + password if no terminal is available or if the -A + option is specified. + + SUDO_COMMAND Set to the command run by sudo + + SUDO_EDITOR Default editor to use in --ee (sudoedit) mode + + SUDO_GID Set to the group ID of the user who invoked sudo + + SUDO_PROMPT Used as the default password prompt + + SUDO_PS1 If set, PS1 will be set to its value for the program + being run + + SUDO_UID Set to the user ID of the user who invoked sudo + + SUDO_USER Set to the login of the user who invoked sudo + + USER Set to the target user (root unless the --uu option is + specified) + + VISUAL Default editor to use in --ee (sudoedit) mode if + SUDO_EDITOR is not set + +FFIILLEESS + _/_e_t_c_/_s_u_d_o_._c_o_n_f ssuuddoo front end configuration + +EEXXAAMMPPLLEESS + Note: the following examples assume a properly configured security + policy. + + To get a file listing of an unreadable directory: + + $ sudo ls /usr/local/protected + + To list the home directory of user yaz on a machine where the file + system holding ~yaz is not exported as root: + + $ sudo -u yaz ls ~yaz + + To edit the _i_n_d_e_x_._h_t_m_l file as user www: + + $ sudo -u www vi ~www/htdocs/index.html + + To view system logs only accessible to root and users in the adm group: + + $ sudo -g adm view /var/log/syslog + + To run an editor as jim with a different primary group: + + $ sudo -u jim -g audio vi ~jim/sound.txt + + To shutdown a machine: + + $ sudo shutdown -r +15 "quick reboot" + + To make a usage listing of the directories in the /home partition. + Note that this runs the commands in a sub-shell to make the cd and file + redirection work. + + $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE" + +SSEEEE AALLSSOO + _g_r_e_p(1), _s_u(1), _s_t_a_t(2), _l_o_g_i_n___c_a_p(3), _p_a_s_s_w_d(4), _s_u_d_o_e_r_s(4), + _s_u_d_o___p_l_u_g_i_n(1m), _s_u_d_o_r_e_p_l_a_y(1m), _v_i_s_u_d_o(1m) + +AAUUTTHHOORRSS + Many people have worked on ssuuddoo over the years; this version consists + of code written primarily by: + + Todd C. Miller + + See the CONTRIBUTORS file in the ssuuddoo distribution + (http://www.sudo.ws/sudo/contributors.html) for a list of people who + have contributed to ssuuddoo. + +HHIISSTTOORRYY + See the HISTORY file in the ssuuddoo distribution + (http://www.sudo.ws/sudo/history.html) for a brief history of sudo. + +CCAAVVEEAATTSS + There is no easy way to prevent a user from gaining a root shell if + that user is allowed to run arbitrary commands via ssuuddoo. Also, many + programs (such as editors) allow the user to run commands via shell + escapes, thus avoiding ssuuddoo's checks. However, on most systems it is + possible to prevent shell escapes with the _s_u_d_o_e_r_s(4) module's _n_o_e_x_e_c + functionality. + + It is not meaningful to run the cd command directly via sudo, e.g., + + $ sudo cd /usr/local/protected + + since when the command exits the parent process (your shell) will still + be the same. Please see the EXAMPLES section for more information. + + Running shell scripts via ssuuddoo can expose the same kernel bugs that + make setuid shell scripts unsafe on some operating systems (if your OS + has a /dev/fd/ directory, setuid shell scripts are generally safe). + +BBUUGGSS + If you feel you have found a bug in ssuuddoo, please submit a bug report at + http://www.sudo.ws/sudo/bugs/ + +SSUUPPPPOORRTT + Limited free support is available via the sudo-users mailing list, see + http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search + the archives. + +DDIISSCCLLAAIIMMEERR + ssuuddoo is provided ``AS IS'' and any express or implied warranties, + including, but not limited to, the implied warranties of + merchantability and fitness for a particular purpose are disclaimed. + See the LICENSE file distributed with ssuuddoo or + http://www.sudo.ws/sudo/license.html for complete details. + + + +1.8.5 March 15, 2012 SUDO(1m) diff --git a/doc/sudo.man.in b/doc/sudo.man.in new file mode 100644 index 0000000..856164e --- /dev/null +++ b/doc/sudo.man.in @@ -0,0 +1,893 @@ +.\" Copyright (c) 1994-1996, 1998-2005, 2007-2012 +.\" 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. +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Sponsored in part by the Defense Advanced Research Projects +.\" Agency (DARPA) and Air Force Research Laboratory, Air Force +.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. +.\" +.nr SL @SEMAN@ +.nr BA @BAMAN@ +.nr LC @LCMAN@ +.nr PT @password_timeout@ +.\" +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SUDO @mansectsu@" +.TH SUDO @mansectsu@ "March 15, 2012" "1.8.5" "MAINTENANCE COMMANDS" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +sudo, sudoedit \- execute a command as another user +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBsudo\fR \fB\-h\fR | \fB\-K\fR | \fB\-k\fR | \fB\-V\fR +.PP +\&\fBsudo\fR \fB\-v\fR [\fB\-AknS\fR] +.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] +[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] +[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] +.PP +\&\fBsudo\fR \fB\-l[l]\fR [\fB\-AknS\fR] +.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] +[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] +[\fB\-U\fR\ \fIuser\ name\fR] [\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] [\fIcommand\fR] +.PP +\&\fBsudo\fR [\fB\-AbEHnPS\fR] +.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] +[\fB\-C\fR\ \fIfd\fR] +.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR] +[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] +.if \n(SL [\fB\-r\fR\ \fIrole\fR] [\fB\-t\fR\ \fItype\fR] +[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] +[\fB\s-1VAR\s0\fR=\fIvalue\fR] [\fB\-i\fR\ |\ \fB\-s\fR] [\fIcommand\fR] +.PP +\&\fBsudoedit\fR [\fB\-AnS\fR] +.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] +[\fB\-C\fR\ \fIfd\fR] +.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR] +[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] +[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] file ... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBsudo\fR allows a permitted user to execute a \fIcommand\fR as the +superuser or another user, as specified by the security policy. +The real and effective uid and gid are set to match those of the +target user, as specified in the password database, and the group +vector is initialized based on the group database (unless the \fB\-P\fR +option was specified). +.PP +\&\fBsudo\fR supports a plugin architecture for security policies and +input/output logging. Third parties can develop and distribute +their own policy and I/O logging modules to work seamlessly with +the \fBsudo\fR front end. The default security policy is \fIsudoers\fR, +which is configured via the file \fI@sysconfdir@/sudoers\fR, or via +\&\s-1LDAP\s0. See the \s-1PLUGINS\s0 section for more information. +.PP +The security policy determines what privileges, if any, a user has +to run \fBsudo\fR. The policy may require that users authenticate +themselves with a password or another authentication mechanism. If +authentication is required, \fBsudo\fR will exit if the user's password +is not entered within a configurable time limit. This limit is +policy-specific; the default password prompt timeout for the +\&\fIsudoers\fR security policy is +.ie \n(PT \f(CW\*(C`@password_timeout@\*(C'\fR minutes. +.el unlimited. +.PP +Security policies may support credential caching to allow the user +to run \fBsudo\fR again for a period of time without requiring +authentication. The \fIsudoers\fR policy caches credentials for +\&\f(CW\*(C`@timeout@\*(C'\fR minutes, unless overridden in \fIsudoers\fR\|(@mansectform@). By +running \fBsudo\fR with the \fB\-v\fR option, a user can update the cached +credentials without running a \fIcommand\fR. +.PP +When invoked as \fBsudoedit\fR, the \fB\-e\fR option (described below), +is implied. +.PP +Security policies may log successful and failed attempts to use +\&\fBsudo\fR. If an I/O plugin is configured, the running command's +input and output may be logged as well. +.SH "OPTIONS" +.IX Header "OPTIONS" +\&\fBsudo\fR accepts the following command line options: +.IP "\-A" 12 +.IX Item "-A" +Normally, if \fBsudo\fR requires a password, it will read it from the +user's terminal. If the \fB\-A\fR (\fIaskpass\fR) option is specified, +a (possibly graphical) helper program is executed to read the user's +password and output the password to the standard output. If the +\&\f(CW\*(C`SUDO_ASKPASS\*(C'\fR environment variable is set, it specifies the path +to the helper program. Otherwise, if \fI@sysconfdir@/sudo.conf\fR +contains a line specifying the askpass program, that value will be +used. For example: +.Sp +.Vb 2 +\& # Path to askpass helper program +\& Path askpass /usr/X11R6/bin/ssh\-askpass +.Ve +.Sp +If no askpass program is available, sudo will exit with an error. +.if \n(BA \{\ +.IP "\-a \fItype\fR" 12 +.IX Item "-a type" +The \fB\-a\fR (\fIauthentication type\fR) option causes \fBsudo\fR to use the +specified authentication type when validating the user, as allowed +by \fI/etc/login.conf\fR. The system administrator may specify a list +of sudo-specific authentication methods by adding an \*(L"auth-sudo\*(R" +entry in \fI/etc/login.conf\fR. This option is only available on systems +that support \s-1BSD\s0 authentication. +\} +.IP "\-b" 12 +.IX Item "-b" +The \fB\-b\fR (\fIbackground\fR) option tells \fBsudo\fR to run the given +command in the background. Note that if you use the \fB\-b\fR +option you cannot use shell job control to manipulate the process. +Most interactive commands will fail to work properly in background +mode. +.IP "\-C \fIfd\fR" 12 +.IX Item "-C fd" +Normally, \fBsudo\fR will close all open file descriptors other than +standard input, standard output and standard error. The \fB\-C\fR +(\fIclose from\fR) option allows the user to specify a starting point +above the standard error (file descriptor three). Values less than +three are not permitted. The security policy may restrict the +user's ability to use the \fB\-C\fR option. The \fIsudoers\fR policy only +permits use of the \fB\-C\fR option when the administrator has enabled +the \fIclosefrom_override\fR option. +.if \n(LC \{\ +.IP "\-c \fIclass\fR" 12 +.IX Item "-c class" +The \fB\-c\fR (\fIclass\fR) option causes \fBsudo\fR to run the specified command +with resources limited by the specified login class. The \fIclass\fR +argument can be either a class name as defined in \fI/etc/login.conf\fR, +or a single '\-' character. Specifying a \fIclass\fR of \f(CW\*(C`\-\*(C'\fR indicates +that the command should be run restricted by the default login +capabilities for the user the command is run as. If the \fIclass\fR +argument specifies an existing user class, the command must be run +as root, or the \fBsudo\fR command must be run from a shell that is already +root. This option is only available on systems with \s-1BSD\s0 login classes. +\} +.IP "\-E" 12 +.IX Item "-E" +The \fB\-E\fR (\fIpreserve\fR \fIenvironment\fR) option indicates to the +security policy that the user wishes to preserve their existing +environment variables. The security policy may return an error if +the \fB\-E\fR option is specified and the user does not have permission +to preserve the environment. +.IP "\-e" 12 +.IX Item "-e" +The \fB\-e\fR (\fIedit\fR) option indicates that, instead of running a +command, the user wishes to edit one or more files. In lieu of a +command, the string \*(L"sudoedit\*(R" is used when consulting the security +policy. If the user is authorized by the policy, the following +steps are taken: +.RS 12 +.IP "1." 4 +Temporary copies are made of the files to be edited with the owner +set to the invoking user. +.IP "2." 4 +The editor specified by the policy is run to edit the temporary files. +The \fIsudoers\fR policy uses the \f(CW\*(C`SUDO_EDITOR\*(C'\fR, \f(CW\*(C`VISUAL\*(C'\fR and \f(CW\*(C`EDITOR\*(C'\fR +environment variables (in that order). If none of \f(CW\*(C`SUDO_EDITOR\*(C'\fR, +\&\f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR are set, the first program listed in the +\&\fIeditor\fR \fIsudoers\fR\|(@mansectform@) option is used. +.IP "3." 4 +If they have been modified, the temporary files are copied back to +their original location and the temporary versions are removed. +.RE +.RS 12 +.Sp +If the specified file does not exist, it will be created. Note +that unlike most commands run by \fBsudo\fR, the editor is run with +the invoking user's environment unmodified. If, for some reason, +\&\fBsudo\fR is unable to update a file with its edited version, the +user will receive a warning and the edited copy will remain in a +temporary file. +.RE +.IP "\-g \fIgroup\fR" 12 +.IX Item "-g group" +Normally, \fBsudo\fR runs a command with the primary group set to the +one specified by the password database for the user the command is +being run as (by default, root). The \fB\-g\fR (\fIgroup\fR) option causes +\&\fBsudo\fR to run the command with the primary group set to \fIgroup\fR +instead. To specify a \fIgid\fR instead of a \fIgroup name\fR, use +\&\fI#gid\fR. When running commands as a \fIgid\fR, many shells require +that the '#' be escaped with a backslash ('\e'). If no \fB\-u\fR option +is specified, the command will be run as the invoking user (not +root). In either case, the primary group will be set to \fIgroup\fR. +.IP "\-H" 12 +.IX Item "-H" +The \fB\-H\fR (\fI\s-1HOME\s0\fR) option requests that the security policy set +the \f(CW\*(C`HOME\*(C'\fR environment variable to the home directory of the target +user (root by default) as specified by the password database. +Depending on the policy, this may be the default behavior. +.IP "\-h" 12 +.IX Item "-h" +The \fB\-h\fR (\fIhelp\fR) option causes \fBsudo\fR to print a short help message +to the standard output and exit. +.IP "\-i [command]" 12 +.IX Item "-i [command]" +The \fB\-i\fR (\fIsimulate initial login\fR) option runs the shell specified +by the password database entry of the target user as a login shell. +This means that login-specific resource files such as \f(CW\*(C`.profile\*(C'\fR +or \f(CW\*(C`.login\*(C'\fR will be read by the shell. If a command is specified, +it is passed to the shell for execution via the shell's \fB\-c\fR option. +If no command is specified, an interactive shell is executed. +\&\fBsudo\fR attempts to change to that user's home directory before +running the shell. The security policy shall initialize the +environment to a minimal set of variables, similar to what is present +when a user logs in. The \fICommand Environment\fR section in the +\&\fIsudoers\fR\|(@mansectform@) manual documents how the \fB\-i\fR option affects the +environment in which a command is run when the \fIsudoers\fR policy +is in use. +.IP "\-K" 12 +.IX Item "-K" +The \fB\-K\fR (sure \fIkill\fR) option is like \fB\-k\fR except that it removes +the user's cached credentials entirely and may not be used in +conjunction with a command or other option. This option does not +require a password. Not all security policies support credential +caching. +.IP "\-k [command]" 12 +.IX Item "-k [command]" +When used alone, the \fB\-k\fR (\fIkill\fR) option to \fBsudo\fR invalidates +the user's cached credentials. The next time \fBsudo\fR is run a +password will be required. This option does not require a password +and was added to allow a user to revoke \fBsudo\fR permissions from a +\&.logout file. Not all security policies support credential +caching. +.Sp +When used in conjunction with a command or an option that may require +a password, the \fB\-k\fR option will cause \fBsudo\fR to ignore the user's +cached credentials. As a result, \fBsudo\fR will prompt for a password +(if one is required by the security policy) and will not update the +user's cached credentials. +.IP "\-l[l] [\fIcommand\fR]" 12 +.IX Item "-l[l] [command]" +If no \fIcommand\fR is specified, the \fB\-l\fR (\fIlist\fR) option will list +the allowed (and forbidden) commands for the invoking user (or the +user specified by the \fB\-U\fR option) on the current host. If a +\&\fIcommand\fR is specified and is permitted by the security policy, +the fully-qualified path to the command is displayed along with any +command line arguments. If \fIcommand\fR is specified but not allowed, +\&\fBsudo\fR will exit with a status value of 1. If the \fB\-l\fR option +is specified with an \fBl\fR argument (i.e. \fB\-ll\fR), or if \fB\-l\fR is +specified multiple times, a longer list format is used. +.IP "\-n" 12 +.IX Item "-n" +The \fB\-n\fR (\fInon-interactive\fR) option prevents \fBsudo\fR from prompting +the user for a password. If a password is required for the command +to run, \fBsudo\fR will display an error messages and exit. +.IP "\-P" 12 +.IX Item "-P" +The \fB\-P\fR (\fIpreserve\fR \fIgroup vector\fR) option causes \fBsudo\fR to +preserve the invoking user's group vector unaltered. By default, +the \fIsudoers\fR policy will initialize the group vector to the list +of groups the target user is in. The real and effective group IDs, +however, are still set to match the target user. +.IP "\-p \fIprompt\fR" 12 +.IX Item "-p prompt" +The \fB\-p\fR (\fIprompt\fR) option allows you to override the default +password prompt and use a custom one. The following percent (`\f(CW\*(C`%\*(C'\fR') +escapes are supported by the \fIsudoers\fR policy: +.RS 12 +.ie n .IP "%H" 4 +.el .IP "\f(CW%H\fR" 4 +.IX Item "%H" +expanded to the host name including the domain name (on if +the machine's host name is fully qualified or the \fIfqdn\fR option +is set in \fIsudoers\fR\|(@mansectform@)) +.ie n .IP "%h" 4 +.el .IP "\f(CW%h\fR" 4 +.IX Item "%h" +expanded to the local host name without the domain name +.ie n .IP "%p" 4 +.el .IP "\f(CW%p\fR" 4 +.IX Item "%p" +expanded to the name of the user whose password is being requested +(respects the \fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in +\&\fIsudoers\fR\|(@mansectform@)) +.ie n .IP "%U" 4 +.el .IP "\f(CW%U\fR" 4 +.IX Item "%U" +expanded to the login name of the user the command will be run as +(defaults to root unless the \f(CW\*(C`\-u\*(C'\fR option is also specified) +.ie n .IP "%u" 4 +.el .IP "\f(CW%u\fR" 4 +.IX Item "%u" +expanded to the invoking user's login name +.ie n .IP "\*(C`%%\*(C'" 4 +.el .IP "\f(CW\*(C`%%\*(C'\fR" 4 +.IX Item "%%" +two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character +.RE +.RS 12 +.Sp +The prompt specified by the \fB\-p\fR option will override the system +password prompt on systems that support \s-1PAM\s0 unless the +\&\fIpassprompt_override\fR flag is disabled in \fIsudoers\fR. +.RE +.if \n(SL \{\ +.IP "\-r \fIrole\fR" 12 +.IX Item "-r role" +The \fB\-r\fR (\fIrole\fR) option causes the new (SELinux) security context to +have the role specified by \fIrole\fR. +\} +.IP "\-S" 12 +.IX Item "-S" +The \fB\-S\fR (\fIstdin\fR) option causes \fBsudo\fR to read the password from +the standard input instead of the terminal device. The password must +be followed by a newline character. +.IP "\-s [command]" 12 +.IX Item "-s [command]" +The \fB\-s\fR (\fIshell\fR) option runs the shell specified by the \fI\s-1SHELL\s0\fR +environment variable if it is set or the shell as specified in the +password database. If a command is specified, it is passed to the +shell for execution via the shell's \fB\-c\fR option. If no command +is specified, an interactive shell is executed. +.if \n(SL \{\ +.IP "\-t \fItype\fR" 12 +.IX Item "-t type" +The \fB\-t\fR (\fItype\fR) option causes the new (SELinux) security context to +have the type specified by \fItype\fR. If no type is specified, the default +type is derived from the specified role. +\} +.IP "\-U \fIuser\fR" 12 +.IX Item "-U user" +The \fB\-U\fR (\fIother user\fR) option is used in conjunction with the +\&\fB\-l\fR option to specify the user whose privileges should be listed. +The security policy may restrict listing other users' privileges. +The \fIsudoers\fR policy only allows root or a user with the \f(CW\*(C`ALL\*(C'\fR +privilege on the current host to use this option. +.IP "\-u \fIuser\fR" 12 +.IX Item "-u user" +The \fB\-u\fR (\fIuser\fR) option causes \fBsudo\fR to run the specified +command as a user other than \fIroot\fR. To specify a \fIuid\fR instead +of a \fIuser name\fR, use \fI#uid\fR. When running commands as a \fIuid\fR, +many shells require that the '#' be escaped with a backslash ('\e'). +Security policies may restrict \fIuid\fRs to those listed in the +password database. The \fIsudoers\fR policy allows \fIuid\fRs that are +not in the password database as long as the \fItargetpw\fR option is +not set. Other security policies may not support this. +.IP "\-V" 12 +.IX Item "-V" +The \fB\-V\fR (\fIversion\fR) option causes \fBsudo\fR to print its version +string and the version string of the security policy plugin and any +I/O plugins. If the invoking user is already root the \fB\-V\fR option +will display the arguments passed to configure when \fIsudo\fR was +built and plugins may display more verbose information such as +default options. +.IP "\-v" 12 +.IX Item "-v" +When given the \fB\-v\fR (\fIvalidate\fR) option, \fBsudo\fR will update the +user's cached credentials, authenticating the user's password if +necessary. For the \fIsudoers\fR plugin, this extends the \fBsudo\fR +timeout for another \f(CW\*(C`@timeout@\*(C'\fR minutes (or whatever the timeout +is set to in \fIsudoers\fR) but does not run a command. Not all +security policies support cached credentials. +.IP "\-\-" 12 +The \fB\-\-\fR option indicates that \fBsudo\fR should stop processing command +line arguments. +.PP +Environment variables to be set for the command may also be passed +on the command line in the form of \fB\s-1VAR\s0\fR=\fIvalue\fR, e.g. +\&\fB\s-1LD_LIBRARY_PATH\s0\fR=\fI/usr/local/pkg/lib\fR. Variables passed on the +command line are subject to the same restrictions as normal environment +variables with one important exception. If the \fIsetenv\fR option +is set in \fIsudoers\fR, the command to be run has the \f(CW\*(C`SETENV\*(C'\fR tag +set or the command matched is \f(CW\*(C`ALL\*(C'\fR, the user may set variables +that would otherwise be forbidden. See \fIsudoers\fR\|(@mansectform@) for more information. +.SH "PLUGINS" +.IX Header "PLUGINS" +Plugins are dynamically loaded based on the contents of the +\&\fI@sysconfdir@/sudo.conf\fR file. If no \fI@sysconfdir@/sudo.conf\fR +file is present, or it contains no \f(CW\*(C`Plugin\*(C'\fR lines, \fBsudo\fR +will use the traditional \fIsudoers\fR security policy and I/O logging, +which corresponds to the following \fI@sysconfdir@/sudo.conf\fR file. +.PP +.Vb 10 +\& # +\& # Default @sysconfdir@/sudo.conf file +\& # +\& # Format: +\& # Plugin plugin_name plugin_path plugin_options ... +\& # Path askpass /path/to/askpass +\& # Path noexec /path/to/sudo_noexec.so +\& # Debug sudo /var/log/sudo_debug all@warn +\& # Set disable_coredump true +\& # +\& # The plugin_path is relative to @prefix@/libexec unless +\& # fully qualified. +\& # The plugin_name corresponds to a global symbol in the plugin +\& # that contains the plugin interface structure. +\& # The plugin_options are optional. +\& # +\& Plugin policy_plugin sudoers.so +\& Plugin io_plugin sudoers.so +.Ve +.PP +A \f(CW\*(C`Plugin\*(C'\fR line consists of the \f(CW\*(C`Plugin\*(C'\fR keyword, followed by the +\&\fIsymbol_name\fR and the \fIpath\fR to the shared object containing the +plugin. The \fIsymbol_name\fR is the name of the \f(CW\*(C`struct policy_plugin\*(C'\fR +or \f(CW\*(C`struct io_plugin\*(C'\fR in the plugin shared object. The \fIpath\fR +may be fully qualified or relative. If not fully qualified it is +relative to the \fI@prefix@/libexec\fR directory. Any additional +parameters after the \fIpath\fR are passed as arguments to the plugin's +\&\fIopen\fR function. Lines that don't begin with \f(CW\*(C`Plugin\*(C'\fR, \f(CW\*(C`Path\*(C'\fR, +\&\f(CW\*(C`Debug\*(C'\fR or \f(CW\*(C`Set\*(C'\fR are silently ignored. +.PP +For more information, see the \fIsudo_plugin\fR\|(@mansectsu@) manual. +.SH "PATHS" +.IX Header "PATHS" +A \f(CW\*(C`Path\*(C'\fR line consists of the \f(CW\*(C`Path\*(C'\fR keyword, followed by the +name of the path to set and its value. E.g. +.PP +.Vb 2 +\& Path noexec @noexec_file@ +\& Path askpass /usr/X11R6/bin/ssh\-askpass +.Ve +.PP +The following plugin-agnostic paths may be set in the +\&\fI@sysconfdir@/sudo.conf\fR file. +.IP "askpass" 16 +.IX Item "askpass" +The fully qualified path to a helper program used to read the user's +password when no terminal is available. This may be the case when +\&\fBsudo\fR is executed from a graphical (as opposed to text-based) +application. The program specified by \fIaskpass\fR should display +the argument passed to it as the prompt and write the user's password +to the standard output. The value of \fIaskpass\fR may be overridden +by the \f(CW\*(C`SUDO_ASKPASS\*(C'\fR environment variable. +.IP "noexec" 16 +.IX Item "noexec" +The fully-qualified path to a shared library containing dummy +versions of the \fIexecv()\fR, \fIexecve()\fR and \fIfexecve()\fR library functions +that just return an error. This is used to implement the \fInoexec\fR +functionality on systems that support \f(CW\*(C`LD_PRELOAD\*(C'\fR or its equivalent. +Defaults to \fI@noexec_file@\fR. +.SH "DEBUG FLAGS" +.IX Header "DEBUG FLAGS" +\&\fBsudo\fR versions 1.8.4 and higher support a flexible debugging +framework that can help track down what \fBsudo\fR is doing internally +if there is a problem. +.PP +A \f(CW\*(C`Debug\*(C'\fR line consists of the \f(CW\*(C`Debug\*(C'\fR keyword, followed by the +name of the program to debug (\fBsudo\fR, \fBvisudo\fR, \fBsudoreplay\fR), +the debug file name and a comma-separated list of debug flags. +The debug flag syntax used by \fBsudo\fR and the \fIsudoers\fR plugin is +\&\fIsubsystem\fR@\fIpriority\fR but the plugin is free to use a different +format so long as it does not include a command \f(CW\*(C`,\*(C'\fR. +.PP +For instance: +.PP +.Vb 1 +\& Debug sudo /var/log/sudo_debug all@warn,plugin@info +.Ve +.PP +would log all debugging statements at the \fIwarn\fR level and higher +in addition to those at the \fIinfo\fR level for the plugin subsystem. +.PP +Currently, only one \f(CW\*(C`Debug\*(C'\fR entry per program is supported. The +\&\f(CW\*(C`sudo\*(C'\fR \f(CW\*(C`Debug\*(C'\fR entry is shared by the \fBsudo\fR front end, \fBsudoedit\fR +and the plugins. A future release may add support for per-plugin +\&\f(CW\*(C`Debug\*(C'\fR lines and/or support for multiple debugging files for a +single program. +.PP +The priorities used by the \fBsudo\fR front end, in order of decreasing +severity, are: \fIcrit\fR, \fIerr\fR, \fIwarn\fR, \fInotice\fR, \fIdiag\fR, \fIinfo\fR, +\&\fItrace\fR and \fIdebug\fR. Each priority, when specified, also includes +all priorities higher than it. For example, a priority of \fInotice\fR +would include debug messages logged at \fInotice\fR and higher. +.PP +The following subsystems are used by \fBsudo\fR: +.IP "\fIall\fR" 10 +.IX Item "all" +matches every subsystem +.IP "\fIargs\fR" 10 +.IX Item "args" +command line argument processing +.IP "\fIconv\fR" 10 +.IX Item "conv" +user conversation +.IP "\fIedit\fR" 10 +.IX Item "edit" +sudoedit +.IP "\fIexec\fR" 10 +.IX Item "exec" +command execution +.IP "\fImain\fR" 10 +.IX Item "main" +\&\fBsudo\fR main function +.IP "\fInetif\fR" 10 +.IX Item "netif" +network interface handling +.IP "\fIpcomm\fR" 10 +.IX Item "pcomm" +communication with the plugin +.IP "\fIplugin\fR" 10 +.IX Item "plugin" +plugin configuration +.IP "\fIpty\fR" 10 +.IX Item "pty" +pseudo-tty related code +.IP "\fIselinux\fR" 10 +.IX Item "selinux" +SELinux-specific handling +.IP "\fIutil\fR" 10 +.IX Item "util" +utility functions +.IP "\fIutmp\fR" 10 +.IX Item "utmp" +utmp handling +.SH "RETURN VALUES" +.IX Header "RETURN VALUES" +Upon successful execution of a program, the exit status from \fBsudo\fR +will simply be the exit status of the program that was executed. +.PP +Otherwise, \fBsudo\fR exits with a value of 1 if there is a +configuration/permission problem or if \fBsudo\fR cannot execute the +given command. In the latter case the error string is printed to +the standard error. If \fBsudo\fR cannot \fIstat\fR\|(2) one or more entries +in the user's \f(CW\*(C`PATH\*(C'\fR, an error is printed on stderr. (If the +directory does not exist or if it is not really a directory, the +entry is ignored and no error is printed.) This should not happen +under normal circumstances. The most common reason for \fIstat\fR\|(2) +to return \*(L"permission denied\*(R" is if you are running an automounter +and one of the directories in your \f(CW\*(C`PATH\*(C'\fR is on a machine that is +currently unreachable. +.SH "SECURITY NOTES" +.IX Header "SECURITY NOTES" +\&\fBsudo\fR tries to be safe when executing external commands. +.PP +To prevent command spoofing, \fBsudo\fR checks \*(L".\*(R" and "" (both denoting +current directory) last when searching for a command in the user's +\&\s-1PATH\s0 (if one or both are in the \s-1PATH\s0). Note, however, that the +actual \f(CW\*(C`PATH\*(C'\fR environment variable is \fInot\fR modified and is passed +unchanged to the program that \fBsudo\fR executes. +.PP +Please note that \fBsudo\fR will normally only log the command it +explicitly runs. If a user runs a command such as \f(CW\*(C`sudo su\*(C'\fR or +\&\f(CW\*(C`sudo sh\*(C'\fR, subsequent commands run from that shell are not subject +to \fBsudo\fR's security policy. The same is true for commands that +offer shell escapes (including most editors). If I/O logging is +enabled, subsequent commands will have their input and/or output +logged, but there will not be traditional logs for those commands. +Because of this, care must be taken when giving users access to +commands via \fBsudo\fR to verify that the command does not inadvertently +give the user an effective root shell. For more information, please +see the \f(CW\*(C`PREVENTING SHELL ESCAPES\*(C'\fR section in \fIsudoers\fR\|(@mansectform@). +.PP +To prevent the disclosure of potentially sensitive information, +\&\fBsudo\fR disables core dumps by default while it is executing (they +are re-enabled for the command that is run). To aid in debugging +\&\fBsudo\fR crashes, you may wish to re-enable core dumps by setting +\&\*(L"disable_coredump\*(R" to false in the \fI@sysconfdir@/sudo.conf\fR file. +.PP +.Vb 1 +\& Set disable_coredump false +.Ve +.PP +Note that by default, most operating systems disable core dumps +from setuid programs, which includes \fBsudo\fR. To actually get a +\&\fBsudo\fR core file you may need to enable core dumps for setuid +processes. On \s-1BSD\s0 and Linux systems this is accomplished via the +sysctl command, on Solaris the coreadm command can be used. +.SH "ENVIRONMENT" +.IX Header "ENVIRONMENT" +\&\fBsudo\fR utilizes the following environment variables. The security +policy has control over the content of the command's environment. +.ie n .IP "\*(C`EDITOR\*(C'" 16 +.el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16 +.IX Item "EDITOR" +Default editor to use in \fB\-e\fR (sudoedit) mode if neither \f(CW\*(C`SUDO_EDITOR\*(C'\fR +nor \f(CW\*(C`VISUAL\*(C'\fR is set +.ie n .IP "\*(C`MAIL\*(C'" 16 +.el .IP "\f(CW\*(C`MAIL\*(C'\fR" 16 +.IX Item "MAIL" +In \fB\-i\fR mode or when \fIenv_reset\fR is enabled in \fIsudoers\fR, set +to the mail spool of the target user +.ie n .IP "\*(C`HOME\*(C'" 16 +.el .IP "\f(CW\*(C`HOME\*(C'\fR" 16 +.IX Item "HOME" +Set to the home directory of the target user if \fB\-i\fR or \fB\-H\fR are +specified, \fIenv_reset\fR or \fIalways_set_home\fR are set in \fIsudoers\fR, +or when the \fB\-s\fR option is specified and \fIset_home\fR is set in +\&\fIsudoers\fR +.ie n .IP "\*(C`PATH\*(C'" 16 +.el .IP "\f(CW\*(C`PATH\*(C'\fR" 16 +.IX Item "PATH" +May be overridden by the security policy. +.ie n .IP "\*(C`SHELL\*(C'" 16 +.el .IP "\f(CW\*(C`SHELL\*(C'\fR" 16 +.IX Item "SHELL" +Used to determine shell to run with \f(CW\*(C`\-s\*(C'\fR option +.ie n .IP "\*(C`SUDO_ASKPASS\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_ASKPASS\*(C'\fR" 16 +.IX Item "SUDO_ASKPASS" +Specifies the path to a helper program used to read the password +if no terminal is available or if the \f(CW\*(C`\-A\*(C'\fR option is specified. +.ie n .IP "\*(C`SUDO_COMMAND\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_COMMAND\*(C'\fR" 16 +.IX Item "SUDO_COMMAND" +Set to the command run by sudo +.ie n .IP "\*(C`SUDO_EDITOR\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_EDITOR\*(C'\fR" 16 +.IX Item "SUDO_EDITOR" +Default editor to use in \fB\-e\fR (sudoedit) mode +.ie n .IP "\*(C`SUDO_GID\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_GID\*(C'\fR" 16 +.IX Item "SUDO_GID" +Set to the group \s-1ID\s0 of the user who invoked sudo +.ie n .IP "\*(C`SUDO_PROMPT\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_PROMPT\*(C'\fR" 16 +.IX Item "SUDO_PROMPT" +Used as the default password prompt +.ie n .IP "\*(C`SUDO_PS1\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_PS1\*(C'\fR" 16 +.IX Item "SUDO_PS1" +If set, \f(CW\*(C`PS1\*(C'\fR will be set to its value for the program being run +.ie n .IP "\*(C`SUDO_UID\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_UID\*(C'\fR" 16 +.IX Item "SUDO_UID" +Set to the user \s-1ID\s0 of the user who invoked sudo +.ie n .IP "\*(C`SUDO_USER\*(C'" 16 +.el .IP "\f(CW\*(C`SUDO_USER\*(C'\fR" 16 +.IX Item "SUDO_USER" +Set to the login of the user who invoked sudo +.ie n .IP "\*(C`USER\*(C'" 16 +.el .IP "\f(CW\*(C`USER\*(C'\fR" 16 +.IX Item "USER" +Set to the target user (root unless the \fB\-u\fR option is specified) +.ie n .IP "\*(C`VISUAL\*(C'" 16 +.el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16 +.IX Item "VISUAL" +Default editor to use in \fB\-e\fR (sudoedit) mode if \f(CW\*(C`SUDO_EDITOR\*(C'\fR +is not set +.SH "FILES" +.IX Header "FILES" +.ie n .IP "\fI@sysconfdir@/sudo.conf\fR" 24 +.el .IP "\fI@sysconfdir@/sudo.conf\fR" 24 +.IX Item "@sysconfdir@/sudo.conf" +\&\fBsudo\fR front end configuration +.SH "EXAMPLES" +.IX Header "EXAMPLES" +Note: the following examples assume a properly configured security policy. +.PP +To get a file listing of an unreadable directory: +.PP +.Vb 1 +\& $ sudo ls /usr/local/protected +.Ve +.PP +To list the home directory of user yaz on a machine where the +file system holding ~yaz is not exported as root: +.PP +.Vb 1 +\& $ sudo \-u yaz ls ~yaz +.Ve +.PP +To edit the \fIindex.html\fR file as user www: +.PP +.Vb 1 +\& $ sudo \-u www vi ~www/htdocs/index.html +.Ve +.PP +To view system logs only accessible to root and users in the adm group: +.PP +.Vb 1 +\& $ sudo \-g adm view /var/log/syslog +.Ve +.PP +To run an editor as jim with a different primary group: +.PP +.Vb 1 +\& $ sudo \-u jim \-g audio vi ~jim/sound.txt +.Ve +.PP +To shutdown a machine: +.PP +.Vb 1 +\& $ sudo shutdown \-r +15 "quick reboot" +.Ve +.PP +To make a usage listing of the directories in the /home +partition. Note that this runs the commands in a sub-shell +to make the \f(CW\*(C`cd\*(C'\fR and file redirection work. +.PP +.Vb 1 +\& $ sudo sh \-c "cd /home ; du \-s * | sort \-rn > USAGE" +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIgrep\fR\|(1), \fIsu\fR\|(1), \fIstat\fR\|(2), +.if \n(LC \&\fIlogin_cap\fR\|(3), +\&\fIpasswd\fR\|(@mansectform@), \fIsudoers\fR\|(@mansectform@), \fIsudo_plugin\fR\|(@mansectsu@), \fIsudoreplay\fR\|(@mansectsu@), \fIvisudo\fR\|(@mansectsu@) +.SH "AUTHORS" +.IX Header "AUTHORS" +Many people have worked on \fBsudo\fR over the years; this +version consists of code written primarily by: +.PP +.Vb 1 +\& Todd C. Miller +.Ve +.PP +See the \s-1CONTRIBUTORS\s0 file in the \fBsudo\fR distribution +(http://www.sudo.ws/sudo/contributors.html) for a list of people +who have contributed to \fBsudo\fR. +.SH "HISTORY" +.IX Header "HISTORY" +See the \s-1HISTORY\s0 file in the \fBsudo\fR distribution +(http://www.sudo.ws/sudo/history.html) for a brief history of sudo. +.SH "CAVEATS" +.IX Header "CAVEATS" +There is no easy way to prevent a user from gaining a root shell +if that user is allowed to run arbitrary commands via \fBsudo\fR. +Also, many programs (such as editors) allow the user to run commands +via shell escapes, thus avoiding \fBsudo\fR's checks. However, on +most systems it is possible to prevent shell escapes with the +\&\fIsudoers\fR\|(@mansectform@) module's \fInoexec\fR functionality. +.PP +It is not meaningful to run the \f(CW\*(C`cd\*(C'\fR command directly via sudo, e.g., +.PP +.Vb 1 +\& $ sudo cd /usr/local/protected +.Ve +.PP +since when the command exits the parent process (your shell) will +still be the same. Please see the \s-1EXAMPLES\s0 section for more information. +.PP +Running shell scripts via \fBsudo\fR can expose the same kernel bugs that +make setuid shell scripts unsafe on some operating systems (if your \s-1OS\s0 +has a /dev/fd/ directory, setuid shell scripts are generally safe). +.SH "BUGS" +.IX Header "BUGS" +If you feel you have found a bug in \fBsudo\fR, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ +.SH "SUPPORT" +.IX Header "SUPPORT" +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or +search the archives. +.SH "DISCLAIMER" +.IX Header "DISCLAIMER" +\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 +file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudo.man.pl b/doc/sudo.man.pl new file mode 100644 index 0000000..e8e6125 --- /dev/null +++ b/doc/sudo.man.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl -p + +BEGIN { + %tags = ( 'a', 'BA', 'c', 'LC', 'r', 'SL', 't', 'SL'); + $cond = -1; +} + +# Initialize the numeric register we use for conditionals +if ($cond == -1) { + $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.nr PT \@password_timeout\@\n.\\\"\n$_"; + $cond = 0; +} + +# Add conditionals +if (/^\.IP.*-([acrt])/) { + $_ = ".if \\n($tags{$1} \\{\\\n$_"; + $cond = 1; +} elsif ($cond && /^\.(Sh|SS|IP|PP)/) { + $_ = "\\}\n$_"; + $cond = 0; +} + +if (/-a.*auth_type/) { + $_ = ".if \\n($tags{'a'} $_"; +} elsif (/(-c.*class.*\||login_cap)/) { + $_ = ".if \\n($tags{'c'} $_"; +} elsif (/-r.*role.*-t.*type/) { + $_ = ".if \\n($tags{'r'} $_"; +} + +# Fix up broken pod2man formatting of F<@foo@/bar> +s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g; + +# Try to deal sensibly with password_timeout being set to 0 by default +s/([^ ]*\@password_timeout\@[^ ]* minutes.$)/\n.ie \\n(PT $1\n.el unlimited./; diff --git a/doc/sudo.pod b/doc/sudo.pod new file mode 100644 index 0000000..b9f7578 --- /dev/null +++ b/doc/sudo.pod @@ -0,0 +1,807 @@ +Copyright (c) 1994-1996, 1998-2005, 2007-2012 + 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. +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +=pod + +=head1 NAME + +sudo, sudoedit - execute a command as another user + +=head1 SYNOPSIS + +B B<-h> | B<-K> | B<-k> | B<-V> + +B B<-v> [B<-AknS>] +S<[B<-a> I]> +S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-u> I|I<#uid>]> + +B B<-l[l]> [B<-AknS>] +S<[B<-a> I]> +S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-U> I]> S<[B<-u> I|I<#uid>]> [I] + +B [B<-AbEHnPS>] +S<[B<-a> I]> +S<[B<-C> I]> +S<[B<-c> I|I<->]> +S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-r> I]> S<[B<-t> I]> +S<[B<-u> I|I<#uid>]> +S<[B=I]> S<[B<-i> | B<-s>]> [I] + +B [B<-AnS>] +S<[B<-a> I]> +S<[B<-C> I]> +S<[B<-c> I|I<->]> +S<[B<-g> I|I<#gid>]> S<[B<-p> I]> +S<[B<-u> I|I<#uid>]> file ... + +=head1 DESCRIPTION + +B allows a permitted user to execute a I as the +superuser or another user, as specified by the security policy. +The real and effective uid and gid are set to match those of the +target user, as specified in the password database, and the group +vector is initialized based on the group database (unless the B<-P> +option was specified). + +B supports a plugin architecture for security policies and +input/output logging. Third parties can develop and distribute +their own policy and I/O logging modules to work seamlessly with +the B front end. The default security policy is I, +which is configured via the file F<@sysconfdir@/sudoers>, or via +LDAP. See the L section for more information. + +The security policy determines what privileges, if any, a user has +to run B. The policy may require that users authenticate +themselves with a password or another authentication mechanism. If +authentication is required, B will exit if the user's password +is not entered within a configurable time limit. This limit is +policy-specific; the default password prompt timeout for the +I security policy is C<@password_timeout@> minutes. + +Security policies may support credential caching to allow the user +to run B again for a period of time without requiring +authentication. The I policy caches credentials for +C<@timeout@> minutes, unless overridden in L. By +running B with the B<-v> option, a user can update the cached +credentials without running a I. + +When invoked as B, the B<-e> option (described below), +is implied. + +Security policies may log successful and failed attempts to use +B. If an I/O plugin is configured, the running command's +input and output may be logged as well. + +=head1 OPTIONS + +B accepts the following command line options: + +=over 12 + +=item -A + +Normally, if B requires a password, it will read it from the +user's terminal. If the B<-A> (I) option is specified, +a (possibly graphical) helper program is executed to read the user's +password and output the password to the standard output. If the +C environment variable is set, it specifies the path +to the helper program. Otherwise, if F<@sysconfdir@/sudo.conf> +contains a line specifying the askpass program, that value will be +used. For example: + + # Path to askpass helper program + Path askpass /usr/X11R6/bin/ssh-askpass + +If no askpass program is available, sudo will exit with an error. + +=item -a I + +The B<-a> (I) option causes B to use the +specified authentication type when validating the user, as allowed +by F. The system administrator may specify a list +of sudo-specific authentication methods by adding an "auth-sudo" +entry in F. This option is only available on systems +that support BSD authentication. + +=item -b + +The B<-b> (I) option tells B to run the given +command in the background. Note that if you use the B<-b> +option you cannot use shell job control to manipulate the process. +Most interactive commands will fail to work properly in background +mode. + +=item -C I + +Normally, B will close all open file descriptors other than +standard input, standard output and standard error. The B<-C> +(I) option allows the user to specify a starting point +above the standard error (file descriptor three). Values less than +three are not permitted. The security policy may restrict the +user's ability to use the B<-C> option. The I policy only +permits use of the B<-C> option when the administrator has enabled +the I option. + +=item -c I + +The B<-c> (I) option causes B to run the specified command +with resources limited by the specified login class. The I +argument can be either a class name as defined in F, +or a single '-' character. Specifying a I of C<-> indicates +that the command should be run restricted by the default login +capabilities for the user the command is run as. If the I +argument specifies an existing user class, the command must be run +as root, or the B command must be run from a shell that is already +root. This option is only available on systems with BSD login classes. + +=item -E + +The B<-E> (I I) option indicates to the +security policy that the user wishes to preserve their existing +environment variables. The security policy may return an error if +the B<-E> option is specified and the user does not have permission +to preserve the environment. + +=item -e + +The B<-e> (I) option indicates that, instead of running a +command, the user wishes to edit one or more files. In lieu of a +command, the string "sudoedit" is used when consulting the security +policy. If the user is authorized by the policy, the following +steps are taken: + +=over 4 + +=item 1. + +Temporary copies are made of the files to be edited with the owner +set to the invoking user. + +=item 2. + +The editor specified by the policy is run to edit the temporary files. +The I policy uses the C, C and C +environment variables (in that order). If none of C, +C or C are set, the first program listed in the +I L option is used. + +=item 3. + +If they have been modified, the temporary files are copied back to +their original location and the temporary versions are removed. + +=back + +If the specified file does not exist, it will be created. Note +that unlike most commands run by B, the editor is run with +the invoking user's environment unmodified. If, for some reason, +B is unable to update a file with its edited version, the +user will receive a warning and the edited copy will remain in a +temporary file. + +=item -g I + +Normally, B runs a command with the primary group set to the +one specified by the password database for the user the command is +being run as (by default, root). The B<-g> (I) option causes +B to run the command with the primary group set to I +instead. To specify a I instead of a I, use +I<#gid>. When running commands as a I, many shells require +that the '#' be escaped with a backslash ('\'). If no B<-u> option +is specified, the command will be run as the invoking user (not +root). In either case, the primary group will be set to I. + +=item -H + +The B<-H> (I) option requests that the security policy set +the C environment variable to the home directory of the target +user (root by default) as specified by the password database. +Depending on the policy, this may be the default behavior. + +=item -h + +The B<-h> (I) option causes B to print a short help message +to the standard output and exit. + +=item -i [command] + +The B<-i> (I) option runs the shell specified +by the password database entry of the target user as a login shell. +This means that login-specific resource files such as C<.profile> +or C<.login> will be read by the shell. If a command is specified, +it is passed to the shell for execution via the shell's B<-c> option. +If no command is specified, an interactive shell is executed. +B attempts to change to that user's home directory before +running the shell. The security policy shall initialize the +environment to a minimal set of variables, similar to what is present +when a user logs in. The I section in the +L manual documents how the B<-i> option affects the +environment in which a command is run when the I policy +is in use. + +=item -K + +The B<-K> (sure I) option is like B<-k> except that it removes +the user's cached credentials entirely and may not be used in +conjunction with a command or other option. This option does not +require a password. Not all security policies support credential +caching. + +=item -k [command] + +When used alone, the B<-k> (I) option to B invalidates +the user's cached credentials. The next time B is run a +password will be required. This option does not require a password +and was added to allow a user to revoke B permissions from a +.logout file. Not all security policies support credential +caching. + +When used in conjunction with a command or an option that may require +a password, the B<-k> option will cause B to ignore the user's +cached credentials. As a result, B will prompt for a password +(if one is required by the security policy) and will not update the +user's cached credentials. + +=item -l[l] [I] + +If no I is specified, the B<-l> (I) option will list +the allowed (and forbidden) commands for the invoking user (or the +user specified by the B<-U> option) on the current host. If a +I is specified and is permitted by the security policy, +the fully-qualified path to the command is displayed along with any +command line arguments. If I is specified but not allowed, +B will exit with a status value of 1. If the B<-l> option +is specified with an B argument (i.e. B<-ll>), or if B<-l> is +specified multiple times, a longer list format is used. + +=item -n + +The B<-n> (I) option prevents B from prompting +the user for a password. If a password is required for the command +to run, B will display an error messages and exit. + +=item -P + +The B<-P> (I I) option causes B to +preserve the invoking user's group vector unaltered. By default, +the I policy will initialize the group vector to the list +of groups the target user is in. The real and effective group IDs, +however, are still set to match the target user. + +=item -p I + +The B<-p> (I) option allows you to override the default +password prompt and use a custom one. The following percent (`C<%>') +escapes are supported by the I policy: + +=over 4 + +=item C<%H> + +expanded to the host name including the domain name (on if +the machine's host name is fully qualified or the I option +is set in L) + +=item C<%h> + +expanded to the local host name without the domain name + +=item C<%p> + +expanded to the name of the user whose password is being requested +(respects the I, I and I flags in +L) + +=item C<%U> + +expanded to the login name of the user the command will be run as +(defaults to root unless the C<-u> option is also specified) + +=item C<%u> + +expanded to the invoking user's login name + +=item C<%%> + +two consecutive C<%> characters are collapsed into a single C<%> character + +=back + +The prompt specified by the B<-p> option will override the system +password prompt on systems that support PAM unless the +I flag is disabled in I. + +=item -r I + +The B<-r> (I) option causes the new (SELinux) security context to +have the role specified by I. + +=item -S + +The B<-S> (I) option causes B to read the password from +the standard input instead of the terminal device. The password must +be followed by a newline character. + +=item -s [command] + +The B<-s> (I) option runs the shell specified by the I +environment variable if it is set or the shell as specified in the +password database. If a command is specified, it is passed to the +shell for execution via the shell's B<-c> option. If no command +is specified, an interactive shell is executed. + +=item -t I + +The B<-t> (I) option causes the new (SELinux) security context to +have the type specified by I. If no type is specified, the default +type is derived from the specified role. + +=item -U I + +The B<-U> (I) option is used in conjunction with the +B<-l> option to specify the user whose privileges should be listed. +The security policy may restrict listing other users' privileges. +The I policy only allows root or a user with the C +privilege on the current host to use this option. + +=item -u I + +The B<-u> (I) option causes B to run the specified +command as a user other than I. To specify a I instead +of a I, use I<#uid>. When running commands as a I, +many shells require that the '#' be escaped with a backslash ('\'). +Security policies may restrict Is to those listed in the +password database. The I policy allows Is that are +not in the password database as long as the I option is +not set. Other security policies may not support this. + +=item -V + +The B<-V> (I) option causes B to print its version +string and the version string of the security policy plugin and any +I/O plugins. If the invoking user is already root the B<-V> option +will display the arguments passed to configure when I was +built and plugins may display more verbose information such as +default options. + +=item -v + +When given the B<-v> (I) option, B will update the +user's cached credentials, authenticating the user's password if +necessary. For the I plugin, this extends the B +timeout for another C<@timeout@> minutes (or whatever the timeout +is set to in I) but does not run a command. Not all +security policies support cached credentials. + +=item -- + +The B<--> option indicates that B should stop processing command +line arguments. + +=back + +Environment variables to be set for the command may also be passed +on the command line in the form of B=I, e.g. +B=I. Variables passed on the +command line are subject to the same restrictions as normal environment +variables with one important exception. If the I option +is set in I, the command to be run has the C tag +set or the command matched is C, the user may set variables +that would otherwise be forbidden. See L for more information. + +=head1 PLUGINS + +Plugins are dynamically loaded based on the contents of the +F<@sysconfdir@/sudo.conf> file. If no F<@sysconfdir@/sudo.conf> +file is present, or it contains no C lines, B +will use the traditional I security policy and I/O logging, +which corresponds to the following F<@sysconfdir@/sudo.conf> file. + + # + # Default @sysconfdir@/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_options ... + # Path askpass /path/to/askpass + # Path noexec /path/to/sudo_noexec.so + # Debug sudo /var/log/sudo_debug all@warn + # Set disable_coredump true + # + # The plugin_path is relative to @prefix@/libexec unless + # fully qualified. + # The plugin_name corresponds to a global symbol in the plugin + # that contains the plugin interface structure. + # The plugin_options are optional. + # + Plugin policy_plugin sudoers.so + Plugin io_plugin sudoers.so + +A C line consists of the C keyword, followed by the +I and the I to the shared object containing the +plugin. The I is the name of the C +or C in the plugin shared object. The I +may be fully qualified or relative. If not fully qualified it is +relative to the F<@prefix@/libexec> directory. Any additional +parameters after the I are passed as arguments to the plugin's +I function. Lines that don't begin with C, C, +C or C are silently ignored. + +For more information, see the L manual. + +=head1 PATHS + +A C line consists of the C keyword, followed by the +name of the path to set and its value. E.g. + + Path noexec @noexec_file@ + Path askpass /usr/X11R6/bin/ssh-askpass + +The following plugin-agnostic paths may be set in the +F<@sysconfdir@/sudo.conf> file. + +=over 16 + +=item askpass + +The fully qualified path to a helper program used to read the user's +password when no terminal is available. This may be the case when +B is executed from a graphical (as opposed to text-based) +application. The program specified by I should display +the argument passed to it as the prompt and write the user's password +to the standard output. The value of I may be overridden +by the C environment variable. + +=item noexec + +The fully-qualified path to a shared library containing dummy +versions of the execv(), execve() and fexecve() library functions +that just return an error. This is used to implement the I +functionality on systems that support C or its equivalent. +Defaults to F<@noexec_file@>. + +=back + +=head1 DEBUG FLAGS + +B versions 1.8.4 and higher support a flexible debugging +framework that can help track down what B is doing internally +if there is a problem. + +A C line consists of the C keyword, followed by the +name of the program to debug (B, B, B), +the debug file name and a comma-separated list of debug flags. +The debug flag syntax used by B and the I plugin is +I@I but the plugin is free to use a different +format so long as it does not include a command C<,>. + +For instance: + + Debug sudo /var/log/sudo_debug all@warn,plugin@info + +would log all debugging statements at the I level and higher +in addition to those at the I level for the plugin subsystem. + +Currently, only one C entry per program is supported. The +C C entry is shared by the B front end, B +and the plugins. A future release may add support for per-plugin +C lines and/or support for multiple debugging files for a +single program. + +The priorities used by the B front end, in order of decreasing +severity, are: I, I, I, I, I, I, +I and I. Each priority, when specified, also includes +all priorities higher than it. For example, a priority of I +would include debug messages logged at I and higher. + +The following subsystems are used by B: + +=over 10 + +=item I + +matches every subsystem + +=item I + +command line argument processing + +=item I + +user conversation + +=item I + +sudoedit + +=item I + +command execution + +=item I
+ +B main function + +=item I + +network interface handling + +=item I + +communication with the plugin + +=item I + +plugin configuration + +=item I + +pseudo-tty related code + +=item I + +SELinux-specific handling + +=item I + +utility functions + +=item I + +utmp handling + +=back + +=head1 RETURN VALUES + +Upon successful execution of a program, the exit status from B +will simply be the exit status of the program that was executed. + +Otherwise, B exits with a value of 1 if there is a +configuration/permission problem or if B cannot execute the +given command. In the latter case the error string is printed to +the standard error. If B cannot L one or more entries +in the user's C, an error is printed on stderr. (If the +directory does not exist or if it is not really a directory, the +entry is ignored and no error is printed.) This should not happen +under normal circumstances. The most common reason for L +to return "permission denied" is if you are running an automounter +and one of the directories in your C is on a machine that is +currently unreachable. + +=head1 SECURITY NOTES + +B tries to be safe when executing external commands. + +To prevent command spoofing, B checks "." and "" (both denoting +current directory) last when searching for a command in the user's +PATH (if one or both are in the PATH). Note, however, that the +actual C environment variable is I modified and is passed +unchanged to the program that B executes. + +Please note that B will normally only log the command it +explicitly runs. If a user runs a command such as C or +C, subsequent commands run from that shell are not subject +to B's security policy. The same is true for commands that +offer shell escapes (including most editors). If I/O logging is +enabled, subsequent commands will have their input and/or output +logged, but there will not be traditional logs for those commands. +Because of this, care must be taken when giving users access to +commands via B to verify that the command does not inadvertently +give the user an effective root shell. For more information, please +see the C section in L. + +To prevent the disclosure of potentially sensitive information, +B disables core dumps by default while it is executing (they +are re-enabled for the command that is run). To aid in debugging +B crashes, you may wish to re-enable core dumps by setting +"disable_coredump" to false in the F<@sysconfdir@/sudo.conf> file. + + Set disable_coredump false + +Note that by default, most operating systems disable core dumps +from setuid programs, which includes B. To actually get a +B core file you may need to enable core dumps for setuid +processes. On BSD and Linux systems this is accomplished via the +sysctl command, on Solaris the coreadm command can be used. + +=head1 ENVIRONMENT + +B utilizes the following environment variables. The security +policy has control over the content of the command's environment. + +=over 16 + +=item C + +Default editor to use in B<-e> (sudoedit) mode if neither C +nor C is set + +=item C + +In B<-i> mode or when I is enabled in I, set +to the mail spool of the target user + +=item C + +Set to the home directory of the target user if B<-i> or B<-H> are +specified, I or I are set in I, +or when the B<-s> option is specified and I is set in +I + +=item C + +May be overridden by the security policy. + +=item C + +Used to determine shell to run with C<-s> option + +=item C + +Specifies the path to a helper program used to read the password +if no terminal is available or if the C<-A> option is specified. + +=item C + +Set to the command run by sudo + +=item C + +Default editor to use in B<-e> (sudoedit) mode + +=item C + +Set to the group ID of the user who invoked sudo + +=item C + +Used as the default password prompt + +=item C + +If set, C will be set to its value for the program being run + +=item C + +Set to the user ID of the user who invoked sudo + +=item C + +Set to the login of the user who invoked sudo + +=item C + +Set to the target user (root unless the B<-u> option is specified) + +=item C + +Default editor to use in B<-e> (sudoedit) mode if C +is not set + +=back + +=head1 FILES + +=over 24 + +=item F<@sysconfdir@/sudo.conf> + +B front end configuration + +=back + +=head1 EXAMPLES + +Note: the following examples assume a properly configured security policy. + +To get a file listing of an unreadable directory: + + $ sudo ls /usr/local/protected + +To list the home directory of user yaz on a machine where the +file system holding ~yaz is not exported as root: + + $ sudo -u yaz ls ~yaz + +To edit the F file as user www: + + $ sudo -u www vi ~www/htdocs/index.html + +To view system logs only accessible to root and users in the adm group: + + $ sudo -g adm view /var/log/syslog + +To run an editor as jim with a different primary group: + + $ sudo -u jim -g audio vi ~jim/sound.txt + +To shutdown a machine: + + $ sudo shutdown -r +15 "quick reboot" + +To make a usage listing of the directories in the /home +partition. Note that this runs the commands in a sub-shell +to make the C and file redirection work. + + $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE" + +=head1 SEE ALSO + +L, L, L, +L, +L, L, L, L, L + +=head1 AUTHORS + +Many people have worked on B over the years; this +version consists of code written primarily by: + + Todd C. Miller + +See the CONTRIBUTORS file in the B distribution +(http://www.sudo.ws/sudo/contributors.html) for a list of people +who have contributed to B. + +=head1 HISTORY + +See the HISTORY file in the B distribution +(http://www.sudo.ws/sudo/history.html) for a brief history of sudo. + +=head1 CAVEATS + +There is no easy way to prevent a user from gaining a root shell +if that user is allowed to run arbitrary commands via B. +Also, many programs (such as editors) allow the user to run commands +via shell escapes, thus avoiding B's checks. However, on +most systems it is possible to prevent shell escapes with the +L module's I functionality. + +It is not meaningful to run the C command directly via sudo, e.g., + + $ sudo cd /usr/local/protected + +since when the command exits the parent process (your shell) will +still be the same. Please see the EXAMPLES section for more information. + +Running shell scripts via B can expose the same kernel bugs that +make setuid shell scripts unsafe on some operating systems (if your OS +has a /dev/fd/ directory, setuid shell scripts are generally safe). + +=head1 BUGS + +If you feel you have found a bug in B, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ + +=head1 SUPPORT + +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or +search the archives. + +=head1 DISCLAIMER + +B is provided ``AS IS'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the LICENSE +file distributed with B or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat new file mode 100644 index 0000000..1d9a996 --- /dev/null +++ b/doc/sudo_plugin.cat @@ -0,0 +1,1358 @@ +SUDO_PLUGIN(1m) MAINTENANCE COMMANDS SUDO_PLUGIN(1m) + + + +NNAAMMEE + sudo_plugin - Sudo Plugin API + +DDEESSCCRRIIPPTTIIOONN + Starting with version 1.8, ssuuddoo supports a plugin API for policy and + session logging. By default, the _s_u_d_o_e_r_s policy plugin and an + associated I/O logging plugin are used. Via the plugin API, ssuuddoo can + be configured to use alternate policy and/or I/O logging plugins + provided by third parties. The plugins to be used are specified via + the _/_e_t_c_/_s_u_d_o_._c_o_n_f file. + + The API is versioned with a major and minor number. The minor version + number is incremented when additions are made. The major number is + incremented when incompatible changes are made. A plugin should be + check the version passed to it and make sure that the major version + matches. + + The plugin API is defined by the sudo_plugin.h header file. + + TThhee ssuuddoo..ccoonnff FFiillee + The _/_e_t_c_/_s_u_d_o_._c_o_n_f file contains plugin configuration directives. + Currently, the only supported keyword is the Plugin directive, which + causes a plugin plugin to be loaded. + + A Plugin line consists of the Plugin keyword, followed by the + _s_y_m_b_o_l___n_a_m_e and the _p_a_t_h to the shared object containing the plugin. + The _s_y_m_b_o_l___n_a_m_e is the name of the struct policy_plugin or struct + io_plugin in the plugin shared object. The _p_a_t_h may be fully qualified + or relative. If not fully qualified it is relative to the + _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c directory. Any additional parameters after the _p_a_t_h + are passed as options to the plugin's _o_p_e_n function. Lines that don't + begin with Plugin, Path, Debug or Set are silently ignored. + + The same shared object may contain multiple plugins, each with a + different symbol name. The shared object file must be owned by uid 0 + and only writable by its owner. Because of ambiguities that arise from + composite policies, only a single policy plugin may be specified. This + limitation does not apply to I/O plugins. + + # + # Default /etc/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_options ... + # Path askpass /path/to/askpass + # Path noexec /path/to/sudo_noexec.so + # Debug sudo /var/log/sudo_debug all@warn + # Set disable_coredump true + # + # The plugin_path is relative to /usr/local/libexec unless + # fully qualified. + # The plugin_name corresponds to a global symbol in the plugin + # that contains the plugin interface structure. + # The plugin_options are optional. + # + Plugin sudoers_policy sudoers.so + Plugin sudoers_io sudoers.so + + PPoolliiccyy PPlluuggiinn AAPPII + A policy plugin must declare and populate a policy_plugin struct in the + global scope. This structure contains pointers to the functions that + implement the ssuuddoo policy checks. The name of the symbol should be + specified in _/_e_t_c_/_s_u_d_o_._c_o_n_f along with a path to the plugin so that + ssuuddoo can load it. + + struct policy_plugin { + #define SUDO_POLICY_PLUGIN 1 + unsigned int type; /* always SUDO_POLICY_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_options[]); + void (*close)(int exit_status, int error); + int (*show_version)(int verbose); + int (*check_policy)(int argc, char * const argv[], + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + int (*list)(int argc, char * const argv[], int verbose, + const char *list_user); + int (*validate)(void); + void (*invalidate)(int remove); + int (*init_session)(struct passwd *pwd, char **user_env[]); + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + }; + + The policy_plugin struct has the following fields: + + type + The type field should always be set to SUDO_POLICY_PLUGIN. + + version + The version field should be set to SUDO_API_VERSION. + + This allows ssuuddoo to determine the API version the plugin was built + against. + + open + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_options[]); + + Returns 1 on success, 0 on failure, -1 if a general error occurred, + or -2 if there was a usage error. In the latter case, ssuuddoo will + print a usage message before it exits. If an error occurs, the + plugin may optionally call the conversation or plugin_printf + function with SUDO_CONF_ERROR_MSG to present additional error + information to the user. + + The function arguments are as follows: + + version + The version passed in by ssuuddoo allows the plugin to determine + the major and minor version number of the plugin API supported + by ssuuddoo. + + conversation + A pointer to the conversation function that can be used by the + plugin to interact with the user (see below). Returns 0 on + success and -1 on failure. + + plugin_printf + A pointer to a printf-style function that may be used to + display informational or error messages (see below). Returns + the number of characters printed on success and -1 on failure. + + settings + A vector of user-supplied ssuuddoo settings in the form of + "name=value" strings. The vector is terminated by a NULL + pointer. These settings correspond to flags the user specified + when running ssuuddoo. As such, they will only be present when the + corresponding flag has been specified on the command line. + + When parsing _s_e_t_t_i_n_g_s, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + debug_flags=string + A comma-separated list of debug flags that correspond to + ssuuddoo's Debug entry in _/_e_t_c_/_s_u_d_o_._c_o_n_f, if there is one. The + flags are passed to the plugin as they appear in + _/_e_t_c_/_s_u_d_o_._c_o_n_f. The syntax used by ssuuddoo and the _s_u_d_o_e_r_s + plugin is _s_u_b_s_y_s_t_e_m@_p_r_i_o_r_i_t_y but the plugin is free to use + a different format so long as it does not include a command + ,. + + For reference, the priorities supported by the ssuuddoo front + end and _s_u_d_o_e_r_s are: _c_r_i_t, _e_r_r, _w_a_r_n, _n_o_t_i_c_e, _d_i_a_g, _i_n_f_o, + _t_r_a_c_e and _d_e_b_u_g. + + The following subsystems are defined: _m_a_i_n, _m_e_m_o_r_y, _a_r_g_s, + _e_x_e_c, _p_t_y, _u_t_m_p, _c_o_n_v, _p_c_o_m_m, _u_t_i_l, _l_i_s_t, _n_e_t_i_f, _a_u_d_i_t, + _e_d_i_t, _s_e_l_i_n_u_x, _l_d_a_p, _m_a_t_c_h, _p_a_r_s_e_r, _a_l_i_a_s, _d_e_f_a_u_l_t_s, _a_u_t_h, + _e_n_v, _l_o_g_g_i_n_g, _n_s_s, _r_b_t_r_e_e, _p_e_r_m_s, _p_l_u_g_i_n. The subsystem + _a_l_l includes every subsystem. + + There is not currently a way to specify a set of debug + flags specific to the plugin--the flags are shared by ssuuddoo + and the plugin. + + debug_level=number + This setting has been deprecated in favor of _d_e_b_u_g___f_l_a_g_s. + + runas_user=string + The user name or uid to to run the command as, if specified + via the -u flag. + + runas_group=string + The group name or gid to to run the command as, if + specified via the -g flag. + + prompt=string + The prompt to use when requesting a password, if specified + via the -p flag. + + set_home=bool + Set to true if the user specified the -H flag. If true, + set the HOME environment variable to the target user's home + directory. + + preserve_environment=bool + Set to true if the user specified the -E flag, indicating + that the user wishes to preserve the environment. + + run_shell=bool + Set to true if the user specified the -s flag, indicating + that the user wishes to run a shell. + + login_shell=bool + Set to true if the user specified the -i flag, indicating + that the user wishes to run a login shell. + + implied_shell=bool + If the user does not specify a program on the command line, + ssuuddoo will pass the plugin the path to the user's shell and + set _i_m_p_l_i_e_d___s_h_e_l_l to true. This allows ssuuddoo with no + arguments to be used similarly to _s_u(1). If the plugin + does not to support this usage, it may return a value of -2 + from the check_policy function, which will cause ssuuddoo to + print a usage message and exit. + + preserve_groups=bool + Set to true if the user specified the -P flag, indicating + that the user wishes to preserve the group vector instead + of setting it based on the runas user. + + ignore_ticket=bool + Set to true if the user specified the -k flag along with a + command, indicating that the user wishes to ignore any + cached authentication credentials. + + noninteractive=bool + Set to true if the user specified the -n flag, indicating + that ssuuddoo should operate in non-interactive mode. The + plugin may reject a command run in non-interactive mode if + user interaction is required. + + login_class=string + BSD login class to use when setting resource limits and + nice value, if specified by the -c flag. + + selinux_role=string + SELinux role to use when executing the command, if + specified by the -r flag. + + selinux_type=string + SELinux type to use when executing the command, if + specified by the -t flag. + + bsdauth_type=string + Authentication type, if specified by the -a flag, to use on + systems where BSD authentication is supported. + + network_addrs=list + A space-separated list of IP network addresses and netmasks + in the form "addr/netmask", e.g. + "192.168.1.2/255.255.255.0". The address and netmask pairs + may be either IPv4 or IPv6, depending on what the operating + system supports. If the address contains a colon (':'), it + is an IPv6 address, else it is IPv4. + + progname=string + The command name that sudo was run as, typically "sudo" or + "sudoedit". + + sudoedit=bool + Set to true when the -e flag is is specified or if invoked + as ssuuddooeeddiitt. The plugin shall substitute an editor into + _a_r_g_v in the _c_h_e_c_k___p_o_l_i_c_y function or return -2 with a usage + error if the plugin does not support _s_u_d_o_e_d_i_t. For more + information, see the _c_h_e_c_k___p_o_l_i_c_y section. + + closefrom=number + If specified, the user has requested via the -C flag that + ssuuddoo close all files descriptors with a value of _n_u_m_b_e_r or + higher. The plugin may optionally pass this, or another + value, back in the _c_o_m_m_a_n_d___i_n_f_o list. + + Additional settings may be added in the future so the plugin + should silently ignore settings that it does not recognize. + + user_info + A vector of information about the user running the command in + the form of "name=value" strings. The vector is terminated by + a NULL pointer. + + When parsing _u_s_e_r___i_n_f_o, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + pid=int + The process ID of the running ssuuddoo process. Only available + starting with API version 1.2 + + ppid=int + The parent process ID of the running ssuuddoo process. Only + available starting with API version 1.2 + + sid=int + The session ID of the running ssuuddoo process or 0 if ssuuddoo is + not part of a POSIX job control session. Only available + starting with API version 1.2 + + pgid=int + The ID of the process group that the running ssuuddoo process + belongs to. Only available starting with API version 1.2 + + tcpgid=int + The ID of the forground process group associated with the + terminal device associcated with the ssuuddoo process or -1 if + there is no terminal present. Only available starting with + API version 1.2 + + user=string + The name of the user invoking ssuuddoo. + + euid=uid_t + The effective user ID of the user invoking ssuuddoo. + + uid=uid_t + The real user ID of the user invoking ssuuddoo. + + egid=gid_t + The effective group ID of the user invoking ssuuddoo. + + gid=gid_t + The real group ID of the user invoking ssuuddoo. + + groups=list + The user's supplementary group list formatted as a string + of comma-separated group IDs. + + cwd=string + The user's current working directory. + + tty=string + The path to the user's terminal device. If the user has no + terminal device associated with the session, the value will + be empty, as in tty=. + + host=string + The local machine's hostname as returned by the + gethostname() system call. + + lines=int + The number of lines the user's terminal supports. If there + is no terminal device available, a default value of 24 is + used. + + cols=int + The number of columns the user's terminal supports. If + there is no terminal device available, a default value of + 80 is used. + + user_env + The user's environment in the form of a NULL-terminated vector + of "name=value" strings. + + When parsing _u_s_e_r___e_n_v, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + plugin_options + Any (non-comment) strings immediately after the plugin path are + treated as arguments to the plugin. These arguments are split + on a white space boundary and are passed to the plugin in the + form of a NULL-terminated array of strings. If no arguments + were specified, _p_l_u_g_i_n___o_p_t_i_o_n_s will be the NULL pointer. + + NOTE: the _p_l_u_g_i_n___o_p_t_i_o_n_s parameter is only available starting + with API version 1.2. A plugin mmuusstt check the API version + specified by the ssuuddoo front end before using _p_l_u_g_i_n___o_p_t_i_o_n_s. + Failure to do so may result in a crash. + + close + void (*close)(int exit_status, int error); + + The close function is called when the command being run by ssuuddoo + finishes. + + The function arguments are as follows: + + exit_status + The command's exit status, as returned by the _w_a_i_t(2) system + call. The value of exit_status is undefined if error is non- + zero. + + error + If the command could not be executed, this is set to the value + of errno set by the _e_x_e_c_v_e(2) system call. The plugin is + responsible for displaying error information via the + conversation or plugin_printf function. If the command was + successfully executed, the value of error is 0. + + show_version + int (*show_version)(int verbose); + + The show_version function is called by ssuuddoo when the user specifies + the -V option. The plugin may display its version information to + the user via the conversation or plugin_printf function using + SUDO_CONV_INFO_MSG. If the user requests detailed version + information, the verbose flag will be set. + + check_policy + int (*check_policy)(int argc, char * const argv[] + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + + The _c_h_e_c_k___p_o_l_i_c_y function is called by ssuuddoo to determine whether + the user is allowed to run the specified commands. + + If the _s_u_d_o_e_d_i_t option was enabled in the _s_e_t_t_i_n_g_s array passed to + the _o_p_e_n function, the user has requested _s_u_d_o_e_d_i_t mode. _s_u_d_o_e_d_i_t + is a mechanism for editing one or more files where an editor is run + with the user's credentials instead of with elevated privileges. + ssuuddoo achieves this by creating user-writable temporary copies of + the files to be edited and then overwriting the originals with the + temporary copies after editing is complete. If the plugin supports + ssuuddooeeddiitt, it should choose the editor to be used, potentially from + a variable in the user's environment, such as EDITOR, and include + it in _a_r_g_v___o_u_t (note that environment variables may include command + line flags). The files to be edited should be copied from _a_r_g_v + into _a_r_g_v___o_u_t, separated from the editor and its arguments by a + "--" element. The "--" will be removed by ssuuddoo before the editor + is executed. The plugin should also set _s_u_d_o_e_d_i_t_=_t_r_u_e in the + _c_o_m_m_a_n_d___i_n_f_o list. + + The _c_h_e_c_k___p_o_l_i_c_y function returns 1 if the command is allowed, 0 if + not allowed, -1 for a general error, or -2 for a usage error or if + ssuuddooeeddiitt was specified but is unsupported by the plugin. In the + latter case, ssuuddoo will print a usage message before it exits. If + an error occurs, the plugin may optionally call the conversation or + plugin_printf function with SUDO_CONF_ERROR_MSG to present + additional error information to the user. + + The function arguments are as follows: + + argc + The number of elements in _a_r_g_v, not counting the final NULL + pointer. + + argv + The argument vector describing the command the user wishes to + run, in the same form as what would be passed to the _e_x_e_c_v_e_(_) + system call. The vector is terminated by a NULL pointer. + + env_add + Additional environment variables specified by the user on the + command line in the form of a NULL-terminated vector of + "name=value" strings. The plugin may reject the command if one + or more variables are not allowed to be set, or it may silently + ignore such variables. + + When parsing _e_n_v___a_d_d, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + command_info + Information about the command being run in the form of + "name=value" strings. These values are used by ssuuddoo to set the + execution environment when running a command. The plugin is + responsible for creating and populating the vector, which must + be terminated with a NULL pointer. The following values are + recognized by ssuuddoo: + + command=string + Fully qualified path to the command to be executed. + + runas_uid=uid + User ID to run the command as. + + runas_euid=uid + Effective user ID to run the command as. If not specified, + the value of _r_u_n_a_s___u_i_d is used. + + runas_gid=gid + Group ID to run the command as. + + runas_egid=gid + Effective group ID to run the command as. If not + specified, the value of _r_u_n_a_s___g_i_d is used. + + runas_groups=list + The supplementary group vector to use for the command in + the form of a comma-separated list of group IDs. If + _p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, this option is ignored. + + login_class=string + BSD login class to use when setting resource limits and + nice value (optional). This option is only set on systems + that support login classes. + + preserve_groups=bool + If set, ssuuddoo will preserve the user's group vector instead + of initializing the group vector based on runas_user. + + cwd=string + The current working directory to change to when executing + the command. + + noexec=bool + If set, prevent the command from executing other programs. + + chroot=string + The root directory to use when running the command. + + nice=int + Nice value (priority) to use when executing the command. + The nice value, if specified, overrides the priority + associated with the _l_o_g_i_n___c_l_a_s_s on BSD systems. + + umask=octal + The file creation mask to use when executing the command. + + selinux_role=string + SELinux role to use when executing the command. + + selinux_type=string + SELinux type to use when executing the command. + + timeout=int + Command timeout. If non-zero then when the timeout expires + the command will be killed. + + sudoedit=bool + Set to true when in _s_u_d_o_e_d_i_t mode. The plugin may enable + _s_u_d_o_e_d_i_t mode even if ssuuddoo was not invoked as ssuuddooeeddiitt. + This allows the plugin to perform command substitution and + transparently enable _s_u_d_o_e_d_i_t when the user attempts to run + an editor. + + closefrom=number + If specified, ssuuddoo will close all files descriptors with a + value of _n_u_m_b_e_r or higher. + + iolog_compress=bool + Set to true if the I/O logging plugins, if any, should + compress the log data. This is a hint to the I/O logging + plugin which may choose to ignore it. + + iolog_path=string + Fully qualified path to the file or directory in which I/O + log is to be stored. This is a hint to the I/O logging + plugin which may choose to ignore it. If no I/O logging + plugin is loaded, this setting has no effect. + + iolog_stdin=bool + Set to true if the I/O logging plugins, if any, should log + the standard input if it is not connected to a terminal + device. This is a hint to the I/O logging plugin which may + choose to ignore it. + + iolog_stdout=bool + Set to true if the I/O logging plugins, if any, should log + the standard output if it is not connected to a terminal + device. This is a hint to the I/O logging plugin which may + choose to ignore it. + + iolog_stderr=bool + Set to true if the I/O logging plugins, if any, should log + the standard error if it is not connected to a terminal + device. This is a hint to the I/O logging plugin which may + choose to ignore it. + + iolog_ttyin=bool + Set to true if the I/O logging plugins, if any, should log + all terminal input. This only includes input typed by the + user and not from a pipe or redirected from a file. This + is a hint to the I/O logging plugin which may choose to + ignore it. + + iolog_ttyout=bool + Set to true if the I/O logging plugins, if any, should log + all terminal output. This only includes output to the + screen, not output to a pipe or file. This is a hint to + the I/O logging plugin which may choose to ignore it. + + use_pty=bool + Allocate a pseudo-tty to run the command in, regardless of + whether or not I/O logging is in use. By default, ssuuddoo + will only run the command in a pty when an I/O log plugin + is loaded. + + set_utmp=bool + Create a utmp (or utmpx) entry when a pseudo-tty is + allocated. By default, the new entry will be a copy of the + user's existing utmp entry (if any), with the tty, time, + type and pid fields updated. + + utmp_user=string + User name to use when constructing a new utmp (or utmpx) + entry when _s_e_t___u_t_m_p is enabled. This option can be used to + set the user field in the utmp entry to the user the + command runs as rather than the invoking user. If not set, + ssuuddoo will base the new entry on the invoking user's + existing entry. + + Unsupported values will be ignored. + + argv_out + The NULL-terminated argument vector to pass to the _e_x_e_c_v_e_(_) + system call when executing the command. The plugin is + responsible for allocating and populating the vector. + + user_env_out + The NULL-terminated environment vector to use when executing + the command. The plugin is responsible for allocating and + populating the vector. + + list + int (*list)(int verbose, const char *list_user, + int argc, char * const argv[]); + + List available privileges for the invoking user. Returns 1 on + success, 0 on failure and -1 on error. On error, the plugin may + optionally call the conversation or plugin_printf function with + SUDO_CONF_ERROR_MSG to present additional error information to the + user. + + Privileges should be output via the conversation or plugin_printf + function using SUDO_CONV_INFO_MSG. + + verbose + Flag indicating whether to list in verbose mode or not. + + list_user + The name of a different user to list privileges for if the + policy allows it. If NULL, the plugin should list the + privileges of the invoking user. + + argc + The number of elements in _a_r_g_v, not counting the final NULL + pointer. + + argv + If non-NULL, an argument vector describing a command the user + wishes to check against the policy in the same form as what + would be passed to the _e_x_e_c_v_e_(_) system call. If the command is + permitted by the policy, the fully-qualified path to the + command should be displayed along with any command line + arguments. + + validate + int (*validate)(void); + + The validate function is called when ssuuddoo is run with the -v flag. + For policy plugins such as _s_u_d_o_e_r_s that cache authentication + credentials, this function will validate and cache the credentials. + + The validate function should be NULL if the plugin does not support + credential caching. + + Returns 1 on success, 0 on failure and -1 on error. On error, the + plugin may optionally call the conversation or plugin_printf + function with SUDO_CONF_ERROR_MSG to present additional error + information to the user. + + invalidate + void (*invalidate)(int remove); + + The invalidate function is called when ssuuddoo is called with the -k + or -K flag. For policy plugins such as _s_u_d_o_e_r_s that cache + authentication credentials, this function will invalidate the + credentials. If the _r_e_m_o_v_e flag is set, the plugin may remove the + credentials instead of simply invalidating them. + + The invalidate function should be NULL if the plugin does not + support credential caching. + + init_session + int (*init_session)(struct passwd *pwd, char **user_envp[); + + The init_session function is called before ssuuddoo sets up the + execution environment for the command. It is run in the parent + ssuuddoo process and before any uid or gid changes. This can be used + to perform session setup that is not supported by _c_o_m_m_a_n_d___i_n_f_o, + such as opening the PAM session. The close function can be used to + tear down the session that was opened by init_session. + + The _p_w_d argument points to a passwd struct for the user the command + will be run as if the uid the command will run as was found in the + password database, otherwise it will be NULL. + + The _u_s_e_r___e_n_v argument points to the environment the command will + run in, in the form of a NULL-terminated vector of "name=value" + strings. This is the same string passed back to the front end via + the Policy Plugin's _u_s_e_r___e_n_v___o_u_t parameter. If the init_session + function needs to modify the user environment, it should update the + pointer stored in _u_s_e_r___e_n_v. The expected use case is to merge the + contents of the PAM environment (if any) with the contents of + _u_s_e_r___e_n_v. NOTE: the _u_s_e_r___e_n_v parameter is only available starting + with API version 1.2. A plugin mmuusstt check the API version + specified by the ssuuddoo front end before using _u_s_e_r___e_n_v. Failure to + do so may result in a crash. + + Returns 1 on success, 0 on failure and -1 on error. On error, the + plugin may optionally call the conversation or plugin_printf + function with SUDO_CONF_ERROR_MSG to present additional error + information to the user. + + register_hooks + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + + The register_hooks function is called by the sudo front end to + register any hooks the plugin needs. If the plugin does not + support hooks, register_hooks should be set to the NULL pointer. + + The _v_e_r_s_i_o_n argument describes the version of the hooks API + supported by the ssuuddoo front end. + + The register_hook function should be used to register any supported + hooks the plugin needs. It returns 0 on success, 1 if the hook + type is not supported and -1 if the major version in struct hook + does not match the front end's major hook API version. + + See the "Hook Function API" section below for more information + about hooks. + + NOTE: the register_hooks function is only available starting with + API version 1.2. If the ssuuddoo front end doesn't support API version + 1.2 or higher, register_hooks will not be called. + + deregister_hooks + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + + The deregister_hooks function is called by the sudo front end to + deregister any hooks the plugin has registered. If the plugin does + not support hooks, deregister_hooks should be set to the NULL + pointer. + + The _v_e_r_s_i_o_n argument describes the version of the hooks API + supported by the ssuuddoo front end. + + The deregister_hook function should be used to deregister any hooks + that were put in place by the register_hook function. If the + plugin tries to deregister a hook that the front end does not + support, deregister_hook will return an error. + + See the "Hook Function API" section below for more information + about hooks. + + NOTE: the deregister_hooks function is only available starting with + API version 1.2. If the ssuuddoo front end doesn't support API version + 1.2 or higher, deregister_hooks will not be called. + + _P_o_l_i_c_y _P_l_u_g_i_n _V_e_r_s_i_o_n _M_a_c_r_o_s + + /* Plugin API version major/minor. */ + #define SUDO_API_VERSION_MAJOR 1 + #define SUDO_API_VERSION_MINOR 2 + #define SUDO_API_MKVERSION(x, y) ((x << 16) | y) + #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\ + SUDO_API_VERSION_MINOR) + + /* Getters and setters for API version */ + #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) + #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff) + #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ + } while(0) + #define SUDO_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ + } while(0) + + II//OO PPlluuggiinn AAPPII + struct io_plugin { + #define SUDO_IO_PLUGIN 2 + unsigned int type; /* always SUDO_IO_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], int argc, char * const argv[], + char * const user_env[], char * const plugin_options[]); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*log_ttyin)(const char *buf, unsigned int len); + int (*log_ttyout)(const char *buf, unsigned int len); + int (*log_stdin)(const char *buf, unsigned int len); + int (*log_stdout)(const char *buf, unsigned int len); + int (*log_stderr)(const char *buf, unsigned int len); + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + }; + + When an I/O plugin is loaded, ssuuddoo runs the command in a pseudo-tty. + This makes it possible to log the input and output from the user's + session. If any of the standard input, standard output or standard + error do not correspond to a tty, ssuuddoo will open a pipe to capture the + I/O for logging before passing it on. + + The log_ttyin function receives the raw user input from the terminal + device (note that this will include input even when echo is disabled, + such as when a password is read). The log_ttyout function receives + output from the pseudo-tty that is suitable for replaying the user's + session at a later time. The log_stdin, log_stdout and log_stderr + functions are only called if the standard input, standard output or + standard error respectively correspond to something other than a tty. + + Any of the logging functions may be set to the NULL pointer if no + logging is to be performed. If the open function returns 0, no I/O + will be sent to the plugin. + + The io_plugin struct has the following fields: + + type + The type field should always be set to SUDO_IO_PLUGIN + + version + The version field should be set to SUDO_API_VERSION. + + This allows ssuuddoo to determine the API version the plugin was built + against. + + open + int (*open)(unsigned int version, sudo_conv_t conversation + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], int argc, char * const argv[], + char * const user_env[], char * const plugin_options[]); + + The _o_p_e_n function is run before the _l_o_g___i_n_p_u_t, _l_o_g___o_u_t_p_u_t or + _s_h_o_w___v_e_r_s_i_o_n functions are called. It is only called if the + version is being requested or the _c_h_e_c_k___p_o_l_i_c_y function has + returned successfully. It returns 1 on success, 0 on failure, -1 + if a general error occurred, or -2 if there was a usage error. In + the latter case, ssuuddoo will print a usage message before it exits. + If an error occurs, the plugin may optionally call the conversation + or plugin_printf function with SUDO_CONF_ERROR_MSG to present + additional error information to the user. + + The function arguments are as follows: + + version + The version passed in by ssuuddoo allows the plugin to determine + the major and minor version number of the plugin API supported + by ssuuddoo. + + conversation + A pointer to the conversation function that may be used by the + _s_h_o_w___v_e_r_s_i_o_n function to display version information (see + show_version below). The conversation function may also be + used to display additional error message to the user. The + conversation function returns 0 on success and -1 on failure. + + plugin_printf + A pointer to a printf-style function that may be used by the + _s_h_o_w___v_e_r_s_i_o_n function to display version information (see + show_version below). The plugin_printf function may also be + used to display additional error message to the user. The + plugin_printf function returns number of characters printed on + success and -1 on failure. + + settings + A vector of user-supplied ssuuddoo settings in the form of + "name=value" strings. The vector is terminated by a NULL + pointer. These settings correspond to flags the user specified + when running ssuuddoo. As such, they will only be present when the + corresponding flag has been specified on the command line. + + When parsing _s_e_t_t_i_n_g_s, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + See the "Policy Plugin API" section for a list of all possible + settings. + + user_info + A vector of information about the user running the command in + the form of "name=value" strings. The vector is terminated by + a NULL pointer. + + When parsing _u_s_e_r___i_n_f_o, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + See the "Policy Plugin API" section for a list of all possible + strings. + + argc + The number of elements in _a_r_g_v, not counting the final NULL + pointer. + + argv + If non-NULL, an argument vector describing a command the user + wishes to run in the same form as what would be passed to the + _e_x_e_c_v_e_(_) system call. + + user_env + The user's environment in the form of a NULL-terminated vector + of "name=value" strings. + + When parsing _u_s_e_r___e_n_v, the plugin should split on the ffiirrsstt + equal sign ('=') since the _n_a_m_e field will never include one + itself but the _v_a_l_u_e might. + + plugin_options + Any (non-comment) strings immediately after the plugin path are + treated as arguments to the plugin. These arguments are split + on a white space boundary and are passed to the plugin in the + form of a NULL-terminated array of strings. If no arguments + were specified, _p_l_u_g_i_n___o_p_t_i_o_n_s will be the NULL pointer. + + NOTE: the _p_l_u_g_i_n___o_p_t_i_o_n_s parameter is only available starting + with API version 1.2. A plugin mmuusstt check the API version + specified by the ssuuddoo front end before using _p_l_u_g_i_n___o_p_t_i_o_n_s. + Failure to do so may result in a crash. + + close + void (*close)(int exit_status, int error); + + The close function is called when the command being run by ssuuddoo + finishes. + + The function arguments are as follows: + + exit_status + The command's exit status, as returned by the _w_a_i_t(2) system + call. The value of exit_status is undefined if error is non- + zero. + + error + If the command could not be executed, this is set to the value + of errno set by the _e_x_e_c_v_e(2) system call. If the command was + successfully executed, the value of error is 0. + + show_version + int (*show_version)(int verbose); + + The show_version function is called by ssuuddoo when the user specifies + the -V option. The plugin may display its version information to + the user via the conversation or plugin_printf function using + SUDO_CONV_INFO_MSG. If the user requests detailed version + information, the verbose flag will be set. + + log_ttyin + int (*log_ttyin)(const char *buf, unsigned int len); + + The _l_o_g___t_t_y_i_n function is called whenever data can be read from the + user but before it is passed to the running command. This allows + the plugin to reject data if it chooses to (for instance if the + input contains banned content). Returns 1 if the data should be + passed to the command, 0 if the data is rejected (which will + terminate the command) or -1 if an error occurred. + + The function arguments are as follows: + + buf The buffer containing user input. + + len The length of _b_u_f in bytes. + + log_ttyout + int (*log_ttyout)(const char *buf, unsigned int len); + + The _l_o_g___t_t_y_o_u_t function is called whenever data can be read from + the command but before it is written to the user's terminal. This + allows the plugin to reject data if it chooses to (for instance if + the output contains banned content). Returns 1 if the data should + be passed to the user, 0 if the data is rejected (which will + terminate the command) or -1 if an error occurred. + + The function arguments are as follows: + + buf The buffer containing command output. + + len The length of _b_u_f in bytes. + + log_stdin + int (*log_stdin)(const char *buf, unsigned int len); + + The _l_o_g___s_t_d_i_n function is only used if the standard input does not + correspond to a tty device. It is called whenever data can be read + from the standard input but before it is passed to the running + command. This allows the plugin to reject data if it chooses to + (for instance if the input contains banned content). Returns 1 if + the data should be passed to the command, 0 if the data is rejected + (which will terminate the command) or -1 if an error occurred. + + The function arguments are as follows: + + buf The buffer containing user input. + + len The length of _b_u_f in bytes. + + log_stdout + int (*log_stdout)(const char *buf, unsigned int len); + + The _l_o_g___s_t_d_o_u_t function is only used if the standard output does + not correspond to a tty device. It is called whenever data can be + read from the command but before it is written to the standard + output. This allows the plugin to reject data if it chooses to + (for instance if the output contains banned content). Returns 1 if + the data should be passed to the user, 0 if the data is rejected + (which will terminate the command) or -1 if an error occurred. + + The function arguments are as follows: + + buf The buffer containing command output. + + len The length of _b_u_f in bytes. + + log_stderr + int (*log_stderr)(const char *buf, unsigned int len); + + The _l_o_g___s_t_d_e_r_r function is only used if the standard error does not + correspond to a tty device. It is called whenever data can be read + from the command but before it is written to the standard error. + This allows the plugin to reject data if it chooses to (for + instance if the output contains banned content). Returns 1 if the + data should be passed to the user, 0 if the data is rejected (which + will terminate the command) or -1 if an error occurred. + + The function arguments are as follows: + + buf The buffer containing command output. + + len The length of _b_u_f in bytes. + + register_hooks + See the "Policy Plugin API" section for a description of + register_hooks. + + deregister_hooks + See the "Policy Plugin API" section for a description of + deregister_hooks. + + _I_/_O _P_l_u_g_i_n _V_e_r_s_i_o_n _M_a_c_r_o_s + + Same as for the "Policy Plugin API". + + HHooookk FFuunnccttiioonn AAPPII + Beginning with plugin API version 1.2, it is possible to install hooks + for certain functions called by the ssuuddoo front end. + + Currently, the only supported hooks relate to the handling of + environment variables. Hooks can be used to intercept attempts to get, + set, or remove environment variables so that these changes can be + reflected in the version of the environment that is used to execute a + command. A future version of the API will support hooking internal + ssuuddoo front end functions as well. + + _H_o_o_k _s_t_r_u_c_t_u_r_e + + Hooks in ssuuddoo are described by the following structure: + + typedef int (*sudo_hook_fn_t)(); + + struct sudo_hook { + int hook_version; + int hook_type; + sudo_hook_fn_t hook_fn; + void *closure; + }; + + The sudo_hook structure has the following fields: + + hook_version + The hook_version field should be set to SUDO_HOOK_VERSION. + + hook_type + The hook_type field may be one of the following supported hook + types: + + SUDO_HOOK_SETENV + The C library setenv() function. Any registered hooks will run + before the C library implementation. The hook_fn field should + be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_setenv_t)(const char *name, + const char *value, int overwrite, void *closure); + + If the registered hook does not match the typedef the results + are unspecified. + + SUDO_HOOK_UNSETENV + The C library unsetenv() function. Any registered hooks will + run before the C library implementation. The hook_fn field + should be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, + void *closure); + + SUDO_HOOK_GETENV + The C library getenv() function. Any registered hooks will run + before the C library implementation. The hook_fn field should + be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_getenv_t)(const char *name, + char **value, void *closure); + + If the registered hook does not match the typedef the results + are unspecified. + + SUDO_HOOK_PUTENV + The C library putenv() function. Any registered hooks will run + before the C library implementation. The hook_fn field should + be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_putenv_t)(char *string, + void *closure); + + If the registered hook does not match the typedef the results + are unspecified. + + hook_fn + sudo_hook_fn_t hook_fn; + + The hook_fn field should be set to the plugin's hook + implementation. The actual function arguments will vary depending + on the hook_type (see hook_type above). In all cases, the closure + field of struct sudo_hook is passed as the last function parameter. + This can be used to pass arbitrary data to the plugin's hook + implementation. + + The function return value may be one of the following: + + SUDO_HOOK_RET_ERROR + The hook function encountered an error. + + SUDO_HOOK_RET_NEXT + The hook completed without error, go on to the next hook + (including the native implementation if applicable). For + example, a getenv hook might return SUDO_HOOK_RET_NEXT if the + specified variable was not found in the private copy of the + environment. + + SUDO_HOOK_RET_STOP + The hook completed without error, stop processing hooks for + this invocation. This can be used to replace the native + implementation. For example, a setenv hook that operates on a + private copy of the environment but leaves environ unchanged. + + Note that it is very easy to create an infinite loop when hooking C + library functions. For example, a getenv hook that calls the snprintf + function may create a loop if the snprintf implementation calls getenv + to check the locale. To prevent this, you may wish to use a static + variable in the hook function to guard against nested calls. E.g. + + static int in_progress = 0; /* avoid recursion */ + if (in_progress) + return SUDO_HOOK_RET_NEXT; + in_progress = 1; + ... + in_progress = 0; + return SUDO_HOOK_RET_STOP; + + _H_o_o_k _A_P_I _V_e_r_s_i_o_n _M_a_c_r_o_s + + /* Hook API version major/minor */ + #define SUDO_HOOK_VERSION_MAJOR 1 + #define SUDO_HOOK_VERSION_MINOR 0 + #define SUDO_HOOK_MKVERSION(x, y) ((x << 16) | y) + #define SUDO_HOOK_VERSION SUDO_HOOK_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\ + SUDO_HOOK_VERSION_MINOR) + + /* Getters and setters for hook API version */ + #define SUDO_HOOK_VERSION_GET_MAJOR(v) ((v) >> 16) + #define SUDO_HOOK_VERSION_GET_MINOR(v) ((v) & 0xffff) + #define SUDO_HOOK_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ + } while(0) + #define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ + } while(0) + + CCoonnvveerrssaattiioonn AAPPII + If the plugin needs to interact with the user, it may do so via the + conversation function. A plugin should not attempt to read directly + from the standard input or the user's tty (neither of which are + guaranteed to exist). The caller must include a trailing newline in + msg if one is to be printed. + + A printf-style function is also available that can be used to display + informational or error messages to the user, which is usually more + convenient for simple messages where no use input is required. + + struct sudo_conv_message { + #define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */ + #define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */ + #define SUDO_CONV_ERROR_MSG 0x0003 /* error message */ + #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ + #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ + #define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */ + #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ + int msg_type; + int timeout; + const char *msg; + }; + + struct sudo_conv_reply { + char *reply; + }; + + typedef int (*sudo_conv_t)(int num_msgs, + const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[]); + + typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...); + + Pointers to the conversation and printf-style functions are passed in + to the plugin's open function when the plugin is initialized. + + To use the conversation function, the plugin must pass an array of + sudo_conv_message and sudo_conv_reply structures. There must be a + struct sudo_conv_message and struct sudo_conv_reply for each message in + the conversation. The plugin is responsible for freeing the reply + buffer filled in to the struct sudo_conv_reply, if any. + + The printf-style function uses the same underlying mechanism as the + conversation function but only supports SUDO_CONV_INFO_MSG, + SUDO_CONV_ERROR_MSG and SUDO_CONV_DEBUG_MSG for the _m_s_g___t_y_p_e parameter. + It can be more convenient than using the conversation function if no + user reply is needed and supports standard _p_r_i_n_t_f_(_) escape sequences. + + Unlike, SUDO_CONV_INFO_MSG and SUDO_CONV_ERROR_MSG, messages sent with + the _m_s_g___t_y_p_e are not directly user-visible. + Instead, they are logged to the file specified in the Debug statement + (if any) in the _/_e_t_c_/_s_u_d_o_._c_o_n_f file. This allows a plugin to log + debugging information and is intended to be used in conjunction with + the _d_e_b_u_g___f_l_a_g_s setting. + + See the sample plugin for an example of the conversation function + usage. + + SSuuddooeerrss GGrroouupp PPlluuggiinn AAPPII + The _s_u_d_o_e_r_s module supports a plugin interface to allow non-Unix group + lookups. This can be used to query a group source other than the + standard Unix group database. A sample group plugin is bundled with + ssuuddoo that implements file-based lookups. Third party group plugins + include a QAS AD plugin available from Quest Software. + + A group plugin must declare and populate a sudoers_group_plugin struct + in the global scope. This structure contains pointers to the functions + that implement plugin initialization, cleanup and group lookup. + + struct sudoers_group_plugin { + unsigned int version; + int (*init)(int version, sudo_printf_t sudo_printf, + char *const argv[]); + void (*cleanup)(void); + int (*query)(const char *user, const char *group, + const struct passwd *pwd); + }; + + The sudoers_group_plugin struct has the following fields: + + version + The version field should be set to GROUP_API_VERSION. + + This allows _s_u_d_o_e_r_s to determine the API version the group plugin + was built against. + + init + int (*init)(int version, sudo_printf_t plugin_printf, + char *const argv[]); + + The _i_n_i_t function is called after _s_u_d_o_e_r_s has been parsed but + before any policy checks. It returns 1 on success, 0 on failure + (or if the plugin is not configured), and -1 if a error occurred. + If an error occurs, the plugin may call the plugin_printf function + with SUDO_CONF_ERROR_MSG to present additional error information to + the user. + + The function arguments are as follows: + + version + The version passed in by _s_u_d_o_e_r_s allows the plugin to determine + the major and minor version number of the group plugin API + supported by _s_u_d_o_e_r_s. + + plugin_printf + A pointer to a printf-style function that may be used to + display informational or error message to the user. Returns + the number of characters printed on success and -1 on failure. + + argv + A NULL-terminated array of arguments generated from the + _g_r_o_u_p___p_l_u_g_i_n option in _s_u_d_o_e_r_s. If no arguments were given, + _a_r_g_v will be NULL. + + cleanup + void (*cleanup)(); + + The _c_l_e_a_n_u_p function is called when _s_u_d_o_e_r_s has finished its group + checks. The plugin should free any memory it has allocated and + close open file handles. + + query + int (*query)(const char *user, const char *group, + const struct passwd *pwd); + + The _q_u_e_r_y function is used to ask the group plugin whether _u_s_e_r is + a member of _g_r_o_u_p. + + The function arguments are as follows: + + user + The name of the user being looked up in the external group + database. + + group + The name of the group being queried. + + pwd The password database entry for _u_s_e_r, if any. If _u_s_e_r is not + present in the password database, _p_w_d will be NULL. + + _G_r_o_u_p _A_P_I _V_e_r_s_i_o_n _M_a_c_r_o_s + + /* Sudoers group plugin version major/minor */ + #define GROUP_API_VERSION_MAJOR 1 + #define GROUP_API_VERSION_MINOR 0 + #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \ + GROUP_API_VERSION_MINOR) + + /* Getters and setters for group version */ + #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16) + #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff) + #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ + } while(0) + #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ + } while(0) + +PPLLUUGGIINN AAPPII CCHHAANNGGEELLOOGG + The following revisions have been made to the Sudo Plugin API. + + Version 1.0 + Initial API version. + + Version 1.1 + The I/O logging plugin's open function was modified to take the + command_info list as an argument. + + Version 1.2 + The Policy and I/O logging plugins' open functions are now passed a + list of plugin options if any are specified in _/_e_t_c_/_s_u_d_o_._c_o_n_f. + + A simple hooks API has been introduced to allow plugins to hook in + to the system's environment handling functions. + + The init_session Policy plugin function is now passed a pointer to + the user environment which can be updated as needed. This can be + used to merge in environment variables stored in the PAM handle + before a command is run. + +SSEEEE AALLSSOO + _s_u_d_o_e_r_s(4), _s_u_d_o(1m) + +BBUUGGSS + If you feel you have found a bug in ssuuddoo, please submit a bug report at + http://www.sudo.ws/sudo/bugs/ + +SSUUPPPPOORRTT + Limited free support is available via the sudo-workers mailing list, + see http://www.sudo.ws/mailman/listinfo/sudo-workers to subscribe or + search the archives. + +DDIISSCCLLAAIIMMEERR + ssuuddoo is provided ``AS IS'' and any express or implied warranties, + including, but not limited to, the implied warranties of + merchantability and fitness for a particular purpose are disclaimed. + See the LICENSE file distributed with ssuuddoo or + http://www.sudo.ws/sudo/license.html for complete details. + + + +1.8.5 April 23, 2012 SUDO_PLUGIN(1m) diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in new file mode 100644 index 0000000..ca9589f --- /dev/null +++ b/doc/sudo_plugin.man.in @@ -0,0 +1,1637 @@ +.\" Copyright (c) 2009-2012 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. +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SUDO_PLUGIN @mansectsu@" +.TH SUDO_PLUGIN @mansectsu@ "April 23, 2012" "1.8.5" "MAINTENANCE COMMANDS" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +sudo_plugin \- Sudo Plugin API +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +Starting with version 1.8, \fBsudo\fR supports a plugin \s-1API\s0 +for policy and session logging. By default, the \fIsudoers\fR policy +plugin and an associated I/O logging plugin are used. Via the plugin +\&\s-1API\s0, \fBsudo\fR can be configured to use alternate policy and/or I/O +logging plugins provided by third parties. The plugins to be used +are specified via the \fI@sysconfdir@/sudo.conf\fR file. +.PP +The \s-1API\s0 is versioned with a major and minor number. The minor +version number is incremented when additions are made. The major +number is incremented when incompatible changes are made. A plugin +should be check the version passed to it and make sure that the +major version matches. +.PP +The plugin \s-1API\s0 is defined by the \f(CW\*(C`sudo_plugin.h\*(C'\fR header file. +.SS "The sudo.conf File" +.IX Subsection "The sudo.conf File" +The \fI@sysconfdir@/sudo.conf\fR file contains plugin configuration directives. +Currently, the only supported keyword is the \f(CW\*(C`Plugin\*(C'\fR directive, +which causes a plugin plugin to be loaded. +.PP +A \f(CW\*(C`Plugin\*(C'\fR line consists of the \f(CW\*(C`Plugin\*(C'\fR keyword, followed by the +\&\fIsymbol_name\fR and the \fIpath\fR to the shared object containing the +plugin. The \fIsymbol_name\fR is the name of the \f(CW\*(C`struct policy_plugin\*(C'\fR +or \f(CW\*(C`struct io_plugin\*(C'\fR in the plugin shared object. The \fIpath\fR +may be fully qualified or relative. If not fully qualified it is +relative to the \fI@prefix@/libexec\fR directory. Any additional +parameters after the \fIpath\fR are passed as options to the plugin's +\&\fIopen\fR function. Lines that don't begin with \f(CW\*(C`Plugin\*(C'\fR, \f(CW\*(C`Path\*(C'\fR, +\&\f(CW\*(C`Debug\*(C'\fR or \f(CW\*(C`Set\*(C'\fR are silently ignored. +.PP +The same shared object may contain multiple plugins, each with a +different symbol name. The shared object file must be owned by uid +0 and only writable by its owner. Because of ambiguities that arise +from composite policies, only a single policy plugin may be specified. +This limitation does not apply to I/O plugins. +.PP +.Vb 10 +\& # +\& # Default @sysconfdir@/sudo.conf file +\& # +\& # Format: +\& # Plugin plugin_name plugin_path plugin_options ... +\& # Path askpass /path/to/askpass +\& # Path noexec /path/to/sudo_noexec.so +\& # Debug sudo /var/log/sudo_debug all@warn +\& # Set disable_coredump true +\& # +\& # The plugin_path is relative to @prefix@/libexec unless +\& # fully qualified. +\& # The plugin_name corresponds to a global symbol in the plugin +\& # that contains the plugin interface structure. +\& # The plugin_options are optional. +\& # +\& Plugin sudoers_policy sudoers.so +\& Plugin sudoers_io sudoers.so +.Ve +.SS "Policy Plugin \s-1API\s0" +.IX Subsection "Policy Plugin API" +A policy plugin must declare and populate a \f(CW\*(C`policy_plugin\*(C'\fR struct +in the global scope. This structure contains pointers to the functions +that implement the \fBsudo\fR policy checks. The name of the symbol should +be specified in \fI@sysconfdir@/sudo.conf\fR along with a path to the plugin +so that \fBsudo\fR can load it. +.PP +.Vb 10 +\& struct policy_plugin { +\& #define SUDO_POLICY_PLUGIN 1 +\& unsigned int type; /* always SUDO_POLICY_PLUGIN */ +\& unsigned int version; /* always SUDO_API_VERSION */ +\& int (*open)(unsigned int version, sudo_conv_t conversation, +\& sudo_printf_t plugin_printf, char * const settings[], +\& char * const user_info[], char * const user_env[], +\& char * const plugin_options[]); +\& void (*close)(int exit_status, int error); +\& int (*show_version)(int verbose); +\& int (*check_policy)(int argc, char * const argv[], +\& char *env_add[], char **command_info[], +\& char **argv_out[], char **user_env_out[]); +\& int (*list)(int argc, char * const argv[], int verbose, +\& const char *list_user); +\& int (*validate)(void); +\& void (*invalidate)(int remove); +\& int (*init_session)(struct passwd *pwd, char **user_env[]); +\& void (*register_hooks)(int version, +\& int (*register_hook)(struct sudo_hook *hook)); +\& void (*deregister_hooks)(int version, +\& int (*deregister_hook)(struct sudo_hook *hook)); +\& }; +.Ve +.PP +The policy_plugin struct has the following fields: +.IP "type" 4 +.IX Item "type" +The \f(CW\*(C`type\*(C'\fR field should always be set to \s-1SUDO_POLICY_PLUGIN\s0. +.IP "version" 4 +.IX Item "version" +The \f(CW\*(C`version\*(C'\fR field should be set to \s-1SUDO_API_VERSION\s0. +.Sp +This allows \fBsudo\fR to determine the \s-1API\s0 version the plugin was +built against. +.IP "open" 4 +.IX Item "open" +.Vb 4 +\& int (*open)(unsigned int version, sudo_conv_t conversation, +\& sudo_printf_t plugin_printf, char * const settings[], +\& char * const user_info[], char * const user_env[], +\& char * const plugin_options[]); +.Ve +.Sp +Returns 1 on success, 0 on failure, \-1 if a general error occurred, +or \-2 if there was a usage error. In the latter case, \fBsudo\fR will +print a usage message before it exits. If an error occurs, the +plugin may optionally call the conversation or plugin_printf function +with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information +to the user. +.Sp +The function arguments are as follows: +.RS 4 +.IP "version" 4 +.IX Item "version" +The version passed in by \fBsudo\fR allows the plugin to determine the +major and minor version number of the plugin \s-1API\s0 supported by +\&\fBsudo\fR. +.IP "conversation" 4 +.IX Item "conversation" +A pointer to the conversation function that can be used by the +plugin to interact with the user (see below). +Returns 0 on success and \-1 on failure. +.IP "plugin_printf" 4 +.IX Item "plugin_printf" +A pointer to a printf-style function that may be used to display +informational or error messages (see below). +Returns the number of characters printed on success and \-1 on failure. +.IP "settings" 4 +.IX Item "settings" +A vector of user-supplied \fBsudo\fR settings in the form of \*(L"name=value\*(R" +strings. The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer. These +settings correspond to flags the user specified when running \fBsudo\fR. +As such, they will only be present when the corresponding flag has +been specified on the command line. +.Sp +When parsing \fIsettings\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.RS 4 +.IP "debug_flags=string" 4 +.IX Item "debug_flags=string" +A comma-separated list of debug flags that correspond to \fBsudo\fR's +\&\f(CW\*(C`Debug\*(C'\fR entry in \fI@sysconfdir@/sudo.conf\fR, if there is one. The +flags are passed to the plugin as they appear in \fI@sysconfdir@/sudo.conf\fR. +The syntax used by \fBsudo\fR and the \fIsudoers\fR plugin is +\&\fIsubsystem\fR@\fIpriority\fR but the plugin is free to use a different +format so long as it does not include a command \f(CW\*(C`,\*(C'\fR. +.Sp +For reference, the priorities supported by the \fBsudo\fR front end and +\&\fIsudoers\fR are: \fIcrit\fR, \fIerr\fR, \fIwarn\fR, \fInotice\fR, \fIdiag\fR, +\&\fIinfo\fR, \fItrace\fR and \fIdebug\fR. +.Sp +The following subsystems are defined: \fImain\fR, \fImemory\fR, \fIargs\fR, +\&\fIexec\fR, \fIpty\fR, \fIutmp\fR, \fIconv\fR, \fIpcomm\fR, \fIutil\fR, \fIlist\fR, +\&\fInetif\fR, \fIaudit\fR, \fIedit\fR, \fIselinux\fR, \fIldap\fR, \fImatch\fR, \fIparser\fR, +\&\fIalias\fR, \fIdefaults\fR, \fIauth\fR, \fIenv\fR, \fIlogging\fR, \fInss\fR, \fIrbtree\fR, +\&\fIperms\fR, \fIplugin\fR. The subsystem \fIall\fR includes every subsystem. +.Sp +There is not currently a way to specify a set of debug flags specific +to the plugin\*(--the flags are shared by \fBsudo\fR and the plugin. +.IP "debug_level=number" 4 +.IX Item "debug_level=number" +This setting has been deprecated in favor of \fIdebug_flags\fR. +.IP "runas_user=string" 4 +.IX Item "runas_user=string" +The user name or uid to to run the command as, if specified via the +\&\f(CW\*(C`\-u\*(C'\fR flag. +.IP "runas_group=string" 4 +.IX Item "runas_group=string" +The group name or gid to to run the command as, if specified via +the \f(CW\*(C`\-g\*(C'\fR flag. +.IP "prompt=string" 4 +.IX Item "prompt=string" +The prompt to use when requesting a password, if specified via +the \f(CW\*(C`\-p\*(C'\fR flag. +.IP "set_home=bool" 4 +.IX Item "set_home=bool" +Set to true if the user specified the \f(CW\*(C`\-H\*(C'\fR flag. If true, set the +\&\f(CW\*(C`HOME\*(C'\fR environment variable to the target user's home directory. +.IP "preserve_environment=bool" 4 +.IX Item "preserve_environment=bool" +Set to true if the user specified the \f(CW\*(C`\-E\*(C'\fR flag, indicating that +the user wishes to preserve the environment. +.IP "run_shell=bool" 4 +.IX Item "run_shell=bool" +Set to true if the user specified the \f(CW\*(C`\-s\*(C'\fR flag, indicating that +the user wishes to run a shell. +.IP "login_shell=bool" 4 +.IX Item "login_shell=bool" +Set to true if the user specified the \f(CW\*(C`\-i\*(C'\fR flag, indicating that +the user wishes to run a login shell. +.IP "implied_shell=bool" 4 +.IX Item "implied_shell=bool" +If the user does not specify a program on the command line, \fBsudo\fR +will pass the plugin the path to the user's shell and set +\&\fIimplied_shell\fR to true. This allows \fBsudo\fR with no arguments +to be used similarly to \fIsu\fR\|(1). If the plugin does not to support +this usage, it may return a value of \-2 from the \f(CW\*(C`check_policy\*(C'\fR +function, which will cause \fBsudo\fR to print a usage message and +exit. +.IP "preserve_groups=bool" 4 +.IX Item "preserve_groups=bool" +Set to true if the user specified the \f(CW\*(C`\-P\*(C'\fR flag, indicating that +the user wishes to preserve the group vector instead of setting it +based on the runas user. +.IP "ignore_ticket=bool" 4 +.IX Item "ignore_ticket=bool" +Set to true if the user specified the \f(CW\*(C`\-k\*(C'\fR flag along with a +command, indicating that the user wishes to ignore any cached +authentication credentials. +.IP "noninteractive=bool" 4 +.IX Item "noninteractive=bool" +Set to true if the user specified the \f(CW\*(C`\-n\*(C'\fR flag, indicating that +\&\fBsudo\fR should operate in non-interactive mode. The plugin may +reject a command run in non-interactive mode if user interaction +is required. +.IP "login_class=string" 4 +.IX Item "login_class=string" +\&\s-1BSD\s0 login class to use when setting resource limits and nice value, +if specified by the \f(CW\*(C`\-c\*(C'\fR flag. +.IP "selinux_role=string" 4 +.IX Item "selinux_role=string" +SELinux role to use when executing the command, if specified by +the \f(CW\*(C`\-r\*(C'\fR flag. +.IP "selinux_type=string" 4 +.IX Item "selinux_type=string" +SELinux type to use when executing the command, if specified by +the \f(CW\*(C`\-t\*(C'\fR flag. +.IP "bsdauth_type=string" 4 +.IX Item "bsdauth_type=string" +Authentication type, if specified by the \f(CW\*(C`\-a\*(C'\fR flag, to use on +systems where \s-1BSD\s0 authentication is supported. +.IP "network_addrs=list" 4 +.IX Item "network_addrs=list" +A space-separated list of \s-1IP\s0 network addresses and netmasks in the +form \*(L"addr/netmask\*(R", e.g. \*(L"192.168.1.2/255.255.255.0\*(R". The address +and netmask pairs may be either IPv4 or IPv6, depending on what the +operating system supports. If the address contains a colon (':'), +it is an IPv6 address, else it is IPv4. +.IP "progname=string" 4 +.IX Item "progname=string" +The command name that sudo was run as, typically \*(L"sudo\*(R" or \*(L"sudoedit\*(R". +.IP "sudoedit=bool" 4 +.IX Item "sudoedit=bool" +Set to true when the \f(CW\*(C`\-e\*(C'\fR flag is is specified or if invoked as +\&\fBsudoedit\fR. The plugin shall substitute an editor into \fIargv\fR +in the \fIcheck_policy\fR function or return \f(CW\*(C`\-2\*(C'\fR with a usage error +if the plugin does not support \fIsudoedit\fR. For more information, +see the \fIcheck_policy\fR section. +.IP "closefrom=number" 4 +.IX Item "closefrom=number" +If specified, the user has requested via the \f(CW\*(C`\-C\*(C'\fR flag that \fBsudo\fR +close all files descriptors with a value of \fInumber\fR or higher. +The plugin may optionally pass this, or another value, back in the +\&\fIcommand_info\fR list. +.RE +.RS 4 +.Sp +Additional settings may be added in the future so the plugin should +silently ignore settings that it does not recognize. +.RE +.IP "user_info" 4 +.IX Item "user_info" +A vector of information about the user running the command in the form of +\&\*(L"name=value\*(R" strings. The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer. +.Sp +When parsing \fIuser_info\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.RS 4 +.IP "pid=int" 4 +.IX Item "pid=int" +The process \s-1ID\s0 of the running \fBsudo\fR process. +Only available starting with \s-1API\s0 version 1.2 +.IP "ppid=int" 4 +.IX Item "ppid=int" +The parent process \s-1ID\s0 of the running \fBsudo\fR process. +Only available starting with \s-1API\s0 version 1.2 +.IP "sid=int" 4 +.IX Item "sid=int" +The session \s-1ID\s0 of the running \fBsudo\fR process or 0 if \fBsudo\fR is +not part of a \s-1POSIX\s0 job control session. +Only available starting with \s-1API\s0 version 1.2 +.IP "pgid=int" 4 +.IX Item "pgid=int" +The \s-1ID\s0 of the process group that the running \fBsudo\fR process belongs +to. +Only available starting with \s-1API\s0 version 1.2 +.IP "tcpgid=int" 4 +.IX Item "tcpgid=int" +The \s-1ID\s0 of the forground process group associated with the terminal +device associcated with the \fBsudo\fR process or \-1 if there is no +terminal present. +Only available starting with \s-1API\s0 version 1.2 +.IP "user=string" 4 +.IX Item "user=string" +The name of the user invoking \fBsudo\fR. +.IP "euid=uid_t" 4 +.IX Item "euid=uid_t" +The effective user \s-1ID\s0 of the user invoking \fBsudo\fR. +.IP "uid=uid_t" 4 +.IX Item "uid=uid_t" +The real user \s-1ID\s0 of the user invoking \fBsudo\fR. +.IP "egid=gid_t" 4 +.IX Item "egid=gid_t" +The effective group \s-1ID\s0 of the user invoking \fBsudo\fR. +.IP "gid=gid_t" 4 +.IX Item "gid=gid_t" +The real group \s-1ID\s0 of the user invoking \fBsudo\fR. +.IP "groups=list" 4 +.IX Item "groups=list" +The user's supplementary group list formatted as a string of +comma-separated group IDs. +.IP "cwd=string" 4 +.IX Item "cwd=string" +The user's current working directory. +.IP "tty=string" 4 +.IX Item "tty=string" +The path to the user's terminal device. If the user has no terminal +device associated with the session, the value will be empty, as in +\&\f(CW\*(C`tty=\*(C'\fR. +.IP "host=string" 4 +.IX Item "host=string" +The local machine's hostname as returned by the \f(CW\*(C`gethostname()\*(C'\fR +system call. +.IP "lines=int" 4 +.IX Item "lines=int" +The number of lines the user's terminal supports. If there is +no terminal device available, a default value of 24 is used. +.IP "cols=int" 4 +.IX Item "cols=int" +The number of columns the user's terminal supports. If there is +no terminal device available, a default value of 80 is used. +.RE +.RS 4 +.RE +.IP "user_env" 4 +.IX Item "user_env" +The user's environment in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of +\&\*(L"name=value\*(R" strings. +.Sp +When parsing \fIuser_env\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.IP "plugin_options" 4 +.IX Item "plugin_options" +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a white space boundary and are passed to the plugin in the form of +a \f(CW\*(C`NULL\*(C'\fR\-terminated array of strings. If no arguments were +specified, \fIplugin_options\fR will be the \s-1NULL\s0 pointer. +.Sp +\&\s-1NOTE:\s0 the \fIplugin_options\fR parameter is only available starting with +\&\s-1API\s0 version 1.2. A plugin \fBmust\fR check the \s-1API\s0 version specified +by the \fBsudo\fR front end before using \fIplugin_options\fR. Failure to +do so may result in a crash. +.RE +.RS 4 +.RE +.IP "close" 4 +.IX Item "close" +.Vb 1 +\& void (*close)(int exit_status, int error); +.Ve +.Sp +The \f(CW\*(C`close\*(C'\fR function is called when the command being run by \fBsudo\fR +finishes. +.Sp +The function arguments are as follows: +.RS 4 +.IP "exit_status" 4 +.IX Item "exit_status" +The command's exit status, as returned by the \fIwait\fR\|(2) system call. +The value of \f(CW\*(C`exit_status\*(C'\fR is undefined if \f(CW\*(C`error\*(C'\fR is non-zero. +.IP "error" 4 +.IX Item "error" +If the command could not be executed, this is set to the value of +\&\f(CW\*(C`errno\*(C'\fR set by the \fIexecve\fR\|(2) system call. The plugin is responsible +for displaying error information via the conversation or plugin_printf +function. If the command was successfully executed, the value of +\&\f(CW\*(C`error\*(C'\fR is 0. +.RE +.RS 4 +.RE +.IP "show_version" 4 +.IX Item "show_version" +.Vb 1 +\& int (*show_version)(int verbose); +.Ve +.Sp +The \f(CW\*(C`show_version\*(C'\fR function is called by \fBsudo\fR when the user specifies +the \f(CW\*(C`\-V\*(C'\fR option. The plugin may display its version information +to the user via the conversation or plugin_printf function using +\&\f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR. If the user requests detailed version +information, the verbose flag will be set. +.IP "check_policy" 4 +.IX Item "check_policy" +.Vb 3 +\& int (*check_policy)(int argc, char * const argv[] +\& char *env_add[], char **command_info[], +\& char **argv_out[], char **user_env_out[]); +.Ve +.Sp +The \fIcheck_policy\fR function is called by \fBsudo\fR to determine +whether the user is allowed to run the specified commands. +.Sp +If the \fIsudoedit\fR option was enabled in the \fIsettings\fR array +passed to the \fIopen\fR function, the user has requested \fIsudoedit\fR +mode. \fIsudoedit\fR is a mechanism for editing one or more files +where an editor is run with the user's credentials instead of with +elevated privileges. \fBsudo\fR achieves this by creating user-writable +temporary copies of the files to be edited and then overwriting the +originals with the temporary copies after editing is complete. If +the plugin supports \fBsudoedit\fR, it should choose the editor to be +used, potentially from a variable in the user's environment, such +as \f(CW\*(C`EDITOR\*(C'\fR, and include it in \fIargv_out\fR (note that environment +variables may include command line flags). The files to be edited +should be copied from \fIargv\fR into \fIargv_out\fR, separated from the +editor and its arguments by a \f(CW"\-\-"\fR element. The \f(CW"\-\-"\fR will +be removed by \fBsudo\fR before the editor is executed. The plugin +should also set \fIsudoedit=true\fR in the \fIcommand_info\fR list. +.Sp +The \fIcheck_policy\fR function returns 1 if the command is allowed, +0 if not allowed, \-1 for a general error, or \-2 for a usage error +or if \fBsudoedit\fR was specified but is unsupported by the plugin. +In the latter case, \fBsudo\fR will print a usage message before it +exits. If an error occurs, the plugin may optionally call the +conversation or plugin_printf function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR +to present additional error information to the user. +.Sp +The function arguments are as follows: +.RS 4 +.IP "argc" 4 +.IX Item "argc" +The number of elements in \fIargv\fR, not counting the final \f(CW\*(C`NULL\*(C'\fR +pointer. +.IP "argv" 4 +.IX Item "argv" +The argument vector describing the command the user wishes to run, +in the same form as what would be passed to the \fIexecve()\fR system +call. The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer. +.IP "env_add" 4 +.IX Item "env_add" +Additional environment variables specified by the user on the command +line in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of \*(L"name=value\*(R" +strings. The plugin may reject the command if one or more variables +are not allowed to be set, or it may silently ignore such variables. +.Sp +When parsing \fIenv_add\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.IP "command_info" 4 +.IX Item "command_info" +Information about the command being run in the form of \*(L"name=value\*(R" +strings. These values are used by \fBsudo\fR to set the execution +environment when running a command. The plugin is responsible for +creating and populating the vector, which must be terminated with +a \f(CW\*(C`NULL\*(C'\fR pointer. The following values are recognized by \fBsudo\fR: +.RS 4 +.IP "command=string" 4 +.IX Item "command=string" +Fully qualified path to the command to be executed. +.IP "runas_uid=uid" 4 +.IX Item "runas_uid=uid" +User \s-1ID\s0 to run the command as. +.IP "runas_euid=uid" 4 +.IX Item "runas_euid=uid" +Effective user \s-1ID\s0 to run the command as. +If not specified, the value of \fIrunas_uid\fR is used. +.IP "runas_gid=gid" 4 +.IX Item "runas_gid=gid" +Group \s-1ID\s0 to run the command as. +.IP "runas_egid=gid" 4 +.IX Item "runas_egid=gid" +Effective group \s-1ID\s0 to run the command as. +If not specified, the value of \fIrunas_gid\fR is used. +.IP "runas_groups=list" 4 +.IX Item "runas_groups=list" +The supplementary group vector to use for the command in the form +of a comma-separated list of group IDs. If \fIpreserve_groups\fR +is set, this option is ignored. +.IP "login_class=string" 4 +.IX Item "login_class=string" +\&\s-1BSD\s0 login class to use when setting resource limits and nice value +(optional). This option is only set on systems that support login +classes. +.IP "preserve_groups=bool" 4 +.IX Item "preserve_groups=bool" +If set, \fBsudo\fR will preserve the user's group vector instead of +initializing the group vector based on \f(CW\*(C`runas_user\*(C'\fR. +.IP "cwd=string" 4 +.IX Item "cwd=string" +The current working directory to change to when executing the command. +.IP "noexec=bool" 4 +.IX Item "noexec=bool" +If set, prevent the command from executing other programs. +.IP "chroot=string" 4 +.IX Item "chroot=string" +The root directory to use when running the command. +.IP "nice=int" 4 +.IX Item "nice=int" +Nice value (priority) to use when executing the command. The nice +value, if specified, overrides the priority associated with the +\&\fIlogin_class\fR on \s-1BSD\s0 systems. +.IP "umask=octal" 4 +.IX Item "umask=octal" +The file creation mask to use when executing the command. +.IP "selinux_role=string" 4 +.IX Item "selinux_role=string" +SELinux role to use when executing the command. +.IP "selinux_type=string" 4 +.IX Item "selinux_type=string" +SELinux type to use when executing the command. +.IP "timeout=int" 4 +.IX Item "timeout=int" +Command timeout. If non-zero then when the timeout expires the +command will be killed. +.IP "sudoedit=bool" 4 +.IX Item "sudoedit=bool" +Set to true when in \fIsudoedit\fR mode. The plugin may enable +\&\fIsudoedit\fR mode even if \fBsudo\fR was not invoked as \fBsudoedit\fR. +This allows the plugin to perform command substitution and transparently +enable \fIsudoedit\fR when the user attempts to run an editor. +.IP "closefrom=number" 4 +.IX Item "closefrom=number" +If specified, \fBsudo\fR will close all files descriptors with a value +of \fInumber\fR or higher. +.IP "iolog_compress=bool" 4 +.IX Item "iolog_compress=bool" +Set to true if the I/O logging plugins, if any, should compress the +log data. This is a hint to the I/O logging plugin which may choose +to ignore it. +.IP "iolog_path=string" 4 +.IX Item "iolog_path=string" +Fully qualified path to the file or directory in which I/O log is +to be stored. This is a hint to the I/O logging plugin which may +choose to ignore it. If no I/O logging plugin is loaded, this +setting has no effect. +.IP "iolog_stdin=bool" 4 +.IX Item "iolog_stdin=bool" +Set to true if the I/O logging plugins, if any, should log the +standard input if it is not connected to a terminal device. This +is a hint to the I/O logging plugin which may choose to ignore it. +.IP "iolog_stdout=bool" 4 +.IX Item "iolog_stdout=bool" +Set to true if the I/O logging plugins, if any, should log the +standard output if it is not connected to a terminal device. This +is a hint to the I/O logging plugin which may choose to ignore it. +.IP "iolog_stderr=bool" 4 +.IX Item "iolog_stderr=bool" +Set to true if the I/O logging plugins, if any, should log the +standard error if it is not connected to a terminal device. This +is a hint to the I/O logging plugin which may choose to ignore it. +.IP "iolog_ttyin=bool" 4 +.IX Item "iolog_ttyin=bool" +Set to true if the I/O logging plugins, if any, should log all +terminal input. This only includes input typed by the user and not +from a pipe or redirected from a file. This is a hint to the I/O +logging plugin which may choose to ignore it. +.IP "iolog_ttyout=bool" 4 +.IX Item "iolog_ttyout=bool" +Set to true if the I/O logging plugins, if any, should log all +terminal output. This only includes output to the screen, not +output to a pipe or file. This is a hint to the I/O logging plugin +which may choose to ignore it. +.IP "use_pty=bool" 4 +.IX Item "use_pty=bool" +Allocate a pseudo-tty to run the command in, regardless of whether +or not I/O logging is in use. By default, \fBsudo\fR will only run +the command in a pty when an I/O log plugin is loaded. +.IP "set_utmp=bool" 4 +.IX Item "set_utmp=bool" +Create a utmp (or utmpx) entry when a pseudo-tty is allocated. By +default, the new entry will be a copy of the user's existing utmp +entry (if any), with the tty, time, type and pid fields updated. +.IP "utmp_user=string" 4 +.IX Item "utmp_user=string" +User name to use when constructing a new utmp (or utmpx) entry when +\&\fIset_utmp\fR is enabled. This option can be used to set the user +field in the utmp entry to the user the command runs as rather than +the invoking user. If not set, \fBsudo\fR will base the new entry on +the invoking user's existing entry. +.RE +.RS 4 +.Sp +Unsupported values will be ignored. +.RE +.IP "argv_out" 4 +.IX Item "argv_out" +The \f(CW\*(C`NULL\*(C'\fR\-terminated argument vector to pass to the \fIexecve()\fR +system call when executing the command. The plugin is responsible +for allocating and populating the vector. +.IP "user_env_out" 4 +.IX Item "user_env_out" +The \f(CW\*(C`NULL\*(C'\fR\-terminated environment vector to use when executing the +command. The plugin is responsible for allocating and populating +the vector. +.RE +.RS 4 +.RE +.IP "list" 4 +.IX Item "list" +.Vb 2 +\& int (*list)(int verbose, const char *list_user, +\& int argc, char * const argv[]); +.Ve +.Sp +List available privileges for the invoking user. Returns 1 on +success, 0 on failure and \-1 on error. On error, the plugin may +optionally call the conversation or plugin_printf function with +\&\f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information to +the user. +.Sp +Privileges should be output via the conversation or plugin_printf +function using \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR. +.RS 4 +.IP "verbose" 4 +.IX Item "verbose" +Flag indicating whether to list in verbose mode or not. +.IP "list_user" 4 +.IX Item "list_user" +The name of a different user to list privileges for if the policy +allows it. If \f(CW\*(C`NULL\*(C'\fR, the plugin should list the privileges of +the invoking user. +.IP "argc" 4 +.IX Item "argc" +The number of elements in \fIargv\fR, not counting the final \f(CW\*(C`NULL\*(C'\fR +pointer. +.IP "argv" 4 +.IX Item "argv" +If non\-\f(CW\*(C`NULL\*(C'\fR, an argument vector describing a command the user +wishes to check against the policy in the same form as what would +be passed to the \fIexecve()\fR system call. If the command is permitted +by the policy, the fully-qualified path to the command should be +displayed along with any command line arguments. +.RE +.RS 4 +.RE +.IP "validate" 4 +.IX Item "validate" +.Vb 1 +\& int (*validate)(void); +.Ve +.Sp +The \f(CW\*(C`validate\*(C'\fR function is called when \fBsudo\fR is run with the +\&\f(CW\*(C`\-v\*(C'\fR flag. For policy plugins such as \fIsudoers\fR that cache +authentication credentials, this function will validate and cache +the credentials. +.Sp +The \f(CW\*(C`validate\*(C'\fR function should be \f(CW\*(C`NULL\*(C'\fR if the plugin does not +support credential caching. +.Sp +Returns 1 on success, 0 on failure and \-1 on error. +On error, the plugin may optionally call the conversation or plugin_printf +function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional +error information to the user. +.IP "invalidate" 4 +.IX Item "invalidate" +.Vb 1 +\& void (*invalidate)(int remove); +.Ve +.Sp +The \f(CW\*(C`invalidate\*(C'\fR function is called when \fBsudo\fR is called with +the \f(CW\*(C`\-k\*(C'\fR or \f(CW\*(C`\-K\*(C'\fR flag. For policy plugins such as \fIsudoers\fR that +cache authentication credentials, this function will invalidate the +credentials. If the \fIremove\fR flag is set, the plugin may remove +the credentials instead of simply invalidating them. +.Sp +The \f(CW\*(C`invalidate\*(C'\fR function should be \f(CW\*(C`NULL\*(C'\fR if the plugin does not +support credential caching. +.IP "init_session" 4 +.IX Item "init_session" +.Vb 1 +\& int (*init_session)(struct passwd *pwd, char **user_envp[); +.Ve +.Sp +The \f(CW\*(C`init_session\*(C'\fR function is called before \fBsudo\fR sets up the +execution environment for the command. It is run in the parent +\&\fBsudo\fR process and before any uid or gid changes. This can be used +to perform session setup that is not supported by \fIcommand_info\fR, +such as opening the \s-1PAM\s0 session. The \f(CW\*(C`close\*(C'\fR function can be +used to tear down the session that was opened by \f(CW\*(C`init_session\*(C'\fR. +.Sp +The \fIpwd\fR argument points to a passwd struct for the user the +command will be run as if the uid the command will run as was found +in the password database, otherwise it will be \s-1NULL\s0. +.Sp +The \fIuser_env\fR argument points to the environment the command will +run in, in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of \*(L"name=value\*(R" +strings. This is the same string passed back to the front end via +the Policy Plugin's \fIuser_env_out\fR parameter. If the \f(CW\*(C`init_session\*(C'\fR +function needs to modify the user environment, it should update the +pointer stored in \fIuser_env\fR. The expected use case is to merge +the contents of the \s-1PAM\s0 environment (if any) with the contents of +\&\fIuser_env\fR. \s-1NOTE:\s0 the \fIuser_env\fR parameter is only available +starting with \s-1API\s0 version 1.2. A plugin \fBmust\fR check the \s-1API\s0 +version specified by the \fBsudo\fR front end before using \fIuser_env\fR. +Failure to do so may result in a crash. +.Sp +Returns 1 on success, 0 on failure and \-1 on error. +On error, the plugin may optionally call the conversation or plugin_printf +function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional +error information to the user. +.IP "register_hooks" 4 +.IX Item "register_hooks" +.Vb 2 +\& void (*register_hooks)(int version, +\& int (*register_hook)(struct sudo_hook *hook)); +.Ve +.Sp +The \f(CW\*(C`register_hooks\*(C'\fR function is called by the sudo front end to +register any hooks the plugin needs. If the plugin does not support +hooks, \f(CW\*(C`register_hooks\*(C'\fR should be set to the \s-1NULL\s0 pointer. +.Sp +The \fIversion\fR argument describes the version of the hooks \s-1API\s0 +supported by the \fBsudo\fR front end. +.Sp +The \f(CW\*(C`register_hook\*(C'\fR function should be used to register any supported +hooks the plugin needs. It returns 0 on success, 1 if the hook +type is not supported and \-1 if the major version in \f(CW\*(C`struct hook\*(C'\fR +does not match the front end's major hook \s-1API\s0 version. +.Sp +See the \*(L"Hook Function \s-1API\s0\*(R" section below for more information +about hooks. +.Sp +\&\s-1NOTE:\s0 the \f(CW\*(C`register_hooks\*(C'\fR function is only available starting +with \s-1API\s0 version 1.2. If the \fBsudo\fR front end doesn't support \s-1API\s0 +version 1.2 or higher, \f(CW\*(C`register_hooks\*(C'\fR will not be called. +.IP "deregister_hooks" 4 +.IX Item "deregister_hooks" +.Vb 2 +\& void (*deregister_hooks)(int version, +\& int (*deregister_hook)(struct sudo_hook *hook)); +.Ve +.Sp +The \f(CW\*(C`deregister_hooks\*(C'\fR function is called by the sudo front end +to deregister any hooks the plugin has registered. If the plugin +does not support hooks, \f(CW\*(C`deregister_hooks\*(C'\fR should be set to the +\&\s-1NULL\s0 pointer. +.Sp +The \fIversion\fR argument describes the version of the hooks \s-1API\s0 +supported by the \fBsudo\fR front end. +.Sp +The \f(CW\*(C`deregister_hook\*(C'\fR function should be used to deregister any +hooks that were put in place by the \f(CW\*(C`register_hook\*(C'\fR function. If +the plugin tries to deregister a hook that the front end does not +support, \f(CW\*(C`deregister_hook\*(C'\fR will return an error. +.Sp +See the \*(L"Hook Function \s-1API\s0\*(R" section below for more information +about hooks. +.Sp +\&\s-1NOTE:\s0 the \f(CW\*(C`deregister_hooks\*(C'\fR function is only available starting +with \s-1API\s0 version 1.2. If the \fBsudo\fR front end doesn't support \s-1API\s0 +version 1.2 or higher, \f(CW\*(C`deregister_hooks\*(C'\fR will not be called. +.PP +\fIPolicy Plugin Version Macros\fR +.IX Subsection "Policy Plugin Version Macros" +.PP +.Vb 6 +\& /* Plugin API version major/minor. */ +\& #define SUDO_API_VERSION_MAJOR 1 +\& #define SUDO_API_VERSION_MINOR 2 +\& #define SUDO_API_MKVERSION(x, y) ((x << 16) | y) +\& #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\e +\& SUDO_API_VERSION_MINOR) +\& +\& /* Getters and setters for API version */ +\& #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) +\& #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff) +\& #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e +\& } while(0) +\& #define SUDO_VERSION_SET_MINOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0xffff0000) | (n); \e +\& } while(0) +.Ve +.SS "I/O Plugin \s-1API\s0" +.IX Subsection "I/O Plugin API" +.Vb 10 +\& struct io_plugin { +\& #define SUDO_IO_PLUGIN 2 +\& unsigned int type; /* always SUDO_IO_PLUGIN */ +\& unsigned int version; /* always SUDO_API_VERSION */ +\& int (*open)(unsigned int version, sudo_conv_t conversation +\& sudo_printf_t plugin_printf, char * const settings[], +\& char * const user_info[], int argc, char * const argv[], +\& char * const user_env[], char * const plugin_options[]); +\& void (*close)(int exit_status, int error); /* wait status or error */ +\& int (*show_version)(int verbose); +\& int (*log_ttyin)(const char *buf, unsigned int len); +\& int (*log_ttyout)(const char *buf, unsigned int len); +\& int (*log_stdin)(const char *buf, unsigned int len); +\& int (*log_stdout)(const char *buf, unsigned int len); +\& int (*log_stderr)(const char *buf, unsigned int len); +\& void (*register_hooks)(int version, +\& int (*register_hook)(struct sudo_hook *hook)); +\& void (*deregister_hooks)(int version, +\& int (*deregister_hook)(struct sudo_hook *hook)); +\& }; +.Ve +.PP +When an I/O plugin is loaded, \fBsudo\fR runs the command in a pseudo-tty. +This makes it possible to log the input and output from the user's +session. If any of the standard input, standard output or standard +error do not correspond to a tty, \fBsudo\fR will open a pipe to capture +the I/O for logging before passing it on. +.PP +The log_ttyin function receives the raw user input from the terminal +device (note that this will include input even when echo is disabled, +such as when a password is read). The log_ttyout function receives +output from the pseudo-tty that is suitable for replaying the user's +session at a later time. The log_stdin, log_stdout and log_stderr +functions are only called if the standard input, standard output +or standard error respectively correspond to something other than +a tty. +.PP +Any of the logging functions may be set to the \s-1NULL\s0 +pointer if no logging is to be performed. If the open function +returns \f(CW0\fR, no I/O will be sent to the plugin. +.PP +The io_plugin struct has the following fields: +.IP "type" 4 +.IX Item "type" +The \f(CW\*(C`type\*(C'\fR field should always be set to \s-1SUDO_IO_PLUGIN\s0 +.IP "version" 4 +.IX Item "version" +The \f(CW\*(C`version\*(C'\fR field should be set to \s-1SUDO_API_VERSION\s0. +.Sp +This allows \fBsudo\fR to determine the \s-1API\s0 version the plugin was +built against. +.IP "open" 4 +.IX Item "open" +.Vb 4 +\& int (*open)(unsigned int version, sudo_conv_t conversation +\& sudo_printf_t plugin_printf, char * const settings[], +\& char * const user_info[], int argc, char * const argv[], +\& char * const user_env[], char * const plugin_options[]); +.Ve +.Sp +The \fIopen\fR function is run before the \fIlog_input\fR, \fIlog_output\fR +or \fIshow_version\fR functions are called. It is only called if the +version is being requested or the \fIcheck_policy\fR function has +returned successfully. It returns 1 on success, 0 on failure, \-1 +if a general error occurred, or \-2 if there was a usage error. In +the latter case, \fBsudo\fR will print a usage message before it exits. +If an error occurs, the plugin may optionally call the conversation +or plugin_printf function with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present +additional error information to the user. +.Sp +The function arguments are as follows: +.RS 4 +.IP "version" 4 +.IX Item "version" +The version passed in by \fBsudo\fR allows the plugin to determine the +major and minor version number of the plugin \s-1API\s0 supported by +\&\fBsudo\fR. +.IP "conversation" 4 +.IX Item "conversation" +A pointer to the conversation function that may be used by the +\&\fIshow_version\fR function to display version information (see +show_version below). The conversation function may also be used +to display additional error message to the user. +The conversation function returns 0 on success and \-1 on failure. +.IP "plugin_printf" 4 +.IX Item "plugin_printf" +A pointer to a printf-style function that may be used by the +\&\fIshow_version\fR function to display version information (see +show_version below). The plugin_printf function may also be used +to display additional error message to the user. +The plugin_printf function returns number of characters printed on +success and \-1 on failure. +.IP "settings" 4 +.IX Item "settings" +A vector of user-supplied \fBsudo\fR settings in the form of \*(L"name=value\*(R" +strings. The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer. These +settings correspond to flags the user specified when running \fBsudo\fR. +As such, they will only be present when the corresponding flag has +been specified on the command line. +.Sp +When parsing \fIsettings\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.Sp +See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a list of all possible settings. +.IP "user_info" 4 +.IX Item "user_info" +A vector of information about the user running the command in the form of +\&\*(L"name=value\*(R" strings. The vector is terminated by a \f(CW\*(C`NULL\*(C'\fR pointer. +.Sp +When parsing \fIuser_info\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.Sp +See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a list of all possible strings. +.IP "argc" 4 +.IX Item "argc" +The number of elements in \fIargv\fR, not counting the final \f(CW\*(C`NULL\*(C'\fR +pointer. +.IP "argv" 4 +.IX Item "argv" +If non\-\f(CW\*(C`NULL\*(C'\fR, an argument vector describing a command the user +wishes to run in the same form as what would be passed to the +\&\fIexecve()\fR system call. +.IP "user_env" 4 +.IX Item "user_env" +The user's environment in the form of a \f(CW\*(C`NULL\*(C'\fR\-terminated vector of +\&\*(L"name=value\*(R" strings. +.Sp +When parsing \fIuser_env\fR, the plugin should split on the \fBfirst\fR +equal sign ('=') since the \fIname\fR field will never include one +itself but the \fIvalue\fR might. +.IP "plugin_options" 4 +.IX Item "plugin_options" +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a white space boundary and are passed to the plugin in the form of +a \f(CW\*(C`NULL\*(C'\fR\-terminated array of strings. If no arguments were +specified, \fIplugin_options\fR will be the \s-1NULL\s0 pointer. +.Sp +\&\s-1NOTE:\s0 the \fIplugin_options\fR parameter is only available starting with +\&\s-1API\s0 version 1.2. A plugin \fBmust\fR check the \s-1API\s0 version specified +by the \fBsudo\fR front end before using \fIplugin_options\fR. Failure to +do so may result in a crash. +.RE +.RS 4 +.RE +.IP "close" 4 +.IX Item "close" +.Vb 1 +\& void (*close)(int exit_status, int error); +.Ve +.Sp +The \f(CW\*(C`close\*(C'\fR function is called when the command being run by \fBsudo\fR +finishes. +.Sp +The function arguments are as follows: +.RS 4 +.IP "exit_status" 4 +.IX Item "exit_status" +The command's exit status, as returned by the \fIwait\fR\|(2) system call. +The value of \f(CW\*(C`exit_status\*(C'\fR is undefined if \f(CW\*(C`error\*(C'\fR is non-zero. +.IP "error" 4 +.IX Item "error" +If the command could not be executed, this is set to the value of +\&\f(CW\*(C`errno\*(C'\fR set by the \fIexecve\fR\|(2) system call. If the command was +successfully executed, the value of \f(CW\*(C`error\*(C'\fR is 0. +.RE +.RS 4 +.RE +.IP "show_version" 4 +.IX Item "show_version" +.Vb 1 +\& int (*show_version)(int verbose); +.Ve +.Sp +The \f(CW\*(C`show_version\*(C'\fR function is called by \fBsudo\fR when the user specifies +the \f(CW\*(C`\-V\*(C'\fR option. The plugin may display its version information +to the user via the conversation or plugin_printf function using +\&\f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR. If the user requests detailed version +information, the verbose flag will be set. +.IP "log_ttyin" 4 +.IX Item "log_ttyin" +.Vb 1 +\& int (*log_ttyin)(const char *buf, unsigned int len); +.Ve +.Sp +The \fIlog_ttyin\fR function is called whenever data can be read from +the user but before it is passed to the running command. This +allows the plugin to reject data if it chooses to (for instance +if the input contains banned content). Returns \f(CW1\fR if the data +should be passed to the command, \f(CW0\fR if the data is rejected +(which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error occurred. +.Sp +The function arguments are as follows: +.RS 4 +.IP "buf" 4 +.IX Item "buf" +The buffer containing user input. +.IP "len" 4 +.IX Item "len" +The length of \fIbuf\fR in bytes. +.RE +.RS 4 +.RE +.IP "log_ttyout" 4 +.IX Item "log_ttyout" +.Vb 1 +\& int (*log_ttyout)(const char *buf, unsigned int len); +.Ve +.Sp +The \fIlog_ttyout\fR function is called whenever data can be read from +the command but before it is written to the user's terminal. This +allows the plugin to reject data if it chooses to (for instance +if the output contains banned content). Returns \f(CW1\fR if the data +should be passed to the user, \f(CW0\fR if the data is rejected +(which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error occurred. +.Sp +The function arguments are as follows: +.RS 4 +.IP "buf" 4 +.IX Item "buf" +The buffer containing command output. +.IP "len" 4 +.IX Item "len" +The length of \fIbuf\fR in bytes. +.RE +.RS 4 +.RE +.IP "log_stdin" 4 +.IX Item "log_stdin" +.Vb 1 +\& int (*log_stdin)(const char *buf, unsigned int len); +.Ve +.Sp +The \fIlog_stdin\fR function is only used if the standard input does +not correspond to a tty device. It is called whenever data can be +read from the standard input but before it is passed to the running +command. This allows the plugin to reject data if it chooses to +(for instance if the input contains banned content). Returns \f(CW1\fR +if the data should be passed to the command, \f(CW0\fR if the data is +rejected (which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error +occurred. +.Sp +The function arguments are as follows: +.RS 4 +.IP "buf" 4 +.IX Item "buf" +The buffer containing user input. +.IP "len" 4 +.IX Item "len" +The length of \fIbuf\fR in bytes. +.RE +.RS 4 +.RE +.IP "log_stdout" 4 +.IX Item "log_stdout" +.Vb 1 +\& int (*log_stdout)(const char *buf, unsigned int len); +.Ve +.Sp +The \fIlog_stdout\fR function is only used if the standard output does +not correspond to a tty device. It is called whenever data can be +read from the command but before it is written to the standard +output. This allows the plugin to reject data if it chooses to +(for instance if the output contains banned content). Returns \f(CW1\fR +if the data should be passed to the user, \f(CW0\fR if the data is +rejected (which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error +occurred. +.Sp +The function arguments are as follows: +.RS 4 +.IP "buf" 4 +.IX Item "buf" +The buffer containing command output. +.IP "len" 4 +.IX Item "len" +The length of \fIbuf\fR in bytes. +.RE +.RS 4 +.RE +.IP "log_stderr" 4 +.IX Item "log_stderr" +.Vb 1 +\& int (*log_stderr)(const char *buf, unsigned int len); +.Ve +.Sp +The \fIlog_stderr\fR function is only used if the standard error does +not correspond to a tty device. It is called whenever data can be +read from the command but before it is written to the standard +error. This allows the plugin to reject data if it chooses to +(for instance if the output contains banned content). Returns \f(CW1\fR +if the data should be passed to the user, \f(CW0\fR if the data is +rejected (which will terminate the command) or \f(CW\*(C`\-1\*(C'\fR if an error +occurred. +.Sp +The function arguments are as follows: +.RS 4 +.IP "buf" 4 +.IX Item "buf" +The buffer containing command output. +.IP "len" 4 +.IX Item "len" +The length of \fIbuf\fR in bytes. +.RE +.RS 4 +.RE +.IP "register_hooks" 4 +.IX Item "register_hooks" +See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a description of +\&\f(CW\*(C`register_hooks\*(C'\fR. +.IP "deregister_hooks" 4 +.IX Item "deregister_hooks" +See the \*(L"Policy Plugin \s-1API\s0\*(R" section for a description of +\&\f(CW\*(C`deregister_hooks\*(C'\fR. +.PP +\fII/O Plugin Version Macros\fR +.IX Subsection "I/O Plugin Version Macros" +.PP +Same as for the \*(L"Policy Plugin \s-1API\s0\*(R". +.SS "Hook Function \s-1API\s0" +.IX Subsection "Hook Function API" +Beginning with plugin \s-1API\s0 version 1.2, it is possible to install +hooks for certain functions called by the \fBsudo\fR front end. +.PP +Currently, the only supported hooks relate to the handling of +environment variables. Hooks can be used to intercept attempts to +get, set, or remove environment variables so that these changes can +be reflected in the version of the environment that is used to +execute a command. A future version of the \s-1API\s0 will support +hooking internal \fBsudo\fR front end functions as well. +.PP +\fIHook structure\fR +.IX Subsection "Hook structure" +.PP +Hooks in \fBsudo\fR are described by the following structure: +.PP +.Vb 1 +\& typedef int (*sudo_hook_fn_t)(); +\& +\& struct sudo_hook { +\& int hook_version; +\& int hook_type; +\& sudo_hook_fn_t hook_fn; +\& void *closure; +\& }; +.Ve +.PP +The \f(CW\*(C`sudo_hook\*(C'\fR structure has the following fields: +.IP "hook_version" 4 +.IX Item "hook_version" +The \f(CW\*(C`hook_version\*(C'\fR field should be set to \s-1SUDO_HOOK_VERSION\s0. +.IP "hook_type" 4 +.IX Item "hook_type" +The \f(CW\*(C`hook_type\*(C'\fR field may be one of the following supported hook types: +.RS 4 +.IP "\s-1SUDO_HOOK_SETENV\s0" 4 +.IX Item "SUDO_HOOK_SETENV" +The C library \f(CW\*(C`setenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_setenv_t)(const char *name, +\& const char *value, int overwrite, void *closure); +.Ve +.Sp +If the registered hook does not match the typedef the results are +unspecified. +.IP "\s-1SUDO_HOOK_UNSETENV\s0" 4 +.IX Item "SUDO_HOOK_UNSETENV" +The C library \f(CW\*(C`unsetenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, +\& void *closure); +.Ve +.IP "\s-1SUDO_HOOK_GETENV\s0" 4 +.IX Item "SUDO_HOOK_GETENV" +The C library \f(CW\*(C`getenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_getenv_t)(const char *name, +\& char **value, void *closure); +.Ve +.Sp +If the registered hook does not match the typedef the results are +unspecified. +.IP "\s-1SUDO_HOOK_PUTENV\s0" 4 +.IX Item "SUDO_HOOK_PUTENV" +The C library \f(CW\*(C`putenv()\*(C'\fR function. Any registered hooks will run +before the C library implementation. The \f(CW\*(C`hook_fn\*(C'\fR field should +be a function that matches the following typedef: +.Sp +.Vb 2 +\& typedef int (*sudo_hook_fn_putenv_t)(char *string, +\& void *closure); +.Ve +.Sp +If the registered hook does not match the typedef the results are +unspecified. +.RE +.RS 4 +.RE +.IP "hook_fn" 4 +.IX Item "hook_fn" +.Vb 1 +\& sudo_hook_fn_t hook_fn; +.Ve +.Sp +The \f(CW\*(C`hook_fn\*(C'\fR field should be set to the plugin's hook implementation. +The actual function arguments will vary depending on the \f(CW\*(C`hook_type\*(C'\fR +(see \f(CW\*(C`hook_type\*(C'\fR above). In all cases, the \f(CW\*(C`closure\*(C'\fR field of +\&\f(CW\*(C`struct sudo_hook\*(C'\fR is passed as the last function parameter. This +can be used to pass arbitrary data to the plugin's hook implementation. +.Sp +The function return value may be one of the following: +.RS 4 +.IP "\s-1SUDO_HOOK_RET_ERROR\s0" 4 +.IX Item "SUDO_HOOK_RET_ERROR" +The hook function encountered an error. +.IP "\s-1SUDO_HOOK_RET_NEXT\s0" 4 +.IX Item "SUDO_HOOK_RET_NEXT" +The hook completed without error, go on to the next hook (including +the native implementation if applicable). For example, a \f(CW\*(C`getenv\*(C'\fR +hook might return \f(CW\*(C`SUDO_HOOK_RET_NEXT\*(C'\fR if the specified variable +was not found in the private copy of the environment. +.IP "\s-1SUDO_HOOK_RET_STOP\s0" 4 +.IX Item "SUDO_HOOK_RET_STOP" +The hook completed without error, stop processing hooks for this +invocation. This can be used to replace the native implementation. +For example, a \f(CW\*(C`setenv\*(C'\fR hook that operates on a private copy of +the environment but leaves \f(CW\*(C`environ\*(C'\fR unchanged. +.RE +.RS 4 +.RE +.PP +Note that it is very easy to create an infinite loop when hooking +C library functions. For example, a \f(CW\*(C`getenv\*(C'\fR hook that calls the +\&\f(CW\*(C`snprintf\*(C'\fR function may create a loop if the \f(CW\*(C`snprintf\*(C'\fR implementation +calls \f(CW\*(C`getenv\*(C'\fR to check the locale. To prevent this, you may wish +to use a static variable in the hook function to guard against +nested calls. E.g. +.PP +.Vb 7 +\& static int in_progress = 0; /* avoid recursion */ +\& if (in_progress) +\& return SUDO_HOOK_RET_NEXT; +\& in_progress = 1; +\& ... +\& in_progress = 0; +\& return SUDO_HOOK_RET_STOP; +.Ve +.PP +\fIHook \s-1API\s0 Version Macros\fR +.IX Subsection "Hook API Version Macros" +.PP +.Vb 6 +\& /* Hook API version major/minor */ +\& #define SUDO_HOOK_VERSION_MAJOR 1 +\& #define SUDO_HOOK_VERSION_MINOR 0 +\& #define SUDO_HOOK_MKVERSION(x, y) ((x << 16) | y) +\& #define SUDO_HOOK_VERSION SUDO_HOOK_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\e +\& SUDO_HOOK_VERSION_MINOR) +\& +\& /* Getters and setters for hook API version */ +\& #define SUDO_HOOK_VERSION_GET_MAJOR(v) ((v) >> 16) +\& #define SUDO_HOOK_VERSION_GET_MINOR(v) ((v) & 0xffff) +\& #define SUDO_HOOK_VERSION_SET_MAJOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e +\& } while(0) +\& #define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0xffff0000) | (n); \e +\& } while(0) +.Ve +.SS "Conversation \s-1API\s0" +.IX Subsection "Conversation API" +If the plugin needs to interact with the user, it may do so via the +conversation function. A plugin should not attempt to read directly +from the standard input or the user's tty (neither of which are +guaranteed to exist). The caller must include a trailing newline +in \f(CW\*(C`msg\*(C'\fR if one is to be printed. +.PP +A printf-style function is also available that can be used to display +informational or error messages to the user, which is usually more +convenient for simple messages where no use input is required. +.PP +.Vb 12 +\& struct sudo_conv_message { +\& #define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */ +\& #define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */ +\& #define SUDO_CONV_ERROR_MSG 0x0003 /* error message */ +\& #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ +\& #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ +\& #define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */ +\& #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ +\& int msg_type; +\& int timeout; +\& const char *msg; +\& }; +\& +\& struct sudo_conv_reply { +\& char *reply; +\& }; +\& +\& typedef int (*sudo_conv_t)(int num_msgs, +\& const struct sudo_conv_message msgs[], +\& struct sudo_conv_reply replies[]); +\& +\& typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...); +.Ve +.PP +Pointers to the conversation and printf-style functions are passed +in to the plugin's \f(CW\*(C`open\*(C'\fR function when the plugin is initialized. +.PP +To use the conversation function, the plugin must pass an array of +\&\f(CW\*(C`sudo_conv_message\*(C'\fR and \f(CW\*(C`sudo_conv_reply\*(C'\fR structures. There must +be a \f(CW\*(C`struct sudo_conv_message\*(C'\fR and \f(CW\*(C`struct sudo_conv_reply\*(C'\fR for +each message in the conversation. The plugin is responsible for +freeing the reply buffer filled in to the \f(CW\*(C`struct sudo_conv_reply\*(C'\fR, +if any. +.PP +The printf-style function uses the same underlying mechanism as the +conversation function but only supports \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR, +\&\f(CW\*(C`SUDO_CONV_ERROR_MSG\*(C'\fR and \f(CW\*(C`SUDO_CONV_DEBUG_MSG\*(C'\fR for the \fImsg_type\fR +parameter. It can be more convenient than using the conversation +function if no user reply is needed and supports standard \fIprintf()\fR +escape sequences. +.PP +Unlike, \f(CW\*(C`SUDO_CONV_INFO_MSG\*(C'\fR and \f(CW\*(C`SUDO_CONV_ERROR_MSG\*(C'\fR, messages +sent with the <\s-1SUDO_CONV_DEBUG_MSG\s0> \fImsg_type\fR are not directly +user-visible. Instead, they are logged to the file specified in +the \f(CW\*(C`Debug\*(C'\fR statement (if any) in the \fI@sysconfdir@/sudo.conf\fR +file. This allows a plugin to log debugging information and is +intended to be used in conjunction with the \fIdebug_flags\fR setting. +.PP +See the sample plugin for an example of the conversation function usage. +.SS "Sudoers Group Plugin \s-1API\s0" +.IX Subsection "Sudoers Group Plugin API" +The \fIsudoers\fR module supports a plugin interface to allow non-Unix +group lookups. This can be used to query a group source other than +the standard Unix group database. A sample group plugin is bundled +with \fBsudo\fR that implements file-based lookups. Third party group +plugins include a \s-1QAS\s0 \s-1AD\s0 plugin available from Quest Software. +.PP +A group plugin must declare and populate a \f(CW\*(C`sudoers_group_plugin\*(C'\fR +struct in the global scope. This structure contains pointers to +the functions that implement plugin initialization, cleanup and +group lookup. +.PP +.Vb 8 +\& struct sudoers_group_plugin { +\& unsigned int version; +\& int (*init)(int version, sudo_printf_t sudo_printf, +\& char *const argv[]); +\& void (*cleanup)(void); +\& int (*query)(const char *user, const char *group, +\& const struct passwd *pwd); +\&}; +.Ve +.PP +The \f(CW\*(C`sudoers_group_plugin\*(C'\fR struct has the following fields: +.IP "version" 4 +.IX Item "version" +The \f(CW\*(C`version\*(C'\fR field should be set to \s-1GROUP_API_VERSION\s0. +.Sp +This allows \fIsudoers\fR to determine the \s-1API\s0 version the group plugin +was built against. +.IP "init" 4 +.IX Item "init" +.Vb 2 +\& int (*init)(int version, sudo_printf_t plugin_printf, +\& char *const argv[]); +.Ve +.Sp +The \fIinit\fR function is called after \fIsudoers\fR has been parsed but +before any policy checks. It returns 1 on success, 0 on failure +(or if the plugin is not configured), and \-1 if a error occurred. +If an error occurs, the plugin may call the plugin_printf function +with \f(CW\*(C`SUDO_CONF_ERROR_MSG\*(C'\fR to present additional error information +to the user. +.Sp +The function arguments are as follows: +.RS 4 +.IP "version" 4 +.IX Item "version" +The version passed in by \fIsudoers\fR allows the plugin to determine the +major and minor version number of the group plugin \s-1API\s0 supported by +\&\fIsudoers\fR. +.IP "plugin_printf" 4 +.IX Item "plugin_printf" +A pointer to a printf-style function that may be used to display +informational or error message to the user. +Returns the number of characters printed on success and \-1 on failure. +.IP "argv" 4 +.IX Item "argv" +A NULL-terminated array of arguments generated from the \fIgroup_plugin\fR +option in \fIsudoers\fR. If no arguments were given, \fIargv\fR will be +\&\s-1NULL\s0. +.RE +.RS 4 +.RE +.IP "cleanup" 4 +.IX Item "cleanup" +.Vb 1 +\& void (*cleanup)(); +.Ve +.Sp +The \fIcleanup\fR function is called when \fIsudoers\fR has finished its +group checks. The plugin should free any memory it has allocated +and close open file handles. +.IP "query" 4 +.IX Item "query" +.Vb 2 +\& int (*query)(const char *user, const char *group, +\& const struct passwd *pwd); +.Ve +.Sp +The \fIquery\fR function is used to ask the group plugin whether \fIuser\fR +is a member of \fIgroup\fR. +.Sp +The function arguments are as follows: +.RS 4 +.IP "user" 4 +.IX Item "user" +The name of the user being looked up in the external group database. +.IP "group" 4 +.IX Item "group" +The name of the group being queried. +.IP "pwd" 4 +.IX Item "pwd" +The password database entry for \fIuser\fR, if any. If \fIuser\fR is not +present in the password database, \fIpwd\fR will be \f(CW\*(C`NULL\*(C'\fR. +.RE +.RS 4 +.RE +.PP +\fIGroup \s-1API\s0 Version Macros\fR +.IX Subsection "Group API Version Macros" +.PP +.Vb 5 +\& /* Sudoers group plugin version major/minor */ +\& #define GROUP_API_VERSION_MAJOR 1 +\& #define GROUP_API_VERSION_MINOR 0 +\& #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \e +\& GROUP_API_VERSION_MINOR) +\& +\& /* Getters and setters for group version */ +\& #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16) +\& #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff) +\& #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e +\& } while(0) +\& #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \e +\& *(vp) = (*(vp) & 0xffff0000) | (n); \e +\& } while(0) +.Ve +.SH "PLUGIN API CHANGELOG" +.IX Header "PLUGIN API CHANGELOG" +The following revisions have been made to the Sudo Plugin \s-1API\s0. +.IP "Version 1.0" 4 +.IX Item "Version 1.0" +Initial \s-1API\s0 version. +.IP "Version 1.1" 4 +.IX Item "Version 1.1" +The I/O logging plugin's \f(CW\*(C`open\*(C'\fR function was modified to take the +\&\f(CW\*(C`command_info\*(C'\fR list as an argument. +.IP "Version 1.2" 4 +.IX Item "Version 1.2" +The Policy and I/O logging plugins' \f(CW\*(C`open\*(C'\fR functions are now passed +a list of plugin options if any are specified in \fI@sysconfdir@/sudo.conf\fR. +.Sp +A simple hooks \s-1API\s0 has been introduced to allow plugins to hook in to the +system's environment handling functions. +.Sp +The \f(CW\*(C`init_session\*(C'\fR Policy plugin function is now passed a pointer +to the user environment which can be updated as needed. This can +be used to merge in environment variables stored in the \s-1PAM\s0 handle +before a command is run. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIsudoers\fR\|(@mansectform@), \fIsudo\fR\|(@mansectsu@) +.SH "BUGS" +.IX Header "BUGS" +If you feel you have found a bug in \fBsudo\fR, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ +.SH "SUPPORT" +.IX Header "SUPPORT" +Limited free support is available via the sudo-workers mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo\-workers to subscribe or +search the archives. +.SH "DISCLAIMER" +.IX Header "DISCLAIMER" +\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 +file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudo_plugin.pod b/doc/sudo_plugin.pod new file mode 100644 index 0000000..d24de9d --- /dev/null +++ b/doc/sudo_plugin.pod @@ -0,0 +1,1617 @@ +Copyright (c) 2009-2012 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. +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=pod + +=head1 NAME + +sudo_plugin - Sudo Plugin API + +=head1 DESCRIPTION + +Starting with version 1.8, B supports a plugin API +for policy and session logging. By default, the I policy +plugin and an associated I/O logging plugin are used. Via the plugin +API, B can be configured to use alternate policy and/or I/O +logging plugins provided by third parties. The plugins to be used +are specified via the F<@sysconfdir@/sudo.conf> file. + +The API is versioned with a major and minor number. The minor +version number is incremented when additions are made. The major +number is incremented when incompatible changes are made. A plugin +should be check the version passed to it and make sure that the +major version matches. + +The plugin API is defined by the C header file. + +=head2 The sudo.conf File + +The F<@sysconfdir@/sudo.conf> file contains plugin configuration directives. +Currently, the only supported keyword is the C directive, +which causes a plugin plugin to be loaded. + +A C line consists of the C keyword, followed by the +I and the I to the shared object containing the +plugin. The I is the name of the C +or C in the plugin shared object. The I +may be fully qualified or relative. If not fully qualified it is +relative to the F<@prefix@/libexec> directory. Any additional +parameters after the I are passed as options to the plugin's +I function. Lines that don't begin with C, C, +C or C are silently ignored. + +The same shared object may contain multiple plugins, each with a +different symbol name. The shared object file must be owned by uid +0 and only writable by its owner. Because of ambiguities that arise +from composite policies, only a single policy plugin may be specified. +This limitation does not apply to I/O plugins. + + # + # Default @sysconfdir@/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_options ... + # Path askpass /path/to/askpass + # Path noexec /path/to/sudo_noexec.so + # Debug sudo /var/log/sudo_debug all@warn + # Set disable_coredump true + # + # The plugin_path is relative to @prefix@/libexec unless + # fully qualified. + # The plugin_name corresponds to a global symbol in the plugin + # that contains the plugin interface structure. + # The plugin_options are optional. + # + Plugin sudoers_policy sudoers.so + Plugin sudoers_io sudoers.so + +=head2 Policy Plugin API + +A policy plugin must declare and populate a C struct +in the global scope. This structure contains pointers to the functions +that implement the B policy checks. The name of the symbol should +be specified in F<@sysconfdir@/sudo.conf> along with a path to the plugin +so that B can load it. + + struct policy_plugin { + #define SUDO_POLICY_PLUGIN 1 + unsigned int type; /* always SUDO_POLICY_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_options[]); + void (*close)(int exit_status, int error); + int (*show_version)(int verbose); + int (*check_policy)(int argc, char * const argv[], + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + int (*list)(int argc, char * const argv[], int verbose, + const char *list_user); + int (*validate)(void); + void (*invalidate)(int remove); + int (*init_session)(struct passwd *pwd, char **user_env[]); + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + }; + +The policy_plugin struct has the following fields: + +=over 4 + +=item type + +The C field should always be set to SUDO_POLICY_PLUGIN. + +=item version + +The C field should be set to SUDO_API_VERSION. + +This allows B to determine the API version the plugin was +built against. + +=item open + + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_options[]); + +Returns 1 on success, 0 on failure, -1 if a general error occurred, +or -2 if there was a usage error. In the latter case, B will +print a usage message before it exits. If an error occurs, the +plugin may optionally call the conversation or plugin_printf function +with C to present additional error information +to the user. + +The function arguments are as follows: + +=over 4 + +=item version + +The version passed in by B allows the plugin to determine the +major and minor version number of the plugin API supported by +B. + +=item conversation + +A pointer to the conversation function that can be used by the +plugin to interact with the user (see below). +Returns 0 on success and -1 on failure. + +=item plugin_printf + +A pointer to a printf-style function that may be used to display +informational or error messages (see below). +Returns the number of characters printed on success and -1 on failure. + +=item settings + +A vector of user-supplied B settings in the form of "name=value" +strings. The vector is terminated by a C pointer. These +settings correspond to flags the user specified when running B. +As such, they will only be present when the corresponding flag has +been specified on the command line. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +=over 4 + +=item debug_flags=string + +A comma-separated list of debug flags that correspond to B's +C entry in F<@sysconfdir@/sudo.conf>, if there is one. The +flags are passed to the plugin as they appear in F<@sysconfdir@/sudo.conf>. +The syntax used by B and the I plugin is +I@I but the plugin is free to use a different +format so long as it does not include a command C<,>. + +For reference, the priorities supported by the B front end and +I are: I, I, I, I, I, +I, I and I. + +The following subsystems are defined: I
, I, I, +I, I, I, I, I, I, I, +I, I, I, I, I, I, I, +I, I, I, I, I, I, I, +I, I. The subsystem I includes every subsystem. + +There is not currently a way to specify a set of debug flags specific +to the plugin--the flags are shared by B and the plugin. + +=item debug_level=number + +This setting has been deprecated in favor of I. + +=item runas_user=string + +The user name or uid to to run the command as, if specified via the +C<-u> flag. + +=item runas_group=string + +The group name or gid to to run the command as, if specified via +the C<-g> flag. + +=item prompt=string + +The prompt to use when requesting a password, if specified via +the C<-p> flag. + +=item set_home=bool + +Set to true if the user specified the C<-H> flag. If true, set the +C environment variable to the target user's home directory. + +=item preserve_environment=bool + +Set to true if the user specified the C<-E> flag, indicating that +the user wishes to preserve the environment. + +=item run_shell=bool + +Set to true if the user specified the C<-s> flag, indicating that +the user wishes to run a shell. + +=item login_shell=bool + +Set to true if the user specified the C<-i> flag, indicating that +the user wishes to run a login shell. + +=item implied_shell=bool + +If the user does not specify a program on the command line, B +will pass the plugin the path to the user's shell and set +I to true. This allows B with no arguments +to be used similarly to L. If the plugin does not to support +this usage, it may return a value of -2 from the C +function, which will cause B to print a usage message and +exit. + +=item preserve_groups=bool + +Set to true if the user specified the C<-P> flag, indicating that +the user wishes to preserve the group vector instead of setting it +based on the runas user. + +=item ignore_ticket=bool + +Set to true if the user specified the C<-k> flag along with a +command, indicating that the user wishes to ignore any cached +authentication credentials. + +=item noninteractive=bool + +Set to true if the user specified the C<-n> flag, indicating that +B should operate in non-interactive mode. The plugin may +reject a command run in non-interactive mode if user interaction +is required. + +=item login_class=string + +BSD login class to use when setting resource limits and nice value, +if specified by the C<-c> flag. + +=item selinux_role=string + +SELinux role to use when executing the command, if specified by +the C<-r> flag. + +=item selinux_type=string + +SELinux type to use when executing the command, if specified by +the C<-t> flag. + +=item bsdauth_type=string + +Authentication type, if specified by the C<-a> flag, to use on +systems where BSD authentication is supported. + +=item network_addrs=list + +A space-separated list of IP network addresses and netmasks in the +form "addr/netmask", e.g. "192.168.1.2/255.255.255.0". The address +and netmask pairs may be either IPv4 or IPv6, depending on what the +operating system supports. If the address contains a colon (':'), +it is an IPv6 address, else it is IPv4. + +=item progname=string + +The command name that sudo was run as, typically "sudo" or "sudoedit". + +=item sudoedit=bool + +Set to true when the C<-e> flag is is specified or if invoked as +B. The plugin shall substitute an editor into I +in the I function or return C<-2> with a usage error +if the plugin does not support I. For more information, +see the I section. + +=item closefrom=number + +If specified, the user has requested via the C<-C> flag that B +close all files descriptors with a value of I or higher. +The plugin may optionally pass this, or another value, back in the +I list. + +=back + +Additional settings may be added in the future so the plugin should +silently ignore settings that it does not recognize. + +=item user_info + +A vector of information about the user running the command in the form of +"name=value" strings. The vector is terminated by a C pointer. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +=over 4 + +=item pid=int + +The process ID of the running B process. +Only available starting with API version 1.2 + +=item ppid=int + +The parent process ID of the running B process. +Only available starting with API version 1.2 + +=item sid=int + +The session ID of the running B process or 0 if B is +not part of a POSIX job control session. +Only available starting with API version 1.2 + +=item pgid=int + +The ID of the process group that the running B process belongs +to. +Only available starting with API version 1.2 + +=item tcpgid=int + +The ID of the forground process group associated with the terminal +device associcated with the B process or -1 if there is no +terminal present. +Only available starting with API version 1.2 + +=item user=string + +The name of the user invoking B. + +=item euid=uid_t + +The effective user ID of the user invoking B. + +=item uid=uid_t + +The real user ID of the user invoking B. + +=item egid=gid_t + +The effective group ID of the user invoking B. + +=item gid=gid_t + +The real group ID of the user invoking B. + +=item groups=list + +The user's supplementary group list formatted as a string of +comma-separated group IDs. + +=item cwd=string + +The user's current working directory. + +=item tty=string + +The path to the user's terminal device. If the user has no terminal +device associated with the session, the value will be empty, as in +C. + +=item host=string + +The local machine's hostname as returned by the C +system call. + +=item lines=int + +The number of lines the user's terminal supports. If there is +no terminal device available, a default value of 24 is used. + +=item cols=int + +The number of columns the user's terminal supports. If there is +no terminal device available, a default value of 80 is used. + +=back + +=item user_env + +The user's environment in the form of a C-terminated vector of +"name=value" strings. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +=item plugin_options + +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a white space boundary and are passed to the plugin in the form of +a C-terminated array of strings. If no arguments were +specified, I will be the NULL pointer. + +NOTE: the I parameter is only available starting with +API version 1.2. A plugin B check the API version specified +by the B front end before using I. Failure to +do so may result in a crash. + +=back + +=item close + + void (*close)(int exit_status, int error); + +The C function is called when the command being run by B +finishes. + +The function arguments are as follows: + +=over 4 + +=item exit_status + +The command's exit status, as returned by the wait(2) system call. +The value of C is undefined if C is non-zero. + +=item error + +If the command could not be executed, this is set to the value of +C set by the execve(2) system call. The plugin is responsible +for displaying error information via the conversation or plugin_printf +function. If the command was successfully executed, the value of +C is 0. + +=back + +=item show_version + + int (*show_version)(int verbose); + +The C function is called by B when the user specifies +the C<-V> option. The plugin may display its version information +to the user via the conversation or plugin_printf function using +C. If the user requests detailed version +information, the verbose flag will be set. + +=item check_policy + + int (*check_policy)(int argc, char * const argv[] + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + +The I function is called by B to determine +whether the user is allowed to run the specified commands. + +If the I option was enabled in the I array +passed to the I function, the user has requested I +mode. I is a mechanism for editing one or more files +where an editor is run with the user's credentials instead of with +elevated privileges. B achieves this by creating user-writable +temporary copies of the files to be edited and then overwriting the +originals with the temporary copies after editing is complete. If +the plugin supports B, it should choose the editor to be +used, potentially from a variable in the user's environment, such +as C, and include it in I (note that environment +variables may include command line flags). The files to be edited +should be copied from I into I, separated from the +editor and its arguments by a C<"--"> element. The C<"--"> will +be removed by B before the editor is executed. The plugin +should also set I in the I list. + +The I function returns 1 if the command is allowed, +0 if not allowed, -1 for a general error, or -2 for a usage error +or if B was specified but is unsupported by the plugin. +In the latter case, B will print a usage message before it +exits. If an error occurs, the plugin may optionally call the +conversation or plugin_printf function with C +to present additional error information to the user. + +The function arguments are as follows: + +=over 4 + +=item argc + +The number of elements in I, not counting the final C +pointer. + +=item argv + +The argument vector describing the command the user wishes to run, +in the same form as what would be passed to the execve() system +call. The vector is terminated by a C pointer. + +=item env_add + +Additional environment variables specified by the user on the command +line in the form of a C-terminated vector of "name=value" +strings. The plugin may reject the command if one or more variables +are not allowed to be set, or it may silently ignore such variables. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +=item command_info + +Information about the command being run in the form of "name=value" +strings. These values are used by B to set the execution +environment when running a command. The plugin is responsible for +creating and populating the vector, which must be terminated with +a C pointer. The following values are recognized by B: + +=over 4 + +=item command=string + +Fully qualified path to the command to be executed. + +=item runas_uid=uid + +User ID to run the command as. + +=item runas_euid=uid + +Effective user ID to run the command as. +If not specified, the value of I is used. + +=item runas_gid=gid + +Group ID to run the command as. + +=item runas_egid=gid + +Effective group ID to run the command as. +If not specified, the value of I is used. + +=item runas_groups=list + +The supplementary group vector to use for the command in the form +of a comma-separated list of group IDs. If I +is set, this option is ignored. + +=item login_class=string + +BSD login class to use when setting resource limits and nice value +(optional). This option is only set on systems that support login +classes. + +=item preserve_groups=bool + +If set, B will preserve the user's group vector instead of +initializing the group vector based on C. + +=item cwd=string + +The current working directory to change to when executing the command. + +=item noexec=bool + +If set, prevent the command from executing other programs. + +=item chroot=string + +The root directory to use when running the command. + +=item nice=int + +Nice value (priority) to use when executing the command. The nice +value, if specified, overrides the priority associated with the +I on BSD systems. + +=item umask=octal + +The file creation mask to use when executing the command. + +=item selinux_role=string + +SELinux role to use when executing the command. + +=item selinux_type=string + +SELinux type to use when executing the command. + +=item timeout=int + +Command timeout. If non-zero then when the timeout expires the +command will be killed. + +=item sudoedit=bool + +Set to true when in I mode. The plugin may enable +I mode even if B was not invoked as B. +This allows the plugin to perform command substitution and transparently +enable I when the user attempts to run an editor. + +=item closefrom=number + +If specified, B will close all files descriptors with a value +of I or higher. + +=item iolog_compress=bool + +Set to true if the I/O logging plugins, if any, should compress the +log data. This is a hint to the I/O logging plugin which may choose +to ignore it. + +=item iolog_path=string + +Fully qualified path to the file or directory in which I/O log is +to be stored. This is a hint to the I/O logging plugin which may +choose to ignore it. If no I/O logging plugin is loaded, this +setting has no effect. + +=item iolog_stdin=bool + +Set to true if the I/O logging plugins, if any, should log the +standard input if it is not connected to a terminal device. This +is a hint to the I/O logging plugin which may choose to ignore it. + +=item iolog_stdout=bool + +Set to true if the I/O logging plugins, if any, should log the +standard output if it is not connected to a terminal device. This +is a hint to the I/O logging plugin which may choose to ignore it. + +=item iolog_stderr=bool + +Set to true if the I/O logging plugins, if any, should log the +standard error if it is not connected to a terminal device. This +is a hint to the I/O logging plugin which may choose to ignore it. + +=item iolog_ttyin=bool + +Set to true if the I/O logging plugins, if any, should log all +terminal input. This only includes input typed by the user and not +from a pipe or redirected from a file. This is a hint to the I/O +logging plugin which may choose to ignore it. + +=item iolog_ttyout=bool + +Set to true if the I/O logging plugins, if any, should log all +terminal output. This only includes output to the screen, not +output to a pipe or file. This is a hint to the I/O logging plugin +which may choose to ignore it. + +=item use_pty=bool + +Allocate a pseudo-tty to run the command in, regardless of whether +or not I/O logging is in use. By default, B will only run +the command in a pty when an I/O log plugin is loaded. + +=item set_utmp=bool + +Create a utmp (or utmpx) entry when a pseudo-tty is allocated. By +default, the new entry will be a copy of the user's existing utmp +entry (if any), with the tty, time, type and pid fields updated. + +=item utmp_user=string + +User name to use when constructing a new utmp (or utmpx) entry when +I is enabled. This option can be used to set the user +field in the utmp entry to the user the command runs as rather than +the invoking user. If not set, B will base the new entry on +the invoking user's existing entry. + +=back + +Unsupported values will be ignored. + +=item argv_out + +The C-terminated argument vector to pass to the execve() +system call when executing the command. The plugin is responsible +for allocating and populating the vector. + +=item user_env_out + +The C-terminated environment vector to use when executing the +command. The plugin is responsible for allocating and populating +the vector. + +=back + +=item list + + int (*list)(int verbose, const char *list_user, + int argc, char * const argv[]); + +List available privileges for the invoking user. Returns 1 on +success, 0 on failure and -1 on error. On error, the plugin may +optionally call the conversation or plugin_printf function with +C to present additional error information to +the user. + +Privileges should be output via the conversation or plugin_printf +function using C. + +=over 4 + +=item verbose + +Flag indicating whether to list in verbose mode or not. + +=item list_user + +The name of a different user to list privileges for if the policy +allows it. If C, the plugin should list the privileges of +the invoking user. + +=item argc + +The number of elements in I, not counting the final C +pointer. + +=item argv + +If non-C, an argument vector describing a command the user +wishes to check against the policy in the same form as what would +be passed to the execve() system call. If the command is permitted +by the policy, the fully-qualified path to the command should be +displayed along with any command line arguments. + +=back + +=item validate + + int (*validate)(void); + +The C function is called when B is run with the +C<-v> flag. For policy plugins such as I that cache +authentication credentials, this function will validate and cache +the credentials. + +The C function should be C if the plugin does not +support credential caching. + +Returns 1 on success, 0 on failure and -1 on error. +On error, the plugin may optionally call the conversation or plugin_printf +function with C to present additional +error information to the user. + +=item invalidate + + void (*invalidate)(int remove); + +The C function is called when B is called with +the C<-k> or C<-K> flag. For policy plugins such as I that +cache authentication credentials, this function will invalidate the +credentials. If the I flag is set, the plugin may remove +the credentials instead of simply invalidating them. + +The C function should be C if the plugin does not +support credential caching. + +=item init_session + + int (*init_session)(struct passwd *pwd, char **user_envp[); + +The C function is called before B sets up the +execution environment for the command. It is run in the parent +B process and before any uid or gid changes. This can be used +to perform session setup that is not supported by I, +such as opening the PAM session. The C function can be +used to tear down the session that was opened by C. + +The I argument points to a passwd struct for the user the +command will be run as if the uid the command will run as was found +in the password database, otherwise it will be NULL. + +The I argument points to the environment the command will +run in, in the form of a C-terminated vector of "name=value" +strings. This is the same string passed back to the front end via +the Policy Plugin's I parameter. If the C +function needs to modify the user environment, it should update the +pointer stored in I. The expected use case is to merge +the contents of the PAM environment (if any) with the contents of +I. NOTE: the I parameter is only available +starting with API version 1.2. A plugin B check the API +version specified by the B front end before using I. +Failure to do so may result in a crash. + +Returns 1 on success, 0 on failure and -1 on error. +On error, the plugin may optionally call the conversation or plugin_printf +function with C to present additional +error information to the user. + +=item register_hooks + + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + +The C function is called by the sudo front end to +register any hooks the plugin needs. If the plugin does not support +hooks, C should be set to the NULL pointer. + +The I argument describes the version of the hooks API +supported by the B front end. + +The C function should be used to register any supported +hooks the plugin needs. It returns 0 on success, 1 if the hook +type is not supported and -1 if the major version in C +does not match the front end's major hook API version. + +See the L section below for more information +about hooks. + +NOTE: the C function is only available starting +with API version 1.2. If the B front end doesn't support API +version 1.2 or higher, C will not be called. + +=item deregister_hooks + + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + +The C function is called by the sudo front end +to deregister any hooks the plugin has registered. If the plugin +does not support hooks, C should be set to the +NULL pointer. + +The I argument describes the version of the hooks API +supported by the B front end. + +The C function should be used to deregister any +hooks that were put in place by the C function. If +the plugin tries to deregister a hook that the front end does not +support, C will return an error. + +See the L section below for more information +about hooks. + +NOTE: the C function is only available starting +with API version 1.2. If the B front end doesn't support API +version 1.2 or higher, C will not be called. + +=back + +=head3 Policy Plugin Version Macros + + /* Plugin API version major/minor. */ + #define SUDO_API_VERSION_MAJOR 1 + #define SUDO_API_VERSION_MINOR 2 + #define SUDO_API_MKVERSION(x, y) ((x << 16) | y) + #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\ + SUDO_API_VERSION_MINOR) + + /* Getters and setters for API version */ + #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) + #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff) + #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ + } while(0) + #define SUDO_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ + } while(0) + +=head2 I/O Plugin API + + struct io_plugin { + #define SUDO_IO_PLUGIN 2 + unsigned int type; /* always SUDO_IO_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], int argc, char * const argv[], + char * const user_env[], char * const plugin_options[]); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*log_ttyin)(const char *buf, unsigned int len); + int (*log_ttyout)(const char *buf, unsigned int len); + int (*log_stdin)(const char *buf, unsigned int len); + int (*log_stdout)(const char *buf, unsigned int len); + int (*log_stderr)(const char *buf, unsigned int len); + void (*register_hooks)(int version, + int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, + int (*deregister_hook)(struct sudo_hook *hook)); + }; + +When an I/O plugin is loaded, B runs the command in a pseudo-tty. +This makes it possible to log the input and output from the user's +session. If any of the standard input, standard output or standard +error do not correspond to a tty, B will open a pipe to capture +the I/O for logging before passing it on. + +The log_ttyin function receives the raw user input from the terminal +device (note that this will include input even when echo is disabled, +such as when a password is read). The log_ttyout function receives +output from the pseudo-tty that is suitable for replaying the user's +session at a later time. The log_stdin, log_stdout and log_stderr +functions are only called if the standard input, standard output +or standard error respectively correspond to something other than +a tty. + +Any of the logging functions may be set to the NULL +pointer if no logging is to be performed. If the open function +returns C<0>, no I/O will be sent to the plugin. + +The io_plugin struct has the following fields: + +=over 4 + +=item type + +The C field should always be set to SUDO_IO_PLUGIN + +=item version + +The C field should be set to SUDO_API_VERSION. + +This allows B to determine the API version the plugin was +built against. + +=item open + + int (*open)(unsigned int version, sudo_conv_t conversation + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], int argc, char * const argv[], + char * const user_env[], char * const plugin_options[]); + +The I function is run before the I, I +or I functions are called. It is only called if the +version is being requested or the I function has +returned successfully. It returns 1 on success, 0 on failure, -1 +if a general error occurred, or -2 if there was a usage error. In +the latter case, B will print a usage message before it exits. +If an error occurs, the plugin may optionally call the conversation +or plugin_printf function with C to present +additional error information to the user. + +The function arguments are as follows: + +=over 4 + +=item version + +The version passed in by B allows the plugin to determine the +major and minor version number of the plugin API supported by +B. + +=item conversation + +A pointer to the conversation function that may be used by the +I function to display version information (see +show_version below). The conversation function may also be used +to display additional error message to the user. +The conversation function returns 0 on success and -1 on failure. + +=item plugin_printf + +A pointer to a printf-style function that may be used by the +I function to display version information (see +show_version below). The plugin_printf function may also be used +to display additional error message to the user. +The plugin_printf function returns number of characters printed on +success and -1 on failure. + +=item settings + +A vector of user-supplied B settings in the form of "name=value" +strings. The vector is terminated by a C pointer. These +settings correspond to flags the user specified when running B. +As such, they will only be present when the corresponding flag has +been specified on the command line. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +See the L section for a list of all possible settings. + +=item user_info + +A vector of information about the user running the command in the form of +"name=value" strings. The vector is terminated by a C pointer. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +See the L section for a list of all possible strings. + +=item argc + +The number of elements in I, not counting the final C +pointer. + +=item argv + +If non-C, an argument vector describing a command the user +wishes to run in the same form as what would be passed to the +execve() system call. + +=item user_env + +The user's environment in the form of a C-terminated vector of +"name=value" strings. + +When parsing I, the plugin should split on the B +equal sign ('=') since the I field will never include one +itself but the I might. + +=item plugin_options + +Any (non-comment) strings immediately after the plugin path are +treated as arguments to the plugin. These arguments are split on +a white space boundary and are passed to the plugin in the form of +a C-terminated array of strings. If no arguments were +specified, I will be the NULL pointer. + +NOTE: the I parameter is only available starting with +API version 1.2. A plugin B check the API version specified +by the B front end before using I. Failure to +do so may result in a crash. + +=back + +=item close + + void (*close)(int exit_status, int error); + +The C function is called when the command being run by B +finishes. + +The function arguments are as follows: + +=over 4 + +=item exit_status + +The command's exit status, as returned by the wait(2) system call. +The value of C is undefined if C is non-zero. + +=item error + +If the command could not be executed, this is set to the value of +C set by the execve(2) system call. If the command was +successfully executed, the value of C is 0. + +=back + +=item show_version + + int (*show_version)(int verbose); + +The C function is called by B when the user specifies +the C<-V> option. The plugin may display its version information +to the user via the conversation or plugin_printf function using +C. If the user requests detailed version +information, the verbose flag will be set. + +=item log_ttyin + + int (*log_ttyin)(const char *buf, unsigned int len); + +The I function is called whenever data can be read from +the user but before it is passed to the running command. This +allows the plugin to reject data if it chooses to (for instance +if the input contains banned content). Returns C<1> if the data +should be passed to the command, C<0> if the data is rejected +(which will terminate the command) or C<-1> if an error occurred. + +The function arguments are as follows: + +=over 4 + +=item buf + +The buffer containing user input. + +=item len + +The length of I in bytes. + +=back + +=item log_ttyout + + int (*log_ttyout)(const char *buf, unsigned int len); + +The I function is called whenever data can be read from +the command but before it is written to the user's terminal. This +allows the plugin to reject data if it chooses to (for instance +if the output contains banned content). Returns C<1> if the data +should be passed to the user, C<0> if the data is rejected +(which will terminate the command) or C<-1> if an error occurred. + +The function arguments are as follows: + +=over 4 + +=item buf + +The buffer containing command output. + +=item len + +The length of I in bytes. + +=back + +=item log_stdin + + int (*log_stdin)(const char *buf, unsigned int len); + +The I function is only used if the standard input does +not correspond to a tty device. It is called whenever data can be +read from the standard input but before it is passed to the running +command. This allows the plugin to reject data if it chooses to +(for instance if the input contains banned content). Returns C<1> +if the data should be passed to the command, C<0> if the data is +rejected (which will terminate the command) or C<-1> if an error +occurred. + +The function arguments are as follows: + +=over 4 + +=item buf + +The buffer containing user input. + +=item len + +The length of I in bytes. + +=back + +=item log_stdout + + int (*log_stdout)(const char *buf, unsigned int len); + +The I function is only used if the standard output does +not correspond to a tty device. It is called whenever data can be +read from the command but before it is written to the standard +output. This allows the plugin to reject data if it chooses to +(for instance if the output contains banned content). Returns C<1> +if the data should be passed to the user, C<0> if the data is +rejected (which will terminate the command) or C<-1> if an error +occurred. + +The function arguments are as follows: + +=over 4 + +=item buf + +The buffer containing command output. + +=item len + +The length of I in bytes. + +=back + +=item log_stderr + + int (*log_stderr)(const char *buf, unsigned int len); + +The I function is only used if the standard error does +not correspond to a tty device. It is called whenever data can be +read from the command but before it is written to the standard +error. This allows the plugin to reject data if it chooses to +(for instance if the output contains banned content). Returns C<1> +if the data should be passed to the user, C<0> if the data is +rejected (which will terminate the command) or C<-1> if an error +occurred. + +The function arguments are as follows: + +=over 4 + +=item buf + +The buffer containing command output. + +=item len + +The length of I in bytes. + +=back + +=item register_hooks + +See the L section for a description of +C. + +=item deregister_hooks + +See the L section for a description of +C. + +=back + +=head3 I/O Plugin Version Macros + +Same as for the L. + +=head2 Hook Function API + +Beginning with plugin API version 1.2, it is possible to install +hooks for certain functions called by the B front end. + +Currently, the only supported hooks relate to the handling of +environment variables. Hooks can be used to intercept attempts to +get, set, or remove environment variables so that these changes can +be reflected in the version of the environment that is used to +execute a command. A future version of the API will support +hooking internal B front end functions as well. + +=head3 Hook structure + +Hooks in B are described by the following structure: + + typedef int (*sudo_hook_fn_t)(); + + struct sudo_hook { + int hook_version; + int hook_type; + sudo_hook_fn_t hook_fn; + void *closure; + }; + +The C structure has the following fields: + +=over 4 + +=item hook_version + +The C field should be set to SUDO_HOOK_VERSION. + +=item hook_type + +The C field may be one of the following supported hook types: + +=over 4 + +=item SUDO_HOOK_SETENV + +The C library C function. Any registered hooks will run +before the C library implementation. The C field should +be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_setenv_t)(const char *name, + const char *value, int overwrite, void *closure); + +If the registered hook does not match the typedef the results are +unspecified. + +=item SUDO_HOOK_UNSETENV + +The C library C function. Any registered hooks will run +before the C library implementation. The C field should +be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, + void *closure); + +=item SUDO_HOOK_GETENV + +The C library C function. Any registered hooks will run +before the C library implementation. The C field should +be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_getenv_t)(const char *name, + char **value, void *closure); + +If the registered hook does not match the typedef the results are +unspecified. + +=item SUDO_HOOK_PUTENV + +The C library C function. Any registered hooks will run +before the C library implementation. The C field should +be a function that matches the following typedef: + + typedef int (*sudo_hook_fn_putenv_t)(char *string, + void *closure); + +If the registered hook does not match the typedef the results are +unspecified. + +=back + +=item hook_fn + + sudo_hook_fn_t hook_fn; + +The C field should be set to the plugin's hook implementation. +The actual function arguments will vary depending on the C +(see C above). In all cases, the C field of +C is passed as the last function parameter. This +can be used to pass arbitrary data to the plugin's hook implementation. + +The function return value may be one of the following: + +=over 4 + +=item SUDO_HOOK_RET_ERROR + +The hook function encountered an error. + +=item SUDO_HOOK_RET_NEXT + +The hook completed without error, go on to the next hook (including +the native implementation if applicable). For example, a C +hook might return C if the specified variable +was not found in the private copy of the environment. + +=item SUDO_HOOK_RET_STOP + +The hook completed without error, stop processing hooks for this +invocation. This can be used to replace the native implementation. +For example, a C hook that operates on a private copy of +the environment but leaves C unchanged. + +=back + +=back + +Note that it is very easy to create an infinite loop when hooking +C library functions. For example, a C hook that calls the +C function may create a loop if the C implementation +calls C to check the locale. To prevent this, you may wish +to use a static variable in the hook function to guard against +nested calls. E.g. + + static int in_progress = 0; /* avoid recursion */ + if (in_progress) + return SUDO_HOOK_RET_NEXT; + in_progress = 1; + ... + in_progress = 0; + return SUDO_HOOK_RET_STOP; + +=head3 Hook API Version Macros + + /* Hook API version major/minor */ + #define SUDO_HOOK_VERSION_MAJOR 1 + #define SUDO_HOOK_VERSION_MINOR 0 + #define SUDO_HOOK_MKVERSION(x, y) ((x << 16) | y) + #define SUDO_HOOK_VERSION SUDO_HOOK_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\ + SUDO_HOOK_VERSION_MINOR) + + /* Getters and setters for hook API version */ + #define SUDO_HOOK_VERSION_GET_MAJOR(v) ((v) >> 16) + #define SUDO_HOOK_VERSION_GET_MINOR(v) ((v) & 0xffff) + #define SUDO_HOOK_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ + } while(0) + #define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ + } while(0) + +=head2 Conversation API + +If the plugin needs to interact with the user, it may do so via the +conversation function. A plugin should not attempt to read directly +from the standard input or the user's tty (neither of which are +guaranteed to exist). The caller must include a trailing newline +in C if one is to be printed. + +A printf-style function is also available that can be used to display +informational or error messages to the user, which is usually more +convenient for simple messages where no use input is required. + + struct sudo_conv_message { + #define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */ + #define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */ + #define SUDO_CONV_ERROR_MSG 0x0003 /* error message */ + #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ + #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ + #define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */ + #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ + int msg_type; + int timeout; + const char *msg; + }; + + struct sudo_conv_reply { + char *reply; + }; + + typedef int (*sudo_conv_t)(int num_msgs, + const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[]); + + typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...); + +Pointers to the conversation and printf-style functions are passed +in to the plugin's C function when the plugin is initialized. + +To use the conversation function, the plugin must pass an array of +C and C structures. There must +be a C and C for +each message in the conversation. The plugin is responsible for +freeing the reply buffer filled in to the C, +if any. + +The printf-style function uses the same underlying mechanism as the +conversation function but only supports C, +C and C for the I +parameter. It can be more convenient than using the conversation +function if no user reply is needed and supports standard printf() +escape sequences. + +Unlike, C and C, messages +sent with the I are not directly +user-visible. Instead, they are logged to the file specified in +the C statement (if any) in the F<@sysconfdir@/sudo.conf> +file. This allows a plugin to log debugging information and is +intended to be used in conjunction with the I setting. + +See the sample plugin for an example of the conversation function usage. + +=head2 Sudoers Group Plugin API + +The I module supports a plugin interface to allow non-Unix +group lookups. This can be used to query a group source other than +the standard Unix group database. A sample group plugin is bundled +with B that implements file-based lookups. Third party group +plugins include a QAS AD plugin available from Quest Software. + +A group plugin must declare and populate a C +struct in the global scope. This structure contains pointers to +the functions that implement plugin initialization, cleanup and +group lookup. + + struct sudoers_group_plugin { + unsigned int version; + int (*init)(int version, sudo_printf_t sudo_printf, + char *const argv[]); + void (*cleanup)(void); + int (*query)(const char *user, const char *group, + const struct passwd *pwd); +}; + +The C struct has the following fields: + +=over 4 + +=item version + +The C field should be set to GROUP_API_VERSION. + +This allows I to determine the API version the group plugin +was built against. + +=item init + + int (*init)(int version, sudo_printf_t plugin_printf, + char *const argv[]); + +The I function is called after I has been parsed but +before any policy checks. It returns 1 on success, 0 on failure +(or if the plugin is not configured), and -1 if a error occurred. +If an error occurs, the plugin may call the plugin_printf function +with C to present additional error information +to the user. + +The function arguments are as follows: + +=over 4 + +=item version + +The version passed in by I allows the plugin to determine the +major and minor version number of the group plugin API supported by +I. + +=item plugin_printf + +A pointer to a printf-style function that may be used to display +informational or error message to the user. +Returns the number of characters printed on success and -1 on failure. + +=item argv + +A NULL-terminated array of arguments generated from the I +option in I. If no arguments were given, I will be +NULL. + +=back + +=item cleanup + + void (*cleanup)(); + +The I function is called when I has finished its +group checks. The plugin should free any memory it has allocated +and close open file handles. + +=item query + + int (*query)(const char *user, const char *group, + const struct passwd *pwd); + +The I function is used to ask the group plugin whether I +is a member of I. + +The function arguments are as follows: + +=over 4 + +=item user + +The name of the user being looked up in the external group database. + +=item group + +The name of the group being queried. + +=item pwd + +The password database entry for I, if any. If I is not +present in the password database, I will be C. + +=back + +=back + +=head3 Group API Version Macros + + /* Sudoers group plugin version major/minor */ + #define GROUP_API_VERSION_MAJOR 1 + #define GROUP_API_VERSION_MINOR 0 + #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \ + GROUP_API_VERSION_MINOR) + + /* Getters and setters for group version */ + #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16) + #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff) + #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ + } while(0) + #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ + } while(0) + +=head1 PLUGIN API CHANGELOG + +The following revisions have been made to the Sudo Plugin API. + +=over 4 + +=item Version 1.0 + +Initial API version. + +=item Version 1.1 + +The I/O logging plugin's C function was modified to take the +C list as an argument. + +=item Version 1.2 + +The Policy and I/O logging plugins' C functions are now passed +a list of plugin options if any are specified in F<@sysconfdir@/sudo.conf>. + +A simple hooks API has been introduced to allow plugins to hook in to the +system's environment handling functions. + +The C Policy plugin function is now passed a pointer +to the user environment which can be updated as needed. This can +be used to merge in environment variables stored in the PAM handle +before a command is run. + +=back + + +=head1 SEE ALSO + +L, L + +=head1 BUGS + +If you feel you have found a bug in B, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ + +=head1 SUPPORT + +Limited free support is available via the sudo-workers mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo-workers to subscribe or +search the archives. + +=head1 DISCLAIMER + +B is provided ``AS IS'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the LICENSE +file distributed with B or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudoers.cat b/doc/sudoers.cat new file mode 100644 index 0000000..6033d16 --- /dev/null +++ b/doc/sudoers.cat @@ -0,0 +1,1817 @@ +SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) + + + +NNAAMMEE + sudoers - default sudo security policy module + +DDEESSCCRRIIPPTTIIOONN + The _s_u_d_o_e_r_s policy module determines a user's ssuuddoo privileges. It is + the default ssuuddoo policy plugin. The policy is driven by the + _/_e_t_c_/_s_u_d_o_e_r_s file or, optionally in LDAP. The policy format is + described in detail in the "SUDOERS FILE FORMAT" section. For + information on storing _s_u_d_o_e_r_s policy information in LDAP, please see + _s_u_d_o_e_r_s_._l_d_a_p(4). + + AAuutthheennttiiccaattiioonn aanndd LLooggggiinngg + The _s_u_d_o_e_r_s security policy requires that most users authenticate + themselves before they can use ssuuddoo. A password is not required if the + invoking user is root, if the target user is the same as the invoking + user, or if the policy has disabled authentication for the user or + command. Unlike _s_u(1), when _s_u_d_o_e_r_s requires authentication, it + validates the invoking user's credentials, not the target user's (or + root's) credentials. This can be changed via the _r_o_o_t_p_w, _t_a_r_g_e_t_p_w and + _r_u_n_a_s_p_w flags, described later. + + If a user who is not listed in the policy tries to run a command via + ssuuddoo, mail is sent to the proper authorities. The address used for + such mail is configurable via the _m_a_i_l_t_o Defaults entry (described + later) and defaults to root. + + Note that mail will not be sent if an unauthorized user tries to run + ssuuddoo with the --ll or --vv option. This allows users to determine for + themselves whether or not they are allowed to use ssuuddoo. + + If ssuuddoo is run by root and the SUDO_USER environment variable is set, + the _s_u_d_o_e_r_s policy will use this value to determine who the actual user + is. This can be used by a user to log commands through sudo even when + a root shell has been invoked. It also allows the --ee option to remain + useful even when invoked via a sudo-run script or program. Note, + however, that the _s_u_d_o_e_r_s lookup is still done for root, not the user + specified by SUDO_USER. + + _s_u_d_o_e_r_s uses time stamp files for credential caching. Once a user has + been authenticated, a time stamp is updated and the user may then use + sudo without a password for a short period of time (5 minutes unless + overridden by the _t_i_m_e_o_u_t option. By default, _s_u_d_o_e_r_s uses a tty-based + time stamp which means that there is a separate time stamp for each of + a user's login sessions. The _t_t_y___t_i_c_k_e_t_s option can be disabled to + force the use of a single time stamp for all of a user's sessions. + + _s_u_d_o_e_r_s can log both successful and unsuccessful attempts (as well as + errors) to _s_y_s_l_o_g(3), a log file, or both. By default, _s_u_d_o_e_r_s will + log via _s_y_s_l_o_g(3) but this is changeable via the _s_y_s_l_o_g and _l_o_g_f_i_l_e + Defaults settings. + + _s_u_d_o_e_r_s also supports logging a command's input and output streams. + I/O logging is not on by default but can be enabled using the _l_o_g___i_n_p_u_t + and _l_o_g___o_u_t_p_u_t Defaults flags as well as the LOG_INPUT and LOG_OUTPUT + command tags. + + CCoommmmaanndd EEnnvviirroonnmmeenntt + Since environment variables can influence program behavior, _s_u_d_o_e_r_s + provides a means to restrict which variables from the user's + environment are inherited by the command to be run. There are two + distinct ways _s_u_d_o_e_r_s can deal with environment variables. + + By default, the _e_n_v___r_e_s_e_t option is enabled. This causes commands to + be executed with a new, minimal environment. On AIX (and Linux systems + without PAM), the environment is initialized with the contents of the + _/_e_t_c_/_e_n_v_i_r_o_n_m_e_n_t file. On BSD systems, if the _u_s_e___l_o_g_i_n_c_l_a_s_s option is + enabled, the environment is initialized based on the _p_a_t_h and _s_e_t_e_n_v + settings in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. The new environment contains the TERM, + PATH, HOME, MAIL, SHELL, LOGNAME, USER, USERNAME and SUDO_* variables + in addition to variables from the invoking process permitted by the + _e_n_v___c_h_e_c_k and _e_n_v___k_e_e_p options. This is effectively a whitelist for + environment variables. + + If, however, the _e_n_v___r_e_s_e_t option is disabled, any variables not + explicitly denied by the _e_n_v___c_h_e_c_k and _e_n_v___d_e_l_e_t_e options are inherited + from the invoking process. In this case, _e_n_v___c_h_e_c_k and _e_n_v___d_e_l_e_t_e + behave like a blacklist. Since it is not possible to blacklist all + potentially dangerous environment variables, use of the default + _e_n_v___r_e_s_e_t behavior is encouraged. + + In all cases, environment variables with a value beginning with () are + removed as they could be interpreted as bbaasshh functions. The list of + environment variables that ssuuddoo allows or denies is contained in the + output of sudo -V when run as root. + + Note that the dynamic linker on most operating systems will remove + variables that can control dynamic linking from the environment of + setuid executables, including ssuuddoo. Depending on the operating system + this may include _RLD*, DYLD_*, LD_*, LDR_*, LIBPATH, SHLIB_PATH, and + others. These type of variables are removed from the environment + before ssuuddoo even begins execution and, as such, it is not possible for + ssuuddoo to preserve them. + + As a special case, if ssuuddoo's --ii option (initial login) is specified, + _s_u_d_o_e_r_s will initialize the environment regardless of the value of + _e_n_v___r_e_s_e_t. The _D_I_S_P_L_A_Y, _P_A_T_H and _T_E_R_M variables remain unchanged; + _H_O_M_E, _M_A_I_L, _S_H_E_L_L, _U_S_E_R, and _L_O_G_N_A_M_E are set based on the target user. + On AIX (and Linux systems without PAM), the contents of + _/_e_t_c_/_e_n_v_i_r_o_n_m_e_n_t are also included. On BSD systems, if the + _u_s_e___l_o_g_i_n_c_l_a_s_s option is enabled, the _p_a_t_h and _s_e_t_e_n_v variables in + _/_e_t_c_/_l_o_g_i_n_._c_o_n_f are also applied. All other environment variables are + removed. + + Finally, if the _e_n_v___f_i_l_e option is defined, any variables present in + that file will be set to their specified values as long as they would + not conflict with an existing environment variable. + +SSUUDDOOEERRSS FFIILLEE FFOORRMMAATT + The _s_u_d_o_e_r_s file is composed of two types of entries: aliases + (basically variables) and user specifications (which specify who may + run what). + + When multiple entries match for a user, they are applied in order. + Where there are multiple matches, the last match is used (which is not + necessarily the most specific match). + + The _s_u_d_o_e_r_s grammar will be described below in Extended Backus-Naur + Form (EBNF). Don't despair if you don't know what EBNF is; it is + fairly simple, and the definitions below are annotated. + + QQuuiicckk gguuiiddee ttoo EEBBNNFF + EBNF is a concise and exact way of describing the grammar of a + language. Each EBNF definition is made up of _p_r_o_d_u_c_t_i_o_n _r_u_l_e_s. E.g., + + symbol ::= definition | alternate1 | alternate2 ... + + Each _p_r_o_d_u_c_t_i_o_n _r_u_l_e references others and thus makes up a grammar for + the language. EBNF also contains the following operators, which many + readers will recognize from regular expressions. Do not, however, + confuse them with "wildcard" characters, which have different meanings. + + ? Means that the preceding symbol (or group of symbols) is optional. + That is, it may appear once or not at all. + + * Means that the preceding symbol (or group of symbols) may appear + zero or more times. + + + Means that the preceding symbol (or group of symbols) may appear + one or more times. + + Parentheses may be used to group symbols together. For clarity, we + will use single quotes ('') to designate what is a verbatim character + string (as opposed to a symbol name). + + AAlliiaasseess + There are four kinds of aliases: User_Alias, Runas_Alias, Host_Alias + and Cmnd_Alias. + + Alias ::= 'User_Alias' User_Alias (':' User_Alias)* | + 'Runas_Alias' Runas_Alias (':' Runas_Alias)* | + 'Host_Alias' Host_Alias (':' Host_Alias)* | + 'Cmnd_Alias' Cmnd_Alias (':' Cmnd_Alias)* + + User_Alias ::= NAME '=' User_List + + Runas_Alias ::= NAME '=' Runas_List + + Host_Alias ::= NAME '=' Host_List + + Cmnd_Alias ::= NAME '=' Cmnd_List + + NAME ::= [A-Z]([A-Z][0-9]_)* + + Each _a_l_i_a_s definition is of the form + + Alias_Type NAME = item1, item2, ... + + where _A_l_i_a_s___T_y_p_e is one of User_Alias, Runas_Alias, Host_Alias, or + Cmnd_Alias. A NAME is a string of uppercase letters, numbers, and + underscore characters ('_'). A NAME mmuusstt start with an uppercase + letter. It is possible to put several alias definitions of the same + type on a single line, joined by a colon (':'). E.g., + + Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 + + The definitions of what constitutes a valid _a_l_i_a_s member follow. + + User_List ::= User | + User ',' User_List + + User ::= '!'* user name | + '!'* #uid | + '!'* %group | + '!'* %#gid | + '!'* +netgroup | + '!'* %:nonunix_group | + '!'* %:#nonunix_gid | + '!'* User_Alias + + A User_List is made up of one or more user names, user ids (prefixed + with '#'), system group names and ids (prefixed with '%' and '%#' + respectively), netgroups (prefixed with '+'), non-Unix group names and + IDs (prefixed with '%:' and '%:#' respectively) and User_Aliases. Each + list item may be prefixed with zero or more '!' operators. An odd + number of '!' operators negate the value of the item; an even number + just cancel each other out. + + A user name, uid, group, gid, netgroup, nonunix_group or nonunix_gid + may be enclosed in double quotes to avoid the need for escaping special + characters. Alternately, special characters may be specified in + escaped hex mode, e.g. \x20 for space. When using double quotes, any + prefix characters must be included inside the quotes. + + The actual nonunix_group and nonunix_gid syntax depends on the + underlying group provider plugin (see the _g_r_o_u_p___p_l_u_g_i_n description + below). For instance, the QAS AD plugin supports the following + formats: + + o Group in the same domain: "Group Name" + + o Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN" + + 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 special characters. See + "Other special characters and reserved words" for a list of characters + that need to be escaped. + + Runas_List ::= Runas_Member | + Runas_Member ',' Runas_List + + Runas_Member ::= '!'* user name | + '!'* #uid | + '!'* %group | + '!'* %#gid | + '!'* %:nonunix_group | + '!'* %:#nonunix_gid | + '!'* +netgroup | + '!'* Runas_Alias + + A Runas_List is similar to a User_List except that instead of + User_Aliases it can contain Runas_Aliases. Note that user names and + groups are matched as strings. In other words, two users (groups) with + the same uid (gid) are considered to be distinct. If you wish to match + all user names with the same uid (e.g. root and toor), you can use a + uid instead (#0 in the example given). + + Host_List ::= Host | + Host ',' Host_List + + Host ::= '!'* host name | + '!'* ip_addr | + '!'* network(/netmask)? | + '!'* +netgroup | + '!'* Host_Alias + + A Host_List is made up of one or more host names, IP addresses, network + numbers, netgroups (prefixed with '+') and other aliases. Again, the + value of an item may be negated with the '!' operator. If you do not + specify a netmask along with the network number, ssuuddoo will query each + of the local host's network interfaces and, if the network number + corresponds to one of the hosts's network interfaces, the corresponding + netmask will be used. The netmask may be specified either in standard + IP address notation (e.g. 255.255.255.0 or ffff:ffff:ffff:ffff::), or + CIDR notation (number of bits, e.g. 24 or 64). A host name may include + shell-style wildcards (see the Wildcards section below), but unless the + host name command on your machine returns the fully qualified host + name, you'll need to use the _f_q_d_n option for wildcards to be useful. + Note ssuuddoo only inspects actual network interfaces; this means that IP + address 127.0.0.1 (localhost) will never match. Also, the host name + "localhost" will only match if that is the actual host name, which is + usually only the case for non-networked systems. + + Cmnd_List ::= Cmnd | + Cmnd ',' Cmnd_List + + commandname ::= file name | + file name args | + file name '""' + + Cmnd ::= '!'* commandname | + '!'* directory | + '!'* "sudoedit" | + '!'* Cmnd_Alias + + A Cmnd_List is a list of one or more commandnames, directories, and + other aliases. A commandname is a fully qualified file name which may + include shell-style wildcards (see the Wildcards section below). A + simple file name allows the user to run the command with any arguments + he/she wishes. However, you may also specify command line arguments + (including wildcards). Alternately, you can specify "" to indicate + that the command may only be run wwiitthhoouutt command line arguments. A + directory is a fully qualified path name ending in a '/'. When you + specify a directory in a Cmnd_List, the user will be able to run any + file within that directory (but not in any subdirectories therein). + + If a Cmnd has associated command line arguments, then the arguments in + the Cmnd must match exactly those given by the user on the command line + (or match the wildcards if there are any). Note that the following + characters must be escaped with a '\' if they are used in command + arguments: ',', ':', '=', '\'. The special command "sudoedit" is used + to permit a user to run ssuuddoo with the --ee option (or as ssuuddooeeddiitt). It + may take command line arguments just as a normal command does. + + DDeeffaauullttss + Certain configuration options may be changed from their default values + at runtime via one or more Default_Entry lines. These may affect all + users on any host, all users on a specific host, a specific user, a + specific command, or commands being run as a specific user. Note that + per-command entries may not include command line arguments. If you + need to specify arguments, define a Cmnd_Alias and reference that + instead. + + Default_Type ::= 'Defaults' | + 'Defaults' '@' Host_List | + 'Defaults' ':' User_List | + 'Defaults' '!' Cmnd_List | + 'Defaults' '>' Runas_List + + Default_Entry ::= Default_Type Parameter_List + + Parameter_List ::= Parameter | + Parameter ',' Parameter_List + + Parameter ::= Parameter '=' Value | + Parameter '+=' Value | + Parameter '-=' Value | + '!'* Parameter + + Parameters may be 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. + + Defaults entries are parsed in the following order: generic, host and + user Defaults first, then runas Defaults and finally command defaults. + + See "SUDOERS OPTIONS" for a list of supported Defaults parameters. + + UUsseerr SSppeecciiffiiccaattiioonn + User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \ + (':' Host_List '=' Cmnd_Spec_List)* + + Cmnd_Spec_List ::= Cmnd_Spec | + Cmnd_Spec ',' Cmnd_Spec_List + + Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd + + Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' + + SELinux_Spec ::= ('ROLE=role' | 'TYPE=type') + + Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | + 'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | + 'LOG_OUTPUT:' | 'NOLOG_OUTPUT:') + + A uusseerr ssppeecciiffiiccaattiioonn determines which commands a user may run (and as + 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) + what'. Let's break that down into its constituent parts: + + RRuunnaass__SSppeecc + A Runas_Spec determines the user and/or the group that a command may be + run as. A fully-specified Runas_Spec consists of two Runas_Lists (as + defined above) separated by a colon (':') and enclosed in a set of + parentheses. The first Runas_List indicates which users the command + may be run as via ssuuddoo's --uu option. The second defines a list of + groups that can be specified via ssuuddoo's --gg option. If both Runas_Lists + are specified, the command may be run with any combination of users and + groups listed in their respective Runas_Lists. If only the first is + specified, the command may be run as any user in the list but no --gg + option may be specified. If the first Runas_List is empty but the + second is specified, the command may be run as the invoking user with + the group set to any listed in the Runas_List. If no Runas_Spec is + specified the command may be run as 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 + + It is also possible to override a Runas_Spec later on in an entry. If + we modify the entry like so: + + dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm + + Then user ddggbb is now allowed to run _/_b_i_n_/_l_s as ooppeerraattoorr, but _/_b_i_n_/_k_i_l_l + and _/_u_s_r_/_b_i_n_/_l_p_r_m as rroooott. + + We can extend this to allow ddggbb to run /bin/ls with either the user or + group set to ooppeerraattoorr: + + 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. + + 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. + + 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 + is specified with the command it will override any default values + specified in _s_u_d_o_e_r_s. A role or type specified on the command line, + however, will supercede the values in _s_u_d_o_e_r_s. + + TTaagg__SSppeecc + A command may have zero or more tags associated with it. There are + eight possible tag values, NOPASSWD, PASSWD, NOEXEC, EXEC, SETENV, + NOSETENV, LOG_INPUT, NOLOG_INPUT, LOG_OUTPUT and NOLOG_OUTPUT. Once a + tag is set on a Cmnd, subsequent Cmnds in the Cmnd_Spec_List, inherit + the tag unless it is overridden by the opposite tag (i.e.: PASSWD + overrides NOPASSWD and NOEXEC overrides EXEC). + + _N_O_P_A_S_S_W_D _a_n_d _P_A_S_S_W_D + + By default, ssuuddoo requires that a user authenticate him or herself + before running a command. This behavior can be modified via the + NOPASSWD tag. Like a Runas_Spec, the NOPASSWD tag sets a default for + the commands that follow it in the Cmnd_Spec_List. Conversely, the + PASSWD tag can be used to reverse things. For example: + + ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm + + would allow the user rraayy to run _/_b_i_n_/_k_i_l_l, _/_b_i_n_/_l_s, and _/_u_s_r_/_b_i_n_/_l_p_r_m + as rroooott on the machine rushmore without authenticating himself. If we + only want rraayy to be able to run _/_b_i_n_/_k_i_l_l without a password the entry + would be: + + ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm + + Note, however, that the PASSWD tag has no effect on users who are in + the group specified by the _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 + user on the current host, he or she will be able to run sudo -l without + a password. Additionally, a user may only run sudo -v without a + password if the NOPASSWD tag is present for all a user's entries that + pertain to the current host. This behavior may be overridden via the + verifypw and listpw options. + + _N_O_E_X_E_C _a_n_d _E_X_E_C + + If ssuuddoo has been compiled with _n_o_e_x_e_c support and the underlying + operating system supports it, the NOEXEC tag can be used to prevent a + dynamically-linked executable from running further commands itself. + + In the following example, user aaaarroonn may run _/_u_s_r_/_b_i_n_/_m_o_r_e and + _/_u_s_r_/_b_i_n_/_v_i but shell escapes will be disabled. + + aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi + + See the "Preventing Shell Escapes" section below for more details on + how NOEXEC works and whether or not it will work on your system. + + _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, 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 + + These tags override the value of the _l_o_g___i_n_p_u_t option on a per-command + basis. For more information, see the description of _l_o_g___i_n_p_u_t in the + "SUDOERS OPTIONS" section below. + + _L_O_G___O_U_T_P_U_T _a_n_d _N_O_L_O_G___O_U_T_P_U_T + + These tags override the value of the _l_o_g___o_u_t_p_u_t option on a per-command + basis. For more information, see the description of _l_o_g___o_u_t_p_u_t in the + "SUDOERS OPTIONS" section below. + + WWiillddccaarrddss + ssuuddoo allows shell-style _w_i_l_d_c_a_r_d_s (aka meta or glob characters) to be + used in host names, path names and command line arguments in the + _s_u_d_o_e_r_s file. Wildcard matching is done via the PPOOSSIIXX _g_l_o_b(3) and + _f_n_m_a_t_c_h(3) routines. Note that these are _n_o_t regular expressions. + + * Matches any set of zero or more characters. + + ? Matches any single character. + + [...] Matches any character in the specified range. + + [!...] Matches any character nnoott in the specified range. + + \x For any character "x", evaluates to "x". This is used to + escape special characters such as: "*", "?", "[", and "}". + + POSIX character classes may also be used if your system's _g_l_o_b(3) and + _f_n_m_a_t_c_h(3) functions support them. However, because the ':' character + has special meaning in _s_u_d_o_e_r_s, it must be escaped. For example: + + /bin/ls [[\:alpha\:]]* + + Would match any file name beginning with a letter. + + Note that a forward slash ('/') will nnoott be matched by wildcards used + 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: + + /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. + + EExxcceeppttiioonnss ttoo wwiillddccaarrdd rruulleess + The following exceptions apply to the above rules: + + "" If the empty string "" is the only command line argument in the + _s_u_d_o_e_r_s entry it means that command is not allowed to be run + with aannyy arguments. + + IInncclluuddiinngg ootthheerr ffiilleess ffrroomm wwiitthhiinn ssuuddooeerrss + It is possible to include other _s_u_d_o_e_r_s files from within the _s_u_d_o_e_r_s + file currently being parsed using the #include and #includedir + directives. + + This can be used, for example, to keep a site-wide _s_u_d_o_e_r_s file in + addition to a local, per-machine file. For the sake of this example + the site-wide _s_u_d_o_e_r_s will be _/_e_t_c_/_s_u_d_o_e_r_s and the per-machine one will + be _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. To include _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l from within + _/_e_t_c_/_s_u_d_o_e_r_s we would use the following line in _/_e_t_c_/_s_u_d_o_e_r_s: + + #include /etc/sudoers.local + + When ssuuddoo reaches this line it will suspend processing of the current + file (_/_e_t_c_/_s_u_d_o_e_r_s) and switch to _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. Upon reaching + the end of _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l, the rest of _/_e_t_c_/_s_u_d_o_e_r_s will be + processed. Files that are included may themselves include other files. + A hard limit of 128 nested include files is enforced to prevent include + file loops. + + If the path to the include file is not fully-qualified (does not begin + with a _/), it must be located in the same directory as the sudoers file + it was included from. For example, if _/_e_t_c_/_s_u_d_o_e_r_s contains the line: + + #include sudoers.local + + the file that will be included is _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. + + The file name may also include the %h escape, signifying the short form + of the host name. I.e., if the machine's host name is "xerxes", then + + #include /etc/sudoers.%h + + will cause 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 + the system package manager can drop _s_u_d_o_e_r_s rules into as part of + package installation. For example, given: + + #includedir /etc/sudoers.d + + ssuuddoo will read each file in _/_e_t_c_/_s_u_d_o_e_r_s_._d, skipping file names that + end in ~ or contain a . character to avoid causing problems with + package manager or editor temporary/backup files. Files are parsed in + sorted lexical order. That is, _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_0_1___f_i_r_s_t will be parsed + before _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1_0___s_e_c_o_n_d. Be aware that because the sorting is + lexical, not numeric, _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1___w_h_o_o_p_s would be loaded aafftteerr + _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1_0___s_e_c_o_n_d. Using a consistent number of leading zeroes + in the file names can be used to avoid such problems. + + Note that unlike files included via #include, vviissuuddoo will not edit the + 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. + + OOtthheerr ssppeecciiaall cchhaarraacctteerrss aanndd rreesseerrvveedd wwoorrddss + The pound sign ('#') is used to indicate a comment (unless it is part + of a #include directive or unless it occurs in the context of a user + name and is followed by one or more digits, in which case it is treated + as a uid). Both the comment character and any text after it, up to the + end of the line, are ignored. + + The reserved word AALLLL is a built-in _a_l_i_a_s that always causes a match to + succeed. It can be used wherever one might otherwise use a Cmnd_Alias, + User_Alias, Runas_Alias, or Host_Alias. You should not try to define + your own _a_l_i_a_s called AALLLL as the built-in alias will be used in + preference to your own. Please note that using AALLLL can be dangerous + since in a command context, it allows the user to run aannyy command on + the system. + + An exclamation point ('!') can be used as a logical _n_o_t operator both + in an _a_l_i_a_s and in front of a Cmnd. This allows one to exclude certain + values. Note, however, that using a ! in conjunction with the built-in + ALL alias to allow a user to run "all but a few" commands rarely works + as intended (see SECURITY NOTES below). + + Long lines can be continued with a backslash ('\') as the last + character on the line. + + Whitespace between elements in a list as well as special syntactic + characters in a _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): '!', '=', ':', + ',', '(', ')', '\'. + +SSUUDDOOEERRSS OOPPTTIIOONNSS + ssuuddoo's behavior can be modified by Default_Entry lines, as explained + earlier. A list of all supported Defaults parameters, grouped by type, + are listed below. + + BBoooolleeaann FFllaaggss: + + always_set_home If enabled, ssuuddoo will set the HOME environment variable + to the home directory of the target user (which is root + unless the --uu option is used). This effectively means + 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 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 + may run commands. This default may be overridden via + the PASSWD and NOPASSWD tags. This flag is _o_n by + default. + + closefrom_override + If set, the user may use ssuuddoo's --CC option which + overrides the default starting point at which ssuuddoo + begins closing open file descriptors. This flag is _o_f_f + by default. + + compress_io If set, and ssuuddoo is configured to log a command's input + or output, the I/O logs will be compressed using zzlliibb. + This flag is _o_n by default when ssuuddoo is compiled with + zzlliibb support. + + env_editor If set, vviissuuddoo will use the value of the EDITOR or + VISUAL environment variables before falling back on the + default editor list. Note that this may create a + security hole as it allows the user to run any + arbitrary command as root without logging. A safer + alternative is to place a colon-separated list of + editors in the editor variable. vviissuuddoo will then only + use the EDITOR or VISUAL if they match a value + specified in editor. This flag is _o_f_f by default. + + env_reset If set, ssuuddoo will run the command in a minimal + environment containing the TERM, PATH, HOME, MAIL, + SHELL, LOGNAME, USER, USERNAME and SUDO_* variables. + Any variables in the caller's environment that match + the env_keep and env_check lists are then added, + followed by any variables present in the file specified + by the _e_n_v___f_i_l_e option (if any). The default contents + of the env_keep and env_check lists are displayed when + ssuuddoo is run by root with the _-_V option. If the + _s_e_c_u_r_e___p_a_t_h option is set, its value will be used for + the PATH environment variable. This flag is _o_n by + default. + + fast_glob Normally, ssuuddoo uses the _g_l_o_b(3) function to do shell- + 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 + when the pattern references a network file system that + is mounted on demand (automounted). The _f_a_s_t___g_l_o_b + option causes ssuuddoo to use the _f_n_m_a_t_c_h(3) function, + which does not access the file system to do its + matching. The disadvantage of _f_a_s_t___g_l_o_b is that it is + unable to match relative path names such as _._/_l_s or + _._._/_b_i_n_/_l_s. This has security implications when path + names that include globbing characters are used with + the negation operator, '!', as such rules can be + trivially bypassed. As such, this option should not be + used when _s_u_d_o_e_r_s contains rules that contain negated + path names which include globbing characters. This + flag is _o_f_f by default. + + fqdn Set this flag if you want to put fully qualified host + 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 + that turning on _f_q_d_n requires ssuuddoo to make DNS lookups + which may make ssuuddoo unusable if DNS stops working (for + example if the machine is not plugged into the + network). Also note that you must use the host's + official name as DNS knows it. That is, you may not + use a host alias (CNAME entry) due to performance + issues and the fact that there is no way to get all + aliases from DNS. If your machine's host name (as + returned by the hostname command) is already fully + qualified you shouldn't need to set _f_q_d_n. This flag is + _o_f_f by default. + + ignore_dot If set, ssuuddoo will ignore '.' or '' (current dir) in the + PATH environment variable; the PATH itself is not + modified. This flag is _o_f_f by default. + + ignore_local_sudoers + If set via LDAP, parsing of _/_e_t_c_/_s_u_d_o_e_r_s will be + skipped. This is intended for Enterprises that wish to + prevent the usage of local sudoers files so that only + LDAP is used. This thwarts the efforts of rogue + operators who would attempt to add roles to + _/_e_t_c_/_s_u_d_o_e_r_s. When this option is present, + _/_e_t_c_/_s_u_d_o_e_r_s does not even need to exist. Since this + option tells ssuuddoo how to behave when no specific LDAP + entries have been matched, this sudoOption is only + meaningful for the cn=defaults section. This flag is + _o_f_f by default. + + insults If set, ssuuddoo will insult users when they enter an + 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_=. The _i_o_l_o_g___f_i_l_e option + may be used to control the format of the session ID. + + Note that user input may contain sensitive information + such as passwords (even if they are not echoed to the + screen), which will be stored in the log file + unencrypted. In most cases, logging the command output + via _l_o_g___o_u_t_p_u_t is all that is required. + + 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_=. The _i_o_l_o_g___f_i_l_e option + may be used to control the format of the session ID. + + 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. + + long_otp_prompt When validating with a One Time Password (OTP) scheme + such as SS//KKeeyy or OOPPIIEE, a two-line prompt is used to + make it easier to cut and paste the challenge to a + local window. It's not as pretty as the default but + some people find it more convenient. This flag is _o_f_f + by default. + + mail_always Send mail to the _m_a_i_l_t_o user every time a users runs + ssuuddoo. This flag is _o_f_f by default. + + mail_badpass Send mail to the _m_a_i_l_t_o user if the user running ssuuddoo + does not enter the correct password. This flag is _o_f_f + by default. + + mail_no_host If set, mail will be sent to the _m_a_i_l_t_o user if the + invoking user exists in the _s_u_d_o_e_r_s file, but is not + allowed to run commands on the current host. This flag + is _o_f_f by default. + + mail_no_perms If set, mail will be sent to the _m_a_i_l_t_o user if the + invoking user is allowed to use ssuuddoo but the command + they are trying is not listed in their _s_u_d_o_e_r_s file + entry or is explicitly denied. This flag is _o_f_f by + default. + + mail_no_user If set, mail will be sent to the _m_a_i_l_t_o user if the + invoking user is not in the _s_u_d_o_e_r_s file. This flag is + _o_n by default. + + noexec If set, all commands run via ssuuddoo will behave as if the + NOEXEC tag has been set, unless overridden by a EXEC + tag. See the description of _N_O_E_X_E_C _a_n_d _E_X_E_C below as + well as the "Preventing Shell Escapes" section at the + end of this manual. This flag is _o_f_f by default. + + 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 + gather information on the location of executables that + the normal user does not have access to. The + disadvantage is that if the executable is simply not in + the user's PATH, ssuuddoo will tell the user that they are + not allowed to run it, which can be confusing. This + flag is _o_n by default. + + passprompt_override + 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:". + 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. + + preserve_groups By default, ssuuddoo will initialize the group vector to + the list of groups the target user is in. When + _p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, the user's existing group + vector is left unaltered. The real and effective group + IDs, however, are still set to match the target user. + This flag is _o_f_f by default. + + pwfeedback By default, ssuuddoo reads the password like most other + Unix programs, by turning off echo until the user hits + the return (or enter) key. Some users become confused + by this as it appears to them that ssuuddoo has hung at + this point. When _p_w_f_e_e_d_b_a_c_k is set, ssuuddoo will provide + visual feedback when the user presses a key. Note that + this does have a security impact as an onlooker may be + able to determine the length of the password being + entered. This flag is _o_f_f by default. + + requiretty If set, ssuuddoo will only run when the user is logged in + to a real tty. When this flag is set, ssuuddoo can only be + run from a login session and not via other means such + as _c_r_o_n(1m) or cgi-bin scripts. This flag is _o_f_f by + default. + + root_sudo If set, root is allowed to run ssuuddoo too. Disabling + this prevents users from "chaining" ssuuddoo commands to + get a root shell by doing something like "sudo sudo + /bin/sh". Note, however, that turning off _r_o_o_t___s_u_d_o + will also prevent root from running ssuuddooeeddiitt. + Disabling _r_o_o_t___s_u_d_o provides no real additional + security; it exists purely for historical reasons. + This flag is _o_n by default. + + rootpw If set, ssuuddoo will prompt for the root password instead + of the password of the invoking user. This flag is _o_f_f + 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 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 + system) use LOGNAME to determine the real identity of + the user, it may be desirable to change this behavior. + This can be done by negating the set_logname option. + Note that if the _e_n_v___r_e_s_e_t option has not been + disabled, entries in the _e_n_v___k_e_e_p list will override + the value of _s_e_t___l_o_g_n_a_m_e. This flag is _o_n by default. + + set_utmp When enabled, ssuuddoo will create an entry in the utmp (or + utmpx) file when a pseudo-tty is allocated. A pseudo- + tty is allocated by ssuuddoo when the _l_o_g___i_n_p_u_t, _l_o_g___o_u_t_p_u_t + or _u_s_e___p_t_y flags are enabled. By default, the new + entry will be a copy of the user's existing utmp entry + (if any), with the tty, time, type and pid fields + updated. This flag is _o_n by default. + + setenv Allow the user to disable the _e_n_v___r_e_s_e_t option from the + command line via the --EE option. Additionally, + environment variables set via 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. + This flag is _o_f_f by default. + + shell_noargs If set and ssuuddoo is invoked with no arguments it acts as + if the --ss option had been given. That is, it runs a + shell as root (the shell is determined by the SHELL + environment variable if it is set, falling back on the + shell listed in the invoking user's /etc/passwd entry + if not). This flag is _o_f_f by default. + + stay_setuid Normally, when ssuuddoo executes a command the real and + effective UIDs are set to the target user (root by + default). This option changes that behavior such that + the real UID is left as the invoking user's UID. In + other words, this makes ssuuddoo act as a setuid wrapper. + This can be useful on systems that disable some + potentially dangerous functionality when a program is + run setuid. This option is only effective on systems + with either the _s_e_t_r_e_u_i_d_(_) or _s_e_t_r_e_s_u_i_d_(_) function. + This flag is _o_f_f by default. + + 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. + + tty_tickets If set, users must authenticate on a per-tty basis. + With this flag enabled, ssuuddoo will use a file named for + the tty the user is logged in on in the user's time + stamp directory. If disabled, the time stamp of the + directory is used instead. This flag is _o_n by default. + + umask_override If set, ssuuddoo will set the umask as specified by _s_u_d_o_e_r_s + without modification. This makes it possible to + specify a more permissive umask in _s_u_d_o_e_r_s than the + user's own umask and matches historical behavior. If + _u_m_a_s_k___o_v_e_r_r_i_d_e is not set, ssuuddoo will set the umask to + be the union of the user's umask and what is specified + in _s_u_d_o_e_r_s. This flag is _o_f_f by default. + + use_loginclass If set, ssuuddoo will apply the defaults specified for the + target user's login class if one exists. Only + available if ssuuddoo is configured with the + --with-logincap option. This flag is _o_f_f by default. + + use_pty If set, ssuuddoo will run the command in a pseudo-pty even + if no I/O logging is being gone. A malicious program + run under ssuuddoo could conceivably fork a background + process that retains to the user's terminal device + after the main program has finished executing. Use of + this option will make that impossible. This flag is + _o_f_f by default. + + utmp_runas If set, ssuuddoo will store the name of the runas user when + updating the utmp (or utmpx) file. By default, ssuuddoo + stores the name of the invoking user. This flag is _o_f_f + by default. + + visiblepw By default, ssuuddoo will refuse to run if the user must + enter a password but it is not possible to disable echo + on the terminal. If the _v_i_s_i_b_l_e_p_w flag is set, ssuuddoo + will prompt for a password even when it would be + visible on the screen. This makes it possible to run + things like "rsh somehost sudo ls" since _r_s_h(1) does + not allocate a tty. This flag is _o_f_f by default. + + IInntteeggeerrss: + + 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: + + loglinelen Number of characters per line for the file log. This + value is used to decide when to wrap lines for nicer + log files. This has no effect on the syslog log file, + only the file log. The default is 80 (use 0 or negate + the option to disable word wrap). + + passwd_timeout Number of minutes before the ssuuddoo password prompt times + out, or 0 for no timeout. The timeout may include a + fractional component if minute granularity is + insufficient, for example 2.5. The default is 5. + + timestamp_timeout + Number of minutes that can elapse before ssuuddoo will ask + for a passwd again. The timeout may include a + fractional component if minute granularity is + insufficient, for example 2.5. The default is 5. Set + this to 0 to always prompt for a password. If set to a + value less than 0 the user's timestamp will never + expire. This can be used to allow users to create or + delete their own timestamps via sudo -v and sudo -k + respectively. + + umask Umask to use when running the command. Negate this + option or set it to 0777 to preserve the user's umask. + The actual umask that is used will be the union of the + user's umask and the value of the _u_m_a_s_k option, which + defaults to 0022. This guarantees that ssuuddoo never + lowers the umask when running a command. Note on + systems that use PAM, the default PAM configuration may + specify its own umask which will override the value set + in _s_u_d_o_e_r_s. + + SSttrriinnggss: + + badpass_message Message that is displayed if a user enters an incorrect + password. The default is Sorry, try again. unless + insults are enabled. + + editor A colon (':') separated list of editors allowed to be + used with vviissuuddoo. vviissuuddoo will choose the editor that + matches the user's EDITOR environment variable if + possible, or the first editor in the list that exists + and is executable. The default is "vi". + + iolog_dir The top-level directory to use when constructing the + path name for the input/output log directory. Only + used if the _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 session sequence number, if any, is + stored in the directory. The default is + "/var/log/sudo-io". + + The following percent (`%') escape sequences are + supported: + + %{seq} + expanded to a monotonically increasing base-36 + sequence number, such as 0100A5, where every two + digits are used to form a new directory, e.g. + _0_1_/_0_0_/_A_5 + + %{user} + expanded to the invoking user's login name + + %{group} + expanded to the name of the invoking user's real + group ID + + %{runas_user} + expanded to the login name of the user the command + will be run as (e.g. root) + + %{runas_group} + expanded to the group name of the user the command + will be run as (e.g. wheel) + + %{hostname} + expanded to the local host name without the domain + name + + %{command} + expanded to the base name of the command being run + + In addition, any escape sequences supported by the + system's _s_t_r_f_t_i_m_e_(_) function will be expanded. + + To include a literal `%' character, the string `%%' + should be used. + + iolog_file The path name, relative to _i_o_l_o_g___d_i_r, 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. Note that _i_o_l_o_g___f_i_l_e + may contain directory components. The default is + "%{seq}". + + See the _i_o_l_o_g___d_i_r option above for a list of supported + percent (`%') escape sequences. + + In addition to the escape sequences, path names that + end in six or more Xs will have the Xs replaced with a + unique combination of digits and letters, similar to + the _m_k_t_e_m_p_(_) function. + + 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 This option is no longer supported. The path to the + noexec file should now be set in the _/_e_t_c_/_s_u_d_o_._c_o_n_f + file. + + passprompt The default prompt to use when asking for a password; + can be overridden via the --pp option or the SUDO_PROMPT + environment variable. The following percent (`%') + escape sequences are supported: + + %H expanded to the local host name including the + domain name (only if the machine's host name is + fully qualified or the _f_q_d_n option is set) + + %h expanded to the local host name without the domain + name + + %p expanded to the user whose password is being asked + for (respects the _r_o_o_t_p_w, _t_a_r_g_e_t_p_w and _r_u_n_a_s_p_w + flags in _s_u_d_o_e_r_s) + + %U expanded to the login name of the user the command + will be run as (defaults to root) + + %u expanded to the invoking user's login name + + %% two consecutive % characters are collapsed into a + single % character + + The default value is Password:. + + role The default SELinux role to use when constructing a new + security context to run the command. The default role + may be overridden on a per-command basis in _s_u_d_o_e_r_s or + via command line options. This option is only + available whe ssuuddoo is built with SELinux support. + + runas_default The default user to run commands as if the --uu option is + not specified on the command line. This defaults to + root. + + syslog_badpri Syslog priority to use when user authenticates + unsuccessfully. Defaults to alert. + + The following syslog priorities are supported: aalleerrtt, + ccrriitt, ddeebbuugg, eemmeerrgg, eerrrr, iinnffoo, nnoottiiccee, and wwaarrnniinngg. + + syslog_goodpri Syslog priority to use when user authenticates + successfully. Defaults to notice. + + See syslog_badpri for the list of supported syslog + priorities. + + sudoers_locale Locale to use when parsing the sudoers file, logging + commands, and sending email. Note that changing the + locale may affect how sudoers is interpreted. Defaults + to "C". + + timestampdir The directory in which ssuuddoo stores its timestamp files. + The default is _/_v_a_r_/_a_d_m_/_s_u_d_o. + + timestampowner The owner of the timestamp directory and the timestamps + stored therein. The default is root. + + type The default SELinux type to use when constructing a new + security context to run the command. The default type + may be overridden on a per-command basis in _s_u_d_o_e_r_s or + via command line options. This option is only + available whe ssuuddoo is built with SELinux support. + + SSttrriinnggss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: + + env_file The _e_n_v___f_i_l_e option specifies the fully qualified path to a + file containing variables to be set in the environment of + the program being run. Entries in this file should either + be of the form VARIABLE=value or export VARIABLE=value. + The value may optionally be surrounded by single or double + quotes. Variables in this file are subject to other ssuuddoo + environment settings such as _e_n_v___k_e_e_p and _e_n_v___c_h_e_c_k. + + exempt_group + Users in this group are exempt from password and PATH + requirements. The group name specified should not include + a % prefix. This is not set by default. + + group_plugin + A string containing a _s_u_d_o_e_r_s group plugin with optional + arguments. This can be used to implement support for the + nonunix_group syntax described earlier. The string should + consist of the plugin path, either fully-qualified or + relative to the _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c directory, followed by + any configuration arguments the plugin requires. These + arguments (if any) will be passed to the plugin's + initialization function. If arguments are present, the + string must be enclosed in double quotes ("). + + For example, given _/_e_t_c_/_s_u_d_o_-_g_r_o_u_p, a group file in Unix + group format, the sample group plugin can be used: + + Defaults group_plugin="sample_group.so /etc/sudo-group" + + For more information see _s_u_d_o___p_l_u_g_i_n(4). + + lecture This option controls when a short lecture will be printed + along with the password prompt. It has the following + possible values: + + always Always lecture the user. + + never Never lecture the user. + + once Only lecture the user the first time they run ssuuddoo. + + If no value is specified, a value of _o_n_c_e is implied. + 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. + + 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: + + 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 + password. + + always The user must always enter a password to use the --ll + option. + + any At least one of 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 password. + + never The user need never enter a password to use the --ll + option. + + If no value is specified, a value of _a_n_y is implied. + Negating the option results in a value of _n_e_v_e_r being used. + The default value is _a_n_y. + + logfile Path to the ssuuddoo log file (not the syslog log file). + Setting a path turns on logging to a file; negating this + option turns it off. By default, ssuuddoo logs via syslog. + + mailerflags Flags to use when invoking mailer. Defaults to --tt. + + mailerpath Path to mail program used to send warning mail. Defaults + to the path to sendmail found at configure time. + + mailfrom Address to use for the "from" address when sending warning + and error mail. The address should be enclosed in double + quotes (") to protect against ssuuddoo interpreting the @ sign. + Defaults to the name of the user running ssuuddoo. + + mailto Address to send warning and error mail to. The address + should be enclosed in double quotes (") to protect against + ssuuddoo interpreting the @ sign. Defaults to root. + + secure_path Path used for every command run from ssuuddoo. If you don't + trust the people running ssuuddoo to have a sane PATH + environment variable you may want to use this. Another use + is if you want to have the "root path" be separate from the + "user path." Users in the group specified by the + _e_x_e_m_p_t___g_r_o_u_p option are not affected by _s_e_c_u_r_e___p_a_t_h. This + option is not set by default. + + syslog Syslog facility if syslog is being used for logging (negate + to disable syslog logging). Defaults to auth. + + The following syslog facilities are supported: aauutthhpprriivv (if + your OS supports it), aauutthh, ddaaeemmoonn, uusseerr, llooccaall00, llooccaall11, + llooccaall22, llooccaall33, llooccaall44, llooccaall55, llooccaall66, and llooccaall77. + + 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 + password. + + always The user must always enter a password to use the --vv + option. + + any At least one of 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 password. + + never The user need never enter a password to use the --vv + option. + + If no value is specified, a value of _a_l_l is implied. + Negating the option results in a value of _n_e_v_e_r being used. + The default value is _a_l_l. + + LLiissttss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: + + env_check Environment variables to be removed from the user's + environment if the variable's value contains % or / + characters. This can be used to guard against printf- + style format vulnerabilities in poorly-written + programs. The argument may be a double-quoted, space- + separated list or a single value without double-quotes. + The list can be replaced, added to, deleted from, or + disabled by using the =, +=, -=, and ! operators + respectively. Regardless of whether the env_reset + option is enabled or disabled, variables specified by + env_check will be preserved in the environment if they + pass the aforementioned check. The default list of + environment variables to check is displayed when ssuuddoo + is run by root with the _-_V option. + + env_delete Environment variables to be removed from the user's + environment when the _e_n_v___r_e_s_e_t option is not in effect. + The argument may be a double-quoted, space-separated + list or a single value without double-quotes. The list + can be replaced, added to, deleted from, or disabled by + using the =, +=, -=, and ! operators respectively. The + default list of environment variables to remove is + displayed when ssuuddoo is run by root with the _-_V option. + Note that many operating systems will remove + potentially dangerous variables from the environment of + 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 =, +=, + -=, and ! operators respectively. The default list of + variables to keep is displayed when ssuuddoo is run by root + with the _-_V option. + +SSUUDDOO..CCOONNFF + The _/_e_t_c_/_s_u_d_o_._c_o_n_f file determines which plugins the ssuuddoo front end + will load. If no _/_e_t_c_/_s_u_d_o_._c_o_n_f file is present, or it contains no + Plugin lines, ssuuddoo will use the _s_u_d_o_e_r_s security policy and I/O + logging, which corresponds to the following _/_e_t_c_/_s_u_d_o_._c_o_n_f file. + + # + # Default /etc/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_options ... + # Path askpass /path/to/askpass + # Path noexec /path/to/sudo_noexec.so + # Debug sudo /var/log/sudo_debug all@warn + # Set disable_coredump true + # + # The plugin_path is relative to /usr/local/libexec unless + # fully qualified. + # The plugin_name corresponds to a global symbol in the plugin + # that contains the plugin interface structure. + # The plugin_options are optional. + # + Plugin policy_plugin sudoers.so + Plugin io_plugin sudoers.so + + PPLLUUGGIINN OOPPTTIIOONNSS + Starting with ssuuddoo 1.8.5 it is possible to pass options to the _s_u_d_o_e_r_s + plugin. Options may be listed after the path to the plugin (i.e. after + _s_u_d_o_e_r_s_._s_o); multiple options should be space-separated. For example: + + Plugin sudoers_policy sudoers.so sudoers_file=/etc/sudoers sudoers_uid=0 sudoers_gid=0 sudoers_mode=0440 + + The following plugin options are supported: + + sudoers_file=pathname + The _s_u_d_o_e_r_s___f_i_l_e option can be used to override the default + path to the _s_u_d_o_e_r_s file. + + sudoers_uid=uid + The _s_u_d_o_e_r_s___u_i_d option can be used to override the default + owner of the sudoers file. It should be specified as a + numeric user ID. + + sudoers_gid=gid + The _s_u_d_o_e_r_s___g_i_d option can be used to override the default + group of the sudoers file. It should be specified as a + numeric group ID. + + sudoers_mode=mode + The _s_u_d_o_e_r_s___m_o_d_e option can be used to override the default + file mode for the sudoers file. It should be specified as an + octal value. + + DDEEBBUUGG FFLLAAGGSS + Versions 1.8.4 and higher of the _s_u_d_o_e_r_s plugin supports a debugging + framework that can help track down what the plugin is doing internally + if there is a problem. This can be configured in the _/_e_t_c_/_s_u_d_o_._c_o_n_f + file as described in _s_u_d_o(1m). + + The _s_u_d_o_e_r_s plugin uses the same debug flag format as ssuuddoo itself: + _s_u_b_s_y_s_t_e_m@_p_r_i_o_r_i_t_y. + + The priorities used by _s_u_d_o_e_r_s, in order of decreasing severity, are: + _c_r_i_t, _e_r_r, _w_a_r_n, _n_o_t_i_c_e, _d_i_a_g, _i_n_f_o, _t_r_a_c_e and _d_e_b_u_g. Each priority, + when specified, also includes all priorities higher than it. For + example, a priority of _n_o_t_i_c_e would include debug messages logged at + _n_o_t_i_c_e and higher. + + The following subsystems are used by _s_u_d_o_e_r_s: + + _a_l_i_a_s User_Alias, Runas_Alias, Host_Alias and Cmnd_Alias processing + + _a_l_l matches every subsystem + + _a_u_d_i_t BSM and Linux audit code + + _a_u_t_h user authentication + + _d_e_f_a_u_l_t_s _s_u_d_o_e_r_s _D_e_f_a_u_l_t_s settings + + _e_n_v environment handling + + _l_d_a_p LDAP-based sudoers + + _l_o_g_g_i_n_g logging support + + _m_a_t_c_h matching of users, groups, hosts and netgroups in _s_u_d_o_e_r_s + + _n_e_t_i_f network interface handling + + _n_s_s network service switch handling in _s_u_d_o_e_r_s + + _p_a_r_s_e_r _s_u_d_o_e_r_s file parsing + + _p_e_r_m_s permission setting + + _p_l_u_g_i_n The equivalent of _m_a_i_n for the plugin. + + _p_t_y pseudo-tty related code + + _r_b_t_r_e_e redblack tree internals + + _u_t_i_l utility functions + +FFIILLEESS + _/_e_t_c_/_s_u_d_o_._c_o_n_f Sudo front end configuration + + _/_e_t_c_/_s_u_d_o_e_r_s List of who can run what + + _/_e_t_c_/_g_r_o_u_p Local groups file + + _/_e_t_c_/_n_e_t_g_r_o_u_p List of network groups + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o I/O log files + + _/_v_a_r_/_a_d_m_/_s_u_d_o Directory containing time stamps for the + _s_u_d_o_e_r_s security policy + + _/_e_t_c_/_e_n_v_i_r_o_n_m_e_n_t Initial environment for --ii mode on AIX and + Linux systems + +EEXXAAMMPPLLEESS + Below are example _s_u_d_o_e_r_s entries. Admittedly, some of these are a bit + contrived. First, we allow a few environment variables to pass and + then define our _a_l_i_a_s_e_s: + + # Run X applications through sudo; HOME is used to find the + # .Xauthority file. Note that other programs use HOME to find + # configuration files and this may lead to privilege escalation! + Defaults env_keep += "DISPLAY HOME" + + # User alias specification + User_Alias FULLTIMERS = millert, mikef, dowdy + User_Alias PARTTIMERS = bostley, jwfox, crawl + User_Alias WEBMASTERS = will, wendy, wim + + # Runas alias specification + Runas_Alias OP = root, operator + Runas_Alias DB = oracle, sybase + Runas_Alias ADMINGRP = adm, oper + + # Host alias specification + Host_Alias SPARC = bigtime, eclipse, moet, anchor :\ + SGI = grolsch, dandelion, black :\ + ALPHA = widget, thalamus, foobar :\ + HPPA = boa, nag, python + Host_Alias CUNETS = 128.138.0.0/255.255.0.0 + Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 + Host_Alias SERVERS = master, mail, www, ns + Host_Alias CDROM = orion, perseus, hercules + + # Cmnd alias specification + Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\ + /usr/sbin/restore, /usr/sbin/rrestore + Cmnd_Alias KILL = /usr/bin/kill + Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm + Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown + Cmnd_Alias HALT = /usr/sbin/halt + Cmnd_Alias REBOOT = /usr/sbin/reboot + Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \ + /usr/local/bin/tcsh, /usr/bin/rsh, \ + /usr/local/bin/zsh + Cmnd_Alias SU = /usr/bin/su + Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less + + Here we override some of the compiled in default values. We want ssuuddoo + to log via _s_y_s_l_o_g(3) using the _a_u_t_h facility in all cases. We don't + want to subject the full time staff to the ssuuddoo lecture, user mmiilllleerrtt + need not give a password, and we don't want to reset the LOGNAME, USER + or USERNAME environment variables when running commands as root. + Additionally, on the machines in the _S_E_R_V_E_R_S Host_Alias, we keep an + additional local log file and make sure we log the year in each log + line since the log entries will be kept around for several years. + Lastly, we disable shell escapes for the commands in the PAGERS + Cmnd_Alias (_/_u_s_r_/_b_i_n_/_m_o_r_e, _/_u_s_r_/_b_i_n_/_p_g and _/_u_s_r_/_b_i_n_/_l_e_s_s). + + # Override built-in defaults + Defaults syslog=auth + Defaults>root !set_logname + Defaults:FULLTIMERS !lecture + Defaults:millert !authenticate + Defaults@SERVERS log_year, logfile=/var/log/sudo.log + Defaults!PAGERS noexec + + The _U_s_e_r _s_p_e_c_i_f_i_c_a_t_i_o_n is the part that actually determines who may run + what. + + root ALL = (ALL) ALL + %wheel ALL = (ALL) ALL + + We let rroooott and any user in group wwhheeeell run any command on any host as + any user. + + FULLTIMERS ALL = NOPASSWD: ALL + + Full time sysadmins (mmiilllleerrtt, mmiikkeeff, and ddoowwddyy) may run any command on + any host without authenticating themselves. + + PARTTIMERS ALL = ALL + + Part time sysadmins (bboossttlleeyy, jjwwffooxx, and ccrraawwll) may run any command on + any host but they must authenticate themselves first (since the entry + lacks the NOPASSWD tag). + + jack CSNETS = ALL + + The user 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. + + lisa CUNETS = ALL + + The user lliissaa may run any command on any host in the _C_U_N_E_T_S alias (the + class B network 128.138.0.0). + + operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\ + sudoedit /etc/printcap, /usr/oper/bin/ + + The ooppeerraattoorr user may run commands limited to simple maintenance. + Here, those are commands related to backups, killing processes, the + printing system, shutting down the system, and any commands in the + directory _/_u_s_r_/_o_p_e_r_/_b_i_n_/. + + joe ALL = /usr/bin/su operator + + The user jjooee may only _s_u(1) to operator. + + pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root + + %opers ALL = (: ADMINGRP) /usr/sbin/ + + Users in the ooppeerrss group may run commands in _/_u_s_r_/_s_b_i_n_/ as themselves + with any group in the _A_D_M_I_N_G_R_P Runas_Alias (the aaddmm and ooppeerr groups). + + The user ppeettee is allowed to change anyone's password except for root on + the _H_P_P_A machines. Note that this assumes _p_a_s_s_w_d(1) does not take + multiple user names on the command line. + + bob SPARC = (OP) ALL : SGI = (OP) ALL + + The user bboobb may run anything on the _S_P_A_R_C and _S_G_I machines as any user + listed in the _O_P Runas_Alias (rroooott and ooppeerraattoorr). + + jim +biglab = ALL + + The user jjiimm may run any command on machines in the _b_i_g_l_a_b netgroup. + ssuuddoo knows that "biglab" is a netgroup due to the '+' prefix. + + +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser + + Users in the sseeccrreettaarriieess netgroup need to help manage the printers as + well as add and remove users, so they are allowed to run those commands + on all machines. + + fred ALL = (DB) NOPASSWD: ALL + + The user 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* + + 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. + + jen ALL, !SERVERS = ALL + + The user jjeenn may run any command on any machine except for those in the + _S_E_R_V_E_R_S Host_Alias (master, mail, www and ns). + + jill SERVERS = /usr/bin/, !SU, !SHELLS + + For any machine in the _S_E_R_V_E_R_S Host_Alias, jjiillll may run any commands in + the directory _/_u_s_r_/_b_i_n_/ except for those commands belonging to the _S_U + and _S_H_E_L_L_S Cmnd_Aliases. + + steve CSNETS = (operator) /usr/local/op_commands/ + + The user sstteevvee may run any command in the directory + /usr/local/op_commands/ but only as user operator. + + matt valkyrie = KILL + + On his personal workstation, valkyrie, mmaatttt needs to be able to kill + hung processes. + + WEBMASTERS www = (www) ALL, (root) /usr/bin/su www + + On the host www, any user in the _W_E_B_M_A_S_T_E_R_S User_Alias (will, wendy, + and wim), may run any command as user www (which owns the web pages) or + simply _s_u(1) to www. + + ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ + /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM + + Any user may mount or unmount a CD-ROM on the machines in the CDROM + Host_Alias (orion, perseus, hercules) without entering a password. + This is a bit tedious for users to type, so it is a prime candidate for + encapsulating in a shell script. + +SSEECCUURRIITTYY NNOOTTEESS + LLiimmiittaattiioonnss ooff tthhee ''!!'' ooppeerraattoorr + It is generally not effective to "subtract" commands from ALL using the + '!' operator. A user can trivially circumvent this by copying the + desired command to a different name and then executing that. For + example: + + bill ALL = ALL, !SU, !SHELLS + + Doesn't really prevent 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). + + In general, if a user has sudo ALL there is nothing to prevent them + from creating their own program that gives them a root shell (or making + their own copy of a shell) regardless of any '!' elements in the user + specification. + + SSeeccuurriittyy iimmpplliiccaattiioonnss ooff _f_a_s_t___g_l_o_b + 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 security issue for + rules that subtract or revoke privileges. + + For example, given the following _s_u_d_o_e_r_s entry: + + john ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*, + /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root + + User jjoohhnn can still run /usr/bin/passwd root if _f_a_s_t___g_l_o_b is enabled by + changing to _/_u_s_r_/_b_i_n and running ./passwd root instead. + + PPrreevveennttiinngg SShheellll EEssccaappeess + Once ssuuddoo executes a program, that program is free to do whatever it + pleases, including run other programs. This can be a security issue + since it is not uncommon for a program to allow shell escapes, which + lets a user bypass ssuuddoo's access control and logging. Common programs + that permit shell escapes include shells (obviously), editors, + paginators, mail and terminal programs. + + There are two basic approaches to this problem: + + restrict Avoid giving users access to commands that allow the user to + run arbitrary commands. Many editors have a restricted mode + where shell escapes are disabled, though ssuuddooeeddiitt is a better + solution to running editors via ssuuddoo. Due to the large + number of programs that offer shell escapes, restricting + users to the set of programs that do not is often unworkable. + + noexec Many systems that support shared libraries have the ability + to override default library functions by pointing an + environment variable (usually LD_PRELOAD) to an alternate + shared library. On such systems, ssuuddoo's _n_o_e_x_e_c functionality + can be used to prevent a program run by ssuuddoo from executing + any other programs. Note, however, that this applies only to + native dynamically-linked executables. Statically-linked + executables and foreign executables running under binary + emulation are not affected. + + The _n_o_e_x_e_c feature is known to work on SunOS, Solaris, *BSD, + Linux, IRIX, Tru64 UNIX, MacOS X, HP-UX 11.x and AIX 5.3 and + above. It should be supported on most operating systems that + support the LD_PRELOAD environment variable. Check your + operating system's manual pages for the dynamic linker + (usually ld.so, ld.so.1, dyld, dld.sl, rld, or loader) to see + if LD_PRELOAD is supported. + + On Solaris 10 and higher, _n_o_e_x_e_c uses Solaris privileges + instead of the LD_PRELOAD environment variable. + + To enable _n_o_e_x_e_c for a command, use the NOEXEC tag as + documented in the User Specification section above. Here is + that example again: + + aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi + + This allows user aaaarroonn to run _/_u_s_r_/_b_i_n_/_m_o_r_e and _/_u_s_r_/_b_i_n_/_v_i + with _n_o_e_x_e_c enabled. This will prevent those two commands + from executing other commands (such as a shell). If you are + unsure whether or not your system is capable of supporting + _n_o_e_x_e_c you can always just try it out and check whether shell + escapes work when _n_o_e_x_e_c is enabled. + + Note that restricting shell escapes is not a panacea. Programs running + as root are still capable of many potentially hazardous operations + (such as changing or overwriting files) that could lead to unintended + privilege escalation. In the specific case of an editor, a safer + approach is to give the user permission to run ssuuddooeeddiitt. + + TTiimmee ssttaammpp ffiillee cchheecckkss + _s_u_d_o_e_r_s will check the ownership of its time stamp directory + (_/_v_a_r_/_a_d_m_/_s_u_d_o by default) and ignore the directory's contents if it is + not owned by root or if it is writable by a user other than root. On + systems that allow non-root users to give away files via _c_h_o_w_n(2), if + the time stamp directory is located in a world-writable directory + (e.g., _/_t_m_p), it is possible for a user to create the time stamp + directory before ssuuddoo is run. However, because _s_u_d_o_e_r_s checks the + ownership and mode of the directory and its contents, the only damage + that can be done is to "hide" files by putting them in the time stamp + dir. This is unlikely to happen since once the time stamp dir is owned + by root and inaccessible by any other user, the user placing files + there would be unable to get them back out. + + _s_u_d_o_e_r_s will not honor time stamps set far in the future. Time stamps + with a date greater than current_time + 2 * TIMEOUT will be ignored and + sudo will log and complain. This is done to keep a user from creating + his/her own time stamp with a bogus date on systems that allow users to + give away files if the time stamp directory is located in a world- + writable directory. + + On systems where the boot time is available, _s_u_d_o_e_r_s will ignore time + stamps that date from before the machine booted. + + Since time stamp files live in the file system, they can outlive a + user's login session. As a result, a user may be able to login, run a + command with ssuuddoo after authenticating, logout, login again, and run + ssuuddoo without authenticating so long as the time stamp file's + modification time is within 5 minutes (or whatever the timeout is set + to in _s_u_d_o_e_r_s). When the _t_t_y___t_i_c_k_e_t_s option is enabled, the time stamp + has per-tty granularity but still may outlive the user's session. On + Linux systems where the devpts filesystem is used, Solaris systems with + the devices filesystem, as well as other systems that utilize a devfs + filesystem that monotonically increase the inode number of devices as + they are created (such as Mac OS X), _s_u_d_o_e_r_s is able to determine when + a tty-based time stamp file is stale and will ignore it. + Administrators should not rely on this feature as it is not universally + available. + +SSEEEE AALLSSOO + _r_s_h(1), _s_u(1), _f_n_m_a_t_c_h(3), _g_l_o_b(3), _m_k_t_e_m_p(3), _s_t_r_f_t_i_m_e(3), + _s_u_d_o_e_r_s_._l_d_a_p(4), _s_u_d_o___p_l_u_g_i_n(1m), _s_u_d_o(1m), _v_i_s_u_d_o(1m) + +CCAAVVEEAATTSS + The _s_u_d_o_e_r_s file should aallwwaayyss be edited by the vviissuuddoo command which + locks the file and does grammatical checking. It is imperative that + _s_u_d_o_e_r_s be free of syntax errors since ssuuddoo will not run with a + syntactically incorrect _s_u_d_o_e_r_s file. + + When using netgroups of machines (as opposed to users), if you store + fully qualified host name in the netgroup (as is usually the case), you + either need to have the machine's host name be fully qualified as + returned by the hostname command or use the _f_q_d_n option in _s_u_d_o_e_r_s. + +BBUUGGSS + If you feel you have found a bug in ssuuddoo, please submit a bug report at + http://www.sudo.ws/sudo/bugs/ + +SSUUPPPPOORRTT + Limited free support is available via the sudo-users mailing list, see + http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search + the archives. + +DDIISSCCLLAAIIMMEERR + ssuuddoo is provided ``AS IS'' and any express or implied warranties, + including, but not limited to, the implied warranties of + merchantability and fitness for a particular purpose are disclaimed. + See the LICENSE file distributed with ssuuddoo or + http://www.sudo.ws/sudo/license.html for complete details. + + + +1.8.5 March 28, 2012 SUDOERS(4) diff --git a/doc/sudoers.ldap.cat b/doc/sudoers.ldap.cat new file mode 100644 index 0000000..67d6d86 --- /dev/null +++ b/doc/sudoers.ldap.cat @@ -0,0 +1,750 @@ +SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) + + + +NNAAMMEE + sudoers.ldap - sudo LDAP configuration + +DDEESSCCRRIIPPTTIIOONN + In addition to the standard _s_u_d_o_e_r_s file, ssuuddoo may be configured via + LDAP. This can be especially useful for synchronizing _s_u_d_o_e_r_s in a + large, distributed environment. + + Using LDAP for _s_u_d_o_e_r_s has several benefits: + + o ssuuddoo no longer needs to read _s_u_d_o_e_r_s in its entirety. When LDAP is + used, there are only two or three LDAP queries per invocation. + This makes it especially fast and particularly usable in LDAP + environments. + + o ssuuddoo no longer exits if there is a typo in _s_u_d_o_e_r_s. It is not + possible to load LDAP data into the server that does not conform to + the sudoers schema, so proper syntax is guaranteed. It is still + possible to have typos in a user or host name, but this will not + prevent ssuuddoo from running. + + o It is possible to specify per-entry options that override the + global default options. _/_e_t_c_/_s_u_d_o_e_r_s only supports default options + and limited options associated with user/host/commands/aliases. + The syntax is complicated and can be difficult for users to + understand. Placing the options directly in the entry is more + natural. + + o The vviissuuddoo program is no longer needed. vviissuuddoo provides locking + and syntax checking of the _/_e_t_c_/_s_u_d_o_e_r_s file. Since LDAP updates + are atomic, locking is no longer necessary. Because syntax is + checked when the data is inserted into LDAP, there is no need for a + specialized tool to check syntax. + + Another major difference between LDAP and file-based _s_u_d_o_e_r_s is that in + LDAP, ssuuddoo-specific Aliases are not supported. + + 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 + 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. + + Cmnd_Aliases are not really required either since it is possible to + have multiple users listed in a sudoRole. Instead of defining a + Cmnd_Alias that is referenced by multiple users, one can create a + sudoRole that contains the commands and assign multiple users to it. + + SSUUDDOOeerrss LLDDAAPP ccoonnttaaiinneerr + The _s_u_d_o_e_r_s configuration is contained in the ou=SUDOers LDAP + container. + + Sudo first looks for the cn=default entry in the SUDOers container. If + found, the multi-valued sudoOption attribute is parsed in the same + manner as a global Defaults line in _/_e_t_c_/_s_u_d_o_e_r_s. In the following + example, the SSH_AUTH_SOCK variable will be preserved in the + environment for all users. + + dn: cn=defaults,ou=SUDOers,dc=example,dc=com + objectClass: top + objectClass: sudoRole + cn: defaults + description: Default sudoOption's go here + sudoOption: env_keep+=SSH_AUTH_SOCK + + The equivalent of a sudoer in LDAP is a sudoRole. It consists of the + following attributes: + + ssuuddooUUsseerr + A user name, user ID (prefixed with '#'), Unix group (prefixed with + '%'), Unix group ID (prefixed with '%#'), or user netgroup + (prefixed with '+'). + + ssuuddooHHoosstt + A host name, IP address, IP network, or host netgroup (prefixed + with a '+'). The special value ALL will match any host. + + ssuuddooCCoommmmaanndd + A Unix command with optional command line arguments, potentially + including globbing characters (aka wild cards). The special value + ALL will match any command. If a command is prefixed with an + exclamation point '!', the user will be prohibited from running + that command. + + ssuuddooOOppttiioonn + Identical in function to the global options described above, but + specific to the sudoRole in which it resides. + + ssuuddooRRuunnAAssUUsseerr + A user name or uid (prefixed with '#') that commands may be run as + or a Unix group (prefixed with a '%') or user netgroup (prefixed + with a '+') that contains a list of users that commands may be run + as. The special value ALL will match any user. + + The sudoRunAsUser attribute is only available in 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. + + The sudoRunAsGroup attribute is only available in ssuuddoo versions + 1.7.0 and higher. + + ssuuddooNNoottBBeeffoorree + A timestamp in the form yyyymmddHHMMSSZ that can be used to provide + a start date/time for when the sudoRole will be valid. If multiple + sudoNotBefore entries are present, the earliest is used. Note that + timestamps must be in Coordinated Universal Time (UTC), not the + local timezone. The minute and seconds portions are optional, but + some LDAP servers require that they be present (contrary to the + RFC). + + 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 yyyymmddHHMMSSZ 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 minute and seconds + portions are optional, but some LDAP servers require that they be + present (contrary to the RFC). + + 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 + objectClass: sudoRole + cn: %wheel + sudoUser: %wheel + sudoHost: ALL + sudoCommand: ALL + + AAnnaattoommyy ooff LLDDAAPP ssuuddooeerrss llooookkuupp + When looking up a sudoer using LDAP there are only two or three LDAP + queries per invocation. The first query is to parse the global + options. The second is to match against the user's name and the groups + that the user belongs to. (The special ALL tag is matched in this + query too.) If no match is returned for the user's name and groups, a + third query returns all entries containing user netgroups and checks to + see if the user belongs to any of them. + + If timed entries are enabled with the 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. + + The order in which different entries are applied can be controlled + using the sudoOrder attribute, but there is no way to guarantee the + order of attributes within a specific entry. If there are conflicting + command rules in an entry, the negative takes precedence. This is + called paranoid behavior (not necessarily the most specific match). + + Here is an example: + + # /etc/sudoers: + # Allow all commands except shell + johnny ALL=(root) ALL,!/bin/sh + # Always allows all commands because ALL is matched last + puddles ALL=(root) !/bin/sh,ALL + + # LDAP equivalent of johnny + # Allows all commands except shell + dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com + objectClass: sudoRole + objectClass: top + cn: role1 + sudoUser: johnny + sudoHost: ALL + sudoCommand: ALL + sudoCommand: !/bin/sh + + # LDAP equivalent of puddles + # Notice that even though ALL comes last, it still behaves like + # role1 since the LDAP code assumes the more paranoid configuration + dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com + objectClass: sudoRole + objectClass: top + cn: role2 + sudoUser: puddles + sudoHost: ALL + sudoCommand: !/bin/sh + sudoCommand: ALL + + Another difference is that negations on the Host, User or Runas are + currently ignored. For example, the following attributes do not behave + the way one might expect. + + # does not match all but joe + # rather, does not match anyone + sudoUser: !joe + + # does not match all but joe + # rather, matches everyone including Joe + sudoUser: ALL + sudoUser: !joe + + # does not match all but web01 + # rather, matches all hosts including web01 + sudoHost: ALL + sudoHost: !web01 + + SSuuddooeerrss SScchheemmaa + In order to use ssuuddoo's LDAP support, the ssuuddoo schema must be installed + on your LDAP server. In addition, be sure to index the 'sudoUser' + attribute. + + Three versions of the schema: one for OpenLDAP servers + (_s_c_h_e_m_a_._O_p_e_n_L_D_A_P), one for Netscape-derived servers (_s_c_h_e_m_a_._i_P_l_a_n_e_t), + and one for Microsoft Active Directory (_s_c_h_e_m_a_._A_c_t_i_v_e_D_i_r_e_c_t_o_r_y) may be + found in the ssuuddoo distribution. + + The schema for ssuuddoo in OpenLDAP form is included in the EXAMPLES + section. + + CCoonnffiigguurriinngg llddaapp..ccoonnff + Sudo reads the _/_e_t_c_/_l_d_a_p_._c_o_n_f file for LDAP-specific configuration. + Typically, this file is shared amongst different LDAP-aware clients. + As such, most of the settings are not ssuuddoo-specific. Note that ssuuddoo + parses _/_e_t_c_/_l_d_a_p_._c_o_n_f itself and may support options that differ from + those described in the _l_d_a_p_._c_o_n_f(4) manual. + + Also note that on systems using the OpenLDAP libraries, default values + 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 as being + supported by ssuuddoo are honored. Configuration options are listed below + in upper case but are parsed in a case-independent manner. + + UURRII ldap[s]://[hostname[:port]] ... + Specifies a whitespace-delimited list of one or more URIs + describing the LDAP server(s) to connect to. The _p_r_o_t_o_c_o_l may be + 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. + + 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 + include an optional _p_o_r_t separated by a colon (':'). The HHOOSSTT + parameter is deprecated in favor of the UURRII specification and is + included for backwards compatibility. + + PPOORRTT port_number + If no UURRII is specified, the PPOORRTT parameter specifies the default + port to connect to on the LDAP server if a HHOOSSTT parameter does not + specify the port itself. If no PPOORRTT parameter is used, the default + is port 389 for LDAP and port 636 for LDAP over TLS (SSL). The + PPOORRTT parameter is deprecated in favor of the UURRII specification and + is included for backwards compatibility. + + BBIINNDD__TTIIMMEELLIIMMIITT seconds + The BBIINNDD__TTIIMMEELLIIMMIITT parameter specifies the amount of time, in + seconds, to wait while trying to connect to an LDAP server. If + 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. + + BBIINNDDPPWW secret + The BBIINNDDPPWW parameter specifies the password to use when performing + LDAP operations. This is typically used in conjunction with the + BBIINNDDDDNN parameter. + + RROOOOTTBBIINNDDDDNN DN + The RROOOOTTBBIINNDDDDNN parameter specifies the identity, in the form of a + Distinguished Name (DN), to use when performing privileged LDAP + operations, such as _s_u_d_o_e_r_s queries. The password corresponding to + the identity should be stored in _/_e_t_c_/_l_d_a_p_._s_e_c_r_e_t. If not + specified, the BBIINNDDDDNN identity is used (if any). + + LLDDAAPP__VVEERRSSIIOONN number + The version of the LDAP protocol to use when connecting to the + server. The default value is protocol version 3. + + SSSSLL on/true/yes/off/false/no + If the SSSSLL parameter is set to on, true or yes, TLS (SSL) + encryption is always used when communicating with the LDAP server. + Typically, this involves connecting to the server on port 636 + (ldaps). + + SSSSLL start_tls + If the SSSSLL parameter is set to start_tls, the LDAP server + connection is initiated normally and TLS encryption is begun before + the bind credentials are sent. This has the advantage of not + requiring a dedicated port for encrypted communications. This + parameter is only supported by LDAP servers that honor the + start_tls extension, such as the OpenLDAP server. + + TTLLSS__CCHHEECCKKPPEEEERR on/true/yes/off/false/no + If enabled, TTLLSS__CCHHEECCKKPPEEEERR will cause the LDAP server's TLS + certificated to be verified. If the server's TLS certificate + cannot be verified (usually because it is signed by an unknown + certificate authority), ssuuddoo will be unable to connect to it. If + TTLLSS__CCHHEECCKKPPEEEERR is disabled, no check is made. Note that disabling + the check creates an opportunity for man-in-the-middle attacks + since the server's identity will not be authenticated. If + possible, the CA's certificate should be installed locally so it + can be verified. + + TTLLSS__CCAACCEERRTT file name + 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 + 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 + OpenLDAP libraries. + + TTLLSS__CCEERRTT file name + The path to a file containing the client certificate which can be + used to authenticate the client to the LDAP server. The + certificate type depends on the LDAP libraries used. + + OpenLDAP: + tls_cert /etc/ssl/client_cert.pem + + Netscape-derived: + tls_cert /var/ldap/cert7.db + + When using Netscape-derived libraries, this file may also contain + Certificate Authority certificates. + + TTLLSS__KKEEYY file name + The path to a file containing the private key which matches the + certificate specified by TTLLSS__CCEERRTT. The private key must not be + password-protected. The key type depends on the LDAP libraries + used. + + OpenLDAP: + tls_key /etc/ssl/client_key.pem + + Netscape-derived: + tls_key /var/ldap/key3.db + + TTLLSS__RRAANNDDFFIILLEE file name + The TTLLSS__RRAANNDDFFIILLEE parameter specifies the path to an entropy source + for systems that lack a random device. It is generally used in + conjunction with _p_r_n_g_d or _e_g_d. This option is only supported by + the OpenLDAP libraries. + + TTLLSS__CCIIPPHHEERRSS cipher list + The TTLLSS__CCIIPPHHEERRSS parameter allows the administer to restrict which + encryption algorithms may be used for TLS (SSL) connections. See + the OpenSSL manual for a list of valid ciphers. This option is + only supported by the OpenLDAP libraries. + + 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. + + SSAASSLL__SSEECCPPRROOPPSS none/properties + SASL security properties or _n_o_n_e for no properties. See the SASL + programmer's manual for details. + + KKRRBB55__CCCCNNAAMMEE file name + The path to the Kerberos 5 credential cache to use when + authenticating with the remote server. + + DDEERREEFF never/searching/finding/always + How alias dereferencing is to be performed when searching. See the + _l_d_a_p_._c_o_n_f(4) manual for a full description of this option. + + See the ldap.conf entry in the EXAMPLES section. + + CCoonnffiigguurriinngg nnsssswwiittcchh..ccoonnff + Unless it is disabled at build time, ssuuddoo consults the Name Service + Switch file, _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f, to specify the _s_u_d_o_e_r_s search order. + Sudo looks for a line beginning with sudoers: and uses this to + determine the search order. Note that ssuuddoo does not stop searching + after the first match and later matches take precedence over earlier + ones. + + The following sources are recognized: + + files read sudoers from F + ldap read sudoers from LDAP + + In addition, the entry [NOTFOUND=return] will short-circuit the search + if the user was not found in the preceding source. + + To consult LDAP first followed by the local sudoers file (if it + exists), use: + + sudoers: ldap files + + The local _s_u_d_o_e_r_s file can be ignored completely by using: + + sudoers: ldap + + If the _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f file is not present or there is no sudoers + line, the following default is assumed: + + 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: + + sudoers = ldap, files + + The local _s_u_d_o_e_r_s file can be ignored completely by using: + + sudoers = ldap + + To treat LDAP as authoratative and only use the local sudoers file if + the user is not present in LDAP, use: + + sudoers = ldap = auth, files + + Note that in the above example, the auth qualfier only affects user + lookups; both LDAP and _s_u_d_o_e_r_s will be queried for Defaults entries. + + If the _/_e_t_c_/_n_e_t_s_v_c_._c_o_n_f file is not present or there is no sudoers + line, the following default is assumed: + + sudoers = files + +FFIILLEESS + _/_e_t_c_/_l_d_a_p_._c_o_n_f LDAP configuration file + + _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f determines sudoers source order + + _/_e_t_c_/_n_e_t_s_v_c_._c_o_n_f determines sudoers source order on AIX + +EEXXAAMMPPLLEESS + EExxaammppllee llddaapp..ccoonnff + # Either specify one or more URIs or one or more host:port pairs. + # If neither is specified sudo will default to localhost, port 389. + # + #host ldapserver + #host ldapserver1 ldapserver2:390 + # + # Default port if host is specified without one, defaults to 389. + #port 389 + # + # URI will override the host and port settings. + uri ldap://ldapserver + #uri ldaps://secureldapserver + #uri ldaps://secureldapserver ldap://ldapserver + # + # The amount of time, in seconds, to wait while trying to connect to + # an LDAP server. + bind_timelimit 30 + # + # The amount of time, in seconds, to wait while performing an LDAP query. + timelimit 30 + # + # Must be set or sudo will ignore LDAP; may be specified multiple times. + sudoers_base ou=SUDOers,dc=example,dc=com + # + # verbose sudoers matching from ldap + #sudoers_debug 2 + # + # Enable support for time-based entries in sudoers. + #sudoers_timed yes + # + # optional proxy credentials + #binddn + #bindpw + #rootbinddn + # + # LDAP protocol version, defaults to 3 + #ldap_version 3 + # + # Define if you want to use an encrypted LDAP connection. + # Typically, you must also set the port to 636 (ldaps). + #ssl on + # + # Define if you want to use port 389 and switch to + # encryption before the bind credentials are sent. + # Only supported by LDAP servers that support the start_tls + # extension such as OpenLDAP. + #ssl start_tls + # + # Additional TLS options follow that allow tweaking of the + # SSL/TLS connection. + # + #tls_checkpeer yes # verify server SSL certificate + #tls_checkpeer no # ignore server SSL certificate + # + # If you enable tls_checkpeer, specify either tls_cacertfile + # or tls_cacertdir. Only supported when using OpenLDAP. + # + #tls_cacertfile /etc/certs/trusted_signers.pem + #tls_cacertdir /etc/certs + # + # For systems that don't have /dev/random + # use this along with PRNGD or EGD.pl to seed the + # random number pool to generate cryptographic session keys. + # Only supported when using OpenLDAP. + # + #tls_randfile /etc/egd-pool + # + # You may restrict which ciphers are used. Consult your SSL + # documentation for which options go here. + # Only supported when using OpenLDAP. + # + #tls_ciphers + # + # Sudo can provide a client certificate when communicating to + # the LDAP server. + # Tips: + # * Enable both lines at the same time. + # * Do not password protect the key file. + # * Ensure the keyfile is only readable by root. + # + # For OpenLDAP: + #tls_cert /etc/certs/client_cert.pem + #tls_key /etc/certs/client_key.pem + # + # For SunONE or iPlanet LDAP, tls_cert and tls_key may specify either + # a directory, in which case the files in the directory must have the + # default names (e.g. cert8.db and key4.db), or the path to the cert + # and key files themselves. However, a bug in version 5.0 of the LDAP + # SDK will prevent specific file names from working. For this reason + # it is suggested that tls_cert and tls_key be set to a directory, + # not a file name. + # + # The certificate database specified by tls_cert may contain CA certs + # and/or the client's cert. If the client's cert is included, tls_key + # should be specified as well. + # For backward compatibility, "sslpath" may be used in place of tls_cert. + #tls_cert /var/ldap + #tls_key /var/ldap + # + # If using SASL authentication for LDAP (OpenSSL) + # use_sasl yes + # sasl_auth_id + # rootuse_sasl yes + # rootsasl_auth_id + # sasl_secprops none + # krb5_ccname /etc/.ldapcache + + SSuuddoo sscchheemmaa ffoorr OOppeennLLDDAAPP + 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. + + attributetype ( 1.3.6.1.4.1.15953.9.1.1 + NAME 'sudoUser' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.8 + NAME 'sudoNotBefore' + DESC 'Start of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.9 + NAME 'sudoNotAfter' + DESC 'End of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + + attributeTypes ( 1.3.6.1.4.1.15953.9.1.10 + NAME 'sudoOrder' + DESC 'an integer to order the sudoRole entries' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + + objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ + sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $ + sudoOrder $ description ) + ) + +SSEEEE AALLSSOO + _l_d_a_p_._c_o_n_f(4), _s_u_d_o_e_r_s(4) + +CCAAVVEEAATTSS + 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 + http://www.sudo.ws/sudo/bugs/ + +SSUUPPPPOORRTT + Limited free support is available via the sudo-users mailing list, see + http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search + the archives. + +DDIISSCCLLAAIIMMEERR + ssuuddoo is provided ``AS IS'' and any express or implied warranties, + including, but not limited to, the implied warranties of + merchantability and fitness for a particular purpose are disclaimed. + See the LICENSE file distributed with ssuuddoo or + http://www.sudo.ws/sudo/license.html for complete details. + + + +1.8.5 March 14, 2012 SUDOERS.LDAP(4) diff --git a/doc/sudoers.ldap.man.in b/doc/sudoers.ldap.man.in new file mode 100644 index 0000000..7ec639e --- /dev/null +++ b/doc/sudoers.ldap.man.in @@ -0,0 +1,925 @@ +.\" Copyright (c) 2003-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. +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SUDOERS.LDAP @mansectform@" +.TH SUDOERS.LDAP @mansectform@ "March 14, 2012" "1.8.5" "MAINTENANCE COMMANDS" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +sudoers.ldap \- sudo LDAP configuration +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +In addition to the standard \fIsudoers\fR file, \fBsudo\fR may be configured +via \s-1LDAP\s0. This can be especially useful for synchronizing \fIsudoers\fR +in a large, distributed environment. +.PP +Using \s-1LDAP\s0 for \fIsudoers\fR has several benefits: +.IP "\(bu" 4 +\&\fBsudo\fR no longer needs to read \fIsudoers\fR in its entirety. When +\&\s-1LDAP\s0 is used, there are only two or three \s-1LDAP\s0 queries per invocation. +This makes it especially fast and particularly usable in \s-1LDAP\s0 +environments. +.IP "\(bu" 4 +\&\fBsudo\fR no longer exits if there is a typo in \fIsudoers\fR. +It is not possible to load \s-1LDAP\s0 data into the server that does +not conform to the sudoers schema, so proper syntax is guaranteed. +It is still possible to have typos in a user or host name, but +this will not prevent \fBsudo\fR from running. +.IP "\(bu" 4 +It is possible to specify per-entry options that override the global +default options. \fI@sysconfdir@/sudoers\fR only supports default options and +limited options associated with user/host/commands/aliases. The +syntax is complicated and can be difficult for users to understand. +Placing the options directly in the entry is more natural. +.IP "\(bu" 4 +The \fBvisudo\fR program is no longer needed. \fBvisudo\fR provides +locking and syntax checking of the \fI@sysconfdir@/sudoers\fR file. +Since \s-1LDAP\s0 updates are atomic, locking is no longer necessary. +Because syntax is checked when the data is inserted into \s-1LDAP\s0, there +is no need for a specialized tool to check syntax. +.PP +Another major difference between \s-1LDAP\s0 and file-based \fIsudoers\fR +is that in \s-1LDAP\s0, \fBsudo\fR\-specific Aliases are not supported. +.PP +For the most part, there is really no need for \fBsudo\fR\-specific +Aliases. Unix groups or user netgroups can be used in place of +User_Aliases and Runas_Aliases. Host netgroups can be used in place +of Host_Aliases. Since Unix groups and netgroups can also be stored +in \s-1LDAP\s0 there is no real need for \fBsudo\fR\-specific aliases. +.PP +Cmnd_Aliases are not really required either since it is possible +to have multiple users listed in a \f(CW\*(C`sudoRole\*(C'\fR. Instead of defining +a Cmnd_Alias that is referenced by multiple users, one can create +a \f(CW\*(C`sudoRole\*(C'\fR that contains the commands and assign multiple users +to it. +.SS "SUDOers \s-1LDAP\s0 container" +.IX Subsection "SUDOers LDAP container" +The \fIsudoers\fR configuration is contained in the \f(CW\*(C`ou=SUDOers\*(C'\fR \s-1LDAP\s0 +container. +.PP +Sudo first looks for the \f(CW\*(C`cn=default\*(C'\fR entry in the SUDOers container. +If found, the multi-valued \f(CW\*(C`sudoOption\*(C'\fR attribute is parsed in the +same manner as a global \f(CW\*(C`Defaults\*(C'\fR line in \fI@sysconfdir@/sudoers\fR. In +the following example, the \f(CW\*(C`SSH_AUTH_SOCK\*(C'\fR variable will be preserved +in the environment for all users. +.PP +.Vb 6 +\& dn: cn=defaults,ou=SUDOers,dc=example,dc=com +\& objectClass: top +\& objectClass: sudoRole +\& cn: defaults +\& description: Default sudoOption\*(Aqs go here +\& sudoOption: env_keep+=SSH_AUTH_SOCK +.Ve +.PP +The equivalent of a sudoer in \s-1LDAP\s0 is a \f(CW\*(C`sudoRole\*(C'\fR. It consists of +the following attributes: +.IP "\fBsudoUser\fR" 4 +.IX Item "sudoUser" +A user name, user \s-1ID\s0 (prefixed with \f(CW\*(Aq#\*(Aq\fR), Unix group (prefixed with +\&\f(CW\*(Aq%\*(Aq\fR), Unix group \s-1ID\s0 (prefixed with \f(CW\*(Aq%#\*(Aq\fR), or user netgroup +(prefixed with \f(CW\*(Aq+\*(Aq\fR). +.IP "\fBsudoHost\fR" 4 +.IX Item "sudoHost" +A host name, \s-1IP\s0 address, \s-1IP\s0 network, or host netgroup (prefixed +with a \f(CW\*(Aq+\*(Aq\fR). +The special value \f(CW\*(C`ALL\*(C'\fR will match any host. +.IP "\fBsudoCommand\fR" 4 +.IX Item "sudoCommand" +A Unix command with optional command line arguments, potentially +including globbing characters (aka wild cards). +The special value \f(CW\*(C`ALL\*(C'\fR will match any command. +If a command is prefixed with an exclamation point \f(CW\*(Aq!\*(Aq\fR, the +user will be prohibited from running that command. +.IP "\fBsudoOption\fR" 4 +.IX Item "sudoOption" +Identical in function to the global options described above, but +specific to the \f(CW\*(C`sudoRole\*(C'\fR in which it resides. +.IP "\fBsudoRunAsUser\fR" 4 +.IX Item "sudoRunAsUser" +A user name or uid (prefixed with \f(CW\*(Aq#\*(Aq\fR) that commands may be run +as or a Unix group (prefixed with a \f(CW\*(Aq%\*(Aq\fR) or user netgroup (prefixed +with a \f(CW\*(Aq+\*(Aq\fR) that contains a list of users that commands may be +run as. +The special value \f(CW\*(C`ALL\*(C'\fR will match any user. +.Sp +The \f(CW\*(C`sudoRunAsUser\*(C'\fR attribute is only available in \fBsudo\fR versions +1.7.0 and higher. Older versions of \fBsudo\fR use the \f(CW\*(C`sudoRunAs\*(C'\fR +attribute instead. +.IP "\fBsudoRunAsGroup\fR" 4 +.IX Item "sudoRunAsGroup" +A Unix group or gid (prefixed with \f(CW\*(Aq#\*(Aq\fR) that commands may be run as. +The special value \f(CW\*(C`ALL\*(C'\fR will match any group. +.Sp +The \f(CW\*(C`sudoRunAsGroup\*(C'\fR attribute is only available in \fBsudo\fR versions +1.7.0 and higher. +.IP "\fBsudoNotBefore\fR" 4 +.IX Item "sudoNotBefore" +A timestamp in the form \f(CW\*(C`yyyymmddHHMMSSZ\*(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. The minute and seconds portions are optional, +but some \s-1LDAP\s0 servers require that they be present (contrary to the \s-1RFC\s0). +.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`yyyymmddHHMMSSZ\*(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. The minute and seconds portions are optional, +but some \s-1LDAP\s0 servers require that they be present (contrary to the \s-1RFC\s0). +.Sp +The \f(CW\*(C`sudoNotAfter\*(C'\fR attribute is only available in \fBsudo\fR versions +1.7.5 and higher and must be explicitly enabled via the \fB\s-1SUDOERS_TIMED\s0\fR +option in \fI@ldap_conf@\fR. +.IP "\fBsudoOrder\fR" 4 +.IX Item "sudoOrder" +The \f(CW\*(C`sudoRole\*(C'\fR entries retrieved from the \s-1LDAP\s0 directory have no +inherent order. The \f(CW\*(C`sudoOrder\*(C'\fR attribute is an integer (or +floating point value for \s-1LDAP\s0 servers that support it) that is used +to sort the matching entries. This allows LDAP-based sudoers entries +to more closely mimic the behaviour of the sudoers file, where the +of the entries influences the result. If multiple entries match, +the entry with the highest \f(CW\*(C`sudoOrder\*(C'\fR attribute is chosen. This +corresponds to the \*(L"last match\*(R" behavior of the sudoers file. If +the \f(CW\*(C`sudoOrder\*(C'\fR attribute is not present, a value of 0 is assumed. +.Sp +The \f(CW\*(C`sudoOrder\*(C'\fR attribute is only available in \fBsudo\fR versions +1.7.5 and higher. +.PP +Each attribute listed above should contain a single value, but there +may be multiple instances of each attribute type. A \f(CW\*(C`sudoRole\*(C'\fR must +contain at least one \f(CW\*(C`sudoUser\*(C'\fR, \f(CW\*(C`sudoHost\*(C'\fR and \f(CW\*(C`sudoCommand\*(C'\fR. +.PP +The following example allows users in group wheel to run any command +on any host via \fBsudo\fR: +.PP +.Vb 7 +\& dn: cn=%wheel,ou=SUDOers,dc=example,dc=com +\& objectClass: top +\& objectClass: sudoRole +\& cn: %wheel +\& sudoUser: %wheel +\& sudoHost: ALL +\& sudoCommand: ALL +.Ve +.SS "Anatomy of \s-1LDAP\s0 sudoers lookup" +.IX Subsection "Anatomy of LDAP sudoers lookup" +When looking up a sudoer using \s-1LDAP\s0 there are only two or three +\&\s-1LDAP\s0 queries per invocation. The first query is to parse the global +options. The second is to match against the user's name and the +groups that the user belongs to. (The special \s-1ALL\s0 tag is matched +in this query too.) If no match is returned for the user's name +and groups, a third query returns all entries containing user +netgroups and checks to see if the user belongs to any of them. +.PP +If timed entries are enabled with the \fB\s-1SUDOERS_TIMED\s0\fR configuration +directive, the \s-1LDAP\s0 queries include a subfilter that limits retrieval +to entries that satisfy the time constraints, if any. +.SS "Differences between \s-1LDAP\s0 and non-LDAP sudoers" +.IX Subsection "Differences between LDAP and non-LDAP sudoers" +There are some subtle differences in the way sudoers is handled +once in \s-1LDAP\s0. Probably the biggest is that according to the \s-1RFC\s0, +\&\s-1LDAP\s0 ordering is arbitrary and you cannot expect that Attributes +and Entries are returned in any specific order. +.PP +The order in which different entries are applied can be controlled +using the \f(CW\*(C`sudoOrder\*(C'\fR attribute, but there is no way to guarantee +the order of attributes within a specific entry. If there are +conflicting command rules in an entry, the negative takes precedence. +This is called paranoid behavior (not necessarily the most specific +match). +.PP +Here is an example: +.PP +.Vb 5 +\& # /etc/sudoers: +\& # Allow all commands except shell +\& johnny ALL=(root) ALL,!/bin/sh +\& # Always allows all commands because ALL is matched last +\& puddles ALL=(root) !/bin/sh,ALL +\& +\& # LDAP equivalent of johnny +\& # Allows all commands except shell +\& dn: cn=role1,ou=Sudoers,dc=my\-domain,dc=com +\& objectClass: sudoRole +\& objectClass: top +\& cn: role1 +\& sudoUser: johnny +\& sudoHost: ALL +\& sudoCommand: ALL +\& sudoCommand: !/bin/sh +\& +\& # LDAP equivalent of puddles +\& # Notice that even though ALL comes last, it still behaves like +\& # role1 since the LDAP code assumes the more paranoid configuration +\& dn: cn=role2,ou=Sudoers,dc=my\-domain,dc=com +\& objectClass: sudoRole +\& objectClass: top +\& cn: role2 +\& sudoUser: puddles +\& sudoHost: ALL +\& sudoCommand: !/bin/sh +\& sudoCommand: ALL +.Ve +.PP +Another difference is that negations on the Host, User or Runas are +currently ignored. For example, the following attributes do not +behave the way one might expect. +.PP +.Vb 3 +\& # does not match all but joe +\& # rather, does not match anyone +\& sudoUser: !joe +\& +\& # does not match all but joe +\& # rather, matches everyone including Joe +\& sudoUser: ALL +\& sudoUser: !joe +\& +\& # does not match all but web01 +\& # rather, matches all hosts including web01 +\& sudoHost: ALL +\& sudoHost: !web01 +.Ve +.SS "Sudoers Schema" +.IX Subsection "Sudoers Schema" +In order to use \fBsudo\fR's \s-1LDAP\s0 support, the \fBsudo\fR schema must be +installed on your \s-1LDAP\s0 server. In addition, be sure to index the +\&'sudoUser' attribute. +.PP +Three versions of the schema: one for OpenLDAP servers (\fIschema.OpenLDAP\fR), +one for Netscape-derived servers (\fIschema.iPlanet\fR), and one for +Microsoft Active Directory (\fIschema.ActiveDirectory\fR) may +be found in the \fBsudo\fR distribution. +.PP +The schema for \fBsudo\fR in OpenLDAP form is included in the \s-1EXAMPLES\s0 +section. +.SS "Configuring ldap.conf" +.IX Subsection "Configuring ldap.conf" +Sudo reads the \fI@ldap_conf@\fR file for LDAP-specific configuration. +Typically, this file is shared amongst different LDAP-aware clients. +As such, most of the settings are not \fBsudo\fR\-specific. Note that +\&\fBsudo\fR parses \fI@ldap_conf@\fR itself and may support options +that differ from those described in the \fIldap.conf\fR\|(@mansectform@) manual. +.PP +Also note that on systems using the OpenLDAP libraries, default +values specified in \fI/etc/openldap/ldap.conf\fR or the user's +\&\fI.ldaprc\fR files are not used. +.PP +Only those options explicitly listed in \fI@ldap_conf@\fR as being +supported by \fBsudo\fR are honored. Configuration options are listed +below in upper case but are parsed in a case-independent manner. +.IP "\fB\s-1URI\s0\fR ldap[s]://[hostname[:port]] ..." 4 +.IX Item "URI ldap[s]://[hostname[:port]] ..." +Specifies a whitespace-delimited list of one or more URIs describing +the \s-1LDAP\s0 server(s) to connect to. The \fIprotocol\fR may be either +\&\fBldap\fR or \fBldaps\fR, the latter being for servers that support \s-1TLS\s0 +(\s-1SSL\s0) encryption. If no \fIport\fR is specified, the default is port +389 for \f(CW\*(C`ldap://\*(C'\fR or port 636 for \f(CW\*(C`ldaps://\*(C'\fR. If no \fIhostname\fR +is specified, \fBsudo\fR will connect to \fBlocalhost\fR. Multiple \fB\s-1URI\s0\fR +lines are treated identically to a \fB\s-1URI\s0\fR line containing multiple +entries. Only systems using the OpenSSL libraries support the +mixing of \f(CW\*(C`ldap://\*(C'\fR and \f(CW\*(C`ldaps://\*(C'\fR URIs. The Netscape-derived +libraries used on most commercial versions of Unix are only capable +of supporting one or the other. +.IP "\fB\s-1HOST\s0\fR name[:port] ..." 4 +.IX Item "HOST name[:port] ..." +If no \fB\s-1URI\s0\fR is specified, the \fB\s-1HOST\s0\fR parameter specifies a +whitespace-delimited list of \s-1LDAP\s0 servers to connect to. Each host +may include an optional \fIport\fR separated by a colon (':'). The +\&\fB\s-1HOST\s0\fR parameter is deprecated in favor of the \fB\s-1URI\s0\fR specification +and is included for backwards compatibility. +.IP "\fB\s-1PORT\s0\fR port_number" 4 +.IX Item "PORT port_number" +If no \fB\s-1URI\s0\fR is specified, the \fB\s-1PORT\s0\fR parameter specifies the +default port to connect to on the \s-1LDAP\s0 server if a \fB\s-1HOST\s0\fR parameter +does not specify the port itself. If no \fB\s-1PORT\s0\fR parameter is used, +the default is port 389 for \s-1LDAP\s0 and port 636 for \s-1LDAP\s0 over \s-1TLS\s0 +(\s-1SSL\s0). The \fB\s-1PORT\s0\fR parameter is deprecated in favor of the \fB\s-1URI\s0\fR +specification and is included for backwards compatibility. +.IP "\fB\s-1BIND_TIMELIMIT\s0\fR seconds" 4 +.IX Item "BIND_TIMELIMIT seconds" +The \fB\s-1BIND_TIMELIMIT\s0\fR parameter specifies the amount of time, in seconds, +to wait while trying to connect to an \s-1LDAP\s0 server. If multiple \fB\s-1URI\s0\fRs or +\&\fB\s-1HOST\s0\fRs are specified, this is the amount of time to wait before trying +the next one in the list. +.IP "\fB\s-1NETWORK_TIMEOUT\s0\fR seconds" 4 +.IX Item "NETWORK_TIMEOUT seconds" +An alias for \fB\s-1BIND_TIMELIMIT\s0\fR for OpenLDAP compatibility. +.IP "\fB\s-1TIMELIMIT\s0\fR seconds" 4 +.IX Item "TIMELIMIT seconds" +The \fB\s-1TIMELIMIT\s0\fR parameter specifies the amount of time, in seconds, +to wait for a response to an \s-1LDAP\s0 query. +.IP "\fB\s-1TIMEOUT\s0\fR seconds" 4 +.IX Item "TIMEOUT seconds" +The \fB\s-1TIMEOUT\s0\fR parameter specifies the amount of time, in seconds, +to wait for a response from the various \s-1LDAP\s0 APIs. +.IP "\fB\s-1SUDOERS_BASE\s0\fR base" 4 +.IX Item "SUDOERS_BASE base" +The base \s-1DN\s0 to use when performing \fBsudo\fR \s-1LDAP\s0 queries. Typically +this is of the form \f(CW\*(C`ou=SUDOers,dc=example,dc=com\*(C'\fR for the domain +\&\f(CW\*(C`example.com\*(C'\fR. Multiple \fB\s-1SUDOERS_BASE\s0\fR lines may be specified, +in which case they are queried in the order specified. +.IP "\fB\s-1SUDOERS_SEARCH_FILTER\s0\fR ldap_filter" 4 +.IX Item "SUDOERS_SEARCH_FILTER ldap_filter" +An \s-1LDAP\s0 filter which is used to restrict the set of records returned +when performing a \fBsudo\fR \s-1LDAP\s0 query. Typically, this is of the +form \f(CW\*(C`attribute=value\*(C'\fR or \f(CW\*(C`(&(attribute=value)(attribute2=value2))\*(C'\fR. +.IP "\fB\s-1SUDOERS_TIMED\s0\fR on/true/yes/off/false/no" 4 +.IX Item "SUDOERS_TIMED on/true/yes/off/false/no" +Whether or not to evaluate the \f(CW\*(C`sudoNotBefore\*(C'\fR and \f(CW\*(C`sudoNotAfter\*(C'\fR +attributes that implement time-dependent sudoers entries. +.IP "\fB\s-1SUDOERS_DEBUG\s0\fR debug_level" 4 +.IX Item "SUDOERS_DEBUG debug_level" +This sets the debug level for \fBsudo\fR \s-1LDAP\s0 queries. Debugging +information is printed to the standard error. A value of 1 results +in a moderate amount of debugging information. A value of 2 shows +the results of the matches themselves. This parameter should not +be set in a production environment as the extra information is +likely to confuse users. +.IP "\fB\s-1BINDDN\s0\fR \s-1DN\s0" 4 +.IX Item "BINDDN DN" +The \fB\s-1BINDDN\s0\fR parameter specifies the identity, in the form of a +Distinguished Name (\s-1DN\s0), to use when performing \s-1LDAP\s0 operations. +If not specified, \s-1LDAP\s0 operations are performed with an anonymous +identity. By default, most \s-1LDAP\s0 servers will allow anonymous access. +.IP "\fB\s-1BINDPW\s0\fR secret" 4 +.IX Item "BINDPW secret" +The \fB\s-1BINDPW\s0\fR parameter specifies the password to use when performing +\&\s-1LDAP\s0 operations. This is typically used in conjunction with the +\&\fB\s-1BINDDN\s0\fR parameter. +.IP "\fB\s-1ROOTBINDDN\s0\fR \s-1DN\s0" 4 +.IX Item "ROOTBINDDN DN" +The \fB\s-1ROOTBINDDN\s0\fR parameter specifies the identity, in the form of +a Distinguished Name (\s-1DN\s0), to use when performing privileged \s-1LDAP\s0 +operations, such as \fIsudoers\fR queries. The password corresponding +to the identity should be stored in \fI@ldap_secret@\fR. +If not specified, the \fB\s-1BINDDN\s0\fR identity is used (if any). +.IP "\fB\s-1LDAP_VERSION\s0\fR number" 4 +.IX Item "LDAP_VERSION number" +The version of the \s-1LDAP\s0 protocol to use when connecting to the server. +The default value is protocol version 3. +.IP "\fB\s-1SSL\s0\fR on/true/yes/off/false/no" 4 +.IX Item "SSL on/true/yes/off/false/no" +If the \fB\s-1SSL\s0\fR parameter is set to \f(CW\*(C`on\*(C'\fR, \f(CW\*(C`true\*(C'\fR or \f(CW\*(C`yes\*(C'\fR, \s-1TLS\s0 +(\s-1SSL\s0) encryption is always used when communicating with the \s-1LDAP\s0 +server. Typically, this involves connecting to the server on port +636 (ldaps). +.IP "\fB\s-1SSL\s0\fR start_tls" 4 +.IX Item "SSL start_tls" +If the \fB\s-1SSL\s0\fR parameter is set to \f(CW\*(C`start_tls\*(C'\fR, the \s-1LDAP\s0 server +connection is initiated normally and \s-1TLS\s0 encryption is begun before +the bind credentials are sent. This has the advantage of not +requiring a dedicated port for encrypted communications. This +parameter is only supported by \s-1LDAP\s0 servers that honor the \f(CW\*(C`start_tls\*(C'\fR +extension, such as the OpenLDAP server. +.IP "\fB\s-1TLS_CHECKPEER\s0\fR on/true/yes/off/false/no" 4 +.IX Item "TLS_CHECKPEER on/true/yes/off/false/no" +If enabled, \fB\s-1TLS_CHECKPEER\s0\fR will cause the \s-1LDAP\s0 server's \s-1TLS\s0 +certificated to be verified. If the server's \s-1TLS\s0 certificate cannot +be verified (usually because it is signed by an unknown certificate +authority), \fBsudo\fR will be unable to connect to it. If \fB\s-1TLS_CHECKPEER\s0\fR +is disabled, no check is made. Note that disabling the check creates +an opportunity for man-in-the-middle attacks since the server's +identity will not be authenticated. If possible, the \s-1CA\s0's certificate +should be installed locally so it can be verified. +.IP "\fB\s-1TLS_CACERT\s0\fR file name" 4 +.IX Item "TLS_CACERT file name" +An alias for \fB\s-1TLS_CACERTFILE\s0\fR for OpenLDAP compatibility. +.IP "\fB\s-1TLS_CACERTFILE\s0\fR file name" 4 +.IX Item "TLS_CACERTFILE file name" +The path to a certificate authority bundle which contains the certificates +for all the Certificate Authorities the client knows to be valid, +e.g. \fI/etc/ssl/ca\-bundle.pem\fR. +This option is only supported by the OpenLDAP libraries. +Netscape-derived \s-1LDAP\s0 libraries use the same certificate +database for \s-1CA\s0 and client certificates (see \fB\s-1TLS_CERT\s0\fR). +.IP "\fB\s-1TLS_CACERTDIR\s0\fR directory" 4 +.IX Item "TLS_CACERTDIR directory" +Similar to \fB\s-1TLS_CACERTFILE\s0\fR but instead of a file, it is a +directory containing individual Certificate Authority certificates, +e.g. \fI/etc/ssl/certs\fR. +The directory specified by \fB\s-1TLS_CACERTDIR\s0\fR is checked after +\&\fB\s-1TLS_CACERTFILE\s0\fR. +This option is only supported by the OpenLDAP libraries. +.IP "\fB\s-1TLS_CERT\s0\fR file name" 4 +.IX Item "TLS_CERT file name" +The path to a file containing the client certificate which can +be used to authenticate the client to the \s-1LDAP\s0 server. +The certificate type depends on the \s-1LDAP\s0 libraries used. +.Sp +OpenLDAP: + \f(CW\*(C`tls_cert /etc/ssl/client_cert.pem\*(C'\fR +.Sp +Netscape-derived: + \f(CW\*(C`tls_cert /var/ldap/cert7.db\*(C'\fR +.Sp +When using Netscape-derived libraries, this file may also contain +Certificate Authority certificates. +.IP "\fB\s-1TLS_KEY\s0\fR file name" 4 +.IX Item "TLS_KEY file name" +The path to a file containing the private key which matches the +certificate specified by \fB\s-1TLS_CERT\s0\fR. The private key must not be +password-protected. The key type depends on the \s-1LDAP\s0 libraries +used. +.Sp +OpenLDAP: + \f(CW\*(C`tls_key /etc/ssl/client_key.pem\*(C'\fR +.Sp +Netscape-derived: + \f(CW\*(C`tls_key /var/ldap/key3.db\*(C'\fR +.IP "\fB\s-1TLS_RANDFILE\s0\fR file name" 4 +.IX Item "TLS_RANDFILE file name" +The \fB\s-1TLS_RANDFILE\s0\fR parameter specifies the path to an entropy +source for systems that lack a random device. It is generally used +in conjunction with \fIprngd\fR or \fIegd\fR. +This option is only supported by the OpenLDAP libraries. +.IP "\fB\s-1TLS_CIPHERS\s0\fR cipher list" 4 +.IX Item "TLS_CIPHERS cipher list" +The \fB\s-1TLS_CIPHERS\s0\fR parameter allows the administer to restrict +which encryption algorithms may be used for \s-1TLS\s0 (\s-1SSL\s0) connections. +See the OpenSSL manual for a list of valid ciphers. +This option is only supported by the OpenLDAP libraries. +.IP "\fB\s-1USE_SASL\s0\fR on/true/yes/off/false/no" 4 +.IX Item "USE_SASL on/true/yes/off/false/no" +Enable \fB\s-1USE_SASL\s0\fR for \s-1LDAP\s0 servers that support \s-1SASL\s0 authentication. +.IP "\fB\s-1SASL_AUTH_ID\s0\fR identity" 4 +.IX Item "SASL_AUTH_ID identity" +The \s-1SASL\s0 user name to use when connecting to the \s-1LDAP\s0 server. +By default, \fBsudo\fR will use an anonymous connection. +.IP "\fB\s-1ROOTUSE_SASL\s0\fR on/true/yes/off/false/no" 4 +.IX Item "ROOTUSE_SASL on/true/yes/off/false/no" +Enable \fB\s-1ROOTUSE_SASL\s0\fR to enable \s-1SASL\s0 authentication when connecting +to an \s-1LDAP\s0 server from a privileged process, such as \fBsudo\fR. +.IP "\fB\s-1ROOTSASL_AUTH_ID\s0\fR identity" 4 +.IX Item "ROOTSASL_AUTH_ID identity" +The \s-1SASL\s0 user name to use when \fB\s-1ROOTUSE_SASL\s0\fR is enabled. +.IP "\fB\s-1SASL_SECPROPS\s0\fR none/properties" 4 +.IX Item "SASL_SECPROPS none/properties" +\&\s-1SASL\s0 security properties or \fInone\fR for no properties. See the +\&\s-1SASL\s0 programmer's manual for details. +.IP "\fB\s-1KRB5_CCNAME\s0\fR file name" 4 +.IX Item "KRB5_CCNAME file name" +The path to the Kerberos 5 credential cache to use when authenticating +with the remote server. +.IP "\fB\s-1DEREF\s0\fR never/searching/finding/always" 4 +.IX Item "DEREF never/searching/finding/always" +How alias dereferencing is to be performed when searching. See the +\&\fIldap.conf\fR\|(@mansectform@) manual for a full description of this option. +.PP +See the \f(CW\*(C`ldap.conf\*(C'\fR entry in the \s-1EXAMPLES\s0 section. +.SS "Configuring nsswitch.conf" +.IX Subsection "Configuring nsswitch.conf" +Unless it is disabled at build time, \fBsudo\fR consults the Name +Service Switch file, \fI@nsswitch_conf@\fR, to specify the \fIsudoers\fR +search order. Sudo looks for a line beginning with \f(CW\*(C`sudoers\*(C'\fR: and +uses this to determine the search order. Note that \fBsudo\fR does +not stop searching after the first match and later matches take +precedence over earlier ones. +.PP +The following sources are recognized: +.PP +.Vb 2 +\& files read sudoers from F<@sysconfdir@/sudoers> +\& ldap read sudoers from LDAP +.Ve +.PP +In addition, the entry \f(CW\*(C`[NOTFOUND=return]\*(C'\fR will short-circuit the +search if the user was not found in the preceding source. +.PP +To consult \s-1LDAP\s0 first followed by the local sudoers file (if it +exists), use: +.PP +.Vb 1 +\& sudoers: ldap files +.Ve +.PP +The local \fIsudoers\fR file can be ignored completely by using: +.PP +.Vb 1 +\& sudoers: ldap +.Ve +.PP +If the \fI@nsswitch_conf@\fR file is not present or there is no +sudoers line, the following default is assumed: +.PP +.Vb 1 +\& sudoers: files +.Ve +.PP +Note that \fI@nsswitch_conf@\fR is supported even when the underlying +operating system does not use an nsswitch.conf file. +.SS "Configuring netsvc.conf" +.IX Subsection "Configuring netsvc.conf" +On \s-1AIX\s0 systems, the \fI@netsvc_conf@\fR file is consulted instead of +\&\fI@nsswitch_conf@\fR. \fBsudo\fR simply treats \fInetsvc.conf\fR as a +variant of \fInsswitch.conf\fR; information in the previous section +unrelated to the file format itself still applies. +.PP +To consult \s-1LDAP\s0 first followed by the local sudoers file (if it +exists), use: +.PP +.Vb 1 +\& sudoers = ldap, files +.Ve +.PP +The local \fIsudoers\fR file can be ignored completely by using: +.PP +.Vb 1 +\& sudoers = ldap +.Ve +.PP +To treat \s-1LDAP\s0 as authoratative and only use the local sudoers file +if the user is not present in \s-1LDAP\s0, use: +.PP +.Vb 1 +\& sudoers = ldap = auth, files +.Ve +.PP +Note that in the above example, the \f(CW\*(C`auth\*(C'\fR qualfier only affects +user lookups; both \s-1LDAP\s0 and \fIsudoers\fR will be queried for \f(CW\*(C`Defaults\*(C'\fR +entries. +.PP +If the \fI@netsvc_conf@\fR file is not present or there is no +sudoers line, the following default is assumed: +.PP +.Vb 1 +\& sudoers = files +.Ve +.SH "FILES" +.IX Header "FILES" +.ie n .IP "\fI@ldap_conf@\fR" 24 +.el .IP "\fI@ldap_conf@\fR" 24 +.IX Item "@ldap_conf@" +\&\s-1LDAP\s0 configuration file +.ie n .IP "\fI@nsswitch_conf@\fR" 24 +.el .IP "\fI@nsswitch_conf@\fR" 24 +.IX Item "@nsswitch_conf@" +determines sudoers source order +.ie n .IP "\fI@netsvc_conf@\fR" 24 +.el .IP "\fI@netsvc_conf@\fR" 24 +.IX Item "@netsvc_conf@" +determines sudoers source order on \s-1AIX\s0 +.SH "EXAMPLES" +.IX Header "EXAMPLES" +.SS "Example ldap.conf" +.IX Subsection "Example ldap.conf" +.Vb 10 +\& # Either specify one or more URIs or one or more host:port pairs. +\& # If neither is specified sudo will default to localhost, port 389. +\& # +\& #host ldapserver +\& #host ldapserver1 ldapserver2:390 +\& # +\& # Default port if host is specified without one, defaults to 389. +\& #port 389 +\& # +\& # URI will override the host and port settings. +\& uri ldap://ldapserver +\& #uri ldaps://secureldapserver +\& #uri ldaps://secureldapserver ldap://ldapserver +\& # +\& # The amount of time, in seconds, to wait while trying to connect to +\& # an LDAP server. +\& bind_timelimit 30 +\& # +\& # The amount of time, in seconds, to wait while performing an LDAP query. +\& timelimit 30 +\& # +\& # Must be set or sudo will ignore LDAP; may be specified multiple times. +\& sudoers_base ou=SUDOers,dc=example,dc=com +\& # +\& # verbose sudoers matching from ldap +\& #sudoers_debug 2 +\& # +\& # Enable support for time\-based entries in sudoers. +\& #sudoers_timed yes +\& # +\& # optional proxy credentials +\& #binddn +\& #bindpw +\& #rootbinddn +\& # +\& # LDAP protocol version, defaults to 3 +\& #ldap_version 3 +\& # +\& # Define if you want to use an encrypted LDAP connection. +\& # Typically, you must also set the port to 636 (ldaps). +\& #ssl on +\& # +\& # Define if you want to use port 389 and switch to +\& # encryption before the bind credentials are sent. +\& # Only supported by LDAP servers that support the start_tls +\& # extension such as OpenLDAP. +\& #ssl start_tls +\& # +\& # Additional TLS options follow that allow tweaking of the +\& # SSL/TLS connection. +\& # +\& #tls_checkpeer yes # verify server SSL certificate +\& #tls_checkpeer no # ignore server SSL certificate +\& # +\& # If you enable tls_checkpeer, specify either tls_cacertfile +\& # or tls_cacertdir. Only supported when using OpenLDAP. +\& # +\& #tls_cacertfile /etc/certs/trusted_signers.pem +\& #tls_cacertdir /etc/certs +\& # +\& # For systems that don\*(Aqt have /dev/random +\& # use this along with PRNGD or EGD.pl to seed the +\& # random number pool to generate cryptographic session keys. +\& # Only supported when using OpenLDAP. +\& # +\& #tls_randfile /etc/egd\-pool +\& # +\& # You may restrict which ciphers are used. Consult your SSL +\& # documentation for which options go here. +\& # Only supported when using OpenLDAP. +\& # +\& #tls_ciphers +\& # +\& # Sudo can provide a client certificate when communicating to +\& # the LDAP server. +\& # Tips: +\& # * Enable both lines at the same time. +\& # * Do not password protect the key file. +\& # * Ensure the keyfile is only readable by root. +\& # +\& # For OpenLDAP: +\& #tls_cert /etc/certs/client_cert.pem +\& #tls_key /etc/certs/client_key.pem +\& # +\& # For SunONE or iPlanet LDAP, tls_cert and tls_key may specify either +\& # a directory, in which case the files in the directory must have the +\& # default names (e.g. cert8.db and key4.db), or the path to the cert +\& # and key files themselves. However, a bug in version 5.0 of the LDAP +\& # SDK will prevent specific file names from working. For this reason +\& # it is suggested that tls_cert and tls_key be set to a directory, +\& # not a file name. +\& # +\& # The certificate database specified by tls_cert may contain CA certs +\& # and/or the client\*(Aqs cert. If the client\*(Aqs cert is included, tls_key +\& # should be specified as well. +\& # For backward compatibility, "sslpath" may be used in place of tls_cert. +\& #tls_cert /var/ldap +\& #tls_key /var/ldap +\& # +\& # If using SASL authentication for LDAP (OpenSSL) +\& # use_sasl yes +\& # sasl_auth_id +\& # rootuse_sasl yes +\& # rootsasl_auth_id +\& # sasl_secprops none +\& # krb5_ccname /etc/.ldapcache +.Ve +.SS "Sudo schema for OpenLDAP" +.IX Subsection "Sudo schema for OpenLDAP" +The following schema, in OpenLDAP format, is included with \fBsudo\fR +source and binary distributions as \fIschema.OpenLDAP\fR. Simply copy +it to the schema directory (e.g. \fI/etc/openldap/schema\fR), add the +proper \f(CW\*(C`include\*(C'\fR line in \f(CW\*(C`slapd.conf\*(C'\fR and restart \fBslapd\fR. +.PP +.Vb 6 +\& attributetype ( 1.3.6.1.4.1.15953.9.1.1 +\& NAME \*(AqsudoUser\*(Aq +\& DESC \*(AqUser(s) who may run sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SUBSTR caseExactIA5SubstringsMatch +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.2 +\& NAME \*(AqsudoHost\*(Aq +\& DESC \*(AqHost(s) who may run sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SUBSTR caseExactIA5SubstringsMatch +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.3 +\& NAME \*(AqsudoCommand\*(Aq +\& DESC \*(AqCommand(s) to be executed by sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.4 +\& NAME \*(AqsudoRunAs\*(Aq +\& DESC \*(AqUser(s) impersonated by sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.5 +\& NAME \*(AqsudoOption\*(Aq +\& DESC \*(AqOptions(s) followed by sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.6 +\& NAME \*(AqsudoRunAsUser\*(Aq +\& DESC \*(AqUser(s) impersonated by sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.7 +\& NAME \*(AqsudoRunAsGroup\*(Aq +\& DESC \*(AqGroup(s) impersonated by sudo\*(Aq +\& EQUALITY caseExactIA5Match +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.8 +\& NAME \*(AqsudoNotBefore\*(Aq +\& DESC \*(AqStart of time interval for which the entry is valid\*(Aq +\& EQUALITY generalizedTimeMatch +\& ORDERING generalizedTimeOrderingMatch +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) +\& +\& attributetype ( 1.3.6.1.4.1.15953.9.1.9 +\& NAME \*(AqsudoNotAfter\*(Aq +\& DESC \*(AqEnd of time interval for which the entry is valid\*(Aq +\& EQUALITY generalizedTimeMatch +\& ORDERING generalizedTimeOrderingMatch +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) +\& +\& attributeTypes ( 1.3.6.1.4.1.15953.9.1.10 +\& NAME \*(AqsudoOrder\*(Aq +\& DESC \*(Aqan integer to order the sudoRole entries\*(Aq +\& EQUALITY integerMatch +\& ORDERING integerOrderingMatch +\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) +\& +\& objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME \*(AqsudoRole\*(Aq SUP top STRUCTURAL +\& DESC \*(AqSudoer Entries\*(Aq +\& MUST ( cn ) +\& MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ +\& sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $ +\& sudoOrder $ description ) +\& ) +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIldap.conf\fR\|(@mansectform@), \fIsudoers\fR\|(@mansectform@) +.SH "CAVEATS" +.IX Header "CAVEATS" +Note that there are differences in the way that LDAP-based \fIsudoers\fR +is parsed compared to file-based \fIsudoers\fR. See the \*(L"Differences +between \s-1LDAP\s0 and non-LDAP sudoers\*(R" section for more information. +.SH "BUGS" +.IX Header "BUGS" +If you feel you have found a bug in \fBsudo\fR, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ +.SH "SUPPORT" +.IX Header "SUPPORT" +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or +search the archives. +.SH "DISCLAIMER" +.IX Header "DISCLAIMER" +\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 +file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudoers.ldap.pod b/doc/sudoers.ldap.pod new file mode 100644 index 0000000..f6a2bee --- /dev/null +++ b/doc/sudoers.ldap.pod @@ -0,0 +1,849 @@ +Copyright (c) 2003-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. +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=pod + +=head1 NAME + +sudoers.ldap - sudo LDAP configuration + +=head1 DESCRIPTION + +In addition to the standard I file, B may be configured +via LDAP. This can be especially useful for synchronizing I +in a large, distributed environment. + +Using LDAP for I has several benefits: + +=over 4 + +=item * + +B no longer needs to read I in its entirety. When +LDAP is used, there are only two or three LDAP queries per invocation. +This makes it especially fast and particularly usable in LDAP +environments. + +=item * + +B no longer exits if there is a typo in I. +It is not possible to load LDAP data into the server that does +not conform to the sudoers schema, so proper syntax is guaranteed. +It is still possible to have typos in a user or host name, but +this will not prevent B from running. + +=item * + +It is possible to specify per-entry options that override the global +default options. F<@sysconfdir@/sudoers> only supports default options and +limited options associated with user/host/commands/aliases. The +syntax is complicated and can be difficult for users to understand. +Placing the options directly in the entry is more natural. + +=item * + +The B program is no longer needed. B provides +locking and syntax checking of the F<@sysconfdir@/sudoers> file. +Since LDAP updates are atomic, locking is no longer necessary. +Because syntax is checked when the data is inserted into LDAP, there +is no need for a specialized tool to check syntax. + +=back + +Another major difference between LDAP and file-based I +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 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 C. Instead of defining +a Cmnd_Alias that is referenced by multiple users, one can create +a C that contains the commands and assign multiple users +to it. + +=head2 SUDOers LDAP container + +The I configuration is contained in the C LDAP +container. + +Sudo first looks for the C entry in the SUDOers container. +If found, the multi-valued C attribute is parsed in the +same manner as a global C line in F<@sysconfdir@/sudoers>. In +the following example, the C variable will be preserved +in the environment for all users. + + dn: cn=defaults,ou=SUDOers,dc=example,dc=com + objectClass: top + objectClass: sudoRole + cn: defaults + description: Default sudoOption's go here + sudoOption: env_keep+=SSH_AUTH_SOCK + +The equivalent of a sudoer in LDAP is a C. It consists of +the following attributes: + +=over 4 + +=item B + +A user name, user ID (prefixed with C<'#'>), Unix group (prefixed with +C<'%'>), Unix group ID (prefixed with C<'%#'>), or user netgroup +(prefixed with C<'+'>). + +=item B + +A host name, IP address, IP network, or host netgroup (prefixed +with a C<'+'>). +The special value C will match any host. + +=item B + +A Unix command with optional command line arguments, potentially +including globbing characters (aka wild cards). +The special value C will match any command. +If a command is prefixed with an exclamation point C<'!'>, the +user will be prohibited from running that command. + +=item B + +Identical in function to the global options described above, but +specific to the C in which it resides. + +=item B + +A user name or uid (prefixed with C<'#'>) that commands may be run +as or a Unix group (prefixed with a C<'%'>) or user netgroup (prefixed +with a C<'+'>) that contains a list of users that commands may be +run as. +The special value C 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 minute and seconds portions are optional, +but some LDAP servers require that they be present (contrary to the RFC). + +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 minute and seconds portions are optional, +but some LDAP servers require that they be present (contrary to the RFC). + +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 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 +on any host via B: + + dn: cn=%wheel,ou=SUDOers,dc=example,dc=com + objectClass: top + objectClass: sudoRole + cn: %wheel + sudoUser: %wheel + sudoHost: ALL + sudoCommand: ALL + +=head2 Anatomy of LDAP sudoers lookup + +When looking up a sudoer using LDAP there are only two or three +LDAP queries per invocation. The first query is to parse the global +options. The second is to match against the user's name and the +groups that the user belongs to. (The special ALL tag is matched +in this query too.) If no match is returned for the user's name +and groups, a third query returns all entries containing user +netgroups and checks to see if the user belongs to any of them. + +If timed entries are enabled with the B configuration +directive, the LDAP queries include a subfilter that limits retrieval +to entries that satisfy the time constraints, if any. + +=head2 Differences between LDAP and non-LDAP sudoers + +There are some subtle differences in the way sudoers is handled +once in LDAP. Probably the biggest is that according to the RFC, +LDAP ordering is arbitrary and you cannot expect that Attributes +and Entries are returned in any specific order. + +The order in which different entries are applied can be controlled +using the C attribute, but there is no way to guarantee +the order of attributes within a specific entry. If there are +conflicting command rules in an entry, the negative takes precedence. +This is called paranoid behavior (not necessarily the most specific +match). + +Here is an example: + + # /etc/sudoers: + # Allow all commands except shell + johnny ALL=(root) ALL,!/bin/sh + # Always allows all commands because ALL is matched last + puddles ALL=(root) !/bin/sh,ALL + + # LDAP equivalent of johnny + # Allows all commands except shell + dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com + objectClass: sudoRole + objectClass: top + cn: role1 + sudoUser: johnny + sudoHost: ALL + sudoCommand: ALL + sudoCommand: !/bin/sh + + # LDAP equivalent of puddles + # Notice that even though ALL comes last, it still behaves like + # role1 since the LDAP code assumes the more paranoid configuration + dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com + objectClass: sudoRole + objectClass: top + cn: role2 + sudoUser: puddles + sudoHost: ALL + sudoCommand: !/bin/sh + sudoCommand: ALL + +Another difference is that negations on the Host, User or Runas are +currently ignored. For example, the following attributes do not +behave the way one might expect. + + # does not match all but joe + # rather, does not match anyone + sudoUser: !joe + + # does not match all but joe + # rather, matches everyone including Joe + sudoUser: ALL + sudoUser: !joe + + # does not match all but web01 + # rather, matches all hosts including web01 + sudoHost: ALL + sudoHost: !web01 + +=head2 Sudoers Schema + +In order to use B's LDAP support, the B schema must be +installed on your LDAP server. In addition, be sure to index the +'sudoUser' attribute. + +Three versions of the schema: one for OpenLDAP servers (F), +one for Netscape-derived servers (F), and one for +Microsoft Active Directory (F) may +be found in the B distribution. + +The schema for B in OpenLDAP form is included in the L +section. + +=head2 Configuring ldap.conf + +Sudo reads the F<@ldap_conf@> file for LDAP-specific configuration. +Typically, this file is shared amongst different LDAP-aware clients. +As such, most of the settings are not B-specific. Note that +B parses F<@ldap_conf@> itself and may support options +that differ from those described in the L manual. + +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@> as being +supported by B are honored. Configuration options are listed +below in upper case but are parsed in a case-independent manner. + +=over 4 + +=item B ldap[s]://[hostname[:port]] ... + +Specifies a whitespace-delimited list of one or more URIs describing +the LDAP server(s) to connect to. The I may be either +B or B, the latter being for servers that support TLS +(SSL) encryption. If no I is specified, the default is port +389 for C or port 636 for C. If no I +is specified, B will connect to B. Multiple B +lines are treated identically to a B line containing multiple +entries. Only systems using the OpenSSL libraries support the +mixing of C and C URIs. The Netscape-derived +libraries used on most commercial versions of Unix are only capable +of supporting one or the other. + +=item B name[:port] ... + +If no B is specified, the B parameter specifies a +whitespace-delimited list of LDAP servers to connect to. Each host +may include an optional I separated by a colon (':'). The +B parameter is deprecated in favor of the B specification +and is included for backwards compatibility. + +=item B port_number + +If no B is specified, the B parameter specifies the +default port to connect to on the LDAP server if a B parameter +does not specify the port itself. If no B parameter is used, +the default is port 389 for LDAP and port 636 for LDAP over TLS +(SSL). The B parameter is deprecated in favor of the B +specification and is included for backwards compatibility. + +=item B seconds + +The B parameter specifies the amount of time, in seconds, +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 +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 +information is printed to the standard error. A value of 1 results +in a moderate amount of debugging information. A value of 2 shows +the results of the matches themselves. This parameter should not +be set in a production environment as the extra information is +likely to confuse users. + +=item B DN + +The B parameter specifies the identity, in the form of a +Distinguished Name (DN), to use when performing LDAP operations. +If not specified, LDAP operations are performed with an anonymous +identity. By default, most LDAP servers will allow anonymous access. + +=item B secret + +The B parameter specifies the password to use when performing +LDAP operations. This is typically used in conjunction with the +B parameter. + +=item B DN + +The B parameter specifies the identity, in the form of +a Distinguished Name (DN), to use when performing privileged LDAP +operations, such as I queries. The password corresponding +to the identity should be stored in F<@ldap_secret@>. +If not specified, the B identity is used (if any). + +=item B number + +The version of the LDAP protocol to use when connecting to the server. +The default value is protocol version 3. + +=item B on/true/yes/off/false/no + +If the B parameter is set to C, C or C, TLS +(SSL) encryption is always used when communicating with the LDAP +server. Typically, this involves connecting to the server on port +636 (ldaps). + +=item B start_tls + +If the B parameter is set to C, the LDAP server +connection is initiated normally and TLS encryption is begun before +the bind credentials are sent. This has the advantage of not +requiring a dedicated port for encrypted communications. This +parameter is only supported by LDAP servers that honor the C +extension, such as the OpenLDAP server. + +=item B on/true/yes/off/false/no + +If enabled, B will cause the LDAP server's TLS +certificated to be verified. If the server's TLS certificate cannot +be verified (usually because it is signed by an unknown certificate +authority), B will be unable to connect to it. If B +is disabled, no check is made. Note that disabling the check creates +an opportunity for man-in-the-middle attacks since the server's +identity will not be authenticated. If possible, the CA's certificate +should be installed locally so it can be verified. + +=item B file name + +An alias for B for OpenLDAP compatibility. + +=item B file name + +The path to a certificate authority bundle which contains the certificates +for all the Certificate Authorities the client knows to be valid, +e.g. F. +This option is only supported by the OpenLDAP libraries. +Netscape-derived LDAP libraries use the same certificate +database for CA and client certificates (see B). + +=item B directory + +Similar to B but instead of a file, it is a +directory containing individual Certificate Authority certificates, +e.g. F. +The directory specified by B is checked after +B. +This option is only supported by the OpenLDAP libraries. + +=item B file name + +The path to a file containing the client certificate which can +be used to authenticate the client to the LDAP server. +The certificate type depends on the LDAP libraries used. + +OpenLDAP: + C + +Netscape-derived: + C + +When using Netscape-derived libraries, this file may also contain +Certificate Authority certificates. + +=item B file name + +The path to a file containing the private key which matches the +certificate specified by B. The private key must not be +password-protected. The key type depends on the LDAP libraries +used. + +OpenLDAP: + C + +Netscape-derived: + C + +=item B file name + +The B parameter specifies the path to an entropy +source for systems that lack a random device. It is generally used +in conjunction with I or I. +This option is only supported by the OpenLDAP libraries. + +=item B cipher list + +The B parameter allows the administer to restrict +which encryption algorithms may be used for TLS (SSL) connections. +See the OpenSSL manual for a list of valid ciphers. +This option is only supported by the OpenLDAP libraries. + +=item B on/true/yes/off/false/no + +Enable B for LDAP servers that support SASL authentication. + +=item B identity + +The SASL user name to use when connecting to the LDAP server. +By default, B will use an anonymous connection. + +=item B on/true/yes/off/false/no + +Enable B to enable SASL authentication when connecting +to an LDAP server from a privileged process, such as B. + +=item B identity + +The SASL user name to use when B is enabled. + +=item B none/properties + +SASL security properties or I for no properties. See the +SASL programmer's manual for details. + +=item B file name + +The path to the Kerberos 5 credential cache to use when authenticating +with the remote server. + +=item B never/searching/finding/always + +How alias dereferencing is to be performed when searching. See the +L manual for a full description of this option. + +=back + +See the C entry in the L section. + +=head2 Configuring nsswitch.conf + +Unless it is disabled at build time, B consults the Name +Service Switch file, F<@nsswitch_conf@>, to specify the I +search order. Sudo looks for a line beginning with C: and +uses this to determine the search order. Note that B does +not stop searching after the first match and later matches take +precedence over earlier ones. + +The following sources are recognized: + + files read sudoers from F<@sysconfdir@/sudoers> + ldap read sudoers from LDAP + +In addition, the entry C<[NOTFOUND=return]> will short-circuit the +search if the user was not found in the preceding source. + +To consult LDAP first followed by the local sudoers file (if it +exists), use: + + sudoers: ldap files + +The local I file can be ignored completely by using: + + sudoers: ldap + +If the F<@nsswitch_conf@> file is not present or there is no +sudoers line, the following default is assumed: + + sudoers: files + +Note that F<@nsswitch_conf@> is supported even when the underlying +operating system does not use an nsswitch.conf file. + +=head2 Configuring netsvc.conf + +On AIX systems, the F<@netsvc_conf@> file is consulted instead of +F<@nsswitch_conf@>. B simply treats I as a +variant of I; information in the previous section +unrelated to the file format itself still applies. + +To consult LDAP first followed by the local sudoers file (if it +exists), use: + + sudoers = ldap, files + +The local I file can be ignored completely by using: + + sudoers = ldap + +To treat LDAP as authoratative and only use the local sudoers file +if the user is not present in LDAP, use: + + sudoers = ldap = auth, files + +Note that in the above example, the C qualfier only affects +user lookups; both LDAP and I will be queried for C +entries. + +If the F<@netsvc_conf@> file is not present or there is no +sudoers line, the following default is assumed: + + sudoers = files + +=head1 FILES + +=over 24 + +=item F<@ldap_conf@> + +LDAP configuration file + +=item F<@nsswitch_conf@> + +determines sudoers source order + +=item F<@netsvc_conf@> + +determines sudoers source order on AIX + +=back + +=head1 EXAMPLES + +=head2 Example ldap.conf + + # Either specify one or more URIs or one or more host:port pairs. + # If neither is specified sudo will default to localhost, port 389. + # + #host ldapserver + #host ldapserver1 ldapserver2:390 + # + # Default port if host is specified without one, defaults to 389. + #port 389 + # + # URI will override the host and port settings. + uri ldap://ldapserver + #uri ldaps://secureldapserver + #uri ldaps://secureldapserver ldap://ldapserver + # + # The amount of time, in seconds, to wait while trying to connect to + # an LDAP server. + bind_timelimit 30 + # + # The amount of time, in seconds, to wait while performing an LDAP query. + timelimit 30 + # + # Must be set or sudo will ignore LDAP; may be specified multiple times. + sudoers_base ou=SUDOers,dc=example,dc=com + # + # verbose sudoers matching from ldap + #sudoers_debug 2 + # + # Enable support for time-based entries in sudoers. + #sudoers_timed yes + # + # optional proxy credentials + #binddn + #bindpw + #rootbinddn + # + # LDAP protocol version, defaults to 3 + #ldap_version 3 + # + # Define if you want to use an encrypted LDAP connection. + # Typically, you must also set the port to 636 (ldaps). + #ssl on + # + # Define if you want to use port 389 and switch to + # encryption before the bind credentials are sent. + # Only supported by LDAP servers that support the start_tls + # extension such as OpenLDAP. + #ssl start_tls + # + # Additional TLS options follow that allow tweaking of the + # SSL/TLS connection. + # + #tls_checkpeer yes # verify server SSL certificate + #tls_checkpeer no # ignore server SSL certificate + # + # If you enable tls_checkpeer, specify either tls_cacertfile + # or tls_cacertdir. Only supported when using OpenLDAP. + # + #tls_cacertfile /etc/certs/trusted_signers.pem + #tls_cacertdir /etc/certs + # + # For systems that don't have /dev/random + # use this along with PRNGD or EGD.pl to seed the + # random number pool to generate cryptographic session keys. + # Only supported when using OpenLDAP. + # + #tls_randfile /etc/egd-pool + # + # You may restrict which ciphers are used. Consult your SSL + # documentation for which options go here. + # Only supported when using OpenLDAP. + # + #tls_ciphers + # + # Sudo can provide a client certificate when communicating to + # the LDAP server. + # Tips: + # * Enable both lines at the same time. + # * Do not password protect the key file. + # * Ensure the keyfile is only readable by root. + # + # For OpenLDAP: + #tls_cert /etc/certs/client_cert.pem + #tls_key /etc/certs/client_key.pem + # + # For SunONE or iPlanet LDAP, tls_cert and tls_key may specify either + # a directory, in which case the files in the directory must have the + # default names (e.g. cert8.db and key4.db), or the path to the cert + # and key files themselves. However, a bug in version 5.0 of the LDAP + # SDK will prevent specific file names from working. For this reason + # it is suggested that tls_cert and tls_key be set to a directory, + # not a file name. + # + # The certificate database specified by tls_cert may contain CA certs + # and/or the client's cert. If the client's cert is included, tls_key + # should be specified as well. + # For backward compatibility, "sslpath" may be used in place of tls_cert. + #tls_cert /var/ldap + #tls_key /var/ldap + # + # If using SASL authentication for LDAP (OpenSSL) + # use_sasl yes + # sasl_auth_id + # rootuse_sasl yes + # rootsasl_auth_id + # sasl_secprops none + # krb5_ccname /etc/.ldapcache + +=head2 Sudo schema for OpenLDAP + +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' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.8 + NAME 'sudoNotBefore' + DESC 'Start of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + + attributetype ( 1.3.6.1.4.1.15953.9.1.9 + NAME 'sudoNotAfter' + DESC 'End of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + + attributeTypes ( 1.3.6.1.4.1.15953.9.1.10 + NAME 'sudoOrder' + DESC 'an integer to order the sudoRole entries' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + + objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ + sudoRunAsGroup $ sudoOption $ sudoNotBefore $ sudoNotAfter $ + sudoOrder $ description ) + ) + +=head1 SEE ALSO + +L, L + +=head1 CAVEATS + +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 + +If you feel you have found a bug in B, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ + +=head1 SUPPORT + +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or +search the archives. + +=head1 DISCLAIMER + +B is provided ``AS IS'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the LICENSE +file distributed with B or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in new file mode 100644 index 0000000..6801a57 --- /dev/null +++ b/doc/sudoers.man.in @@ -0,0 +1,2190 @@ +.\" Copyright (c) 1994-1996, 1998-2005, 2007-2012 +.\" 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. +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Sponsored in part by the Defense Advanced Research Projects +.\" Agency (DARPA) and Air Force Research Laboratory, Air Force +.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. +.\" +.nr SL @SEMAN@ +.nr BA @BAMAN@ +.nr LC @LCMAN@ +.\" +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SUDOERS @mansectform@" +.TH SUDOERS @mansectform@ "March 28, 2012" "1.8.5" "MAINTENANCE COMMANDS" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +sudoers \- default sudo security policy module +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fIsudoers\fR policy module determines a user's \fBsudo\fR privileges. +It is the default \fBsudo\fR policy plugin. The policy is driven by +the \fI@sysconfdir@/sudoers\fR file or, optionally in \s-1LDAP\s0. The policy +format is described in detail in the \*(L"\s-1SUDOERS\s0 \s-1FILE\s0 \s-1FORMAT\s0\*(R" +section. For information on storing \fIsudoers\fR policy information +in \s-1LDAP\s0, please see \fIsudoers.ldap\fR\|(@mansectform@). +.SS "Authentication and Logging" +.IX Subsection "Authentication and Logging" +The \fIsudoers\fR security policy requires that most users authenticate +themselves before they can use \fBsudo\fR. A password is not required +if the invoking user is root, if the target user is the same as the +invoking user, or if the policy has disabled authentication for the +user or command. Unlike \fIsu\fR\|(1), when \fIsudoers\fR requires +authentication, it validates the invoking user's credentials, not +the target user's (or root's) credentials. This can be changed via +the \fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags, described later. +.PP +If a user who is not listed in the policy tries to run a command +via \fBsudo\fR, mail is sent to the proper authorities. The address +used for such mail is configurable via the \fImailto\fR Defaults entry +(described later) and defaults to \f(CW\*(C`@mailto@\*(C'\fR. +.PP +Note that mail will not be sent if an unauthorized user tries to +run \fBsudo\fR with the \fB\-l\fR or \fB\-v\fR option. This allows users to +determine for themselves whether or not they are allowed to use +\&\fBsudo\fR. +.PP +If \fBsudo\fR is run by root and the \f(CW\*(C`SUDO_USER\*(C'\fR environment variable +is set, the \fIsudoers\fR policy will use this value to determine who +the actual user is. This can be used by a user to log commands +through sudo even when a root shell has been invoked. It also +allows the \fB\-e\fR option to remain useful even when invoked via a +sudo-run script or program. Note, however, that the \fIsudoers\fR +lookup is still done for root, not the user specified by \f(CW\*(C`SUDO_USER\*(C'\fR. +.PP +\&\fIsudoers\fR uses time stamp files for credential caching. Once a +user has been authenticated, a time stamp is updated and the user +may then use sudo without a password for a short period of time +(\f(CW\*(C`@timeout@\*(C'\fR minutes unless overridden by the \fItimeout\fR option. +By default, \fIsudoers\fR uses a tty-based time stamp which means that +there is a separate time stamp for each of a user's login sessions. +The \fItty_tickets\fR option can be disabled to force the use of a +single time stamp for all of a user's sessions. +.PP +\&\fIsudoers\fR can log both successful and unsuccessful attempts (as well +as errors) to \fIsyslog\fR\|(3), a log file, or both. By default, \fIsudoers\fR +will log via \fIsyslog\fR\|(3) but this is changeable via the \fIsyslog\fR +and \fIlogfile\fR Defaults settings. +.PP +\&\fIsudoers\fR also supports logging a command's input and output +streams. I/O logging is not on by default but can be enabled using +the \fIlog_input\fR and \fIlog_output\fR Defaults flags as well as the +\&\f(CW\*(C`LOG_INPUT\*(C'\fR and \f(CW\*(C`LOG_OUTPUT\*(C'\fR command tags. +.SS "Command Environment" +.IX Subsection "Command Environment" +Since environment variables can influence program behavior, \fIsudoers\fR +provides a means to restrict which variables from the user's +environment are inherited by the command to be run. There are two +distinct ways \fIsudoers\fR can deal with environment variables. +.PP +By default, the \fIenv_reset\fR option is enabled. This causes commands +to be executed with a new, minimal environment. On \s-1AIX\s0 (and Linux +systems without \s-1PAM\s0), the environment is initialized with the +contents of the \fI/etc/environment\fR file. On \s-1BSD\s0 systems, if the +\&\fIuse_loginclass\fR option is enabled, the environment is initialized +based on the \fIpath\fR and \fIsetenv\fR settings in \fI/etc/login.conf\fR. +The new environment contains the \f(CW\*(C`TERM\*(C'\fR, \f(CW\*(C`PATH\*(C'\fR, \f(CW\*(C`HOME\*(C'\fR, \f(CW\*(C`MAIL\*(C'\fR, +\&\f(CW\*(C`SHELL\*(C'\fR, \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR, \f(CW\*(C`USERNAME\*(C'\fR and \f(CW\*(C`SUDO_*\*(C'\fR variables +in addition to variables from the invoking process permitted by the +\&\fIenv_check\fR and \fIenv_keep\fR options. This is effectively a whitelist +for environment variables. +.PP +If, however, the \fIenv_reset\fR option is disabled, any variables not +explicitly denied by the \fIenv_check\fR and \fIenv_delete\fR options are +inherited from the invoking process. In this case, \fIenv_check\fR +and \fIenv_delete\fR behave like a blacklist. Since it is not possible +to blacklist all potentially dangerous environment variables, use +of the default \fIenv_reset\fR behavior is encouraged. +.PP +In all cases, environment variables with a value beginning with +\&\f(CW\*(C`()\*(C'\fR are removed as they could be interpreted as \fBbash\fR functions. +The list of environment variables that \fBsudo\fR allows or denies is +contained in the output of \f(CW\*(C`sudo \-V\*(C'\fR when run as root. +.PP +Note that the dynamic linker on most operating systems will remove +variables that can control dynamic linking from the environment of +setuid executables, including \fBsudo\fR. Depending on the operating +system this may include \f(CW\*(C`_RLD*\*(C'\fR, \f(CW\*(C`DYLD_*\*(C'\fR, \f(CW\*(C`LD_*\*(C'\fR, \f(CW\*(C`LDR_*\*(C'\fR, +\&\f(CW\*(C`LIBPATH\*(C'\fR, \f(CW\*(C`SHLIB_PATH\*(C'\fR, and others. These type of variables are +removed from the environment before \fBsudo\fR even begins execution +and, as such, it is not possible for \fBsudo\fR to preserve them. +.PP +As a special case, if \fBsudo\fR's \fB\-i\fR option (initial login) is +specified, \fIsudoers\fR will initialize the environment regardless +of the value of \fIenv_reset\fR. The \fI\s-1DISPLAY\s0\fR, \fI\s-1PATH\s0\fR and \fI\s-1TERM\s0\fR +variables remain unchanged; \fI\s-1HOME\s0\fR, \fI\s-1MAIL\s0\fR, \fI\s-1SHELL\s0\fR, \fI\s-1USER\s0\fR, +and \fI\s-1LOGNAME\s0\fR are set based on the target user. On \s-1AIX\s0 (and Linux +systems without \s-1PAM\s0), the contents of \fI/etc/environment\fR are also +included. On \s-1BSD\s0 systems, if the \fIuse_loginclass\fR option is +enabled, the \fIpath\fR and \fIsetenv\fR variables in \fI/etc/login.conf\fR +are also applied. All other environment variables are removed. +.PP +Finally, if the \fIenv_file\fR option is defined, any variables present +in that file will be set to their specified values as long as they +would not conflict with an existing environment variable. +.SH "SUDOERS FILE FORMAT" +.IX Header "SUDOERS FILE FORMAT" +The \fIsudoers\fR file is composed of two types of entries: aliases +(basically variables) and user specifications (which specify who +may run what). +.PP +When multiple entries match for a user, they are applied in order. +Where there are multiple matches, the last match is used (which is +not necessarily the most specific match). +.PP +The \fIsudoers\fR grammar will be described below in Extended Backus-Naur +Form (\s-1EBNF\s0). Don't despair if you don't know what \s-1EBNF\s0 is; it is +fairly simple, and the definitions below are annotated. +.SS "Quick guide to \s-1EBNF\s0" +.IX Subsection "Quick guide to EBNF" +\&\s-1EBNF\s0 is a concise and exact way of describing the grammar of a language. +Each \s-1EBNF\s0 definition is made up of \fIproduction rules\fR. E.g., +.PP +.Vb 1 +\& symbol ::= definition | alternate1 | alternate2 ... +.Ve +.PP +Each \fIproduction rule\fR references others and thus makes up a +grammar for the language. \s-1EBNF\s0 also contains the following +operators, which many readers will recognize from regular +expressions. Do not, however, confuse them with \*(L"wildcard\*(R" +characters, which have different meanings. +.ie n .IP "\*(C`?\*(C'" 4 +.el .IP "\f(CW\*(C`?\*(C'\fR" 4 +.IX Item "?" +Means that the preceding symbol (or group of symbols) is optional. +That is, it may appear once or not at all. +.ie n .IP "\*(C`*\*(C'" 4 +.el .IP "\f(CW\*(C`*\*(C'\fR" 4 +.IX Item "*" +Means that the preceding symbol (or group of symbols) may appear +zero or more times. +.ie n .IP "\*(C`+\*(C'" 4 +.el .IP "\f(CW\*(C`+\*(C'\fR" 4 +.IX Item "+" +Means that the preceding symbol (or group of symbols) may appear +one or more times. +.PP +Parentheses may be used to group symbols together. For clarity, +we will use single quotes ('') to designate what is a verbatim character +string (as opposed to a symbol name). +.SS "Aliases" +.IX Subsection "Aliases" +There are four kinds of aliases: \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, +\&\f(CW\*(C`Host_Alias\*(C'\fR and \f(CW\*(C`Cmnd_Alias\*(C'\fR. +.PP +.Vb 4 +\& Alias ::= \*(AqUser_Alias\*(Aq User_Alias (\*(Aq:\*(Aq User_Alias)* | +\& \*(AqRunas_Alias\*(Aq Runas_Alias (\*(Aq:\*(Aq Runas_Alias)* | +\& \*(AqHost_Alias\*(Aq Host_Alias (\*(Aq:\*(Aq Host_Alias)* | +\& \*(AqCmnd_Alias\*(Aq Cmnd_Alias (\*(Aq:\*(Aq Cmnd_Alias)* +\& +\& User_Alias ::= NAME \*(Aq=\*(Aq User_List +\& +\& Runas_Alias ::= NAME \*(Aq=\*(Aq Runas_List +\& +\& Host_Alias ::= NAME \*(Aq=\*(Aq Host_List +\& +\& Cmnd_Alias ::= NAME \*(Aq=\*(Aq Cmnd_List +\& +\& NAME ::= [A\-Z]([A\-Z][0\-9]_)* +.Ve +.PP +Each \fIalias\fR definition is of the form +.PP +.Vb 1 +\& Alias_Type NAME = item1, item2, ... +.Ve +.PP +where \fIAlias_Type\fR is one of \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, \f(CW\*(C`Host_Alias\*(C'\fR, +or \f(CW\*(C`Cmnd_Alias\*(C'\fR. A \f(CW\*(C`NAME\*(C'\fR is a string of uppercase letters, numbers, +and underscore characters ('_'). A \f(CW\*(C`NAME\*(C'\fR \fBmust\fR start with an +uppercase letter. It is possible to put several alias definitions +of the same type on a single line, joined by a colon (':'). E.g., +.PP +.Vb 1 +\& Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 +.Ve +.PP +The definitions of what constitutes a valid \fIalias\fR member follow. +.PP +.Vb 2 +\& User_List ::= User | +\& User \*(Aq,\*(Aq User_List +\& +\& User ::= \*(Aq!\*(Aq* user name | +\& \*(Aq!\*(Aq* #uid | +\& \*(Aq!\*(Aq* %group | +\& \*(Aq!\*(Aq* %#gid | +\& \*(Aq!\*(Aq* +netgroup | +\& \*(Aq!\*(Aq* %:nonunix_group | +\& \*(Aq!\*(Aq* %:#nonunix_gid | +\& \*(Aq!\*(Aq* User_Alias +.Ve +.PP +A \f(CW\*(C`User_List\*(C'\fR is made up of one or more user names, user ids +(prefixed with '#'), system group names and ids (prefixed with '%' +and '%#' respectively), netgroups (prefixed with '+'), non-Unix +group names and IDs (prefixed with '%:' and '%:#' respectively) and +\&\f(CW\*(C`User_Alias\*(C'\fRes. Each list item may be prefixed with zero or more +\&'!' operators. An odd number of '!' operators negate the value of +the item; an even number just cancel each other out. +.PP +A \f(CW\*(C`user name\*(C'\fR, \f(CW\*(C`uid\*(C'\fR, \f(CW\*(C`group\*(C'\fR, \f(CW\*(C`gid\*(C'\fR, \f(CW\*(C`netgroup\*(C'\fR, \f(CW\*(C`nonunix_group\*(C'\fR +or \f(CW\*(C`nonunix_gid\*(C'\fR may be enclosed in double quotes to avoid the +need for escaping special characters. Alternately, special characters +may be specified in escaped hex mode, e.g. \ex20 for space. When +using double quotes, any prefix characters must be included inside +the quotes. +.PP +The actual \f(CW\*(C`nonunix_group\*(C'\fR and \f(CW\*(C`nonunix_gid\*(C'\fR syntax depends on +the underlying group provider plugin (see the \fIgroup_plugin\fR +description below). For instance, the \s-1QAS\s0 \s-1AD\s0 plugin supports the +following formats: +.IP "\(bu" 4 +Group in the same domain: \*(L"Group Name\*(R" +.IP "\(bu" 4 +Group in any domain: \*(L"Group Name@FULLY.QUALIFIED.DOMAIN\*(R" +.IP "\(bu" 4 +Group \s-1SID:\s0 \*(L"S\-1\-2\-34\-5678901234\-5678901234\-5678901234\-567\*(R" +.PP +Note that quotes around group names are optional. Unquoted strings +must use a backslash (\e) to escape spaces and special characters. +See \*(L"Other special characters and reserved words\*(R" for a list of +characters that need to be escaped. +.PP +.Vb 2 +\& Runas_List ::= Runas_Member | +\& Runas_Member \*(Aq,\*(Aq Runas_List +\& +\& Runas_Member ::= \*(Aq!\*(Aq* user name | +\& \*(Aq!\*(Aq* #uid | +\& \*(Aq!\*(Aq* %group | +\& \*(Aq!\*(Aq* %#gid | +\& \*(Aq!\*(Aq* %:nonunix_group | +\& \*(Aq!\*(Aq* %:#nonunix_gid | +\& \*(Aq!\*(Aq* +netgroup | +\& \*(Aq!\*(Aq* Runas_Alias +.Ve +.PP +A \f(CW\*(C`Runas_List\*(C'\fR is similar to a \f(CW\*(C`User_List\*(C'\fR except that instead +of \f(CW\*(C`User_Alias\*(C'\fRes it can contain \f(CW\*(C`Runas_Alias\*(C'\fRes. Note that +user names and groups are matched as strings. In other words, two +users (groups) with the same uid (gid) are considered to be distinct. +If you wish to match all user names with the same uid (e.g.\ root +and toor), you can use a uid instead (#0 in the example given). +.PP +.Vb 2 +\& Host_List ::= Host | +\& Host \*(Aq,\*(Aq Host_List +\& +\& Host ::= \*(Aq!\*(Aq* host name | +\& \*(Aq!\*(Aq* ip_addr | +\& \*(Aq!\*(Aq* network(/netmask)? | +\& \*(Aq!\*(Aq* +netgroup | +\& \*(Aq!\*(Aq* Host_Alias +.Ve +.PP +A \f(CW\*(C`Host_List\*(C'\fR is made up of one or more host names, \s-1IP\s0 addresses, +network numbers, netgroups (prefixed with '+') and other aliases. +Again, the value of an item may be negated with the '!' operator. +If you do not specify a netmask along with the network number, +\&\fBsudo\fR will query each of the local host's network interfaces and, +if the network number corresponds to one of the hosts's network +interfaces, the corresponding netmask will be used. The netmask +may be specified either in standard \s-1IP\s0 address notation +(e.g.\ 255.255.255.0 or ffff:ffff:ffff:ffff::), +or \s-1CIDR\s0 notation (number of bits, e.g.\ 24 or 64). A host name may +include shell-style wildcards (see the Wildcards section below), +but unless the \f(CW\*(C`host name\*(C'\fR command on your machine returns the fully +qualified host name, you'll need to use the \fIfqdn\fR option for +wildcards to be useful. Note \fBsudo\fR only inspects actual network +interfaces; this means that \s-1IP\s0 address 127.0.0.1 (localhost) will +never match. Also, the host name \*(L"localhost\*(R" will only match if +that is the actual host name, which is usually only the case for +non-networked systems. +.PP +.Vb 2 +\& Cmnd_List ::= Cmnd | +\& Cmnd \*(Aq,\*(Aq Cmnd_List +\& +\& commandname ::= file name | +\& file name args | +\& file name \*(Aq""\*(Aq +\& +\& Cmnd ::= \*(Aq!\*(Aq* commandname | +\& \*(Aq!\*(Aq* directory | +\& \*(Aq!\*(Aq* "sudoedit" | +\& \*(Aq!\*(Aq* Cmnd_Alias +.Ve +.PP +A \f(CW\*(C`Cmnd_List\*(C'\fR is a list of one or more commandnames, directories, and other +aliases. A commandname is a fully qualified file name which may include +shell-style wildcards (see the Wildcards section below). A simple +file name allows the user to run the command with any arguments he/she +wishes. However, you may also specify command line arguments (including +wildcards). Alternately, you can specify \f(CW""\fR to indicate that the command +may only be run \fBwithout\fR command line arguments. A directory is a +fully qualified path name ending in a '/'. When you specify a directory +in a \f(CW\*(C`Cmnd_List\*(C'\fR, the user will be able to run any file within that directory +(but not in any subdirectories therein). +.PP +If a \f(CW\*(C`Cmnd\*(C'\fR has associated command line arguments, then the arguments +in the \f(CW\*(C`Cmnd\*(C'\fR must match exactly those given by the user on the command line +(or match the wildcards if there are any). Note that the following +characters must be escaped with a '\e' if they are used in command +arguments: ',', ':', '=', '\e'. The special command \f(CW"sudoedit"\fR +is used to permit a user to run \fBsudo\fR with the \fB\-e\fR option (or +as \fBsudoedit\fR). It may take command line arguments just as +a normal command does. +.SS "Defaults" +.IX Subsection "Defaults" +Certain configuration options may be changed from their default +values at runtime via one or more \f(CW\*(C`Default_Entry\*(C'\fR lines. These +may affect all users on any host, all users on a specific host, a +specific user, a specific command, or commands being run as a specific user. +Note that per-command entries may not include command line arguments. +If you need to specify arguments, define a \f(CW\*(C`Cmnd_Alias\*(C'\fR and reference +that instead. +.PP +.Vb 5 +\& Default_Type ::= \*(AqDefaults\*(Aq | +\& \*(AqDefaults\*(Aq \*(Aq@\*(Aq Host_List | +\& \*(AqDefaults\*(Aq \*(Aq:\*(Aq User_List | +\& \*(AqDefaults\*(Aq \*(Aq!\*(Aq Cmnd_List | +\& \*(AqDefaults\*(Aq \*(Aq>\*(Aq Runas_List +\& +\& Default_Entry ::= Default_Type Parameter_List +\& +\& Parameter_List ::= Parameter | +\& Parameter \*(Aq,\*(Aq Parameter_List +\& +\& Parameter ::= Parameter \*(Aq=\*(Aq Value | +\& Parameter \*(Aq+=\*(Aq Value | +\& Parameter \*(Aq\-=\*(Aq Value | +\& \*(Aq!\*(Aq* Parameter +.Ve +.PP +Parameters may be \fBflags\fR, \fBinteger\fR values, \fBstrings\fR, or \fBlists\fR. +Flags are implicitly boolean and can be turned off via the '!' +operator. Some integer, string and list parameters may also be +used in a boolean context to disable them. Values may be enclosed +in double quotes (\f(CW\*(C`"\*(C'\fR) when they contain multiple words. Special +characters may be escaped with a backslash (\f(CW\*(C`\e\*(C'\fR). +.PP +Lists have two additional assignment operators, \f(CW\*(C`+=\*(C'\fR and \f(CW\*(C`\-=\*(C'\fR. +These operators are used to add to and delete from a list respectively. +It is not an error to use the \f(CW\*(C`\-=\*(C'\fR operator to remove an element +that does not exist in a list. +.PP +Defaults entries are parsed in the following order: generic, host +and user Defaults first, then runas Defaults and finally command +defaults. +.PP +See \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" for a list of supported Defaults parameters. +.SS "User Specification" +.IX Subsection "User Specification" +.Vb 2 +\& User_Spec ::= User_List Host_List \*(Aq=\*(Aq Cmnd_Spec_List \e +\& (\*(Aq:\*(Aq Host_List \*(Aq=\*(Aq Cmnd_Spec_List)* +\& +\& Cmnd_Spec_List ::= Cmnd_Spec | +\& Cmnd_Spec \*(Aq,\*(Aq Cmnd_Spec_List +\& +.ie \n(SL \& Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd +.el \& Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd +\& +\& Runas_Spec ::= \*(Aq(\*(Aq Runas_List? (\*(Aq:\*(Aq Runas_List)? \*(Aq)\*(Aq +\& +.if \n(SL \{\ +\& SELinux_Spec ::= (\*(AqROLE=role\*(Aq | \*(AqTYPE=type\*(Aq) +\& +\} +\& Tag_Spec ::= (\*(AqNOPASSWD:\*(Aq | \*(AqPASSWD:\*(Aq | \*(AqNOEXEC:\*(Aq | \*(AqEXEC:\*(Aq | +\& \*(AqSETENV:\*(Aq | \*(AqNOSETENV:\*(Aq | \*(AqLOG_INPUT:\*(Aq | \*(AqNOLOG_INPUT:\*(Aq | +\& \*(AqLOG_OUTPUT:\*(Aq | \*(AqNOLOG_OUTPUT:\*(Aq) +.Ve +.PP +A \fBuser specification\fR determines which commands a user may run +(and as what user) on specified hosts. By default, commands are +run as \fBroot\fR, but this can be changed on a per-command basis. +.PP +The basic structure of a user specification is `who where = (as_whom) +what'. Let's break that down into its constituent parts: +.SS "Runas_Spec" +.IX Subsection "Runas_Spec" +A \f(CW\*(C`Runas_Spec\*(C'\fR determines the user and/or the group that a command +may be run as. A fully-specified \f(CW\*(C`Runas_Spec\*(C'\fR consists of two +\&\f(CW\*(C`Runas_List\*(C'\fRs (as defined above) separated by a colon (':') and +enclosed in a set of parentheses. The first \f(CW\*(C`Runas_List\*(C'\fR indicates +which users the command may be run as via \fBsudo\fR's \fB\-u\fR option. +The second defines a list of groups that can be specified via +\&\fBsudo\fR's \fB\-g\fR option. If both \f(CW\*(C`Runas_List\*(C'\fRs are specified, the +command may be run with any combination of users and groups listed +in their respective \f(CW\*(C`Runas_List\*(C'\fRs. If only the first is specified, +the command may be run as any user in the list but no \fB\-g\fR option +may be specified. If the first \f(CW\*(C`Runas_List\*(C'\fR is empty but the +second is specified, the command may be run as the invoking user +with the group set to any listed in the \f(CW\*(C`Runas_List\*(C'\fR. If no +\&\f(CW\*(C`Runas_Spec\*(C'\fR is specified the command may be run as \fBroot\fR and +no group may be specified. +.PP +A \f(CW\*(C`Runas_Spec\*(C'\fR sets the default for the commands that follow it. +What this means is that for the entry: +.PP +.Vb 1 +\& dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm +.Ve +.PP +The user \fBdgb\fR may run \fI/bin/ls\fR, \fI/bin/kill\fR, and +\&\fI/usr/bin/lprm\fR \*(-- but only as \fBoperator\fR. E.g., +.PP +.Vb 1 +\& $ sudo \-u operator /bin/ls +.Ve +.PP +It is also possible to override a \f(CW\*(C`Runas_Spec\*(C'\fR later on in an +entry. If we modify the entry like so: +.PP +.Vb 1 +\& dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm +.Ve +.PP +Then user \fBdgb\fR is now allowed to run \fI/bin/ls\fR as \fBoperator\fR, +but \fI/bin/kill\fR and \fI/usr/bin/lprm\fR as \fBroot\fR. +.PP +We can extend this to allow \fBdgb\fR to run \f(CW\*(C`/bin/ls\*(C'\fR with either +the user or group set to \fBoperator\fR: +.PP +.Vb 2 +\& dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \e +\& /usr/bin/lprm +.Ve +.PP +Note that while the group portion of the \f(CW\*(C`Runas_Spec\*(C'\fR permits the +user to run as command with that group, it does not force the user +to do so. If no group is specified on the command line, the command +will run with the group listed in the target user's password database +entry. The following would all be permitted by the sudoers entry above: +.PP +.Vb 3 +\& $ sudo \-u operator /bin/ls +\& $ sudo \-u operator \-g operator /bin/ls +\& $ sudo \-g operator /bin/ls +.Ve +.PP +In the following example, user \fBtcm\fR may run commands that access +a modem device file with the dialer group. +.PP +.Vb 2 +\& tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \e +\& /usr/local/bin/minicom +.Ve +.PP +Note that in this example only the group will be set, the command +still runs as user \fBtcm\fR. E.g. +.PP +.Vb 1 +\& $ sudo \-g dialer /usr/bin/cu +.Ve +.PP +Multiple users and groups may be present in a \f(CW\*(C`Runas_Spec\*(C'\fR, in +which case the user may select any combination of users and groups +via the \fB\-u\fR and \fB\-g\fR options. In this example: +.PP +.Vb 1 +\& alan ALL = (root, bin : operator, system) ALL +.Ve +.PP +user \fBalan\fR may run any command as either user root or bin, +optionally setting the group to operator or system. +.if \n(SL \{\ +.SS "SELinux_Spec" +.IX Subsection "SELinux_Spec" +On systems with SELinux support, \fIsudoers\fR entries may optionally have +an SELinux role and/or type associated with a command. If a role or +type is specified with the command it will override any default values +specified in \fIsudoers\fR. A role or type specified on the command line, +however, will supercede the values in \fIsudoers\fR. +\} +.SS "Tag_Spec" +.IX Subsection "Tag_Spec" +A command may have zero or more tags associated with it. There are +eight possible tag values, \f(CW\*(C`NOPASSWD\*(C'\fR, \f(CW\*(C`PASSWD\*(C'\fR, \f(CW\*(C`NOEXEC\*(C'\fR, +\&\f(CW\*(C`EXEC\*(C'\fR, \f(CW\*(C`SETENV\*(C'\fR, \f(CW\*(C`NOSETENV\*(C'\fR, \f(CW\*(C`LOG_INPUT\*(C'\fR, \f(CW\*(C`NOLOG_INPUT\*(C'\fR, +\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR and \f(CW\*(C`NOLOG_OUTPUT\*(C'\fR. Once a tag is set on a \f(CW\*(C`Cmnd\*(C'\fR, +subsequent \f(CW\*(C`Cmnd\*(C'\fRs in the \f(CW\*(C`Cmnd_Spec_List\*(C'\fR, inherit the tag unless +it is overridden by the opposite tag (i.e.: \f(CW\*(C`PASSWD\*(C'\fR overrides +\&\f(CW\*(C`NOPASSWD\*(C'\fR and \f(CW\*(C`NOEXEC\*(C'\fR overrides \f(CW\*(C`EXEC\*(C'\fR). +.PP +\fI\s-1NOPASSWD\s0 and \s-1PASSWD\s0\fR +.IX Subsection "NOPASSWD and PASSWD" +.PP +By default, \fBsudo\fR requires that a user authenticate him or herself +before running a command. This behavior can be modified via the +\&\f(CW\*(C`NOPASSWD\*(C'\fR tag. Like a \f(CW\*(C`Runas_Spec\*(C'\fR, the \f(CW\*(C`NOPASSWD\*(C'\fR tag sets +a default for the commands that follow it in the \f(CW\*(C`Cmnd_Spec_List\*(C'\fR. +Conversely, the \f(CW\*(C`PASSWD\*(C'\fR tag can be used to reverse things. +For example: +.PP +.Vb 1 +\& ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm +.Ve +.PP +would allow the user \fBray\fR to run \fI/bin/kill\fR, \fI/bin/ls\fR, and +\&\fI/usr/bin/lprm\fR as \fBroot\fR on the machine rushmore without +authenticating himself. If we only want \fBray\fR to be able to +run \fI/bin/kill\fR without a password the entry would be: +.PP +.Vb 1 +\& ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm +.Ve +.PP +Note, however, that the \f(CW\*(C`PASSWD\*(C'\fR tag has no effect on users who are +in the group specified by the \fIexempt_group\fR option. +.PP +By default, if the \f(CW\*(C`NOPASSWD\*(C'\fR tag is applied to any of the entries +for a user on the current host, he or she will be able to run +\&\f(CW\*(C`sudo \-l\*(C'\fR without a password. Additionally, a user may only run +\&\f(CW\*(C`sudo \-v\*(C'\fR without a password if the \f(CW\*(C`NOPASSWD\*(C'\fR tag is present +for all a user's entries that pertain to the current host. +This behavior may be overridden via the verifypw and listpw options. +.PP +\fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR +.IX Subsection "NOEXEC and EXEC" +.PP +If \fBsudo\fR has been compiled with \fInoexec\fR support and the underlying +operating system supports it, the \f(CW\*(C`NOEXEC\*(C'\fR tag can be used to prevent +a dynamically-linked executable from running further commands itself. +.PP +In the following example, user \fBaaron\fR may run \fI/usr/bin/more\fR +and \fI/usr/bin/vi\fR but shell escapes will be disabled. +.PP +.Vb 1 +\& aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi +.Ve +.PP +See the \*(L"Preventing Shell Escapes\*(R" section below for more details +on how \f(CW\*(C`NOEXEC\*(C'\fR works and whether or not it will work on your system. +.PP +\fI\s-1SETENV\s0 and \s-1NOSETENV\s0\fR +.IX Subsection "SETENV and NOSETENV" +.PP +These tags override the value of the \fIsetenv\fR option on a per-command +basis. Note that if \f(CW\*(C`SETENV\*(C'\fR has been set for a command, the user +may disable the \fIenv_reset\fR option from the command line via the +\&\fB\-E\fR option. Additionally, environment variables set on the command +line are not subject to the restrictions imposed by \fIenv_check\fR, +\&\fIenv_delete\fR, or \fIenv_keep\fR. As such, only trusted users should +be allowed to set variables in this manner. If the command matched +is \fB\s-1ALL\s0\fR, the \f(CW\*(C`SETENV\*(C'\fR tag is implied for that command; this +default may be overridden by use of the \f(CW\*(C`NOSETENV\*(C'\fR tag. +.PP +\fI\s-1LOG_INPUT\s0 and \s-1NOLOG_INPUT\s0\fR +.IX Subsection "LOG_INPUT and NOLOG_INPUT" +.PP +These tags override the value of the \fIlog_input\fR option on a +per-command basis. For more information, see the description of +\&\fIlog_input\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below. +.PP +\fI\s-1LOG_OUTPUT\s0 and \s-1NOLOG_OUTPUT\s0\fR +.IX Subsection "LOG_OUTPUT and NOLOG_OUTPUT" +.PP +These tags override the value of the \fIlog_output\fR option on a +per-command basis. For more information, see the description of +\&\fIlog_output\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below. +.SS "Wildcards" +.IX Subsection "Wildcards" +\&\fBsudo\fR allows shell-style \fIwildcards\fR (aka meta or glob characters) +to be used in host names, path names and command line arguments in +the \fIsudoers\fR file. Wildcard matching is done via the \fB\s-1POSIX\s0\fR +\&\fIglob\fR\|(3) and \fIfnmatch\fR\|(3) routines. Note that these are \fInot\fR +regular expressions. +.ie n .IP "\*(C`*\*(C'" 8 +.el .IP "\f(CW\*(C`*\*(C'\fR" 8 +.IX Item "*" +Matches any set of zero or more characters. +.ie n .IP "\*(C`?\*(C'" 8 +.el .IP "\f(CW\*(C`?\*(C'\fR" 8 +.IX Item "?" +Matches any single character. +.ie n .IP "\*(C`[...]\*(C'" 8 +.el .IP "\f(CW\*(C`[...]\*(C'\fR" 8 +.IX Item "[...]" +Matches any character in the specified range. +.ie n .IP "\*(C`[!...]\*(C'" 8 +.el .IP "\f(CW\*(C`[!...]\*(C'\fR" 8 +.IX Item "[!...]" +Matches any character \fBnot\fR in the specified range. +.ie n .IP "\*(C`\ex\*(C'" 8 +.el .IP "\f(CW\*(C`\ex\*(C'\fR" 8 +.IX Item "x" +For any character \*(L"x\*(R", evaluates to \*(L"x\*(R". This is used to +escape special characters such as: \*(L"*\*(R", \*(L"?\*(R", \*(L"[\*(R", and \*(L"}\*(R". +.PP +\&\s-1POSIX\s0 character classes may also be used if your system's \fIglob\fR\|(3) +and \fIfnmatch\fR\|(3) functions support them. However, because the +\&\f(CW\*(Aq:\*(Aq\fR character has special meaning in \fIsudoers\fR, it must be +escaped. For example: +.PP +.Vb 1 +\& /bin/ls [[\e:alpha\e:]]* +.Ve +.PP +Would match any file name beginning with a letter. +.PP +Note that a forward slash ('/') will \fBnot\fR be matched by +wildcards used in the path name. When matching the command +line arguments, however, a slash \fBdoes\fR get matched by +wildcards. This is to make a path like: +.PP +.Vb 1 +\& /usr/bin/* +.Ve +.PP +match \fI/usr/bin/who\fR but not \fI/usr/bin/X11/xterm\fR. +.SS "Exceptions to wildcard rules" +.IX Subsection "Exceptions to wildcard rules" +The following exceptions apply to the above rules: +.ie n .IP """""" 8 +.el .IP "\f(CW``''\fR" 8 +.IX Item """""" +If the empty string \f(CW""\fR is the only command line argument in the +\&\fIsudoers\fR entry it means that command is not allowed to be run +with \fBany\fR arguments. +.SS "Including other files from within sudoers" +.IX Subsection "Including other files from within sudoers" +It is possible to include other \fIsudoers\fR files from within the +\&\fIsudoers\fR file currently being parsed using the \f(CW\*(C`#include\*(C'\fR and +\&\f(CW\*(C`#includedir\*(C'\fR directives. +.PP +This can be used, for example, to keep a site-wide \fIsudoers\fR file +in addition to a local, per-machine file. For the sake of this +example the site-wide \fIsudoers\fR will be \fI/etc/sudoers\fR and the +per-machine one will be \fI/etc/sudoers.local\fR. To include +\&\fI/etc/sudoers.local\fR from within \fI/etc/sudoers\fR we would use the +following line in \fI/etc/sudoers\fR: +.Sp +.RS 4 +\&\f(CW\*(C`#include /etc/sudoers.local\*(C'\fR +.RE +.PP +When \fBsudo\fR reaches this line it will suspend processing of the +current file (\fI/etc/sudoers\fR) and switch to \fI/etc/sudoers.local\fR. +Upon reaching the end of \fI/etc/sudoers.local\fR, the rest of +\&\fI/etc/sudoers\fR will be processed. Files that are included may +themselves include other files. A hard limit of 128 nested include +files is enforced to prevent include file loops. +.PP +If the path to the include file is not fully-qualified (does not +begin with a \fI/\fR), it must be located in the same directory as the +sudoers file it was included from. For example, if \fI/etc/sudoers\fR +contains the line: +.Sp +.RS 4 +\&\f(CW\*(C`#include sudoers.local\*(C'\fR +.RE +.PP +the file that will be included is \fI/etc/sudoers.local\fR. +.PP +The file name may also include the \f(CW%h\fR escape, signifying the short form +of the host name. I.e., if the machine's host name is \*(L"xerxes\*(R", then +.PP +\&\f(CW\*(C`#include /etc/sudoers.%h\*(C'\fR +.PP +will cause \fBsudo\fR to include the file \fI/etc/sudoers.xerxes\fR. +.PP +The \f(CW\*(C`#includedir\*(C'\fR directive can be used to create a \fIsudo.d\fR +directory that the system package manager can drop \fIsudoers\fR rules +into as part of package installation. For example, given: +.PP +\&\f(CW\*(C`#includedir /etc/sudoers.d\*(C'\fR +.PP +\&\fBsudo\fR will read each file in \fI/etc/sudoers.d\fR, skipping file +names that end in \f(CW\*(C`~\*(C'\fR or contain a \f(CW\*(C`.\*(C'\fR character to avoid causing +problems with package manager or editor temporary/backup files. +Files are parsed in sorted lexical order. That is, +\&\fI/etc/sudoers.d/01_first\fR will be parsed before +\&\fI/etc/sudoers.d/10_second\fR. Be aware that because the sorting is +lexical, not numeric, \fI/etc/sudoers.d/1_whoops\fR would be loaded +\&\fBafter\fR \fI/etc/sudoers.d/10_second\fR. Using a consistent number +of leading zeroes in the file names can be used to avoid such +problems. +.PP +Note that unlike files included via \f(CW\*(C`#include\*(C'\fR, \fBvisudo\fR will not +edit the files in a \f(CW\*(C`#includedir\*(C'\fR directory unless one of them +contains a syntax error. It is still possible to run \fBvisudo\fR +with the \f(CW\*(C`\-f\*(C'\fR flag to edit the files directly. +.SS "Other special characters and reserved words" +.IX Subsection "Other special characters and reserved words" +The pound sign ('#') is used to indicate a comment (unless it is +part of a #include directive or unless it occurs in the context of +a user name and is followed by one or more digits, in which case +it is treated as a uid). Both the comment character and any text +after it, up to the end of the line, are ignored. +.PP +The reserved word \fB\s-1ALL\s0\fR is a built-in \fIalias\fR that always causes +a match to succeed. It can be used wherever one might otherwise +use a \f(CW\*(C`Cmnd_Alias\*(C'\fR, \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, or \f(CW\*(C`Host_Alias\*(C'\fR. +You should not try to define your own \fIalias\fR called \fB\s-1ALL\s0\fR as the +built-in alias will be used in preference to your own. Please note +that using \fB\s-1ALL\s0\fR can be dangerous since in a command context, it +allows the user to run \fBany\fR command on the system. +.PP +An exclamation point ('!') can be used as a logical \fInot\fR operator +both in an \fIalias\fR and in front of a \f(CW\*(C`Cmnd\*(C'\fR. This allows one to +exclude certain values. Note, however, that using a \f(CW\*(C`!\*(C'\fR in +conjunction with the built-in \f(CW\*(C`ALL\*(C'\fR alias to allow a user to +run \*(L"all but a few\*(R" commands rarely works as intended (see \s-1SECURITY\s0 +\&\s-1NOTES\s0 below). +.PP +Long lines can be continued with a backslash ('\e') as the last +character on the line. +.PP +Whitespace between elements in a list as well as special syntactic +characters in a \fIUser Specification\fR ('=', ':', '(', ')') is optional. +.PP +The following characters must be escaped with a backslash ('\e') when +used as part of a word (e.g.\ a user name or host name): +\&'!', '=', ':', ',', '(', ')', '\e'. +.SH "SUDOERS OPTIONS" +.IX Header "SUDOERS OPTIONS" +\&\fBsudo\fR's behavior can be modified by \f(CW\*(C`Default_Entry\*(C'\fR lines, as +explained earlier. A list of all supported Defaults parameters, +grouped by type, are listed below. +.PP +\&\fBBoolean Flags\fR: +.IP "always_set_home" 16 +.IX Item "always_set_home" +If enabled, \fBsudo\fR will set the \f(CW\*(C`HOME\*(C'\fR environment variable to the +home directory of the target user (which is root unless the \fB\-u\fR +option is used). This effectively means that the \fB\-H\fR option is +always implied. Note that \f(CW\*(C`HOME\*(C'\fR is already set when the the +\&\fIenv_reset\fR option is enabled, so \fIalways_set_home\fR is only +effective for configurations where either \fIenv_reset\fR is disabled +or \f(CW\*(C`HOME\*(C'\fR is present in the \fIenv_keep\fR list. +This flag is \fIoff\fR by default. +.IP "authenticate" 16 +.IX Item "authenticate" +If set, users must authenticate themselves via a password (or other +means of authentication) before they may run commands. This default +may be overridden via the \f(CW\*(C`PASSWD\*(C'\fR and \f(CW\*(C`NOPASSWD\*(C'\fR tags. +This flag is \fIon\fR by default. +.IP "closefrom_override" 16 +.IX Item "closefrom_override" +If set, the user may use \fBsudo\fR's \fB\-C\fR option which +overrides the default starting point at which \fBsudo\fR begins +closing open file descriptors. This flag is \fIoff\fR by default. +.IP "compress_io" 16 +.IX Item "compress_io" +If set, and \fBsudo\fR is configured to log a command's input or output, +the I/O logs will be compressed using \fBzlib\fR. This flag is \fIon\fR +by default when \fBsudo\fR is compiled with \fBzlib\fR support. +.IP "env_editor" 16 +.IX Item "env_editor" +If set, \fBvisudo\fR will use the value of the \s-1EDITOR\s0 or \s-1VISUAL\s0 +environment variables before falling back on the default editor list. +Note that this may create a security hole as it allows the user to +run any arbitrary command as root without logging. A safer alternative +is to place a colon-separated list of editors in the \f(CW\*(C`editor\*(C'\fR +variable. \fBvisudo\fR will then only use the \s-1EDITOR\s0 or \s-1VISUAL\s0 if +they match a value specified in \f(CW\*(C`editor\*(C'\fR. This flag is \fI@env_editor@\fR by +default. +.IP "env_reset" 16 +.IX Item "env_reset" +If set, \fBsudo\fR will run the command in a minimal environment +containing the \f(CW\*(C`TERM\*(C'\fR, \f(CW\*(C`PATH\*(C'\fR, \f(CW\*(C`HOME\*(C'\fR, \f(CW\*(C`MAIL\*(C'\fR, \f(CW\*(C`SHELL\*(C'\fR, +\&\f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR, \f(CW\*(C`USERNAME\*(C'\fR and \f(CW\*(C`SUDO_*\*(C'\fR variables. Any +variables in the caller's environment that match the \f(CW\*(C`env_keep\*(C'\fR +and \f(CW\*(C`env_check\*(C'\fR lists are then added, followed by any variables +present in the file specified by the \fIenv_file\fR option (if any). +The default contents of the \f(CW\*(C`env_keep\*(C'\fR and \f(CW\*(C`env_check\*(C'\fR lists are +displayed when \fBsudo\fR is run by root with the \fI\-V\fR option. If +the \fIsecure_path\fR option is set, its value will be used for the +\&\f(CW\*(C`PATH\*(C'\fR environment variable. This flag is \fI@env_reset@\fR by +default. +.IP "fast_glob" 16 +.IX Item "fast_glob" +Normally, \fBsudo\fR uses the \fIglob\fR\|(3) function to do shell-style +globbing when matching path names. However, since it accesses the +file system, \fIglob\fR\|(3) can take a long time to complete for some +patterns, especially when the pattern references a network file +system that is mounted on demand (automounted). The \fIfast_glob\fR +option causes \fBsudo\fR to use the \fIfnmatch\fR\|(3) function, which does +not access the file system to do its matching. The disadvantage +of \fIfast_glob\fR is that it is unable to match relative path names +such as \fI./ls\fR or \fI../bin/ls\fR. This has security implications +when path names that include globbing characters are used with the +negation operator, \f(CW\*(Aq!\*(Aq\fR, as such rules can be trivially bypassed. +As such, this option should not be used when \fIsudoers\fR contains rules +that contain negated path names which include globbing characters. +This flag is \fIoff\fR by default. +.IP "fqdn" 16 +.IX Item "fqdn" +Set this flag if you want to put fully qualified host names in the +\&\fIsudoers\fR file. I.e., instead of myhost you would use myhost.mydomain.edu. +You may still use the short form if you wish (and even mix the two). +Beware that turning on \fIfqdn\fR requires \fBsudo\fR to make \s-1DNS\s0 lookups +which may make \fBsudo\fR unusable if \s-1DNS\s0 stops working (for example +if the machine is not plugged into the network). Also note that +you must use the host's official name as \s-1DNS\s0 knows it. That is, +you may not use a host alias (\f(CW\*(C`CNAME\*(C'\fR entry) due to performance +issues and the fact that there is no way to get all aliases from +\&\s-1DNS\s0. If your machine's host name (as returned by the \f(CW\*(C`hostname\*(C'\fR +command) is already fully qualified you shouldn't need to set +\&\fIfqdn\fR. This flag is \fI@fqdn@\fR by default. +.IP "ignore_dot" 16 +.IX Item "ignore_dot" +If set, \fBsudo\fR will ignore '.' or '' (current dir) in the \f(CW\*(C`PATH\*(C'\fR +environment variable; the \f(CW\*(C`PATH\*(C'\fR itself is not modified. This +flag is \fI@ignore_dot@\fR by default. +.IP "ignore_local_sudoers" 16 +.IX Item "ignore_local_sudoers" +If set via \s-1LDAP\s0, parsing of \fI@sysconfdir@/sudoers\fR will be skipped. +This is intended for Enterprises that wish to prevent the usage of local +sudoers files so that only \s-1LDAP\s0 is used. This thwarts the efforts of +rogue operators who would attempt to add roles to \fI@sysconfdir@/sudoers\fR. +When this option is present, \fI@sysconfdir@/sudoers\fR does not even need to +exist. Since this option tells \fBsudo\fR how to behave when no specific \s-1LDAP\s0 +entries have been matched, this sudoOption is only meaningful for the +\&\f(CW\*(C`cn=defaults\*(C'\fR section. This flag is \fIoff\fR by default. +.IP "insults" 16 +.IX Item "insults" +If set, \fBsudo\fR will insult users when they enter an incorrect +password. This flag is \fI@insults@\fR by default. +.IP "log_host" 16 +.IX Item "log_host" +If set, the host name will be logged in the (non-syslog) \fBsudo\fR log file. +This flag is \fIoff\fR by default. +.IP "log_input" 16 +.IX Item "log_input" +If set, \fBsudo\fR will run the command in a \fIpseudo tty\fR and log all +user input. +If the standard input is not connected to the user's tty, due to +I/O redirection or because the command is part of a pipeline, that +input is also captured and stored in a separate log file. +.Sp +Input is logged to the directory specified by the \fIiolog_dir\fR +option (\fI@iolog_dir@\fR by default) using a unique session \s-1ID\s0 that +is included in the normal \fBsudo\fR log line, prefixed with \fITSID=\fR. +The \fIiolog_file\fR option may be used to control the format of the +session \s-1ID\s0. +.Sp +Note that user input may contain sensitive information such as +passwords (even if they are not echoed to the screen), which will +be stored in the log file unencrypted. In most cases, logging the +command output via \fIlog_output\fR is all that is required. +.IP "log_output" 16 +.IX Item "log_output" +If set, \fBsudo\fR will run the command in a \fIpseudo tty\fR and log all +output that is sent to the screen, similar to the \fIscript\fR\|(1) command. +If the standard output or standard error is not connected to the +user's tty, due to I/O redirection or because the command is part +of a pipeline, that output is also captured and stored in separate +log files. +.Sp +Output is logged to the directory specified by the \fIiolog_dir\fR +option (\fI@iolog_dir@\fR by default) using a unique session \s-1ID\s0 that +is included in the normal \fBsudo\fR log line, prefixed with \fITSID=\fR. +The \fIiolog_file\fR option may be used to control the format of the +session \s-1ID\s0. +.Sp +Output logs may be viewed with the \fIsudoreplay\fR\|(@mansectsu@) utility, which +can also be used to list or search the available logs. +.IP "log_year" 16 +.IX Item "log_year" +If set, the four-digit year will be logged in the (non-syslog) \fBsudo\fR log file. +This flag is \fIoff\fR by default. +.IP "long_otp_prompt" 16 +.IX Item "long_otp_prompt" +When validating with a One Time Password (\s-1OTP\s0) scheme such as +\&\fBS/Key\fR or \fB\s-1OPIE\s0\fR, a two-line prompt is used to make it easier +to cut and paste the challenge to a local window. It's not as +pretty as the default but some people find it more convenient. This +flag is \fI@long_otp_prompt@\fR by default. +.IP "mail_always" 16 +.IX Item "mail_always" +Send mail to the \fImailto\fR user every time a users runs \fBsudo\fR. +This flag is \fIoff\fR by default. +.IP "mail_badpass" 16 +.IX Item "mail_badpass" +Send mail to the \fImailto\fR user if the user running \fBsudo\fR does not +enter the correct password. This flag is \fIoff\fR by default. +.IP "mail_no_host" 16 +.IX Item "mail_no_host" +If set, mail will be sent to the \fImailto\fR user if the invoking +user exists in the \fIsudoers\fR file, but is not allowed to run +commands on the current host. This flag is \fI@mail_no_host@\fR by default. +.IP "mail_no_perms" 16 +.IX Item "mail_no_perms" +If set, mail will be sent to the \fImailto\fR user if the invoking +user is allowed to use \fBsudo\fR but the command they are trying is not +listed in their \fIsudoers\fR file entry or is explicitly denied. +This flag is \fI@mail_no_perms@\fR by default. +.IP "mail_no_user" 16 +.IX Item "mail_no_user" +If set, mail will be sent to the \fImailto\fR user if the invoking +user is not in the \fIsudoers\fR file. This flag is \fI@mail_no_user@\fR +by default. +.IP "noexec" 16 +.IX Item "noexec" +If set, all commands run via \fBsudo\fR will behave as if the \f(CW\*(C`NOEXEC\*(C'\fR +tag has been set, unless overridden by a \f(CW\*(C`EXEC\*(C'\fR tag. See the +description of \fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR below as well as the \*(L"Preventing Shell +Escapes\*(R" section at the end of this manual. This flag is \fIoff\fR by default. +.IP "path_info" 16 +.IX Item "path_info" +Normally, \fBsudo\fR will tell the user when a command could not be +found in their \f(CW\*(C`PATH\*(C'\fR environment variable. Some sites may wish +to disable this as it could be used to gather information on the +location of executables that the normal user does not have access +to. The disadvantage is that if the executable is simply not in +the user's \f(CW\*(C`PATH\*(C'\fR, \fBsudo\fR will tell the user that they are not +allowed to run it, which can be confusing. This flag is \fI@path_info@\fR +by default. +.IP "passprompt_override" 16 +.IX Item "passprompt_override" +The password prompt specified by \fIpassprompt\fR will normally only +be used if the password prompt provided by systems such as \s-1PAM\s0 matches +the string \*(L"Password:\*(R". If \fIpassprompt_override\fR is set, \fIpassprompt\fR +will always be used. This flag is \fIoff\fR by default. +.IP "preserve_groups" 16 +.IX Item "preserve_groups" +By default, \fBsudo\fR will initialize the group vector to the list of +groups the target user is in. When \fIpreserve_groups\fR is set, the +user's existing group vector is left unaltered. The real and +effective group IDs, however, are still set to match the target +user. This flag is \fIoff\fR by default. +.IP "pwfeedback" 16 +.IX Item "pwfeedback" +By default, \fBsudo\fR reads the password like most other Unix programs, +by turning off echo until the user hits the return (or enter) key. +Some users become confused by this as it appears to them that \fBsudo\fR +has hung at this point. When \fIpwfeedback\fR is set, \fBsudo\fR will +provide visual feedback when the user presses a key. Note that +this does have a security impact as an onlooker may be able to +determine the length of the password being entered. +This flag is \fIoff\fR by default. +.IP "requiretty" 16 +.IX Item "requiretty" +If set, \fBsudo\fR will only run when the user is logged in to a real +tty. When this flag is set, \fBsudo\fR can only be run from a login +session and not via other means such as \fIcron\fR\|(@mansectsu@) or cgi-bin scripts. +This flag is \fIoff\fR by default. +.IP "root_sudo" 16 +.IX Item "root_sudo" +If set, root is allowed to run \fBsudo\fR too. Disabling this prevents users +from \*(L"chaining\*(R" \fBsudo\fR commands to get a root shell by doing something +like \f(CW"sudo sudo /bin/sh"\fR. Note, however, that turning off \fIroot_sudo\fR +will also prevent root from running \fBsudoedit\fR. +Disabling \fIroot_sudo\fR provides no real additional security; it +exists purely for historical reasons. +This flag is \fI@root_sudo@\fR by default. +.IP "rootpw" 16 +.IX Item "rootpw" +If set, \fBsudo\fR will prompt for the root password instead of the password +of the invoking user. This flag is \fIoff\fR by default. +.IP "runaspw" 16 +.IX Item "runaspw" +If set, \fBsudo\fR will prompt for the password of the user defined by the +\&\fIrunas_default\fR option (defaults to \f(CW\*(C`@runas_default@\*(C'\fR) instead of the +password of the invoking user. This flag is \fIoff\fR by default. +.IP "set_home" 16 +.IX Item "set_home" +If enabled and \fBsudo\fR is invoked with the \fB\-s\fR option the \f(CW\*(C`HOME\*(C'\fR +environment variable will be set to the home directory of the target +user (which is root unless the \fB\-u\fR option is used). This effectively +makes the \fB\-s\fR option imply \fB\-H\fR. Note that \f(CW\*(C`HOME\*(C'\fR is already +set when the the \fIenv_reset\fR option is enabled, so \fIset_home\fR is +only effective for configurations where either \fIenv_reset\fR is disabled +or \f(CW\*(C`HOME\*(C'\fR is present in the \fIenv_keep\fR list. +This flag is \fIoff\fR by default. +.IP "set_logname" 16 +.IX Item "set_logname" +Normally, \fBsudo\fR will set the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR and \f(CW\*(C`USERNAME\*(C'\fR +environment variables to the name of the target user (usually root +unless the \fB\-u\fR option is given). However, since some programs +(including the \s-1RCS\s0 revision control system) use \f(CW\*(C`LOGNAME\*(C'\fR to +determine the real identity of the user, it may be desirable to +change this behavior. This can be done by negating the set_logname +option. Note that if the \fIenv_reset\fR option has not been disabled, +entries in the \fIenv_keep\fR list will override the value of +\&\fIset_logname\fR. This flag is \fIon\fR by default. +.IP "set_utmp" 16 +.IX Item "set_utmp" +When enabled, \fBsudo\fR will create an entry in the utmp (or utmpx) +file when a pseudo-tty is allocated. A pseudo-tty is allocated by +\&\fBsudo\fR when the \fIlog_input\fR, \fIlog_output\fR or \fIuse_pty\fR flags +are enabled. By default, the new entry will be a copy of the user's +existing utmp entry (if any), with the tty, time, type and pid +fields updated. This flag is \fIon\fR by default. +.IP "setenv" 16 +.IX Item "setenv" +Allow the user to disable the \fIenv_reset\fR option from the command +line via the \fB\-E\fR option. Additionally, environment variables set +via the command line are not subject to the restrictions imposed +by \fIenv_check\fR, \fIenv_delete\fR, or \fIenv_keep\fR. As such, only +trusted users should be allowed to set variables in this manner. +This flag is \fIoff\fR by default. +.IP "shell_noargs" 16 +.IX Item "shell_noargs" +If set and \fBsudo\fR is invoked with no arguments it acts as if the +\&\fB\-s\fR option had been given. That is, it runs a shell as root (the +shell is determined by the \f(CW\*(C`SHELL\*(C'\fR environment variable if it is +set, falling back on the shell listed in the invoking user's +/etc/passwd entry if not). This flag is \fIoff\fR by default. +.IP "stay_setuid" 16 +.IX Item "stay_setuid" +Normally, when \fBsudo\fR executes a command the real and effective +UIDs are set to the target user (root by default). This option +changes that behavior such that the real \s-1UID\s0 is left as the invoking +user's \s-1UID\s0. In other words, this makes \fBsudo\fR act as a setuid +wrapper. This can be useful on systems that disable some potentially +dangerous functionality when a program is run setuid. This option +is only effective on systems with either the \fIsetreuid()\fR or \fIsetresuid()\fR +function. This flag is \fIoff\fR by default. +.IP "targetpw" 16 +.IX Item "targetpw" +If set, \fBsudo\fR will prompt for the password of the user specified +by the \fB\-u\fR option (defaults to \f(CW\*(C`root\*(C'\fR) instead of the password +of the invoking user. In addition, the timestamp file name will +include the target user's name. Note that this flag precludes the +use of a uid not listed in the passwd database as an argument to +the \fB\-u\fR option. This flag is \fIoff\fR by default. +.IP "tty_tickets" 16 +.IX Item "tty_tickets" +If set, users must authenticate on a per-tty basis. With this flag +enabled, \fBsudo\fR will use a file named for the tty the user is +logged in on in the user's time stamp directory. If disabled, the +time stamp of the directory is used instead. This flag is +\&\fI@tty_tickets@\fR by default. +.IP "umask_override" 16 +.IX Item "umask_override" +If set, \fBsudo\fR will set the umask as specified by \fIsudoers\fR without +modification. This makes it possible to specify a more permissive +umask in \fIsudoers\fR than the user's own umask and matches historical +behavior. If \fIumask_override\fR is not set, \fBsudo\fR will set the +umask to be the union of the user's umask and what is specified in +\&\fIsudoers\fR. This flag is \fI@umask_override@\fR by default. +.if \n(LC \{\ +.IP "use_loginclass" 16 +.IX Item "use_loginclass" +If set, \fBsudo\fR will apply the defaults specified for the target user's +login class if one exists. Only available if \fBsudo\fR is configured with +the \-\-with\-logincap option. This flag is \fIoff\fR by default. +\} +.IP "use_pty" 16 +.IX Item "use_pty" +If set, \fBsudo\fR will run the command in a pseudo-pty even if no I/O +logging is being gone. A malicious program run under \fBsudo\fR could +conceivably fork a background process that retains to the user's +terminal device after the main program has finished executing. Use +of this option will make that impossible. This flag is \fIoff\fR by default. +.IP "utmp_runas" 16 +.IX Item "utmp_runas" +If set, \fBsudo\fR will store the name of the runas user when updating +the utmp (or utmpx) file. By default, \fBsudo\fR stores the name of +the invoking user. This flag is \fIoff\fR by default. +.IP "visiblepw" 16 +.IX Item "visiblepw" +By default, \fBsudo\fR will refuse to run if the user must enter a +password but it is not possible to disable echo on the terminal. +If the \fIvisiblepw\fR flag is set, \fBsudo\fR will prompt for a password +even when it would be visible on the screen. This makes it possible +to run things like \f(CW"rsh somehost sudo ls"\fR since \fIrsh\fR\|(1) does +not allocate a tty. This flag is \fIoff\fR by default. +.PP +\&\fBIntegers\fR: +.IP "closefrom" 16 +.IX Item "closefrom" +Before it executes a command, \fBsudo\fR will close all open file +descriptors other than standard input, standard output and standard +error (ie: file descriptors 0\-2). The \fIclosefrom\fR option can be used +to specify a different file descriptor at which to start closing. +The default is \f(CW3\fR. +.IP "passwd_tries" 16 +.IX Item "passwd_tries" +The number of tries a user gets to enter his/her password before +\&\fBsudo\fR logs the failure and exits. The default is \f(CW\*(C`@passwd_tries@\*(C'\fR. +.PP +\&\fBIntegers that can be used in a boolean context\fR: +.IP "loglinelen" 16 +.IX Item "loglinelen" +Number of characters per line for the file log. This value is used +to decide when to wrap lines for nicer log files. This has no +effect on the syslog log file, only the file log. The default is +\&\f(CW\*(C`@loglen@\*(C'\fR (use 0 or negate the option to disable word wrap). +.IP "passwd_timeout" 16 +.IX Item "passwd_timeout" +Number of minutes before the \fBsudo\fR password prompt times out, or +\&\f(CW0\fR for no timeout. The timeout may include a fractional component +if minute granularity is insufficient, for example \f(CW2.5\fR. The +default is \f(CW\*(C`@password_timeout@\*(C'\fR. +.IP "timestamp_timeout" 16 +.IX Item "timestamp_timeout" +Number of minutes that can elapse before \fBsudo\fR will ask for a +passwd again. The timeout may include a fractional component if +minute granularity is insufficient, for example \f(CW2.5\fR. The default +is \f(CW\*(C`@timeout@\*(C'\fR. Set this to \f(CW0\fR to always prompt for a password. +If set to a value less than \f(CW0\fR the user's timestamp will never +expire. This can be used to allow users to create or delete their +own timestamps via \f(CW\*(C`sudo \-v\*(C'\fR and \f(CW\*(C`sudo \-k\*(C'\fR respectively. +.IP "umask" 16 +.IX Item "umask" +Umask to use when running the command. Negate this option or set +it to 0777 to preserve the user's umask. The actual umask that is +used will be the union of the user's umask and the value of the +\&\fIumask\fR option, which defaults to \f(CW\*(C`@sudo_umask@\*(C'\fR. This guarantees +that \fBsudo\fR never lowers the umask when running a command. Note +on systems that use \s-1PAM\s0, the default \s-1PAM\s0 configuration may specify +its own umask which will override the value set in \fIsudoers\fR. +.PP +\&\fBStrings\fR: +.IP "badpass_message" 16 +.IX Item "badpass_message" +Message that is displayed if a user enters an incorrect password. +The default is \f(CW\*(C`@badpass_message@\*(C'\fR unless insults are enabled. +.IP "editor" 16 +.IX Item "editor" +A colon (':') separated list of editors allowed to be used with +\&\fBvisudo\fR. \fBvisudo\fR will choose the editor that matches the user's +\&\s-1EDITOR\s0 environment variable if possible, or the first editor in the +list that exists and is executable. The default is \f(CW"@editor@"\fR. +.IP "iolog_dir" 16 +.IX Item "iolog_dir" +The top-level directory to use when constructing the path name for +the input/output log directory. Only used if the \fIlog_input\fR or +\&\fIlog_output\fR options are enabled or when the \f(CW\*(C`LOG_INPUT\*(C'\fR or +\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR tags are present for a command. The session sequence +number, if any, is stored in the directory. +The default is \f(CW"@iolog_dir@"\fR. +.Sp +The following percent (`\f(CW\*(C`%\*(C'\fR') escape sequences are supported: +.RS 16 +.ie n .IP "\*(C`%{seq}\*(C'" 4 +.el .IP "\f(CW\*(C`%{seq}\*(C'\fR" 4 +.IX Item "%{seq}" +expanded to a monotonically increasing base\-36 sequence number, such as 0100A5, +where every two digits are used to form a new directory, e.g. \fI01/00/A5\fR +.ie n .IP "\*(C`%{user}\*(C'" 4 +.el .IP "\f(CW\*(C`%{user}\*(C'\fR" 4 +.IX Item "%{user}" +expanded to the invoking user's login name +.ie n .IP "\*(C`%{group}\*(C'" 4 +.el .IP "\f(CW\*(C`%{group}\*(C'\fR" 4 +.IX Item "%{group}" +expanded to the name of the invoking user's real group \s-1ID\s0 +.ie n .IP "\*(C`%{runas_user}\*(C'" 4 +.el .IP "\f(CW\*(C`%{runas_user}\*(C'\fR" 4 +.IX Item "%{runas_user}" +expanded to the login name of the user the command will +be run as (e.g. root) +.ie n .IP "\*(C`%{runas_group}\*(C'" 4 +.el .IP "\f(CW\*(C`%{runas_group}\*(C'\fR" 4 +.IX Item "%{runas_group}" +expanded to the group name of the user the command will +be run as (e.g. wheel) +.ie n .IP "\*(C`%{hostname}\*(C'" 4 +.el .IP "\f(CW\*(C`%{hostname}\*(C'\fR" 4 +.IX Item "%{hostname}" +expanded to the local host name without the domain name +.ie n .IP "\*(C`%{command}\*(C'" 4 +.el .IP "\f(CW\*(C`%{command}\*(C'\fR" 4 +.IX Item "%{command}" +expanded to the base name of the command being run +.RE +.RS 16 +.Sp +In addition, any escape sequences supported by the system's \fIstrftime()\fR +function will be expanded. +.Sp +To include a literal `\f(CW\*(C`%\*(C'\fR' character, the string `\f(CW\*(C`%%\*(C'\fR' should +be used. +.RE +.IP "iolog_file" 16 +.IX Item "iolog_file" +The path name, relative to \fIiolog_dir\fR, in which to store input/output +logs when the \fIlog_input\fR or \fIlog_output\fR options are enabled or +when the \f(CW\*(C`LOG_INPUT\*(C'\fR or \f(CW\*(C`LOG_OUTPUT\*(C'\fR tags are present for a command. +Note that \fIiolog_file\fR may contain directory components. +The default is \f(CW"%{seq}"\fR. +.Sp +See the \fIiolog_dir\fR option above for a list of supported percent +(`\f(CW\*(C`%\*(C'\fR') escape sequences. +.Sp +In addition to the escape sequences, path names that end in six or +more \f(CW\*(C`X\*(C'\fRs will have the \f(CW\*(C`X\*(C'\fRs replaced with a unique combination +of digits and letters, similar to the \fImktemp()\fR function. +.IP "mailsub" 16 +.IX Item "mailsub" +Subject of the mail sent to the \fImailto\fR user. The escape \f(CW%h\fR +will expand to the host name of the machine. +Default is \f(CW\*(C`@mailsub@\*(C'\fR. +.IP "noexec_file" 16 +.IX Item "noexec_file" +This option is no longer supported. The path to the noexec file +should now be set in the \fI@sysconfdir@/sudo.conf\fR file. +.IP "passprompt" 16 +.IX Item "passprompt" +The default prompt to use when asking for a password; can be overridden +via the \fB\-p\fR option or the \f(CW\*(C`SUDO_PROMPT\*(C'\fR environment variable. +The following percent (`\f(CW\*(C`%\*(C'\fR') escape sequences are supported: +.RS 16 +.ie n .IP "%H" 4 +.el .IP "\f(CW%H\fR" 4 +.IX Item "%H" +expanded to the local host name including the domain name +(only if the machine's host name is fully qualified or the \fIfqdn\fR +option is set) +.ie n .IP "%h" 4 +.el .IP "\f(CW%h\fR" 4 +.IX Item "%h" +expanded to the local host name without the domain name +.ie n .IP "%p" 4 +.el .IP "\f(CW%p\fR" 4 +.IX Item "%p" +expanded to the user whose password is being asked for (respects the +\&\fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in \fIsudoers\fR) +.ie n .IP "%U" 4 +.el .IP "\f(CW%U\fR" 4 +.IX Item "%U" +expanded to the login name of the user the command will +be run as (defaults to root) +.ie n .IP "%u" 4 +.el .IP "\f(CW%u\fR" 4 +.IX Item "%u" +expanded to the invoking user's login name +.ie n .IP "\*(C`%%\*(C'" 4 +.el .IP "\f(CW\*(C`%%\*(C'\fR" 4 +.IX Item "%%" +two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character +.RE +.RS 16 +.Sp +The default value is \f(CW\*(C`@passprompt@\*(C'\fR. +.RE +.if \n(SL \{\ +.IP "role" 16 +.IX Item "role" +The default SELinux role to use when constructing a new security +context to run the command. The default role may be overridden on +a per-command basis in \fIsudoers\fR or via command line options. +This option is only available whe \fBsudo\fR is built with SELinux support. +\} +.IP "runas_default" 16 +.IX Item "runas_default" +The default user to run commands as if the \fB\-u\fR option is not specified +on the command line. This defaults to \f(CW\*(C`@runas_default@\*(C'\fR. +.IP "syslog_badpri" 16 +.IX Item "syslog_badpri" +Syslog priority to use when user authenticates unsuccessfully. +Defaults to \f(CW\*(C`@badpri@\*(C'\fR. +.Sp +The following syslog priorities are supported: \fBalert\fR, \fBcrit\fR, +\&\fBdebug\fR, \fBemerg\fR, \fBerr\fR, \fBinfo\fR, \fBnotice\fR, and \fBwarning\fR. +.IP "syslog_goodpri" 16 +.IX Item "syslog_goodpri" +Syslog priority to use when user authenticates successfully. +Defaults to \f(CW\*(C`@goodpri@\*(C'\fR. +.Sp +See syslog_badpri for the list of supported syslog priorities. +.IP "sudoers_locale" 16 +.IX Item "sudoers_locale" +Locale to use when parsing the sudoers file, logging commands, and +sending email. Note that changing the locale may affect how sudoers +is interpreted. Defaults to \f(CW"C"\fR. +.IP "timestampdir" 16 +.IX Item "timestampdir" +The directory in which \fBsudo\fR stores its timestamp files. +The default is \fI@timedir@\fR. +.IP "timestampowner" 16 +.IX Item "timestampowner" +The owner of the timestamp directory and the timestamps stored therein. +The default is \f(CW\*(C`root\*(C'\fR. +.if \n(SL \{\ +.IP "type" 16 +.IX Item "type" +The default SELinux type to use when constructing a new security +context to run the command. The default type may be overridden on +a per-command basis in \fIsudoers\fR or via command line options. +This option is only available whe \fBsudo\fR is built with SELinux support. +\} +.PP +\&\fBStrings that can be used in a boolean context\fR: +.IP "env_file" 12 +.IX Item "env_file" +The \fIenv_file\fR option specifies the fully qualified path to a +file containing variables to be set in the environment of the program +being run. Entries in this file should either be of the form +\&\f(CW\*(C`VARIABLE=value\*(C'\fR or \f(CW\*(C`export VARIABLE=value\*(C'\fR. The value may +optionally be surrounded by single or double quotes. Variables in +this file are subject to other \fBsudo\fR environment settings such +as \fIenv_keep\fR and \fIenv_check\fR. +.IP "exempt_group" 12 +.IX Item "exempt_group" +Users in this group are exempt from password and \s-1PATH\s0 requirements. +The group name specified should not include a \f(CW\*(C`%\*(C'\fR prefix. +This is not set by default. +.IP "group_plugin" 12 +.IX Item "group_plugin" +A string containing a \fIsudoers\fR group plugin with optional arguments. +This can be used to implement support for the \f(CW\*(C`nonunix_group\*(C'\fR +syntax described earlier. The string should consist of the plugin +path, either fully-qualified or relative to the \fI@prefix@/libexec\fR +directory, followed by any configuration arguments the plugin +requires. These arguments (if any) will be passed to the plugin's +initialization function. If arguments are present, the string must +be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR). +.Sp +For example, given \fI/etc/sudo\-group\fR, a group file in Unix group +format, the sample group plugin can be used: +.Sp +.Vb 1 +\& Defaults group_plugin="sample_group.so /etc/sudo\-group" +.Ve +.Sp +For more information see \fIsudo_plugin\fR\|(@mansectform@). +.IP "lecture" 12 +.IX Item "lecture" +This option controls when a short lecture will be printed along with +the password prompt. It has the following possible values: +.RS 12 +.IP "always" 8 +.IX Item "always" +Always lecture the user. +.IP "never" 8 +.IX Item "never" +Never lecture the user. +.IP "once" 8 +.IX Item "once" +Only lecture the user the first time they run \fBsudo\fR. +.RE +.RS 12 +.Sp +If no value is specified, a value of \fIonce\fR is implied. +Negating the option results in a value of \fInever\fR being used. +The default value is \fI@lecture@\fR. +.RE +.IP "lecture_file" 12 +.IX Item "lecture_file" +Path to a file containing an alternate \fBsudo\fR lecture that will +be used in place of the standard lecture if the named file exists. +By default, \fBsudo\fR uses a built-in lecture. +.IP "listpw" 12 +.IX Item "listpw" +This option controls when a password will be required when a +user runs \fBsudo\fR with the \fB\-l\fR option. It has the following possible values: +.RS 12 +.IP "all" 8 +.IX Item "all" +All the user's \fIsudoers\fR entries for the current host must have +the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. +.IP "always" 8 +.IX Item "always" +The user must always enter a password to use the \fB\-l\fR option. +.IP "any" 8 +.IX Item "any" +At least one of the user's \fIsudoers\fR entries for the current host +must have the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. +.IP "never" 8 +.IX Item "never" +The user need never enter a password to use the \fB\-l\fR option. +.RE +.RS 12 +.Sp +If no value is specified, a value of \fIany\fR is implied. +Negating the option results in a value of \fInever\fR being used. +The default value is \fIany\fR. +.RE +.IP "logfile" 12 +.IX Item "logfile" +Path to the \fBsudo\fR log file (not the syslog log file). Setting a path +turns on logging to a file; negating this option turns it off. +By default, \fBsudo\fR logs via syslog. +.IP "mailerflags" 12 +.IX Item "mailerflags" +Flags to use when invoking mailer. Defaults to \fB\-t\fR. +.IP "mailerpath" 12 +.IX Item "mailerpath" +Path to mail program used to send warning mail. +Defaults to the path to sendmail found at configure time. +.IP "mailfrom" 12 +.IX Item "mailfrom" +Address to use for the \*(L"from\*(R" address when sending warning and error +mail. The address should be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR) to +protect against \fBsudo\fR interpreting the \f(CW\*(C`@\*(C'\fR sign. Defaults to +the name of the user running \fBsudo\fR. +.IP "mailto" 12 +.IX Item "mailto" +Address to send warning and error mail to. The address should +be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR) to protect against \fBsudo\fR +interpreting the \f(CW\*(C`@\*(C'\fR sign. Defaults to \f(CW\*(C`@mailto@\*(C'\fR. +.IP "secure_path" 12 +.IX Item "secure_path" +Path used for every command run from \fBsudo\fR. If you don't trust the +people running \fBsudo\fR to have a sane \f(CW\*(C`PATH\*(C'\fR environment variable you may +want to use this. Another use is if you want to have the \*(L"root path\*(R" +be separate from the \*(L"user path.\*(R" Users in the group specified by the +\&\fIexempt_group\fR option are not affected by \fIsecure_path\fR. +This option is @secure_path@ by default. +.IP "syslog" 12 +.IX Item "syslog" +Syslog facility if syslog is being used for logging (negate to +disable syslog logging). Defaults to \f(CW\*(C`@logfac@\*(C'\fR. +.Sp +The following syslog facilities are supported: \fBauthpriv\fR (if your +\&\s-1OS\s0 supports it), \fBauth\fR, \fBdaemon\fR, \fBuser\fR, \fBlocal0\fR, \fBlocal1\fR, +\&\fBlocal2\fR, \fBlocal3\fR, \fBlocal4\fR, \fBlocal5\fR, \fBlocal6\fR, and \fBlocal7\fR. +.IP "verifypw" 12 +.IX Item "verifypw" +This option controls when a password will be required when a user runs +\&\fBsudo\fR with the \fB\-v\fR option. It has the following possible values: +.RS 12 +.IP "all" 8 +.IX Item "all" +All the user's \fIsudoers\fR entries for the current host must have +the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. +.IP "always" 8 +.IX Item "always" +The user must always enter a password to use the \fB\-v\fR option. +.IP "any" 8 +.IX Item "any" +At least one of the user's \fIsudoers\fR entries for the current host +must have the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. +.IP "never" 8 +.IX Item "never" +The user need never enter a password to use the \fB\-v\fR option. +.RE +.RS 12 +.Sp +If no value is specified, a value of \fIall\fR is implied. +Negating the option results in a value of \fInever\fR being used. +The default value is \fIall\fR. +.RE +.PP +\&\fBLists that can be used in a boolean context\fR: +.IP "env_check" 16 +.IX Item "env_check" +Environment variables to be removed from the user's environment if +the variable's value contains \f(CW\*(C`%\*(C'\fR or \f(CW\*(C`/\*(C'\fR characters. This can +be used to guard against printf-style format vulnerabilities in +poorly-written programs. The argument may be a double-quoted, +space-separated list or a single value without double-quotes. The +list can be replaced, added to, deleted from, or disabled by using +the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and \f(CW\*(C`!\*(C'\fR operators respectively. Regardless +of whether the \f(CW\*(C`env_reset\*(C'\fR option is enabled or disabled, variables +specified by \f(CW\*(C`env_check\*(C'\fR will be preserved in the environment if +they pass the aforementioned check. The default list of environment +variables to check is displayed when \fBsudo\fR is run by root with +the \fI\-V\fR option. +.IP "env_delete" 16 +.IX Item "env_delete" +Environment variables to be removed from the user's environment +when the \fIenv_reset\fR option is not in effect. The argument may +be a double-quoted, space-separated list or a single value without +double-quotes. The list can be replaced, added to, deleted from, +or disabled by using the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and \f(CW\*(C`!\*(C'\fR operators +respectively. The default list of environment variables to remove +is displayed when \fBsudo\fR is run by root with the \fI\-V\fR option. +Note that many operating systems will remove potentially dangerous +variables from the environment of any setuid process (such as +\&\fBsudo\fR). +.IP "env_keep" 16 +.IX Item "env_keep" +Environment variables to be preserved in the user's environment +when the \fIenv_reset\fR option is in effect. This allows fine-grained +control over the environment \fBsudo\fR\-spawned processes will receive. +The argument may be a double-quoted, space-separated list or a +single value without double-quotes. The list can be replaced, added +to, deleted from, or disabled by using the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and +\&\f(CW\*(C`!\*(C'\fR operators respectively. The default list of variables to keep +is displayed when \fBsudo\fR is run by root with the \fI\-V\fR option. +.SH "SUDO.CONF" +.IX Header "SUDO.CONF" +The \fI@sysconfdir@/sudo.conf\fR file determines which plugins the +\&\fBsudo\fR front end will load. If no \fI@sysconfdir@/sudo.conf\fR file +is present, or it contains no \f(CW\*(C`Plugin\*(C'\fR lines, \fBsudo\fR will use the +\&\fIsudoers\fR security policy and I/O logging, which corresponds to +the following \fI@sysconfdir@/sudo.conf\fR file. +.PP +.Vb 10 +\& # +\& # Default @sysconfdir@/sudo.conf file +\& # +\& # Format: +\& # Plugin plugin_name plugin_path plugin_options ... +\& # Path askpass /path/to/askpass +\& # Path noexec /path/to/sudo_noexec.so +\& # Debug sudo /var/log/sudo_debug all@warn +\& # Set disable_coredump true +\& # +\& # The plugin_path is relative to @prefix@/libexec unless +\& # fully qualified. +\& # The plugin_name corresponds to a global symbol in the plugin +\& # that contains the plugin interface structure. +\& # The plugin_options are optional. +\& # +\& Plugin policy_plugin sudoers.so +\& Plugin io_plugin sudoers.so +.Ve +.SS "\s-1PLUGIN\s0 \s-1OPTIONS\s0" +.IX Subsection "PLUGIN OPTIONS" +Starting with \fBsudo\fR 1.8.5 it is possible to pass options to the +\&\fIsudoers\fR plugin. Options may be listed after the path to the +plugin (i.e. after \fIsudoers.so\fR); multiple options should be +space-separated. For example: +.PP +.Vb 1 +\& Plugin sudoers_policy sudoers.so sudoers_file=/etc/sudoers sudoers_uid=0 sudoers_gid=0 sudoers_mode=0440 +.Ve +.PP +The following plugin options are supported: +.IP "sudoers_file=pathname" 10 +.IX Item "sudoers_file=pathname" +The \fIsudoers_file\fR option can be used to override the default path +to the \fIsudoers\fR file. +.IP "sudoers_uid=uid" 10 +.IX Item "sudoers_uid=uid" +The \fIsudoers_uid\fR option can be used to override the default owner +of the sudoers file. It should be specified as a numeric user \s-1ID\s0. +.IP "sudoers_gid=gid" 10 +.IX Item "sudoers_gid=gid" +The \fIsudoers_gid\fR option can be used to override the default group +of the sudoers file. It should be specified as a numeric group \s-1ID\s0. +.IP "sudoers_mode=mode" 10 +.IX Item "sudoers_mode=mode" +The \fIsudoers_mode\fR option can be used to override the default file +mode for the sudoers file. It should be specified as an octal value. +.SS "\s-1DEBUG\s0 \s-1FLAGS\s0" +.IX Subsection "DEBUG FLAGS" +Versions 1.8.4 and higher of the \fIsudoers\fR plugin supports a +debugging framework that can help track down what the plugin is +doing internally if there is a problem. This can be configured in +the \fI@sysconfdir@/sudo.conf\fR file as described in \fIsudo\fR\|(@mansectsu@). +.PP +The \fIsudoers\fR plugin uses the same debug flag format as \fBsudo\fR +itself: \fIsubsystem\fR@\fIpriority\fR. +.PP +The priorities used by \fIsudoers\fR, in order of decreasing severity, +are: \fIcrit\fR, \fIerr\fR, \fIwarn\fR, \fInotice\fR, \fIdiag\fR, \fIinfo\fR, \fItrace\fR +and \fIdebug\fR. Each priority, when specified, also includes all +priorities higher than it. For example, a priority of \fInotice\fR +would include debug messages logged at \fInotice\fR and higher. +.PP +The following subsystems are used by \fIsudoers\fR: +.IP "\fIalias\fR" 10 +.IX Item "alias" +\&\f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, \f(CW\*(C`Host_Alias\*(C'\fR and \f(CW\*(C`Cmnd_Alias\*(C'\fR processing +.IP "\fIall\fR" 10 +.IX Item "all" +matches every subsystem +.IP "\fIaudit\fR" 10 +.IX Item "audit" +\&\s-1BSM\s0 and Linux audit code +.IP "\fIauth\fR" 10 +.IX Item "auth" +user authentication +.IP "\fIdefaults\fR" 10 +.IX Item "defaults" +\&\fIsudoers\fR \fIDefaults\fR settings +.IP "\fIenv\fR" 10 +.IX Item "env" +environment handling +.IP "\fIldap\fR" 10 +.IX Item "ldap" +LDAP-based sudoers +.IP "\fIlogging\fR" 10 +.IX Item "logging" +logging support +.IP "\fImatch\fR" 10 +.IX Item "match" +matching of users, groups, hosts and netgroups in \fIsudoers\fR +.IP "\fInetif\fR" 10 +.IX Item "netif" +network interface handling +.IP "\fInss\fR" 10 +.IX Item "nss" +network service switch handling in \fIsudoers\fR +.IP "\fIparser\fR" 10 +.IX Item "parser" +\&\fIsudoers\fR file parsing +.IP "\fIperms\fR" 10 +.IX Item "perms" +permission setting +.IP "\fIplugin\fR" 10 +.IX Item "plugin" +The equivalent of \fImain\fR for the plugin. +.IP "\fIpty\fR" 10 +.IX Item "pty" +pseudo-tty related code +.IP "\fIrbtree\fR" 10 +.IX Item "rbtree" +redblack tree internals +.IP "\fIutil\fR" 10 +.IX Item "util" +utility functions +.SH "FILES" +.IX Header "FILES" +.ie n .IP "\fI@sysconfdir@/sudo.conf\fR" 24 +.el .IP "\fI@sysconfdir@/sudo.conf\fR" 24 +.IX Item "@sysconfdir@/sudo.conf" +Sudo front end configuration +.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24 +.el .IP "\fI@sysconfdir@/sudoers\fR" 24 +.IX Item "@sysconfdir@/sudoers" +List of who can run what +.IP "\fI/etc/group\fR" 24 +.IX Item "/etc/group" +Local groups file +.IP "\fI/etc/netgroup\fR" 24 +.IX Item "/etc/netgroup" +List of network groups +.ie n .IP "\fI@iolog_dir@\fR" 24 +.el .IP "\fI@iolog_dir@\fR" 24 +.IX Item "@iolog_dir@" +I/O log files +.ie n .IP "\fI@timedir@\fR" 24 +.el .IP "\fI@timedir@\fR" 24 +.IX Item "@timedir@" +Directory containing time stamps for the \fIsudoers\fR security policy +.IP "\fI/etc/environment\fR" 24 +.IX Item "/etc/environment" +Initial environment for \fB\-i\fR mode on \s-1AIX\s0 and Linux systems +.SH "EXAMPLES" +.IX Header "EXAMPLES" +Below are example \fIsudoers\fR entries. Admittedly, some of +these are a bit contrived. First, we allow a few environment +variables to pass and then define our \fIaliases\fR: +.PP +.Vb 4 +\& # Run X applications through sudo; HOME is used to find the +\& # .Xauthority file. Note that other programs use HOME to find +\& # configuration files and this may lead to privilege escalation! +\& Defaults env_keep += "DISPLAY HOME" +\& +\& # User alias specification +\& User_Alias FULLTIMERS = millert, mikef, dowdy +\& User_Alias PARTTIMERS = bostley, jwfox, crawl +\& User_Alias WEBMASTERS = will, wendy, wim +\& +\& # Runas alias specification +\& Runas_Alias OP = root, operator +\& Runas_Alias DB = oracle, sybase +\& Runas_Alias ADMINGRP = adm, oper +\& +\& # Host alias specification +\& Host_Alias SPARC = bigtime, eclipse, moet, anchor :\e +\& SGI = grolsch, dandelion, black :\e +\& ALPHA = widget, thalamus, foobar :\e +\& HPPA = boa, nag, python +\& Host_Alias CUNETS = 128.138.0.0/255.255.0.0 +\& Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 +\& Host_Alias SERVERS = master, mail, www, ns +\& Host_Alias CDROM = orion, perseus, hercules +\& +\& # Cmnd alias specification +\& Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e +\& /usr/sbin/restore, /usr/sbin/rrestore +\& Cmnd_Alias KILL = /usr/bin/kill +\& Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm +\& Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown +\& Cmnd_Alias HALT = /usr/sbin/halt +\& Cmnd_Alias REBOOT = /usr/sbin/reboot +\& Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \e +\& /usr/local/bin/tcsh, /usr/bin/rsh, \e +\& /usr/local/bin/zsh +\& Cmnd_Alias SU = /usr/bin/su +\& Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less +.Ve +.PP +Here we override some of the compiled in default values. We want +\&\fBsudo\fR to log via \fIsyslog\fR\|(3) using the \fIauth\fR facility in all +cases. We don't want to subject the full time staff to the \fBsudo\fR +lecture, user \fBmillert\fR need not give a password, and we don't +want to reset the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR or \f(CW\*(C`USERNAME\*(C'\fR environment +variables when running commands as root. Additionally, on the +machines in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, we keep an additional +local log file and make sure we log the year in each log line since +the log entries will be kept around for several years. Lastly, we +disable shell escapes for the commands in the \s-1PAGERS\s0 \f(CW\*(C`Cmnd_Alias\*(C'\fR +(\fI/usr/bin/more\fR, \fI/usr/bin/pg\fR and \fI/usr/bin/less\fR). +.PP +.Vb 7 +\& # Override built\-in defaults +\& Defaults syslog=auth +\& Defaults>root !set_logname +\& Defaults:FULLTIMERS !lecture +\& Defaults:millert !authenticate +\& Defaults@SERVERS log_year, logfile=/var/log/sudo.log +\& Defaults!PAGERS noexec +.Ve +.PP +The \fIUser specification\fR is the part that actually determines who may +run what. +.PP +.Vb 2 +\& root ALL = (ALL) ALL +\& %wheel ALL = (ALL) ALL +.Ve +.PP +We let \fBroot\fR and any user in group \fBwheel\fR run any command on any +host as any user. +.PP +.Vb 1 +\& FULLTIMERS ALL = NOPASSWD: ALL +.Ve +.PP +Full time sysadmins (\fBmillert\fR, \fBmikef\fR, and \fBdowdy\fR) may run any +command on any host without authenticating themselves. +.PP +.Vb 1 +\& PARTTIMERS ALL = ALL +.Ve +.PP +Part time sysadmins (\fBbostley\fR, \fBjwfox\fR, and \fBcrawl\fR) may run any +command on any host but they must authenticate themselves first +(since the entry lacks the \f(CW\*(C`NOPASSWD\*(C'\fR tag). +.PP +.Vb 1 +\& jack CSNETS = ALL +.Ve +.PP +The user \fBjack\fR may run any command on the machines in the \fI\s-1CSNETS\s0\fR alias +(the networks \f(CW128.138.243.0\fR, \f(CW128.138.204.0\fR, and \f(CW128.138.242.0\fR). +Of those networks, only \f(CW128.138.204.0\fR has an explicit netmask (in +\&\s-1CIDR\s0 notation) indicating it is a class C network. For the other +networks in \fI\s-1CSNETS\s0\fR, the local machine's netmask will be used +during matching. +.PP +.Vb 1 +\& lisa CUNETS = ALL +.Ve +.PP +The user \fBlisa\fR may run any command on any host in the \fI\s-1CUNETS\s0\fR alias +(the class B network \f(CW128.138.0.0\fR). +.PP +.Vb 2 +\& operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\e +\& sudoedit /etc/printcap, /usr/oper/bin/ +.Ve +.PP +The \fBoperator\fR user may run commands limited to simple maintenance. +Here, those are commands related to backups, killing processes, the +printing system, shutting down the system, and any commands in the +directory \fI/usr/oper/bin/\fR. +.PP +.Vb 1 +\& joe ALL = /usr/bin/su operator +.Ve +.PP +The user \fBjoe\fR may only \fIsu\fR\|(1) to operator. +.PP +.Vb 1 +\& pete HPPA = /usr/bin/passwd [A\-Za\-z]*, !/usr/bin/passwd root +\& +\& %opers ALL = (: ADMINGRP) /usr/sbin/ +.Ve +.PP +Users in the \fBopers\fR group may run commands in \fI/usr/sbin/\fR as themselves +with any group in the \fI\s-1ADMINGRP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (the \fBadm\fR and \fBoper\fR +groups). +.PP +The user \fBpete\fR is allowed to change anyone's password except for +root on the \fI\s-1HPPA\s0\fR machines. Note that this assumes \fIpasswd\fR\|(1) +does not take multiple user names on the command line. +.PP +.Vb 1 +\& bob SPARC = (OP) ALL : SGI = (OP) ALL +.Ve +.PP +The user \fBbob\fR may run anything on the \fI\s-1SPARC\s0\fR and \fI\s-1SGI\s0\fR machines +as any user listed in the \fI\s-1OP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (\fBroot\fR and \fBoperator\fR). +.PP +.Vb 1 +\& jim +biglab = ALL +.Ve +.PP +The user \fBjim\fR may run any command on machines in the \fIbiglab\fR netgroup. +\&\fBsudo\fR knows that \*(L"biglab\*(R" is a netgroup due to the '+' prefix. +.PP +.Vb 1 +\& +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser +.Ve +.PP +Users in the \fBsecretaries\fR netgroup need to help manage the printers +as well as add and remove users, so they are allowed to run those +commands on all machines. +.PP +.Vb 1 +\& fred ALL = (DB) NOPASSWD: ALL +.Ve +.PP +The user \fBfred\fR can run commands as any user in the \fI\s-1DB\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR +(\fBoracle\fR or \fBsybase\fR) without giving a password. +.PP +.Vb 1 +\& john ALPHA = /usr/bin/su [!\-]*, !/usr/bin/su *root* +.Ve +.PP +On the \fI\s-1ALPHA\s0\fR machines, user \fBjohn\fR may su to anyone except root +but he is not allowed to specify any options to the \fIsu\fR\|(1) command. +.PP +.Vb 1 +\& jen ALL, !SERVERS = ALL +.Ve +.PP +The user \fBjen\fR may run any command on any machine except for those +in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR (master, mail, www and ns). +.PP +.Vb 1 +\& jill SERVERS = /usr/bin/, !SU, !SHELLS +.Ve +.PP +For any machine in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, \fBjill\fR may run +any commands in the directory \fI/usr/bin/\fR except for those commands +belonging to the \fI\s-1SU\s0\fR and \fI\s-1SHELLS\s0\fR \f(CW\*(C`Cmnd_Aliases\*(C'\fR. +.PP +.Vb 1 +\& steve CSNETS = (operator) /usr/local/op_commands/ +.Ve +.PP +The user \fBsteve\fR may run any command in the directory /usr/local/op_commands/ +but only as user operator. +.PP +.Vb 1 +\& matt valkyrie = KILL +.Ve +.PP +On his personal workstation, valkyrie, \fBmatt\fR needs to be able to +kill hung processes. +.PP +.Vb 1 +\& WEBMASTERS www = (www) ALL, (root) /usr/bin/su www +.Ve +.PP +On the host www, any user in the \fI\s-1WEBMASTERS\s0\fR \f(CW\*(C`User_Alias\*(C'\fR (will, +wendy, and wim), may run any command as user www (which owns the +web pages) or simply \fIsu\fR\|(1) to www. +.PP +.Vb 2 +\& ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\e +\& /sbin/mount \-o nosuid\e,nodev /dev/cd0a /CDROM +.Ve +.PP +Any user may mount or unmount a CD-ROM on the machines in the \s-1CDROM\s0 +\&\f(CW\*(C`Host_Alias\*(C'\fR (orion, perseus, hercules) without entering a password. +This is a bit tedious for users to type, so it is a prime candidate +for encapsulating in a shell script. +.SH "SECURITY NOTES" +.IX Header "SECURITY NOTES" +.SS "Limitations of the '!' operator" +.IX Subsection "Limitations of the '!' operator" +It is generally not effective to \*(L"subtract\*(R" commands from \f(CW\*(C`ALL\*(C'\fR +using the '!' operator. A user can trivially circumvent this +by copying the desired command to a different name and then +executing that. For example: +.PP +.Vb 1 +\& bill ALL = ALL, !SU, !SHELLS +.Ve +.PP +Doesn't really prevent \fBbill\fR from running the commands listed in +\&\fI\s-1SU\s0\fR or \fI\s-1SHELLS\s0\fR since he can simply copy those commands to a +different name, or use a shell escape from an editor or other +program. Therefore, these kind of restrictions should be considered +advisory at best (and reinforced by policy). +.PP +In general, if a user has sudo \f(CW\*(C`ALL\*(C'\fR there is nothing to prevent +them from creating their own program that gives them a root shell +(or making their own copy of a shell) regardless of any '!' elements +in the user specification. +.SS "Security implications of \fIfast_glob\fP" +.IX Subsection "Security implications of fast_glob" +If the \fIfast_glob\fR option is in use, it is not possible +to reliably negate commands where the path name includes globbing +(aka wildcard) characters. This is because the C library's +\&\fIfnmatch\fR\|(3) function cannot resolve relative paths. While this +is typically only an inconvenience for rules that grant privileges, +it can result in a security issue for rules that subtract or revoke +privileges. +.PP +For example, given the following \fIsudoers\fR entry: +.PP +.Vb 2 +\& john ALL = /usr/bin/passwd [a\-zA\-Z0\-9]*, /usr/bin/chsh [a\-zA\-Z0\-9]*, +\& /usr/bin/chfn [a\-zA\-Z0\-9]*, !/usr/bin/* root +.Ve +.PP +User \fBjohn\fR can still run \f(CW\*(C`/usr/bin/passwd root\*(C'\fR if \fIfast_glob\fR is +enabled by changing to \fI/usr/bin\fR and running \f(CW\*(C`./passwd root\*(C'\fR instead. +.SS "Preventing Shell Escapes" +.IX Subsection "Preventing Shell Escapes" +Once \fBsudo\fR executes a program, that program is free to do whatever +it pleases, including run other programs. This can be a security +issue since it is not uncommon for a program to allow shell escapes, +which lets a user bypass \fBsudo\fR's access control and logging. +Common programs that permit shell escapes include shells (obviously), +editors, paginators, mail and terminal programs. +.PP +There are two basic approaches to this problem: +.IP "restrict" 10 +.IX Item "restrict" +Avoid giving users access to commands that allow the user to run +arbitrary commands. Many editors have a restricted mode where shell +escapes are disabled, though \fBsudoedit\fR is a better solution to +running editors via \fBsudo\fR. Due to the large number of programs that +offer shell escapes, restricting users to the set of programs that +do not is often unworkable. +.IP "noexec" 10 +.IX Item "noexec" +Many systems that support shared libraries have the ability to +override default library functions by pointing an environment +variable (usually \f(CW\*(C`LD_PRELOAD\*(C'\fR) to an alternate shared library. +On such systems, \fBsudo\fR's \fInoexec\fR functionality can be used to +prevent a program run by \fBsudo\fR from executing any other programs. +Note, however, that this applies only to native dynamically-linked +executables. Statically-linked executables and foreign executables +running under binary emulation are not affected. +.Sp +The \fInoexec\fR feature is known to work on SunOS, Solaris, *BSD, +Linux, \s-1IRIX\s0, Tru64 \s-1UNIX\s0, MacOS X, HP-UX 11.x and \s-1AIX\s0 5.3 and above. +It should be supported on most operating systems that support the +\&\f(CW\*(C`LD_PRELOAD\*(C'\fR environment variable. Check your operating system's +manual pages for the dynamic linker (usually ld.so, ld.so.1, dyld, +dld.sl, rld, or loader) to see if \f(CW\*(C`LD_PRELOAD\*(C'\fR is supported. +.Sp +On Solaris 10 and higher, \fInoexec\fR uses Solaris privileges instead +of the \f(CW\*(C`LD_PRELOAD\*(C'\fR environment variable. +.Sp +To enable \fInoexec\fR for a command, use the \f(CW\*(C`NOEXEC\*(C'\fR tag as documented +in the User Specification section above. Here is that example again: +.Sp +.Vb 1 +\& aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi +.Ve +.Sp +This allows user \fBaaron\fR to run \fI/usr/bin/more\fR and \fI/usr/bin/vi\fR +with \fInoexec\fR enabled. This will prevent those two commands from +executing other commands (such as a shell). If you are unsure +whether or not your system is capable of supporting \fInoexec\fR you +can always just try it out and check whether shell escapes work +when \fInoexec\fR is enabled. +.PP +Note that restricting shell escapes is not a panacea. Programs +running as root are still capable of many potentially hazardous +operations (such as changing or overwriting files) that could lead +to unintended privilege escalation. In the specific case of an +editor, a safer approach is to give the user permission to run +\&\fBsudoedit\fR. +.SS "Time stamp file checks" +.IX Subsection "Time stamp file checks" +\&\fIsudoers\fR will check the ownership of its time stamp directory +(\fI@timedir@\fR by default) and ignore the directory's contents if +it is not owned by root or if it is writable by a user other than +root. On systems that allow non-root users to give away files via +\&\fIchown\fR\|(2), if the time stamp directory is located in a world-writable +directory (e.g., \fI/tmp\fR), it is possible for a user to create the +time stamp directory before \fBsudo\fR is run. However, because +\&\fIsudoers\fR checks the ownership and mode of the directory and its +contents, the only damage that can be done is to \*(L"hide\*(R" files by +putting them in the time stamp dir. This is unlikely to happen +since once the time stamp dir is owned by root and inaccessible by +any other user, the user placing files there would be unable to get +them back out. +.PP +\&\fIsudoers\fR will not honor time stamps set far in the future. Time +stamps with a date greater than current_time + 2 * \f(CW\*(C`TIMEOUT\*(C'\fR will +be ignored and sudo will log and complain. This is done to keep a +user from creating his/her own time stamp with a bogus date on +systems that allow users to give away files if the time stamp directory +is located in a world-writable directory. +.PP +On systems where the boot time is available, \fIsudoers\fR will ignore +time stamps that date from before the machine booted. +.PP +Since time stamp files live in the file system, they can outlive a +user's login session. As a result, a user may be able to login, +run a command with \fBsudo\fR after authenticating, logout, login +again, and run \fBsudo\fR without authenticating so long as the time +stamp file's modification time is within \f(CW\*(C`@timeout@\*(C'\fR minutes (or +whatever the timeout is set to in \fIsudoers\fR). When the \fItty_tickets\fR +option is enabled, the time stamp has per-tty granularity but still +may outlive the user's session. On Linux systems where the devpts +filesystem is used, Solaris systems with the devices filesystem, +as well as other systems that utilize a devfs filesystem that +monotonically increase the inode number of devices as they are +created (such as Mac \s-1OS\s0 X), \fIsudoers\fR is able to determine when a +tty-based time stamp file is stale and will ignore it. Administrators +should not rely on this feature as it is not universally available. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIrsh\fR\|(1), \fIsu\fR\|(1), \fIfnmatch\fR\|(3), \fIglob\fR\|(3), \fImktemp\fR\|(3), \fIstrftime\fR\|(3), +\&\fIsudoers.ldap\fR\|(@mansectform@), \fIsudo_plugin\fR\|(@mansectsu@), \fIsudo\fR\|(@mansectsu@), \fIvisudo\fR\|(@mansectsu@) +.SH "CAVEATS" +.IX Header "CAVEATS" +The \fIsudoers\fR file should \fBalways\fR be edited by the \fBvisudo\fR +command which locks the file and does grammatical checking. It is +imperative that \fIsudoers\fR be free of syntax errors since \fBsudo\fR +will not run with a syntactically incorrect \fIsudoers\fR file. +.PP +When using netgroups of machines (as opposed to users), if you +store fully qualified host name in the netgroup (as is usually the +case), you either need to have the machine's host name be fully qualified +as returned by the \f(CW\*(C`hostname\*(C'\fR command or use the \fIfqdn\fR option in +\&\fIsudoers\fR. +.SH "BUGS" +.IX Header "BUGS" +If you feel you have found a bug in \fBsudo\fR, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ +.SH "SUPPORT" +.IX Header "SUPPORT" +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or +search the archives. +.SH "DISCLAIMER" +.IX Header "DISCLAIMER" +\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 +file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudoers.man.pl b/doc/sudoers.man.pl new file mode 100644 index 0000000..6e5da2c --- /dev/null +++ b/doc/sudoers.man.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl -p + +BEGIN { + $cond = -1; +} + +# Initialize the numeric register we use for conditionals +if ($cond == -1) { + $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.\\\"\n$_"; + $cond = 0; +} + +# Make SELinux_Spec conditional +if (/(.*)SELinux_Spec\? (.*)$/) { + $_ = ".ie \\n(SL $_.el $1$2\n"; +} elsif (/^(.*SELinux_Spec ::=)/) { + $_ = ".if \\n(SL \\{\\\n$_"; +} elsif (/^(.*Tag_Spec ::=)/) { + $_ = "\\}\n$_"; +} + +if (/^\.S[Sh] "SELinux_Spec"/) { + $_ = ".if \\n(SL \\{\\\n$_"; + $cond = 1; +} elsif (/^\.IP "(role|type)"/) { + $_ = ".if \\n(SL \\{\\\n$_"; + $cond = 1; +} elsif (/^\.IP "use_loginclass"/) { + $_ = ".if \\n(LC \\{\\\n$_"; + $cond = 1; +} elsif ($cond && /^\.(Sh|SS|IP|PP)/) { + $_ = "\\}\n$_"; + $cond = 0; +} + +# Fix up broken pod2man formatting of F<@foo@/bar> +s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g; +s/\\f\(\CW\@([^\@]*)\\fR\@/\@$1\@/g; +#\f(CW@secure_path\fR@ diff --git a/doc/sudoers.pod b/doc/sudoers.pod new file mode 100644 index 0000000..5c5fb1f --- /dev/null +++ b/doc/sudoers.pod @@ -0,0 +1,2155 @@ +Copyright (c) 1994-1996, 1998-2005, 2007-2012 + 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. +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +=pod + +=head1 NAME + +sudoers - default sudo security policy module + +=head1 DESCRIPTION + +The I policy module determines a user's B privileges. +It is the default B policy plugin. The policy is driven by +the F<@sysconfdir@/sudoers> file or, optionally in LDAP. The policy +format is described in detail in the L<"SUDOERS FILE FORMAT"> +section. For information on storing I policy information +in LDAP, please see L. + +=head2 Authentication and Logging + +The I security policy requires that most users authenticate +themselves before they can use B. A password is not required +if the invoking user is root, if the target user is the same as the +invoking user, or if the policy has disabled authentication for the +user or command. Unlike L, when I requires +authentication, it validates the invoking user's credentials, not +the target user's (or root's) credentials. This can be changed via +the I, I and I flags, described later. + +If a user who is not listed in the policy tries to run a command +via B, mail is sent to the proper authorities. The address +used for such mail is configurable via the I Defaults entry +(described later) and defaults to C<@mailto@>. + +Note that mail will not be sent if an unauthorized user tries to +run B with the B<-l> or B<-v> option. This allows users to +determine for themselves whether or not they are allowed to use +B. + +If B is run by root and the C environment variable +is set, the I policy will use this value to determine who +the actual user is. This can be used by a user to log commands +through sudo even when a root shell has been invoked. It also +allows the B<-e> option to remain useful even when invoked via a +sudo-run script or program. Note, however, that the I +lookup is still done for root, not the user specified by C. + +I uses time stamp files for credential caching. Once a +user has been authenticated, a time stamp is updated and the user +may then use sudo without a password for a short period of time +(C<@timeout@> minutes unless overridden by the I option. +By default, I uses a tty-based time stamp which means that +there is a separate time stamp for each of a user's login sessions. +The I option can be disabled to force the use of a +single time stamp for all of a user's sessions. + +I can log both successful and unsuccessful attempts (as well +as errors) to syslog(3), a log file, or both. By default, I +will log via syslog(3) but this is changeable via the I +and I Defaults settings. + +I also supports logging a command's input and output +streams. I/O logging is not on by default but can be enabled using +the I and I Defaults flags as well as the +C and C command tags. + +=head2 Command Environment + +Since environment variables can influence program behavior, I +provides a means to restrict which variables from the user's +environment are inherited by the command to be run. There are two +distinct ways I can deal with environment variables. + +By default, the I option is enabled. This causes commands +to be executed with a new, minimal environment. On AIX (and Linux +systems without PAM), the environment is initialized with the +contents of the F file. On BSD systems, if the +I option is enabled, the environment is initialized +based on the I and I settings in F. +The new environment contains the C, C, C, C, +C, C, C, C and C variables +in addition to variables from the invoking process permitted by the +I and I options. This is effectively a whitelist +for environment variables. + +If, however, the I option is disabled, any variables not +explicitly denied by the I and I options are +inherited from the invoking process. In this case, I +and I behave like a blacklist. Since it is not possible +to blacklist all potentially dangerous environment variables, use +of the default I behavior is encouraged. + +In all cases, environment variables with a value beginning with +C<()> are removed as they could be interpreted as B functions. +The list of environment variables that B allows or denies is +contained in the output of C when run as root. + +Note that the dynamic linker on most operating systems will remove +variables that can control dynamic linking from the environment of +setuid executables, including B. Depending on the operating +system this may include C<_RLD*>, C, C, C, +C, C, and others. These type of variables are +removed from the environment before B even begins execution +and, as such, it is not possible for B to preserve them. + +As a special case, if B's B<-i> option (initial login) is +specified, I will initialize the environment regardless +of the value of I. The I, I and I +variables remain unchanged; I, I, I, I, +and I are set based on the target user. On AIX (and Linux +systems without PAM), the contents of F are also +included. On BSD systems, if the I option is +enabled, the I and I variables in F +are also applied. All other environment variables are removed. + +Finally, if the I option is defined, any variables present +in that file will be set to their specified values as long as they +would not conflict with an existing environment variable. + +=head1 SUDOERS FILE FORMAT + +The I file is composed of two types of entries: aliases +(basically variables) and user specifications (which specify who +may run what). + +When multiple entries match for a user, they are applied in order. +Where there are multiple matches, the last match is used (which is +not necessarily the most specific match). + +The I grammar will be described below in Extended Backus-Naur +Form (EBNF). Don't despair if you don't know what EBNF is; it is +fairly simple, and the definitions below are annotated. + +=head2 Quick guide to EBNF + +EBNF is a concise and exact way of describing the grammar of a language. +Each EBNF definition is made up of I. E.g., + + symbol ::= definition | alternate1 | alternate2 ... + +Each I references others and thus makes up a +grammar for the language. EBNF also contains the following +operators, which many readers will recognize from regular +expressions. Do not, however, confuse them with "wildcard" +characters, which have different meanings. + +=over 4 + +=item C + +Means that the preceding symbol (or group of symbols) is optional. +That is, it may appear once or not at all. + +=item C<*> + +Means that the preceding symbol (or group of symbols) may appear +zero or more times. + +=item C<+> + +Means that the preceding symbol (or group of symbols) may appear +one or more times. + +=back + +Parentheses may be used to group symbols together. For clarity, +we will use single quotes ('') to designate what is a verbatim character +string (as opposed to a symbol name). + +=head2 Aliases + +There are four kinds of aliases: C, C, +C and C. + + Alias ::= 'User_Alias' User_Alias (':' User_Alias)* | + 'Runas_Alias' Runas_Alias (':' Runas_Alias)* | + 'Host_Alias' Host_Alias (':' Host_Alias)* | + 'Cmnd_Alias' Cmnd_Alias (':' Cmnd_Alias)* + + User_Alias ::= NAME '=' User_List + + Runas_Alias ::= NAME '=' Runas_List + + Host_Alias ::= NAME '=' Host_List + + Cmnd_Alias ::= NAME '=' Cmnd_List + + NAME ::= [A-Z]([A-Z][0-9]_)* + +Each I definition is of the form + + Alias_Type NAME = item1, item2, ... + +where I is one of C, C, C, +or C. A C is a string of uppercase letters, numbers, +and underscore characters ('_'). A C B start with an +uppercase letter. It is possible to put several alias definitions +of the same type on a single line, joined by a colon (':'). E.g., + + Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 + +The definitions of what constitutes a valid I member follow. + + User_List ::= User | + User ',' User_List + + User ::= '!'* user name | + '!'* #uid | + '!'* %group | + '!'* %#gid | + '!'* +netgroup | + '!'* %:nonunix_group | + '!'* %:#nonunix_gid | + '!'* User_Alias + +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 actual C and C syntax depends on +the underlying group provider plugin (see the I +description below). For instance, the QAS AD plugin supports the +following formats: + +=over 4 + +=item * + +Group in the same domain: "Group Name" + +=item * + +Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN" + +=item * + +Group SID: "S-1-2-34-5678901234-5678901234-5678901234-567" + +=back + +Note that quotes around group names are optional. Unquoted strings +must use a backslash (\) to escape spaces and special characters. +See L<"Other special characters and reserved words"> for a list of +characters that need to be escaped. + + Runas_List ::= Runas_Member | + Runas_Member ',' Runas_List + + Runas_Member ::= '!'* user name | + '!'* #uid | + '!'* %group | + '!'* %#gid | + '!'* %:nonunix_group | + '!'* %:#nonunix_gid | + '!'* +netgroup | + '!'* Runas_Alias + +A C is similar to a C except that instead +of Ces it can contain Ces. Note that +user names and groups are matched as strings. In other words, two +users (groups) with the same uid (gid) are considered to be distinct. +If you wish to match all user names with the same uid (e.g.Eroot +and toor), you can use a uid instead (#0 in the example given). + + Host_List ::= Host | + Host ',' Host_List + + Host ::= '!'* host name | + '!'* ip_addr | + '!'* network(/netmask)? | + '!'* +netgroup | + '!'* Host_Alias + +A C is made up of one or more host names, IP addresses, +network numbers, netgroups (prefixed with '+') and other aliases. +Again, the value of an item may be negated with the '!' operator. +If you do not specify a netmask along with the network number, +B will query each of the local host's network interfaces and, +if the network number corresponds to one of the hosts's network +interfaces, the corresponding netmask will be used. The netmask +may be specified either in standard IP address notation +(e.g.E255.255.255.0 or ffff:ffff:ffff:ffff::), +or CIDR notation (number of bits, e.g.E24 or 64). A host name may +include shell-style wildcards (see the L section below), +but unless the C command on your machine returns the fully +qualified host name, you'll need to use the I option for +wildcards to be useful. Note B only inspects actual network +interfaces; this means that IP address 127.0.0.1 (localhost) will +never match. Also, the host name "localhost" will only match if +that is the actual host name, which is usually only the case for +non-networked systems. + + Cmnd_List ::= Cmnd | + Cmnd ',' Cmnd_List + + commandname ::= file name | + file name args | + file name '""' + + Cmnd ::= '!'* commandname | + '!'* directory | + '!'* "sudoedit" | + '!'* Cmnd_Alias + +A C is a list of one or more commandnames, directories, and other +aliases. A commandname is a fully qualified file name which may include +shell-style wildcards (see the L section below). A simple +file name allows the user to run the command with any arguments he/she +wishes. However, you may also specify command line arguments (including +wildcards). Alternately, you can specify C<""> to indicate that the command +may only be run B command line arguments. A directory is a +fully qualified path name ending in a '/'. When you specify a directory +in a C, the user will be able to run any file within that directory +(but not in any subdirectories therein). + +If a C has associated command line arguments, then the arguments +in the C must match exactly those given by the user on the command line +(or match the wildcards if there are any). Note that the following +characters must be escaped with a '\' if they are used in command +arguments: ',', ':', '=', '\'. The special command C<"sudoedit"> +is used to permit a user to run B with the B<-e> option (or +as B). It may take command line arguments just as +a normal command does. + +=head2 Defaults + +Certain configuration options may be changed from their default +values at runtime via one or more C lines. These +may affect all users on any host, all users on a specific host, a +specific user, a specific command, or commands being run as a specific user. +Note that per-command entries may not include command line arguments. +If you need to specify arguments, define a C and reference +that instead. + + Default_Type ::= 'Defaults' | + 'Defaults' '@' Host_List | + 'Defaults' ':' User_List | + 'Defaults' '!' Cmnd_List | + 'Defaults' '>' Runas_List + + Default_Entry ::= Default_Type Parameter_List + + Parameter_List ::= Parameter | + Parameter ',' Parameter_List + + Parameter ::= Parameter '=' Value | + Parameter '+=' Value | + Parameter '-=' Value | + '!'* Parameter + +Parameters may be B, B values, B, or B. +Flags are implicitly boolean and can be turned off via the '!' +operator. Some integer, string and list parameters may also be +used in a boolean context to disable them. Values may be enclosed +in double quotes (C<">) when they contain multiple words. Special +characters may be escaped with a backslash (C<\>). + +Lists have two additional assignment operators, C<+=> and C<-=>. +These operators are used to add to and delete from a list respectively. +It is not an error to use the C<-=> operator to remove an element +that does not exist in a list. + +Defaults entries are parsed in the following order: generic, host +and user Defaults first, then runas Defaults and finally command +defaults. + +See L<"SUDOERS OPTIONS"> for a list of supported Defaults parameters. + +=head2 User Specification + + User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \ + (':' Host_List '=' Cmnd_Spec_List)* + + Cmnd_Spec_List ::= Cmnd_Spec | + Cmnd_Spec ',' Cmnd_Spec_List + + Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd + + Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' + + SELinux_Spec ::= ('ROLE=role' | 'TYPE=type') + + Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | + 'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | + 'LOG_OUTPUT:' | 'NOLOG_OUTPUT:') + +A B 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) +what'. Let's break that down into its constituent parts: + +=head2 Runas_Spec + +A C determines the user and/or the group that a command +may be run as. A fully-specified C consists of two +Cs (as defined above) separated by a colon (':') and +enclosed in a set of parentheses. The first C indicates +which users the command may be run as via B's B<-u> option. +The second defines a list of groups that can be specified via +B's B<-g> option. If both Cs are specified, the +command may be run with any combination of users and groups listed +in their respective Cs. If only the first is specified, +the command may be run as any user in the list but no B<-g> option +may be specified. If the first C is empty but the +second is specified, the command may be run as the invoking user +with the group set to any listed in the C. If no +C is specified the command may be run as B and +no group may be specified. + +A C sets the default for the commands that follow it. +What this means is that for the entry: + + dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm + +The user B may run F, F, and +F -- but only as B. E.g., + + $ 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: + + dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm + +Then user B is now allowed to run F as B, +but F and F as B. + +We can extend this to allow B to run C with either +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. + + 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 +an SELinux role and/or type associated with a command. If a role or +type is specified with the command it will override any default values +specified in I. A role or type specified on the command line, +however, will supercede the values in I. + +=head2 Tag_Spec + +A command may have zero or more tags associated with it. There are +eight possible tag values, C, C, C, +C, C, C, C, C, +C and C. Once a tag is set on a C, +subsequent Cs in the C, inherit the tag unless +it is overridden by the opposite tag (i.e.: C overrides +C and C overrides C). + +=head3 NOPASSWD and PASSWD + +By default, B requires that a user authenticate him or herself +before running a command. This behavior can be modified via the +C tag. Like a C, the C tag sets +a default for the commands that follow it in the C. +Conversely, the C tag can be used to reverse things. +For example: + + ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm + +would allow the user B to run F, F, and +F as B on the machine rushmore without +authenticating himself. If we only want B to be able to +run F without a password the entry would be: + + ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm + +Note, however, that the C tag has no effect on users who are +in the group specified by the I option. + +By default, if the C tag is applied to any of the entries +for a user on the current host, he or she will be able to run +C without a password. Additionally, a user may only run +C without a password if the C tag is present +for all a user's entries that pertain to the current host. +This behavior may be overridden via the verifypw and listpw options. + +=head3 NOEXEC and EXEC + +If B has been compiled with I support and the underlying +operating system supports it, the C tag can be used to prevent +a dynamically-linked executable from running further commands itself. + +In the following example, user B may run F +and F but shell escapes will be disabled. + + aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi + +See the L section below for more details +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, 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 + +These tags override the value of the I option on a +per-command basis. For more information, see the description of +I in the L<"SUDOERS OPTIONS"> section below. + +=head3 LOG_OUTPUT and NOLOG_OUTPUT + +These tags override the value of the I option on a +per-command basis. For more information, see the description of +I in the L<"SUDOERS OPTIONS"> section below. + +=head2 Wildcards + +B allows shell-style I (aka meta or glob characters) +to be used in host names, path names and command line arguments in +the I file. Wildcard matching is done via the B +L and L routines. Note that these are I +regular expressions. + +=over 8 + +=item C<*> + +Matches any set of zero or more characters. + +=item C + +Matches any single character. + +=item C<[...]> + +Matches any character in the specified range. + +=item C<[!...]> + +Matches any character B in the specified range. + +=item C<\x> + +For any character "x", evaluates to "x". This is used to +escape special characters such as: "*", "?", "[", and "}". + +=back + +POSIX character classes may also be used if your system's L +and L functions support them. However, because the +C<':'> character has special meaning in I, it must be +escaped. For example: + + /bin/ls [[\:alpha\:]]* + +Would match any file name beginning with a letter. + +Note that a forward slash ('/') will B be matched by +wildcards used in the path name. When matching the command +line arguments, however, a slash B get matched by +wildcards. This is to make a path like: + + /usr/bin/* + +match F but not F. + +=head2 Exceptions to wildcard rules + +The following exceptions apply to the above rules: + +=over 8 + +=item C<""> + +If the empty string C<""> is the only command line argument in the +I entry it means that command is not allowed to be run +with B arguments. + +=back + +=head2 Including other files from within sudoers + +It is possible to include other I files from within the +I file currently being parsed using the C<#include> and +C<#includedir> directives. + +This can be used, for example, to keep a site-wide I file +in addition to a local, per-machine file. For the sake of this +example the site-wide I will be F and the +per-machine one will be F. To include +F from within F we would use the +following line in F: + +=over 4 + +C<#include /etc/sudoers.local> + +=back + +When B reaches this line it will suspend processing of the +current file (F) and switch to F. +Upon reaching the end of F, the rest of +F will be processed. Files that are included may +themselves include other files. A hard limit of 128 nested include +files is enforced to prevent include file loops. + +If the path to the include file is not fully-qualified (does not +begin with a F), it must be located in the same directory as the +sudoers file it was included from. For example, if F +contains the line: + +=over 4 + +C<#include sudoers.local> + +=back + +the file that will be included is F. + +The file name may also include the C<%h> escape, signifying the short form +of the host name. I.e., if the machine's host name is "xerxes", then + +C<#include /etc/sudoers.%h> + +will cause B to include the file F. + +The C<#includedir> directive can be used to create a F +directory that the system package manager can drop I rules +into as part of package installation. For example, given: + +C<#includedir /etc/sudoers.d> + +B will read each file in F, skipping file +names that end in C<~> or contain a C<.> character to avoid causing +problems with package manager or editor temporary/backup files. +Files are parsed in sorted lexical order. That is, +F will be parsed before +F. Be aware that because the sorting is +lexical, not numeric, F would be loaded +B F. Using a consistent number +of leading zeroes in the file names can be used to avoid such +problems. + +Note that unlike files included via C<#include>, B will not +edit the files in a C<#includedir> directory unless one of them +contains a syntax error. It is still possible to run B +with the C<-f> flag to edit the files directly. + +=head2 Other special characters and reserved words + +The pound sign ('#') is used to indicate a comment (unless it is +part of a #include directive or unless it occurs in the context of +a user name and is followed by one or more digits, in which case +it is treated as a uid). Both the comment character and any text +after it, up to the end of the line, are ignored. + +The reserved word B is a built-in I that always causes +a match to succeed. It can be used wherever one might otherwise +use a C, C, C, or C. +You should not try to define your own I called B as the +built-in alias will be used in preference to your own. Please note +that using B can be dangerous since in a command context, it +allows the user to run B command on the system. + +An exclamation point ('!') can be used as a logical I operator +both in an I and in front of a C. This allows one to +exclude certain values. Note, however, that using a C in +conjunction with the built-in C alias to allow a user to +run "all but a few" commands rarely works as intended (see SECURITY +NOTES below). + +Long lines can be continued with a backslash ('\') as the last +character on the line. + +Whitespace between elements in a list as well as special syntactic +characters in a I ('=', ':', '(', ')') 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 + +B's behavior can be modified by C lines, as +explained earlier. A list of all supported Defaults parameters, +grouped by type, are listed below. + +B: + +=over 16 + +=item always_set_home + +If enabled, B will set the C environment variable to the +home directory of the target user (which is root unless the B<-u> +option is used). This effectively means that the B<-H> option is +always implied. Note that C is already set when the the +I option is enabled, so I is only +effective for configurations where either I is disabled +or C is present in the I list. +This flag is I by default. + +=item authenticate + +If set, users must authenticate themselves via a password (or other +means of authentication) before they may run commands. This default +may be overridden via the C and C tags. +This flag is I by default. + +=item closefrom_override + +If set, the user may use B's B<-C> option which +overrides the default starting point at which B begins +closing open file descriptors. This flag is I by default. + +=item compress_io + +If set, and B is configured to log a command's input or output, +the I/O logs will be compressed using B. This flag is I +by default when B is compiled with B support. + +=item env_editor + +If set, B will use the value of the EDITOR or VISUAL +environment variables before falling back on the default editor list. +Note that this may create a security hole as it allows the user to +run any arbitrary command as root without logging. A safer alternative +is to place a colon-separated list of editors in the C +variable. B will then only use the EDITOR or VISUAL if +they match a value specified in C. This flag is I<@env_editor@> by +default. + +=item env_reset + +If set, B will run the command in a minimal environment +containing the C, C, C, C, C, +C, C, C and C variables. Any +variables in the caller's environment that match the C +and C lists are then added, followed by any variables +present in the file specified by the I option (if any). +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<@env_reset@> by +default. + +=item fast_glob + +Normally, B uses the L function to do shell-style +globbing when matching path names. However, since it accesses the +file system, L can take a long time to complete for some +patterns, especially when the pattern references a network file +system that is mounted on demand (automounted). The I +option causes B to use the L function, which does +not access the file system to do its matching. The disadvantage +of I is that it is unable to match relative path names +such as F<./ls> or F<../bin/ls>. This has security implications +when path names that include globbing characters are used with the +negation operator, C<'!'>, as such rules can be trivially bypassed. +As such, this option should not be used when I contains rules +that contain negated path names which include globbing characters. +This flag is I by default. + +=item fqdn + +Set this flag if you want to put fully qualified host names in the +I file. I.e., instead of myhost you would use myhost.mydomain.edu. +You may still use the short form if you wish (and even mix the two). +Beware that turning on I requires B to make DNS lookups +which may make B unusable if DNS stops working (for example +if the machine is not plugged into the network). Also note that +you must use the host's official name as DNS knows it. That is, +you may not use a host alias (C entry) due to performance +issues and the fact that there is no way to get all aliases from +DNS. If your machine's host name (as returned by the C +command) is already fully qualified you shouldn't need to set +I. This flag is I<@fqdn@> by default. + +=item ignore_dot + +If set, B will ignore '.' or '' (current dir) in the C +environment variable; the C itself is not modified. This +flag is I<@ignore_dot@> by default. + +=item ignore_local_sudoers + +If set via LDAP, parsing of F<@sysconfdir@/sudoers> will be skipped. +This is intended for Enterprises that wish to prevent the usage of local +sudoers files so that only LDAP is used. This thwarts the efforts of +rogue operators who would attempt to add roles to F<@sysconfdir@/sudoers>. +When this option is present, F<@sysconfdir@/sudoers> does not even need to +exist. Since this option tells B how to behave when no specific LDAP +entries have been matched, this sudoOption is only meaningful for the +C section. This flag is I by default. + +=item insults + +If set, B will insult users when they enter an incorrect +password. This flag is I<@insults@> by default. + +=item log_host + +If set, the host name will be logged in the (non-syslog) B 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. +The I option may be used to control the format of the +session ID. + +Note that user input may contain sensitive information such as +passwords (even if they are not echoed to the screen), which will +be stored in the log file unencrypted. In most cases, logging the +command output via I 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. +The I option may be used to control the format of the +session ID. + +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. +This flag is I by default. + +=item long_otp_prompt + +When validating with a One Time Password (OTP) scheme such as +B or B, a two-line prompt is used to make it easier +to cut and paste the challenge to a local window. It's not as +pretty as the default but some people find it more convenient. This +flag is I<@long_otp_prompt@> by default. + +=item mail_always + +Send mail to the I user every time a users runs B. +This flag is I by default. + +=item mail_badpass + +Send mail to the I user if the user running B does not +enter the correct password. This flag is I by default. + +=item mail_no_host + +If set, mail will be sent to the I user if the invoking +user exists in the I file, but is not allowed to run +commands on the current host. This flag is I<@mail_no_host@> by default. + +=item mail_no_perms + +If set, mail will be sent to the I user if the invoking +user is allowed to use B but the command they are trying is not +listed in their I file entry or is explicitly denied. +This flag is I<@mail_no_perms@> by default. + +=item mail_no_user + +If set, mail will be sent to the I user if the invoking +user is not in the I file. This flag is I<@mail_no_user@> +by default. + +=item noexec + +If set, all commands run via B will behave as if the C +tag has been set, unless overridden by a C tag. See the +description of I below as well as the L section at the end of this manual. This flag is I by default. + +=item path_info + +Normally, B will tell the user when a command could not be +found in their C environment variable. Some sites may wish +to disable this as it could be used to gather information on the +location of executables that the normal user does not have access +to. The disadvantage is that if the executable is simply not in +the user's C, B will tell the user that they are not +allowed to run it, which can be confusing. This flag is I<@path_info@> +by default. + +=item passprompt_override + +The password prompt specified by I will normally only +be used if the password prompt provided by systems such as PAM matches +the string "Password:". If I is set, I +will always be used. This flag is I by default. + +=item preserve_groups + +By default, B will initialize the group vector to the list of +groups the target user is in. When I is set, the +user's existing group vector is left unaltered. The real and +effective group IDs, however, are still set to match the target +user. This flag is I by default. + +=item pwfeedback + +By default, B reads the password like most other Unix programs, +by turning off echo until the user hits the return (or enter) key. +Some users become confused by this as it appears to them that B +has hung at this point. When I is set, B will +provide visual feedback when the user presses a key. Note that +this does have a security impact as an onlooker may be able to +determine the length of the password being entered. +This flag is I by default. + +=item requiretty + +If set, B will only run when the user is logged in to a real +tty. When this flag is set, B can only be run from a login +session and not via other means such as L or cgi-bin scripts. +This flag is I by default. + +=item root_sudo + +If set, root is allowed to run B too. Disabling this prevents users +from "chaining" B commands to get a root shell by doing something +like C<"sudo sudo /bin/sh">. Note, however, that turning off I +will also prevent root from running B. +Disabling I provides no real additional security; it +exists purely for historical reasons. +This flag is I<@root_sudo@> by default. + +=item rootpw + +If set, B will prompt for the root password instead of the password +of the invoking user. This flag is I by default. + +=item runaspw + +If set, B will prompt for the password of the user defined by the +I option (defaults to C<@runas_default@>) instead of the +password of the invoking user. This flag is I by default. + +=item set_home + +If enabled and B is invoked with the B<-s> option the C +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 either I is disabled +or C is present in the I list. +This flag is I by default. + +=item set_logname + +Normally, B will set the C, C and C +environment variables to the name of the target user (usually root +unless the B<-u> option is given). However, since some programs +(including the RCS revision control system) use C to +determine the real identity of the user, it may be desirable to +change this behavior. This can be done by negating the set_logname +option. Note that if the I option has not been disabled, +entries in the I list will override the value of +I. This flag is I by default. + +=item set_utmp + +When enabled, B will create an entry in the utmp (or utmpx) +file when a pseudo-tty is allocated. A pseudo-tty is allocated by +B when the I, I or I flags +are enabled. By default, the new entry will be a copy of the user's +existing utmp entry (if any), with the tty, time, type and pid +fields updated. This flag is I by default. + +=item setenv + +Allow the user to disable the I option from the command +line via the B<-E> option. Additionally, environment variables set +via the command line are not subject to the restrictions imposed +by I, I, or I. As such, only +trusted users should be allowed to set variables in this manner. +This flag is I by default. + +=item shell_noargs + +If set and B is invoked with no arguments it acts as if the +B<-s> option had been given. That is, it runs a shell as root (the +shell is determined by the C environment variable if it is +set, falling back on the shell listed in the invoking user's +/etc/passwd entry if not). This flag is I by default. + +=item stay_setuid + +Normally, when B executes a command the real and effective +UIDs are set to the target user (root by default). This option +changes that behavior such that the real UID is left as the invoking +user's UID. In other words, this makes B act as a setuid +wrapper. This can be useful on systems that disable some potentially +dangerous functionality when a program is run setuid. This option +is only effective on systems with either the setreuid() or setresuid() +function. This flag is I by default. + +=item targetpw + +If set, B will prompt for the password of the user specified +by the B<-u> option (defaults to C) instead of the password +of the invoking user. In addition, the timestamp file name will +include the target user's name. Note that this flag precludes the +use of a uid not listed in the passwd database as an argument to +the B<-u> option. This flag is I by default. + +=item tty_tickets + +If set, users must authenticate on a per-tty basis. With this flag +enabled, B will use a file named for the tty the user is +logged in on in the user's time stamp directory. If disabled, the +time stamp of the directory is used instead. This flag is +I<@tty_tickets@> by default. + +=item umask_override + +If set, B will set the umask as specified by I without +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<@umask_override@> by default. + +=item use_loginclass + +If set, B will apply the defaults specified for the target user's +login class if one exists. Only available if B is configured with +the --with-logincap option. This flag is I by default. + +=item use_pty + +If set, B will run the command in a pseudo-pty even if no I/O +logging is being gone. A malicious program run under B could +conceivably fork a background process that retains to the user's +terminal device after the main program has finished executing. Use +of this option will make that impossible. This flag is I by default. + +=item utmp_runas + +If set, B will store the name of the runas user when updating +the utmp (or utmpx) file. By default, B stores the name of +the invoking user. This flag is I by default. + +=item visiblepw + +By default, B will refuse to run if the user must enter a +password but it is not possible to disable echo on the terminal. +If the I flag is set, B will prompt for a password +even when it would be visible on the screen. This makes it possible +to run things like C<"rsh somehost sudo ls"> since L does +not allocate a tty. This flag is I by default. + +=back + +B: + +=over 16 + +=item closefrom + +Before it executes a command, B will close all open file +descriptors other than standard input, standard output and standard +error (ie: file descriptors 0-2). The I option can be used +to specify a different file descriptor at which to start closing. +The default is C<3>. + +=item passwd_tries + +The number of tries a user gets to enter his/her password before +B logs the failure and exits. The default is C<@passwd_tries@>. + +=back + +B: + +=over 16 + +=item loglinelen + +Number of characters per line for the file log. This value is used +to decide when to wrap lines for nicer log files. This has no +effect on the syslog log file, only the file log. The default is +C<@loglen@> (use 0 or negate the option to disable word wrap). + +=item passwd_timeout + +Number of minutes before the B password prompt times out, or +C<0> for no timeout. The timeout may include a fractional component +if minute granularity is insufficient, for example C<2.5>. The +default is C<@password_timeout@>. + +=item timestamp_timeout + +Number of minutes that can elapse before B will ask for a +passwd again. The timeout may include a fractional component if +minute granularity is insufficient, for example C<2.5>. The default +is C<@timeout@>. Set this to C<0> to always prompt for a password. +If set to a value less than C<0> the user's timestamp will never +expire. This can be used to allow users to create or delete their +own timestamps via C and C respectively. + +=item umask + +Umask to use when running the command. Negate this option or set +it to 0777 to preserve the user's umask. The actual umask that is +used will be the union of the user's umask and the value of the +I option, which defaults to C<@sudo_umask@>. This guarantees +that B never lowers the umask when running a command. Note +on systems that use PAM, the default PAM configuration may specify +its own umask which will override the value set in I. + +=back + +B: + +=over 16 + +=item badpass_message + +Message that is displayed if a user enters an incorrect password. +The default is C<@badpass_message@> unless insults are enabled. + +=item editor + +A colon (':') separated list of editors allowed to be used with +B. 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 top-level directory to use when constructing the path name for +the input/output log directory. Only used if the I or +I options are enabled or when the C or +C tags are present for a command. The session sequence +number, if any, is stored in the directory. +The default is C<"@iolog_dir@">. + +The following percent (`C<%>') escape sequences are supported: + +=over 4 + +=item C<%{seq}> + +expanded to a monotonically increasing base-36 sequence number, such as 0100A5, +where every two digits are used to form a new directory, e.g. F<01/00/A5> + +=item C<%{user}> + +expanded to the invoking user's login name + +=item C<%{group}> + +expanded to the name of the invoking user's real group ID + +=item C<%{runas_user}> + +expanded to the login name of the user the command will +be run as (e.g. root) + +=item C<%{runas_group}> + +expanded to the group name of the user the command will +be run as (e.g. wheel) + +=item C<%{hostname}> + +expanded to the local host name without the domain name + +=item C<%{command}> + +expanded to the base name of the command being run + +=back + +In addition, any escape sequences supported by the system's strftime() +function will be expanded. + +To include a literal `C<%>' character, the string `C<%%>' should +be used. + +=item iolog_file + +The path name, relative to I, 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. +Note that I may contain directory components. +The default is C<"%{seq}">. + +See the I option above for a list of supported percent +(`C<%>') escape sequences. + +In addition to the escape sequences, path names that end in six or +more Cs will have the Cs replaced with a unique combination +of digits and letters, similar to the mktemp() function. + +=item mailsub + +Subject of the mail sent to the I user. The escape C<%h> +will expand to the host name of the machine. +Default is C<@mailsub@>. + +=item noexec_file + +This option is no longer supported. The path to the noexec file +should now be set in the F<@sysconfdir@/sudo.conf> file. + +=item passprompt + +The default prompt to use when asking for a password; can be overridden +via the B<-p> option or the C environment variable. +The following percent (`C<%>') escape sequences are supported: + +=over 4 + +=item C<%H> + +expanded to the local host name including the domain name +(only if the machine's host name is fully qualified or the I +option is set) + +=item C<%h> + +expanded to the local host name without the domain name + +=item C<%p> + +expanded to the user whose password is being asked for (respects the +I, I and I flags in I) + +=item C<%U> + +expanded to the login name of the user the command will +be run as (defaults to root) + +=item C<%u> + +expanded to the invoking user's login name + +=item C<%%> + +two consecutive C<%> characters are collapsed into a single C<%> character + +=back + +The default value is C<@passprompt@>. + +=item role + +The default SELinux role to use when constructing a new security +context to run the command. The default role may be overridden on +a per-command basis in I or via command line options. +This option is only available whe B is built with SELinux support. + +=item runas_default + +The default user to run commands as if the B<-u> option is not specified +on the command line. This defaults to C<@runas_default@>. + +=item syslog_badpri + +Syslog priority to use when user authenticates unsuccessfully. +Defaults to C<@badpri@>. + +The following syslog priorities are supported: B, B, +B, B, B, B, B, and B. + +=item syslog_goodpri + +Syslog priority to use when user authenticates successfully. +Defaults to C<@goodpri@>. + +See L for the list of supported syslog priorities. + +=item sudoers_locale + +Locale to use when parsing the sudoers file, logging commands, and +sending email. Note that changing the locale may affect how sudoers +is interpreted. Defaults to C<"C">. + +=item timestampdir + +The directory in which B stores its timestamp files. +The default is F<@timedir@>. + +=item timestampowner + +The owner of the timestamp directory and the timestamps stored therein. +The default is C. + +=item type + +The default SELinux type to use when constructing a new security +context to run the command. The default type may be overridden on +a per-command basis in I or via command line options. +This option is only available whe B is built with SELinux support. + +=back + +B: + +=over 12 + +=item env_file + +The I option specifies the fully qualified path to a +file containing variables to be set in the environment of the program +being run. Entries in this file should either be of the form +C or C. The value may +optionally be surrounded by single or double quotes. Variables in +this file are subject to other B environment settings such +as I and I. + +=item exempt_group + +Users in this group are exempt from password and PATH requirements. +The group name specified should not include a C<%> prefix. +This is not set by default. + +=item group_plugin + +A string containing a I group plugin with optional arguments. +This can be used to implement support for the C +syntax described earlier. The string should consist of the plugin +path, either fully-qualified or relative to the F<@prefix@/libexec> +directory, followed by any configuration arguments the plugin +requires. These arguments (if any) will be passed to the plugin's +initialization function. If arguments are present, the string must +be enclosed in double quotes (C<">). + +For example, given F, a group file in Unix group +format, the sample group plugin can be used: + + Defaults group_plugin="sample_group.so /etc/sudo-group" + +For more information see L. + +=item lecture + +This option controls when a short lecture will be printed along with +the password prompt. It has the following possible values: + +=over 8 + +=item always + +Always lecture the user. + +=item never + +Never lecture the user. + +=item once + +Only lecture the user the first time they run B. + +=back + +If no value is specified, a value of I is implied. +Negating the option results in a value of I being used. +The default value is I<@lecture@>. + +=item lecture_file + +Path to a file containing an alternate B lecture that will +be used in place of the standard lecture if the named file exists. +By default, B uses a built-in lecture. + +=item listpw + +This option controls when a password will be required when a +user runs B with the B<-l> option. It has the following possible values: + +=over 8 + +=item all + +All the user's I entries for the current host must have +the C flag set to avoid entering a password. + +=item always + +The user must always enter a password to use the B<-l> option. + +=item any + +At least one of the user's I entries for the current host +must have the C flag set to avoid entering a password. + +=item never + +The user need never enter a password to use the B<-l> option. + +=back + +If no value is specified, a value of I is implied. +Negating the option results in a value of I being used. +The default value is I. + +=item logfile + +Path to the B log file (not the syslog log file). Setting a path +turns on logging to a file; negating this option turns it off. +By default, B logs via syslog. + +=item mailerflags + +Flags to use when invoking mailer. Defaults to B<-t>. + +=item mailerpath + +Path to mail program used to send warning mail. +Defaults to the path to sendmail found at configure time. + +=item mailfrom + +Address to use for the "from" address when sending warning and error +mail. The address should be enclosed in double quotes (C<">) to +protect against B interpreting the C<@> sign. Defaults to +the name of the user running B. + +=item mailto + +Address to send warning and error mail to. The address should +be enclosed in double quotes (C<">) to protect against B +interpreting the C<@> sign. Defaults to C<@mailto@>. + +=item secure_path + +Path used for every command run from B. If you don't trust the +people running B to have a sane C environment variable you may +want to use this. Another use is if you want to have the "root path" +be separate from the "user path." Users in the group specified by the +I option are not affected by I. +This option is @secure_path@ by default. + +=item syslog + +Syslog facility if syslog is being used for logging (negate to +disable syslog logging). Defaults to C<@logfac@>. + +The following syslog facilities are supported: B (if your +OS supports it), B, B, B, B, B, +B, B, B, B, B, and B. + +=item verifypw + +This option controls when a password will be required when a user runs +B with the B<-v> option. It has the following possible values: + +=over 8 + +=item all + +All the user's I entries for the current host must have +the C flag set to avoid entering a password. + +=item always + +The user must always enter a password to use the B<-v> option. + +=item any + +At least one of the user's I entries for the current host +must have the C flag set to avoid entering a password. + +=item never + +The user need never enter a password to use the B<-v> option. + +=back + +If no value is specified, a value of I is implied. +Negating the option results in a value of I being used. +The default value is I. + +=back + +B: + +=over 16 + +=item env_check + +Environment variables to be removed from the user's environment if +the variable's value contains C<%> or C characters. This can +be used to guard against printf-style format vulnerabilities in +poorly-written programs. The argument may be a double-quoted, +space-separated list or a single value without double-quotes. The +list can be replaced, added to, deleted from, or disabled by using +the C<=>, C<+=>, C<-=>, and C operators respectively. Regardless +of whether the C option is enabled or disabled, variables +specified by C will be preserved in the environment if +they pass the aforementioned check. The default list of environment +variables to check is displayed when B is run by root with +the I<-V> option. + +=item env_delete + +Environment variables to be removed from the user's environment +when the I option is not in effect. The argument may +be a double-quoted, space-separated list or a single value without +double-quotes. The list can be replaced, added to, deleted from, +or disabled by using the C<=>, C<+=>, C<-=>, and C operators +respectively. The default list of environment variables to remove +is displayed when B is run by root with the I<-V> option. +Note that many operating systems will remove potentially dangerous +variables from the environment of any setuid process (such as +B). + +=item env_keep + +Environment variables to be preserved in the user's environment +when the I option is in effect. This allows fine-grained +control over the environment B-spawned processes will receive. +The argument may be a double-quoted, space-separated list or a +single value without double-quotes. The list can be replaced, added +to, deleted from, or disabled by using the C<=>, C<+=>, C<-=>, and +C operators respectively. The default list of variables to keep +is displayed when B is run by root with the I<-V> option. + +=back + +=head1 SUDO.CONF + +The F<@sysconfdir@/sudo.conf> file determines which plugins the +B front end will load. If no F<@sysconfdir@/sudo.conf> file +is present, or it contains no C lines, B will use the +I security policy and I/O logging, which corresponds to +the following F<@sysconfdir@/sudo.conf> file. + + # + # Default @sysconfdir@/sudo.conf file + # + # Format: + # Plugin plugin_name plugin_path plugin_options ... + # Path askpass /path/to/askpass + # Path noexec /path/to/sudo_noexec.so + # Debug sudo /var/log/sudo_debug all@warn + # Set disable_coredump true + # + # The plugin_path is relative to @prefix@/libexec unless + # fully qualified. + # The plugin_name corresponds to a global symbol in the plugin + # that contains the plugin interface structure. + # The plugin_options are optional. + # + Plugin policy_plugin sudoers.so + Plugin io_plugin sudoers.so + +=head2 PLUGIN OPTIONS + +Starting with B 1.8.5 it is possible to pass options to the +I plugin. Options may be listed after the path to the +plugin (i.e. after F); multiple options should be +space-separated. For example: + + Plugin sudoers_policy sudoers.so sudoers_file=/etc/sudoers sudoers_uid=0 sudoers_gid=0 sudoers_mode=0440 + +The following plugin options are supported: + +=over 10 + +=item sudoers_file=pathname + +The I option can be used to override the default path +to the I file. + +=item sudoers_uid=uid + +The I option can be used to override the default owner +of the sudoers file. It should be specified as a numeric user ID. + +=item sudoers_gid=gid + +The I option can be used to override the default group +of the sudoers file. It should be specified as a numeric group ID. + +=item sudoers_mode=mode + +The I option can be used to override the default file +mode for the sudoers file. It should be specified as an octal value. + +=back + +=head2 DEBUG FLAGS + +Versions 1.8.4 and higher of the I plugin supports a +debugging framework that can help track down what the plugin is +doing internally if there is a problem. This can be configured in +the F<@sysconfdir@/sudo.conf> file as described in L. + +The I plugin uses the same debug flag format as B +itself: I@I. + +The priorities used by I, in order of decreasing severity, +are: I, I, I, I, I, I, I +and I. Each priority, when specified, also includes all +priorities higher than it. For example, a priority of I +would include debug messages logged at I and higher. + +The following subsystems are used by I: + +=over 10 + +=item I + +C, C, C and C processing + +=item I + +matches every subsystem + +=item I + +BSM and Linux audit code + +=item I + +user authentication + +=item I + +I I settings + +=item I + +environment handling + +=item I + +LDAP-based sudoers + +=item I + +logging support + +=item I + +matching of users, groups, hosts and netgroups in I + +=item I + +network interface handling + +=item I + +network service switch handling in I + +=item I + +I file parsing + +=item I + +permission setting + +=item I + +The equivalent of I
for the plugin. + +=item I + +pseudo-tty related code + +=item I + +redblack tree internals + +=item I + +utility functions + +=back + +=head1 FILES + +=over 24 + +=item F<@sysconfdir@/sudo.conf> + +Sudo front end configuration + +=item F<@sysconfdir@/sudoers> + +List of who can run what + +=item F + +Local groups file + +=item F + +List of network groups + +=item F<@iolog_dir@> + +I/O log files + +=item F<@timedir@> + +Directory containing time stamps for the I security policy + +=item F + +Initial environment for B<-i> mode on AIX and Linux systems + +=back + +=head1 EXAMPLES + +Below are example I entries. Admittedly, some of +these are a bit contrived. First, we allow a few environment +variables to pass and then define our I: + + # Run X applications through sudo; HOME is used to find the + # .Xauthority file. Note that other programs use HOME to find + # configuration files and this may lead to privilege escalation! + Defaults env_keep += "DISPLAY HOME" + + # User alias specification + User_Alias FULLTIMERS = millert, mikef, dowdy + User_Alias PARTTIMERS = bostley, jwfox, crawl + User_Alias WEBMASTERS = will, wendy, wim + + # Runas alias specification + Runas_Alias OP = root, operator + Runas_Alias DB = oracle, sybase + Runas_Alias ADMINGRP = adm, oper + + # Host alias specification + Host_Alias SPARC = bigtime, eclipse, moet, anchor :\ + SGI = grolsch, dandelion, black :\ + ALPHA = widget, thalamus, foobar :\ + HPPA = boa, nag, python + Host_Alias CUNETS = 128.138.0.0/255.255.0.0 + Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 + Host_Alias SERVERS = master, mail, www, ns + Host_Alias CDROM = orion, perseus, hercules + + # Cmnd alias specification + Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\ + /usr/sbin/restore, /usr/sbin/rrestore + Cmnd_Alias KILL = /usr/bin/kill + Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm + Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown + Cmnd_Alias HALT = /usr/sbin/halt + Cmnd_Alias REBOOT = /usr/sbin/reboot + Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \ + /usr/local/bin/tcsh, /usr/bin/rsh, \ + /usr/local/bin/zsh + Cmnd_Alias SU = /usr/bin/su + Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less + +Here we override some of the compiled in default values. We want +B to log via L using the I facility in all +cases. We don't want to subject the full time staff to the B +lecture, user B need not give a password, and we don't +want to reset the C, C or C environment +variables when running commands as root. Additionally, on the +machines in the I C, we keep an additional +local log file and make sure we log the year in each log line since +the log entries will be kept around for several years. Lastly, we +disable shell escapes for the commands in the PAGERS C +(F, F and F). + + # Override built-in defaults + Defaults syslog=auth + Defaults>root !set_logname + Defaults:FULLTIMERS !lecture + Defaults:millert !authenticate + Defaults@SERVERS log_year, logfile=/var/log/sudo.log + Defaults!PAGERS noexec + +The I is the part that actually determines who may +run what. + + root ALL = (ALL) ALL + %wheel ALL = (ALL) ALL + +We let B and any user in group B run any command on any +host as any user. + + FULLTIMERS ALL = NOPASSWD: ALL + +Full time sysadmins (B, B, and B) may run any +command on any host without authenticating themselves. + + PARTTIMERS ALL = ALL + +Part time sysadmins (B, B, and B) may run any +command on any host but they must authenticate themselves first +(since the entry lacks the C tag). + + jack CSNETS = ALL + +The user B may run any command on the machines in the I alias +(the networks C<128.138.243.0>, C<128.138.204.0>, and C<128.138.242.0>). +Of those networks, only C<128.138.204.0> has an explicit netmask (in +CIDR notation) indicating it is a class C network. For the other +networks in I, the local machine's netmask will be used +during matching. + + lisa CUNETS = ALL + +The user B may run any command on any host in the I alias +(the class B network C<128.138.0.0>). + + operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\ + sudoedit /etc/printcap, /usr/oper/bin/ + +The B user may run commands limited to simple maintenance. +Here, those are commands related to backups, killing processes, the +printing system, shutting down the system, and any commands in the +directory F. + + joe ALL = /usr/bin/su operator + +The user B may only L to operator. + + pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root + + %opers ALL = (: ADMINGRP) /usr/sbin/ + +Users in the B group may run commands in F as themselves +with any group in the I C (the B and B +groups). + +The user B is allowed to change anyone's password except for +root on the I machines. Note that this assumes L +does not take multiple user names on the command line. + + bob SPARC = (OP) ALL : SGI = (OP) ALL + +The user B may run anything on the I and I machines +as any user listed in the I C (B and B). + + jim +biglab = ALL + +The user B may run any command on machines in the I netgroup. +B knows that "biglab" is a netgroup due to the '+' prefix. + + +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser + +Users in the B netgroup need to help manage the printers +as well as add and remove users, so they are allowed to run those +commands on all machines. + + fred ALL = (DB) NOPASSWD: ALL + +The user B can run commands as any user in the I C +(B or B) without giving a password. + + john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* + +On the I machines, user B may su to anyone except root +but he is not allowed to specify any options to the L command. + + jen ALL, !SERVERS = ALL + +The user B may run any command on any machine except for those +in the I C (master, mail, www and ns). + + jill SERVERS = /usr/bin/, !SU, !SHELLS + +For any machine in the I C, B may run +any commands in the directory F except for those commands +belonging to the I and I C. + + steve CSNETS = (operator) /usr/local/op_commands/ + +The user B may run any command in the directory /usr/local/op_commands/ +but only as user operator. + + matt valkyrie = KILL + +On his personal workstation, valkyrie, B needs to be able to +kill hung processes. + + WEBMASTERS www = (www) ALL, (root) /usr/bin/su www + +On the host www, any user in the I C (will, +wendy, and wim), may run any command as user www (which owns the +web pages) or simply L to www. + + ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ + /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM + +Any user may mount or unmount a CD-ROM on the machines in the CDROM +C (orion, perseus, hercules) without entering a password. +This is a bit tedious for users to type, so it is a prime candidate +for encapsulating in a shell script. + +=head1 SECURITY NOTES + +=head2 Limitations of the '!' operator + +It is generally not effective to "subtract" commands from C +using the '!' operator. A user can trivially circumvent this +by copying the desired command to a different name and then +executing that. For example: + + bill ALL = ALL, !SU, !SHELLS + +Doesn't really prevent B from running the commands listed in +I or I 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). + +In general, if a user has sudo C there is nothing to prevent +them from creating their own program that gives them a root shell +(or making their own copy of a shell) regardless of any '!' elements +in the user specification. + +=head2 Security implications of I + +If the I option is in use, it is not possible +to reliably negate commands where the path name includes globbing +(aka wildcard) characters. This is because the C library's +L function cannot resolve relative paths. While this +is typically only an inconvenience for rules that grant privileges, +it can result in a security issue for rules that subtract or revoke +privileges. + +For example, given the following I entry: + + john ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*, + /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root + +User B can still run C if I is +enabled by changing to F and running C<./passwd root> instead. + +=head2 Preventing Shell Escapes + +Once B executes a program, that program is free to do whatever +it pleases, including run other programs. This can be a security +issue since it is not uncommon for a program to allow shell escapes, +which lets a user bypass B's access control and logging. +Common programs that permit shell escapes include shells (obviously), +editors, paginators, mail and terminal programs. + +There are two basic approaches to this problem: + +=over 10 + +=item restrict + +Avoid giving users access to commands that allow the user to run +arbitrary commands. Many editors have a restricted mode where shell +escapes are disabled, though B is a better solution to +running editors via B. Due to the large number of programs that +offer shell escapes, restricting users to the set of programs that +do not is often unworkable. + +=item noexec + +Many systems that support shared libraries have the ability to +override default library functions by pointing an environment +variable (usually C) to an alternate shared library. +On such systems, B's I functionality can be used to +prevent a program run by B from executing any other programs. +Note, however, that this applies only to native dynamically-linked +executables. Statically-linked executables and foreign executables +running under binary emulation are not affected. + +The I feature is known to work on SunOS, Solaris, *BSD, +Linux, IRIX, Tru64 UNIX, MacOS X, HP-UX 11.x and AIX 5.3 and above. +It should be supported on most operating systems that support the +C environment variable. Check your operating system's +manual pages for the dynamic linker (usually ld.so, ld.so.1, dyld, +dld.sl, rld, or loader) to see if C is supported. + +On Solaris 10 and higher, I uses Solaris privileges instead +of the C environment variable. + +To enable I for a command, use the C tag as documented +in the User Specification section above. Here is that example again: + + aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi + +This allows user B to run F and F +with I enabled. This will prevent those two commands from +executing other commands (such as a shell). If you are unsure +whether or not your system is capable of supporting I you +can always just try it out and check whether shell escapes work +when I is enabled. + +=back + +Note that restricting shell escapes is not a panacea. Programs +running as root are still capable of many potentially hazardous +operations (such as changing or overwriting files) that could lead +to unintended privilege escalation. In the specific case of an +editor, a safer approach is to give the user permission to run +B. + +=head2 Time stamp file checks + +I will check the ownership of its time stamp directory +(F<@timedir@> by default) and ignore the directory's contents if +it is not owned by root or if it is writable by a user other than +root. On systems that allow non-root users to give away files via +L, if the time stamp directory is located in a world-writable +directory (e.g., F), it is possible for a user to create the +time stamp directory before B is run. However, because +I checks the ownership and mode of the directory and its +contents, the only damage that can be done is to "hide" files by +putting them in the time stamp dir. This is unlikely to happen +since once the time stamp dir is owned by root and inaccessible by +any other user, the user placing files there would be unable to get +them back out. + +I will not honor time stamps set far in the future. Time +stamps with a date greater than current_time + 2 * C will +be ignored and sudo will log and complain. This is done to keep a +user from creating his/her own time stamp with a bogus date on +systems that allow users to give away files if the time stamp directory +is located in a world-writable directory. + +On systems where the boot time is available, I will ignore +time stamps that date from before the machine booted. + +Since time stamp files live in the file system, they can outlive a +user's login session. As a result, a user may be able to login, +run a command with B after authenticating, logout, login +again, and run B without authenticating so long as the time +stamp file's modification time is within C<@timeout@> minutes (or +whatever the timeout is set to in I). When the I +option is enabled, the time stamp has per-tty granularity but still +may outlive the user's session. On Linux systems where the devpts +filesystem is used, Solaris systems with the devices filesystem, +as well as other systems that utilize a devfs filesystem that +monotonically increase the inode number of devices as they are +created (such as Mac OS X), I is able to determine when a +tty-based time stamp file is stale and will ignore it. Administrators +should not rely on this feature as it is not universally available. + +=head1 SEE ALSO + +L, L, L, L, L, L, +L, L, L, L + +=head1 CAVEATS + +The I file should B be edited by the B +command which locks the file and does grammatical checking. It is +imperative that I be free of syntax errors since B +will not run with a syntactically incorrect I file. + +When using netgroups of machines (as opposed to users), if you +store fully qualified host name in the netgroup (as is usually the +case), you either need to have the machine's host name be fully qualified +as returned by the C command or use the I option in +I. + +=head1 BUGS + +If you feel you have found a bug in B, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ + +=head1 SUPPORT + +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or +search the archives. + +=head1 DISCLAIMER + +B is provided ``AS IS'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the LICENSE +file distributed with B or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudoreplay.cat b/doc/sudoreplay.cat new file mode 100644 index 0000000..0f4816e --- /dev/null +++ b/doc/sudoreplay.cat @@ -0,0 +1,264 @@ +SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) + + + +NNAAMMEE + sudoreplay - replay sudo session logs + +SSYYNNOOPPSSIISS + 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 [--hh] [--dd _d_i_r_e_c_t_o_r_y] -l [search expression] + +DDEESSCCRRIIPPTTIIOONN + ssuuddoorreeppllaayy plays back or lists the output logs created by ssuuddoo. When + replaying, ssuuddoorreeppllaayy can play the session back in real-time, or the + playback speed may be adjusted (faster or slower) based on the command + line options. + + The _I_D should either be a six character sequence of digits and upper + case letters, e.g. 0100A5, or a pattern matching the _i_o_l_o_g___f_i_l_e option + in the _s_u_d_o_e_r_s file. When a command is run via ssuuddoo with _l_o_g___o_u_t_p_u_t + enabled in the _s_u_d_o_e_r_s file, a TSID=ID string is logged via syslog or + to the ssuuddoo log file. The _I_D may also be determined using ssuuddoorreeppllaayy's + list mode. + + In list mode, ssuuddoorreeppllaayy can be used to find the ID of a session based + on a number of criteria such as the user, tty or command run. + + In replay mode, if the standard output has not been redirected, + ssuuddoorreeppllaayy will act on the following keys: + + ' ' (space) + Pause output; press any key to resume. + + '<' Reduce the playback speed by one half. + + '>' Double the playback speed. + +OOPPTTIIOONNSS + ssuuddoorreeppllaayy accepts the following command line options: + + -d _d_i_r_e_c_t_o_r_y + Use _d_i_r_e_c_t_o_r_y to for the session logs instead of the + default, _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o. + + -f _f_i_l_t_e_r By default, ssuuddoorreeppllaayy will play back the command's + standard output, standard error and tty output. The _-_f + option can be used to select which of these to output. The + _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. + + -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 sessions in a format similar to the ssuuddoo log file + format, sorted by file name (or sequence number). 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 + regular expression support, a simple substring + match is performed instead. + + cwd _d_i_r_e_c_t_o_r_y + Evaluates to true if the command was run with the + specified current working directory. + + fromdate _d_a_t_e + Evaluates to true if the command was run on or + after _d_a_t_e. See "Date and time format" for a + description of supported date and time formats. + + group _r_u_n_a_s___g_r_o_u_p + Evaluates to true if the command was run with the + specified _r_u_n_a_s___g_r_o_u_p. Note that unless a + _r_u_n_a_s___g_r_o_u_p was explicitly specified when ssuuddoo was + run this field will be empty in the log. + + runas _r_u_n_a_s___u_s_e_r + Evaluates to true if the command was run as the + specified _r_u_n_a_s___u_s_e_r. Note that ssuuddoo runs commands + as user _r_o_o_t by default. + + todate _d_a_t_e + Evaluates to true if the command was run on or + prior to _d_a_t_e. See "Date and time format" for a + description of supported date and time formats. + + tty _t_t_y Evaluates to true if the command was run on the + specified terminal device. The _t_t_y should be + specified without the _/_d_e_v_/ prefix, e.g. _t_t_y_0_1 + instead of _/_d_e_v_/_t_t_y_0_1. + + user _u_s_e_r _n_a_m_e + Evaluates to true if the ID matches a command run + by _u_s_e_r _n_a_m_e. + + Predicates may be abbreviated to the shortest unique string + (currently all predicates may be shortened to a single + character). + + Predicates may be combined using _a_n_d, _o_r and _! operators as + well as '(' and ')' for grouping (note that parentheses + must generally be escaped from the shell). The _a_n_d + operator is optional, adjacent predicates have an implied + _a_n_d unless separated by an _o_r. + + -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 + point number, .e.g. _2_._5. + + -s _s_p_e_e_d___f_a_c_t_o_r + This option causes ssuuddoorreeppllaayy to adjust the number of + seconds it will wait between key presses or program output. + This can be used to slow down or speed up the display. For + example, a _s_p_e_e_d___f_a_c_t_o_r of _2 would make the output twice as + fast whereas a _s_p_e_e_d___f_a_c_t_o_r of <.5> would make the output + twice as slow. + + -V The --VV (version) option causes ssuuddoorreeppllaayy to print its + version number and exit. + + DDaattee aanndd ttiimmee ffoorrmmaatt + The time and date may be specified multiple ways, common formats + include: + + HH:MM:SS am MM/DD/CCYY timezone + 24 hour time may be used in place of am/pm. + + HH:MM:SS am Month, Day Year timezone + 24 hour time may be used in place of am/pm, and month and day + names may be abbreviated. Note that month and day of the week + names must be specified in English. + + CCYY-MM-DD HH:MM:SS + ISO time format + + DD Month CCYY HH:MM:SS + The month name may be abbreviated. + + Either time or date may be omitted, the am/pm and timezone are + optional. If no date is specified, the current day is assumed; if no + time is specified, the first second of the specified date is used. The + less significant parts of both time and date may also be omitted, in + which case zero is assumed. For example, the following are all valid: + + The following are all valid time and date specifications: + + now The current time and date. + + tomorrow + Exactly one day from now. + + yesterday + 24 hours ago. + + 2 hours ago + 2 hours ago. + + next Friday + The first second of the next Friday. + + this week + The current time but the first day of the coming week. + + a fortnight ago + The current time but 14 days ago. + + 10:01 am 9/17/2009 + 10:01 am, September 17, 2009. + + 10:01 am + 10:01 am on the current day. + + 10 10:00 am on the current day. + + 9/17/2009 + 00:00 am, September 17, 2009. + + 10:01 am Sep 17, 2009 + 10:01 am, September 17, 2009. + +FFIILLEESS + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o The default I/O log directory. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_l_o_g + Example session log info. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_s_t_d_i_n + Example session standard input log. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_s_t_d_o_u_t + Example session standard output log. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_s_t_d_e_r_r + Example session standard error log. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_t_t_y_i_n + Example session tty input file. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_t_t_y_o_u_t + Example session tty output file. + + _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_t_i_m_i_n_g + Example session timing file. + + Note that the _s_t_d_i_n, _s_t_d_o_u_t and _s_t_d_e_r_r files will be empty unless ssuuddoo + was used as part of a pipeline for a particular command. + +EEXXAAMMPPLLEESS + List sessions run by user _m_i_l_l_e_r_t: + + sudoreplay -l user millert + + 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: + + sudoreplay -l user jeff command '/bin/[a-z]*sh' + + List sessions run by jeff or bob on the console: + + sudoreplay -l ( user jeff or user bob ) tty console + +SSEEEE AALLSSOO + _s_u_d_o(1m), _s_c_r_i_p_t(1) + +AAUUTTHHOORR + Todd C. Miller + +BBUUGGSS + If you feel you have found a bug in ssuuddoorreeppllaayy, please submit a bug + report at http://www.sudo.ws/sudo/bugs/ + +SSUUPPPPOORRTT + Limited free support is available via the sudo-users mailing list, see + http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search + the archives. + +DDIISSCCLLAAIIMMEERR + ssuuddoorreeppllaayy is provided ``AS IS'' and any express or implied warranties, + including, but not limited to, the implied warranties of + merchantability and fitness for a particular purpose are disclaimed. + See the LICENSE file distributed with ssuuddoo or + http://www.sudo.ws/sudo/license.html for complete details. + + + +1.8.5 April 16, 2012 SUDOREPLAY(1m) diff --git a/doc/sudoreplay.man.in b/doc/sudoreplay.man.in new file mode 100644 index 0000000..df52ebe --- /dev/null +++ b/doc/sudoreplay.man.in @@ -0,0 +1,413 @@ +.\" 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 +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SUDOREPLAY @mansectsu@" +.TH SUDOREPLAY @mansectsu@ "April 16, 2012" "1.8.5" "MAINTENANCE COMMANDS" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +sudoreplay \- replay sudo session logs +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBsudoreplay\fR [\fB\-h\fR] [\fB\-d\fR \fIdirectory\fR] [\fB\-f\fR \fIfilter\fR] [\fB\-m\fR \fImax_wait\fR] [\fB\-s\fR \fIspeed_factor\fR] \s-1ID\s0 +.PP +\&\fBsudoreplay\fR [\fB\-h\fR] [\fB\-d\fR \fIdirectory\fR] \-l [search expression] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBsudoreplay\fR plays back or lists the output logs created by \fBsudo\fR. +When replaying, \fBsudoreplay\fR can play the session back in real-time, +or the playback speed may be adjusted (faster or slower) based on +the command line options. +.PP +The \fI\s-1ID\s0\fR should either be a six character sequence of digits and +upper case letters, e.g. \f(CW\*(C`0100A5\*(C'\fR, or a pattern matching the +\&\fIiolog_file\fR option in the \fIsudoers\fR file. When a command is run +via \fBsudo\fR with \fIlog_output\fR enabled in the \fIsudoers\fR file, a +\&\f(CW\*(C`TSID=ID\*(C'\fR string is logged via syslog or to the \fBsudo\fR log file. +The \fI\s-1ID\s0\fR may also be determined using \fBsudoreplay\fR's list mode. +.PP +In list mode, \fBsudoreplay\fR can be used to find the \s-1ID\s0 of a session +based on a number of criteria such as the user, tty or command run. +.PP +In replay mode, if the standard output has not been redirected, +\&\fBsudoreplay\fR will act on the following keys: +.IP "' ' (space)" 8 +.IX Item "' ' (space)" +Pause output; press any key to resume. +.IP "'<'" 8 +Reduce the playback speed by one half. +.IP "'>'" 8 +Double the playback speed. +.SH "OPTIONS" +.IX Header "OPTIONS" +\&\fBsudoreplay\fR accepts the following command line options: +.IP "\-d \fIdirectory\fR" 12 +.IX Item "-d directory" +Use \fIdirectory\fR to for the session logs instead of the default, +\&\fI/var/log/sudo\-io\fR. +.IP "\-f \fIfilter\fR" 12 +.IX Item "-f filter" +By default, \fBsudoreplay\fR will play back the command's standard +output, standard error and tty output. The \fI\-f\fR option can be +used to select which of these to output. The \fIfilter\fR argument +is a comma-separated list, consisting of one or more of following: +\&\fIstdout\fR, \fIstderr\fR, and \fIttyout\fR. +.IP "\-h" 12 +.IX Item "-h" +The \fB\-h\fR (\fIhelp\fR) option causes \fBsudoreplay\fR to print a short +help message to the standard output and exit. +.IP "\-l [\fIsearch expression\fR]" 12 +.IX Item "-l [search expression]" +Enable \*(L"list mode\*(R". In this mode, \fBsudoreplay\fR will list available +sessions in a format similar to the \fBsudo\fR log file format, sorted +by file name (or sequence number). If a \fIsearch expression\fR is +specified, it will be used to restrict the IDs that are displayed. +An expression is composed of the following predicates: +.RS 12 +.IP "command \fIcommand pattern\fR" 8 +.IX Item "command command pattern" +Evaluates to true if the command run matches \fIcommand pattern\fR. +On systems with \s-1POSIX\s0 regular expression support, the pattern may +be an extended regular expression. On systems without \s-1POSIX\s0 regular +expression support, a simple substring match is performed instead. +.IP "cwd \fIdirectory\fR" 8 +.IX Item "cwd directory" +Evaluates to true if the command was run with the specified current +working directory. +.IP "fromdate \fIdate\fR" 8 +.IX Item "fromdate date" +Evaluates to true if the command was run on or after \fIdate\fR. +See \*(L"Date and time format\*(R" for a description of supported +date and time formats. +.IP "group \fIrunas_group\fR" 8 +.IX Item "group runas_group" +Evaluates to true if the command was run with the specified +\&\fIrunas_group\fR. Note that unless a \fIrunas_group\fR was explicitly +specified when \fBsudo\fR was run this field will be empty in the log. +.IP "runas \fIrunas_user\fR" 8 +.IX Item "runas runas_user" +Evaluates to true if the command was run as the specified \fIrunas_user\fR. +Note that \fBsudo\fR runs commands as user \fIroot\fR by default. +.IP "todate \fIdate\fR" 8 +.IX Item "todate date" +Evaluates to true if the command was run on or prior to \fIdate\fR. +See \*(L"Date and time format\*(R" for a description of supported +date and time formats. +.IP "tty \fItty\fR" 8 +.IX Item "tty tty" +Evaluates to true if the command was run on the specified terminal +device. The \fItty\fR should be specified without the \fI/dev/\fR prefix, +e.g. \fItty01\fR instead of \fI/dev/tty01\fR. +.IP "user \fIuser name\fR" 8 +.IX Item "user user name" +Evaluates to true if the \s-1ID\s0 matches a command run by \fIuser name\fR. +.RE +.RS 12 +.Sp +Predicates may be abbreviated to the shortest unique string (currently +all predicates may be shortened to a single character). +.Sp +Predicates may be combined using \fIand\fR, \fIor\fR and \fI!\fR operators +as well as \f(CW\*(Aq(\*(Aq\fR and \f(CW\*(Aq)\*(Aq\fR for grouping (note that parentheses +must generally be escaped from the shell). The \fIand\fR operator is +optional, adjacent predicates have an implied \fIand\fR unless separated +by an \fIor\fR. +.RE +.IP "\-m \fImax_wait\fR" 12 +.IX Item "-m max_wait" +Specify an upper bound on how long to wait between key presses or +output data. By default, \fBsudo_replay\fR will accurately reproduce +the delays between key presses or program output. However, this +can be tedious when the session includes long pauses. When the +\&\fI\-m\fR option is specified, \fBsudoreplay\fR will limit these pauses +to at most \fImax_wait\fR seconds. The value may be specified as a +floating point number, .e.g. \fI2.5\fR. +.IP "\-s \fIspeed_factor\fR" 12 +.IX Item "-s speed_factor" +This option causes \fBsudoreplay\fR to adjust the number of seconds +it will wait between key presses or program output. This can be +used to slow down or speed up the display. For example, a +\&\fIspeed_factor\fR of \fI2\fR would make the output twice as fast whereas +a \fIspeed_factor\fR of <.5> would make the output twice as slow. +.IP "\-V" 12 +.IX Item "-V" +The \fB\-V\fR (version) option causes \fBsudoreplay\fR to print its version number +and exit. +.SS "Date and time format" +.IX Subsection "Date and time format" +The time and date may be specified multiple ways, common formats include: +.IP "\s-1HH:MM:SS\s0 am \s-1MM/DD/CCYY\s0 timezone" 8 +.IX Item "HH:MM:SS am MM/DD/CCYY timezone" +24 hour time may be used in place of am/pm. +.IP "\s-1HH:MM:SS\s0 am Month, Day Year timezone" 8 +.IX Item "HH:MM:SS am Month, Day Year timezone" +24 hour time may be used in place of am/pm, and month and day names +may be abbreviated. Note that month and day of the week names must +be specified in English. +.IP "CCYY-MM-DD \s-1HH:MM:SS\s0" 8 +.IX Item "CCYY-MM-DD HH:MM:SS" +\&\s-1ISO\s0 time format +.IP "\s-1DD\s0 Month \s-1CCYY\s0 \s-1HH:MM:SS\s0" 8 +.IX Item "DD Month CCYY HH:MM:SS" +The month name may be abbreviated. +.PP +Either time or date may be omitted, the am/pm and timezone are +optional. If no date is specified, the current day is assumed; if +no time is specified, the first second of the specified date is +used. The less significant parts of both time and date may also +be omitted, in which case zero is assumed. For example, the following +are all valid: +.PP +The following are all valid time and date specifications: +.IP "now" 8 +.IX Item "now" +The current time and date. +.IP "tomorrow" 8 +.IX Item "tomorrow" +Exactly one day from now. +.IP "yesterday" 8 +.IX Item "yesterday" +24 hours ago. +.IP "2 hours ago" 8 +.IX Item "2 hours ago" +2 hours ago. +.IP "next Friday" 8 +.IX Item "next Friday" +The first second of the next Friday. +.IP "this week" 8 +.IX Item "this week" +The current time but the first day of the coming week. +.IP "a fortnight ago" 8 +.IX Item "a fortnight ago" +The current time but 14 days ago. +.IP "10:01 am 9/17/2009" 8 +.IX Item "10:01 am 9/17/2009" +10:01 am, September 17, 2009. +.IP "10:01 am" 8 +.IX Item "10:01 am" +10:01 am on the current day. +.IP "10" 8 +.IX Item "10" +10:00 am on the current day. +.IP "9/17/2009" 8 +.IX Item "9/17/2009" +00:00 am, September 17, 2009. +.IP "10:01 am Sep 17, 2009" 8 +.IX Item "10:01 am Sep 17, 2009" +10:01 am, September 17, 2009. +.SH "FILES" +.IX Header "FILES" +.IP "\fI/var/log/sudo\-io\fR" 24 +.IX Item "/var/log/sudo-io" +The default I/O log directory. +.IP "\fI/var/log/sudo\-io/00/00/01/log\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/log" +Example session log info. +.IP "\fI/var/log/sudo\-io/00/00/01/stdin\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/stdin" +Example session standard input log. +.IP "\fI/var/log/sudo\-io/00/00/01/stdout\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/stdout" +Example session standard output log. +.IP "\fI/var/log/sudo\-io/00/00/01/stderr\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/stderr" +Example session standard error log. +.IP "\fI/var/log/sudo\-io/00/00/01/ttyin\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/ttyin" +Example session tty input file. +.IP "\fI/var/log/sudo\-io/00/00/01/ttyout\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/ttyout" +Example session tty output file. +.IP "\fI/var/log/sudo\-io/00/00/01/timing\fR" 24 +.IX Item "/var/log/sudo-io/00/00/01/timing" +Example session timing file. +.PP +Note that the \fIstdin\fR, \fIstdout\fR and \fIstderr\fR files will be empty +unless \fBsudo\fR was used as part of a pipeline for a particular +command. +.SH "EXAMPLES" +.IX Header "EXAMPLES" +List sessions run by user \fImillert\fR: +.PP +.Vb 1 +\& sudoreplay \-l user millert +.Ve +.PP +List sessions run by user \fIbob\fR with a command containing the string vi: +.PP +.Vb 1 +\& sudoreplay \-l user bob command vi +.Ve +.PP +List sessions run by user \fIjeff\fR that match a regular expression: +.PP +.Vb 1 +\& sudoreplay \-l user jeff command \*(Aq/bin/[a\-z]*sh\*(Aq +.Ve +.PP +List sessions run by jeff or bob on the console: +.PP +.Vb 1 +\& sudoreplay \-l ( user jeff or user bob ) tty console +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIsudo\fR\|(@mansectsu@), \fIscript\fR\|(1) +.SH "AUTHOR" +.IX Header "AUTHOR" +Todd C. Miller +.SH "BUGS" +.IX Header "BUGS" +If you feel you have found a bug in \fBsudoreplay\fR, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ +.SH "SUPPORT" +.IX Header "SUPPORT" +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or +search the archives. +.SH "DISCLAIMER" +.IX Header "DISCLAIMER" +\&\fBsudoreplay\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 +file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/sudoreplay.pod b/doc/sudoreplay.pod new file mode 100644 index 0000000..38c743d --- /dev/null +++ b/doc/sudoreplay.pod @@ -0,0 +1,351 @@ +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 +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=pod + +=head1 NAME + +sudoreplay - replay sudo session logs + +=head1 SYNOPSIS + +B [B<-h>] [B<-d> I] [B<-f> I] [B<-m> I] [B<-s> I] ID + +B [B<-h>] [B<-d> I] -l [search expression] + +=head1 DESCRIPTION + +B plays back or lists the output logs created by B. +When replaying, B can play the session back in real-time, +or the playback speed may be adjusted (faster or slower) based on +the command line options. + +The I should either be a six character sequence of digits and +upper case letters, e.g. C<0100A5>, or a pattern matching the +I option in the I file. When a command is run +via B with I enabled in the I file, a +C string is logged via syslog or to the B log file. +The I may also be determined using B's list mode. + +In list mode, B can be used to find the ID of a session +based on a number of criteria such as the user, tty or command run. + +In replay mode, if the standard output has not been redirected, +B will act on the following keys: + +=over 8 + +=item ' ' (space) + +Pause output; press any key to resume. + +=item '<' + +Reduce the playback speed by one half. + +=item '>' + +Double the playback speed. + +=back + +=head1 OPTIONS + +B accepts the following command line options: + +=over 12 + +=item -d I + +Use I to for the session logs instead of the default, +F. + +=item -f I + +By default, B will play back the command's standard +output, standard error and tty output. The I<-f> option can be +used to select which of these to output. The I argument +is a comma-separated list, consisting of one or more of following: +I, I, and I. + +=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 +sessions in a format similar to the B log file format, sorted +by file name (or sequence number). If a I is +specified, it will be used to restrict the IDs that are displayed. +An expression is composed of the following predicates: + +=over 8 + +=item command I + +Evaluates to true if the command run matches I. +On systems with POSIX regular expression support, the pattern may +be an extended regular expression. On systems without POSIX regular +expression support, a simple substring match is performed instead. + +=item cwd I + +Evaluates to true if the command was run with the specified current +working directory. + +=item fromdate I + +Evaluates to true if the command was run on or after I. +See L<"Date and time format"> for a description of supported +date and time formats. + +=item group I + +Evaluates to true if the command was run with the specified +I. Note that unless a I was explicitly +specified when B was run this field will be empty in the log. + +=item runas I + +Evaluates to true if the command was run as the specified I. +Note that B runs commands as user I by default. + +=item todate I + +Evaluates to true if the command was run on or prior to I. +See L<"Date and time format"> for a description of supported +date and time formats. + +=item tty I + +Evaluates to true if the command was run on the specified terminal +device. The I should be specified without the F prefix, +e.g. F instead of F. + +=item user I + +Evaluates to true if the ID matches a command run by I. + +=back + +Predicates may be abbreviated to the shortest unique string (currently +all predicates may be shortened to a single character). + +Predicates may be combined using I, I and I operators +as well as C<'('> and C<')'> for grouping (note that parentheses +must generally be escaped from the shell). The I operator is +optional, adjacent predicates have an implied I unless separated +by an I. + +=item -m I + +Specify an upper bound on how long to wait between key presses or +output data. By default, B will accurately reproduce +the delays between key presses or program output. However, this +can be tedious when the session includes long pauses. When the +I<-m> option is specified, B will limit these pauses +to at most I seconds. The value may be specified as a +floating point number, .e.g. I<2.5>. + +=item -s I + +This option causes B to adjust the number of seconds +it will wait between key presses or program output. This can be +used to slow down or speed up the display. For example, a +I of I<2> would make the output twice as fast whereas +a I of <.5> would make the output twice as slow. + +=item -V + +The B<-V> (version) option causes B to print its version number +and exit. + +=back + +=head2 Date and time format + +The time and date may be specified multiple ways, common formats include: + +=over 8 + +=item HH:MM:SS am MM/DD/CCYY timezone + +24 hour time may be used in place of am/pm. + +=item HH:MM:SS am Month, Day Year timezone + +24 hour time may be used in place of am/pm, and month and day names +may be abbreviated. Note that month and day of the week names must +be specified in English. + +=item CCYY-MM-DD HH:MM:SS + +ISO time format + +=item DD Month CCYY HH:MM:SS + +The month name may be abbreviated. + +=back + +Either time or date may be omitted, the am/pm and timezone are +optional. If no date is specified, the current day is assumed; if +no time is specified, the first second of the specified date is +used. The less significant parts of both time and date may also +be omitted, in which case zero is assumed. For example, the following +are all valid: + +The following are all valid time and date specifications: + +=over 8 + +=item now + +The current time and date. + +=item tomorrow + +Exactly one day from now. + +=item yesterday + +24 hours ago. + +=item 2 hours ago + +2 hours ago. + +=item next Friday + +The first second of the next Friday. + +=item this week + +The current time but the first day of the coming week. + +=item a fortnight ago + +The current time but 14 days ago. + +=item 10:01 am 9/17/2009 + +10:01 am, September 17, 2009. + +=item 10:01 am + +10:01 am on the current day. + +=item 10 + +10:00 am on the current day. + +=item 9/17/2009 + +00:00 am, September 17, 2009. + +=item 10:01 am Sep 17, 2009 + +10:01 am, September 17, 2009. + +=back + +=head1 FILES + +=over 24 + +=item F + +The default I/O log directory. + +=item F + +Example session log info. + +=item F + +Example session standard input log. + +=item F + +Example session standard output log. + +=item F + +Example session standard error log. + +=item F + +Example session tty input file. + +=item F + +Example session tty output file. + +=item F + +Example session timing file. + +=back + +Note that the I, I and I files will be empty +unless B was used as part of a pipeline for a particular +command. + +=head1 EXAMPLES + +List sessions run by user I: + + sudoreplay -l user millert + +List sessions run by user I with a command containing the string vi: + + sudoreplay -l user bob command vi + +List sessions run by user I that match a regular expression: + + sudoreplay -l user jeff command '/bin/[a-z]*sh' + +List sessions run by jeff or bob on the console: + + sudoreplay -l ( user jeff or user bob ) tty console + +=head1 SEE ALSO + +L, L + +=head1 AUTHOR + +Todd C. Miller + +=head1 BUGS + +If you feel you have found a bug in B, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ + +=head1 SUPPORT + +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or +search the archives. + +=head1 DISCLAIMER + +B is provided ``AS IS'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the LICENSE +file distributed with B or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/visudo.cat b/doc/visudo.cat new file mode 100644 index 0000000..b1a4e99 --- /dev/null +++ b/doc/visudo.cat @@ -0,0 +1,154 @@ +VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) + + + +NNAAMMEE + visudo - edit the sudoers file + +SSYYNNOOPPSSIISS + 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). + vviissuuddoo locks the _s_u_d_o_e_r_s file against multiple simultaneous edits, + provides basic sanity checks, and checks for parse errors. If the + _s_u_d_o_e_r_s file is currently being edited you will receive a message to + try again later. + + There is a hard-coded list of one or more editors that vviissuuddoo will use + set at compile-time that may be overridden via the _e_d_i_t_o_r _s_u_d_o_e_r_s + Default variable. This list defaults to "vi". Normally, vviissuuddoo does + not honor the VISUAL or EDITOR environment variables unless they + contain an editor in the aforementioned editors list. However, if + vviissuuddoo is configured with the _-_-_w_i_t_h_-_e_n_v_-_e_d_i_t_o_r option or the + _e_n_v___e_d_i_t_o_r Default variable is set in _s_u_d_o_e_r_s, vviissuuddoo will use any the + editor defines by VISUAL or EDITOR. Note that this can be a security + hole since it allows the user to execute any program they wish simply + by setting VISUAL or EDITOR. + + vviissuuddoo parses the _s_u_d_o_e_r_s file after the edit and will not save the + changes if there is a syntax error. Upon finding an error, vviissuuddoo will + print a message stating the line number(s) where the error occurred and + the user will receive the "What now?" prompt. At this point the user + may enter "e" to re-edit the _s_u_d_o_e_r_s file, "x" to exit without saving + the changes, or "Q" to quit and save changes. The "Q" option should be + used with extreme care because if vviissuuddoo believes there to be a parse + error, so will ssuuddoo and no one will be able to ssuuddoo again until the + error is fixed. If "e" is typed to edit the _s_u_d_o_e_r_s file after a + parse error has been detected, the cursor will be placed on the line + where the error occurred (if the editor supports this feature). + +OOPPTTIIOONNSS + vviissuuddoo accepts the following command line options: + + -c Enable cchheecckk--oonnllyy mode. The existing _s_u_d_o_e_r_s file will be + checked for syntax errors, owner and mode. A message will + be printed to the standard output describing the status of + _s_u_d_o_e_r_s unless the --qq option was specified. If the check + completes successfully, vviissuuddoo will exit with a value of 0. + If an error is encountered, vviissuuddoo will exit with a value + of 1. + + -f _s_u_d_o_e_r_s Specify and alternate _s_u_d_o_e_r_s file location. With this + 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. 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. + + -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 + used before it is defined, vviissuuddoo will consider this a + parse error. Note that it is not possible to differentiate + between an alias and a host name or user name that consists + solely of uppercase letters, digits, and the underscore + ('_') character. + + -V The --VV (version) option causes vviissuuddoo to print its version + number and exit. + +EENNVVIIRROONNMMEENNTT + The following environment variables may be consulted depending on the + value of the _e_d_i_t_o_r and _e_n_v___e_d_i_t_o_r _s_u_d_o_e_r_s variables: + + VISUAL Invoked by visudo as the editor to use + + EDITOR Used by visudo if VISUAL is not set + +FFIILLEESS + _/_e_t_c_/_s_u_d_o_e_r_s List of who can run what + + _/_e_t_c_/_s_u_d_o_e_r_s_._t_m_p Lock file for visudo + +DDIIAAGGNNOOSSTTIICCSS + sudoers file busy, try again later. + Someone else is currently editing the _s_u_d_o_e_r_s file. + + /etc/sudoers.tmp: Permission denied + You didn't run vviissuuddoo as root. + + Can't find you in the passwd database + Your userid does not appear in the system passwd file. + + Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined + Either you are trying to use an undeclare + {User,Runas,Host,Cmnd}_Alias or you have a user or host name listed + that consists solely of uppercase letters, digits, and the + underscore ('_') character. In the latter case, you can ignore the + warnings (ssuuddoo will not complain). In --ss (strict) mode these are + errors, not warnings. + + Warning: unused {User,Runas,Host,Cmnd}_Alias + The specified {User,Runas,Host,Cmnd}_Alias was defined but never + used. You may wish to comment out or remove the unused alias. In + --ss (strict) mode this is an error, not a warning. + + Warning: cycle in {User,Runas,Host,Cmnd}_Alias + The specified {User,Runas,Host,Cmnd}_Alias includes a reference to + itself, either directly or through an alias it includes. This is + only a warning by default as ssuuddoo will ignore cycles when parsing + the _s_u_d_o_e_r_s file. + +SSEEEE AALLSSOO + _v_i(1), _s_u_d_o_e_r_s(4), _s_u_d_o(1m), _v_i_p_w(1m) + +AAUUTTHHOORR + Many people have worked on ssuuddoo over the years; this version of vviissuuddoo + was written by: + + Todd Miller + + See the CONTRIBUTORS file in the ssuuddoo distribution + (http://www.sudo.ws/sudo/contributors.html) for a list of people who + have contributed to ssuuddoo. + +CCAAVVEEAATTSS + There is no easy way to prevent a user from gaining a root shell if the + editor used by vviissuuddoo allows shell escapes. + +BBUUGGSS + If you feel you have found a bug in vviissuuddoo, please submit a bug report + at http://www.sudo.ws/sudo/bugs/ + +SSUUPPPPOORRTT + Limited free support is available via the sudo-users mailing list, see + http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search + the archives. + +DDIISSCCLLAAIIMMEERR + vviissuuddoo is provided ``AS IS'' and any express or implied warranties, + including, but not limited to, the implied warranties of + merchantability and fitness for a particular purpose are disclaimed. + See the LICENSE file distributed with ssuuddoo or + http://www.sudo.ws/sudo/license.html for complete details. + + + +1.8.5 March 14, 2012 VISUDO(1m) diff --git a/doc/visudo.man.in b/doc/visudo.man.in new file mode 100644 index 0000000..20a1e11 --- /dev/null +++ b/doc/visudo.man.in @@ -0,0 +1,314 @@ +.\" Copyright (c) 1996,1998-2005, 2007-2012 +.\" 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. +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Sponsored in part by the Defense Advanced Research Projects +.\" Agency (DARPA) and Air Force Research Laboratory, Air Force +.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. +.\" +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` +. ds C' +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "VISUDO @mansectsu@" +.TH VISUDO @mansectsu@ "March 14, 2012" "1.8.5" "MAINTENANCE COMMANDS" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +visudo \- edit the sudoers file +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fBvisudo\fR [\fB\-chqsV\fR] [\fB\-f\fR \fIsudoers\fR] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBvisudo\fR edits the \fIsudoers\fR file in a safe fashion, analogous to +\&\fIvipw\fR\|(@mansectsu@). \fBvisudo\fR locks the \fIsudoers\fR file against multiple +simultaneous edits, provides basic sanity checks, and checks +for parse errors. If the \fIsudoers\fR file is currently being +edited you will receive a message to try again later. +.PP +There is a hard-coded list of one or more editors that \fBvisudo\fR will +use set at compile-time that may be overridden via the \fIeditor\fR \fIsudoers\fR +\&\f(CW\*(C`Default\*(C'\fR variable. This list defaults to \f(CW"@editor@"\fR. Normally, +\&\fBvisudo\fR does not honor the \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR environment +variables unless they contain an editor in the aforementioned editors +list. However, if \fBvisudo\fR is configured with the \fI\-\-with\-env\-editor\fR +option or the \fIenv_editor\fR \f(CW\*(C`Default\*(C'\fR variable is set in \fIsudoers\fR, +\&\fBvisudo\fR will use any the editor defines by \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR. +Note that this can be a security hole since it allows the user to +execute any program they wish simply by setting \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR. +.PP +\&\fBvisudo\fR parses the \fIsudoers\fR file after the edit and will +not save the changes if there is a syntax error. Upon finding +an error, \fBvisudo\fR will print a message stating the line number(s) +where the error occurred and the user will receive the +\&\*(L"What now?\*(R" prompt. At this point the user may enter \*(L"e\*(R" +to re-edit the \fIsudoers\fR file, \*(L"x\*(R" to exit without +saving the changes, or \*(L"Q\*(R" to quit and save changes. The +\&\*(L"Q\*(R" option should be used with extreme care because if \fBvisudo\fR +believes there to be a parse error, so will \fBsudo\fR and no one +will be able to \fBsudo\fR again until the error is fixed. +If \*(L"e\*(R" is typed to edit the \fIsudoers\fR file after a parse error +has been detected, the cursor will be placed on the line where the +error occurred (if the editor supports this feature). +.SH "OPTIONS" +.IX Header "OPTIONS" +\&\fBvisudo\fR accepts the following command line options: +.IP "\-c" 12 +.IX Item "-c" +Enable \fBcheck-only\fR mode. The existing \fIsudoers\fR file will be +checked for syntax errors, owner and mode. A message will be printed +to the standard output describing the status of \fIsudoers\fR unless +the \fB\-q\fR option was specified. If the check completes successfully, +\&\fBvisudo\fR will exit with a value of 0. If an error is encountered, +\&\fBvisudo\fR will exit with a value of 1. +.IP "\-f \fIsudoers\fR" 12 +.IX Item "-f sudoers" +Specify and alternate \fIsudoers\fR file location. With this option +\&\fBvisudo\fR will edit (or check) the \fIsudoers\fR file of your choice, +instead of the default, \fI@sysconfdir@/sudoers\fR. The lock file used +is the specified \fIsudoers\fR file with \*(L".tmp\*(R" appended to it. +In \fBcheck-only\fR mode only, the argument to \fB\-f\fR may be \*(L"\-\*(R", +indicating that \fIsudoers\fR will be read from the standard input. +.IP "\-h" 12 +.IX Item "-h" +The \fB\-h\fR (\fIhelp\fR) option causes \fBvisudo\fR to print a short help message +to the standard output and exit. +.IP "\-q" 12 +.IX Item "-q" +Enable \fBquiet\fR mode. In this mode details about syntax errors +are not printed. This option is only useful when combined with +the \fB\-c\fR option. +.IP "\-s" 12 +.IX Item "-s" +Enable \fBstrict\fR checking of the \fIsudoers\fR file. If an alias is +used before it is defined, \fBvisudo\fR will consider this a parse +error. Note that it is not possible to differentiate between an +alias and a host name or user name that consists solely of uppercase +letters, digits, and the underscore ('_') character. +.IP "\-V" 12 +.IX Item "-V" +The \fB\-V\fR (version) option causes \fBvisudo\fR to print its version number +and exit. +.SH "ENVIRONMENT" +.IX Header "ENVIRONMENT" +The following environment variables may be consulted depending on +the value of the \fIeditor\fR and \fIenv_editor\fR \fIsudoers\fR variables: +.ie n .IP "\*(C`VISUAL\*(C'" 16 +.el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16 +.IX Item "VISUAL" +Invoked by visudo as the editor to use +.ie n .IP "\*(C`EDITOR\*(C'" 16 +.el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16 +.IX Item "EDITOR" +Used by visudo if \s-1VISUAL\s0 is not set +.SH "FILES" +.IX Header "FILES" +.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24 +.el .IP "\fI@sysconfdir@/sudoers\fR" 24 +.IX Item "@sysconfdir@/sudoers" +List of who can run what +.ie n .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24 +.el .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24 +.IX Item "@sysconfdir@/sudoers.tmp" +Lock file for visudo +.SH "DIAGNOSTICS" +.IX Header "DIAGNOSTICS" +.IP "sudoers file busy, try again later." 4 +.IX Item "sudoers file busy, try again later." +Someone else is currently editing the \fIsudoers\fR file. +.ie n .IP "@sysconfdir@/sudoers.tmp: Permission denied" 4 +.el .IP "\f(CW@sysconfdir\fR@/sudoers.tmp: Permission denied" 4 +.IX Item "@sysconfdir@/sudoers.tmp: Permission denied" +You didn't run \fBvisudo\fR as root. +.IP "Can't find you in the passwd database" 4 +.IX Item "Can't find you in the passwd database" +Your userid does not appear in the system passwd file. +.IP "Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined" 4 +.IX Item "Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined" +Either you are trying to use an undeclare {User,Runas,Host,Cmnd}_Alias +or you have a user or host name listed that consists solely of +uppercase letters, digits, and the underscore ('_') character. In +the latter case, you can ignore the warnings (\fBsudo\fR will not +complain). In \fB\-s\fR (strict) mode these are errors, not warnings. +.IP "Warning: unused {User,Runas,Host,Cmnd}_Alias" 4 +.IX Item "Warning: unused {User,Runas,Host,Cmnd}_Alias" +The specified {User,Runas,Host,Cmnd}_Alias was defined but never +used. You may wish to comment out or remove the unused alias. In +\&\fB\-s\fR (strict) mode this is an error, not a warning. +.IP "Warning: cycle in {User,Runas,Host,Cmnd}_Alias" 4 +.IX Item "Warning: cycle in {User,Runas,Host,Cmnd}_Alias" +The specified {User,Runas,Host,Cmnd}_Alias includes a reference to +itself, either directly or through an alias it includes. This is +only a warning by default as \fBsudo\fR will ignore cycles when parsing +the \fIsudoers\fR file. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIvi\fR\|(1), \fIsudoers\fR\|(@mansectform@), \fIsudo\fR\|(@mansectsu@), \fIvipw\fR\|(@mansectsu@) +.SH "AUTHOR" +.IX Header "AUTHOR" +Many people have worked on \fBsudo\fR over the years; this version of +\&\fBvisudo\fR was written by: +.PP +.Vb 1 +\& Todd Miller +.Ve +.PP +See the \s-1CONTRIBUTORS\s0 file in the \fBsudo\fR distribution +(http://www.sudo.ws/sudo/contributors.html) for a list of people +who have contributed to \fBsudo\fR. +.SH "CAVEATS" +.IX Header "CAVEATS" +There is no easy way to prevent a user from gaining a root shell if +the editor used by \fBvisudo\fR allows shell escapes. +.SH "BUGS" +.IX Header "BUGS" +If you feel you have found a bug in \fBvisudo\fR, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ +.SH "SUPPORT" +.IX Header "SUPPORT" +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or +search the archives. +.SH "DISCLAIMER" +.IX Header "DISCLAIMER" +\&\fBvisudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 +file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/doc/visudo.pod b/doc/visudo.pod new file mode 100644 index 0000000..c3e9ba7 --- /dev/null +++ b/doc/visudo.pod @@ -0,0 +1,221 @@ +Copyright (c) 1996,1998-2005, 2007-2012 + 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. +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Sponsored in part by the Defense Advanced Research Projects +Agency (DARPA) and Air Force Research Laboratory, Air Force +Materiel Command, USAF, under agreement number F39502-99-1-0512. + +=pod + +=head1 NAME + +visudo - edit the sudoers file + +=head1 SYNOPSIS + +B [B<-chqsV>] [B<-f> I] + +=head1 DESCRIPTION + +B edits the I file in a safe fashion, analogous to +L. B locks the I file against multiple +simultaneous edits, provides basic sanity checks, and checks +for parse errors. If the I file is currently being +edited you will receive a message to try again later. + +There is a hard-coded list of one or more editors that B will +use set at compile-time that may be overridden via the I I +C variable. This list defaults to C<"@editor@">. Normally, +B does not honor the C or C environment +variables unless they contain an editor in the aforementioned editors +list. However, if B is configured with the I<--with-env-editor> +option or the I C variable is set in I, +B will use any the editor defines by C or C. +Note that this can be a security hole since it allows the user to +execute any program they wish simply by setting C or C. + +B parses the I file after the edit and will +not save the changes if there is a syntax error. Upon finding +an error, B will print a message stating the line number(s) +where the error occurred and the user will receive the +"What now?" prompt. At this point the user may enter "e" +to re-edit the I file, "x" to exit without +saving the changes, or "Q" to quit and save changes. The +"Q" option should be used with extreme care because if B +believes there to be a parse error, so will B and no one +will be able to B again until the error is fixed. +If "e" is typed to edit the I file after a parse error +has been detected, the cursor will be placed on the line where the +error occurred (if the editor supports this feature). + +=head1 OPTIONS + +B accepts the following command line options: + +=over 12 + +=item -c + +Enable B mode. The existing I file will be +checked for syntax errors, owner and mode. A message will be printed +to the standard output describing the status of I unless +the B<-q> option was specified. If the check completes successfully, +B will exit with a value of 0. If an error is encountered, +B will exit with a value of 1. + +=item -f I + +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 + +Enable B mode. In this mode details about syntax errors +are not printed. This option is only useful when combined with +the B<-c> option. + +=item -s + +Enable B checking of the I file. If an alias is +used before it is defined, B will consider this a parse +error. Note that it is not possible to differentiate between an +alias and a host name or user name that consists solely of uppercase +letters, digits, and the underscore ('_') character. + +=item -V + +The B<-V> (version) option causes B to print its version number +and exit. + +=back + +=head1 ENVIRONMENT + +The following environment variables may be consulted depending on +the value of the I and I I variables: + +=over 16 + +=item C + +Invoked by visudo as the editor to use + +=item C + +Used by visudo if VISUAL is not set + +=back + +=head1 FILES + +=over 24 + +=item F<@sysconfdir@/sudoers> + +List of who can run what + +=item F<@sysconfdir@/sudoers.tmp> + +Lock file for visudo + +=back + +=head1 DIAGNOSTICS + +=over 4 + +=item sudoers file busy, try again later. + +Someone else is currently editing the I file. + +=item @sysconfdir@/sudoers.tmp: Permission denied + +You didn't run B as root. + +=item Can't find you in the passwd database + +Your userid does not appear in the system passwd file. + +=item Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined + +Either you are trying to use an undeclare {User,Runas,Host,Cmnd}_Alias +or you have a user or host name listed that consists solely of +uppercase letters, digits, and the underscore ('_') character. In +the latter case, you can ignore the warnings (B will not +complain). In B<-s> (strict) mode these are errors, not warnings. + +=item Warning: unused {User,Runas,Host,Cmnd}_Alias + +The specified {User,Runas,Host,Cmnd}_Alias was defined but never +used. You may wish to comment out or remove the unused alias. In +B<-s> (strict) mode this is an error, not a warning. + +=item Warning: cycle in {User,Runas,Host,Cmnd}_Alias + +The specified {User,Runas,Host,Cmnd}_Alias includes a reference to +itself, either directly or through an alias it includes. This is +only a warning by default as B will ignore cycles when parsing +the I file. + +=back + +=head1 SEE ALSO + +L, L, L, L + +=head1 AUTHOR + +Many people have worked on B over the years; this version of +B was written by: + + Todd Miller + +See the CONTRIBUTORS file in the B distribution +(http://www.sudo.ws/sudo/contributors.html) for a list of people +who have contributed to B. + +=head1 CAVEATS + +There is no easy way to prevent a user from gaining a root shell if +the editor used by B allows shell escapes. + +=head1 BUGS + +If you feel you have found a bug in B, please submit a bug report +at http://www.sudo.ws/sudo/bugs/ + +=head1 SUPPORT + +Limited free support is available via the sudo-users mailing list, +see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or +search the archives. + +=head1 DISCLAIMER + +B is provided ``AS IS'' and any express or implied warranties, +including, but not limited to, the implied warranties of merchantability +and fitness for a particular purpose are disclaimed. See the LICENSE +file distributed with B or http://www.sudo.ws/sudo/license.html +for complete details. diff --git a/emul/charclass.h b/emul/charclass.h deleted file mode 100644 index 15463ff..0000000 --- a/emul/charclass.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2008 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. - */ - -/* - * POSIX character class support for fnmatch() and glob(). - */ -static struct cclass { - const char *name; - int (*isctype) __P((int)); -} cclasses[] = { - { "alnum", isalnum }, - { "alpha", isalpha }, - { "blank", isblank }, - { "cntrl", iscntrl }, - { "digit", isdigit }, - { "graph", isgraph }, - { "lower", islower }, - { "print", isprint }, - { "punct", ispunct }, - { "space", isspace }, - { "upper", isupper }, - { "xdigit", isxdigit }, - { NULL, NULL } -}; - -#define NCCLASSES (sizeof(cclasses) / sizeof(cclasses[0]) - 1) diff --git a/emul/fnmatch.h b/emul/fnmatch.h deleted file mode 100644 index 9f65bc5..0000000 --- a/emul/fnmatch.h +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 - * $OpenBSD: fnmatch.h,v 1.4 1997/09/22 05:25:32 millert Exp $ - */ - -#ifndef _FNMATCH_H_ -#define _FNMATCH_H_ - -#define FNM_NOMATCH 1 /* Match failed. */ - -#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ -#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ -#define FNM_PERIOD 0x04 /* Period must be matched by period. */ -#define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ -#define FNM_CASEFOLD 0x10 /* Case insensitive search. */ - -int fnmatch __P((const char *, const char *, int)); - -#endif /* !_FNMATCH_H_ */ diff --git a/emul/glob.h b/emul/glob.h deleted file mode 100644 index 36efc00..0000000 --- a/emul/glob.h +++ /dev/null @@ -1,84 +0,0 @@ -/* $OpenBSD: glob.h,v 1.8 2003/06/02 19:34:12 millert Exp $ */ - -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)glob.h 8.1 (Berkeley) 6/2/93 - */ - -#ifndef _GLOB_H_ -#define _GLOB_H_ - -struct stat; -typedef struct { - int gl_pathc; /* Count of total paths so far. */ - int gl_matchc; /* Count of paths matching pattern. */ - int gl_offs; /* Reserved at beginning of gl_pathv. */ - int gl_flags; /* Copy of flags parameter to glob. */ - char **gl_pathv; /* List of paths matching pattern. */ - /* Copy of errfunc parameter to glob. */ -#ifdef __STDC__ - int (*gl_errfunc)(const char *, int); -#else - int (*gl_errfunc)(); -#endif -} glob_t; - -/* Flags */ -#define GLOB_APPEND 0x0001 /* Append to output from previous call. */ -#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */ -#define GLOB_ERR 0x0004 /* Return on error. */ -#define GLOB_MARK 0x0008 /* Append / to matching directories. */ -#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */ -#define GLOB_NOSORT 0x0020 /* Don't sort. */ -#define GLOB_NOESCAPE 0x0040 /* Disable backslash escaping. */ - -/* Non-POSIX extensions */ -#define GLOB_MAGCHAR 0x0080 /* Pattern had globbing characters. */ -#define GLOB_BRACE 0x0100 /* Expand braces ala csh. */ -#define GLOB_TILDE 0x0200 /* Expand tilde names from the passwd file. */ - -/* Error values returned by glob(3) */ -#define GLOB_NOSPACE (-1) /* Malloc call failed. */ -#define GLOB_ABORTED (-2) /* Unignored error. */ -#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */ -#define GLOB_NOSYS (-4) /* Function not supported. */ -#define GLOB_ABEND GLOB_ABORTED - -#ifdef __STDC__ -int glob(const char *, int, int (*)(const char *, int), glob_t *); -void globfree(glob_t *); -#else -int glob(); -void globfree(); -#endif - -#endif /* !_GLOB_H_ */ diff --git a/emul/timespec.h b/emul/timespec.h deleted file mode 100644 index 681c523..0000000 --- a/emul/timespec.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2005 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_TIMESPEC_H -#define _SUDO_TIMESPEC_H - -struct timespec { - time_t tv_sec; - long tv_nsec; -}; - -#endif /* _SUDO_TIMESPEC_H */ diff --git a/emul/utime.h b/emul/utime.h deleted file mode 100644 index e5c63a5..0000000 --- a/emul/utime.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005 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 _UTIME_H -#define _UTIME_H - -struct utimbuf { - time_t actime; /* access time */ - time_t modtime; /* mod time */ -}; - -#ifdef __STDC__ -int utime(const char *, const struct utimbuf *); -#else -int utime(); -#endif - -#endif /* _UTIME_H */ diff --git a/env.c b/env.c deleted file mode 100644 index 2be75d8..0000000 --- a/env.c +++ /dev/null @@ -1,984 +0,0 @@ -/* - * Copyright (c) 2000-2005, 2007-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. - */ - -#include - -#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 */ -#include -#include -#include - -#include "sudo.h" - -/* - * Flags used in rebuild_env() - */ -#undef DID_TERM -#define DID_TERM 0x0001 -#undef DID_PATH -#define DID_PATH 0x0002 -#undef DID_HOME -#define DID_HOME 0x0004 -#undef DID_SHELL -#define DID_SHELL 0x0008 -#undef DID_LOGNAME -#define DID_LOGNAME 0x0010 -#undef DID_USER -#define DID_USER 0x0020 -#undef DID_USERNAME -#define DID_USERNAME 0x0040 -#undef DID_MAIL -#define DID_MAIL 0x0080 -#undef DID_MAX -#define DID_MAX 0x00ff - -#undef KEPT_TERM -#define KEPT_TERM 0x0100 -#undef KEPT_PATH -#define KEPT_PATH 0x0200 -#undef KEPT_HOME -#define KEPT_HOME 0x0400 -#undef KEPT_SHELL -#define KEPT_SHELL 0x0800 -#undef KEPT_LOGNAME -#define KEPT_LOGNAME 0x1000 -#undef KEPT_USER -#define KEPT_USER 0x2000 -#undef KEPT_USERNAME -#define KEPT_USERNAME 0x4000 -#undef KEPT_MAIL -#define KEPT_MAIL 0x8000 -#undef KEPT_MAX -#define KEPT_MAX 0xff00 - -struct environment { - char **envp; /* pointer to the new environment */ - size_t env_size; /* size of new_environ in char **'s */ - size_t env_len; /* number of slots used, not counting NULL */ - int owned; /* do we own envp or is it the system's? */ -}; - -/* - * Prototypes - */ -static void sudo_setenv __P((const char *, const char *, int)); -static void sudo_putenv __P((char *, int, int)); - -extern char **environ; /* global environment */ - -/* - * Copy of the sudo-managed environment. - */ -static struct environment env; - -/* - * Default table of "bad" variables to remove from the environment. - * XXX - how to omit TERMCAP if it starts with '/'? - */ -static const char *initial_badenv_table[] = { - "IFS", - "CDPATH", - "LOCALDOMAIN", - "RES_OPTIONS", - "HOSTALIASES", - "NLSPATH", - "PATH_LOCALE", - "LD_*", - "_RLD*", -#ifdef __hpux - "SHLIB_PATH", -#endif /* __hpux */ -#ifdef _AIX - "LDR_*", - "LIBPATH", - "AUTHSTATE", -#endif -#ifdef __APPLE__ - "DYLD_*", -#endif -#ifdef HAVE_KERB4 - "KRB_CONF*", - "KRBCONFDIR", - "KRBTKFILE", -#endif /* HAVE_KERB4 */ -#ifdef HAVE_KERB5 - "KRB5_CONFIG*", - "KRB5_KTNAME", -#endif /* HAVE_KERB5 */ -#ifdef HAVE_SECURID - "VAR_ACE", - "USR_ACE", - "DLC_ACE", -#endif /* HAVE_SECURID */ - "TERMINFO", /* terminfo, exclusive path to terminfo files */ - "TERMINFO_DIRS", /* terminfo, path(s) to terminfo files */ - "TERMPATH", /* termcap, path(s) to termcap files */ - "TERMCAP", /* XXX - only if it starts with '/' */ - "ENV", /* ksh, file to source before script runs */ - "BASH_ENV", /* bash, file to source before script runs */ - "PS4", /* bash, prefix for lines in xtrace mode */ - "GLOBIGNORE", /* bash, globbing patterns to ignore */ - "SHELLOPTS", /* bash, extra command line options */ - "JAVA_TOOL_OPTIONS", /* java, extra command line options */ - "PERLIO_DEBUG ", /* perl, debugging output file */ - "PERLLIB", /* perl, search path for modules/includes */ - "PERL5LIB", /* perl 5, search path for modules/includes */ - "PERL5OPT", /* perl 5, extra command line options */ - "PERL5DB", /* perl 5, command used to load debugger */ - "FPATH", /* ksh, search path for functions */ - "NULLCMD", /* zsh, command for null file redirection */ - "READNULLCMD", /* zsh, command for null file redirection */ - "ZDOTDIR", /* zsh, search path for dot files */ - "TMPPREFIX", /* zsh, prefix for temporary files */ - "PYTHONHOME", /* python, module search path */ - "PYTHONPATH", /* python, search path */ - "PYTHONINSPECT", /* python, allow inspection */ - "PYTHONUSERBASE", /* python, per user site-packages directory */ - "RUBYLIB", /* ruby, library load path */ - "RUBYOPT", /* ruby, extra command line options */ - NULL -}; - -/* - * Default table of variables to check for '%' and '/' characters. - */ -static const char *initial_checkenv_table[] = { - "COLORTERM", - "LANG", - "LANGUAGE", - "LC_*", - "LINGUAS", - "TERM", - NULL -}; - -/* - * Default table of variables to preserve in the environment. - */ -static const char *initial_keepenv_table[] = { - "COLORS", - "DISPLAY", - "HOSTNAME", - "KRB5CCNAME", - "LS_COLORS", - "PATH", - "PS1", - "PS2", - "TZ", - "XAUTHORITY", - "XAUTHORIZATION", - NULL -}; - -/* - * Initialize env based on envp. - */ -void -env_init(lazy) - int lazy; -{ - char * const *ep; - size_t len; - - for (ep = environ; *ep != NULL; ep++) - continue; - len = (size_t)(ep - environ); - - if (lazy) { - /* - * If we are already initialized due to lazy init (usualy via getenv()) - * we need to avoid calling malloc() as it may call getenv() itself. - */ - env.envp = environ; - env.env_len = len; - env.env_size = len; - } else if (!env.owned) { - env.env_len = len; - env.env_size = len + 1 + 128; - env.envp = emalloc2(env.env_size, sizeof(char *)); -#ifdef ENV_DEBUG - memset(env.envp, 0, env.env_size * sizeof(char *)); -#endif - memcpy(env.envp, environ, len * sizeof(char *)); - env.envp[len] = '\0'; - env.owned = TRUE; - } -} - -char ** -env_get() -{ - return env.envp; -} - -/* - * Similar to setenv(3) but operates on sudo's private copy of the environment - * (not environ) and it always overwrites. The dupcheck param determines - * whether we need to verify that the variable is not already set. - */ -static void -sudo_setenv(var, val, dupcheck) - const char *var; - const char *val; - int dupcheck; -{ - char *estring; - size_t esize; - - esize = strlen(var) + 1 + strlen(val) + 1; - estring = emalloc(esize); - - /* Build environment string and insert it. */ - if (strlcpy(estring, var, esize) >= esize || - strlcat(estring, "=", esize) >= esize || - strlcat(estring, val, esize) >= esize) { - - errorx(1, "internal error, sudo_setenv() overflow"); - } - sudo_putenv(estring, dupcheck, TRUE); -} - -/* - * Version of getenv(3) that uses our own environ pointer. - */ -char * -getenv(var) - const char *var; -{ - char *cp, **ev; - size_t vlen = strlen(var); - - if (env.envp == NULL) - env_init(TRUE); - - for (ev = env.envp; (cp = *ev) != NULL; ev++) { - if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=') - return cp + vlen + 1; - } - return NULL; -} - -/* - * Version of setenv(3) that uses our own environ pointer. - */ -int -setenv(var, val, overwrite) - const char *var; - const char *val; - int overwrite; -{ - char *estring, *ep; - const char *cp; - size_t esize; - - if (!var || *var == '\0') { - errno = EINVAL; - return(-1); - } - - if (env.envp == NULL) - env_init(TRUE); - - /* - * POSIX says a var name with '=' is an error but BSD - * just ignores the '=' and anything after it. - */ - for (cp = var; *cp && *cp != '='; cp++) - ; - esize = (size_t)(cp - var) + 2; - if (val) { - esize += strlen(val); /* glibc treats a NULL val as "" */ - } - - /* Allocate and fill in estring. */ - estring = ep = emalloc(esize); - for (cp = var; *cp && *cp != '='; cp++) - *ep++ = *cp; - *ep++ = '='; - if (val) { - for (cp = val; *cp; cp++) - *ep++ = *cp; - } - *ep = '\0'; - -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "setenv: corrupted envp, len mismatch"); -#endif - sudo_putenv(estring, TRUE, overwrite); - return(0); -} - -/* - * Version of unsetenv(3) that uses our own environ pointer. - */ -#ifdef UNSETENV_VOID -void -#else -int -#endif -unsetenv(var) - const char *var; -{ - char **ep; - size_t len; - - if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) { - errno = EINVAL; -#ifdef UNSETENV_VOID - return; -#else - return(-1); -#endif - } - - if (env.envp == NULL) - env_init(TRUE); - -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "unsetenv: corrupted envp, len mismatch"); -#endif - - len = strlen(var); - for (ep = env.envp; *ep != NULL;) { - if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') { - /* Found it; shift remainder + NULL over by one. */ - char **cur = ep; - while ((*cur = *(cur + 1)) != NULL) - cur++; - /* Keep going, could be multiple instances of the var. */ - } else { - ep++; - } - } - env.env_len = ep - env.envp; -#ifndef UNSETENV_VOID - return(0); -#endif -} - -/* - * Version of putenv(3) that uses our own environ pointer. - */ -int -#ifdef PUTENV_CONST -putenv(const char *string) -#else -putenv(string) - char *string; -#endif -{ - if (env.envp == NULL) - env_init(TRUE); - - if (strchr(string, '=') == NULL) { - errno = EINVAL; - return(-1); - } -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "putenv: corrupted envp, len mismatch"); -#endif - sudo_putenv((char *)string, TRUE, TRUE); - return(0); -} - -/* - * Similar to putenv(3) but operates on sudo's private copy of the - * environment (not environ) and it always overwrites. The dupcheck param - * determines whether we need to verify that the variable is not already set. - * Will only overwrite an existing variable if overwrite is set. - */ -static void -sudo_putenv(str, dupcheck, overwrite) - char *str; - int dupcheck; - int overwrite; -{ - char **ep; - size_t len; - int found = FALSE; - - /* Make sure there is room for the new entry plus a NULL. */ - if (env.env_len + 2 > env.env_size) { - env.env_size += 128; - if (env.owned) { - env.envp = erealloc3(env.envp, env.env_size, sizeof(char *)); - } else { - /* We don't own env.envp, allocate a new one. */ - ep = emalloc2(env.env_size, sizeof(char *)); - memcpy(ep, env.envp, env.env_size * sizeof(char *)); - env.envp = ep; - env.owned = TRUE; - } -#ifdef ENV_DEBUG - memset(env.envp + env.env_len, 0, - (env.env_size - env.env_len) * sizeof(char *)); -#endif - } - -#ifdef ENV_DEBUG - if (env.envp[env.env_len] != NULL) - errorx(1, "sudo_putenv: corrupted envp, len mismatch"); -#endif - - if (dupcheck) { - len = (strchr(str, '=') - str) + 1; - for (ep = env.envp; !found && *ep != NULL; ep++) { - if (strncmp(str, *ep, len) == 0) { - if (overwrite) - *ep = str; - found = TRUE; - } - } - /* Prune out duplicate variables. */ - if (found && overwrite) { - while (*ep != NULL) { - if (strncmp(str, *ep, len) == 0) { - char **cur = ep; - while ((*cur = *(cur + 1)) != NULL) - cur++; - } else { - ep++; - } - } - env.env_len = ep - env.envp; - } - } - - if (!found) { - ep = env.envp + env.env_len; - env.env_len++; - *ep++ = str; - *ep = NULL; - } -} - -/* - * Check the env_delete blacklist. - * Returns TRUE if the variable was found, else false. - */ -static int -matches_env_delete(var) - const char *var; -{ - struct list_member *cur; - size_t len; - int iswild, match = FALSE; - - /* Skip anything listed in env_delete. */ - for (cur = def_env_delete; cur; cur = cur->next) { - len = strlen(cur->value); - /* Deal with '*' wildcard */ - if (cur->value[len - 1] == '*') { - len--; - iswild = TRUE; - } else - iswild = FALSE; - if (strncmp(cur->value, var, len) == 0 && - (iswild || var[len] == '=')) { - match = TRUE; - break; - } - } - return(match); -} - -/* - * Apply the env_check list. - * Returns TRUE if the variable is allowed, FALSE if denied - * or -1 if no match. - */ -static int -matches_env_check(var) - const char *var; -{ - struct list_member *cur; - size_t len; - int iswild, keepit = -1; - - for (cur = def_env_check; cur; cur = cur->next) { - len = strlen(cur->value); - /* Deal with '*' wildcard */ - if (cur->value[len - 1] == '*') { - len--; - iswild = TRUE; - } else - iswild = FALSE; - if (strncmp(cur->value, var, len) == 0 && - (iswild || var[len] == '=')) { - keepit = !strpbrk(var, "/%"); - break; - } - } - return(keepit); -} - -/* - * Check the env_keep list. - * Returns TRUE if the variable is allowed else FALSE. - */ -static int -matches_env_keep(var) - const char *var; -{ - struct list_member *cur; - size_t len; - int iswild, keepit = FALSE; - - for (cur = def_env_keep; cur; cur = cur->next) { - len = strlen(cur->value); - /* Deal with '*' wildcard */ - if (cur->value[len - 1] == '*') { - len--; - iswild = TRUE; - } else - iswild = FALSE; - if (strncmp(cur->value, var, len) == 0 && - (iswild || var[len] == '=')) { - keepit = TRUE; - break; - } - } - return(keepit); -} - -/* - * Build a new environment and ether clear potentially dangerous - * variables from the old one or start with a clean slate. - * Also adds sudo-specific variables (SUDO_*). - */ -void -rebuild_env(noexec) - int noexec; -{ - char **old_envp, **ep, *cp, *ps1; - char idbuf[MAX_UID_T_LEN]; - unsigned int didvar; - int reset_home = FALSE; - - /* - * Either clean out the environment or reset to a safe default. - */ - ps1 = NULL; - didvar = 0; - env.env_len = 0; - env.env_size = 128; - old_envp = env.envp; - env.envp = emalloc2(env.env_size, sizeof(char *)); -#ifdef ENV_DEBUG - memset(env.envp, 0, env.env_size * sizeof(char *)); -#endif - - /* Reset HOME based on target user if configured to. */ - if (ISSET(sudo_mode, MODE_RUN)) { - if (def_always_set_home || - ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || - (ISSET(sudo_mode, MODE_SHELL) && def_set_home)) - reset_home = TRUE; - } - - if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) { - /* Pull in vars we want to keep from the old environment. */ - for (ep = old_envp; *ep; ep++) { - int keepit; - - /* Skip variables with values beginning with () (bash functions) */ - if ((cp = strchr(*ep, '=')) != NULL) { - if (strncmp(cp, "=() ", 3) == 0) - continue; - } - - /* - * First check certain variables for '%' and '/' characters. - * If no match there, check the keep list. - * If nothing matched, we remove it from the environment. - */ - keepit = matches_env_check(*ep); - if (keepit == -1) - keepit = matches_env_keep(*ep); - - /* For SUDO_PS1 -> PS1 conversion. */ - if (strncmp(*ep, "SUDO_PS1=", 8) == 0) - ps1 = *ep + 5; - - if (keepit) { - /* Preserve variable. */ - switch (**ep) { - case 'H': - if (strncmp(*ep, "HOME=", 5) == 0) - SET(didvar, DID_HOME); - break; - case 'L': - if (strncmp(*ep, "LOGNAME=", 8) == 0) - SET(didvar, DID_LOGNAME); - break; - case 'M': - if (strncmp(*ep, "MAIL=", 5) == 0) - SET(didvar, DID_MAIL); - break; - case 'P': - if (strncmp(*ep, "PATH=", 5) == 0) - SET(didvar, DID_PATH); - break; - case 'S': - if (strncmp(*ep, "SHELL=", 6) == 0) - SET(didvar, DID_SHELL); - break; - case 'T': - if (strncmp(*ep, "TERM=", 5) == 0) - SET(didvar, DID_TERM); - break; - case 'U': - if (strncmp(*ep, "USER=", 5) == 0) - SET(didvar, DID_USER); - if (strncmp(*ep, "USERNAME=", 5) == 0) - SET(didvar, DID_USERNAME); - break; - } - sudo_putenv(*ep, FALSE, FALSE); - } - } - didvar |= didvar << 8; /* convert DID_* to KEPT_* */ - - /* - * Add in defaults. In -i mode these come from the runas user, - * otherwise they may be from the user's environment (depends - * on sudoers options). - */ - if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { - sudo_setenv("SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL)); - sudo_setenv("LOGNAME", runas_pw->pw_name, - ISSET(didvar, DID_LOGNAME)); - sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER)); - sudo_setenv("USERNAME", runas_pw->pw_name, - ISSET(didvar, DID_USERNAME)); - } else { - if (!ISSET(didvar, DID_SHELL)) - sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE); - if (!ISSET(didvar, DID_LOGNAME)) - sudo_setenv("LOGNAME", user_name, FALSE); - if (!ISSET(didvar, DID_USER)) - sudo_setenv("USER", user_name, FALSE); - if (!ISSET(didvar, DID_USERNAME)) - sudo_setenv("USERNAME", user_name, FALSE); - } - - /* If we didn't keep HOME, reset it based on target user. */ - if (!ISSET(didvar, KEPT_HOME)) - reset_home = TRUE; - - /* - * Set MAIL to target user in -i mode or if MAIL is not preserved - * from user's environment. - */ - if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) { - cp = _PATH_MAILDIR; - if (cp[sizeof(_PATH_MAILDIR) - 2] == '/') - easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name); - else - easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name); - sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE); - } - } else { - /* - * Copy environ entries as long as they don't match env_delete or - * env_check. - */ - for (ep = old_envp; *ep; ep++) { - int okvar; - - /* Skip variables with values beginning with () (bash functions) */ - if ((cp = strchr(*ep, '=')) != NULL) { - if (strncmp(cp, "=() ", 3) == 0) - continue; - } - - /* - * First check variables against the blacklist in env_delete. - * If no match there check for '%' and '/' characters. - */ - okvar = matches_env_delete(*ep) != TRUE; - if (okvar) - okvar = matches_env_check(*ep) != FALSE; - - if (okvar) { - if (strncmp(*ep, "SUDO_PS1=", 9) == 0) - ps1 = *ep + 5; - else if (strncmp(*ep, "PATH=", 5) == 0) - SET(didvar, DID_PATH); - else if (strncmp(*ep, "TERM=", 5) == 0) - SET(didvar, DID_TERM); - sudo_putenv(*ep, FALSE, FALSE); - } - } - } - /* Replace the PATH envariable with a secure one? */ - if (def_secure_path && !user_is_exempt()) { - sudo_setenv("PATH", def_secure_path, TRUE); - SET(didvar, DID_PATH); - } - - /* Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is true. */ - if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL)) { - if (!ISSET(didvar, KEPT_LOGNAME)) - sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE); - if (!ISSET(didvar, KEPT_USER)) - sudo_setenv("USER", runas_pw->pw_name, TRUE); - if (!ISSET(didvar, KEPT_USERNAME)) - sudo_setenv("USERNAME", runas_pw->pw_name, TRUE); - } - - /* Set $HOME to target user if not preserving user's value. */ - if (reset_home) - sudo_setenv("HOME", runas_pw->pw_dir, TRUE); - - /* Provide default values for $TERM and $PATH if they are not set. */ - if (!ISSET(didvar, DID_TERM)) - sudo_putenv("TERM=unknown", FALSE, FALSE); - if (!ISSET(didvar, DID_PATH)) - sudo_setenv("PATH", _PATH_STDPATH, FALSE); - - /* - * Preload a noexec file? For a list of LD_PRELOAD-alikes, see - * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html - * XXX - should prepend to original value, if any - */ - if (noexec && def_noexec_file != NULL) { -#if defined(__darwin__) || defined(__APPLE__) - sudo_setenv("DYLD_INSERT_LIBRARIES", def_noexec_file, TRUE); - sudo_setenv("DYLD_FORCE_FLAT_NAMESPACE", "", TRUE); -#else -# if defined(__osf__) || defined(__sgi) - easprintf(&cp, "%s:DEFAULT", def_noexec_file); - sudo_setenv("_RLD_LIST", cp, TRUE); - efree(cp); -# else -# ifdef _AIX - sudo_setenv("LDR_PRELOAD", def_noexec_file, TRUE); -# else - sudo_setenv("LD_PRELOAD", def_noexec_file, TRUE); -# endif /* _AIX */ -# endif /* __osf__ || __sgi */ -#endif /* __darwin__ || __APPLE__ */ - } - - /* Set PS1 if SUDO_PS1 is set. */ - if (ps1 != NULL) - sudo_putenv(ps1, TRUE, TRUE); - - /* Add the SUDO_COMMAND envariable (cmnd + args). */ - if (user_args) { - easprintf(&cp, "%s %s", user_cmnd, user_args); - sudo_setenv("SUDO_COMMAND", cp, TRUE); - efree(cp); - } else { - sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE); - } - - /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ - sudo_setenv("SUDO_USER", user_name, TRUE); - snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_uid); - sudo_setenv("SUDO_UID", idbuf, TRUE); - snprintf(idbuf, sizeof(idbuf), "%lu", (unsigned long) user_gid); - sudo_setenv("SUDO_GID", idbuf, TRUE); - - /* Free old environment. */ - efree(old_envp); -} - -void -insert_env_vars(env_vars) - struct list_member *env_vars; -{ - struct list_member *cur; - - /* Add user-specified environment variables. */ - for (cur = env_vars; cur != NULL; cur = cur->next) - putenv(cur->value); -} - -/* - * Validate the list of environment variables passed in on the command - * line against env_delete, env_check, and env_keep. - * Calls log_error() if any specified variables are not allowed. - */ -void -validate_env_vars(env_vars) - struct list_member *env_vars; -{ - struct list_member *var; - char *eq, *bad = NULL; - size_t len, blen = 0, bsize = 0; - int okvar; - - /* Add user-specified environment variables. */ - for (var = env_vars; var != NULL; var = var->next) { - if (def_secure_path && !user_is_exempt() && - strncmp(var->value, "PATH=", 5) == 0) { - okvar = FALSE; - } else if (def_env_reset) { - okvar = matches_env_check(var->value); - if (okvar == -1) - okvar = matches_env_keep(var->value); - } else { - okvar = matches_env_delete(var->value) == FALSE; - if (okvar == FALSE) - okvar = matches_env_check(var->value) != FALSE; - } - if (okvar == FALSE) { - /* Not allowed, add to error string, allocating as needed. */ - if ((eq = strchr(var->value, '=')) != NULL) - *eq = '\0'; - len = strlen(var->value) + 2; - if (blen + len >= bsize) { - do { - bsize += 1024; - } while (blen + len >= bsize); - bad = erealloc(bad, bsize); - bad[blen] = '\0'; - } - strlcat(bad, var->value, bsize); - strlcat(bad, ", ", bsize); - blen += len; - if (eq != NULL) - *eq = '='; - } - } - if (bad != NULL) { - bad[blen - 2] = '\0'; /* remove trailing ", " */ - log_error(NO_MAIL, - "sorry, you are not allowed to set the following environment variables: %s", bad); - /* NOTREACHED */ - efree(bad); - } -} - -/* - * Read in /etc/environment ala AIX and Linux. - * Lines may be in either of three formats: - * NAME=VALUE - * NAME="VALUE" - * NAME='VALUE' - * with an optional "export" prefix so the shell can source the file. - * Invalid lines, blank lines, or lines consisting solely of a comment - * character are skipped. - */ -void -read_env_file(path, overwrite) - const char *path; - int overwrite; -{ - FILE *fp; - char *cp, *var, *val; - size_t var_len, val_len; - - if ((fp = fopen(path, "r")) == NULL) - return; - - while ((var = sudo_parseln(fp)) != NULL) { - /* Skip blank or comment lines */ - if (*var == '\0') - continue; - - /* Skip optional "export " */ - if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) { - var += 7; - while (isspace((unsigned char) *var)) { - var++; - } - } - - /* Must be of the form name=["']value['"] */ - for (val = var; *val != '\0' && *val != '='; val++) - ; - if (var == val || *val != '=') - continue; - var_len = (size_t)(val - var); - val_len = strlen(++val); - - /* Strip leading and trailing single/double quotes */ - if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) { - val[val_len - 1] = '\0'; - val++; - val_len -= 2; - } - - cp = emalloc(var_len + 1 + val_len + 1); - memcpy(cp, var, var_len + 1); /* includes '=' */ - memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */ - - sudo_putenv(cp, TRUE, overwrite); - } - fclose(fp); -} - -void -init_envtables() -{ - struct list_member *cur; - const char **p; - - /* Fill in the "env_delete" list. */ - for (p = initial_badenv_table; *p; p++) { - cur = emalloc(sizeof(struct list_member)); - cur->value = estrdup(*p); - cur->next = def_env_delete; - def_env_delete = cur; - } - - /* Fill in the "env_check" list. */ - for (p = initial_checkenv_table; *p; p++) { - cur = emalloc(sizeof(struct list_member)); - cur->value = estrdup(*p); - cur->next = def_env_check; - def_env_check = cur; - } - - /* Fill in the "env_keep" list. */ - for (p = initial_keepenv_table; *p; p++) { - cur = emalloc(sizeof(struct list_member)); - cur->value = estrdup(*p); - cur->next = def_env_keep; - def_env_keep = cur; - } -} diff --git a/error.c b/error.c deleted file mode 100644 index 317f105..0000000 --- a/error.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2004-2005 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. - */ - -#include -#include -#include -#include - -#include -#include -#include "error.h" - -static void _warning __P((int, const char *, va_list)); - void cleanup __P((int)); - -void -#ifdef __STDC__ -error(int eval, const char *fmt, ...) -#else -error(eval, fmt, va_alist) - int eval; - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - _warning(1, fmt, ap); - va_end(ap); - cleanup(0); - exit(eval); -} - -void -#ifdef __STDC__ -errorx(int eval, const char *fmt, ...) -#else -errorx(eval, fmt, va_alist) - int eval; - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - _warning(0, fmt, ap); - va_end(ap); - cleanup(0); - exit(eval); -} - -void -#ifdef __STDC__ -warning(const char *fmt, ...) -#else -warning(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - _warning(1, fmt, ap); - va_end(ap); -} - -void -#ifdef __STDC__ -warningx(const char *fmt, ...) -#else -warningx(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - _warning(0, fmt, ap); - va_end(ap); -} - -static void -_warning(use_errno, fmt, ap) - int use_errno; - const char *fmt; - va_list ap; -{ - int serrno = errno; - - fputs(getprogname(), stderr); - if (fmt != NULL) { - fputs(": ", stderr); - vfprintf(stderr, fmt, ap); - } - if (use_errno) { - fputs(": ", stderr); - fputs(strerror(serrno), stderr); - } - putc('\n', stderr); -} diff --git a/error.h b/error.h deleted file mode 100644 index 5ac3076..0000000 --- a/error.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2004 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_ERROR_H_ -#define _SUDO_ERROR_H_ - -#ifdef __STDC__ -# include -void error(int, const char *, ...) __attribute__((__noreturn__)); -void errorx(int, const char *, ...) __attribute__((__noreturn__)); -void warning(const char *, ...); -void warningx(const char *, ...); -#else -# include -void error() __attribute__((__noreturn__)); -void errorx() __attribute__((__noreturn__)); -void warning(); -void warningx(); -#endif /* __STDC__ */ - -#endif /* _SUDO_ERROR_H_ */ diff --git a/exec.c b/exec.c deleted file mode 100644 index 784f90a..0000000 --- a/exec.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_TERMIOS_H -# include -#else -# include -#endif /* HAVE_TERMIOS_H */ -#include -#ifdef HAVE_SYS_SELECT_H -# include -#endif /* HAVE_SYS_SELECT_H */ -#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 TIME_WITH_SYS_TIME -# include -#endif -#ifdef HAVE_SETLOCALE -# include -#endif -#include -#include -#include -#ifdef HAVE_SELINUX -# include -#endif - -#include "sudo.h" -#include "sudo_exec.h" - -/* shared with exec_pty.c */ -sig_atomic_t recvsig[NSIG]; -void handler __P((int s)); - -/* - * Like execve(2) but falls back to running through /bin/sh - * ala execvp(3) if we get ENOEXEC. - */ -int -my_execve(path, argv, envp) - const char *path; - char *argv[]; - char *envp[]; -{ - execve(path, argv, envp); - if (errno == ENOEXEC) { - argv--; /* at least one extra slot... */ - argv[0] = "sh"; - argv[1] = (char *)path; - execve(_PATH_BSHELL, argv, envp); - } - return -1; -} - -/* - * Fork and execute a command, returns the child's pid. - * Sends errno back on sv[1] if execve() fails. - */ -static int fork_cmnd(path, argv, envp, sv, rbac_enabled) - const char *path; - char *argv[]; - char *envp[]; - int sv[2]; - int rbac_enabled; -{ - struct command_status cstat; - sigaction_t sa; - int pid; - - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */ - sa.sa_handler = handler; - sigaction(SIGCONT, &sa, NULL); - - pid = fork(); - switch (pid) { - case -1: - error(1, "fork"); - break; - case 0: - /* child */ - close(sv[0]); - fcntl(sv[1], F_SETFD, FD_CLOEXEC); - if (exec_setup(rbac_enabled, user_ttypath, -1) == TRUE) { - /* headed for execve() */ - closefrom(def_closefrom); -#ifdef HAVE_SELINUX - if (rbac_enabled) - selinux_execve(path, argv, envp); - else -#endif - my_execve(path, argv, envp); - } - cstat.type = CMD_ERRNO; - cstat.val = errno; - send(sv[1], &cstat, sizeof(cstat), 0); - _exit(1); - } - return pid; -} - -/* - * Execute a command, potentially in a pty with I/O loggging. - * This is a little bit tricky due to how POSIX job control works and - * we fact that we have two different controlling terminals to deal with. - */ -int -sudo_execve(path, argv, envp, uid, cstat, dowait, bgmode) - const char *path; - char *argv[]; - char *envp[]; - uid_t uid; - struct command_status *cstat; - int dowait; - int bgmode; -{ - sigaction_t sa; - fd_set *fdsr, *fdsw; - int maxfd, n, nready, status, sv[2]; - int rbac_enabled = 0; - int log_io; - pid_t child; - - /* If running in background mode, fork and exit. */ - if (bgmode) { - switch (fork()) { - case -1: - cstat->type = CMD_ERRNO; - cstat->val = errno; - return -1; - case 0: - /* child continues */ - break; - default: - /* parent exits */ - exit(0); - } - } - -#ifdef _PATH_SUDO_IO_LOGDIR - log_io = def_log_output || def_log_input || def_use_pty; - if (log_io) { - if (!bgmode) - pty_setup(uid); - io_log_open(); - dowait = TRUE; - } -#endif /* _PATH_SUDO_IO_LOGDIR */ - -#ifdef HAVE_SELINUX - rbac_enabled = is_selinux_enabled() > 0 && user_role != NULL; - if (rbac_enabled) - dowait = TRUE; -#endif - - /* - * If we don't need to wait for the command to finish, just exec it. - */ - if (!dowait) { - exec_setup(FALSE, NULL, -1); - closefrom(def_closefrom); - my_execve(path, argv, envp); - cstat->type = CMD_ERRNO; - cstat->val = errno; - return(127); - } - - /* - * We communicate with the child over a bi-directional pair of sockets. - * Parent sends signal info to child and child sends back wait status. - */ - if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) != 0) - error(1, "cannot create sockets"); - - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - - /* 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(SIGCHLD, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGPIPE, &sa, NULL); - sigaction(SIGQUIT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - - /* Max fd we will be selecting on. */ - maxfd = sv[0]; - - /* - * Child will run the command in the pty, parent will pass data - * to and from pty. Adjusts maxfd as needed. - */ -#ifdef _PATH_SUDO_IO_LOGDIR - if (log_io) - child = fork_pty(path, argv, envp, sv, rbac_enabled, &maxfd); - else -#endif - child = fork_cmnd(path, argv, envp, sv, rbac_enabled); - close(sv[1]); - -#ifdef HAVE_SETLOCALE - /* - * I/O logging must be in the C locale for floating point numbers - * to be logged consistently. - */ - setlocale(LC_ALL, "C"); -#endif - - /* - * In the event loop we pass input from user tty to master - * and pass output from master to stdout and IO plugin. - */ - fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); - fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); - for (;;) { - 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(sv[0], fdsr); -#ifdef _PATH_SUDO_IO_LOGDIR - 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"); - } - if (FD_ISSET(sv[0], fdsr)) { - /* read child status */ - n = recv(sv[0], cstat, sizeof(*cstat), 0); - if (n == -1) { - if (errno == EINTR) - continue; - /* - * If not logging I/O we will receive ECONNRESET when - * the command is executed. It is safe to ignore this. - */ - if (log_io && errno != EAGAIN) { - cstat->type = CMD_ERRNO; - cstat->val = errno; - break; - } - } -#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; - continue; - } else { - /* Child exited or was killed, either way we are done. */ - break; - } - } else -#endif /* _PATH_SUDO_IO_LOGDIR */ - if (cstat->type == CMD_ERRNO) { - /* Child was unable to execute command or broken pipe. */ - break; - } - } - -#ifdef _PATH_SUDO_IO_LOGDIR - /* 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) - break; -#endif /* _PATH_SUDO_IO_LOGDIR */ - } - -#ifdef _PATH_SUDO_IO_LOGDIR - if (log_io) { - /* Flush any remaining output and free pty-related memory. */ - pty_close(cstat); - } -#endif /* _PATH_SUDO_IO_LOGDIR */ - -#ifdef HAVE_SELINUX - if (rbac_enabled) { - /* This is probably not needed in log_io mode. */ - if (selinux_restore_tty() != 0) - warningx("unable to restore tty label"); - } -#endif - - efree(fdsr); - efree(fdsw); - - return cstat->type == CMD_ERRNO ? -1 : 0; -} - -/* - * Generic handler for signals passed from parent -> child. - * The recvsig[] array is checked in the main event loop. - */ -void -handler(s) - int s; -{ - recvsig[s] = TRUE; -} diff --git a/exec_pty.c b/exec_pty.c deleted file mode 100644 index 2d6b0e8..0000000 --- a/exec_pty.c +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_TERMIOS_H -# include -#else -# include -#endif /* HAVE_TERMIOS_H */ -#include -#ifdef HAVE_SYS_SELECT_H -# include -#endif /* HAVE_SYS_SELECT_H */ -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if TIME_WITH_SYS_TIME -# include -#endif -#include -#include -#include - -#include "sudo.h" -#include "sudo_exec.h" - -#define SFD_STDIN 0 -#define SFD_STDOUT 1 -#define SFD_STDERR 2 -#define SFD_MASTER 3 -#define SFD_SLAVE 4 -#define SFD_USERTTY 5 - -#define TERM_COOKED 0 -#define TERM_RAW 1 - -/* Compatibility with older tty systems. */ -#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ) -# define TIOCGSIZE TIOCGWINSZ -# define TIOCSSIZE TIOCSWINSZ -# define ttysize winsize -# define ts_cols ws_col -#endif - -struct io_buffer { - struct io_buffer *next; - int len; /* buffer length (how much produced) */ - int off; /* write position (how much already consumed) */ - int rfd; /* reader (producer) */ - int wfd; /* writer (consumer) */ - int (*action) __P((const char *buf, unsigned int len)); - char buf[16 * 1024]; -}; - -static char slavename[PATH_MAX]; -static int foreground; -static int io_fds[6] = { -1, -1, -1, -1, -1, -1}; -static int pipeline = FALSE; -static int tty_initialized; -static int ttymode = TERM_COOKED; -static pid_t ppgrp, child; -static struct io_buffer *iobufs; - -static void flush_output __P((void)); -static int exec_monitor __P((const char *path, char *argv[], - char *envp[], int, int)); -static void exec_pty __P((const char *path, char *argv[], - char *envp[], int)); -static void sigwinch __P((int s)); -static void sync_ttysize __P((int src, int dst)); -static void deliver_signal __P((pid_t pid, int signo)); -static int safe_close __P((int fd)); - -/* - * Allocate a pty if /dev/tty is a tty. - * Fills in io_fds[SFD_USERTTY], io_fds[SFD_MASTER], io_fds[SFD_SLAVE] - * and slavename globals. - */ -void -pty_setup(uid) - uid_t uid; -{ - io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0); - if (io_fds[SFD_USERTTY] != -1) { - if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE], - slavename, sizeof(slavename), uid)) - error(1, "Can't get pty"); - } -} - -/* - * Check whether we are running in the foregroup. - * Updates the foreground global and does lazy init of the - * the pty slave as needed. - */ -static void -check_foreground() -{ - if (io_fds[SFD_USERTTY] != -1) { - foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp; - if (foreground && !tty_initialized) { - if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) { - tty_initialized = 1; - sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]); - } - } - } -} - -/* - * Suspend sudo if the underlying command is suspended. - * Returns SIGUSR1 if the child should be resume in foreground else SIGUSR2. - */ -int -suspend_parent(signo) - int signo; -{ - sigaction_t sa, osa; - int n, oldmode = ttymode, rval = 0; - - switch (signo) { - case SIGTTOU: - case SIGTTIN: - /* - * If we are the foreground process, just resume the child. - * Otherwise, re-send the signal with the handler disabled. - */ - if (!foreground) - check_foreground(); - if (foreground) { - if (ttymode != TERM_RAW) { - do { - n = term_raw(io_fds[SFD_USERTTY], 0); - } while (!n && errno == EINTR); - ttymode = TERM_RAW; - } - rval = SIGUSR1; /* resume child in foreground */ - break; - } - ttymode = TERM_RAW; - /* FALLTHROUGH */ - case SIGSTOP: - case SIGTSTP: - /* Flush any remaining output before suspending. */ - flush_output(); - - /* Restore original tty mode before suspending. */ - if (oldmode != TERM_COOKED) { - do { - n = term_restore(io_fds[SFD_USERTTY], 0); - } while (!n && errno == EINTR); - } - - /* Suspend self and continue child when we resume. */ - sa.sa_handler = SIG_DFL; - sigaction(signo, &sa, &osa); - if (killpg(ppgrp, signo) != 0) - warning("killpg(%d, %d)", ppgrp, signo); - - /* Check foreground/background status on resume. */ - check_foreground(); - - /* - * Only modify term if we are foreground process and either - * the old tty mode was not cooked or child got SIGTT{IN,OU} - */ - if (ttymode != TERM_COOKED) { - if (foreground) { - /* Set raw mode. */ - do { - n = term_raw(io_fds[SFD_USERTTY], 0); - } while (!n && errno == EINTR); - } else { - /* Background process, no access to tty. */ - ttymode = TERM_COOKED; - } - } - - sigaction(signo, &osa, NULL); - rval = ttymode == TERM_RAW ? SIGUSR1 : SIGUSR2; - break; - } - - return(rval); -} - -/* - * Kill child with increasing urgency. - */ -static void -terminate_child(pid, use_pgrp) - pid_t pid; - int use_pgrp; -{ - /* - * Note that SIGCHLD will interrupt the sleep() - */ - if (use_pgrp) { - killpg(pid, SIGHUP); - killpg(pid, SIGTERM); - sleep(2); - killpg(pid, SIGKILL); - } else { - kill(pid, SIGHUP); - kill(pid, SIGTERM); - sleep(2); - kill(pid, SIGKILL); - } -} - -/* - * Allocate a new io_buffer struct and insert it at the head of the list. - * Returns the new head element. - */ -static struct io_buffer * -io_buf_new(rfd, wfd, action, head) - int rfd; - int wfd; - int (*action) __P((const char *, unsigned int)); - struct io_buffer *head; -{ - struct io_buffer *iob; - - iob = emalloc(sizeof(*iob)); - zero_bytes(iob, sizeof(*iob)); - iob->rfd = rfd; - iob->wfd = wfd; - iob->action = action; - iob->next = head; - return iob; -} - -/* - * Read/write iobufs depending on fdsr and fdsw. - * Fills in cstat on error. - * Returns the number of errors. - */ -int -perform_io(fdsr, fdsw, cstat) - fd_set *fdsr; - fd_set *fdsw; - struct command_status *cstat; -{ - struct io_buffer *iob; - int n, errors = 0; - - for (iob = iobufs; iob; iob = iob->next) { - if (iob->rfd != -1 && FD_ISSET(iob->rfd, fdsr)) { - do { - n = read(iob->rfd, iob->buf + iob->len, - sizeof(iob->buf) - iob->len); - } while (n == -1 && errno == EINTR); - switch (n) { - case -1: - if (errno == EAGAIN) - break; - if (errno != ENXIO && errno != EBADF) { - errors++; - break; - } - /* FALLTHROUGH */ - case 0: - /* got EOF or pty has gone away */ - safe_close(iob->rfd); - iob->rfd = -1; - break; - default: - if (!iob->action(iob->buf + iob->len, n)) - terminate_child(child, TRUE); - iob->len += n; - break; - } - } - if (iob->wfd != -1 && FD_ISSET(iob->wfd, fdsw)) { - do { - n = write(iob->wfd, iob->buf + iob->off, - iob->len - iob->off); - } while (n == -1 && errno == EINTR); - if (n == -1) { - if (errno == EPIPE || errno == ENXIO || errno == EBADF) { - /* other end of pipe closed or pty revoked */ - if (iob->rfd != -1) { - safe_close(iob->rfd); - iob->rfd = -1; - } - safe_close(iob->wfd); - iob->wfd = -1; - continue; - } - if (errno != EAGAIN) - errors++; - } else { - iob->off += n; - } - } - } - if (errors && cstat != NULL) { - cstat->type = CMD_ERRNO; - cstat->val = errno; - } - return errors; -} - -/* - * Fork a monitor process which runs the actual command as its own child - * process with std{in,out,err} hooked up to the pty or pipes as appropriate. - * Returns the child pid. - */ -int -fork_pty(path, argv, envp, sv, rbac_enabled, maxfd) - const char *path; - char *argv[]; - char *envp[]; - int sv[2]; - int rbac_enabled; - int *maxfd; -{ - struct command_status cstat; - struct io_buffer *iob; - int io_pipe[3][2], n; - sigaction_t sa; - - ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */ - - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - - if (io_fds[SFD_USERTTY] != -1) { - sa.sa_flags = SA_RESTART; - sa.sa_handler = sigwinch; - sigaction(SIGWINCH, &sa, NULL); - } - - /* - * Setup stdin/stdout/stderr for child, to be duped after forking. - */ - io_fds[SFD_STDIN] = io_fds[SFD_SLAVE]; - io_fds[SFD_STDOUT] = io_fds[SFD_SLAVE]; - io_fds[SFD_STDERR] = io_fds[SFD_SLAVE]; - - /* Copy /dev/tty -> pty master */ - if (io_fds[SFD_USERTTY] != -1) { - iobufs = io_buf_new(io_fds[SFD_USERTTY], io_fds[SFD_MASTER], - log_ttyin, iobufs); - - /* Copy pty master -> /dev/tty */ - iobufs = io_buf_new(io_fds[SFD_MASTER], io_fds[SFD_USERTTY], - log_ttyout, iobufs); - - /* Are we the foreground process? */ - foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp; - } - - /* - * If either stdin, stdout or stderr is not a tty we use a pipe - * to interpose ourselves instead of duping the pty fd. - */ - memset(io_pipe, 0, sizeof(io_pipe)); - if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) { - pipeline = TRUE; - if (pipe(io_pipe[STDIN_FILENO]) != 0) - error(1, "unable to create pipe"); - iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], - log_stdin, iobufs); - io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; - } - if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) { - pipeline = TRUE; - if (pipe(io_pipe[STDOUT_FILENO]) != 0) - error(1, "unable to create pipe"); - iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, - log_stdout, iobufs); - io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; - } - if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) { - if (pipe(io_pipe[STDERR_FILENO]) != 0) - error(1, "unable to create pipe"); - iobufs = io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, - log_stderr, iobufs); - io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; - } - - /* Job control signals to relay from parent to child. */ - sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */ - sa.sa_handler = handler; - sigaction(SIGTSTP, &sa, NULL); - - if (foreground) { - /* Copy terminal attrs from user tty -> pty slave. */ - if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) { - tty_initialized = 1; - sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]); - } - - /* Start out in raw mode if we are not part of a pipeline. */ - if (!pipeline) { - ttymode = TERM_RAW; - do { - n = term_raw(io_fds[SFD_USERTTY], 0); - } while (!n && errno == EINTR); - if (!n) - error(1, "Can't set terminal to raw mode"); - } - } - - child = fork(); - switch (child) { - case -1: - error(1, "fork"); - break; - case 0: - /* child */ - close(sv[0]); - fcntl(sv[1], F_SETFD, FD_CLOEXEC); - if (exec_setup(rbac_enabled, slavename, io_fds[SFD_SLAVE]) == TRUE) { - /* Close the other end of the stdin/stdout/stderr pipes and exec. */ - if (io_pipe[STDIN_FILENO][1]) - close(io_pipe[STDIN_FILENO][1]); - if (io_pipe[STDOUT_FILENO][0]) - close(io_pipe[STDOUT_FILENO][0]); - if (io_pipe[STDERR_FILENO][0]) - close(io_pipe[STDERR_FILENO][0]); - exec_monitor(path, argv, envp, sv[1], rbac_enabled); - } - cstat.type = CMD_ERRNO; - cstat.val = errno; - send(sv[1], &cstat, sizeof(cstat), 0); - _exit(1); - } - - /* Close the other end of the stdin/stdout/stderr pipes. */ - if (io_pipe[STDIN_FILENO][0]) - close(io_pipe[STDIN_FILENO][0]); - if (io_pipe[STDOUT_FILENO][1]) - close(io_pipe[STDOUT_FILENO][1]); - if (io_pipe[STDERR_FILENO][1]) - close(io_pipe[STDERR_FILENO][1]); - - for (iob = iobufs; iob; iob = iob->next) { - /* Adjust maxfd. */ - if (iob->rfd > *maxfd) - *maxfd = iob->rfd; - if (iob->wfd > *maxfd) - *maxfd = iob->wfd; - - /* Set non-blocking mode. */ - n = fcntl(iob->rfd, F_GETFL, 0); - if (n != -1 && !ISSET(n, O_NONBLOCK)) - (void) fcntl(iob->rfd, F_SETFL, n | O_NONBLOCK); - n = fcntl(iob->wfd, F_GETFL, 0); - if (n != -1 && !ISSET(n, O_NONBLOCK)) - (void) fcntl(iob->wfd, F_SETFL, n | O_NONBLOCK); - } - - return child; -} - -/* - * Flush any remaining output and restore /dev/tty to the way we found it. - * If the command died due to a signal, writes the reason to stdout. - */ -void -pty_close(cstat) - struct command_status *cstat; -{ - int n; - - /* Flush any remaining output (the plugin already got it) */ - if (io_fds[SFD_USERTTY] != -1) { - n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0); - if (n != -1 && ISSET(n, O_NONBLOCK)) { - CLR(n, O_NONBLOCK); - (void) fcntl(io_fds[SFD_USERTTY], F_SETFL, n); - } - } - flush_output(); - - if (io_fds[SFD_USERTTY] != -1) { - do { - n = term_restore(io_fds[SFD_USERTTY], 0); - } while (!n && errno == EINTR); - } - - /* If child was signalled, write the reason to stdout like the shell. */ - if (cstat->type == CMD_WSTATUS && WIFSIGNALED(cstat->val)) { - int signo = WTERMSIG(cstat->val); - if (signo && signo != SIGINT && signo != SIGPIPE) { - const char *reason = strsignal(signo); - n = io_fds[SFD_USERTTY] != -1 ? - io_fds[SFD_USERTTY] : STDOUT_FILENO; - write(n, reason, strlen(reason)); - if (WCOREDUMP(cstat->val)) - write(n, " (core dumped)", 14); - write(n, "\n", 1); - } - } -} - - -/* - * Fill in fdsr and fdsw based on the io buffers list. - * Called prior to select(). - */ -void -fd_set_iobs(fdsr, fdsw) - fd_set *fdsr; - fd_set *fdsw; -{ - struct io_buffer *iob; - - for (iob = iobufs; iob; iob = iob->next) { - if (iob->rfd == -1 && iob->wfd == -1) - continue; - if (iob->off == iob->len) { - iob->off = iob->len = 0; - /* Forward the EOF from reader to writer. */ - if (iob->rfd == -1) { - safe_close(iob->wfd); - iob->wfd = -1; - } - } - /* Don't read/write /dev/tty if we are not in the foreground. */ - if (iob->rfd != -1 && - (ttymode == TERM_RAW || iob->rfd != io_fds[SFD_USERTTY])) { - if (iob->len != sizeof(iob->buf)) - FD_SET(iob->rfd, fdsr); - } - if (iob->wfd != -1 && - (foreground || iob->wfd != io_fds[SFD_USERTTY])) { - if (iob->len > iob->off) - FD_SET(iob->wfd, fdsw); - } - } -} - -/* - * Deliver a relayed signal to the command. - */ -static void -deliver_signal(pid, signo) - pid_t pid; - int signo; -{ - int status; - - /* Handle signal from parent. */ - switch (signo) { - case 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. */ - do { - status = tcsetpgrp(io_fds[SFD_SLAVE], pid); - } while (status == -1 && errno == EINTR); - killpg(pid, SIGCONT); - break; - case SIGUSR2: - /* background process, I take controlling tty. */ - do { - status = tcsetpgrp(io_fds[SFD_SLAVE], getpid()); - } while (status == -1 && errno == EINTR); - killpg(pid, SIGCONT); - break; - default: - warningx("unexpected signal from child: %d", signo); - break; - } -} - -/* - * Send status to parent over socketpair. - * Return value is the same as send(2). - */ -static int -send_status(fd, cstat) - int fd; - struct command_status *cstat; -{ - int n = -1; - - if (cstat->type != CMD_INVALID) { - do { - n = send(fd, cstat, sizeof(*cstat), 0); - } while (n == -1 && errno == EINTR); - cstat->type = CMD_INVALID; /* prevent re-sending */ - } - return n; -} - -/* - * Wait for child status after receiving SIGCHLD. - * If the child was stopped, the status is send back to the parent. - * Otherwise, cstat is filled in but not sent. - * Returns TRUE if child is still alive, else FALSE. - */ -static int -handle_sigchld(backchannel, cstat) - int backchannel; - struct command_status *cstat; -{ - int status, alive = TRUE; - pid_t pid; - - /* read child status */ - do { -#ifdef sudo_waitpid - pid = sudo_waitpid(child, &status, WUNTRACED|WNOHANG); -#else - pid = wait(&status); -#endif - } while (pid == -1 && errno == EINTR); - if (pid == child) { - if (cstat->type != CMD_ERRNO) { - cstat->type = CMD_WSTATUS; - cstat->val = status; - if (WIFSTOPPED(status)) { - if (send_status(backchannel, cstat) == -1) - return alive; /* XXX */ - } - } - if (!WIFSTOPPED(status)) - alive = FALSE; - } - return alive; -} - -/* - * Monitor process that creates a new session with the controlling tty, - * resets signal handlers and forks a child to call exec_pty(). - * Waits for status changes from the command and relays them to the - * parent and relays signals from the parent to the command. - * Returns an error if fork(2) fails, else calls _exit(2). - */ -static int -exec_monitor(path, argv, envp, backchannel, rbac) - const char *path; - char *argv[]; - char *envp[]; - int backchannel; - int rbac; -{ - struct command_status cstat; - struct timeval tv; - fd_set *fdsr; - sigaction_t sa; - int errpipe[2], maxfd, n, status; - int alive = TRUE; - - /* Close unused fds. */ - if (io_fds[SFD_MASTER] != -1) - close(io_fds[SFD_MASTER]); - if (io_fds[SFD_USERTTY] != -1) - close(io_fds[SFD_USERTTY]); - - /* Reset SIGWINCH and SIGALRM. */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = SIG_DFL; - sigaction(SIGWINCH, &sa, NULL); - sigaction(SIGALRM, &sa, NULL); - - /* Ignore any SIGTTIN or SIGTTOU we get. */ - sa.sa_handler = SIG_IGN; - sigaction(SIGTTIN, &sa, NULL); - sigaction(SIGTTOU, &sa, NULL); - - /* Note: HP-UX select() will not be interrupted if SA_RESTART set */ - sa.sa_flags = SA_INTERRUPT; - sa.sa_handler = handler; - sigaction(SIGCHLD, &sa, NULL); - - /* - * Start a new session with the parent as the session leader - * and the slave pty as the controlling terminal. - * This allows us to be notified when the child has been suspended. - */ - if (setsid() == -1) { - warning("setsid"); - goto bad; - } - if (io_fds[SFD_SLAVE] != -1) { -#ifdef TIOCSCTTY - if (ioctl(io_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0) - error(1, "unable to set controlling tty"); -#else - /* Set controlling tty by reopening slave. */ - if ((n = open(slavename, O_RDWR)) >= 0) - close(n); -#endif - } - - /* - * If stdin/stdout is not a tty, start command in the background - * since it might be part of a pipeline that reads from /dev/tty. - * In this case, we rely on the command receiving SIGTTOU or SIGTTIN - * when it needs access to the controlling tty. - */ - if (pipeline) - foreground = 0; - - /* Start command and wait for it to stop or exit */ - if (pipe(errpipe) == -1) - error(1, "unable to create pipe"); - child = fork(); - if (child == -1) { - warning("Can't fork"); - goto bad; - } - if (child == 0) { - /* We pass errno back to our parent via pipe on exec failure. */ - close(backchannel); - close(errpipe[0]); - fcntl(errpipe[1], F_SETFD, FD_CLOEXEC); - - /* setup tty and exec command */ - exec_pty(path, argv, envp, rbac); - cstat.type = CMD_ERRNO; - cstat.val = errno; - write(errpipe[1], &cstat, sizeof(cstat)); - _exit(1); - } - close(errpipe[1]); - - /* If any of stdin/stdout/stderr are pipes, close them in parent. */ - if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDIN]); - if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDOUT]); - if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDERR]); - - /* - * Put child in its own process group. If we are starting the command - * in the foreground, assign its pgrp to the tty. - */ - setpgid(child, child); - if (foreground) { - do { - status = tcsetpgrp(io_fds[SFD_SLAVE], child); - } while (status == -1 && errno == EINTR); - } - - /* Wait for errno on pipe, signal on backchannel or for SIGCHLD */ - maxfd = MAX(errpipe[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); - if (errpipe[0] != -1) - FD_SET(errpipe[0], fdsr); - maxfd = MAX(errpipe[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) { - if (n == 0) - goto done; - if (errno == EINTR) - continue; - error(1, "select failed"); - } - - if (errpipe[0] != -1 && FD_ISSET(errpipe[0], fdsr)) { - /* read errno or EOF from command pipe */ - n = read(errpipe[0], &cstat, sizeof(cstat)); - if (n == -1) { - if (errno == EINTR) - continue; - warning("error reading from pipe"); - goto done; - } - /* Got errno or EOF, either way we are done with errpipe. */ - FD_CLR(errpipe[0], fdsr); - close(errpipe[0]); - errpipe[0] = -1; - } - if (FD_ISSET(backchannel, fdsr)) { - struct command_status cstmp; - - /* read command from backchannel, should be a signal */ - n = recv(backchannel, &cstmp, sizeof(cstmp), 0); - if (n == -1) { - if (errno == EINTR) - continue; - warning("error reading from socketpair"); - goto done; - } - if (cstmp.type != CMD_SIGNO) { - warningx("unexpected reply type on backchannel: %d", cstmp.type); - continue; - } - deliver_signal(child, cstmp.val); - } - } - -done: - if (alive) { - /* XXX An error occurred, should send an error back. */ - kill(child, SIGKILL); - } else { - /* Send parent status. */ - send_status(backchannel, &cstat); - } - _exit(1); - -bad: - return errno; -} - -/* - * Flush any output buffered in iobufs or readable from the fds. - * Does not read from /dev/tty. - */ -static void -flush_output() -{ - struct io_buffer *iob; - struct timeval tv; - fd_set *fdsr, *fdsw; - int nready, nwriters, maxfd = -1; - - /* Determine maxfd */ - for (iob = iobufs; iob; iob = iob->next) { - if (iob->rfd > maxfd) - maxfd = iob->rfd; - if (iob->wfd > maxfd) - maxfd = iob->wfd; - } - if (maxfd == -1) - return; - - fdsr = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); - fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); - for (;;) { - zero_bytes(fdsw, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask)); - zero_bytes(fdsr, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask)); - - nwriters = 0; - for (iob = iobufs; iob; iob = iob->next) { - /* Don't read from /dev/tty while flushing. */ - if (io_fds[SFD_USERTTY] != -1 && iob->rfd == io_fds[SFD_USERTTY]) - continue; - if (iob->rfd == -1 && iob->wfd == -1) - continue; - if (iob->off == iob->len) { - iob->off = iob->len = 0; - /* Forward the EOF from reader to writer. */ - if (iob->rfd == -1) { - safe_close(iob->wfd); - iob->wfd = -1; - } - } - if (iob->rfd != -1) { - if (iob->len != sizeof(iob->buf)) - FD_SET(iob->rfd, fdsr); - } - if (iob->wfd != -1) { - if (iob->len > iob->off) { - nwriters++; - FD_SET(iob->wfd, fdsw); - } - } - } - - /* Don't sleep in select if there are no buffers that need writing. */ - tv.tv_sec = 0; - tv.tv_usec = 0; - nready = select(maxfd + 1, fdsr, fdsw, NULL, nwriters ? NULL : &tv); - if (nready <= 0) { - if (nready == 0) - break; /* all I/O flushed */ - if (errno == EINTR) - continue; - error(1, "select failed"); - } - if (perform_io(fdsr, fdsw, NULL) != 0) - break; - } - efree(fdsr); - efree(fdsw); -} - -/* - * Sets up std{in,out,err} and executes the actual command. - * Returns only if execve() fails. - */ -static void -exec_pty(path, argv, envp, rbac_enabled) - const char *path; - char *argv[]; - char *envp[]; - int rbac_enabled; -{ - 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); - - /* Wire up standard fds, note that stdout/stderr may be pipes. */ - if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 || - dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 || - dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1) - error(1, "dup2"); - - /* Wait for parent to grant us the tty if we are foreground. */ - if (foreground) { - while (tcgetpgrp(io_fds[SFD_SLAVE]) != self) - ; /* spin */ - } - - /* We have guaranteed that the slave fd is > 2 */ - if (io_fds[SFD_SLAVE] != -1) - close(io_fds[SFD_SLAVE]); - if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDIN]); - if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDOUT]); - if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE]) - close(io_fds[SFD_STDERR]); - - closefrom(def_closefrom); -#ifdef HAVE_SELINUX - if (rbac_enabled) - selinux_execve(path, argv, envp); - else -#endif - my_execve(path, argv, envp); -} - -/* - * Propagates tty size change signals to pty being used by the command. - */ -static void -sync_ttysize(src, dst) - int src; - int dst; -{ -#ifdef TIOCGSIZE - struct ttysize tsize; - pid_t pgrp; - - if (ioctl(src, TIOCGSIZE, &tsize) == 0) { - ioctl(dst, TIOCSSIZE, &tsize); - if ((pgrp = tcgetpgrp(dst)) != -1) - killpg(pgrp, SIGWINCH); - } -#endif -} - -/* - * Handler for SIGWINCH in parent. - */ -static void -sigwinch(s) - int s; -{ - int serrno = errno; - - sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]); - errno = serrno; -} - -/* - * Only close the fd if it is not /dev/tty or std{in,out,err}. - * Return value is the same as send(2). - */ -static int -safe_close(fd) - int fd; -{ - /* Avoid closing /dev/tty or std{in,out,err}. */ - if (fd < 3 || fd == io_fds[SFD_USERTTY]) { - errno = EINVAL; - return -1; - } - return close(fd); -} diff --git a/fileops.c b/fileops.c deleted file mode 100644 index ca4903f..0000000 --- a/fileops.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2007, 2009, 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. - */ - -#include - -#include -#include -#include -#ifdef HAVE_FLOCK -# include -#endif /* HAVE_FLOCK */ -#include -#ifdef HAVE_STRING_H -# include -#endif /* HAVE_STRING_H */ -#ifdef HAVE_STRINGS_H -# include -#endif /* HAVE_STRINGS_H */ -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#if TIME_WITH_SYS_TIME -# include -#endif -#ifndef HAVE_TIMESPEC -# include -#endif - -#include "sudo.h" - -#ifndef LINE_MAX -# define LINE_MAX 2048 -#endif - -/* - * Update the access and modify times on an fd or file. - */ -int -touch(fd, path, tvp) - int fd; - char *path; - struct timeval *tvp; -{ - struct timeval times[2]; - - if (tvp != NULL) { - times[0].tv_sec = times[1].tv_sec = tvp->tv_sec; - times[0].tv_usec = times[1].tv_usec = tvp->tv_usec; - } - -#if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES) - if (fd != -1) - return(futimes(fd, tvp ? times : NULL)); - else -#endif - if (path != NULL) - return(utimes(path, tvp ? times : NULL)); - else - return(-1); -} - -/* - * Lock/unlock a file. - */ -#ifdef HAVE_LOCKF -int -lock_file(fd, lockit) - int fd; - int lockit; -{ - int op = 0; - - switch (lockit) { - case SUDO_LOCK: - op = F_LOCK; - break; - case SUDO_TLOCK: - op = F_TLOCK; - break; - case SUDO_UNLOCK: - op = F_ULOCK; - break; - } - return(lockf(fd, op, 0) == 0); -} -#elif HAVE_FLOCK -int -lock_file(fd, lockit) - int fd; - int lockit; -{ - int op = 0; - - switch (lockit) { - case SUDO_LOCK: - op = LOCK_EX; - break; - case SUDO_TLOCK: - op = LOCK_EX | LOCK_NB; - break; - case SUDO_UNLOCK: - op = LOCK_UN; - break; - } - return(flock(fd, op) == 0); -} -#else -int -lock_file(fd, lockit) - int fd; - int lockit; -{ -#ifdef F_SETLK - int func; - struct flock lock; - - lock.l_start = 0; - lock.l_len = 0; - lock.l_pid = getpid(); - lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK; - lock.l_whence = SEEK_SET; - func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK; - - return(fcntl(fd, func, &lock) == 0); -#else - return(TRUE); -#endif -} -#endif - -/* - * Read a line of input, remove comments and strip off leading - * and trailing spaces. Returns static storage that is reused. - */ -char * -sudo_parseln(fp) - FILE *fp; -{ - size_t len; - char *cp = NULL; - static char buf[LINE_MAX]; - - if (fgets(buf, sizeof(buf), fp) != NULL) { - /* Remove comments */ - if ((cp = strchr(buf, '#')) != NULL) - *cp = '\0'; - - /* Trim leading and trailing whitespace/newline */ - len = strlen(buf); - while (len > 0 && isspace((unsigned char)buf[len - 1])) - buf[--len] = '\0'; - for (cp = buf; isblank(*cp); cp++) - continue; - } - return(cp); -} diff --git a/find_path.c b/find_path.c deleted file mode 100644 index 78c96ea..0000000 --- a/find_path.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 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. - */ - -#include - -#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 */ - -#include "sudo.h" - -/* - * This function finds the full pathname for a command and - * stores it in a statically allocated array, filling in a pointer - * to the array. Returns FOUND if the command was found, NOT_FOUND - * if it was not found, or NOT_FOUND_DOT if it would have been found - * but it is in '.' and IGNORE_DOT is set. - */ -int -find_path(infile, outfile, sbp, path, ignore_dot) - char *infile; /* file to find */ - char **outfile; /* result parameter */ - struct stat *sbp; /* stat result parameter */ - char *path; /* path to search */ - int ignore_dot; /* don't check cwd */ -{ - static char command[PATH_MAX]; /* qualified filename */ - char *n; /* for traversing path */ - char *origpath; /* so we can free path later */ - char *result = NULL; /* result of path/file lookup */ - int checkdot = 0; /* check current dir? */ - int len; /* length parameter */ - - if (strlen(infile) >= PATH_MAX) - errorx(1, "%s: File name too long", infile); - - /* - * If we were given a fully qualified or relative path - * there is no need to look at $PATH. - */ - if (strchr(infile, '/')) { - strlcpy(command, infile, sizeof(command)); /* paranoia */ - if (sudo_goodpath(command, sbp)) { - *outfile = command; - return(FOUND); - } else - return(NOT_FOUND); - } - - if (path == NULL) - return(NOT_FOUND); - path = estrdup(path); - origpath = path; - - do { - if ((n = strchr(path, ':'))) - *n = '\0'; - - /* - * Search current dir last if it is in PATH This will miss sneaky - * things like using './' or './/' - */ - if (*path == '\0' || (*path == '.' && *(path + 1) == '\0')) { - checkdot = 1; - path = n + 1; - continue; - } - - /* - * Resolve the path and exit the loop if found. - */ - len = snprintf(command, sizeof(command), "%s/%s", path, infile); - if (len <= 0 || len >= sizeof(command)) - errorx(1, "%s: File name too long", infile); - if ((result = sudo_goodpath(command, sbp))) - break; - - path = n + 1; - - } while (n); - efree(origpath); - - /* - * Check current dir if dot was in the PATH - */ - if (!result && checkdot) { - len = snprintf(command, sizeof(command), "./%s", infile); - if (len <= 0 || len >= sizeof(command)) - errorx(1, "%s: File name too long", infile); - result = sudo_goodpath(command, sbp); - if (result && ignore_dot) - return(NOT_FOUND_DOT); - } - - if (result) { - *outfile = result; - return(FOUND); - } else - return(NOT_FOUND); -} diff --git a/fnmatch.c b/fnmatch.c deleted file mode 100644 index 2255e52..0000000 --- a/fnmatch.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2008, 2010 Todd C. Miller - * Copyright (c) 1989, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. - * Compares a filename or pathname to a pattern. - */ - -#include - -#include -#include -#ifdef HAVE_STRING_H -# include -#endif /* HAVE_STRING_H */ -#ifdef HAVE_STRINGS_H -# include -#endif /* HAVE_STRINGS_H */ - -#include -#include "emul/fnmatch.h" -#include "emul/charclass.h" - -#undef EOS -#define EOS '\0' - -#define RANGE_MATCH 1 -#define RANGE_NOMATCH 0 -#define RANGE_ERROR (-1) - -#if defined(LIBC_SCCS) && !defined(lint) -__unused static const char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $"; -#endif /* LIBC_SCCS and not lint */ - -static int rangematch __P((const char *, int, int, char **)); -static int classmatch __P((const char *, int, int, const char **)); - -int -fnmatch(pattern, string, flags) - const char *pattern, *string; - int flags; -{ - const char *stringstart; - char *newp; - char c, test; - - for (stringstart = string;;) - switch (c = *pattern++) { - case EOS: - if (ISSET(flags, FNM_LEADING_DIR) && *string == '/') - return (0); - return (*string == EOS ? 0 : FNM_NOMATCH); - case '?': - if (*string == EOS) - return (FNM_NOMATCH); - if (*string == '/' && ISSET(flags, FNM_PATHNAME)) - return (FNM_NOMATCH); - if (*string == '.' && ISSET(flags, FNM_PERIOD) && - (string == stringstart || - (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/'))) - return (FNM_NOMATCH); - ++string; - break; - case '*': - c = *pattern; - /* Collapse multiple stars. */ - while (c == '*') - c = *++pattern; - - if (*string == '.' && ISSET(flags, FNM_PERIOD) && - (string == stringstart || - (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/'))) - return (FNM_NOMATCH); - - /* Optimize for pattern with * at end or before /. */ - if (c == EOS) { - if (ISSET(flags, FNM_PATHNAME)) - return (ISSET(flags, FNM_LEADING_DIR) || - strchr(string, '/') == NULL ? - 0 : FNM_NOMATCH); - else - return (0); - } else if (c == '/' && ISSET(flags, FNM_PATHNAME)) { - if ((string = strchr(string, '/')) == NULL) - return (FNM_NOMATCH); - break; - } - - /* General case, use recursion. */ - while ((test = *string) != EOS) { - if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) - return (0); - if (test == '/' && ISSET(flags, FNM_PATHNAME)) - break; - ++string; - } - return (FNM_NOMATCH); - case '[': - if (*string == EOS) - return (FNM_NOMATCH); - if (*string == '/' && ISSET(flags, FNM_PATHNAME)) - return (FNM_NOMATCH); - if (*string == '.' && ISSET(flags, FNM_PERIOD) && - (string == stringstart || - (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/'))) - return (FNM_NOMATCH); - - switch (rangematch(pattern, *string, flags, &newp)) { - case RANGE_ERROR: - /* not a good range, treat as normal text */ - goto normal; - case RANGE_MATCH: - pattern = newp; - break; - case RANGE_NOMATCH: - return (FNM_NOMATCH); - } - ++string; - break; - case '\\': - if (!ISSET(flags, FNM_NOESCAPE)) { - if ((c = *pattern++) == EOS) { - c = '\\'; - --pattern; - } - } - /* FALLTHROUGH */ - default: - normal: - if (c != *string && !(ISSET(flags, FNM_CASEFOLD) && - (tolower((unsigned char)c) == - tolower((unsigned char)*string)))) - return (FNM_NOMATCH); - ++string; - break; - } - /* NOTREACHED */ -} - -static int -#ifdef __STDC__ -rangematch(const char *pattern, int test, int flags, char **newp) -#else -rangematch(pattern, test, flags, newp) - const char *pattern; - int test; - int flags; - char **newp; -#endif -{ - int negate, ok, rv; - char c, c2; - - /* - * A bracket expression starting with an unquoted circumflex - * character produces unspecified results (IEEE 1003.2-1992, - * 3.13.2). This implementation treats it like '!', for - * consistency with the regular expression syntax. - * J.T. Conklin (conklin@ngai.kaleida.com) - */ - if ((negate = (*pattern == '!' || *pattern == '^'))) - ++pattern; - - if (ISSET(flags, FNM_CASEFOLD)) - test = tolower(test); - - /* - * A right bracket shall lose its special meaning and represent - * itself in a bracket expression if it occurs first in the list. - * -- POSIX.2 2.8.3.2 - */ - ok = 0; - c = *pattern++; - do { - if (c == '[' && *pattern == ':') { - do { - rv = classmatch(pattern + 1, test, - (flags & FNM_CASEFOLD), &pattern); - if (rv == RANGE_MATCH) - ok = 1; - c = *pattern++; - } while (rv != RANGE_ERROR && c == '[' && *pattern == ':'); - if (c == ']') - break; - } - if (c == '\\' && !ISSET(flags, FNM_NOESCAPE)) - c = *pattern++; - if (c == EOS) - return (RANGE_ERROR); - if (c == '/' && ISSET(flags, FNM_PATHNAME)) - return (RANGE_NOMATCH); - if (ISSET(flags, FNM_CASEFOLD)) - c = tolower((unsigned char)c); - if (*pattern == '-' - && (c2 = *(pattern+1)) != EOS && c2 != ']') { - pattern += 2; - if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE)) - c2 = *pattern++; - if (c2 == EOS) - return (RANGE_ERROR); - if (ISSET(flags, FNM_CASEFOLD)) - c2 = tolower((unsigned char)c2); - if (c <= test && test <= c2) - ok = 1; - } else if (c == test) - ok = 1; - } while ((c = *pattern++) != ']'); - - *newp = (char *)pattern; - return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); -} - -static int -#ifdef __STDC__ -classmatch(const char *pattern, int test, int foldcase, const char **ep) -#else -classmatch(pattern, test, foldcase, ep) - const char *pattern; - int test; - int foldcase; - const char **ep; -#endif -{ - struct cclass *cc; - const char *colon; - size_t len; - int rval = RANGE_NOMATCH; - - if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') { - *ep = pattern - 2; - return(RANGE_ERROR); - } - *ep = colon + 2; - len = (size_t)(colon - pattern); - - if (foldcase && strncmp(pattern, "upper:]", 7) == 0) - pattern = "lower:]"; - for (cc = cclasses; cc->name != NULL; cc++) { - if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') { - if (cc->isctype(test)) - rval = RANGE_MATCH; - break; - } - } - if (cc->name == NULL) { - /* invalid character class, return EOS */ - *ep = colon + strlen(colon); - rval = RANGE_ERROR; - } - return(rval); -} diff --git a/get_pty.c b/get_pty.c deleted file mode 100644 index 7b35108..0000000 --- a/get_pty.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#include -#include -#ifdef HAVE_SYS_STROPTS_H -#include -#endif /* HAVE_SYS_STROPTS_H */ -#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 */ -#include -#include -#include -#include - -#ifdef HAVE_UTIL_H -# include -#endif -#ifdef HAVE_PTY_H -# include -#endif - -#include "sudo.h" - -#if defined(HAVE_OPENPTY) -int -get_pty(master, slave, name, namesz, ttyuid) - int *master; - int *slave; - char *name; - size_t namesz; - uid_t ttyuid; -{ - struct group *gr; - gid_t ttygid = -1; - - if ((gr = sudo_getgrnam("tty")) != NULL) - ttygid = gr->gr_gid; - - if (openpty(master, slave, name, NULL, NULL) != 0) - return(0); - (void) chown(name, ttyuid, ttygid); - return(1); -} - -#elif defined(HAVE__GETPTY) -int -get_pty(master, slave, name, namesz, ttyuid) - int *master; - int *slave; - char *name; - size_t namesz; - uid_t ttyuid; -{ - char *line; - - /* IRIX-style dynamic ptys (may fork) */ - line = _getpty(master, O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP, 0); - if (line == NULL) - return (0); - *slave = open(line, O_RDWR|O_NOCTTY, 0); - if (*slave == -1) { - close(*master); - return(0); - } - (void) chown(line, ttyuid, -1); - strlcpy(name, line, namesz); - return(1); -} -#elif defined(HAVE_GRANTPT) -# ifndef HAVE_POSIX_OPENPT -static int -posix_openpt(oflag) - int oflag; -{ - int fd; - -# ifdef _AIX - fd = open("/dev/ptc", oflag); -# else - fd = open("/dev/ptmx", oflag); -# endif - return(fd); -} -# endif /* HAVE_POSIX_OPENPT */ - -int -get_pty(master, slave, name, namesz, ttyuid) - int *master; - int *slave; - char *name; - size_t namesz; - uid_t ttyuid; -{ - char *line; - - *master = posix_openpt(O_RDWR|O_NOCTTY); - if (*master == -1) - return(0); - - (void) grantpt(*master); /* may fork */ - if (unlockpt(*master) != 0) { - close(*master); - return(0); - } - line = ptsname(*master); - if (line == NULL) { - close(*master); - return(0); - } - *slave = open(line, O_RDWR|O_NOCTTY, 0); - if (*slave == -1) { - close(*master); - return(0); - } -# if defined(I_PUSH) && !defined(_AIX) - ioctl(*slave, I_PUSH, "ptem"); /* pseudo tty emulation module */ - ioctl(*slave, I_PUSH, "ldterm"); /* line discipline module */ -# endif - (void) chown(line, ttyuid, -1); - strlcpy(name, line, namesz); - return(1); -} - -#else /* Old-style BSD ptys */ - -static char line[] = "/dev/ptyXX"; - -int -get_pty(master, slave, name, namesz, ttyuid) - int *master; - int *slave; - char *name; - size_t namesz; - uid_t ttyuid; -{ - char *bank, *cp; - struct group *gr; - gid_t ttygid = -1; - - if ((gr = sudo_getgrnam("tty")) != NULL) - ttygid = gr->gr_gid; - - for (bank = "pqrs"; *bank != '\0'; bank++) { - line[sizeof("/dev/ptyX") - 2] = *bank; - for (cp = "0123456789abcdef"; *cp != '\0'; cp++) { - line[sizeof("/dev/ptyXX") - 2] = *cp; - *master = open(line, O_RDWR|O_NOCTTY, 0); - if (*master == -1) { - if (errno == ENOENT) - return(0); /* out of ptys */ - continue; /* already in use */ - } - line[sizeof("/dev/p") - 2] = 't'; - (void) chown(line, ttyuid, ttygid); - (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); -# ifdef HAVE_REVOKE - (void) revoke(line); -# endif - *slave = open(line, O_RDWR|O_NOCTTY, 0); - if (*slave != -1) { - strlcpy(name, line, namesz); - return(1); /* success */ - } - (void) close(*master); - } - } - return(0); -} -#endif /* HAVE_OPENPTY */ diff --git a/getcwd.c b/getcwd.c deleted file mode 100644 index 109794a..0000000 --- a/getcwd.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) 1989, 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -#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 */ -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif - -#include - -#define ISDOT(dp) \ - (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ - (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) - -char * -getcwd(pt, size) - char *pt; - size_t size; -{ - struct dirent *dp; - DIR *dir = NULL; - dev_t dev; - ino_t ino; - int first; - char *bpt, *bup; - struct stat s; - dev_t root_dev; - ino_t root_ino; - size_t ptsize, upsize; - int save_errno; - char *ept, *eup, *up; - - /* - * If no buffer specified by the user, allocate one as necessary. - * If a buffer is specified, the size has to be non-zero. The path - * is built from the end of the buffer backwards. - */ - if (pt) { - ptsize = 0; - if (!size) { - errno = EINVAL; - return (NULL); - } - ept = pt + size; - } else { - if ((pt = malloc(ptsize = 1024 - 4)) == NULL) - return (NULL); - ept = pt + ptsize; - } - bpt = ept - 1; - *bpt = '\0'; - - /* - * Allocate bytes (1024 - malloc space) for the string of "../"'s. - * Should always be enough (it's 340 levels). If it's not, allocate - * as necessary. Special * case the first stat, it's ".", not "..". - */ - if ((up = malloc(upsize = 1024 - 4)) == NULL) - goto err; - eup = up + PATH_MAX; - bup = up; - up[0] = '.'; - up[1] = '\0'; - - /* Save root values, so know when to stop. */ - if (stat("/", &s)) - goto err; - root_dev = s.st_dev; - root_ino = s.st_ino; - - errno = 0; /* XXX readdir has no error return. */ - - for (first = 1;; first = 0) { - /* Stat the current level. */ - if (lstat(up, &s)) - goto err; - - /* Save current node values. */ - ino = s.st_ino; - dev = s.st_dev; - - /* Check for reaching root. */ - if (root_dev == dev && root_ino == ino) { - *--bpt = '/'; - /* - * It's unclear that it's a requirement to copy the - * path to the beginning of the buffer, but it's always - * been that way and stuff would probably break. - */ - bcopy(bpt, pt, ept - bpt); - free(up); - return (pt); - } - - /* - * Build pointer to the parent directory, allocating memory - * as necessary. Max length is 3 for "../", the largest - * possible component name, plus a trailing NULL. - */ - if (bup + 3 + MAXNAMLEN + 1 >= eup) { - char *nup; - - if ((nup = realloc(up, upsize *= 2)) == NULL) - goto err; - up = nup; - bup = up; - eup = up + upsize; - } - *bup++ = '.'; - *bup++ = '.'; - *bup = '\0'; - - /* Open and stat parent directory. */ - if (!(dir = opendir(up)) || fstat(dirfd(dir), &s)) - goto err; - - /* Add trailing slash for next directory. */ - *bup++ = '/'; - - /* - * If it's a mount point, have to stat each element because - * the inode number in the directory is for the entry in the - * parent directory, not the inode number of the mounted file. - */ - save_errno = 0; - if (s.st_dev == dev) { - for (;;) { - if (!(dp = readdir(dir))) - goto notfound; - if (dp->d_fileno == ino) - break; - } - } else - for (;;) { - if (!(dp = readdir(dir))) - goto notfound; - if (ISDOT(dp)) - continue; - bcopy(dp->d_name, bup, NAMLEN(dp) + 1); - - /* Save the first error for later. */ - if (lstat(up, &s)) { - if (!save_errno) - save_errno = errno; - errno = 0; - continue; - } - if (s.st_dev == dev && s.st_ino == ino) - break; - } - - /* - * Check for length of the current name, preceding slash, - * leading slash. - */ - if (bpt - pt <= NAMLEN(dp) + (first ? 1 : 2)) { - size_t len, off; - char *npt; - - if (!ptsize) { - errno = ERANGE; - goto err; - } - off = bpt - pt; - len = ept - bpt; - if ((npt = realloc(pt, ptsize *= 2)) == NULL) - goto err; - pt = npt; - bpt = pt + off; - ept = pt + ptsize; - bcopy(bpt, ept - len, len); - bpt = ept - len; - } - if (!first) - *--bpt = '/'; - bpt -= NAMLEN(dp); - bcopy(dp->d_name, bpt, NAMLEN(dp)); - (void)closedir(dir); - - /* Truncate any file name. */ - *bup = '\0'; - } - -notfound: - /* - * If readdir set errno, use it, not any saved error; otherwise, - * didn't find the current directory in its parent directory, set - * errno to ENOENT. - */ - if (!errno) - errno = save_errno ? save_errno : ENOENT; - /* FALLTHROUGH */ -err: - if (ptsize) - free(pt); - if (up) - free(up); - if (dir) - (void)closedir(dir); - return (NULL); -} diff --git a/getdate.c b/getdate.c deleted file mode 100644 index 928246b..0000000 --- a/getdate.c +++ /dev/null @@ -1,1595 +0,0 @@ -#include -#include -#define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define YYLEX yylex() -#define YYEMPTY -1 -#define yyclearin (yychar=(YYEMPTY)) -#define yyerrok (yyerrflag=0) -#define YYRECOVERING() (yyerrflag!=0) -#define YYPREFIX "yy" -#line 2 "getdate.y" -/* -** Originally written by Steven M. Bellovin while -** at the University of North Carolina at Chapel Hill. Later tweaked by -** a couple of people on Usenet. Completely overhauled by Rich $alz -** and Jim Berets in August, 1990; -** -** This grammar has 10 shift/reduce conflicts. -** -** This code is in the public domain and has no copyright. -*/ -/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ -/* SUPPRESS 288 on yyerrlab *//* Label unused */ - -#include - -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#if TIME_WITH_SYS_TIME -# include -#endif -#include - -#include "compat.h" - - -#define EPOCH 1970 -#define HOUR(x) ((time_t)(x) * 60) -#define SECSPERDAY (24L * 60L * 60L) - - -/* -** An entry in the lexical lookup table. -*/ -typedef struct _TABLE { - char *name; - int type; - time_t value; -} TABLE; - - -/* -** Daylight-savings mode: on, off, or not yet known. -*/ -typedef enum _DSTMODE { - DSTon, DSToff, DSTmaybe -} DSTMODE; - -/* -** Meridian: am, pm, or 24-hour style. -*/ -typedef enum _MERIDIAN { - MERam, MERpm, MER24 -} MERIDIAN; - - -/* -** Global variables. We could get rid of most of these by using a good -** union as the yacc stack. (This routine was originally written before -** yacc had the %union construct.) Maybe someday; right now we only use -** the %union very rarely. -*/ -static char *yyInput; -static DSTMODE yyDSTmode; -static time_t yyDayOrdinal; -static time_t yyDayNumber; -static int yyHaveDate; -static int yyHaveDay; -static int yyHaveRel; -static int yyHaveTime; -static int yyHaveZone; -static time_t yyTimezone; -static time_t yyDay; -static time_t yyHour; -static time_t yyMinutes; -static time_t yyMonth; -static time_t yySeconds; -static time_t yyYear; -static MERIDIAN yyMeridian; -static time_t yyRelMonth; -static time_t yyRelSeconds; - -static int yyerror __P((char *s)); -static int yylex __P((void)); -static int yyparse __P((void)); - -#line 107 "getdate.y" -#ifndef YYSTYPE_DEFINED -#define YYSTYPE_DEFINED -typedef union { - time_t Number; - enum _MERIDIAN Meridian; -} YYSTYPE; -#endif /* YYSTYPE_DEFINED */ -#line 125 "y.tab.c" -#define tAGO 257 -#define tDAY 258 -#define tDAYZONE 259 -#define tID 260 -#define tMERIDIAN 261 -#define tMINUTE_UNIT 262 -#define tMONTH 263 -#define tMONTH_UNIT 264 -#define tSEC_UNIT 265 -#define tSNUMBER 266 -#define tUNUMBER 267 -#define tZONE 268 -#define tDST 269 -#define YYERRCODE 256 -#if defined(__cplusplus) || defined(__STDC__) -const short yylhs[] = -#else -short yylhs[] = -#endif - { -1, - 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, - 3, 3, 3, 4, 4, 4, 6, 6, 6, 5, - 5, 5, 5, 5, 5, 5, 5, 7, 7, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 8, 1, - 1, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yylen[] = -#else -short yylen[] = -#endif - { 2, - 0, 2, 1, 1, 1, 1, 1, 1, 2, 4, - 4, 6, 6, 1, 1, 2, 1, 2, 2, 3, - 5, 3, 3, 2, 4, 2, 3, 2, 1, 2, - 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, - 1, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yydefred[] = -#else -short yydefred[] = -#endif - { 1, - 0, 0, 15, 32, 0, 38, 35, 0, 0, 0, - 2, 3, 4, 5, 6, 7, 8, 0, 18, 0, - 31, 36, 33, 19, 9, 30, 0, 37, 34, 0, - 0, 0, 16, 28, 0, 23, 27, 22, 0, 0, - 25, 41, 11, 0, 10, 0, 0, 21, 13, 12, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yydgoto[] = -#else -short yydgoto[] = -#endif - { 1, - 45, 11, 12, 13, 14, 15, 16, 17, 18, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yysindex[] = -#else -short yysindex[] = -#endif - { 0, - -249, -38, 0, 0, -260, 0, 0, -240, -47, -248, - 0, 0, 0, 0, 0, 0, 0, -237, 0, -18, - 0, 0, 0, 0, 0, 0, -262, 0, 0, -239, - -238, -236, 0, 0, -235, 0, 0, 0, -56, -19, - 0, 0, 0, -234, 0, -232, -258, 0, 0, 0,}; -#if defined(__cplusplus) || defined(__STDC__) -const short yyrindex[] = -#else -short yyrindex[] = -#endif - { 0, - 0, 1, 0, 0, 0, 0, 0, 0, 69, 12, - 0, 0, 0, 0, 0, 0, 0, 23, 0, 34, - 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 56, 45, - 0, 0, 0, 0, 0, 0, 56, 0, 0, 0,}; -#if defined(__cplusplus) || defined(__STDC__) -const short yygindex[] = -#else -short yygindex[] = -#endif - { 0, - -17, 0, 0, 0, 0, 0, 0, 0, 0, -}; -#define YYTABLESIZE 337 -#if defined(__cplusplus) || defined(__STDC__) -const short yytable[] = -#else -short yytable[] = -#endif - { 32, - 17, 44, 42, 36, 37, 19, 20, 49, 2, 3, - 31, 14, 4, 5, 6, 7, 8, 9, 10, 34, - 33, 21, 29, 22, 23, 35, 38, 46, 39, 50, - 40, 41, 47, 24, 48, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 26, 0, 39, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 42, 0, 0, 0, 0, 43, - 24, 0, 0, 25, 26, 27, 28, 29, 30, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, - 0, 0, 17, 17, 17, 17, 17, 17, 17, 14, - 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, - 29, 29, 0, 0, 29, 29, 29, 29, 29, 29, - 29, 24, 24, 0, 0, 24, 24, 24, 24, 24, - 24, 24, 20, 20, 0, 0, 20, 20, 20, 20, - 20, 20, 20, 40, 40, 0, 0, 40, 40, 40, - 40, 0, 40, 40, 26, 26, 0, 39, 26, 26, - 26, 26, 0, 0, 26, 39, 39, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yycheck[] = -#else -short yycheck[] = -#endif - { 47, - 0, 58, 261, 266, 267, 44, 267, 266, 258, 259, - 58, 0, 262, 263, 264, 265, 266, 267, 268, 257, - 269, 262, 0, 264, 265, 44, 266, 47, 267, 47, - 267, 267, 267, 0, 267, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 261, -1, -1, -1, -1, 266, - 258, -1, -1, 261, 262, 263, 264, 265, 266, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 258, 259, - -1, -1, 262, 263, 264, 265, 266, 267, 268, 258, - 259, -1, -1, 262, 263, 264, 265, 266, 267, 268, - 258, 259, -1, -1, 262, 263, 264, 265, 266, 267, - 268, 258, 259, -1, -1, 262, 263, 264, 265, 266, - 267, 268, 258, 259, -1, -1, 262, 263, 264, 265, - 266, 267, 268, 258, 259, -1, -1, 262, 263, 264, - 265, -1, 267, 268, 258, 259, -1, 259, 262, 263, - 264, 265, -1, -1, 268, 267, 268, -}; -#define YYFINAL 1 -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif -#define YYMAXTOKEN 269 -#if YYDEBUG -#if defined(__cplusplus) || defined(__STDC__) -const char * const yyname[] = -#else -char *yyname[] = -#endif - { -"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tAGO","tDAY", -"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT", -"tSNUMBER","tUNUMBER","tZONE","tDST", -}; -#if defined(__cplusplus) || defined(__STDC__) -const char * const yyrule[] = -#else -char *yyrule[] = -#endif - {"$accept : spec", -"spec :", -"spec : spec item", -"item : time", -"item : zone", -"item : date", -"item : day", -"item : rel", -"item : number", -"time : tUNUMBER tMERIDIAN", -"time : tUNUMBER ':' tUNUMBER o_merid", -"time : tUNUMBER ':' tUNUMBER tSNUMBER", -"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid", -"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER", -"zone : tZONE", -"zone : tDAYZONE", -"zone : tZONE tDST", -"day : tDAY", -"day : tDAY ','", -"day : tUNUMBER tDAY", -"date : tUNUMBER '/' tUNUMBER", -"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", -"date : tUNUMBER tSNUMBER tSNUMBER", -"date : tUNUMBER tMONTH tSNUMBER", -"date : tMONTH tUNUMBER", -"date : tMONTH tUNUMBER ',' tUNUMBER", -"date : tUNUMBER tMONTH", -"date : tUNUMBER tMONTH tUNUMBER", -"rel : relunit tAGO", -"rel : relunit", -"relunit : tUNUMBER tMINUTE_UNIT", -"relunit : tSNUMBER tMINUTE_UNIT", -"relunit : tMINUTE_UNIT", -"relunit : tSNUMBER tSEC_UNIT", -"relunit : tUNUMBER tSEC_UNIT", -"relunit : tSEC_UNIT", -"relunit : tSNUMBER tMONTH_UNIT", -"relunit : tUNUMBER tMONTH_UNIT", -"relunit : tMONTH_UNIT", -"number : tUNUMBER", -"o_merid :", -"o_merid : tMERIDIAN", -}; -#endif -#ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE -#else -#ifdef YYMAXDEPTH -#define YYSTACKSIZE YYMAXDEPTH -#else -#define YYSTACKSIZE 10000 -#define YYMAXDEPTH 10000 -#endif -#endif -#define YYINITSTACKSIZE 200 -/* LINTUSED */ -int yydebug; -int yynerrs; -int yyerrflag; -int yychar; -short *yyssp; -YYSTYPE *yyvsp; -YYSTYPE yyval; -YYSTYPE yylval; -short *yyss; -short *yysslim; -YYSTYPE *yyvs; -int yystacksize; -#line 326 "getdate.y" - -/* Month and day table. */ -static TABLE const MonthDayTable[] = { - { "january", tMONTH, 1 }, - { "february", tMONTH, 2 }, - { "march", tMONTH, 3 }, - { "april", tMONTH, 4 }, - { "may", tMONTH, 5 }, - { "june", tMONTH, 6 }, - { "july", tMONTH, 7 }, - { "august", tMONTH, 8 }, - { "september", tMONTH, 9 }, - { "sept", tMONTH, 9 }, - { "october", tMONTH, 10 }, - { "november", tMONTH, 11 }, - { "december", tMONTH, 12 }, - { "sunday", tDAY, 0 }, - { "monday", tDAY, 1 }, - { "tuesday", tDAY, 2 }, - { "tues", tDAY, 2 }, - { "wednesday", tDAY, 3 }, - { "wednes", tDAY, 3 }, - { "thursday", tDAY, 4 }, - { "thur", tDAY, 4 }, - { "thurs", tDAY, 4 }, - { "friday", tDAY, 5 }, - { "saturday", tDAY, 6 }, - { NULL } -}; - -/* Time units table. */ -static TABLE const UnitsTable[] = { - { "year", tMONTH_UNIT, 12 }, - { "month", tMONTH_UNIT, 1 }, - { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, - { "week", tMINUTE_UNIT, 7 * 24 * 60 }, - { "day", tMINUTE_UNIT, 1 * 24 * 60 }, - { "hour", tMINUTE_UNIT, 60 }, - { "minute", tMINUTE_UNIT, 1 }, - { "min", tMINUTE_UNIT, 1 }, - { "second", tSEC_UNIT, 1 }, - { "sec", tSEC_UNIT, 1 }, - { NULL } -}; - -/* Assorted relative-time words. */ -static TABLE const OtherTable[] = { - { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, - { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, - { "today", tMINUTE_UNIT, 0 }, - { "now", tMINUTE_UNIT, 0 }, - { "last", tUNUMBER, -1 }, - { "this", tMINUTE_UNIT, 0 }, - { "next", tUNUMBER, 2 }, - { "first", tUNUMBER, 1 }, -/* { "second", tUNUMBER, 2 }, */ - { "third", tUNUMBER, 3 }, - { "fourth", tUNUMBER, 4 }, - { "fifth", tUNUMBER, 5 }, - { "sixth", tUNUMBER, 6 }, - { "seventh", tUNUMBER, 7 }, - { "eighth", tUNUMBER, 8 }, - { "ninth", tUNUMBER, 9 }, - { "tenth", tUNUMBER, 10 }, - { "eleventh", tUNUMBER, 11 }, - { "twelfth", tUNUMBER, 12 }, - { "ago", tAGO, 1 }, - { NULL } -}; - -/* The timezone table. */ -/* Some of these are commented out because a time_t can't store a float. */ -static TABLE const TimezoneTable[] = { - { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ - { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ - { "utc", tZONE, HOUR( 0) }, - { "wet", tZONE, HOUR( 0) }, /* Western European */ - { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ - { "wat", tZONE, HOUR( 1) }, /* West Africa */ - { "at", tZONE, HOUR( 2) }, /* Azores */ -#if 0 - /* For completeness. BST is also British Summer, and GST is - * also Guam Standard. */ - { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ - { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ -#endif -#if 0 - { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ - { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ - { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ -#endif - { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ - { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ - { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ - { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ - { "cst", tZONE, HOUR( 6) }, /* Central Standard */ - { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ - { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ - { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ - { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ - { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ - { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ - { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ - { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ - { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ - { "cat", tZONE, HOUR(10) }, /* Central Alaska */ - { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ - { "nt", tZONE, HOUR(11) }, /* Nome */ - { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ - { "cet", tZONE, -HOUR(1) }, /* Central European */ - { "met", tZONE, -HOUR(1) }, /* Middle European */ - { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ - { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ - { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ - { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ - { "fwt", tZONE, -HOUR(1) }, /* French Winter */ - { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ - { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ - { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ -#if 0 - { "it", tZONE, -HOUR(3.5) },/* Iran */ -#endif - { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ - { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ -#if 0 - { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ -#endif - { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ -#if 0 - /* For completeness. NST is also Newfoundland Stanard, and SST is - * also Swedish Summer. */ - { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ - { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ -#endif /* 0 */ - { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ - { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ -#if 0 - { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ -#endif - { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ - { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ -#if 0 - { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ - { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ -#endif - { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ - { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ - { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ - { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ - { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ - { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ - { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ - { NULL } -}; - -/* Military timezone table. */ -static TABLE const MilitaryTable[] = { - { "a", tZONE, HOUR( 1) }, - { "b", tZONE, HOUR( 2) }, - { "c", tZONE, HOUR( 3) }, - { "d", tZONE, HOUR( 4) }, - { "e", tZONE, HOUR( 5) }, - { "f", tZONE, HOUR( 6) }, - { "g", tZONE, HOUR( 7) }, - { "h", tZONE, HOUR( 8) }, - { "i", tZONE, HOUR( 9) }, - { "k", tZONE, HOUR( 10) }, - { "l", tZONE, HOUR( 11) }, - { "m", tZONE, HOUR( 12) }, - { "n", tZONE, HOUR(- 1) }, - { "o", tZONE, HOUR(- 2) }, - { "p", tZONE, HOUR(- 3) }, - { "q", tZONE, HOUR(- 4) }, - { "r", tZONE, HOUR(- 5) }, - { "s", tZONE, HOUR(- 6) }, - { "t", tZONE, HOUR(- 7) }, - { "u", tZONE, HOUR(- 8) }, - { "v", tZONE, HOUR(- 9) }, - { "w", tZONE, HOUR(-10) }, - { "x", tZONE, HOUR(-11) }, - { "y", tZONE, HOUR(-12) }, - { "z", tZONE, HOUR( 0) }, - { NULL } -}; - - - - -/* ARGSUSED */ -static int -yyerror(s) - char *s; -{ - return 0; -} - - -static time_t -ToSeconds(Hours, Minutes, Seconds, Meridian) - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; -{ - if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) - return -1; - switch (Meridian) { - case MER24: - if (Hours < 0 || Hours > 23) - return -1; - return (Hours * 60L + Minutes) * 60L + Seconds; - case MERam: - if (Hours < 1 || Hours > 12) - return -1; - if (Hours == 12) - Hours = 0; - return (Hours * 60L + Minutes) * 60L + Seconds; - case MERpm: - if (Hours < 1 || Hours > 12) - return -1; - if (Hours == 12) - Hours = 0; - return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; - default: - abort (); - } - /* NOTREACHED */ -} - - -/* Year is either - * A negative number, which means to use its absolute value (why?) - * A number from 0 to 99, which means a year from 1900 to 1999, or - * The actual year (>=100). */ -static time_t -Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE DSTmode; -{ - static int DaysInMonth[12] = { - 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - time_t tod; - time_t Julian; - int i; - - if (Year < 0) - Year = -Year; - if (Year < 69) - Year += 2000; - else if (Year < 100) { - Year += 1900; - if (Year < EPOCH) - Year += 100; - } - DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) - ? 29 : 28; - /* Checking for 2038 bogusly assumes that time_t is 32 bits. But - I'm too lazy to try to check for time_t overflow in another way. */ - if (Year < EPOCH || Year > 2038 - || Month < 1 || Month > 12 - /* Lint fluff: "conversion from long may lose accuracy" */ - || Day < 1 || Day > DaysInMonth[(int)--Month]) - return -1; - - for (Julian = Day - 1, i = 0; i < Month; i++) - Julian += DaysInMonth[i]; - for (i = EPOCH; i < Year; i++) - Julian += 365 + (i % 4 == 0); - Julian *= SECSPERDAY; - Julian += yyTimezone * 60L; - if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) - return -1; - Julian += tod; - if (DSTmode == DSTon - || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) - Julian -= 60 * 60; - return Julian; -} - - -static time_t -DSTcorrect(Start, Future) - time_t Start; - time_t Future; -{ - time_t StartDay; - time_t FutureDay; - - StartDay = (localtime(&Start)->tm_hour + 1) % 24; - FutureDay = (localtime(&Future)->tm_hour + 1) % 24; - return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; -} - - -static time_t -RelativeDate(Start, DayOrdinal, DayNumber) - time_t Start; - time_t DayOrdinal; - time_t DayNumber; -{ - struct tm *tm; - time_t now; - - now = Start; - tm = localtime(&now); - now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); - now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); - return DSTcorrect(Start, now); -} - - -static time_t -RelativeMonth(Start, RelMonth) - time_t Start; - time_t RelMonth; -{ - struct tm *tm; - time_t Month; - time_t Year; - - if (RelMonth == 0) - return 0; - tm = localtime(&Start); - Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; - Year = Month / 12; - Month = Month % 12 + 1; - return DSTcorrect(Start, - Convert(Month, (time_t)tm->tm_mday, Year, - (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, - MER24, DSTmaybe)); -} - - -static int -LookupWord(buff) - char *buff; -{ - char *p; - char *q; - const TABLE *tp; - int i; - int abbrev; - - /* Make it lowercase. */ - for (p = buff; *p; p++) - if (isupper((unsigned char)*p)) - *p = tolower((unsigned char)*p); - - if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { - yylval.Meridian = MERam; - return tMERIDIAN; - } - if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { - yylval.Meridian = MERpm; - return tMERIDIAN; - } - - /* See if we have an abbreviation for a month. */ - if (strlen(buff) == 3) - abbrev = 1; - else if (strlen(buff) == 4 && buff[3] == '.') { - abbrev = 1; - buff[3] = '\0'; - } - else - abbrev = 0; - - for (tp = MonthDayTable; tp->name; tp++) { - if (abbrev) { - if (strncmp(buff, tp->name, 3) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - else if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - - for (tp = TimezoneTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - if (strcmp(buff, "dst") == 0) - return tDST; - - for (tp = UnitsTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - /* Strip off any plural and try the units table again. */ - i = strlen(buff) - 1; - if (buff[i] == 's') { - buff[i] = '\0'; - for (tp = UnitsTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - buff[i] = 's'; /* Put back for "this" in OtherTable. */ - } - - for (tp = OtherTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - /* Military timezones. */ - if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { - for (tp = MilitaryTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - - /* Drop out any periods and try the timezone table again. */ - for (i = 0, p = q = buff; *q; q++) - if (*q != '.') - *p++ = *q; - else - i++; - *p = '\0'; - if (i) - for (tp = TimezoneTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - return tID; -} - - -static int -yylex() -{ - char c; - char *p; - char buff[20]; - int Count; - int sign; - - for ( ; ; ) { - while (isspace((unsigned char)*yyInput)) - yyInput++; - - if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') { - if (c == '-' || c == '+') { - sign = c == '-' ? -1 : 1; - if (!isdigit((unsigned char)*++yyInput)) - /* skip the '-' sign */ - continue; - } - else - sign = 0; - for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); ) - yylval.Number = 10 * yylval.Number + c - '0'; - yyInput--; - if (sign < 0) - yylval.Number = -yylval.Number; - return sign ? tSNUMBER : tUNUMBER; - } - if (isalpha((unsigned char)c)) { - for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; ) - if (p < &buff[sizeof buff - 1]) - *p++ = c; - *p = '\0'; - yyInput--; - return LookupWord(buff); - } - if (c != '(') - return *yyInput++; - Count = 0; - do { - c = *yyInput++; - if (c == '\0') - return c; - if (c == '(') - Count++; - else if (c == ')') - Count--; - } while (Count > 0); - } -} - -#define TM_YEAR_ORIGIN 1900 - -/* Yield A - B, measured in seconds. */ -static long -difftm (a, b) - struct tm *a, *b; -{ - int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); - int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int days = ( - /* difference in day of year */ - a->tm_yday - b->tm_yday - /* + intervening leap days */ - + ((ay >> 2) - (by >> 2)) - - (ay/100 - by/100) - + ((ay/100 >> 2) - (by/100 >> 2)) - /* + difference in years * 365 */ - + (long)(ay-by) * 365 - ); - return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) - + (a->tm_min - b->tm_min)) - + (a->tm_sec - b->tm_sec)); -} - -time_t -get_date(p) - char *p; -{ - struct tm *tm, *gmt, gmtbuf; - time_t Start; - time_t tod; - time_t now; - time_t timezone; - - yyInput = p; - (void)time (&now); - - gmt = gmtime (&now); - if (gmt != NULL) - { - /* Make a copy, in case localtime modifies *tm (I think - that comment now applies to *gmt, but I am too - lazy to dig into how gmtime and locatime allocate the - structures they return pointers to). */ - gmtbuf = *gmt; - gmt = &gmtbuf; - } - - if (! (tm = localtime (&now))) - return -1; - - if (gmt != NULL) - timezone = difftm (gmt, tm) / 60; - else - /* We are on a system like VMS, where the system clock is - in local time and the system has no concept of timezones. - Hopefully we can fake this out (for the case in which the - user specifies no timezone) by just saying the timezone - is zero. */ - timezone = 0; - - if(tm->tm_isdst) - timezone += 60; - - tm = localtime(&now); - yyYear = tm->tm_year + 1900; - yyMonth = tm->tm_mon + 1; - yyDay = tm->tm_mday; - yyTimezone = timezone; - yyDSTmode = DSTmaybe; - yyHour = 0; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = MER24; - yyRelSeconds = 0; - yyRelMonth = 0; - yyHaveDate = 0; - yyHaveDay = 0; - yyHaveRel = 0; - yyHaveTime = 0; - yyHaveZone = 0; - - if (yyparse() - || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) - return -1; - - if (yyHaveDate || yyHaveTime || yyHaveDay) { - Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, - yyMeridian, yyDSTmode); - if (Start < 0) - return -1; - } - else { - Start = now; - if (!yyHaveRel) - Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; - } - - Start += yyRelSeconds; - Start += RelativeMonth(Start, yyRelMonth); - - if (yyHaveDay && !yyHaveDate) { - tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); - Start += tod; - } - - /* Have to do *something* with a legitimate -1 so it's distinguishable - * from the error return value. (Alternately could set errno on error.) */ - return Start == -1 ? 0 : Start; -} - - -#if defined(TEST) - -/* ARGSUSED */ -int -main(ac, av) - int ac; - char *av[]; -{ - char buff[128]; - time_t d; - - (void)printf("Enter date, or blank line to exit.\n\t> "); - (void)fflush(stdout); - while (gets(buff) && buff[0]) { - d = get_date(buff); - if (d == -1) - (void)printf("Bad format - couldn't convert.\n"); - else - (void)printf("%s", ctime(&d)); - (void)printf("\t> "); - (void)fflush(stdout); - } - exit(0); - /* NOTREACHED */ -} -#endif /* defined(TEST) */ -#line 979 "y.tab.c" -/* allocate initial stack or double stack size, up to YYMAXDEPTH */ -#if defined(__cplusplus) || defined(__STDC__) -static int yygrowstack(void) -#else -static int yygrowstack() -#endif -{ - int newsize, i; - short *newss; - YYSTYPE *newvs; - - if ((newsize = yystacksize) == 0) - newsize = YYINITSTACKSIZE; - else if (newsize >= YYMAXDEPTH) - return -1; - else if ((newsize *= 2) > YYMAXDEPTH) - newsize = YYMAXDEPTH; - i = yyssp - yyss; -#ifdef SIZE_MAX -#define YY_SIZE_MAX SIZE_MAX -#else -#define YY_SIZE_MAX 0x7fffffff -#endif - if (newsize && YY_SIZE_MAX / newsize < sizeof *newss) - goto bail; - newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : - (short *)malloc(newsize * sizeof *newss); /* overflow check above */ - if (newss == NULL) - goto bail; - yyss = newss; - yyssp = newss + i; - if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs) - goto bail; - newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : - (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */ - if (newvs == NULL) - goto bail; - yyvs = newvs; - yyvsp = newvs + i; - yystacksize = newsize; - yysslim = yyss + newsize - 1; - return 0; -bail: - if (yyss) - free(yyss); - if (yyvs) - free(yyvs); - yyss = yyssp = NULL; - yyvs = yyvsp = NULL; - yystacksize = 0; - return -1; -} - -#define YYABORT goto yyabort -#define YYREJECT goto yyabort -#define YYACCEPT goto yyaccept -#define YYERROR goto yyerrlab -int -#if defined(__cplusplus) || defined(__STDC__) -yyparse(void) -#else -yyparse() -#endif -{ - int yym, yyn, yystate; -#if YYDEBUG -#if defined(__cplusplus) || defined(__STDC__) - const char *yys; -#else /* !(defined(__cplusplus) || defined(__STDC__)) */ - char *yys; -#endif /* !(defined(__cplusplus) || defined(__STDC__)) */ - - if ((yys = getenv("YYDEBUG"))) - { - yyn = *yys; - if (yyn >= '0' && yyn <= '9') - yydebug = yyn - '0'; - } -#endif /* YYDEBUG */ - - yynerrs = 0; - yyerrflag = 0; - yychar = (-1); - - if (yyss == NULL && yygrowstack()) goto yyoverflow; - yyssp = yyss; - yyvsp = yyvs; - *yyssp = yystate = 0; - -yyloop: - if ((yyn = yydefred[yystate]) != 0) goto yyreduce; - if (yychar < 0) - { - if ((yychar = yylex()) < 0) yychar = 0; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - } - if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, yystate, yytable[yyn]); -#endif - if (yyssp >= yysslim && yygrowstack()) - { - goto yyoverflow; - } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; - yychar = (-1); - if (yyerrflag > 0) --yyerrflag; - goto yyloop; - } - if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { - yyn = yytable[yyn]; - goto yyreduce; - } - if (yyerrflag) goto yyinrecovery; -#if defined(lint) || defined(__GNUC__) - goto yynewerror; -#endif -yynewerror: - yyerror("syntax error"); -#if defined(lint) || defined(__GNUC__) - goto yyerrlab; -#endif -yyerrlab: - ++yynerrs; -yyinrecovery: - if (yyerrflag < 3) - { - yyerrflag = 3; - for (;;) - { - if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); -#endif - if (yyssp >= yysslim && yygrowstack()) - { - goto yyoverflow; - } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; - goto yyloop; - } - else - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *yyssp); -#endif - if (yyssp <= yyss) goto yyabort; - --yyssp; - --yyvsp; - } - } - } - else - { - if (yychar == 0) goto yyabort; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - yychar = (-1); - goto yyloop; - } -yyreduce: -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, yystate, yyn, yyrule[yyn]); -#endif - yym = yylen[yyn]; - if (yym) - yyval = yyvsp[1-yym]; - else - memset(&yyval, 0, sizeof yyval); - switch (yyn) - { -case 3: -#line 125 "getdate.y" -{ - yyHaveTime++; - } -break; -case 4: -#line 128 "getdate.y" -{ - yyHaveZone++; - } -break; -case 5: -#line 131 "getdate.y" -{ - yyHaveDate++; - } -break; -case 6: -#line 134 "getdate.y" -{ - yyHaveDay++; - } -break; -case 7: -#line 137 "getdate.y" -{ - yyHaveRel++; - } -break; -case 9: -#line 143 "getdate.y" -{ - yyHour = yyvsp[-1].Number; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = yyvsp[0].Meridian; - } -break; -case 10: -#line 149 "getdate.y" -{ - yyHour = yyvsp[-3].Number; - yyMinutes = yyvsp[-1].Number; - yySeconds = 0; - yyMeridian = yyvsp[0].Meridian; - } -break; -case 11: -#line 155 "getdate.y" -{ - yyHour = yyvsp[-3].Number; - yyMinutes = yyvsp[-1].Number; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); - } -break; -case 12: -#line 162 "getdate.y" -{ - yyHour = yyvsp[-5].Number; - yyMinutes = yyvsp[-3].Number; - yySeconds = yyvsp[-1].Number; - yyMeridian = yyvsp[0].Meridian; - } -break; -case 13: -#line 168 "getdate.y" -{ - yyHour = yyvsp[-5].Number; - yyMinutes = yyvsp[-3].Number; - yySeconds = yyvsp[-1].Number; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); - } -break; -case 14: -#line 178 "getdate.y" -{ - yyTimezone = yyvsp[0].Number; - yyDSTmode = DSToff; - } -break; -case 15: -#line 182 "getdate.y" -{ - yyTimezone = yyvsp[0].Number; - yyDSTmode = DSTon; - } -break; -case 16: -#line 187 "getdate.y" -{ - yyTimezone = yyvsp[-1].Number; - yyDSTmode = DSTon; - } -break; -case 17: -#line 193 "getdate.y" -{ - yyDayOrdinal = 1; - yyDayNumber = yyvsp[0].Number; - } -break; -case 18: -#line 197 "getdate.y" -{ - yyDayOrdinal = 1; - yyDayNumber = yyvsp[-1].Number; - } -break; -case 19: -#line 201 "getdate.y" -{ - yyDayOrdinal = yyvsp[-1].Number; - yyDayNumber = yyvsp[0].Number; - } -break; -case 20: -#line 207 "getdate.y" -{ - yyMonth = yyvsp[-2].Number; - yyDay = yyvsp[0].Number; - } -break; -case 21: -#line 211 "getdate.y" -{ - if (yyvsp[-4].Number >= 100) { - yyYear = yyvsp[-4].Number; - yyMonth = yyvsp[-2].Number; - yyDay = yyvsp[0].Number; - } else { - yyMonth = yyvsp[-4].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; - } - } -break; -case 22: -#line 222 "getdate.y" -{ - /* ISO 8601 format. yyyy-mm-dd. */ - yyYear = yyvsp[-2].Number; - yyMonth = -yyvsp[-1].Number; - yyDay = -yyvsp[0].Number; - } -break; -case 23: -#line 228 "getdate.y" -{ - /* e.g. 17-JUN-1992. */ - yyDay = yyvsp[-2].Number; - yyMonth = yyvsp[-1].Number; - yyYear = -yyvsp[0].Number; - } -break; -case 24: -#line 234 "getdate.y" -{ - yyMonth = yyvsp[-1].Number; - yyDay = yyvsp[0].Number; - } -break; -case 25: -#line 238 "getdate.y" -{ - yyMonth = yyvsp[-3].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; - } -break; -case 26: -#line 243 "getdate.y" -{ - yyMonth = yyvsp[0].Number; - yyDay = yyvsp[-1].Number; - } -break; -case 27: -#line 247 "getdate.y" -{ - yyMonth = yyvsp[-1].Number; - yyDay = yyvsp[-2].Number; - yyYear = yyvsp[0].Number; - } -break; -case 28: -#line 254 "getdate.y" -{ - yyRelSeconds = -yyRelSeconds; - yyRelMonth = -yyRelMonth; - } -break; -case 30: -#line 261 "getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; - } -break; -case 31: -#line 264 "getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; - } -break; -case 32: -#line 267 "getdate.y" -{ - yyRelSeconds += yyvsp[0].Number * 60L; - } -break; -case 33: -#line 270 "getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number; - } -break; -case 34: -#line 273 "getdate.y" -{ - yyRelSeconds += yyvsp[-1].Number; - } -break; -case 35: -#line 276 "getdate.y" -{ - yyRelSeconds++; - } -break; -case 36: -#line 279 "getdate.y" -{ - yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; - } -break; -case 37: -#line 282 "getdate.y" -{ - yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; - } -break; -case 38: -#line 285 "getdate.y" -{ - yyRelMonth += yyvsp[0].Number; - } -break; -case 39: -#line 290 "getdate.y" -{ - if (yyHaveTime && yyHaveDate && !yyHaveRel) - yyYear = yyvsp[0].Number; - else { - if(yyvsp[0].Number>10000) { - yyHaveDate++; - yyDay= (yyvsp[0].Number)%100; - yyMonth= (yyvsp[0].Number/100)%100; - yyYear = yyvsp[0].Number/10000; - } - else { - yyHaveTime++; - if (yyvsp[0].Number < 100) { - yyHour = yyvsp[0].Number; - yyMinutes = 0; - } - else { - yyHour = yyvsp[0].Number / 100; - yyMinutes = yyvsp[0].Number % 100; - } - yySeconds = 0; - yyMeridian = MER24; - } - } - } -break; -case 40: -#line 317 "getdate.y" -{ - yyval.Meridian = MER24; - } -break; -case 41: -#line 320 "getdate.y" -{ - yyval.Meridian = yyvsp[0].Meridian; - } -break; -#line 1474 "y.tab.c" - } - yyssp -= yym; - yystate = *yyssp; - yyvsp -= yym; - yym = yylhs[yyn]; - if (yystate == 0 && yym == 0) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); -#endif - yystate = YYFINAL; - *++yyssp = YYFINAL; - *++yyvsp = yyval; - if (yychar < 0) - { - if ((yychar = yylex()) < 0) yychar = 0; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, yychar, yys); - } -#endif - } - if (yychar == 0) goto yyaccept; - goto yyloop; - } - if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yystate) - yystate = yytable[yyn]; - else - yystate = yydgoto[yym]; -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *yyssp, yystate); -#endif - if (yyssp >= yysslim && yygrowstack()) - { - goto yyoverflow; - } - *++yyssp = yystate; - *++yyvsp = yyval; - goto yyloop; -yyoverflow: - yyerror("yacc stack overflow"); -yyabort: - if (yyss) - free(yyss); - if (yyvs) - free(yyvs); - yyss = yyssp = NULL; - yyvs = yyvsp = NULL; - yystacksize = 0; - return (1); -yyaccept: - if (yyss) - free(yyss); - if (yyvs) - free(yyvs); - yyss = yyssp = NULL; - yyvs = yyvsp = NULL; - yystacksize = 0; - return (0); -} diff --git a/getdate.y b/getdate.y deleted file mode 100644 index 2b2e3c9..0000000 --- a/getdate.y +++ /dev/null @@ -1,962 +0,0 @@ -%{ -/* -** Originally written by Steven M. Bellovin while -** at the University of North Carolina at Chapel Hill. Later tweaked by -** a couple of people on Usenet. Completely overhauled by Rich $alz -** and Jim Berets in August, 1990; -** -** This grammar has 10 shift/reduce conflicts. -** -** This code is in the public domain and has no copyright. -*/ -/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ -/* SUPPRESS 288 on yyerrlab *//* Label unused */ - -#include - -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#if TIME_WITH_SYS_TIME -# include -#endif -#include - -#include "compat.h" - - -#define EPOCH 1970 -#define HOUR(x) ((time_t)(x) * 60) -#define SECSPERDAY (24L * 60L * 60L) - - -/* -** An entry in the lexical lookup table. -*/ -typedef struct _TABLE { - char *name; - int type; - time_t value; -} TABLE; - - -/* -** Daylight-savings mode: on, off, or not yet known. -*/ -typedef enum _DSTMODE { - DSTon, DSToff, DSTmaybe -} DSTMODE; - -/* -** Meridian: am, pm, or 24-hour style. -*/ -typedef enum _MERIDIAN { - MERam, MERpm, MER24 -} MERIDIAN; - - -/* -** Global variables. We could get rid of most of these by using a good -** union as the yacc stack. (This routine was originally written before -** yacc had the %union construct.) Maybe someday; right now we only use -** the %union very rarely. -*/ -static char *yyInput; -static DSTMODE yyDSTmode; -static time_t yyDayOrdinal; -static time_t yyDayNumber; -static int yyHaveDate; -static int yyHaveDay; -static int yyHaveRel; -static int yyHaveTime; -static int yyHaveZone; -static time_t yyTimezone; -static time_t yyDay; -static time_t yyHour; -static time_t yyMinutes; -static time_t yyMonth; -static time_t yySeconds; -static time_t yyYear; -static MERIDIAN yyMeridian; -static time_t yyRelMonth; -static time_t yyRelSeconds; - -static int yyerror __P((char *s)); -static int yylex __P((void)); -static int yyparse __P((void)); - -%} - -%union { - time_t Number; - enum _MERIDIAN Meridian; -} - -%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT -%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST - -%type tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT -%type tSEC_UNIT tSNUMBER tUNUMBER tZONE -%type tMERIDIAN o_merid - -%% - -spec : /* NULL */ - | spec item - ; - -item : time { - yyHaveTime++; - } - | zone { - yyHaveZone++; - } - | date { - yyHaveDate++; - } - | day { - yyHaveDay++; - } - | rel { - yyHaveRel++; - } - | number - ; - -time : tUNUMBER tMERIDIAN { - yyHour = $1; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = $2; - } - | tUNUMBER ':' tUNUMBER o_merid { - yyHour = $1; - yyMinutes = $3; - yySeconds = 0; - yyMeridian = $4; - } - | tUNUMBER ':' tUNUMBER tSNUMBER { - yyHour = $1; - yyMinutes = $3; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - ($4 % 100 + ($4 / 100) * 60); - } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { - yyHour = $1; - yyMinutes = $3; - yySeconds = $5; - yyMeridian = $6; - } - | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { - yyHour = $1; - yyMinutes = $3; - yySeconds = $5; - yyMeridian = MER24; - yyDSTmode = DSToff; - yyTimezone = - ($6 % 100 + ($6 / 100) * 60); - } - ; - -zone : tZONE { - yyTimezone = $1; - yyDSTmode = DSToff; - } - | tDAYZONE { - yyTimezone = $1; - yyDSTmode = DSTon; - } - | - tZONE tDST { - yyTimezone = $1; - yyDSTmode = DSTon; - } - ; - -day : tDAY { - yyDayOrdinal = 1; - yyDayNumber = $1; - } - | tDAY ',' { - yyDayOrdinal = 1; - yyDayNumber = $1; - } - | tUNUMBER tDAY { - yyDayOrdinal = $1; - yyDayNumber = $2; - } - ; - -date : tUNUMBER '/' tUNUMBER { - yyMonth = $1; - yyDay = $3; - } - | tUNUMBER '/' tUNUMBER '/' tUNUMBER { - if ($1 >= 100) { - yyYear = $1; - yyMonth = $3; - yyDay = $5; - } else { - yyMonth = $1; - yyDay = $3; - yyYear = $5; - } - } - | tUNUMBER tSNUMBER tSNUMBER { - /* ISO 8601 format. yyyy-mm-dd. */ - yyYear = $1; - yyMonth = -$2; - yyDay = -$3; - } - | tUNUMBER tMONTH tSNUMBER { - /* e.g. 17-JUN-1992. */ - yyDay = $1; - yyMonth = $2; - yyYear = -$3; - } - | tMONTH tUNUMBER { - yyMonth = $1; - yyDay = $2; - } - | tMONTH tUNUMBER ',' tUNUMBER { - yyMonth = $1; - yyDay = $2; - yyYear = $4; - } - | tUNUMBER tMONTH { - yyMonth = $2; - yyDay = $1; - } - | tUNUMBER tMONTH tUNUMBER { - yyMonth = $2; - yyDay = $1; - yyYear = $3; - } - ; - -rel : relunit tAGO { - yyRelSeconds = -yyRelSeconds; - yyRelMonth = -yyRelMonth; - } - | relunit - ; - -relunit : tUNUMBER tMINUTE_UNIT { - yyRelSeconds += $1 * $2 * 60L; - } - | tSNUMBER tMINUTE_UNIT { - yyRelSeconds += $1 * $2 * 60L; - } - | tMINUTE_UNIT { - yyRelSeconds += $1 * 60L; - } - | tSNUMBER tSEC_UNIT { - yyRelSeconds += $1; - } - | tUNUMBER tSEC_UNIT { - yyRelSeconds += $1; - } - | tSEC_UNIT { - yyRelSeconds++; - } - | tSNUMBER tMONTH_UNIT { - yyRelMonth += $1 * $2; - } - | tUNUMBER tMONTH_UNIT { - yyRelMonth += $1 * $2; - } - | tMONTH_UNIT { - yyRelMonth += $1; - } - ; - -number : tUNUMBER { - if (yyHaveTime && yyHaveDate && !yyHaveRel) - yyYear = $1; - else { - if($1>10000) { - yyHaveDate++; - yyDay= ($1)%100; - yyMonth= ($1/100)%100; - yyYear = $1/10000; - } - else { - yyHaveTime++; - if ($1 < 100) { - yyHour = $1; - yyMinutes = 0; - } - else { - yyHour = $1 / 100; - yyMinutes = $1 % 100; - } - yySeconds = 0; - yyMeridian = MER24; - } - } - } - ; - -o_merid : /* NULL */ { - $$ = MER24; - } - | tMERIDIAN { - $$ = $1; - } - ; - -%% - -/* Month and day table. */ -static TABLE const MonthDayTable[] = { - { "january", tMONTH, 1 }, - { "february", tMONTH, 2 }, - { "march", tMONTH, 3 }, - { "april", tMONTH, 4 }, - { "may", tMONTH, 5 }, - { "june", tMONTH, 6 }, - { "july", tMONTH, 7 }, - { "august", tMONTH, 8 }, - { "september", tMONTH, 9 }, - { "sept", tMONTH, 9 }, - { "october", tMONTH, 10 }, - { "november", tMONTH, 11 }, - { "december", tMONTH, 12 }, - { "sunday", tDAY, 0 }, - { "monday", tDAY, 1 }, - { "tuesday", tDAY, 2 }, - { "tues", tDAY, 2 }, - { "wednesday", tDAY, 3 }, - { "wednes", tDAY, 3 }, - { "thursday", tDAY, 4 }, - { "thur", tDAY, 4 }, - { "thurs", tDAY, 4 }, - { "friday", tDAY, 5 }, - { "saturday", tDAY, 6 }, - { NULL } -}; - -/* Time units table. */ -static TABLE const UnitsTable[] = { - { "year", tMONTH_UNIT, 12 }, - { "month", tMONTH_UNIT, 1 }, - { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, - { "week", tMINUTE_UNIT, 7 * 24 * 60 }, - { "day", tMINUTE_UNIT, 1 * 24 * 60 }, - { "hour", tMINUTE_UNIT, 60 }, - { "minute", tMINUTE_UNIT, 1 }, - { "min", tMINUTE_UNIT, 1 }, - { "second", tSEC_UNIT, 1 }, - { "sec", tSEC_UNIT, 1 }, - { NULL } -}; - -/* Assorted relative-time words. */ -static TABLE const OtherTable[] = { - { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, - { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, - { "today", tMINUTE_UNIT, 0 }, - { "now", tMINUTE_UNIT, 0 }, - { "last", tUNUMBER, -1 }, - { "this", tMINUTE_UNIT, 0 }, - { "next", tUNUMBER, 2 }, - { "first", tUNUMBER, 1 }, -/* { "second", tUNUMBER, 2 }, */ - { "third", tUNUMBER, 3 }, - { "fourth", tUNUMBER, 4 }, - { "fifth", tUNUMBER, 5 }, - { "sixth", tUNUMBER, 6 }, - { "seventh", tUNUMBER, 7 }, - { "eighth", tUNUMBER, 8 }, - { "ninth", tUNUMBER, 9 }, - { "tenth", tUNUMBER, 10 }, - { "eleventh", tUNUMBER, 11 }, - { "twelfth", tUNUMBER, 12 }, - { "ago", tAGO, 1 }, - { NULL } -}; - -/* The timezone table. */ -/* Some of these are commented out because a time_t can't store a float. */ -static TABLE const TimezoneTable[] = { - { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ - { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ - { "utc", tZONE, HOUR( 0) }, - { "wet", tZONE, HOUR( 0) }, /* Western European */ - { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ - { "wat", tZONE, HOUR( 1) }, /* West Africa */ - { "at", tZONE, HOUR( 2) }, /* Azores */ -#if 0 - /* For completeness. BST is also British Summer, and GST is - * also Guam Standard. */ - { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ - { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ -#endif -#if 0 - { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ - { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ - { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ -#endif - { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ - { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ - { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ - { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ - { "cst", tZONE, HOUR( 6) }, /* Central Standard */ - { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ - { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ - { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ - { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ - { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ - { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ - { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ - { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ - { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ - { "cat", tZONE, HOUR(10) }, /* Central Alaska */ - { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ - { "nt", tZONE, HOUR(11) }, /* Nome */ - { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ - { "cet", tZONE, -HOUR(1) }, /* Central European */ - { "met", tZONE, -HOUR(1) }, /* Middle European */ - { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ - { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ - { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ - { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ - { "fwt", tZONE, -HOUR(1) }, /* French Winter */ - { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ - { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ - { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ -#if 0 - { "it", tZONE, -HOUR(3.5) },/* Iran */ -#endif - { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ - { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ -#if 0 - { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ -#endif - { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ -#if 0 - /* For completeness. NST is also Newfoundland Stanard, and SST is - * also Swedish Summer. */ - { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ - { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ -#endif /* 0 */ - { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ - { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ -#if 0 - { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ -#endif - { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ - { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ -#if 0 - { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ - { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ -#endif - { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ - { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ - { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ - { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ - { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ - { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ - { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ - { NULL } -}; - -/* Military timezone table. */ -static TABLE const MilitaryTable[] = { - { "a", tZONE, HOUR( 1) }, - { "b", tZONE, HOUR( 2) }, - { "c", tZONE, HOUR( 3) }, - { "d", tZONE, HOUR( 4) }, - { "e", tZONE, HOUR( 5) }, - { "f", tZONE, HOUR( 6) }, - { "g", tZONE, HOUR( 7) }, - { "h", tZONE, HOUR( 8) }, - { "i", tZONE, HOUR( 9) }, - { "k", tZONE, HOUR( 10) }, - { "l", tZONE, HOUR( 11) }, - { "m", tZONE, HOUR( 12) }, - { "n", tZONE, HOUR(- 1) }, - { "o", tZONE, HOUR(- 2) }, - { "p", tZONE, HOUR(- 3) }, - { "q", tZONE, HOUR(- 4) }, - { "r", tZONE, HOUR(- 5) }, - { "s", tZONE, HOUR(- 6) }, - { "t", tZONE, HOUR(- 7) }, - { "u", tZONE, HOUR(- 8) }, - { "v", tZONE, HOUR(- 9) }, - { "w", tZONE, HOUR(-10) }, - { "x", tZONE, HOUR(-11) }, - { "y", tZONE, HOUR(-12) }, - { "z", tZONE, HOUR( 0) }, - { NULL } -}; - - - - -/* ARGSUSED */ -static int -yyerror(s) - char *s; -{ - return 0; -} - - -static time_t -ToSeconds(Hours, Minutes, Seconds, Meridian) - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; -{ - if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) - return -1; - switch (Meridian) { - case MER24: - if (Hours < 0 || Hours > 23) - return -1; - return (Hours * 60L + Minutes) * 60L + Seconds; - case MERam: - if (Hours < 1 || Hours > 12) - return -1; - if (Hours == 12) - Hours = 0; - return (Hours * 60L + Minutes) * 60L + Seconds; - case MERpm: - if (Hours < 1 || Hours > 12) - return -1; - if (Hours == 12) - Hours = 0; - return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; - default: - abort (); - } - /* NOTREACHED */ -} - - -/* Year is either - * A negative number, which means to use its absolute value (why?) - * A number from 0 to 99, which means a year from 1900 to 1999, or - * The actual year (>=100). */ -static time_t -Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) - time_t Month; - time_t Day; - time_t Year; - time_t Hours; - time_t Minutes; - time_t Seconds; - MERIDIAN Meridian; - DSTMODE DSTmode; -{ - static int DaysInMonth[12] = { - 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; - time_t tod; - time_t Julian; - int i; - - if (Year < 0) - Year = -Year; - if (Year < 69) - Year += 2000; - else if (Year < 100) { - Year += 1900; - if (Year < EPOCH) - Year += 100; - } - DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) - ? 29 : 28; - /* Checking for 2038 bogusly assumes that time_t is 32 bits. But - I'm too lazy to try to check for time_t overflow in another way. */ - if (Year < EPOCH || Year > 2038 - || Month < 1 || Month > 12 - /* Lint fluff: "conversion from long may lose accuracy" */ - || Day < 1 || Day > DaysInMonth[(int)--Month]) - return -1; - - for (Julian = Day - 1, i = 0; i < Month; i++) - Julian += DaysInMonth[i]; - for (i = EPOCH; i < Year; i++) - Julian += 365 + (i % 4 == 0); - Julian *= SECSPERDAY; - Julian += yyTimezone * 60L; - if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) - return -1; - Julian += tod; - if (DSTmode == DSTon - || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) - Julian -= 60 * 60; - return Julian; -} - - -static time_t -DSTcorrect(Start, Future) - time_t Start; - time_t Future; -{ - time_t StartDay; - time_t FutureDay; - - StartDay = (localtime(&Start)->tm_hour + 1) % 24; - FutureDay = (localtime(&Future)->tm_hour + 1) % 24; - return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; -} - - -static time_t -RelativeDate(Start, DayOrdinal, DayNumber) - time_t Start; - time_t DayOrdinal; - time_t DayNumber; -{ - struct tm *tm; - time_t now; - - now = Start; - tm = localtime(&now); - now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); - now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); - return DSTcorrect(Start, now); -} - - -static time_t -RelativeMonth(Start, RelMonth) - time_t Start; - time_t RelMonth; -{ - struct tm *tm; - time_t Month; - time_t Year; - - if (RelMonth == 0) - return 0; - tm = localtime(&Start); - Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; - Year = Month / 12; - Month = Month % 12 + 1; - return DSTcorrect(Start, - Convert(Month, (time_t)tm->tm_mday, Year, - (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, - MER24, DSTmaybe)); -} - - -static int -LookupWord(buff) - char *buff; -{ - char *p; - char *q; - const TABLE *tp; - int i; - int abbrev; - - /* Make it lowercase. */ - for (p = buff; *p; p++) - if (isupper((unsigned char)*p)) - *p = tolower((unsigned char)*p); - - if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { - yylval.Meridian = MERam; - return tMERIDIAN; - } - if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { - yylval.Meridian = MERpm; - return tMERIDIAN; - } - - /* See if we have an abbreviation for a month. */ - if (strlen(buff) == 3) - abbrev = 1; - else if (strlen(buff) == 4 && buff[3] == '.') { - abbrev = 1; - buff[3] = '\0'; - } - else - abbrev = 0; - - for (tp = MonthDayTable; tp->name; tp++) { - if (abbrev) { - if (strncmp(buff, tp->name, 3) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - else if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - - for (tp = TimezoneTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - if (strcmp(buff, "dst") == 0) - return tDST; - - for (tp = UnitsTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - /* Strip off any plural and try the units table again. */ - i = strlen(buff) - 1; - if (buff[i] == 's') { - buff[i] = '\0'; - for (tp = UnitsTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - buff[i] = 's'; /* Put back for "this" in OtherTable. */ - } - - for (tp = OtherTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - /* Military timezones. */ - if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { - for (tp = MilitaryTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - } - - /* Drop out any periods and try the timezone table again. */ - for (i = 0, p = q = buff; *q; q++) - if (*q != '.') - *p++ = *q; - else - i++; - *p = '\0'; - if (i) - for (tp = TimezoneTable; tp->name; tp++) - if (strcmp(buff, tp->name) == 0) { - yylval.Number = tp->value; - return tp->type; - } - - return tID; -} - - -static int -yylex() -{ - char c; - char *p; - char buff[20]; - int Count; - int sign; - - for ( ; ; ) { - while (isspace((unsigned char)*yyInput)) - yyInput++; - - if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') { - if (c == '-' || c == '+') { - sign = c == '-' ? -1 : 1; - if (!isdigit((unsigned char)*++yyInput)) - /* skip the '-' sign */ - continue; - } - else - sign = 0; - for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); ) - yylval.Number = 10 * yylval.Number + c - '0'; - yyInput--; - if (sign < 0) - yylval.Number = -yylval.Number; - return sign ? tSNUMBER : tUNUMBER; - } - if (isalpha((unsigned char)c)) { - for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; ) - if (p < &buff[sizeof buff - 1]) - *p++ = c; - *p = '\0'; - yyInput--; - return LookupWord(buff); - } - if (c != '(') - return *yyInput++; - Count = 0; - do { - c = *yyInput++; - if (c == '\0') - return c; - if (c == '(') - Count++; - else if (c == ')') - Count--; - } while (Count > 0); - } -} - -#define TM_YEAR_ORIGIN 1900 - -/* Yield A - B, measured in seconds. */ -static long -difftm (a, b) - struct tm *a, *b; -{ - int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); - int by = b->tm_year + (TM_YEAR_ORIGIN - 1); - int days = ( - /* difference in day of year */ - a->tm_yday - b->tm_yday - /* + intervening leap days */ - + ((ay >> 2) - (by >> 2)) - - (ay/100 - by/100) - + ((ay/100 >> 2) - (by/100 >> 2)) - /* + difference in years * 365 */ - + (long)(ay-by) * 365 - ); - return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) - + (a->tm_min - b->tm_min)) - + (a->tm_sec - b->tm_sec)); -} - -time_t -get_date(p) - char *p; -{ - struct tm *tm, *gmt, gmtbuf; - time_t Start; - time_t tod; - time_t now; - time_t timezone; - - yyInput = p; - (void)time (&now); - - gmt = gmtime (&now); - if (gmt != NULL) - { - /* Make a copy, in case localtime modifies *tm (I think - that comment now applies to *gmt, but I am too - lazy to dig into how gmtime and locatime allocate the - structures they return pointers to). */ - gmtbuf = *gmt; - gmt = &gmtbuf; - } - - if (! (tm = localtime (&now))) - return -1; - - if (gmt != NULL) - timezone = difftm (gmt, tm) / 60; - else - /* We are on a system like VMS, where the system clock is - in local time and the system has no concept of timezones. - Hopefully we can fake this out (for the case in which the - user specifies no timezone) by just saying the timezone - is zero. */ - timezone = 0; - - if(tm->tm_isdst) - timezone += 60; - - tm = localtime(&now); - yyYear = tm->tm_year + 1900; - yyMonth = tm->tm_mon + 1; - yyDay = tm->tm_mday; - yyTimezone = timezone; - yyDSTmode = DSTmaybe; - yyHour = 0; - yyMinutes = 0; - yySeconds = 0; - yyMeridian = MER24; - yyRelSeconds = 0; - yyRelMonth = 0; - yyHaveDate = 0; - yyHaveDay = 0; - yyHaveRel = 0; - yyHaveTime = 0; - yyHaveZone = 0; - - if (yyparse() - || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) - return -1; - - if (yyHaveDate || yyHaveTime || yyHaveDay) { - Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, - yyMeridian, yyDSTmode); - if (Start < 0) - return -1; - } - else { - Start = now; - if (!yyHaveRel) - Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; - } - - Start += yyRelSeconds; - Start += RelativeMonth(Start, yyRelMonth); - - if (yyHaveDay && !yyHaveDate) { - tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); - Start += tod; - } - - /* Have to do *something* with a legitimate -1 so it's distinguishable - * from the error return value. (Alternately could set errno on error.) */ - return Start == -1 ? 0 : Start; -} - - -#if defined(TEST) - -/* ARGSUSED */ -int -main(ac, av) - int ac; - char *av[]; -{ - char buff[128]; - time_t d; - - (void)printf("Enter date, or blank line to exit.\n\t> "); - (void)fflush(stdout); - while (gets(buff) && buff[0]) { - d = get_date(buff); - if (d == -1) - (void)printf("Bad format - couldn't convert.\n"); - else - (void)printf("%s", ctime(&d)); - (void)printf("\t> "); - (void)fflush(stdout); - } - exit(0); - /* NOTREACHED */ -} -#endif /* defined(TEST) */ diff --git a/getline.c b/getline.c deleted file mode 100644 index b7db379..0000000 --- a/getline.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#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 */ -#include - -#include "compat.h" -#include "alloc.h" - -#ifndef LINE_MAX -# define LINE_MAX 2048 -#endif - -#ifdef HAVE_FGETLN -ssize_t -getline(bufp, bufsizep, fp) - char **bufp; - size_t *bufsizep; - FILE *fp; -{ - char *buf; - size_t bufsize; - size_t len; - - buf = fgetln(fp, &len); - if (buf) { - bufsize = *bufp ? *bufsizep : 0; - if (bufsize < len + 1) { - bufsize = len + 1; - *bufp = erealloc(*bufp, bufsize); - *bufsizep = bufsize; - } - memcpy(*bufp, buf, len); - (*bufp)[len] = '\0'; - } - return(buf ? len : -1); -} -#else -ssize_t -getline(bufp, bufsizep, fp) - char **bufp; - size_t *bufsizep; - FILE *fp; -{ - char *buf; - size_t bufsize; - ssize_t len = 0; - - buf = *bufp; - bufsize = *bufsizep; - if (buf == NULL || bufsize == 0) { - bufsize = LINE_MAX; - buf = erealloc(buf, LINE_MAX); - } - - for (;;) { - if (fgets(buf + len, bufsize - len, fp) == NULL) { - len = -1; - break; - } - len = strlen(buf); - if (!len || buf[len - 1] == '\n' || feof(fp)) - break; - bufsize *= 2; - buf = erealloc(buf, bufsize); - } - *bufp = buf; - *bufsizep = bufsize; - return(len); -} -#endif diff --git a/getprogname.c b/getprogname.c deleted file mode 100644 index f269405..0000000 --- a/getprogname.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2003-2005 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. - */ - -#include -#include - -#include -#include - -const char * -getprogname() -{ - static const char *progname; - extern int Argc; - extern char **Argv; - - if (progname == NULL) { - if (Argc < 0) - progname = "sudo"; - else if ((progname = strrchr(Argv[0], '/')) != NULL) - progname++; - else - progname = Argv[0]; - } - return(progname); -} diff --git a/getspwuid.c b/getspwuid.c deleted file mode 100644 index 7ee5eba..0000000 --- a/getspwuid.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 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. - */ - -#include - -#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 */ -#include -#include -#ifdef HAVE_GETSPNAM -# include -#endif /* HAVE_GETSPNAM */ -#ifdef HAVE_GETPRPWNAM -# ifdef __hpux -# undef MAXINT -# include -# else -# include -# endif /* __hpux */ -# include -#endif /* HAVE_GETPRPWNAM */ -#ifdef HAVE_GETPWANAM -# include -# include -# include -#endif /* HAVE_GETPWANAM */ -#ifdef HAVE_GETAUTHUID -# include -#endif /* HAVE_GETAUTHUID */ - -#include "sudo.h" - -/* - * Exported for auth/secureware.c - */ -#if defined(HAVE_GETPRPWNAM) && defined(__alpha) -int crypt_type = INT_MAX; -#endif /* HAVE_GETPRPWNAM && __alpha */ - -/* - * Return a copy of the encrypted password for the user described by pw. - * If shadow passwords are in use, look in the shadow file. - */ -char * -sudo_getepw(pw) - const struct passwd *pw; -{ - char *epw; - - /* If there is a function to check for shadow enabled, use it... */ -#ifdef HAVE_ISCOMSEC - if (!iscomsec()) - return(estrdup(pw->pw_passwd)); -#endif /* HAVE_ISCOMSEC */ -#ifdef HAVE_ISSECURE - if (!issecure()) - return(estrdup(pw->pw_passwd)); -#endif /* HAVE_ISSECURE */ - - epw = NULL; -#ifdef HAVE_GETPRPWNAM - { - struct pr_passwd *spw; - - if ((spw = getprpwnam(pw->pw_name)) && spw->ufld.fd_encrypt) { -# ifdef __alpha - crypt_type = spw->ufld.fd_oldcrypt; -# endif /* __alpha */ - epw = estrdup(spw->ufld.fd_encrypt); - } - if (epw) - return(epw); - } -#endif /* HAVE_GETPRPWNAM */ -#ifdef HAVE_GETSPNAM - { - struct spwd *spw; - - if ((spw = getspnam(pw->pw_name)) && spw->sp_pwdp) - epw = estrdup(spw->sp_pwdp); - if (epw) - return(epw); - } -#endif /* HAVE_GETSPNAM */ -#ifdef HAVE_GETSPWUID - { - struct s_passwd *spw; - - if ((spw = getspwuid(pw->pw_uid)) && spw->pw_passwd) - epw = estrdup(spw->pw_passwd); - if (epw) - return(epw); - } -#endif /* HAVE_GETSPWUID */ -#ifdef HAVE_GETPWANAM - { - struct passwd_adjunct *spw; - - if ((spw = getpwanam(pw->pw_name)) && spw->pwa_passwd) - epw = estrdup(spw->pwa_passwd); - if (epw) - return(epw); - } -#endif /* HAVE_GETPWANAM */ -#ifdef HAVE_GETAUTHUID - { - AUTHORIZATION *spw; - - if ((spw = getauthuid(pw->pw_uid)) && spw->a_password) - epw = estrdup(spw->a_password); - if (epw) - return(epw); - } -#endif /* HAVE_GETAUTHUID */ - - /* Fall back on normal password. */ - return(estrdup(pw->pw_passwd)); -} - -void -sudo_setspent() -{ -#ifdef HAVE_GETPRPWNAM - setprpwent(); -#endif -#ifdef HAVE_GETSPNAM - setspent(); -#endif -#ifdef HAVE_GETSPWUID - setspwent(); -#endif -#ifdef HAVE_GETPWANAM - setpwaent(); -#endif -#ifdef HAVE_GETAUTHUID - setauthent(); -#endif -} - -void -sudo_endspent() -{ -#ifdef HAVE_GETPRPWNAM - endprpwent(); -#endif -#ifdef HAVE_GETSPNAM - endspent(); -#endif -#ifdef HAVE_GETSPWUID - endspwent(); -#endif -#ifdef HAVE_GETPWANAM - endpwaent(); -#endif -#ifdef HAVE_GETAUTHUID - endauthent(); -#endif -} diff --git a/gettime.c b/gettime.c deleted file mode 100644 index 9a13003..0000000 --- a/gettime.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2004-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. - */ - -#include - -#include -#include -#include -#if TIME_WITH_SYS_TIME -# include -#endif - -#include - -/* - * Get the current time via gettimeofday() for systems with - * timespecs in struct stat or, otherwise, using time(). - */ -int -gettime(tv) - struct timeval *tv; -{ - int rval; -#if defined(HAVE_GETTIMEOFDAY) && (defined(HAVE_ST_MTIM) || defined(HAVE_ST_MTIMESPEC)) - rval = gettimeofday(tv, NULL); -#else - rval = (int)time(&tv->tv_sec); - tv->tv_usec = 0; -#endif - return (rval); -} diff --git a/glob.c b/glob.c deleted file mode 100644 index 9673626..0000000 --- a/glob.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * Copyright (c) 2008-2010 Todd C. Miller - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Guido van Rossum. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)glob.c 8.3 (Berkeley) 10/13/93 - */ - -/* - * glob(3) -- a superset of the one defined in POSIX 1003.2. - * - * The [!...] convention to negate a range is supported (SysV, Posix, ksh). - * - * Optional extra services, controlled by flags not defined by POSIX: - * - * GLOB_MAGCHAR: - * Set in gl_flags if pattern contained a globbing character. - * GLOB_TILDE: - * expand ~user/foo to the /home/dir/of/user/foo - * GLOB_BRACE: - * expand {1,2}{a,b} to 1a 1b 2a 2b - * gl_matchc: - * Number of matches in the current invocation of glob. - */ - -#include - -#include -#include - -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !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 */ -#include -#ifdef HAVE_DIRENT_H -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif -#include -#include -#include - -#include -#include "emul/glob.h" -#include "emul/charclass.h" - -#define DOLLAR '$' -#define DOT '.' -#define EOS '\0' -#define LBRACKET '[' -#define NOT '!' -#define QUESTION '?' -#define QUOTE '\\' -#define RANGE '-' -#define RBRACKET ']' -#define SEP '/' -#define STAR '*' -#define TILDE '~' -#define UNDERSCORE '_' -#define LBRACE '{' -#define RBRACE '}' -#define SLASH '/' -#define COMMA ',' - -#ifndef DEBUG - -#define M_QUOTE 0x8000 -#define M_PROTECT 0x4000 -#define M_MASK 0xffff -#define M_ASCII 0x00ff - -typedef unsigned short Char; - -#else - -#define M_QUOTE 0x80 -#define M_PROTECT 0x40 -#define M_MASK 0xff -#define M_ASCII 0x7f - -typedef char Char; - -#endif - - -#define CHAR(c) ((Char)((c)&M_ASCII)) -#define META(c) ((Char)((c)|M_QUOTE)) -#define M_ALL META('*') -#define M_END META(']') -#define M_NOT META('!') -#define M_ONE META('?') -#define M_RNG META('-') -#define M_SET META('[') -#define M_CLASS META(':') -#define ismeta(c) (((c)&M_QUOTE) != 0) - - -static int compare __P((const void *, const void *)); -static int g_Ctoc __P((const Char *, char *, unsigned int)); -static int g_lstat __P((Char *, struct stat *, glob_t *)); -static DIR *g_opendir __P((Char *, glob_t *)); -static Char *g_strchr __P((const Char *, int)); -static int g_strncmp __P((const Char *, const char *, size_t)); -static int g_stat __P((Char *, struct stat *, glob_t *)); -static int glob0 __P((const Char *, glob_t *)); -static int glob1 __P((Char *, Char *, glob_t *)); -static int glob2 __P((Char *, Char *, Char *, Char *, Char *, Char *, - glob_t *)); -static int glob3 __P((Char *, Char *, Char *, Char *, Char *, Char *, - Char *, Char *, glob_t *)); -static int globextend __P((const Char *, glob_t *)); -static const Char * - globtilde __P((const Char *, Char *, size_t, glob_t *)); -static int globexp1 __P((const Char *, glob_t *)); -static int globexp2 __P((const Char *, const Char *, glob_t *, int *)); -static int match __P((Char *, Char *, Char *)); -#ifdef DEBUG -static void qprintf __P((const char *, Char *)); -#endif - -extern struct passwd *sudo_getpwnam __P((const char *)); -extern struct passwd *sudo_getpwuid __P((uid_t)); - -int -glob(pattern, flags, errfunc, pglob) - const char *pattern; - int flags, (*errfunc) __P((const char *, int)); - glob_t *pglob; -{ - const unsigned char *patnext; - int c; - Char *bufnext, *bufend, patbuf[PATH_MAX]; - - patnext = (unsigned char *) pattern; - if (!(flags & GLOB_APPEND)) { - pglob->gl_pathc = 0; - pglob->gl_pathv = NULL; - if (!(flags & GLOB_DOOFFS)) - pglob->gl_offs = 0; - } - pglob->gl_flags = flags & ~GLOB_MAGCHAR; - pglob->gl_errfunc = errfunc; - pglob->gl_matchc = 0; - - bufnext = patbuf; - bufend = bufnext + PATH_MAX - 1; - if (flags & GLOB_NOESCAPE) - while (bufnext < bufend && (c = *patnext++) != EOS) - *bufnext++ = c; - else { - /* Protect the quoted characters. */ - while (bufnext < bufend && (c = *patnext++) != EOS) - if (c == QUOTE) { - if ((c = *patnext++) == EOS) { - c = QUOTE; - --patnext; - } - *bufnext++ = c | M_PROTECT; - } else - *bufnext++ = c; - } - *bufnext = EOS; - - if (flags & GLOB_BRACE) - return globexp1(patbuf, pglob); - else - return glob0(patbuf, pglob); -} - -/* - * Expand recursively a glob {} pattern. When there is no more expansion - * invoke the standard globbing routine to glob the rest of the magic - * characters - */ -static int -globexp1(pattern, pglob) - const Char *pattern; - glob_t *pglob; -{ - const Char* ptr = pattern; - int rv; - - /* Protect a single {}, for find(1), like csh */ - if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) - return glob0(pattern, pglob); - - while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) - if (!globexp2(ptr, pattern, pglob, &rv)) - return rv; - - return glob0(pattern, pglob); -} - - -/* - * Recursive brace globbing helper. Tries to expand a single brace. - * If it succeeds then it invokes globexp1 with the new pattern. - * If it fails then it tries to glob the rest of the pattern and returns. - */ -static int -globexp2(ptr, pattern, pglob, rv) - const Char *ptr, *pattern; - glob_t *pglob; - int *rv; -{ - int i; - Char *lm, *ls; - const Char *pe, *pm, *pl; - Char patbuf[PATH_MAX]; - - /* copy part up to the brace */ - for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) - continue; - *lm = EOS; - ls = lm; - - /* Find the balanced brace */ - for (i = 0, pe = ++ptr; *pe; pe++) - if (*pe == LBRACKET) { - /* Ignore everything between [] */ - for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) - continue; - if (*pe == EOS) { - /* - * We could not find a matching RBRACKET. - * Ignore and just look for RBRACE - */ - pe = pm; - } - } else if (*pe == LBRACE) - i++; - else if (*pe == RBRACE) { - if (i == 0) - break; - i--; - } - - /* Non matching braces; just glob the pattern */ - if (i != 0 || *pe == EOS) { - *rv = glob0(patbuf, pglob); - return 0; - } - - for (i = 0, pl = pm = ptr; pm <= pe; pm++) { - switch (*pm) { - case LBRACKET: - /* Ignore everything between [] */ - for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++) - continue; - if (*pm == EOS) { - /* - * We could not find a matching RBRACKET. - * Ignore and just look for RBRACE - */ - pm = pl; - } - break; - - case LBRACE: - i++; - break; - - case RBRACE: - if (i) { - i--; - break; - } - /* FALLTHROUGH */ - case COMMA: - if (i && *pm == COMMA) - break; - else { - /* Append the current string */ - for (lm = ls; (pl < pm); *lm++ = *pl++) - continue; - - /* - * Append the rest of the pattern after the - * closing brace - */ - for (pl = pe + 1; (*lm++ = *pl++) != EOS; ) - continue; - - /* Expand the current pattern */ -#ifdef DEBUG - qprintf("globexp2:", patbuf); -#endif - *rv = globexp1(patbuf, pglob); - - /* move after the comma, to the next string */ - pl = pm + 1; - } - break; - - default: - break; - } - } - *rv = 0; - return 0; -} - - - -/* - * expand tilde from the passwd file. - */ -static const Char * -globtilde(pattern, patbuf, patbuf_len, pglob) - const Char *pattern; - Char *patbuf; - size_t patbuf_len; - glob_t *pglob; -{ - struct passwd *pwd; - char *h; - const Char *p; - Char *b, *eb; - - if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) - return pattern; - - /* Copy up to the end of the string or / */ - eb = &patbuf[patbuf_len - 1]; - for (p = pattern + 1, h = (char *) patbuf; - h < (char *)eb && *p && *p != SLASH; *h++ = *p++) - continue; - - *h = EOS; - - if (((char *) patbuf)[0] == EOS) { - /* - * handle a plain ~ or ~/ by expanding $HOME - * first and then trying the password file - */ - if ((h = getenv("HOME")) == NULL) { - if ((pwd = sudo_getpwuid(getuid())) == NULL) - return pattern; - else - h = pwd->pw_dir; - } - } else { - /* - * Expand a ~user - */ - if ((pwd = sudo_getpwnam((char*) patbuf)) == NULL) - return pattern; - else - h = pwd->pw_dir; - } - - /* Copy the home directory */ - for (b = patbuf; b < eb && *h; *b++ = *h++) - continue; - - /* Append the rest of the pattern */ - while (b < eb && (*b++ = *p++) != EOS) - continue; - *b = EOS; - - return patbuf; -} - -static int -g_strncmp(s1, s2, n) - const Char *s1; - const char *s2; - size_t n; -{ - int rv = 0; - - while (n--) { - rv = *(Char *)s1 - *(const unsigned char *)s2++; - if (rv) - break; - if (*s1++ == '\0') - break; - } - return rv; -} - -static int -g_charclass(patternp, bufnextp) - const Char **patternp; - Char **bufnextp; -{ - const Char *pattern = *patternp + 1; - Char *bufnext = *bufnextp; - const Char *colon; - struct cclass *cc; - size_t len; - - if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']') - return 1; /* not a character class */ - - len = (size_t)(colon - pattern); - for (cc = cclasses; cc->name != NULL; cc++) { - if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0') - break; - } - if (cc->name == NULL) - return -1; /* invalid character class */ - *bufnext++ = M_CLASS; - *bufnext++ = (Char)(cc - &cclasses[0]); - *bufnextp = bufnext; - *patternp += len + 3; - - return 0; -} - -/* - * The main glob() routine: compiles the pattern (optionally processing - * quotes), calls glob1() to do the real pattern matching, and finally - * sorts the list (unless unsorted operation is requested). Returns 0 - * if things went well, nonzero if errors occurred. It is not an error - * to find no matches. - */ -static int -glob0(pattern, pglob) - const Char *pattern; - glob_t *pglob; -{ - const Char *qpatnext; - int c, err, oldpathc; - Char *bufnext, patbuf[PATH_MAX]; - - qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob); - oldpathc = pglob->gl_pathc; - bufnext = patbuf; - - /* We don't need to check for buffer overflow any more. */ - while ((c = *qpatnext++) != EOS) { - switch (c) { - case LBRACKET: - c = *qpatnext; - if (c == NOT) - ++qpatnext; - if (*qpatnext == EOS || - g_strchr(qpatnext+1, RBRACKET) == NULL) { - *bufnext++ = LBRACKET; - if (c == NOT) - --qpatnext; - break; - } - *bufnext++ = M_SET; - if (c == NOT) - *bufnext++ = M_NOT; - c = *qpatnext++; - do { - if (c == LBRACKET && *qpatnext == ':') { - do { - err = g_charclass(&qpatnext, - &bufnext); - if (err) - break; - c = *qpatnext++; - } while (c == LBRACKET && *qpatnext == ':'); - if (err == -1 && - !(pglob->gl_flags & GLOB_NOCHECK)) - return GLOB_NOMATCH; - if (c == RBRACKET) - break; - } - *bufnext++ = CHAR(c); - if (*qpatnext == RANGE && - (c = qpatnext[1]) != RBRACKET) { - *bufnext++ = M_RNG; - *bufnext++ = CHAR(c); - qpatnext += 2; - } - } while ((c = *qpatnext++) != RBRACKET); - pglob->gl_flags |= GLOB_MAGCHAR; - *bufnext++ = M_END; - break; - case QUESTION: - pglob->gl_flags |= GLOB_MAGCHAR; - *bufnext++ = M_ONE; - break; - case STAR: - pglob->gl_flags |= GLOB_MAGCHAR; - /* collapse adjacent stars to one, - * to avoid exponential behavior - */ - if (bufnext == patbuf || bufnext[-1] != M_ALL) - *bufnext++ = M_ALL; - break; - default: - *bufnext++ = CHAR(c); - break; - } - } - *bufnext = EOS; -#ifdef DEBUG - qprintf("glob0:", patbuf); -#endif - - if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0) - return(err); - - /* - * If there was no match we are going to append the pattern - * if GLOB_NOCHECK was specified. - */ - if (pglob->gl_pathc == oldpathc) { - if (pglob->gl_flags & GLOB_NOCHECK) - return(globextend(pattern, pglob)); - else - return(GLOB_NOMATCH); - } - if (!(pglob->gl_flags & GLOB_NOSORT)) - qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, - pglob->gl_pathc - oldpathc, sizeof(char *), compare); - return(0); -} - -static int -compare(p, q) - const void *p, *q; -{ - return(strcmp(*(char **)p, *(char **)q)); -} - -static int -glob1(pattern, pattern_last, pglob) - Char *pattern, *pattern_last; - glob_t *pglob; -{ - Char pathbuf[PATH_MAX]; - - /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ - if (*pattern == EOS) - return(0); - return(glob2(pathbuf, pathbuf + PATH_MAX - 1, - pathbuf, pathbuf + PATH_MAX - 1, - pattern, pattern_last, pglob)); -} - -/* - * The functions glob2 and glob3 are mutually recursive; there is one level - * of recursion for each segment in the pattern that contains one or more - * meta characters. - */ -static int -glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob) - Char *pathbuf, *pathbuf_last; - Char *pathend, *pathend_last; - Char *pattern, *pattern_last; - glob_t *pglob; -{ - struct stat sb; - Char *p, *q; - int anymeta; - - /* - * Loop over pattern segments until end of pattern or until - * segment with meta character found. - */ - for (anymeta = 0;;) { - if (*pattern == EOS) { /* End of pattern? */ - *pathend = EOS; - if (g_lstat(pathbuf, &sb, pglob)) - return(0); - - if (((pglob->gl_flags & GLOB_MARK) && - pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || - (S_ISLNK(sb.st_mode) && - (g_stat(pathbuf, &sb, pglob) == 0) && - S_ISDIR(sb.st_mode)))) { - if (pathend+1 > pathend_last) - return (1); - *pathend++ = SEP; - *pathend = EOS; - } - ++pglob->gl_matchc; - return(globextend(pathbuf, pglob)); - } - - /* Find end of next segment, copy tentatively to pathend. */ - q = pathend; - p = pattern; - while (*p != EOS && *p != SEP) { - if (ismeta(*p)) - anymeta = 1; - if (q+1 > pathend_last) - return (1); - *q++ = *p++; - } - - if (!anymeta) { /* No expansion, do next segment. */ - pathend = q; - pattern = p; - while (*pattern == SEP) { - if (pathend+1 > pathend_last) - return (1); - *pathend++ = *pattern++; - } - } else - /* Need expansion, recurse. */ - return(glob3(pathbuf, pathbuf_last, pathend, - pathend_last, pattern, pattern_last, - p, pattern_last, pglob)); - } - /* NOTREACHED */ -} - -static int -glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, - restpattern, restpattern_last, pglob) - Char *pathbuf, *pathbuf_last, *pathend, *pathend_last; - Char *pattern, *pattern_last, *restpattern, *restpattern_last; - glob_t *pglob; -{ - struct dirent *dp; - DIR *dirp; - int err; - char buf[PATH_MAX]; - - if (pathend > pathend_last) - return (1); - *pathend = EOS; - errno = 0; - - if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { - /* TODO: don't call for ENOENT or ENOTDIR? */ - if (pglob->gl_errfunc) { - if (g_Ctoc(pathbuf, buf, sizeof(buf))) - return(GLOB_ABORTED); - if (pglob->gl_errfunc(buf, errno) || - pglob->gl_flags & GLOB_ERR) - return(GLOB_ABORTED); - } - return(0); - } - - err = 0; - - /* Search directory for matching names. */ - while ((dp = readdir(dirp))) { - unsigned char *sc; - Char *dc; - - /* Initial DOT must be matched literally. */ - if (dp->d_name[0] == DOT && *pattern != DOT) - continue; - dc = pathend; - sc = (unsigned char *) dp->d_name; - while (dc < pathend_last && (*dc++ = *sc++) != EOS) - continue; - if (dc >= pathend_last) { - *dc = EOS; - err = 1; - break; - } - - if (!match(pathend, pattern, restpattern)) { - *pathend = EOS; - continue; - } - err = glob2(pathbuf, pathbuf_last, --dc, pathend_last, - restpattern, restpattern_last, pglob); - if (err) - break; - } - - closedir(dirp); - return(err); -} - -/* - * Extend the gl_pathv member of a glob_t structure to accommodate a new item, - * add the new item, and update gl_pathc. - * - * This assumes the BSD realloc, which only copies the block when its size - * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic - * behavior. - * - * Return 0 if new item added, error code if memory couldn't be allocated. - * - * Invariant of the glob_t structure: - * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and - * gl_pathv points to (gl_offs + gl_pathc + 1) items. - */ -static int -globextend(path, pglob) - const Char *path; - glob_t *pglob; -{ - char **pathv; - int i; - unsigned int newsize, len; - char *copy; - const Char *p; - - newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); - pathv = pglob->gl_pathv ? - (char **)realloc((char *)pglob->gl_pathv, newsize) : - (char **)malloc(newsize); - if (pathv == NULL) { - if (pglob->gl_pathv) { - free(pglob->gl_pathv); - pglob->gl_pathv = NULL; - } - return(GLOB_NOSPACE); - } - - if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { - /* first time around -- clear initial gl_offs items */ - pathv += pglob->gl_offs; - for (i = pglob->gl_offs; --i >= 0; ) - *--pathv = NULL; - } - pglob->gl_pathv = pathv; - - for (p = path; *p++;) - continue; - len = (size_t)(p - path); - if ((copy = malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { - free(copy); - return(GLOB_NOSPACE); - } - pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; - } - pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - - return(copy == NULL ? GLOB_NOSPACE : 0); -} - -/* - * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. - */ -static int -match(name, pat, patend) - Char *name, *pat, *patend; -{ - int ok, negate_range; - Char c, k; - - while (pat < patend) { - c = *pat++; - switch (c & M_MASK) { - case M_ALL: - if (pat == patend) - return(1); - do { - if (match(name, pat, patend)) - return(1); - } while (*name++ != EOS); - return(0); - case M_ONE: - if (*name++ == EOS) - return(0); - break; - case M_SET: - ok = 0; - if ((k = *name++) == EOS) - return(0); - if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) - ++pat; - while (((c = *pat++) & M_MASK) != M_END) { - if ((c & M_MASK) == M_CLASS) { - int idx = *pat & M_MASK; - if (idx < NCCLASSES && - cclasses[idx].isctype(k)) - ok = 1; - ++pat; - } - if ((*pat & M_MASK) == M_RNG) { - if (c <= k && k <= pat[1]) - ok = 1; - pat += 2; - } else if (c == k) - ok = 1; - } - if (ok == negate_range) - return(0); - break; - default: - if (*name++ != c) - return(0); - break; - } - } - return(*name == EOS); -} - -/* Free allocated data belonging to a glob_t structure. */ -void -globfree(pglob) - glob_t *pglob; -{ - int i; - char **pp; - - if (pglob->gl_pathv != NULL) { - pp = pglob->gl_pathv + pglob->gl_offs; - for (i = pglob->gl_pathc; i--; ++pp) - if (*pp) - free(*pp); - free(pglob->gl_pathv); - pglob->gl_pathv = NULL; - } -} - -static DIR * -g_opendir(str, pglob) - Char *str; - glob_t *pglob; -{ - char buf[PATH_MAX]; - - if (!*str) { - buf[0] = '.'; - buf[1] = '\0'; - } else { - if (g_Ctoc(str, buf, sizeof(buf))) - return(NULL); - } - return(opendir(buf)); -} - -static int -g_lstat(fn, sb, pglob) - Char *fn; - struct stat *sb; - glob_t *pglob; -{ - char buf[PATH_MAX]; - - if (g_Ctoc(fn, buf, sizeof(buf))) - return(-1); - return(lstat(buf, sb)); -} - -static int -g_stat(fn, sb, pglob) - Char *fn; - struct stat *sb; - glob_t *pglob; -{ - char buf[PATH_MAX]; - - if (g_Ctoc(fn, buf, sizeof(buf))) - return(-1); - return(stat(buf, sb)); -} - -static Char * -g_strchr(str, ch) - const Char *str; - int ch; -{ - do { - if (*str == ch) - return ((Char *)str); - } while (*str++); - return (NULL); -} - -static int -g_Ctoc(str, buf, len) - const Char *str; - char *buf; - unsigned int len; -{ - - while (len--) { - if ((*buf++ = *str++) == EOS) - return (0); - } - return (1); -} - -#ifdef DEBUG -static void -qprintf(str, s) - const char *str; - Char *s; -{ - Char *p; - - (void)printf("%s:\n", str); - for (p = s; *p; p++) - (void)printf("%c", CHAR(*p)); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", *p & M_PROTECT ? '"' : ' '); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", ismeta(*p) ? '_' : ' '); - (void)printf("\n"); -} -#endif diff --git a/goodpath.c b/goodpath.c deleted file mode 100644 index 1971314..0000000 --- a/goodpath.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 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. - */ - -#include - -#include -#include -#include -#include -#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 */ -#include - -#include "sudo.h" - -/* - * Verify that path is a normal file and executable by root. - */ -char * -sudo_goodpath(path, sbp) - const char *path; - struct stat *sbp; -{ - struct stat sb; - - /* Check for brain damage */ - if (path == NULL || path[0] == '\0') - return(NULL); - - if (stat(path, &sb)) - return(NULL); - - /* Make sure path describes an executable regular file. */ - if (!S_ISREG(sb.st_mode) || !(sb.st_mode & 0000111)) { - errno = EACCES; - return(NULL); - } - - if (sbp != NULL) - (void) memcpy(sbp, &sb, sizeof(struct stat)); - return((char *)path); -} diff --git a/gram.c b/gram.c deleted file mode 100644 index d2e8b46..0000000 --- a/gram.c +++ /dev/null @@ -1,1665 +0,0 @@ -#include -#include -#define YYBYACC 1 -#define YYMAJOR 1 -#define YYMINOR 9 -#define YYLEX yylex() -#define YYEMPTY -1 -#define yyclearin (yychar=(YYEMPTY)) -#define yyerrok (yyerrflag=0) -#define YYRECOVERING() (yyerrflag!=0) -#define YYPREFIX "yy" -#line 2 "gram.y" -/* - * Copyright (c) 1996, 1998-2005, 2007-2010 - * Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ - -#include - -#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(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) -# include -#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ -#include - -#include "sudo.h" -#include "parse.h" - -/* - * We must define SIZE_MAX for yacc's skeleton.c. - * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t - * could be signed (as it is on SunOS 4.x). - */ -#ifndef SIZE_MAX -# ifdef SIZE_T_MAX -# define SIZE_MAX SIZE_T_MAX -# else -# define SIZE_MAX INT_MAX -# endif /* SIZE_T_MAX */ -#endif /* SIZE_MAX */ - -/* - * Globals - */ -extern int sudolineno; -extern char *sudoers; -int parse_error; -int pedantic = FALSE; -int verbose = FALSE; -int errorlineno = -1; -char *errorfile = NULL; - -struct defaults_list defaults; -struct userspec_list userspecs; - -/* - * Local protoypes - */ -static void add_defaults __P((int, struct member *, struct defaults *)); -static void add_userspec __P((struct member *, struct privilege *)); -static struct defaults *new_default __P((char *, char *, int)); -static struct member *new_member __P((char *, int)); - void yyerror __P((const char *)); - -void -yyerror(s) - const char *s; -{ - /* Save the line the first error occurred on. */ - if (errorlineno == -1) { - errorlineno = sudolineno ? sudolineno - 1 : 0; - errorfile = estrdup(sudoers); - } - if (verbose && s != NULL) { -#ifndef TRACELEXER - (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s, - sudolineno ? sudolineno - 1 : 0); -#else - (void) fprintf(stderr, "<*> "); -#endif - } - parse_error = TRUE; -} -#line 112 "gram.y" -#ifndef YYSTYPE_DEFINED -#define YYSTYPE_DEFINED -typedef union { - struct cmndspec *cmndspec; - struct defaults *defaults; - struct member *member; - struct runascontainer *runas; - struct privilege *privilege; - struct sudo_command command; - struct cmndtag tag; - struct selinux_info seinfo; - char *string; - int tok; -} YYSTYPE; -#endif /* YYSTYPE_DEFINED */ -#line 138 "y.tab.c" -#define COMMAND 257 -#define ALIAS 258 -#define DEFVAR 259 -#define NTWKADDR 260 -#define NETGROUP 261 -#define USERGROUP 262 -#define WORD 263 -#define DEFAULTS 264 -#define DEFAULTS_HOST 265 -#define DEFAULTS_USER 266 -#define DEFAULTS_RUNAS 267 -#define DEFAULTS_CMND 268 -#define NOPASSWD 269 -#define PASSWD 270 -#define NOEXEC 271 -#define EXEC 272 -#define SETENV 273 -#define NOSETENV 274 -#define LOG_INPUT 275 -#define NOLOG_INPUT 276 -#define LOG_OUTPUT 277 -#define NOLOG_OUTPUT 278 -#define ALL 279 -#define COMMENT 280 -#define HOSTALIAS 281 -#define CMNDALIAS 282 -#define USERALIAS 283 -#define RUNASALIAS 284 -#define ERROR 285 -#define TYPE 286 -#define ROLE 287 -#define YYERRCODE 256 -#if defined(__cplusplus) || defined(__STDC__) -const short yylhs[] = -#else -short yylhs[] = -#endif - { -1, - 0, 0, 25, 25, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 4, 4, 3, 3, - 3, 3, 3, 20, 20, 19, 10, 10, 8, 8, - 8, 8, 8, 2, 2, 1, 6, 6, 23, 24, - 22, 22, 22, 22, 22, 17, 17, 18, 18, 18, - 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, - 21, 5, 5, 5, 28, 28, 31, 9, 9, 29, - 29, 32, 7, 7, 30, 30, 33, 27, 27, 34, - 13, 13, 11, 11, 12, 12, 12, 12, 12, 16, - 16, 14, 14, 15, 15, 15, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yylen[] = -#else -short yylen[] = -#endif - { 2, - 0, 1, 1, 2, 1, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 3, 3, 1, 3, 1, 2, - 3, 3, 3, 1, 3, 3, 1, 2, 1, 1, - 1, 1, 1, 1, 3, 4, 1, 2, 3, 3, - 0, 1, 1, 2, 2, 0, 3, 1, 3, 2, - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 3, 3, 1, 3, 1, - 3, 3, 1, 3, 1, 3, 3, 1, 3, 3, - 1, 3, 1, 2, 1, 1, 1, 1, 1, 1, - 3, 1, 2, 1, 1, 1, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yydefred[] = -#else -short yydefred[] = -#endif - { 0, - 0, 85, 87, 88, 89, 0, 0, 0, 0, 0, - 86, 5, 0, 0, 0, 0, 0, 0, 81, 83, - 0, 0, 3, 6, 0, 0, 17, 0, 29, 32, - 31, 33, 30, 0, 27, 0, 68, 0, 0, 64, - 63, 62, 0, 37, 73, 0, 0, 0, 65, 0, - 0, 70, 0, 0, 78, 0, 0, 75, 84, 0, - 0, 24, 0, 4, 0, 0, 0, 20, 0, 28, - 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 82, 0, 0, 21, 22, - 23, 18, 69, 74, 0, 66, 0, 71, 0, 79, - 0, 76, 0, 34, 0, 0, 25, 0, 0, 0, - 0, 0, 0, 51, 0, 0, 94, 96, 95, 0, - 90, 92, 0, 0, 47, 35, 0, 0, 0, 44, - 45, 93, 0, 0, 40, 39, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 36, 91, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yydgoto[] = -#else -short yydgoto[] = -#endif - { 18, - 104, 105, 27, 28, 44, 45, 46, 35, 61, 37, - 19, 20, 21, 121, 122, 123, 106, 110, 62, 63, - 129, 114, 115, 116, 22, 23, 54, 48, 51, 57, - 49, 52, 58, 55, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yysindex[] = -#else -short yysindex[] = -#endif - { 475, - -270, 0, 0, 0, 0, -29, 567, 594, 594, -2, - 0, 0, -240, -222, -216, -212, -241, 0, 0, 0, - -25, 475, 0, 0, -10, -207, 0, 9, 0, 0, - 0, 0, 0, -235, 0, -33, 0, -31, -31, 0, - 0, 0, -242, 0, 0, -30, -7, 3, 0, -6, - 4, 0, -5, 6, 0, -1, 8, 0, 0, 594, - -20, 0, 10, 0, -205, -196, -194, 0, -29, 0, - 567, 9, 9, 9, 0, -2, 9, 567, -240, -2, - -222, 594, -216, 594, -212, 0, 31, 567, 0, 0, - 0, 0, 0, 0, 26, 0, 28, 0, 29, 0, - 29, 0, 541, 0, 32, -247, 0, 86, -15, 33, - 31, 14, 16, 0, -208, -204, 0, 0, 0, -231, - 0, 0, 38, 86, 0, 0, -179, -178, 491, 0, - 0, 0, 86, 38, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,}; -#if defined(__cplusplus) || defined(__STDC__) -const short yyrindex[] = -#else -short yyrindex[] = -#endif - { 87, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 90, 0, 0, 1, 0, 0, 177, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 207, 0, 0, - 237, 0, 0, 271, 0, 0, 300, 0, 0, 0, - 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, - 0, 358, 387, 417, 0, 0, 446, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -26, 0, 0, 0, - 0, 0, 0, 0, 30, 0, 59, 0, 89, 0, - 118, 0, 0, 0, 148, 514, 0, 0, 45, 0, - -26, 0, 0, 0, 537, 565, 0, 0, 0, 0, - 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,}; -#if defined(__cplusplus) || defined(__STDC__) -const short yygindex[] = -#else -short yygindex[] = -#endif - { 0, - -17, 0, 27, 11, 54, -64, 15, 64, 2, 34, - 39, 84, -3, -27, -18, -21, 0, 0, 19, 0, - 0, 0, -12, -4, 0, 88, 0, 0, 0, 0, - 35, 40, 23, 37, -}; -#define YYTABLESIZE 873 -#if defined(__cplusplus) || defined(__STDC__) -const short yytable[] = -#else -short yytable[] = -#endif - { 26, - 19, 26, 26, 26, 38, 39, 46, 34, 36, 24, - 71, 94, 60, 76, 40, 41, 2, 47, 60, 3, - 4, 5, 29, 71, 30, 31, 117, 32, 60, 67, - 43, 118, 66, 19, 67, 50, 42, 11, 112, 113, - 87, 53, 124, 33, 19, 56, 72, 119, 73, 74, - 65, 68, 69, 78, 80, 82, 77, 89, 72, 84, - 79, 81, 67, 83, 147, 85, 90, 88, 91, 71, - 103, 76, 60, 125, 127, 111, 128, 112, 99, 95, - 101, 133, 113, 135, 136, 48, 1, 67, 80, 2, - 50, 72, 49, 126, 97, 92, 75, 70, 86, 109, - 59, 132, 134, 131, 93, 148, 107, 102, 0, 64, - 130, 0, 0, 96, 0, 0, 72, 77, 120, 100, - 98, 80, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 80, 26, 0, 0, - 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 77, 12, 0, 0, 0, - 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 26, 9, 0, 0, 12, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 25, 0, 25, 25, 25, - 46, 46, 29, 0, 30, 31, 10, 32, 0, 9, - 0, 0, 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 33, 40, 41, 19, 0, 19, 46, - 46, 19, 19, 19, 19, 19, 19, 19, 19, 10, - 8, 0, 0, 0, 0, 0, 42, 0, 0, 19, - 19, 19, 19, 19, 19, 67, 0, 67, 0, 0, - 67, 67, 67, 67, 67, 67, 67, 67, 0, 11, - 0, 0, 0, 8, 0, 0, 0, 0, 67, 67, - 67, 67, 67, 67, 72, 0, 72, 0, 0, 72, - 72, 72, 72, 72, 72, 72, 72, 0, 7, 0, - 0, 0, 11, 0, 0, 0, 0, 72, 72, 72, - 72, 72, 72, 117, 80, 0, 80, 0, 118, 80, - 80, 80, 80, 80, 80, 80, 80, 15, 0, 0, - 0, 7, 0, 0, 119, 0, 0, 80, 80, 80, - 80, 80, 80, 77, 0, 77, 0, 0, 77, 77, - 77, 77, 77, 77, 77, 77, 13, 0, 0, 0, - 15, 0, 0, 0, 0, 0, 77, 77, 77, 77, - 77, 77, 0, 26, 0, 26, 0, 0, 26, 26, - 26, 26, 26, 26, 26, 26, 14, 0, 0, 13, - 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, - 26, 26, 12, 0, 12, 0, 0, 12, 12, 12, - 12, 12, 12, 12, 12, 16, 0, 0, 0, 14, - 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, - 12, 0, 9, 0, 9, 0, 0, 9, 9, 9, - 9, 9, 9, 9, 9, 0, 0, 0, 16, 0, - 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, - 9, 0, 10, 0, 10, 0, 0, 10, 10, 10, - 10, 10, 10, 10, 10, 0, 0, 17, 0, 0, - 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, - 10, 0, 0, 43, 0, 0, 8, 0, 8, 0, - 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, - 0, 0, 0, 0, 0, 0, 41, 0, 0, 8, - 8, 8, 8, 8, 8, 11, 0, 11, 0, 0, - 11, 11, 11, 11, 11, 11, 11, 11, 0, 42, - 0, 0, 0, 17, 0, 0, 0, 0, 11, 11, - 11, 11, 11, 11, 7, 0, 7, 0, 0, 7, - 7, 7, 7, 7, 7, 7, 7, 43, 108, 34, - 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, - 7, 7, 7, 15, 0, 15, 0, 0, 15, 15, - 15, 15, 15, 15, 15, 15, 17, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, - 15, 15, 13, 0, 13, 0, 0, 13, 13, 13, - 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, - 13, 0, 14, 0, 14, 0, 0, 14, 14, 14, - 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, - 14, 16, 0, 16, 0, 0, 16, 16, 16, 16, - 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, - 1, 0, 2, 0, 0, 3, 4, 5, 6, 7, - 8, 9, 10, 0, 0, 0, 0, 40, 41, 0, - 0, 0, 0, 11, 12, 13, 14, 15, 16, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 42, - 41, 41, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 41, 41, 41, 41, 41, 41, 41, 41, - 41, 41, 41, 42, 42, 0, 0, 0, 2, 0, - 0, 3, 4, 5, 0, 42, 42, 42, 42, 42, - 42, 42, 42, 42, 42, 42, 0, 0, 0, 11, - 0, 43, 43, 0, 29, 0, 30, 31, 0, 32, - 0, 0, 0, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 43, 0, 33, 0, 0, 0, 0, - 0, 2, 0, 0, 3, 4, 5, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 11, -}; -#if defined(__cplusplus) || defined(__STDC__) -const short yycheck[] = -#else -short yycheck[] = -#endif - { 33, - 0, 33, 33, 33, 8, 9, 33, 33, 7, 280, - 44, 76, 44, 44, 257, 258, 258, 258, 44, 261, - 262, 263, 258, 44, 260, 261, 258, 263, 44, 0, - 33, 263, 43, 33, 45, 258, 279, 279, 286, 287, - 61, 258, 58, 279, 44, 258, 36, 279, 38, 39, - 61, 259, 44, 61, 61, 61, 46, 263, 0, 61, - 58, 58, 33, 58, 129, 58, 263, 58, 263, 44, - 40, 44, 44, 41, 61, 44, 61, 286, 82, 78, - 84, 44, 287, 263, 263, 41, 0, 58, 0, 0, - 41, 33, 41, 111, 80, 69, 43, 34, 60, 103, - 17, 120, 124, 116, 71, 133, 88, 85, -1, 22, - 115, -1, -1, 79, -1, -1, 58, 0, 33, 83, - 81, 33, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 58, 0, -1, -1, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 58, 0, -1, -1, -1, - 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 58, 0, -1, -1, 33, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 259, -1, 259, 259, 259, - 257, 258, 258, -1, 260, 261, 0, 263, -1, 33, - -1, -1, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 279, 257, 258, 256, -1, 258, 286, - 287, 261, 262, 263, 264, 265, 266, 267, 268, 33, - 0, -1, -1, -1, -1, -1, 279, -1, -1, 279, - 280, 281, 282, 283, 284, 256, -1, 258, -1, -1, - 261, 262, 263, 264, 265, 266, 267, 268, -1, 0, - -1, -1, -1, 33, -1, -1, -1, -1, 279, 280, - 281, 282, 283, 284, 256, -1, 258, -1, -1, 261, - 262, 263, 264, 265, 266, 267, 268, -1, 0, -1, - -1, -1, 33, -1, -1, -1, -1, 279, 280, 281, - 282, 283, 284, 258, 256, -1, 258, -1, 263, 261, - 262, 263, 264, 265, 266, 267, 268, 0, -1, -1, - -1, 33, -1, -1, 279, -1, -1, 279, 280, 281, - 282, 283, 284, 256, -1, 258, -1, -1, 261, 262, - 263, 264, 265, 266, 267, 268, 0, -1, -1, -1, - 33, -1, -1, -1, -1, -1, 279, 280, 281, 282, - 283, 284, -1, 256, -1, 258, -1, -1, 261, 262, - 263, 264, 265, 266, 267, 268, 0, -1, -1, 33, - -1, -1, -1, -1, -1, -1, 279, 280, 281, 282, - 283, 284, 256, -1, 258, -1, -1, 261, 262, 263, - 264, 265, 266, 267, 268, 0, -1, -1, -1, 33, - -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, - 284, -1, 256, -1, 258, -1, -1, 261, 262, 263, - 264, 265, 266, 267, 268, -1, -1, -1, 33, -1, - -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, - 284, -1, 256, -1, 258, -1, -1, 261, 262, 263, - 264, 265, 266, 267, 268, -1, -1, 33, -1, -1, - -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, - 284, -1, -1, 33, -1, -1, 256, -1, 258, -1, - -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, - -1, -1, -1, -1, -1, -1, 33, -1, -1, 279, - 280, 281, 282, 283, 284, 256, -1, 258, -1, -1, - 261, 262, 263, 264, 265, 266, 267, 268, -1, 33, - -1, -1, -1, 33, -1, -1, -1, -1, 279, 280, - 281, 282, 283, 284, 256, -1, 258, -1, -1, 261, - 262, 263, 264, 265, 266, 267, 268, 33, 58, 33, - -1, -1, -1, -1, -1, -1, -1, 279, 280, 281, - 282, 283, 284, 256, -1, 258, -1, -1, 261, 262, - 263, 264, 265, 266, 267, 268, 33, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 279, 280, 281, 282, - 283, 284, 256, -1, 258, -1, -1, 261, 262, 263, - 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, - 284, -1, 256, -1, 258, -1, -1, 261, 262, 263, - 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, - 284, 256, -1, 258, -1, -1, 261, 262, 263, 264, - 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 279, 280, 281, 282, 283, 284, - 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, - 266, 267, 268, -1, -1, -1, -1, 257, 258, -1, - -1, -1, -1, 279, 280, 281, 282, 283, 284, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 257, 258, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 257, 258, -1, -1, -1, 258, -1, - -1, 261, 262, 263, -1, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, -1, -1, -1, 279, - -1, 257, 258, -1, 258, -1, 260, 261, -1, 263, - -1, -1, -1, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, -1, 279, -1, -1, -1, -1, - -1, 258, -1, -1, 261, 262, 263, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 279, -}; -#define YYFINAL 18 -#ifndef YYDEBUG -#define YYDEBUG 0 -#endif -#define YYMAXTOKEN 287 -#if YYDEBUG -#if defined(__cplusplus) || defined(__STDC__) -const char * const yyname[] = -#else -char *yyname[] = -#endif - { -"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -"'!'",0,0,0,0,0,0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,"':'", -0,0,"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS", -"DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND","NOPASSWD", -"PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","LOG_INPUT","NOLOG_INPUT", -"LOG_OUTPUT","NOLOG_OUTPUT","ALL","COMMENT","HOSTALIAS","CMNDALIAS","USERALIAS", -"RUNASALIAS","ERROR","TYPE","ROLE", -}; -#if defined(__cplusplus) || defined(__STDC__) -const char * const yyrule[] = -#else -char *yyrule[] = -#endif - {"$accept : file", -"file :", -"file : line", -"line : entry", -"line : line entry", -"entry : COMMENT", -"entry : error COMMENT", -"entry : userlist privileges", -"entry : USERALIAS useraliases", -"entry : HOSTALIAS hostaliases", -"entry : CMNDALIAS cmndaliases", -"entry : RUNASALIAS runasaliases", -"entry : DEFAULTS defaults_list", -"entry : DEFAULTS_USER userlist defaults_list", -"entry : DEFAULTS_RUNAS userlist defaults_list", -"entry : DEFAULTS_HOST hostlist defaults_list", -"entry : DEFAULTS_CMND cmndlist defaults_list", -"defaults_list : defaults_entry", -"defaults_list : defaults_list ',' defaults_entry", -"defaults_entry : DEFVAR", -"defaults_entry : '!' DEFVAR", -"defaults_entry : DEFVAR '=' WORD", -"defaults_entry : DEFVAR '+' WORD", -"defaults_entry : DEFVAR '-' WORD", -"privileges : privilege", -"privileges : privileges ':' privilege", -"privilege : hostlist '=' cmndspeclist", -"ophost : host", -"ophost : '!' host", -"host : ALIAS", -"host : ALL", -"host : NETGROUP", -"host : NTWKADDR", -"host : WORD", -"cmndspeclist : cmndspec", -"cmndspeclist : cmndspeclist ',' cmndspec", -"cmndspec : runasspec selinux cmndtag opcmnd", -"opcmnd : cmnd", -"opcmnd : '!' cmnd", -"rolespec : ROLE '=' WORD", -"typespec : TYPE '=' WORD", -"selinux :", -"selinux : rolespec", -"selinux : typespec", -"selinux : rolespec typespec", -"selinux : typespec rolespec", -"runasspec :", -"runasspec : '(' runaslist ')'", -"runaslist : userlist", -"runaslist : userlist ':' grouplist", -"runaslist : ':' grouplist", -"cmndtag :", -"cmndtag : cmndtag NOPASSWD", -"cmndtag : cmndtag PASSWD", -"cmndtag : cmndtag NOEXEC", -"cmndtag : cmndtag EXEC", -"cmndtag : cmndtag SETENV", -"cmndtag : cmndtag NOSETENV", -"cmndtag : cmndtag LOG_INPUT", -"cmndtag : cmndtag NOLOG_INPUT", -"cmndtag : cmndtag LOG_OUTPUT", -"cmndtag : cmndtag NOLOG_OUTPUT", -"cmnd : ALL", -"cmnd : ALIAS", -"cmnd : COMMAND", -"hostaliases : hostalias", -"hostaliases : hostaliases ':' hostalias", -"hostalias : ALIAS '=' hostlist", -"hostlist : ophost", -"hostlist : hostlist ',' ophost", -"cmndaliases : cmndalias", -"cmndaliases : cmndaliases ':' cmndalias", -"cmndalias : ALIAS '=' cmndlist", -"cmndlist : opcmnd", -"cmndlist : cmndlist ',' opcmnd", -"runasaliases : runasalias", -"runasaliases : runasaliases ':' runasalias", -"runasalias : ALIAS '=' userlist", -"useraliases : useralias", -"useraliases : useraliases ':' useralias", -"useralias : ALIAS '=' userlist", -"userlist : opuser", -"userlist : userlist ',' opuser", -"opuser : user", -"opuser : '!' user", -"user : ALIAS", -"user : ALL", -"user : NETGROUP", -"user : USERGROUP", -"user : WORD", -"grouplist : opgroup", -"grouplist : grouplist ',' opgroup", -"opgroup : group", -"opgroup : '!' group", -"group : ALIAS", -"group : ALL", -"group : WORD", -}; -#endif -#ifdef YYSTACKSIZE -#undef YYMAXDEPTH -#define YYMAXDEPTH YYSTACKSIZE -#else -#ifdef YYMAXDEPTH -#define YYSTACKSIZE YYMAXDEPTH -#else -#define YYSTACKSIZE 10000 -#define YYMAXDEPTH 10000 -#endif -#endif -#define YYINITSTACKSIZE 200 -/* LINTUSED */ -int yydebug; -int yynerrs; -int yyerrflag; -int yychar; -short *yyssp; -YYSTYPE *yyvsp; -YYSTYPE yyval; -YYSTYPE yylval; -short *yyss; -short *yysslim; -YYSTYPE *yyvs; -int yystacksize; -#line 606 "gram.y" -static struct defaults * -new_default(var, val, op) - char *var; - char *val; - int op; -{ - struct defaults *d; - - d = emalloc(sizeof(struct defaults)); - d->var = var; - d->val = val; - tq_init(&d->binding); - d->type = 0; - d->op = op; - d->prev = d; - d->next = NULL; - - return(d); -} - -static struct member * -new_member(name, type) - char *name; - int type; -{ - struct member *m; - - m = emalloc(sizeof(struct member)); - m->name = name; - m->type = type; - m->prev = m; - m->next = NULL; - - return(m); -} - -/* - * Add a list of defaults structures to the defaults list. - * The binding, if non-NULL, specifies a list of hosts, users, or - * runas users the entries apply to (specified by the type). - */ -static void -add_defaults(type, bmem, defs) - int type; - struct member *bmem; - struct defaults *defs; -{ - struct defaults *d; - struct member_list binding; - - /* - * We can only call list2tq once on bmem as it will zero - * out the prev pointer when it consumes bmem. - */ - list2tq(&binding, bmem); - - /* - * Set type and binding (who it applies to) for new entries. - */ - for (d = defs; d != NULL; d = d->next) { - d->type = type; - d->binding = binding; - } - tq_append(&defaults, defs); -} - -/* - * Allocate a new struct userspec, populate it, and insert it at the - * and of the userspecs list. - */ -static void -add_userspec(members, privs) - struct member *members; - struct privilege *privs; -{ - struct userspec *u; - - u = emalloc(sizeof(*u)); - list2tq(&u->users, members); - list2tq(&u->privileges, privs); - u->prev = u; - u->next = NULL; - tq_append(&userspecs, u); -} - -/* - * Free up space used by data structures from a previous parser run and sets - * the current sudoers file to path. - */ -void -init_parser(path, quiet) - char *path; - int quiet; -{ - struct defaults *d; - struct member *m, *binding; - struct userspec *us; - struct privilege *priv; - struct cmndspec *cs; - struct sudo_command *c; - - while ((us = tq_pop(&userspecs)) != NULL) { - while ((m = tq_pop(&us->users)) != NULL) { - efree(m->name); - efree(m); - } - while ((priv = tq_pop(&us->privileges)) != NULL) { - struct member *runasuser = NULL, *runasgroup = NULL; -#ifdef HAVE_SELINUX - char *role = NULL, *type = NULL; -#endif /* HAVE_SELINUX */ - - while ((m = tq_pop(&priv->hostlist)) != NULL) { - efree(m->name); - efree(m); - } - while ((cs = tq_pop(&priv->cmndlist)) != NULL) { -#ifdef HAVE_SELINUX - /* Only free the first instance of a role/type. */ - if (cs->role != role) { - role = cs->role; - efree(cs->role); - } - if (cs->type != type) { - type = cs->type; - efree(cs->type); - } -#endif /* HAVE_SELINUX */ - if (tq_last(&cs->runasuserlist) != runasuser) { - runasuser = tq_last(&cs->runasuserlist); - while ((m = tq_pop(&cs->runasuserlist)) != NULL) { - efree(m->name); - efree(m); - } - } - if (tq_last(&cs->runasgrouplist) != runasgroup) { - runasgroup = tq_last(&cs->runasgrouplist); - while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { - efree(m->name); - efree(m); - } - } - if (cs->cmnd->type == COMMAND) { - c = (struct sudo_command *) cs->cmnd->name; - efree(c->cmnd); - efree(c->args); - } - efree(cs->cmnd->name); - efree(cs->cmnd); - efree(cs); - } - efree(priv); - } - efree(us); - } - tq_init(&userspecs); - - binding = NULL; - while ((d = tq_pop(&defaults)) != NULL) { - if (tq_last(&d->binding) != binding) { - binding = tq_last(&d->binding); - while ((m = tq_pop(&d->binding)) != NULL) { - if (m->type == COMMAND) { - c = (struct sudo_command *) m->name; - efree(c->cmnd); - efree(c->args); - } - efree(m->name); - efree(m); - } - } - efree(d->var); - efree(d->val); - efree(d); - } - tq_init(&defaults); - - init_aliases(); - - init_lexer(); - - efree(sudoers); - sudoers = path ? estrdup(path) : NULL; - - parse_error = FALSE; - errorlineno = -1; - errorfile = NULL; - sudolineno = 1; - verbose = !quiet; -} -#line 775 "y.tab.c" -/* allocate initial stack or double stack size, up to YYMAXDEPTH */ -#if defined(__cplusplus) || defined(__STDC__) -static int yygrowstack(void) -#else -static int yygrowstack() -#endif -{ - int newsize, i; - short *newss; - YYSTYPE *newvs; - - if ((newsize = yystacksize) == 0) - newsize = YYINITSTACKSIZE; - else if (newsize >= YYMAXDEPTH) - return -1; - else if ((newsize *= 2) > YYMAXDEPTH) - newsize = YYMAXDEPTH; - i = yyssp - yyss; -#ifdef SIZE_MAX -#define YY_SIZE_MAX SIZE_MAX -#else -#define YY_SIZE_MAX 0x7fffffff -#endif - if (newsize && YY_SIZE_MAX / newsize < sizeof *newss) - goto bail; - newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : - (short *)malloc(newsize * sizeof *newss); /* overflow check above */ - if (newss == NULL) - goto bail; - yyss = newss; - yyssp = newss + i; - if (newsize && YY_SIZE_MAX / newsize < sizeof *newvs) - goto bail; - newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : - (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */ - if (newvs == NULL) - goto bail; - yyvs = newvs; - yyvsp = newvs + i; - yystacksize = newsize; - yysslim = yyss + newsize - 1; - return 0; -bail: - if (yyss) - free(yyss); - if (yyvs) - free(yyvs); - yyss = yyssp = NULL; - yyvs = yyvsp = NULL; - yystacksize = 0; - return -1; -} - -#define YYABORT goto yyabort -#define YYREJECT goto yyabort -#define YYACCEPT goto yyaccept -#define YYERROR goto yyerrlab -int -#if defined(__cplusplus) || defined(__STDC__) -yyparse(void) -#else -yyparse() -#endif -{ - int yym, yyn, yystate; -#if YYDEBUG -#if defined(__cplusplus) || defined(__STDC__) - const char *yys; -#else /* !(defined(__cplusplus) || defined(__STDC__)) */ - char *yys; -#endif /* !(defined(__cplusplus) || defined(__STDC__)) */ - - if ((yys = getenv("YYDEBUG"))) - { - yyn = *yys; - if (yyn >= '0' && yyn <= '9') - yydebug = yyn - '0'; - } -#endif /* YYDEBUG */ - - yynerrs = 0; - yyerrflag = 0; - yychar = (-1); - - if (yyss == NULL && yygrowstack()) goto yyoverflow; - yyssp = yyss; - yyvsp = yyvs; - *yyssp = yystate = 0; - -yyloop: - if ((yyn = yydefred[yystate]) != 0) goto yyreduce; - if (yychar < 0) - { - if ((yychar = yylex()) < 0) yychar = 0; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - } - if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, shifting to state %d\n", - YYPREFIX, yystate, yytable[yyn]); -#endif - if (yyssp >= yysslim && yygrowstack()) - { - goto yyoverflow; - } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; - yychar = (-1); - if (yyerrflag > 0) --yyerrflag; - goto yyloop; - } - if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yychar) - { - yyn = yytable[yyn]; - goto yyreduce; - } - if (yyerrflag) goto yyinrecovery; -#if defined(lint) || defined(__GNUC__) - goto yynewerror; -#endif -yynewerror: - yyerror("syntax error"); -#if defined(lint) || defined(__GNUC__) - goto yyerrlab; -#endif -yyerrlab: - ++yynerrs; -yyinrecovery: - if (yyerrflag < 3) - { - yyerrflag = 3; - for (;;) - { - if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, error recovery shifting\ - to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); -#endif - if (yyssp >= yysslim && yygrowstack()) - { - goto yyoverflow; - } - *++yyssp = yystate = yytable[yyn]; - *++yyvsp = yylval; - goto yyloop; - } - else - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: error recovery discarding state %d\n", - YYPREFIX, *yyssp); -#endif - if (yyssp <= yyss) goto yyabort; - --yyssp; - --yyvsp; - } - } - } - else - { - if (yychar == 0) goto yyabort; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, error recovery discards token %d (%s)\n", - YYPREFIX, yystate, yychar, yys); - } -#endif - yychar = (-1); - goto yyloop; - } -yyreduce: -#if YYDEBUG - if (yydebug) - printf("%sdebug: state %d, reducing by rule %d (%s)\n", - YYPREFIX, yystate, yyn, yyrule[yyn]); -#endif - yym = yylen[yyn]; - if (yym) - yyval = yyvsp[1-yym]; - else - memset(&yyval, 0, sizeof yyval); - switch (yyn) - { -case 1: -#line 187 "gram.y" -{ ; } -break; -case 5: -#line 195 "gram.y" -{ - ; - } -break; -case 6: -#line 198 "gram.y" -{ - yyerrok; - } -break; -case 7: -#line 201 "gram.y" -{ - add_userspec(yyvsp[-1].member, yyvsp[0].privilege); - } -break; -case 8: -#line 204 "gram.y" -{ - ; - } -break; -case 9: -#line 207 "gram.y" -{ - ; - } -break; -case 10: -#line 210 "gram.y" -{ - ; - } -break; -case 11: -#line 213 "gram.y" -{ - ; - } -break; -case 12: -#line 216 "gram.y" -{ - add_defaults(DEFAULTS, NULL, yyvsp[0].defaults); - } -break; -case 13: -#line 219 "gram.y" -{ - add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults); - } -break; -case 14: -#line 222 "gram.y" -{ - add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults); - } -break; -case 15: -#line 225 "gram.y" -{ - add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults); - } -break; -case 16: -#line 228 "gram.y" -{ - add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults); - } -break; -case 18: -#line 234 "gram.y" -{ - list_append(yyvsp[-2].defaults, yyvsp[0].defaults); - yyval.defaults = yyvsp[-2].defaults; - } -break; -case 19: -#line 240 "gram.y" -{ - yyval.defaults = new_default(yyvsp[0].string, NULL, TRUE); - } -break; -case 20: -#line 243 "gram.y" -{ - yyval.defaults = new_default(yyvsp[0].string, NULL, FALSE); - } -break; -case 21: -#line 246 "gram.y" -{ - yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, TRUE); - } -break; -case 22: -#line 249 "gram.y" -{ - yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); - } -break; -case 23: -#line 252 "gram.y" -{ - yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); - } -break; -case 25: -#line 258 "gram.y" -{ - list_append(yyvsp[-2].privilege, yyvsp[0].privilege); - yyval.privilege = yyvsp[-2].privilege; - } -break; -case 26: -#line 264 "gram.y" -{ - struct privilege *p = emalloc(sizeof(*p)); - list2tq(&p->hostlist, yyvsp[-2].member); - list2tq(&p->cmndlist, yyvsp[0].cmndspec); - p->prev = p; - p->next = NULL; - yyval.privilege = p; - } -break; -case 27: -#line 274 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = FALSE; - } -break; -case 28: -#line 278 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = TRUE; - } -break; -case 29: -#line 284 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, ALIAS); - } -break; -case 30: -#line 287 "gram.y" -{ - yyval.member = new_member(NULL, ALL); - } -break; -case 31: -#line 290 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, NETGROUP); - } -break; -case 32: -#line 293 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, NTWKADDR); - } -break; -case 33: -#line 296 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, WORD); - } -break; -case 35: -#line 302 "gram.y" -{ - list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec); -#ifdef HAVE_SELINUX - /* propagate role and type */ - if (yyvsp[0].cmndspec->role == NULL) - yyvsp[0].cmndspec->role = yyvsp[0].cmndspec->prev->role; - if (yyvsp[0].cmndspec->type == NULL) - yyvsp[0].cmndspec->type = yyvsp[0].cmndspec->prev->type; -#endif /* HAVE_SELINUX */ - /* propagate tags and runas list */ - if (yyvsp[0].cmndspec->tags.nopasswd == UNSPEC) - yyvsp[0].cmndspec->tags.nopasswd = yyvsp[0].cmndspec->prev->tags.nopasswd; - if (yyvsp[0].cmndspec->tags.noexec == UNSPEC) - yyvsp[0].cmndspec->tags.noexec = yyvsp[0].cmndspec->prev->tags.noexec; - if (yyvsp[0].cmndspec->tags.setenv == UNSPEC && - yyvsp[0].cmndspec->prev->tags.setenv != IMPLIED) - yyvsp[0].cmndspec->tags.setenv = yyvsp[0].cmndspec->prev->tags.setenv; - if (yyvsp[0].cmndspec->tags.log_input == UNSPEC) - yyvsp[0].cmndspec->tags.log_input = yyvsp[0].cmndspec->prev->tags.log_input; - if (yyvsp[0].cmndspec->tags.log_output == UNSPEC) - yyvsp[0].cmndspec->tags.log_output = yyvsp[0].cmndspec->prev->tags.log_output; - if ((tq_empty(&yyvsp[0].cmndspec->runasuserlist) && - tq_empty(&yyvsp[0].cmndspec->runasgrouplist)) && - (!tq_empty(&yyvsp[0].cmndspec->prev->runasuserlist) || - !tq_empty(&yyvsp[0].cmndspec->prev->runasgrouplist))) { - yyvsp[0].cmndspec->runasuserlist = yyvsp[0].cmndspec->prev->runasuserlist; - yyvsp[0].cmndspec->runasgrouplist = yyvsp[0].cmndspec->prev->runasgrouplist; - } - yyval.cmndspec = yyvsp[-2].cmndspec; - } -break; -case 36: -#line 334 "gram.y" -{ - struct cmndspec *cs = emalloc(sizeof(*cs)); - if (yyvsp[-3].runas != NULL) { - list2tq(&cs->runasuserlist, yyvsp[-3].runas->runasusers); - list2tq(&cs->runasgrouplist, yyvsp[-3].runas->runasgroups); - efree(yyvsp[-3].runas); - } else { - tq_init(&cs->runasuserlist); - tq_init(&cs->runasgrouplist); - } -#ifdef HAVE_SELINUX - cs->role = yyvsp[-2].seinfo.role; - cs->type = yyvsp[-2].seinfo.type; -#endif - cs->tags = yyvsp[-1].tag; - cs->cmnd = yyvsp[0].member; - cs->prev = cs; - cs->next = NULL; - /* sudo "ALL" implies the SETENV tag */ - if (cs->cmnd->type == ALL && !cs->cmnd->negated && - cs->tags.setenv == UNSPEC) - cs->tags.setenv = IMPLIED; - yyval.cmndspec = cs; - } -break; -case 37: -#line 360 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = FALSE; - } -break; -case 38: -#line 364 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = TRUE; - } -break; -case 39: -#line 370 "gram.y" -{ - yyval.string = yyvsp[0].string; - } -break; -case 40: -#line 375 "gram.y" -{ - yyval.string = yyvsp[0].string; - } -break; -case 41: -#line 380 "gram.y" -{ - yyval.seinfo.role = NULL; - yyval.seinfo.type = NULL; - } -break; -case 42: -#line 384 "gram.y" -{ - yyval.seinfo.role = yyvsp[0].string; - yyval.seinfo.type = NULL; - } -break; -case 43: -#line 388 "gram.y" -{ - yyval.seinfo.type = yyvsp[0].string; - yyval.seinfo.role = NULL; - } -break; -case 44: -#line 392 "gram.y" -{ - yyval.seinfo.role = yyvsp[-1].string; - yyval.seinfo.type = yyvsp[0].string; - } -break; -case 45: -#line 396 "gram.y" -{ - yyval.seinfo.type = yyvsp[-1].string; - yyval.seinfo.role = yyvsp[0].string; - } -break; -case 46: -#line 402 "gram.y" -{ - yyval.runas = NULL; - } -break; -case 47: -#line 405 "gram.y" -{ - yyval.runas = yyvsp[-1].runas; - } -break; -case 48: -#line 410 "gram.y" -{ - yyval.runas = emalloc(sizeof(struct runascontainer)); - yyval.runas->runasusers = yyvsp[0].member; - yyval.runas->runasgroups = NULL; - } -break; -case 49: -#line 415 "gram.y" -{ - yyval.runas = emalloc(sizeof(struct runascontainer)); - yyval.runas->runasusers = yyvsp[-2].member; - yyval.runas->runasgroups = yyvsp[0].member; - } -break; -case 50: -#line 420 "gram.y" -{ - yyval.runas = emalloc(sizeof(struct runascontainer)); - yyval.runas->runasusers = NULL; - yyval.runas->runasgroups = yyvsp[0].member; - } -break; -case 51: -#line 427 "gram.y" -{ - yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = - yyval.tag.log_input = yyval.tag.log_output = UNSPEC; - } -break; -case 52: -#line 431 "gram.y" -{ - yyval.tag.nopasswd = TRUE; - } -break; -case 53: -#line 434 "gram.y" -{ - yyval.tag.nopasswd = FALSE; - } -break; -case 54: -#line 437 "gram.y" -{ - yyval.tag.noexec = TRUE; - } -break; -case 55: -#line 440 "gram.y" -{ - yyval.tag.noexec = FALSE; - } -break; -case 56: -#line 443 "gram.y" -{ - yyval.tag.setenv = TRUE; - } -break; -case 57: -#line 446 "gram.y" -{ - yyval.tag.setenv = FALSE; - } -break; -case 58: -#line 449 "gram.y" -{ - yyval.tag.log_input = TRUE; - } -break; -case 59: -#line 452 "gram.y" -{ - yyval.tag.log_input = FALSE; - } -break; -case 60: -#line 455 "gram.y" -{ - yyval.tag.log_output = TRUE; - } -break; -case 61: -#line 458 "gram.y" -{ - yyval.tag.log_output = FALSE; - } -break; -case 62: -#line 463 "gram.y" -{ - yyval.member = new_member(NULL, ALL); - } -break; -case 63: -#line 466 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, ALIAS); - } -break; -case 64: -#line 469 "gram.y" -{ - struct sudo_command *c = emalloc(sizeof(*c)); - c->cmnd = yyvsp[0].command.cmnd; - c->args = yyvsp[0].command.args; - yyval.member = new_member((char *)c, COMMAND); - } -break; -case 67: -#line 481 "gram.y" -{ - char *s; - if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) { - yyerror(s); - YYERROR; - } - } -break; -case 69: -#line 491 "gram.y" -{ - list_append(yyvsp[-2].member, yyvsp[0].member); - yyval.member = yyvsp[-2].member; - } -break; -case 72: -#line 501 "gram.y" -{ - char *s; - if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) { - yyerror(s); - YYERROR; - } - } -break; -case 74: -#line 511 "gram.y" -{ - list_append(yyvsp[-2].member, yyvsp[0].member); - yyval.member = yyvsp[-2].member; - } -break; -case 77: -#line 521 "gram.y" -{ - char *s; - if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) { - yyerror(s); - YYERROR; - } - } -break; -case 80: -#line 534 "gram.y" -{ - char *s; - if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) { - yyerror(s); - YYERROR; - } - } -break; -case 82: -#line 544 "gram.y" -{ - list_append(yyvsp[-2].member, yyvsp[0].member); - yyval.member = yyvsp[-2].member; - } -break; -case 83: -#line 550 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = FALSE; - } -break; -case 84: -#line 554 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = TRUE; - } -break; -case 85: -#line 560 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, ALIAS); - } -break; -case 86: -#line 563 "gram.y" -{ - yyval.member = new_member(NULL, ALL); - } -break; -case 87: -#line 566 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, NETGROUP); - } -break; -case 88: -#line 569 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, USERGROUP); - } -break; -case 89: -#line 572 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, WORD); - } -break; -case 91: -#line 578 "gram.y" -{ - list_append(yyvsp[-2].member, yyvsp[0].member); - yyval.member = yyvsp[-2].member; - } -break; -case 92: -#line 584 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = FALSE; - } -break; -case 93: -#line 588 "gram.y" -{ - yyval.member = yyvsp[0].member; - yyval.member->negated = TRUE; - } -break; -case 94: -#line 594 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, ALIAS); - } -break; -case 95: -#line 597 "gram.y" -{ - yyval.member = new_member(NULL, ALL); - } -break; -case 96: -#line 600 "gram.y" -{ - yyval.member = new_member(yyvsp[0].string, WORD); - } -break; -#line 1544 "y.tab.c" - } - yyssp -= yym; - yystate = *yyssp; - yyvsp -= yym; - yym = yylhs[yyn]; - if (yystate == 0 && yym == 0) - { -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state 0 to\ - state %d\n", YYPREFIX, YYFINAL); -#endif - yystate = YYFINAL; - *++yyssp = YYFINAL; - *++yyvsp = yyval; - if (yychar < 0) - { - if ((yychar = yylex()) < 0) yychar = 0; -#if YYDEBUG - if (yydebug) - { - yys = 0; - if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; - if (!yys) yys = "illegal-symbol"; - printf("%sdebug: state %d, reading %d (%s)\n", - YYPREFIX, YYFINAL, yychar, yys); - } -#endif - } - if (yychar == 0) goto yyaccept; - goto yyloop; - } - if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && - yyn <= YYTABLESIZE && yycheck[yyn] == yystate) - yystate = yytable[yyn]; - else - yystate = yydgoto[yym]; -#if YYDEBUG - if (yydebug) - printf("%sdebug: after reduction, shifting from state %d \ -to state %d\n", YYPREFIX, *yyssp, yystate); -#endif - if (yyssp >= yysslim && yygrowstack()) - { - goto yyoverflow; - } - *++yyssp = yystate; - *++yyvsp = yyval; - goto yyloop; -yyoverflow: - yyerror("yacc stack overflow"); -yyabort: - if (yyss) - free(yyss); - if (yyvs) - free(yyvs); - yyss = yyssp = NULL; - yyvs = yyvsp = NULL; - yystacksize = 0; - return (1); -yyaccept: - if (yyss) - free(yyss); - if (yyvs) - free(yyvs); - yyss = yyssp = NULL; - yyvs = yyvsp = NULL; - yystacksize = 0; - return (0); -} diff --git a/gram.h b/gram.h deleted file mode 100644 index 2bec420..0000000 --- a/gram.h +++ /dev/null @@ -1,47 +0,0 @@ -#define COMMAND 257 -#define ALIAS 258 -#define DEFVAR 259 -#define NTWKADDR 260 -#define NETGROUP 261 -#define USERGROUP 262 -#define WORD 263 -#define DEFAULTS 264 -#define DEFAULTS_HOST 265 -#define DEFAULTS_USER 266 -#define DEFAULTS_RUNAS 267 -#define DEFAULTS_CMND 268 -#define NOPASSWD 269 -#define PASSWD 270 -#define NOEXEC 271 -#define EXEC 272 -#define SETENV 273 -#define NOSETENV 274 -#define LOG_INPUT 275 -#define NOLOG_INPUT 276 -#define LOG_OUTPUT 277 -#define NOLOG_OUTPUT 278 -#define ALL 279 -#define COMMENT 280 -#define HOSTALIAS 281 -#define CMNDALIAS 282 -#define USERALIAS 283 -#define RUNASALIAS 284 -#define ERROR 285 -#define TYPE 286 -#define ROLE 287 -#ifndef YYSTYPE_DEFINED -#define YYSTYPE_DEFINED -typedef union { - struct cmndspec *cmndspec; - struct defaults *defaults; - struct member *member; - struct runascontainer *runas; - struct privilege *privilege; - struct sudo_command command; - struct cmndtag tag; - struct selinux_info seinfo; - char *string; - int tok; -} YYSTYPE; -#endif /* YYSTYPE_DEFINED */ -extern YYSTYPE yylval; diff --git a/gram.y b/gram.y deleted file mode 100644 index f319eea..0000000 --- a/gram.y +++ /dev/null @@ -1,795 +0,0 @@ -%{ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - * 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(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) -# include -#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ -#include - -#include "sudo.h" -#include "parse.h" - -/* - * We must define SIZE_MAX for yacc's skeleton.c. - * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t - * could be signed (as it is on SunOS 4.x). - */ -#ifndef SIZE_MAX -# ifdef SIZE_T_MAX -# define SIZE_MAX SIZE_T_MAX -# else -# define SIZE_MAX INT_MAX -# endif /* SIZE_T_MAX */ -#endif /* SIZE_MAX */ - -/* - * Globals - */ -extern int sudolineno; -extern char *sudoers; -int parse_error; -int pedantic = FALSE; -int verbose = FALSE; -int errorlineno = -1; -char *errorfile = NULL; - -struct defaults_list defaults; -struct userspec_list userspecs; - -/* - * Local protoypes - */ -static void add_defaults __P((int, struct member *, struct defaults *)); -static void add_userspec __P((struct member *, struct privilege *)); -static struct defaults *new_default __P((char *, char *, int)); -static struct member *new_member __P((char *, int)); - void yyerror __P((const char *)); - -void -yyerror(s) - const char *s; -{ - /* Save the line the first error occurred on. */ - if (errorlineno == -1) { - errorlineno = sudolineno ? sudolineno - 1 : 0; - errorfile = estrdup(sudoers); - } - if (verbose && s != NULL) { -#ifndef TRACELEXER - (void) fprintf(stderr, ">>> %s: %s near line %d <<<\n", sudoers, s, - sudolineno ? sudolineno - 1 : 0); -#else - (void) fprintf(stderr, "<*> "); -#endif - } - parse_error = TRUE; -} -%} - -%union { - struct cmndspec *cmndspec; - struct defaults *defaults; - struct member *member; - struct runascontainer *runas; - struct privilege *privilege; - struct sudo_command command; - struct cmndtag tag; - struct selinux_info seinfo; - char *string; - int tok; -} - -%start file /* special start symbol */ -%token COMMAND /* absolute pathname w/ optional args */ -%token ALIAS /* an UPPERCASE alias name */ -%token DEFVAR /* a Defaults variable name */ -%token NTWKADDR /* ipv4 or ipv6 address */ -%token NETGROUP /* a netgroup (+NAME) */ -%token USERGROUP /* a usergroup (%NAME) */ -%token WORD /* a word */ -%token DEFAULTS /* Defaults entry */ -%token DEFAULTS_HOST /* Host-specific defaults entry */ -%token DEFAULTS_USER /* User-specific defaults entry */ -%token DEFAULTS_RUNAS /* Runas-specific defaults entry */ -%token DEFAULTS_CMND /* Command-specific defaults entry */ -%token NOPASSWD /* no passwd req for command */ -%token PASSWD /* passwd req for command (default) */ -%token NOEXEC /* preload dummy execve() for cmnd */ -%token EXEC /* don't preload dummy execve() */ -%token SETENV /* user may set environment for cmnd */ -%token NOSETENV /* user may not set environment */ -%token LOG_INPUT /* log user's cmnd input */ -%token NOLOG_INPUT /* don't log user's cmnd input */ -%token LOG_OUTPUT /* log cmnd output */ -%token NOLOG_OUTPUT /* don't log cmnd output */ -%token ALL /* ALL keyword */ -%token COMMENT /* comment and/or carriage return */ -%token HOSTALIAS /* Host_Alias keyword */ -%token CMNDALIAS /* Cmnd_Alias keyword */ -%token USERALIAS /* User_Alias keyword */ -%token RUNASALIAS /* Runas_Alias keyword */ -%token ':' '=' ',' '!' '+' '-' /* union member tokens */ -%token '(' ')' /* runas tokens */ -%token ERROR -%token TYPE /* SELinux type */ -%token ROLE /* SELinux role */ - -%type cmndspec -%type cmndspeclist -%type defaults_entry -%type defaults_list -%type cmnd -%type opcmnd -%type cmndlist -%type host -%type hostlist -%type ophost -%type opuser -%type user -%type userlist -%type opgroup -%type group -%type grouplist -%type runasspec -%type runaslist -%type privilege -%type privileges -%type cmndtag -%type selinux -%type rolespec -%type typespec - -%% - -file : { ; } - | line - ; - -line : entry - | line entry - ; - -entry : COMMENT { - ; - } - | error COMMENT { - yyerrok; - } - | userlist privileges { - add_userspec($1, $2); - } - | USERALIAS useraliases { - ; - } - | HOSTALIAS hostaliases { - ; - } - | CMNDALIAS cmndaliases { - ; - } - | RUNASALIAS runasaliases { - ; - } - | DEFAULTS defaults_list { - add_defaults(DEFAULTS, NULL, $2); - } - | DEFAULTS_USER userlist defaults_list { - add_defaults(DEFAULTS_USER, $2, $3); - } - | DEFAULTS_RUNAS userlist defaults_list { - add_defaults(DEFAULTS_RUNAS, $2, $3); - } - | DEFAULTS_HOST hostlist defaults_list { - add_defaults(DEFAULTS_HOST, $2, $3); - } - | DEFAULTS_CMND cmndlist defaults_list { - add_defaults(DEFAULTS_CMND, $2, $3); - } - ; - -defaults_list : defaults_entry - | defaults_list ',' defaults_entry { - list_append($1, $3); - $$ = $1; - } - ; - -defaults_entry : DEFVAR { - $$ = new_default($1, NULL, TRUE); - } - | '!' DEFVAR { - $$ = new_default($2, NULL, FALSE); - } - | DEFVAR '=' WORD { - $$ = new_default($1, $3, TRUE); - } - | DEFVAR '+' WORD { - $$ = new_default($1, $3, '+'); - } - | DEFVAR '-' WORD { - $$ = new_default($1, $3, '-'); - } - ; - -privileges : privilege - | privileges ':' privilege { - list_append($1, $3); - $$ = $1; - } - ; - -privilege : hostlist '=' cmndspeclist { - struct privilege *p = emalloc(sizeof(*p)); - list2tq(&p->hostlist, $1); - list2tq(&p->cmndlist, $3); - p->prev = p; - p->next = NULL; - $$ = p; - } - ; - -ophost : host { - $$ = $1; - $$->negated = FALSE; - } - | '!' host { - $$ = $2; - $$->negated = TRUE; - } - ; - -host : ALIAS { - $$ = new_member($1, ALIAS); - } - | ALL { - $$ = new_member(NULL, ALL); - } - | NETGROUP { - $$ = new_member($1, NETGROUP); - } - | NTWKADDR { - $$ = new_member($1, NTWKADDR); - } - | WORD { - $$ = new_member($1, WORD); - } - ; - -cmndspeclist : cmndspec - | cmndspeclist ',' cmndspec { - list_append($1, $3); -#ifdef HAVE_SELINUX - /* propagate role and type */ - if ($3->role == NULL) - $3->role = $3->prev->role; - if ($3->type == NULL) - $3->type = $3->prev->type; -#endif /* HAVE_SELINUX */ - /* propagate tags and runas list */ - if ($3->tags.nopasswd == UNSPEC) - $3->tags.nopasswd = $3->prev->tags.nopasswd; - if ($3->tags.noexec == UNSPEC) - $3->tags.noexec = $3->prev->tags.noexec; - if ($3->tags.setenv == UNSPEC && - $3->prev->tags.setenv != IMPLIED) - $3->tags.setenv = $3->prev->tags.setenv; - if ($3->tags.log_input == UNSPEC) - $3->tags.log_input = $3->prev->tags.log_input; - if ($3->tags.log_output == UNSPEC) - $3->tags.log_output = $3->prev->tags.log_output; - if ((tq_empty(&$3->runasuserlist) && - tq_empty(&$3->runasgrouplist)) && - (!tq_empty(&$3->prev->runasuserlist) || - !tq_empty(&$3->prev->runasgrouplist))) { - $3->runasuserlist = $3->prev->runasuserlist; - $3->runasgrouplist = $3->prev->runasgrouplist; - } - $$ = $1; - } - ; - -cmndspec : runasspec selinux cmndtag opcmnd { - struct cmndspec *cs = emalloc(sizeof(*cs)); - if ($1 != NULL) { - list2tq(&cs->runasuserlist, $1->runasusers); - list2tq(&cs->runasgrouplist, $1->runasgroups); - efree($1); - } else { - tq_init(&cs->runasuserlist); - tq_init(&cs->runasgrouplist); - } -#ifdef HAVE_SELINUX - cs->role = $2.role; - cs->type = $2.type; -#endif - cs->tags = $3; - cs->cmnd = $4; - cs->prev = cs; - cs->next = NULL; - /* sudo "ALL" implies the SETENV tag */ - if (cs->cmnd->type == ALL && !cs->cmnd->negated && - cs->tags.setenv == UNSPEC) - cs->tags.setenv = IMPLIED; - $$ = cs; - } - ; - -opcmnd : cmnd { - $$ = $1; - $$->negated = FALSE; - } - | '!' cmnd { - $$ = $2; - $$->negated = TRUE; - } - ; - -rolespec : ROLE '=' WORD { - $$ = $3; - } - ; - -typespec : TYPE '=' WORD { - $$ = $3; - } - ; - -selinux : /* empty */ { - $$.role = NULL; - $$.type = NULL; - } - | rolespec { - $$.role = $1; - $$.type = NULL; - } - | typespec { - $$.type = $1; - $$.role = NULL; - } - | rolespec typespec { - $$.role = $1; - $$.type = $2; - } - | typespec rolespec { - $$.type = $1; - $$.role = $2; - } - ; - -runasspec : /* empty */ { - $$ = NULL; - } - | '(' runaslist ')' { - $$ = $2; - } - ; - -runaslist : userlist { - $$ = emalloc(sizeof(struct runascontainer)); - $$->runasusers = $1; - $$->runasgroups = NULL; - } - | userlist ':' grouplist { - $$ = emalloc(sizeof(struct runascontainer)); - $$->runasusers = $1; - $$->runasgroups = $3; - } - | ':' grouplist { - $$ = emalloc(sizeof(struct runascontainer)); - $$->runasusers = NULL; - $$->runasgroups = $2; - } - ; - -cmndtag : /* empty */ { - $$.nopasswd = $$.noexec = $$.setenv = - $$.log_input = $$.log_output = UNSPEC; - } - | cmndtag NOPASSWD { - $$.nopasswd = TRUE; - } - | cmndtag PASSWD { - $$.nopasswd = FALSE; - } - | cmndtag NOEXEC { - $$.noexec = TRUE; - } - | cmndtag EXEC { - $$.noexec = FALSE; - } - | cmndtag SETENV { - $$.setenv = TRUE; - } - | cmndtag NOSETENV { - $$.setenv = FALSE; - } - | cmndtag LOG_INPUT { - $$.log_input = TRUE; - } - | cmndtag NOLOG_INPUT { - $$.log_input = FALSE; - } - | cmndtag LOG_OUTPUT { - $$.log_output = TRUE; - } - | cmndtag NOLOG_OUTPUT { - $$.log_output = FALSE; - } - ; - -cmnd : ALL { - $$ = new_member(NULL, ALL); - } - | ALIAS { - $$ = new_member($1, ALIAS); - } - | COMMAND { - struct sudo_command *c = emalloc(sizeof(*c)); - c->cmnd = $1.cmnd; - c->args = $1.args; - $$ = new_member((char *)c, COMMAND); - } - ; - -hostaliases : hostalias - | hostaliases ':' hostalias - ; - -hostalias : ALIAS '=' hostlist { - char *s; - if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) { - yyerror(s); - YYERROR; - } - } - ; - -hostlist : ophost - | hostlist ',' ophost { - list_append($1, $3); - $$ = $1; - } - ; - -cmndaliases : cmndalias - | cmndaliases ':' cmndalias - ; - -cmndalias : ALIAS '=' cmndlist { - char *s; - if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) { - yyerror(s); - YYERROR; - } - } - ; - -cmndlist : opcmnd - | cmndlist ',' opcmnd { - list_append($1, $3); - $$ = $1; - } - ; - -runasaliases : runasalias - | runasaliases ':' runasalias - ; - -runasalias : ALIAS '=' userlist { - char *s; - if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) { - yyerror(s); - YYERROR; - } - } - ; - -useraliases : useralias - | useraliases ':' useralias - ; - -useralias : ALIAS '=' userlist { - char *s; - if ((s = alias_add($1, USERALIAS, $3)) != NULL) { - yyerror(s); - YYERROR; - } - } - ; - -userlist : opuser - | userlist ',' opuser { - list_append($1, $3); - $$ = $1; - } - ; - -opuser : user { - $$ = $1; - $$->negated = FALSE; - } - | '!' user { - $$ = $2; - $$->negated = TRUE; - } - ; - -user : ALIAS { - $$ = new_member($1, ALIAS); - } - | ALL { - $$ = new_member(NULL, ALL); - } - | NETGROUP { - $$ = new_member($1, NETGROUP); - } - | USERGROUP { - $$ = new_member($1, USERGROUP); - } - | WORD { - $$ = new_member($1, WORD); - } - ; - -grouplist : opgroup - | grouplist ',' opgroup { - list_append($1, $3); - $$ = $1; - } - ; - -opgroup : group { - $$ = $1; - $$->negated = FALSE; - } - | '!' group { - $$ = $2; - $$->negated = TRUE; - } - ; - -group : ALIAS { - $$ = new_member($1, ALIAS); - } - | ALL { - $$ = new_member(NULL, ALL); - } - | WORD { - $$ = new_member($1, WORD); - } - ; - -%% -static struct defaults * -new_default(var, val, op) - char *var; - char *val; - int op; -{ - struct defaults *d; - - d = emalloc(sizeof(struct defaults)); - d->var = var; - d->val = val; - tq_init(&d->binding); - d->type = 0; - d->op = op; - d->prev = d; - d->next = NULL; - - return(d); -} - -static struct member * -new_member(name, type) - char *name; - int type; -{ - struct member *m; - - m = emalloc(sizeof(struct member)); - m->name = name; - m->type = type; - m->prev = m; - m->next = NULL; - - return(m); -} - -/* - * Add a list of defaults structures to the defaults list. - * The binding, if non-NULL, specifies a list of hosts, users, or - * runas users the entries apply to (specified by the type). - */ -static void -add_defaults(type, bmem, defs) - int type; - struct member *bmem; - struct defaults *defs; -{ - struct defaults *d; - struct member_list binding; - - /* - * We can only call list2tq once on bmem as it will zero - * out the prev pointer when it consumes bmem. - */ - list2tq(&binding, bmem); - - /* - * Set type and binding (who it applies to) for new entries. - */ - for (d = defs; d != NULL; d = d->next) { - d->type = type; - d->binding = binding; - } - tq_append(&defaults, defs); -} - -/* - * Allocate a new struct userspec, populate it, and insert it at the - * and of the userspecs list. - */ -static void -add_userspec(members, privs) - struct member *members; - struct privilege *privs; -{ - struct userspec *u; - - u = emalloc(sizeof(*u)); - list2tq(&u->users, members); - list2tq(&u->privileges, privs); - u->prev = u; - u->next = NULL; - tq_append(&userspecs, u); -} - -/* - * Free up space used by data structures from a previous parser run and sets - * the current sudoers file to path. - */ -void -init_parser(path, quiet) - char *path; - int quiet; -{ - struct defaults *d; - struct member *m, *binding; - struct userspec *us; - struct privilege *priv; - struct cmndspec *cs; - struct sudo_command *c; - - while ((us = tq_pop(&userspecs)) != NULL) { - while ((m = tq_pop(&us->users)) != NULL) { - efree(m->name); - efree(m); - } - while ((priv = tq_pop(&us->privileges)) != NULL) { - struct member *runasuser = NULL, *runasgroup = NULL; -#ifdef HAVE_SELINUX - char *role = NULL, *type = NULL; -#endif /* HAVE_SELINUX */ - - while ((m = tq_pop(&priv->hostlist)) != NULL) { - efree(m->name); - efree(m); - } - while ((cs = tq_pop(&priv->cmndlist)) != NULL) { -#ifdef HAVE_SELINUX - /* Only free the first instance of a role/type. */ - if (cs->role != role) { - role = cs->role; - efree(cs->role); - } - if (cs->type != type) { - type = cs->type; - efree(cs->type); - } -#endif /* HAVE_SELINUX */ - if (tq_last(&cs->runasuserlist) != runasuser) { - runasuser = tq_last(&cs->runasuserlist); - while ((m = tq_pop(&cs->runasuserlist)) != NULL) { - efree(m->name); - efree(m); - } - } - if (tq_last(&cs->runasgrouplist) != runasgroup) { - runasgroup = tq_last(&cs->runasgrouplist); - while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { - efree(m->name); - efree(m); - } - } - if (cs->cmnd->type == COMMAND) { - c = (struct sudo_command *) cs->cmnd->name; - efree(c->cmnd); - efree(c->args); - } - efree(cs->cmnd->name); - efree(cs->cmnd); - efree(cs); - } - efree(priv); - } - efree(us); - } - tq_init(&userspecs); - - binding = NULL; - while ((d = tq_pop(&defaults)) != NULL) { - if (tq_last(&d->binding) != binding) { - binding = tq_last(&d->binding); - while ((m = tq_pop(&d->binding)) != NULL) { - if (m->type == COMMAND) { - c = (struct sudo_command *) m->name; - efree(c->cmnd); - efree(c->args); - } - efree(m->name); - efree(m); - } - } - efree(d->var); - efree(d->val); - efree(d); - } - tq_init(&defaults); - - init_aliases(); - - init_lexer(); - - efree(sudoers); - sudoers = path ? estrdup(path) : NULL; - - parse_error = FALSE; - errorlineno = -1; - errorfile = NULL; - sudolineno = 1; - verbose = !quiet; -} diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 0000000..9dbe4c4 --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,87 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +includedir = @includedir@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ + +# User and group ids the installed files should be "owned" by +install_uid = 0 +install_gid = 0 + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +all: + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file include/Makefile) + +.SUFFIXES: .h + +pre-install: + +install: install-includes + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(includedir) + +install-binaries: + +install-doc: + +install-includes: install-dirs + $(INSTALL) -O $(install_uid) -G $(install_gid) -m 0444 $(srcdir)/sudo_plugin.h $(DESTDIR)$(includedir) + +install-plugin: + +uninstall: + -rm -f $(DESTDIR)$(includedir)/sudo_plugin.h + +check: + +clean: + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile + +clobber: distclean + +realclean: distclean + +cleandir: distclean diff --git a/include/alloc.h b/include/alloc.h new file mode 100644 index 0000000..b5b3e38 --- /dev/null +++ b/include/alloc.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2009-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. + */ + +#ifndef _SUDO_ALLOC_H +#define _SUDO_ALLOC_H + +#include + +int easprintf(char **, const char *, ...) __printflike(2, 3); +int evasprintf(char **, const char *, va_list) __printflike(2, 0); +void efree(void *); +void *ecalloc(size_t, size_t); +void *emalloc(size_t); +void *emalloc2(size_t, size_t); +void *erealloc(void *, size_t); +void *erealloc3(void *, size_t, size_t); +void *erecalloc(void *, size_t, size_t, size_t); +char *estrdup(const char *); +char *estrndup(const char *, size_t); + +#endif /* _SUDO_ALLOC_H */ diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..f587b89 --- /dev/null +++ b/include/error.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2004, 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. + */ + +#ifndef _SUDO_ERROR_H_ +#define _SUDO_ERROR_H_ + +#include + +/* + * We wrap error/errorx and warn/warnx so that the same output can + * go to the debug file, if there is one. + */ +#if defined(SUDO_ERROR_WRAP) && SUDO_ERROR_WRAP == 0 +# if defined(__GNUC__) && __GNUC__ == 2 +# define error(rval, fmt...) error2((rval), (fmt)) +# define errorx(rval, fmt...) errorx2((rval), (fmt)) +# define warning(fmt...) warning2((fmt)) +# define warningx(fmt...) warningx2((fmt)) +# else +# define error(rval, ...) error2((rval), __VA_ARGS__) +# define errorx(rval, ...) errorx2((rval), __VA_ARGS__) +# define warning(...) warning2(__VA_ARGS__) +# define warningx(...) warningx2(__VA_ARGS__) +# endif /* __GNUC__ == 2 */ +#else /* SUDO_ERROR_WRAP */ +# if defined(__GNUC__) && __GNUC__ == 2 +# define error(rval, fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + (fmt)); \ + error2((rval), (fmt)); \ +} while (0) +# define errorx(rval, fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, (fmt)); \ + errorx2((rval), (fmt)); \ +} while (0) +# define warning(fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + (fmt)); \ + warning2((fmt)); \ +} while (0) +# define warningx(fmt...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, (fmt)); \ + warningx2((fmt)); \ +} while (0) +# else +# define error(rval, ...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + __VA_ARGS__); \ + error2((rval), __VA_ARGS__); \ +} while (0) +# define errorx(rval, ...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO|sudo_debug_subsys, __VA_ARGS__); \ + errorx2((rval), __VA_ARGS__); \ +} while (0) +# define warning(...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|SUDO_DEBUG_ERRNO|sudo_debug_subsys, \ + __VA_ARGS__); \ + warning2(__VA_ARGS__); \ +} while (0) +# define warningx(...) do { \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, \ + SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO|sudo_debug_subsys, __VA_ARGS__); \ + warningx2(__VA_ARGS__); \ +} while (0) +# endif /* __GNUC__ == 2 */ +#endif /* SUDO_ERROR_WRAP */ + +void error2(int, const char *, ...) __printflike(2, 3) __attribute__((__noreturn__)); +void errorx2(int, const char *, ...) __printflike(2, 3) __attribute__((__noreturn__)); +void warning2(const char *, ...) __printflike(1, 2); +void warningx2(const char *, ...) __printflike(1, 2); + +#endif /* _SUDO_ERROR_H_ */ diff --git a/include/fileops.h b/include/fileops.h new file mode 100644 index 0000000..cd0a0df --- /dev/null +++ b/include/fileops.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _SUDO_FILEOPS_H +#define _SUDO_FILEOPS_H + +/* + * Flags for lock_file() + */ +#define SUDO_LOCK 1 /* lock a file */ +#define SUDO_TLOCK 2 /* test & lock a file (non-blocking) */ +#define SUDO_UNLOCK 4 /* unlock a file */ + +struct timeval; + +bool lock_file(int, int); +int touch(int, char *, struct timeval *); +char *sudo_parseln(FILE *); + +#endif /* _SUDO_FILEOPS_H */ diff --git a/include/gettext.h b/include/gettext.h new file mode 100644 index 0000000..27f0796 --- /dev/null +++ b/include/gettext.h @@ -0,0 +1,66 @@ +/* + * 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_GETTEXT_H +#define _SUDO_GETTEXT_H + +/* + * Solaris locale.h includes libintl.h which causes problems when we + * redefine the gettext functions. We include it first to avoid this. + */ +#if defined(HAVE_LOCALE_H) && defined(__sun__) && defined(__svr4__) +# include +#endif + +#ifdef HAVE_LIBINTL_H + +# include + +/* + * If DEFAULT_TEXT_DOMAIN is defined, use its value as the domain for + * gettext() and ngettext() instead of the value set by textdomain(). + * This is used by the sudoers plugin as well as the convenience libraries. + */ +# ifdef DEFAULT_TEXT_DOMAIN +# undef gettext +# define gettext(String) \ + dgettext(DEFAULT_TEXT_DOMAIN, String) +# undef ngettext +# define ngettext(String, String_Plural, N) \ + dngettext(DEFAULT_TEXT_DOMAIN, String, String_Plural, N) +# endif + +/* Gettext convenience macros */ +# define _(String) gettext(String) +# define gettext_noop(String) String +# define N_(String) gettext_noop(String) + +#else /* !HAVE_LIBINTL_H */ + +/* + * Internationalization is either unavailable or has been disabled. + * Define away the gettext functions used by sudo. + */ +# define _(String) String +# define N_(String) String +# define textdomain(Domain) +# define bindtextdomain(Package, Directory) +# define ngettext(String, String_Plural, N) \ + ((N) == 1 ? (String) : (String_Plural)) + +#endif /* HAVE_LIBINTL_H */ + +#endif /* _SUDO_GETTEXT_H */ diff --git a/include/lbuf.h b/include/lbuf.h new file mode 100644 index 0000000..c6d5093 --- /dev/null +++ b/include/lbuf.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2007, 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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SUDO_LBUF_H +#define _SUDO_LBUF_H + +/* + * Line buffer struct. + */ +struct lbuf { + int (*output)(const char *); + char *buf; + const char *continuation; + int indent; + int len; + int size; + int cols; +}; + +void lbuf_init(struct lbuf *, int (*)(const char *), int, const char *, int); +void lbuf_destroy(struct lbuf *); +void lbuf_append(struct lbuf *, const char *, ...) __printflike(2, 3); +void lbuf_append_quoted(struct lbuf *, const char *, const char *, ...) __printflike(3, 4); +void lbuf_print(struct lbuf *); + +#endif /* _SUDO_LBUF_H */ diff --git a/include/list.h b/include/list.h new file mode 100644 index 0000000..1055e22 --- /dev/null +++ b/include/list.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2007, 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. + */ + +#ifndef _SUDO_LIST_H +#define _SUDO_LIST_H + +/* + * Convenience macro for declaring a list head. + */ +#define TQ_DECLARE(n) \ +struct n##_list { \ + struct n *first; \ + struct n *last; \ +}; + +/* + * Foreach loops: forward and reverse + */ +#undef tq_foreach_fwd +#define tq_foreach_fwd(h, v) \ + for ((v) = (h)->first; (v) != NULL; (v) = (v)->next) + +#undef tq_foreach_rev +#define tq_foreach_rev(h, v) \ + for ((v) = (h)->last; (v) != NULL; (v) = (v)->prev) + +/* + * Init a list head. + */ +#undef tq_init +#define tq_init(h) do { \ + (h)->first = NULL; \ + (h)->last = NULL; \ +} while (0) + +/* + * Simple macros to avoid exposing first/last and prev/next. + */ +#undef tq_empty +#define tq_empty(h) ((h)->first == NULL) + +#undef tq_first +#define tq_first(h) ((h)->first) + +#undef tq_last +#define tq_last(h) ((h)->last) + +#undef list_next +#define list_next(e) ((e)->next) + +#undef list_prev +#define list_prev(e) ((e)->prev) + +/* + * Prototypes for list.c + */ +void *tq_pop(void *); +void tq_append(void *, void *); +void tq_remove(void *, void *); +void list_append(void *, void *); +void list2tq(void *, void *); + +#endif /* _SUDO_LIST_H */ diff --git a/include/missing.h b/include/missing.h new file mode 100644 index 0000000..6f00a57 --- /dev/null +++ b/include/missing.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1996, 1998-2005, 2008, 2009-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_MISSING_H +#define _SUDO_MISSING_H + +#include +#include + +/* + * Macros and functions that may be missing on some operating systems. + */ + +/* Define away __attribute__ for non-gcc or old gcc */ +#if !defined(__GNUC__) || __GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 5 +# define __attribute__(x) +#endif + +/* For 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 + +/* + * 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 + +/* + * Older systems may be missing stddef.h and/or offsetof macro + */ +#ifndef offsetof +# ifdef __offsetof +# define offsetof(type, field) __offsetof(type, field) +# else +# define offsetof(type, field) ((size_t)(&((type *)0)->field)) +# endif +#endif + +/* + * Simple isblank() macro and function for systems without it. + */ +#ifndef HAVE_ISBLANK +int isblank(int); +# define isblank(_x) ((_x) == ' ' || (_x) == '\t') +#endif + +/* + * NCR's SVr4 has _innetgr(3) instead of innetgr(3) for some reason. + */ +#ifdef HAVE__INNETGR +# define innetgr(n, h, u, d) (_innetgr(n, h, u, d)) +# define HAVE_INNETGR 1 +#endif /* HAVE__INNETGR */ + +/* + * On POSIX systems, O_NOCTTY is the default so some OS's may lack this define. + */ +#ifndef O_NOCTTY +# define O_NOCTTY 0 +#endif /* O_NOCTTY */ + +/* + * Add IRIX-like sigaction_t for those without it. + * SA_RESTART is not required by POSIX; SunOS has SA_INTERRUPT instead. + */ +#ifndef HAVE_SIGACTION_T +typedef struct sigaction sigaction_t; +#endif +#ifndef SA_INTERRUPT +# define SA_INTERRUPT 0 +#endif +#ifndef SA_RESTART +# define SA_RESTART 0 +#endif + +/* + * If dirfd() does not exists, hopefully dd_fd does. + */ +#if !defined(HAVE_DIRFD) && defined(HAVE_DD_FD) +# define dirfd(_d) ((_d)->dd_fd) +# define HAVE_DIRFD +#endif + +/* + * Define futimes() in terms of futimesat() if needed. + */ +#if !defined(HAVE_FUTIMES) && defined(HAVE_FUTIMESAT) +# define futimes(_f, _tv) futimesat(_f, NULL, _tv) +# define HAVE_FUTIMES +#endif + +#if !defined(HAVE_KILLPG) && !defined(killpg) +# define killpg(s) kill(-(s)) +#endif + +/* + * If we lack getprogname(), emulate with __progname if possible. + * Otherwise, add a prototype for use with our own getprogname.c. + */ +#ifndef HAVE_GETPROGNAME +# ifdef HAVE___PROGNAME +extern const char *__progname; +# define getprogname() (__progname) +# else +const char *getprogname(void); +void setprogname(const char *); +#endif /* HAVE___PROGNAME */ +#endif /* !HAVE_GETPROGNAME */ + +/* + * Declare errno if errno.h doesn't do it for us. + */ +#if defined(HAVE_DECL_ERRNO) && !HAVE_DECL_ERRNO +extern int errno; +#endif /* !HAVE_DECL_ERRNO */ + +#ifndef timevalclear +# define timevalclear(tv) ((tv)->tv_sec = (tv)->tv_usec = 0) +#endif +#ifndef timevalisset +# define timevalisset(tv) ((tv)->tv_sec || (tv)->tv_usec) +#endif +#ifndef timevalcmp +# define timevalcmp(tv1, tv2, op) \ + (((tv1)->tv_sec == (tv2)->tv_sec) ? \ + ((tv1)->tv_usec op (tv2)->tv_usec) : \ + ((tv1)->tv_sec op (tv2)->tv_sec)) +#endif +#ifndef timevaladd +# define timevaladd(tv1, tv2) \ + do { \ + (tv1)->tv_sec += (tv2)->tv_sec; \ + (tv1)->tv_usec += (tv2)->tv_usec; \ + if ((tv1)->tv_usec >= 1000000) { \ + (tv1)->tv_sec++; \ + (tv1)->tv_usec -= 1000000; \ + } \ + } while (0) +#endif +#ifndef timevalsub +# define timevalsub(tv1, tv2) \ + do { \ + (tv1)->tv_sec -= (tv2)->tv_sec; \ + (tv1)->tv_usec -= (tv2)->tv_usec; \ + if ((tv1)->tv_usec < 0) { \ + (tv1)->tv_sec--; \ + (tv1)->tv_usec += 1000000; \ + } \ + } while (0) +#endif + +/* Not all systems define NSIG in signal.h */ +#if !defined(NSIG) +# if defined(_NSIG) +# define NSIG _NSIG +# elif defined(__NSIG) +# define NSIG __NSIG +# else +# define NSIG 64 +# endif +#endif + +#ifndef WCOREDUMP +# define WCOREDUMP(x) ((x) & 0x80) +#endif + +#ifndef HAVE_SETEUID +# if defined(HAVE_SETRESUID) +# define seteuid(u) setresuid(-1, (u), -1) +# define setegid(g) setresgid(-1, (g), -1) +# define HAVE_SETEUID 1 +# elif defined(HAVE_SETREUID) +# define seteuid(u) setreuid(-1, (u)) +# define setegid(g) setregid(-1, (g)) +# define HAVE_SETEUID 1 +# endif +#endif /* HAVE_SETEUID */ + +/* + * HP-UX does not declare innetgr() or getdomainname(). + * Solaris does not declare getdomainname(). + */ +#if defined(__hpux) +int innetgr(const char *, const char *, const char *, const char *); +#endif +#if defined(__hpux) || defined(__sun) +int getdomainname(char *, size_t); +#endif + +/* Functions "missing" from libc. */ + +struct timeval; +struct timespec; + +#ifndef HAVE_CLOSEFROM +void closefrom(int); +#endif +#ifndef HAVE_GETCWD +char *getcwd(char *, size_t size); +#endif +#ifndef HAVE_GETGROUPLIST +int getgrouplist(const char *, gid_t, gid_t *, int *); +#endif +#ifndef HAVE_GETLINE +ssize_t getline(char **, size_t *, FILE *); +#endif +#ifndef HAVE_UTIMES +int utimes(const char *, const struct timeval *); +#endif +#ifdef HAVE_FUTIME +int futimes(int, const struct timeval *); +#endif +#ifndef HAVE_SNPRINTF +int snprintf(char *, size_t, const char *, ...) __printflike(3, 4); +#endif +#ifndef HAVE_VSNPRINTF +int vsnprintf(char *, size_t, const char *, va_list) __printflike(3, 0); +#endif +#ifndef HAVE_ASPRINTF +int asprintf(char **, const char *, ...) __printflike(2, 3); +#endif +#ifndef HAVE_VASPRINTF +int vasprintf(char **, const char *, va_list) __printflike(2, 0); +#endif +#ifndef HAVE_STRLCAT +size_t strlcat(char *, const char *, size_t); +#endif +#ifndef HAVE_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif +#ifndef HAVE_MEMRCHR +void *memrchr(const void *, int, size_t); +#endif +#ifndef HAVE_MKDTEMP +char *mkdtemp(char *); +#endif +#ifndef HAVE_MKSTEMPS +int mkstemps(char *, int); +#endif +#ifndef HAVE_NANOSLEEP +int nanosleep(const struct timespec *, struct timespec *); +#endif +#ifndef HAVE_PW_DUP +struct passwd *pw_dup(const struct passwd *); +#endif +#ifndef HAVE_SETENV +int setenv(const char *, const char *, int); +#endif +#ifndef HAVE_UNSETENV +int unsetenv(const char *); +#endif +#ifndef HAVE_STRSIGNAL +char *strsignal(int); +#endif + +#endif /* _SUDO_MISSING_H */ diff --git a/include/secure_path.h b/include/secure_path.h new file mode 100644 index 0000000..b96b89b --- /dev/null +++ b/include/secure_path.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2012 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_SECURE_PATH_H +#define _SUDO_SECURE_PATH_H + +#define SUDO_PATH_SECURE 0 +#define SUDO_PATH_MISSING -1 +#define SUDO_PATH_BAD_TYPE -2 +#define SUDO_PATH_WRONG_OWNER -3 +#define SUDO_PATH_WORLD_WRITABLE -4 +#define SUDO_PATH_GROUP_WRITABLE -5 + +int sudo_secure_dir(const char *path, uid_t uid, gid_t gid, struct stat *sbp); +int sudo_secure_file(const char *path, uid_t uid, gid_t gid, struct stat *sbp); +int sudo_secure_path(const char *path, int type, uid_t uid, gid_t gid, struct stat *sbp); + +#endif /* _SUDO_SECURE_PATH_H */ diff --git a/include/sudo_conf.h b/include/sudo_conf.h new file mode 100644 index 0000000..c0dcc5a --- /dev/null +++ b/include/sudo_conf.h @@ -0,0 +1,41 @@ +/* + * 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_CONF_H +#define _SUDO_CONF_H + +#include "list.h" + +struct plugin_info { + struct plugin_info *prev; /* required */ + struct plugin_info *next; /* required */ + const char *path; + const char *symbol_name; + char * const * options; +}; +TQ_DECLARE(plugin_info) + +/* Read main sudo.conf file. */ +void sudo_conf_read(void); + +/* Accessor functions. */ +const char *sudo_conf_askpass_path(void); +const char *sudo_conf_noexec_path(void); +const char *sudo_conf_debug_flags(void); +struct plugin_info_list *sudo_conf_plugins(void); +bool sudo_conf_disable_coredump(void); + +#endif /* _SUDO_CONF_H */ diff --git a/include/sudo_debug.h b/include/sudo_debug.h new file mode 100644 index 0000000..b7b458d --- /dev/null +++ b/include/sudo_debug.h @@ -0,0 +1,208 @@ +/* + * 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_DEBUG_H +#define _SUDO_DEBUG_H + +#include + +/* + * The priority and subsystem are encoded in a single 32-bit value. + * The lower 4 bits are the priority and the top 26 bits are the subsystem. + * This allows for 16 priorities and a very large number of subsystems. + * Bit 5 is used as a flag to specify whether to log the errno value. + * Bit 6 specifies whether to log the function, file and line number data. + */ + +/* + * Sudo debug priorities, ordered least to most verbose, + * in other words, highest to lowest priority. Max pri is 15. + * Note: order must match sudo_debug_priorities[] + */ +#define SUDO_DEBUG_CRIT 1 /* critical errors */ +#define SUDO_DEBUG_ERROR 2 /* non-critical errors */ +#define SUDO_DEBUG_WARN 3 /* non-fatal warnings */ +#define SUDO_DEBUG_NOTICE 4 /* non-error condition notices */ +#define SUDO_DEBUG_DIAG 5 /* diagnostic messages */ +#define SUDO_DEBUG_INFO 6 /* informational message */ +#define SUDO_DEBUG_TRACE 7 /* log function enter/exit */ +#define SUDO_DEBUG_DEBUG 8 /* very verbose debugging */ + +/* + * Sudo debug subsystems. + * This includes subsystems in the sudoers plugin. + * Note: order must match sudo_debug_subsystems[] + */ +#define SUDO_DEBUG_MAIN ( 1<<6) /* sudo main() */ +#define SUDO_DEBUG_ARGS ( 2<<6) /* command line argument processing */ +#define SUDO_DEBUG_EXEC ( 3<<6) /* command execution */ +#define SUDO_DEBUG_PTY ( 4<<6) /* pseudo-tty */ +#define SUDO_DEBUG_UTMP ( 5<<6) /* utmp file ops */ +#define SUDO_DEBUG_CONV ( 6<<6) /* user conversation */ +#define SUDO_DEBUG_PCOMM ( 7<<6) /* plugin communications */ +#define SUDO_DEBUG_UTIL ( 8<<6) /* utility functions */ +#define SUDO_DEBUG_NETIF ( 9<<6) /* network interface functions */ +#define SUDO_DEBUG_AUDIT (10<<6) /* audit */ +#define SUDO_DEBUG_EDIT (11<<6) /* sudoedit */ +#define SUDO_DEBUG_SELINUX (12<<6) /* selinux */ +#define SUDO_DEBUG_LDAP (13<<6) /* sudoers LDAP */ +#define SUDO_DEBUG_MATCH (14<<6) /* sudoers matching */ +#define SUDO_DEBUG_PARSER (15<<6) /* sudoers parser */ +#define SUDO_DEBUG_ALIAS (16<<6) /* sudoers alias functions */ +#define SUDO_DEBUG_DEFAULTS (17<<6) /* sudoers defaults settings */ +#define SUDO_DEBUG_AUTH (18<<6) /* authentication functions */ +#define SUDO_DEBUG_ENV (19<<6) /* environment handling */ +#define SUDO_DEBUG_LOGGING (20<<6) /* logging functions */ +#define SUDO_DEBUG_NSS (21<<6) /* network service switch */ +#define SUDO_DEBUG_RBTREE (22<<6) /* red-black tree functions */ +#define SUDO_DEBUG_PERMS (23<<6) /* uid/gid swapping functions */ +#define SUDO_DEBUG_PLUGIN (24<<6) /* main plugin functions */ +#define SUDO_DEBUG_HOOKS (25<<6) /* hook functions */ +#define SUDO_DEBUG_ALL 0xfff0 /* all subsystems */ + +/* Flag to include string version of errno in debug info. */ +#define SUDO_DEBUG_ERRNO (1<<4) + +/* Flag to include function, file and line number in debug info. */ +#define SUDO_DEBUG_LINENO (1<<5) + +/* Extract priority and convert to an index. */ +#define SUDO_DEBUG_PRI(n) (((n) & 0xf) - 1) + +/* Extract subsystem and convert to an index. */ +#define SUDO_DEBUG_SUBSYS(n) (((n) >> 6) - 1) + +/* + * Wrapper for sudo_debug_enter() that declares __func__ as needed + * and sets sudo_debug_subsys for sudo_debug_exit(). + */ +#ifdef HAVE___FUNC__ +# define debug_decl(funcname, subsys) \ + const int sudo_debug_subsys = (subsys); \ + sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys); +#else +# define debug_decl(funcname, subsys) \ + const int sudo_debug_subsys = (subsys); \ + const char *__func__ = #funcname; \ + sudo_debug_enter(__func__, __FILE__, __LINE__, sudo_debug_subsys); +#endif + +/* + * Wrappers for sudo_debug_exit() and friends. + */ +#define debug_return \ + do { \ + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); \ + return; \ + } while (0) + +#define debug_return_int(rval) \ + do { \ + int sudo_debug_rval = (rval); \ + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_rval); \ + return sudo_debug_rval; \ + } while (0) + +#define debug_return_size_t(rval) \ + do { \ + size_t sudo_debug_rval = (rval); \ + sudo_debug_exit_size_t(__func__, __FILE__, __LINE__, sudo_debug_subsys,\ + sudo_debug_rval); \ + return sudo_debug_rval; \ + } while (0) + +#define debug_return_long(rval) \ + do { \ + long sudo_debug_rval = (rval); \ + sudo_debug_exit_long(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_rval); \ + return sudo_debug_rval; \ + } while (0) + +#define debug_return_bool(rval) \ + do { \ + int sudo_debug_rval = (rval); \ + sudo_debug_exit_bool(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_rval); \ + return sudo_debug_rval; \ + } while (0) + +#define debug_return_str(rval) \ + do { \ + const char *sudo_debug_rval = (rval); \ + sudo_debug_exit_str(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_rval); \ + return (char *)sudo_debug_rval; \ + } while (0) + +#define debug_return_str_masked(rval) \ + do { \ + const char *sudo_debug_rval = (rval); \ + sudo_debug_exit_str_masked(__func__, __FILE__, __LINE__, \ + sudo_debug_subsys, sudo_debug_rval); \ + return (char *)sudo_debug_rval; \ + } while (0) + +#define debug_return_ptr(rval) \ + do { \ + const void *sudo_debug_rval = (rval); \ + sudo_debug_exit_ptr(__func__, __FILE__, __LINE__, sudo_debug_subsys, \ + sudo_debug_rval); \ + return (void *)sudo_debug_rval; \ + } while (0) + +/* + * Variadic macros are a C99 feature but GNU cpp has supported + * a (different) version of them for a long time. + */ +#if defined(__GNUC__) && __GNUC__ == 2 +# define sudo_debug_printf(pri, fmt...) \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, (pri)|sudo_debug_subsys, \ + (fmt)) +#else +# define sudo_debug_printf(pri, ...) \ + sudo_debug_printf2(__func__, __FILE__, __LINE__, (pri)|sudo_debug_subsys, \ + __VA_ARGS__) +#endif + +#define sudo_debug_execve(pri, path, argv, envp) \ + sudo_debug_execve2((pri)|sudo_debug_subsys, (path), (argv), (envp)) + +/* + * NULL-terminated string lists of priorities and subsystems. + */ +extern const char *const sudo_debug_priorities[]; +extern const char *const sudo_debug_subsystems[]; + +void sudo_debug_enter(const char *func, const char *file, int line, int subsys); +void sudo_debug_execve2(int level, const char *path, char *const argv[], char *const envp[]); +void sudo_debug_exit(const char *func, const char *file, int line, int subsys); +void sudo_debug_exit_int(const char *func, const char *file, int line, int subsys, int rval); +void sudo_debug_exit_long(const char *func, const char *file, int line, int subsys, long rval); +void sudo_debug_exit_size_t(const char *func, const char *file, int line, int subsys, size_t rval); +void sudo_debug_exit_bool(const char *func, const char *file, int line, int subsys, int rval); +void sudo_debug_exit_str(const char *func, const char *file, int line, int subsys, const char *rval); +void sudo_debug_exit_str_masked(const char *func, const char *file, int line, int subsys, const char *rval); +void sudo_debug_exit_ptr(const char *func, const char *file, int line, int subsys, const void *rval); +int sudo_debug_fd_set(int fd); +int sudo_debug_init(const char *debugfile, const char *settings); +void sudo_debug_printf2(const char *func, const char *file, int line, int level, const char *format, ...) __printflike(5, 6); +void sudo_debug_write(const char *str, int len, int errno_val); +void sudo_debug_write2(const char *func, const char *file, int line, const char *str, int len, int errno_val); +pid_t sudo_debug_fork(void); + +#endif /* _SUDO_DEBUG_H */ diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h new file mode 100644 index 0000000..52dee0a --- /dev/null +++ b/include/sudo_plugin.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2009-2012 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_PLUGIN_H +#define _SUDO_PLUGIN_H + +/* API version major/minor */ +#define SUDO_API_VERSION_MAJOR 1 +#define SUDO_API_VERSION_MINOR 2 +#define SUDO_API_MKVERSION(x, y) ((x << 16) | y) +#define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR, SUDO_API_VERSION_MINOR) + +/* Getters and setters for API version */ +#define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16) +#define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff) +#define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ +} while(0) +#define SUDO_API_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ +} while(0) + +/* Conversation function types and defines */ +struct sudo_conv_message { +#define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */ +#define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */ +#define SUDO_CONV_ERROR_MSG 0x0003 /* error message */ +#define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ +#define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ +#define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */ +#define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ + int msg_type; + int timeout; + const char *msg; +}; + +struct sudo_conv_reply { + char *reply; +}; + +typedef int (*sudo_conv_t)(int num_msgs, const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[]); +typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...); + +/* + * Hooks allow a plugin to hook into specific sudo and/or libc functions. + */ + +/* Hook functions typedefs. */ +typedef int (*sudo_hook_fn_t)(); +typedef int (*sudo_hook_fn_setenv_t)(const char *name, const char *value, int overwrite, void *closure); +typedef int (*sudo_hook_fn_putenv_t)(char *string, void *closure); +typedef int (*sudo_hook_fn_getenv_t)(const char *name, char **value, void *closure); +typedef int (*sudo_hook_fn_unsetenv_t)(const char *name, void *closure); + +/* Hook structure definition. */ +struct sudo_hook { + int hook_version; + int hook_type; + sudo_hook_fn_t hook_fn; + void *closure; +}; + +/* Hook API version major/minor */ +#define SUDO_HOOK_VERSION_MAJOR 1 +#define SUDO_HOOK_VERSION_MINOR 0 +#define SUDO_HOOK_MKVERSION(x, y) ((x << 16) | y) +#define SUDO_HOOK_VERSION SUDO_HOOK_MKVERSION(SUDO_HOOK_VERSION_MAJOR, SUDO_HOOK_VERSION_MINOR) + +/* Getters and setters for hook API version */ +#define SUDO_HOOK_VERSION_GET_MAJOR(v) ((v) >> 16) +#define SUDO_HOOK_VERSION_GET_MINOR(v) ((v) & 0xffff) +#define SUDO_HOOK_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ +} while(0) +#define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ +} while(0) + +/* + * Hook function return values. + */ +#define SUDO_HOOK_RET_ERROR -1 /* error */ +#define SUDO_HOOK_RET_NEXT 0 /* go to the next hook in the list */ +#define SUDO_HOOK_RET_STOP 1 /* stop hook processing for this type */ + +/* + * Hooks for setenv/unsetenv/putenv/getenv. + * This allows the plugin to be notified when a PAM module modifies + * the environment so it can update the copy of the environment that + * is passed to execve(). + */ +#define SUDO_HOOK_SETENV 1 +#define SUDO_HOOK_UNSETENV 2 +#define SUDO_HOOK_PUTENV 3 +#define SUDO_HOOK_GETENV 4 + +/* Policy plugin type and defines */ +struct passwd; +struct policy_plugin { +#define SUDO_POLICY_PLUGIN 1 + unsigned int type; /* always SUDO_POLICY_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], char * const user_env[], + char * const plugin_plugins[]); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*check_policy)(int argc, char * const argv[], + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + int (*list)(int argc, char * const argv[], int verbose, + const char *list_user); + int (*validate)(void); + void (*invalidate)(int remove); + int (*init_session)(struct passwd *pwd, char **user_env_out[]); + void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); +}; + +/* I/O plugin type and defines */ +struct io_plugin { +#define SUDO_IO_PLUGIN 2 + unsigned int type; /* always SUDO_IO_PLUGIN */ + unsigned int version; /* always SUDO_API_VERSION */ + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], char * const command_info[], + int argc, char * const argv[], char * const user_env[], + char * const plugin_plugins[]); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*log_ttyin)(const char *buf, unsigned int len); + int (*log_ttyout)(const char *buf, unsigned int len); + int (*log_stdin)(const char *buf, unsigned int len); + int (*log_stdout)(const char *buf, unsigned int len); + int (*log_stderr)(const char *buf, unsigned int len); + void (*register_hooks)(int version, int (*register_hook)(struct sudo_hook *hook)); + void (*deregister_hooks)(int version, int (*deregister_hook)(struct sudo_hook *hook)); +}; + +/* Sudoers group plugin version major/minor */ +#define GROUP_API_VERSION_MAJOR 1 +#define GROUP_API_VERSION_MINOR 0 +#define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | GROUP_API_VERSION_MINOR) + +/* Getters and setters for group version */ +#define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16) +#define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff) +#define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \ + *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \ +} while(0) +#define GROUP_API_VERSION_SET_MINOR(vp, n) do { \ + *(vp) = (*(vp) & 0xffff0000) | (n); \ +} while(0) + +/* + * version: for compatibility checking + * group_init: return 1 on success, 0 if unconfigured, -1 on error. + * group_cleanup: called to clean up resources used by provider + * user_in_group: returns 1 if user is in group, 0 if not. + * note that pwd may be NULL if the user is not in passwd. + */ +struct sudoers_group_plugin { + unsigned int version; + int (*init)(int version, sudo_printf_t sudo_printf, char *const argv[]); + void (*cleanup)(void); + int (*query)(const char *user, const char *group, const struct passwd *pwd); +}; + +#endif /* _SUDO_PLUGIN_H */ diff --git a/ins_2001.h b/ins_2001.h deleted file mode 100644 index 63a5d64..0000000 --- a/ins_2001.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 1996, 1998, 1999 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_INS_2001_H -#define _SUDO_INS_2001_H - - /* - * HAL insults (paraphrased) from 2001. - */ - - "Just what do you think you're doing Dave?", - "It can only be attributed to human error.", - "That's something I cannot allow to happen.", - "My mind is going. I can feel it.", - "Sorry about this, I know it's a bit silly.", - "Take a stress pill and think things over.", - "This mission is too important for me to allow you to jeopardize it.", - "I feel much better now.", - -#endif /* _SUDO_INS_2001_H */ diff --git a/ins_classic.h b/ins_classic.h deleted file mode 100644 index b1942bd..0000000 --- a/ins_classic.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 1996, 1998, 1999 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_INS_CLASSIC_H -#define _SUDO_INS_CLASSIC_H - - /* - * Insults from the original sudo(8). - */ - - "Wrong! You cheating scum!", -#ifdef PC_INSULTS - "And you call yourself a Rocket Scientist!", -#else - "No soap, honkie-lips.", -#endif - "Where did you learn to type?", - "Are you on drugs?", - "My pet ferret can type better than you!", - "You type like i drive.", - "Do you think like you type?", - "Your mind just hasn't been the same since the electro-shock, has it?", - -#endif /* _SUDO_INS_CLASSIC_H */ diff --git a/ins_csops.h b/ins_csops.h deleted file mode 100644 index 20e9b02..0000000 --- a/ins_csops.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 1996, 1998, 1999, 2004 - * 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_INS_CSOPS_H -#define _SUDO_INS_CSOPS_H - - /* - * CSOps insults (may be site dependent). - */ - - "Maybe if you used more than just two fingers...", - "BOB says: You seem to have forgotten your passwd, enter another!", - "stty: unknown mode: doofus", - "I can't hear you -- I'm using the scrambler.", - "The more you drive -- the dumber you get.", -#ifdef PC_INSULTS - "Listen, broccoli brains, I don't have time to listen to this trash.", -#else - "Listen, burrito brains, I don't have time to listen to this trash.", -#endif - "I've seen penguins that can type better than that.", - "Have you considered trying to match wits with a rutabaga?", - "You speak an infinite deal of nothing", - -#endif /* _SUDO_INS_CSOPS_H */ diff --git a/ins_goons.h b/ins_goons.h deleted file mode 100644 index 16a262a..0000000 --- a/ins_goons.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 1996, 1998, 1999 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_INS_GOONS_H -#define _SUDO_INS_GOONS_H - - /* - * Insults from the "Goon Show." - */ - - "You silly, twisted boy you.", - "He has fallen in the water!", - "We'll all be murdered in our beds!", - "You can't come in. Our tiger has got flu", - "I don't wish to know that.", - "What, what, what, what, what, what, what, what, what, what?", - "You can't get the wood, you know.", - "You'll starve!", - "... and it used to be so popular...", - "Pauses for audience applause, not a sausage", - "Hold it up to the light --- not a brain in sight!", - "Have a gorilla...", - "There must be cure for it!", - "There's a lot of it about, you know.", - "You do that again and see what happens...", - "Ying Tong Iddle I Po", - "Harm can come to a young lad like that!", - "And with that remarks folks, the case of the Crown vs yourself was proven.", - "Speak English you fool --- there are no subtitles in this scene.", - "You gotta go owwwww!", - "I have been called worse.", - "It's only your word against mine.", - "I think ... err ... I think ... I think I'll go home", - -#endif /* _SUDO_INS_GOONS_H */ diff --git a/install-sh b/install-sh index 7a207e2..79e7f40 100755 --- a/install-sh +++ b/install-sh @@ -71,7 +71,7 @@ while ${MORETODO} ; do ;; X-b*) BACKIT=true - BACKUP=`expr "$1" : '-b\(.*\)'` + BACKUP="`echo \"$1\" | sed 's/^..//'`" ;; X-c) # backwards compatibility @@ -85,7 +85,7 @@ while ${MORETODO} ; do shift ;; X-g*) - GROUP=`expr "$1" : '-g\(.*\)'` + GROUP="`echo \"$1\" | sed 's/^..//'`" CHGROUPIT=true ;; X-G) @@ -95,7 +95,7 @@ while ${MORETODO} ; do ;; X-G*) if ${ROOT} ; then - GROUP=`expr "$1" : '-g\(.*\)'` + GROUP="`echo \"$1\" | sed 's/^..//'`" CHGROUPIT=true fi ;; @@ -105,7 +105,7 @@ while ${MORETODO} ; do shift ;; X-m*) - MODE=`expr "$1" : '-m\(.*\)'` + MODE="`echo \"$1\" | sed 's/^..//'`" CHMODIT=true ;; X-M) @@ -114,7 +114,7 @@ while ${MORETODO} ; do shift ;; X-M*) - MODE=`expr "$1" : '-m\(.*\)'` + MODE="`echo \"$1\" | sed 's/^..//'`" ${ROOT} && CHMODIT=true ;; X-n) @@ -126,7 +126,7 @@ while ${MORETODO} ; do shift ;; X-o*) - OWNER=`expr "$1" : '-o\(.*\)'` + OWNER="`echo \"$1\" | sed 's/^..//'`" CHOWNIT=true ;; X-O) @@ -136,7 +136,7 @@ while ${MORETODO} ; do ;; X-O*) if ${ROOT} ; then - OWNER=`expr "$1" : '-o\(.*\)'` + OWNER="`echo \"$1\" | sed 's/^..//'`" CHOWNIT=true fi ;; diff --git a/insults.h b/insults.h deleted file mode 100644 index bdb3fc6..0000000 --- a/insults.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 1994-1996, 1998-1999, 2004 - * 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_INSULTS_H -#define _SUDO_INSULTS_H - -#if defined(HAL_INSULTS) || defined(GOONS_INSULTS) || defined(CLASSIC_INSULTS) || defined(CSOPS_INSULTS) - -/* - * Use one or more set of insults as determined by configure - */ - -char *insults[] = { - -# ifdef HAL_INSULTS -# include "ins_2001.h" -# endif - -# ifdef GOONS_INSULTS -# include "ins_goons.h" -# endif - -# ifdef CLASSIC_INSULTS -# include "ins_classic.h" -# endif - -# ifdef CSOPS_INSULTS -# include "ins_csops.h" -# endif - - (char *) 0 - -}; - -/* - * How may I insult you? Let me count the ways... - */ -#define NOFINSULTS (sizeof(insults) / sizeof(insults[0]) - 1) - -/* - * return a pseudo-random insult. - */ -#define INSULT (insults[time(NULL) % NOFINSULTS]) - -#endif /* HAL_INSULTS || GOONS_INSULTS || CLASSIC_INSULTS || CSOPS_INSULTS */ - -#endif /* _SUDO_INSULTS_H */ diff --git a/interfaces.c b/interfaces.c deleted file mode 100644 index 502cb94..0000000 --- a/interfaces.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - */ - -/* - * Suppress a warning w/ gcc on Digital UN*X. - * The system headers should really do this.... - */ -#if defined(__osf__) && !defined(__cplusplus) -struct mbuf; -struct rtentry; -#endif - -#include - -#include -#include -#include -#include -#include -#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF) -# include -#endif -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include -#ifdef _ISC -# include -# include -# include -# define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\ - strioctl.ic_dp=(param);\ - strioctl.ic_timout=0;\ - strioctl.ic_len=(len);} -#endif /* _ISC */ -#ifdef _MIPS -# include -#endif /* _MIPS */ -#include -#include -#include -#ifdef HAVE_GETIFADDRS -# include -#endif - -#include "sudo.h" -#include "interfaces.h" - -/* Minix apparently lacks IFF_LOOPBACK */ -#ifndef IFF_LOOPBACK -# define IFF_LOOPBACK 0 -#endif - -#ifdef HAVE_GETIFADDRS - -/* - * Allocate and fill in the interfaces global variable with the - * machine's ip addresses and netmasks. - */ -void -load_interfaces() -{ - struct ifaddrs *ifa, *ifaddrs; - struct sockaddr_in *sin; -#ifdef HAVE_IN6_ADDR - struct sockaddr_in6 *sin6; -#endif - int i; - - if (getifaddrs(&ifaddrs)) - return; - - /* Allocate space for the interfaces list. */ - for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) { - /* Skip interfaces marked "down" and "loopback". */ - if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) || - ISSET(ifa->ifa_flags, IFF_LOOPBACK)) - continue; - - switch(ifa->ifa_addr->sa_family) { - case AF_INET: -#ifdef HAVE_IN6_ADDR - case AF_INET6: -#endif - num_interfaces++; - break; - } - } - if (num_interfaces == 0) - return; - interfaces = - (struct interface *) emalloc2(num_interfaces, sizeof(struct interface)); - - /* Store the ip addr / netmask pairs. */ - for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) { - /* Skip interfaces marked "down" and "loopback". */ - if (ifa->ifa_addr == NULL || !ISSET(ifa->ifa_flags, IFF_UP) || - ISSET(ifa->ifa_flags, IFF_LOOPBACK)) - continue; - - switch(ifa->ifa_addr->sa_family) { - case AF_INET: - sin = (struct sockaddr_in *)ifa->ifa_addr; - if (sin == NULL) - continue; - memcpy(&interfaces[i].addr, &sin->sin_addr, - sizeof(struct in_addr)); - sin = (struct sockaddr_in *)ifa->ifa_netmask; - if (sin == NULL) - continue; - memcpy(&interfaces[i].netmask, &sin->sin_addr, - sizeof(struct in_addr)); - interfaces[i].family = AF_INET; - i++; - break; -#ifdef HAVE_IN6_ADDR - case AF_INET6: - sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; - if (sin6 == NULL) - continue; - memcpy(&interfaces[i].addr, &sin6->sin6_addr, - sizeof(struct in6_addr)); - sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask; - if (sin6 == NULL) - continue; - memcpy(&interfaces[i].netmask, &sin6->sin6_addr, - sizeof(struct in6_addr)); - interfaces[i].family = AF_INET6; - i++; - break; -#endif /* HAVE_IN6_ADDR */ - } - } -#ifdef HAVE_FREEIFADDRS - freeifaddrs(ifaddrs); -#else - efree(ifaddrs); -#endif -} - -#elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES) - -/* - * Allocate and fill in the interfaces global variable with the - * machine's ip addresses and netmasks. - */ -void -load_interfaces() -{ - struct ifconf *ifconf; - struct ifreq *ifr, ifr_tmp; - struct sockaddr_in *sin; - int sock, n, i; - size_t len = sizeof(struct ifconf) + BUFSIZ; - char *previfname = "", *ifconf_buf = NULL; -#ifdef _ISC - struct strioctl strioctl; -#endif /* _ISC */ - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) - error(1, "cannot open socket"); - - /* - * Get interface configuration or return (leaving num_interfaces == 0) - */ - for (;;) { - ifconf_buf = erealloc(ifconf_buf, len); - ifconf = (struct ifconf *) ifconf_buf; - ifconf->ifc_len = len - sizeof(struct ifconf); - ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf)); - -#ifdef _ISC - STRSET(SIOCGIFCONF, (caddr_t) ifconf, len); - if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) { -#else - /* Note that some kernels return EINVAL if the buffer is too small */ - if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) { -#endif /* _ISC */ - efree(ifconf_buf); - (void) close(sock); - return; - } - - /* Break out of loop if we have a big enough buffer. */ - if (ifconf->ifc_len + sizeof(struct ifreq) < len) - break; - len += BUFSIZ; - } - - /* Allocate space for the maximum number of interfaces that could exist. */ - if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0) - return; - interfaces = (struct interface *) emalloc2(n, sizeof(struct interface)); - - /* For each interface, store the ip address and netmask. */ - for (i = 0; i < ifconf->ifc_len; ) { - /* Get a pointer to the current interface. */ - ifr = (struct ifreq *) &ifconf->ifc_buf[i]; - - /* Set i to the subscript of the next interface. */ - i += sizeof(struct ifreq); -#ifdef HAVE_SA_LEN - if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) - i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); -#endif /* HAVE_SA_LEN */ - - /* Skip duplicates and interfaces with NULL addresses. */ - sin = (struct sockaddr_in *) &ifr->ifr_addr; - if (sin->sin_addr.s_addr == 0 || - strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0) - continue; - - if (ifr->ifr_addr.sa_family != AF_INET) - continue; - -#ifdef SIOCGIFFLAGS - zero_bytes(&ifr_tmp, sizeof(ifr_tmp)); - strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); - if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0) -#endif - ifr_tmp = *ifr; - - /* Skip interfaces marked "down" and "loopback". */ - if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) || - ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK)) - continue; - - sin = (struct sockaddr_in *) &ifr->ifr_addr; - interfaces[num_interfaces].addr.ip4.s_addr = sin->sin_addr.s_addr; - - /* Stash the name of the interface we saved. */ - previfname = ifr->ifr_name; - - /* Get the netmask. */ - zero_bytes(&ifr_tmp, sizeof(ifr_tmp)); - strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); -#ifdef SIOCGIFNETMASK -#ifdef _ISC - STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp)); - if (ioctl(sock, I_STR, (caddr_t) &strioctl) == 0) { -#else - if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) == 0) { -#endif /* _ISC */ - sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr; - - interfaces[num_interfaces].netmask.ip4.s_addr = sin->sin_addr.s_addr; - } else { -#else - { -#endif /* SIOCGIFNETMASK */ - if (IN_CLASSC(interfaces[num_interfaces].addr.ip4.s_addr)) - interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSC_NET); - else if (IN_CLASSB(interfaces[num_interfaces].addr.ip4.s_addr)) - interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSB_NET); - else - interfaces[num_interfaces].netmask.ip4.s_addr = htonl(IN_CLASSA_NET); - } - - /* Only now can we be sure it was a good/interesting interface. */ - interfaces[num_interfaces].family = AF_INET; - num_interfaces++; - } - - /* If the expected size < real size, realloc the array. */ - if (n != num_interfaces) { - if (num_interfaces != 0) - interfaces = (struct interface *) erealloc3(interfaces, - num_interfaces, sizeof(struct interface)); - else - efree(interfaces); - } - efree(ifconf_buf); - (void) close(sock); -} - -#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */ - -/* - * Stub function for those without SIOCGIFCONF - */ -void -load_interfaces() -{ - return; -} - -#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */ - -void -dump_interfaces() -{ - int i; -#ifdef HAVE_IN6_ADDR - char addrbuf[INET6_ADDRSTRLEN], maskbuf[INET6_ADDRSTRLEN]; -#endif - - puts("Local IP address and netmask pairs:"); - for (i = 0; i < num_interfaces; i++) { - switch(interfaces[i].family) { - case AF_INET: - printf("\t%s / ", inet_ntoa(interfaces[i].addr.ip4)); - puts(inet_ntoa(interfaces[i].netmask.ip4)); - break; -#ifdef HAVE_IN6_ADDR - case AF_INET6: - inet_ntop(AF_INET6, &interfaces[i].addr.ip6, - addrbuf, sizeof(addrbuf)); - inet_ntop(AF_INET6, &interfaces[i].netmask.ip6, - maskbuf, sizeof(maskbuf)); - printf("\t%s / %s\n", addrbuf, maskbuf); - break; -#endif /* HAVE_IN6_ADDR */ - } - } -} diff --git a/interfaces.h b/interfaces.h deleted file mode 100644 index 06b0b85..0000000 --- a/interfaces.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007 - * 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_INTERFACES_H -#define _SUDO_INTERFACES_H - -/* - * Union to hold either strucr in_addr or in6_add - */ -union sudo_in_addr_un { - struct in_addr ip4; -#ifdef HAVE_IN6_ADDR - struct in6_addr ip6; -#endif -}; - -/* - * IP address and netmask pairs for checking against local interfaces. - */ -struct interface { - int family; /* AF_INET or AF_INET6 */ - union sudo_in_addr_un addr; - union sudo_in_addr_un netmask; -}; - -/* - * Prototypes for external functions. - */ -void load_interfaces __P((void)); -void dump_interfaces __P((void)); - -/* - * Definitions for external variables. - */ -#ifndef _SUDO_MAIN -extern struct interface *interfaces; -extern int num_interfaces; -#endif - -#endif /* _SUDO_INTERFACES_H */ diff --git a/iolog.c b/iolog.c deleted file mode 100644 index 4e492b6..0000000 --- a/iolog.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#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 TIME_WITH_SYS_TIME -# include -#endif -#include -#include -#include -#include -#include -#ifdef HAVE_ZLIB_H -# include -#endif - -#include "sudo.h" - -union io_fd { - FILE *f; -#ifdef HAVE_ZLIB_H - gzFile g; -#endif - void *v; -}; - -struct script_buf { - int len; /* buffer length (how much read in) */ - int off; /* write position (how much already consumed) */ - char buf[16 * 1024]; -}; - -#define IOFD_STDIN 0 -#define IOFD_STDOUT 1 -#define IOFD_STDERR 2 -#define IOFD_TTYIN 3 -#define IOFD_TTYOUT 4 -#define IOFD_TIMING 5 -#define IOFD_MAX 6 - -#ifdef __STDC__ -# define SESSID_MAX 2176782336U -#else -# define SESSID_MAX (unsigned long)2176782336 -#endif - -static sigset_t ttyblock; -static struct timeval last_time; -static union io_fd io_fds[IOFD_MAX]; - -void -io_nextid() -{ - struct stat sb; - char buf[32], *ep; - int fd, i, ch; - unsigned long id = 0; - int len; - ssize_t nread; - char pathbuf[PATH_MAX]; - - /* - * Create _PATH_SUDO_IO_LOGDIR 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); - } 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); - } - - /* - * Open sequence file - */ - len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", _PATH_SUDO_IO_LOGDIR); - if (len <= 0 || len >= sizeof(pathbuf)) { - errno = ENAMETOOLONG; - log_error(USE_ERRNO, "%s/seq", pathbuf); - } - fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); - if (fd == -1) - log_error(USE_ERRNO, "cannot open %s", pathbuf); - lock_file(fd, SUDO_LOCK); - - /* Read seq number (base 36). */ - nread = read(fd, buf, sizeof(buf)); - if (nread != 0) { - if (nread == -1) - log_error(USE_ERRNO, "cannot read %s", pathbuf); - id = strtoul(buf, &ep, 36); - if (buf == ep || id >= SESSID_MAX) - log_error(0, "invalid sequence number %s", pathbuf); - } - id++; - - /* - * Convert id to a string and stash in sudo_user.sessid. - * Note that that least significant digits go at the end of the string. - */ - for (i = 5; i >= 0; i--) { - ch = id % 36; - id /= 36; - buf[i] = ch < 10 ? ch + '0' : ch - 10 + 'A'; - } - buf[6] = '\n'; - - /* Stash id logging purposes */ - memcpy(sudo_user.sessid, buf, 6); - sudo_user.sessid[6] = '\0'; - - /* Rewind and overwrite old seq file. */ - if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7) - log_error(USE_ERRNO, "Can't write to %s", pathbuf); - close(fd); -} - -static int -build_idpath(pathbuf, pathsize) - char *pathbuf; - size_t pathsize; -{ - struct stat sb; - int i, len; - - if (sudo_user.sessid[0] == '\0') - log_error(0, "tried to build a session id path without a session id"); - - /* - * Path is of the form /var/log/sudo-session/00/00/01. - */ - len = snprintf(pathbuf, pathsize, "%s/%c%c/%c%c/%c%c", _PATH_SUDO_IO_LOGDIR, - 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); - } - - /* - * Create the intermediate subdirs as needed. - */ - for (i = 6; i > 0; i -= 3) { - pathbuf[len - i] = '\0'; - if (stat(pathbuf, &sb) != 0) { - if (mkdir(pathbuf, S_IRWXU) != 0) - log_error(USE_ERRNO, "Can't mkdir %s", pathbuf); - } else if (!S_ISDIR(sb.st_mode)) { - log_error(0, "%s: %s", pathbuf, strerror(ENOTDIR)); - } - pathbuf[len - i] = '/'; - } - - return(len); -} - -static void * -open_io_fd(pathbuf, len, suffix, docompress) - char *pathbuf; - int len; - const char *suffix; - int docompress; -{ - void *vfd = NULL; - int fd; - - pathbuf[len] = '\0'; - strlcat(pathbuf, suffix, PATH_MAX); - fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); - if (fd != -1) { - fcntl(fd, F_SETFD, FD_CLOEXEC); -#ifdef HAVE_ZLIB_H - if (docompress) - vfd = gzdopen(fd, "w"); - else -#endif - vfd = fdopen(fd, "w"); - } - return vfd; -} - -int -io_log_open() -{ - char pathbuf[PATH_MAX]; - FILE *io_logfile; - int len; - - if (!def_log_input && !def_log_output) - return FALSE; - - /* - * Build a path containing the session id split into two-digit subdirs, - * so ID 000001 becomes /var/log/sudo-session/00/00/01. - */ - len = build_idpath(pathbuf, sizeof(pathbuf)); - if (len == -1) - return -1; - - if (mkdir(pathbuf, S_IRUSR|S_IWUSR|S_IXUSR) != 0) - log_error(USE_ERRNO, "Can't mkdir %s", pathbuf); - - /* - * We create 7 files: a log file, a timing file and 5 for input/output. - */ - io_logfile = open_io_fd(pathbuf, len, "/log", FALSE); - if (io_logfile == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - - io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", def_compress_io); - if (io_fds[IOFD_TIMING].v == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - - if (def_log_input) { - io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", def_compress_io); - if (io_fds[IOFD_TTYIN].v == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - } - - if (def_log_output) { - io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", def_compress_io); - if (io_fds[IOFD_TTYOUT].v == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - } - - if (def_log_input) { - io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", def_compress_io); - if (io_fds[IOFD_STDIN].v == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - } - - if (def_log_output) { - io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", def_compress_io); - if (io_fds[IOFD_STDOUT].v == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - } - - if (def_log_output) { - io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", def_compress_io); - if (io_fds[IOFD_STDERR].v == NULL) - log_error(USE_ERRNO, "Can't create %s", pathbuf); - } - - /* So we can block tty-generated signals */ - sigemptyset(&ttyblock); - sigaddset(&ttyblock, SIGINT); - sigaddset(&ttyblock, SIGQUIT); - sigaddset(&ttyblock, SIGTSTP); - sigaddset(&ttyblock, SIGTTIN); - sigaddset(&ttyblock, SIGTTOU); - - gettimeofday(&last_time, NULL); - - /* XXX - log more stuff? window size? environment? */ - fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec, user_name, - runas_pw->pw_name, runas_gr ? runas_gr->gr_name : "", user_tty); - fprintf(io_logfile, "%s\n", user_cwd); - fprintf(io_logfile, "%s%s%s\n", user_cmnd, user_args ? " " : "", - user_args ? user_args : ""); - fclose(io_logfile); - - return TRUE; -} - -void -io_log_close() -{ - int i; - - for (i = 0; i < IOFD_MAX; i++) { - if (io_fds[i].v == NULL) - continue; -#ifdef HAVE_ZLIB_H - if (def_compress_io) - gzclose(io_fds[i].g); - else -#endif - fclose(io_fds[i].f); - } -} - -static int -log_io(buf, len, idx) - const char *buf; - unsigned int len; - int idx; -{ - struct timeval now, delay; - sigset_t omask; - - gettimeofday(&now, NULL); - - sigprocmask(SIG_BLOCK, &ttyblock, &omask); - -#ifdef HAVE_ZLIB_H - if (def_compress_io) - gzwrite(io_fds[idx].g, buf, len); - else -#endif - fwrite(buf, 1, len, io_fds[idx].f); - delay.tv_sec = now.tv_sec; - delay.tv_usec = now.tv_usec; - timevalsub(&delay, &last_time); -#ifdef HAVE_ZLIB_H - if (def_compress_io) - gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx, - delay.tv_sec + ((double)delay.tv_usec / 1000000), len); - else -#endif - fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx, - delay.tv_sec + ((double)delay.tv_usec / 1000000), len); - last_time.tv_sec = now.tv_sec; - last_time.tv_usec = now.tv_usec; - - sigprocmask(SIG_SETMASK, &omask, NULL); - - return TRUE; -} - -int -log_ttyin(buf, len) - const char *buf; - unsigned int len; -{ - if (!io_fds[IOFD_TTYIN].v) - return TRUE; - return log_io(buf, len, IOFD_TTYIN); -} - -int -log_ttyout(buf, len) - const char *buf; - unsigned int len; -{ - if (!io_fds[IOFD_TTYOUT].v) - return TRUE; - return log_io(buf, len, IOFD_TTYOUT); -} - -int -log_stdin(buf, len) - const char *buf; - unsigned int len; -{ - if (!io_fds[IOFD_STDIN].v) - return TRUE; - return log_io(buf, len, IOFD_STDIN); -} - -int -log_stdout(buf, len) - const char *buf; - unsigned int len; -{ - if (!io_fds[IOFD_STDOUT].v) - return TRUE; - return log_io(buf, len, IOFD_STDOUT); -} - -int -log_stderr(buf, len) - const char *buf; - unsigned int len; -{ - if (!io_fds[IOFD_STDOUT].v) - return TRUE; - return log_io(buf, len, IOFD_STDERR); -} diff --git a/isblank.c b/isblank.c deleted file mode 100644 index e6ad58d..0000000 --- a/isblank.c +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2008 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. - */ - -#include -#include - -#undef isblank -int -isblank(ch) - int ch; -{ - return(ch == ' ' || ch == '\t'); -} diff --git a/lbuf.c b/lbuf.c deleted file mode 100644 index bd218da..0000000 --- a/lbuf.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (c) 2007-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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#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 */ -#include -#ifdef HAVE_TERMIOS_H -# include -#else -# ifdef HAVE_TERMIO_H -# include -# endif -#endif - -#include "sudo.h" -#include "lbuf.h" - -#if !defined(TIOCGSIZE) && defined(TIOCGWINSZ) -# define TIOCGSIZE TIOCGWINSZ -# define ttysize winsize -# define ts_cols ws_col -#endif - -int -get_ttycols() -{ - char *p; - int cols; -#ifdef TIOCGSIZE - struct ttysize win; - - if (ioctl(STDERR_FILENO, TIOCGSIZE, &win) == 0 && win.ts_cols != 0) - return((int)win.ts_cols); -#endif - - /* Fall back on $COLUMNS. */ - if ((p = getenv("COLUMNS")) == NULL || (cols = atoi(p)) <= 0) - cols = 80; - return(cols); -} - -void -lbuf_init(lbuf, output, indent, continuation) - struct lbuf *lbuf; - int (*output)__P((const char *)); - int indent; - const char *continuation; -{ - lbuf->output = output; - lbuf->continuation = continuation; - lbuf->indent = indent; - lbuf->cols = get_ttycols(); - lbuf->len = 0; - lbuf->size = 0; - lbuf->buf = NULL; -} - -void -lbuf_destroy(lbuf) - struct lbuf *lbuf; -{ - efree(lbuf->buf); - lbuf->buf = NULL; -} - -/* - * Append strings to the buffer, expanding it as needed. - */ -void -#ifdef __STDC__ -lbuf_append_quoted(struct lbuf *lbuf, const char *set, ...) -#else -lbuf_append_quoted(lbuf, set, va_alist) - struct lbuf *lbuf; - const char *set; - va_dcl -#endif -{ - va_list ap; - int len = 0; - char *cp, *s; - -#ifdef __STDC__ - va_start(ap, set); -#else - va_start(ap); -#endif - while ((s = va_arg(ap, char *)) != NULL) { - len += strlen(s); - for (cp = s; (cp = strpbrk(cp, set)) != NULL; cp++) - len++; - } - va_end(ap); - - /* Expand buffer as needed. */ - if (lbuf->len + len >= lbuf->size) { - do { - lbuf->size += 256; - } while (lbuf->len + len >= lbuf->size); - lbuf->buf = erealloc(lbuf->buf, lbuf->size); - } - -#ifdef __STDC__ - va_start(ap, set); -#else - va_start(ap); -#endif - /* Append each string. */ - while ((s = va_arg(ap, char *)) != NULL) { - while ((cp = strpbrk(s, set)) != NULL) { - len = (int)(cp - s); - memcpy(lbuf->buf + lbuf->len, s, len); - lbuf->len += len; - lbuf->buf[lbuf->len++] = '\\'; - lbuf->buf[lbuf->len++] = *cp; - s = cp + 1; - } - if (*s != '\0') { - len = strlen(s); - memcpy(lbuf->buf + lbuf->len, s, len); - lbuf->len += len; - } - } - lbuf->buf[lbuf->len] = '\0'; - va_end(ap); -} - -/* - * Append strings to the buffer, expanding it as needed. - */ -void -#ifdef __STDC__ -lbuf_append(struct lbuf *lbuf, ...) -#else -lbuf_append(lbuf, va_alist) - struct lbuf *lbuf; - va_dcl -#endif -{ - va_list ap; - int len = 0; - char *s; - -#ifdef __STDC__ - va_start(ap, lbuf); -#else - va_start(ap); -#endif - while ((s = va_arg(ap, char *)) != NULL) - len += strlen(s); - va_end(ap); - - /* Expand buffer as needed. */ - if (lbuf->len + len >= lbuf->size) { - do { - lbuf->size += 256; - } while (lbuf->len + len >= lbuf->size); - lbuf->buf = erealloc(lbuf->buf, lbuf->size); - } - -#ifdef __STDC__ - va_start(ap, lbuf); -#else - va_start(ap); -#endif - /* Append each string. */ - while ((s = va_arg(ap, char *)) != NULL) { - len = strlen(s); - memcpy(lbuf->buf + lbuf->len, s, len); - lbuf->len += len; - } - lbuf->buf[lbuf->len] = '\0'; - va_end(ap); -} - -static void -lbuf_println(lbuf, line, len) - struct lbuf *lbuf; - char *line; - int len; -{ - char *cp, save; - int i, have, contlen; - - contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0; - - /* - * Print the buffer, splitting the line as needed on a word - * boundary. - */ - cp = line; - have = lbuf->cols; - while (cp != NULL && *cp != '\0') { - char *ep = NULL; - int need = len - (int)(cp - line); - - if (need > have) { - have -= contlen; /* subtract for continuation char */ - if ((ep = memrchr(cp, ' ', have)) == NULL) - ep = memchr(cp + have, ' ', need - have); - if (ep != NULL) - need = (int)(ep - cp); - } - if (cp != line) { - /* indent continued lines */ - /* XXX - build up string instead? */ - for (i = 0; i < lbuf->indent; i++) - lbuf->output(" "); - } - /* NUL-terminate cp for the output function and restore afterwards */ - save = cp[need]; - cp[need] = '\0'; - lbuf->output(cp); - cp[need] = save; - cp = ep; - - /* - * If there is more to print, reset have, incremement cp past - * the whitespace, and print a line continuaton char if needed. - */ - if (cp != NULL) { - have = lbuf->cols - lbuf->indent; - ep = line + len; - while (cp < ep && isblank((unsigned char)*cp)) { - cp++; - } - if (contlen) - lbuf->output(lbuf->continuation); - } - lbuf->output("\n"); - } -} - -/* - * Print the buffer with word wrap based on the tty width. - * The lbuf is reset on return. - */ -void -lbuf_print(lbuf) - struct lbuf *lbuf; -{ - char *cp, *ep; - int len, contlen; - - contlen = lbuf->continuation ? strlen(lbuf->continuation) : 0; - - /* For very small widths just give up... */ - if (lbuf->cols <= lbuf->indent + contlen + 20) { - lbuf->output(lbuf->buf); - lbuf->output("\n"); - goto done; - } - - /* Print each line in the buffer */ - for (cp = lbuf->buf; cp != NULL && *cp != '\0'; ) { - if (*cp == '\n') { - 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); - cp = ep ? ep + 1 : NULL; - } - } - -done: - lbuf->len = 0; /* reset the buffer for re-use. */ -} diff --git a/lbuf.h b/lbuf.h deleted file mode 100644 index db6f964..0000000 --- a/lbuf.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2007, 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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SUDO_LBUF_H -#define _SUDO_LBUF_H - -/* - * Line buffer struct. - */ -struct lbuf { - int (*output)__P((const char *)); - char *buf; - const char *continuation; - int indent; - int len; - int size; - int cols; -}; - -int get_ttycols __P((void)); -void lbuf_append __P((struct lbuf *, ...)); -void lbuf_append_quoted __P((struct lbuf *, const char *, ...)); -void lbuf_destroy __P((struct lbuf *)); -void lbuf_init __P((struct lbuf *, int (*)(const char *), int, const char *)); -void lbuf_print __P((struct lbuf *)); - -#endif /* _SUDO_LBUF_H */ diff --git a/ldap.c b/ldap.c deleted file mode 100644 index 81d3c40..0000000 --- a/ldap.c +++ /dev/null @@ -1,2049 +0,0 @@ -/* - * Copyright (c) 2003-2010 Todd C. Miller - * - * This code is derived from software contributed by Aaron Spangler. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include -#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 */ -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include -#include -#include -#include -#include -#ifdef HAVE_LBER_H -# include -#endif -#include -#if defined(HAVE_LDAP_SSL_H) -# include -#elif defined(HAVE_MPS_LDAP_SSL_H) -# include -#endif -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S -# ifdef HAVE_SASL_SASL_H -# include -# else -# include -# endif -# if HAVE_GSS_KRB5_CCACHE_NAME -# if defined(HAVE_GSSAPI_GSSAPI_KRB5_H) -# include -# include -# elif defined(HAVE_GSSAPI_GSSAPI_H) -# include -# else -# include -# endif -# endif -#endif - -#include "sudo.h" -#include "parse.h" -#include "lbuf.h" - -#ifndef LDAP_OPT_SUCCESS -# define LDAP_OPT_SUCCESS LDAP_SUCCESS -#endif - -#ifndef LDAPS_PORT -# define LDAPS_PORT 636 -#endif - -#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET) -# define LDAP_SASL_QUIET 0 -#endif - -#ifndef HAVE_LDAP_UNBIND_EXT_S -#define ldap_unbind_ext_s(a, b, c) ldap_unbind_s(a) -#endif - -#ifndef HAVE_LDAP_SEARCH_EXT_S -#define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k) \ - ldap_search_s(a, b, c, d, e, f, k) -#endif - -#define LDAP_FOREACH(var, ld, res) \ - for ((var) = ldap_first_entry((ld), (res)); \ - (var) != NULL; \ - (var) = ldap_next_entry((ld), (var))) - -#define DPRINTF(args, level) if (ldap_conf.debug >= level) warningx args - -#define CONF_BOOL 0 -#define CONF_INT 1 -#define CONF_STR 2 -#define CONF_LIST_STR 4 - -#define SUDO_LDAP_SSL 1 -#define SUDO_LDAP_STARTTLS 2 - -struct ldap_config_table { - const char *conf_str; /* config file string */ - short type; /* CONF_BOOL, CONF_INT, CONF_STR */ - short connected; /* connection-specific value? */ - int opt_val; /* LDAP_OPT_* (or -1 for sudo internal) */ - void *valp; /* pointer into ldap_conf */ -}; - -struct ldap_config_list_str { - struct ldap_config_list_str *next; - char val[1]; -}; - -/* ldap configuration structure */ -static struct ldap_config { - int port; - int version; - int debug; - int ldap_debug; - int tls_checkpeer; - int timelimit; - int bind_timelimit; - int use_sasl; - int rootuse_sasl; - int ssl_mode; - char *host; - struct ldap_config_list_str *uri; - char *binddn; - char *bindpw; - char *rootbinddn; - struct ldap_config_list_str *base; - char *ssl; - char *tls_cacertfile; - char *tls_cacertdir; - char *tls_random_file; - char *tls_cipher_suite; - char *tls_certfile; - char *tls_keyfile; - char *sasl_auth_id; - char *rootsasl_auth_id; - char *sasl_secprops; - char *krb5_ccname; -} ldap_conf; - -static struct ldap_config_table ldap_conf_table[] = { - { "sudoers_debug", CONF_INT, FALSE, -1, &ldap_conf.debug }, - { "host", CONF_STR, FALSE, -1, &ldap_conf.host }, - { "port", CONF_INT, FALSE, -1, &ldap_conf.port }, - { "ssl", CONF_STR, FALSE, -1, &ldap_conf.ssl }, - { "sslpath", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile }, - { "uri", CONF_LIST_STR, FALSE, -1, &ldap_conf.uri }, -#ifdef LDAP_OPT_DEBUG_LEVEL - { "debug", CONF_INT, FALSE, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug }, -#endif -#ifdef LDAP_OPT_PROTOCOL_VERSION - { "ldap_version", CONF_INT, TRUE, LDAP_OPT_PROTOCOL_VERSION, - &ldap_conf.version }, -#endif -#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT - { "tls_checkpeer", CONF_BOOL, FALSE, LDAP_OPT_X_TLS_REQUIRE_CERT, - &ldap_conf.tls_checkpeer }, -#else - { "tls_checkpeer", CONF_BOOL, FALSE, -1, &ldap_conf.tls_checkpeer }, -#endif -#ifdef LDAP_OPT_X_TLS_CACERTFILE - { "tls_cacertfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE, - &ldap_conf.tls_cacertfile }, - { "tls_cacert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTFILE, - &ldap_conf.tls_cacertfile }, -#endif -#ifdef LDAP_OPT_X_TLS_CACERTDIR - { "tls_cacertdir", CONF_STR, FALSE, LDAP_OPT_X_TLS_CACERTDIR, - &ldap_conf.tls_cacertdir }, -#endif -#ifdef LDAP_OPT_X_TLS_RANDOM_FILE - { "tls_randfile", CONF_STR, FALSE, LDAP_OPT_X_TLS_RANDOM_FILE, - &ldap_conf.tls_random_file }, -#endif -#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE - { "tls_ciphers", CONF_STR, FALSE, LDAP_OPT_X_TLS_CIPHER_SUITE, - &ldap_conf.tls_cipher_suite }, -#endif -#ifdef LDAP_OPT_X_TLS_CERTFILE - { "tls_cert", CONF_STR, FALSE, LDAP_OPT_X_TLS_CERTFILE, - &ldap_conf.tls_certfile }, -#else - { "tls_cert", CONF_STR, FALSE, -1, &ldap_conf.tls_certfile }, -#endif -#ifdef LDAP_OPT_X_TLS_KEYFILE - { "tls_key", CONF_STR, FALSE, LDAP_OPT_X_TLS_KEYFILE, - &ldap_conf.tls_keyfile }, -#else - { "tls_key", CONF_STR, FALSE, -1, &ldap_conf.tls_keyfile }, -#endif -#ifdef LDAP_OPT_NETWORK_TIMEOUT - { "bind_timelimit", CONF_INT, TRUE, -1 /* needs timeval, set manually */, - &ldap_conf.bind_timelimit }, -#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT) - { "bind_timelimit", CONF_INT, TRUE, LDAP_X_OPT_CONNECT_TIMEOUT, - &ldap_conf.bind_timelimit }, -#endif - { "timelimit", CONF_INT, TRUE, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit }, - { "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 }, -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S - { "use_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.use_sasl }, - { "sasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.sasl_auth_id }, - { "rootuse_sasl", CONF_BOOL, FALSE, -1, &ldap_conf.rootuse_sasl }, - { "rootsasl_auth_id", CONF_STR, FALSE, -1, &ldap_conf.rootsasl_auth_id }, -# ifdef LDAP_OPT_X_SASL_SECPROPS - { "sasl_secprops", CONF_STR, TRUE, LDAP_OPT_X_SASL_SECPROPS, - &ldap_conf.sasl_secprops }, -# endif - { "krb5_ccname", CONF_STR, FALSE, -1, &ldap_conf.krb5_ccname }, -#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ - { NULL } -}; - -/* sudo_nss implementation */ -static int sudo_ldap_open __P((struct sudo_nss *nss)); -static int sudo_ldap_close __P((struct sudo_nss *nss)); -static int sudo_ldap_parse __P((struct sudo_nss *nss)); -static int sudo_ldap_setdefs __P((struct sudo_nss *nss)); -static int sudo_ldap_lookup __P((struct sudo_nss *nss, int ret, int pwflag)); -static int sudo_ldap_display_cmnd __P((struct sudo_nss *nss, - struct passwd *pw)); -static int sudo_ldap_display_defaults __P((struct sudo_nss *nss, - struct passwd *pw, struct lbuf *lbuf)); -static int sudo_ldap_display_bound_defaults __P((struct sudo_nss *nss, - struct passwd *pw, struct lbuf *lbuf)); -static int sudo_ldap_display_privs __P((struct sudo_nss *nss, - struct passwd *pw, struct lbuf *lbuf)); - -struct sudo_nss sudo_nss_ldap = { - &sudo_nss_ldap, - NULL, - sudo_ldap_open, - sudo_ldap_close, - sudo_ldap_parse, - sudo_ldap_setdefs, - sudo_ldap_lookup, - sudo_ldap_display_cmnd, - sudo_ldap_display_defaults, - sudo_ldap_display_bound_defaults, - sudo_ldap_display_privs -}; - -#ifdef HAVE_LDAP_CREATE -/* - * Rebuild the hosts list and include a specific port for each host. - * ldap_create() does not take a default port parameter so we must - * append one if we want something other than LDAP_PORT. - */ -static void -sudo_ldap_conf_add_ports() -{ - - char *host, *port, defport[13]; - char hostbuf[LINE_MAX * 2]; - - hostbuf[0] = '\0'; - if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport)) - errorx(1, "sudo_ldap_conf_add_ports: port too large"); - - for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) { - if (hostbuf[0] != '\0') { - if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - } - - if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - /* Append port if there is not one already. */ - if ((port = strrchr(host, ':')) == NULL || - !isdigit((unsigned char)port[1])) { - if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - } - } - - free(ldap_conf.host); - ldap_conf.host = estrdup(hostbuf); - return; - -toobig: - errorx(1, "sudo_ldap_conf_add_ports: out of space expanding hostbuf"); -} -#endif - -#ifndef HAVE_LDAP_INITIALIZE -/* - * For each uri, convert to host:port pairs. For ldaps:// enable SSL - * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/ - * where the trailing slash is optional. - */ -static int -sudo_ldap_parse_uri(uri_list) - const struct ldap_config_list_str *uri_list; -{ - char *buf, *uri, *host, *cp, *port; - char hostbuf[LINE_MAX]; - int nldap = 0, nldaps = 0; - int rc = -1; - - do { - buf = estrdup(uri_list->val); - hostbuf[0] = '\0'; - for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) { - if (strncasecmp(uri, "ldap://", 7) == 0) { - nldap++; - host = uri + 7; - } else if (strncasecmp(uri, "ldaps://", 8) == 0) { - nldaps++; - host = uri + 8; - } else { - warningx("unsupported LDAP uri type: %s", uri); - goto done; - } - - /* trim optional trailing slash */ - if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') { - *cp = '\0'; - } - - if (hostbuf[0] != '\0') { - if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - } - - if (*host == '\0') - host = "localhost"; /* no host specified, use localhost */ - - if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - - /* If using SSL and no port specified, add port 636 */ - if (nldaps) { - if ((port = strrchr(host, ':')) == NULL || - !isdigit((unsigned char)port[1])) - if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf)) - goto toobig; - } - } - if (hostbuf[0] == '\0') { - warningx("invalid uri: %s", uri_list); - goto done; - } - - if (nldaps != 0) { - if (nldap != 0) { - warningx("cannot mix ldap and ldaps URIs"); - goto done; - } - if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { - warningx("cannot mix ldaps and starttls"); - goto done; - } - ldap_conf.ssl_mode = SUDO_LDAP_SSL; - } - - free(ldap_conf.host); - ldap_conf.host = estrdup(hostbuf); - efree(buf); - } while ((uri_list = uri_list->next)); - - buf = NULL; - rc = 0; - -done: - efree(buf); - return(rc); - -toobig: - errorx(1, "sudo_ldap_parse_uri: out of space building hostbuf"); -} -#else -static char * -sudo_ldap_join_uri(uri_list) - struct ldap_config_list_str *uri_list; -{ - struct ldap_config_list_str *uri; - size_t len = 0; - char *buf, *cp; - - /* Usually just a single entry. */ - if (uri_list->next == NULL) - return(estrdup(uri_list->val)); - - for (uri = uri_list; uri != NULL; uri = uri->next) { - len += strlen(uri->val) + 1; - } - buf = cp = emalloc(len); - buf[0] = '\0'; - for (uri = uri_list; uri != NULL; uri = uri->next) { - cp += strlcpy(cp, uri->val, len - (cp - buf)); - *cp++ = ' '; - } - cp[-1] = '\0'; - return(buf); -} -#endif /* HAVE_LDAP_INITIALIZE */ - -static int -sudo_ldap_init(ldp, host, port) - LDAP **ldp; - const char *host; - int port; -{ - LDAP *ld = NULL; - int rc = LDAP_CONNECT_ERROR; - -#ifdef HAVE_LDAPSSL_INIT - if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) { - DPRINTF(("ldapssl_clientauth_init(%s, %s)", - ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL", - ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2); - rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL, - ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL); - /* - * Mozilla-derived SDKs have a bug starting with version 5.0 - * where the path can no longer be a file name and must be a dir. - */ - if (rc != LDAP_SUCCESS) { - char *cp; - if (ldap_conf.tls_certfile) { - cp = strrchr(ldap_conf.tls_certfile, '/'); - if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0) - *cp = '\0'; - } - if (ldap_conf.tls_keyfile) { - cp = strrchr(ldap_conf.tls_keyfile, '/'); - if (cp != NULL && strncmp(cp + 1, "key", 3) == 0) - *cp = '\0'; - } - DPRINTF(("ldapssl_clientauth_init(%s, %s)", - ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL", - ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2); - rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL, - ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL); - if (rc != LDAP_SUCCESS) { - warningx("unable to initialize SSL cert and key db: %s", - ldapssl_err2string(rc)); - goto done; - } - } - - DPRINTF(("ldapssl_init(%s, %d, 1)", host, port), 2); - if ((ld = ldapssl_init(host, port, 1)) != NULL) - rc = LDAP_SUCCESS; - } else -#endif - { -#ifdef HAVE_LDAP_CREATE - DPRINTF(("ldap_create()"), 2); - if ((rc = ldap_create(&ld)) != LDAP_SUCCESS) - goto done; - DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2); - rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host); -#else - DPRINTF(("ldap_init(%s, %d)", host, port), 2); - if ((ld = ldap_init(host, port)) != NULL) - rc = LDAP_SUCCESS; -#endif - } - -done: - *ldp = ld; - return(rc); -} - -/* - * Walk through search results and return TRUE if we have a matching - * netgroup, else FALSE. - */ -static int -sudo_ldap_check_user_netgroup(ld, entry, user) - LDAP *ld; - LDAPMessage *entry; - char *user; -{ - struct berval **bv, **p; - char *val; - int ret = FALSE; - - if (!entry) - return(ret); - - /* get the values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoUser"); - if (bv == NULL) - return(ret); - - /* walk through values */ - for (p = bv; *p != NULL && !ret; p++) { - val = (*p)->bv_val; - /* match any */ - if (netgr_matches(val, NULL, NULL, user)) - ret = TRUE; - DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val, - ret ? "MATCH!" : "not"), 2); - } - - ldap_value_free_len(bv); /* cleanup */ - - return(ret); -} - -/* - * Walk through search results and return TRUE if we have a - * host match, else FALSE. - */ -static int -sudo_ldap_check_host(ld, entry) - LDAP *ld; - LDAPMessage *entry; -{ - struct berval **bv, **p; - char *val; - int ret = FALSE; - - if (!entry) - return(ret); - - /* get the values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoHost"); - if (bv == NULL) - return(ret); - - /* walk through values */ - for (p = bv; *p != NULL && !ret; p++) { - val = (*p)->bv_val; - /* match any or address or netgroup or hostname */ - if (!strcmp(val, "ALL") || addr_matches(val) || - netgr_matches(val, user_host, user_shost, NULL) || - hostname_matches(user_shost, user_host, val)) - ret = TRUE; - DPRINTF(("ldap sudoHost '%s' ... %s", val, - ret ? "MATCH!" : "not"), 2); - } - - ldap_value_free_len(bv); /* cleanup */ - - return(ret); -} - -static int -sudo_ldap_check_runas_user(ld, entry) - LDAP *ld; - LDAPMessage *entry; -{ - struct berval **bv, **p; - char *val; - int ret = FALSE; - - if (!runas_pw) - return(UNSPEC); - - /* get the runas user from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); - if (bv == NULL) - bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */ - - /* - * BUG: - * - * if runas is not specified on the command line, the only information - * as to which user to run as is in the runas_default option. We should - * check to see if we have the local option present. Unfortunately we - * don't parse these options until after this routine says yes or no. - * The query has already returned, so we could peek at the attribute - * values here though. - * - * For now just require users to always use -u option unless its set - * in the global defaults. This behaviour is no different than the global - * /etc/sudoers. - * - * Sigh - maybe add this feature later - */ - - /* - * If there are no runas entries, match runas_default against - * what the user specified on the command line. - */ - if (bv == NULL) - return(!strcasecmp(runas_pw->pw_name, def_runas_default)); - - /* walk through values returned, looking for a match */ - for (p = bv; *p != NULL && !ret; p++) { - val = (*p)->bv_val; - switch (val[0]) { - case '+': - if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) - ret = TRUE; - break; - case '%': - if (usergr_matches(val, runas_pw->pw_name, runas_pw)) - ret = TRUE; - break; - case 'A': - if (strcmp(val, "ALL") == 0) { - ret = TRUE; - break; - } - /* FALLTHROUGH */ - default: - if (strcasecmp(val, runas_pw->pw_name) == 0) - ret = TRUE; - break; - } - DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val, - ret ? "MATCH!" : "not"), 2); - } - - ldap_value_free_len(bv); /* cleanup */ - - return(ret); -} - -static int -sudo_ldap_check_runas_group(ld, entry) - LDAP *ld; - LDAPMessage *entry; -{ - struct berval **bv, **p; - char *val; - int ret = FALSE; - - /* runas_gr is only set if the user specified the -g flag */ - if (!runas_gr) - return(UNSPEC); - - /* get the values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); - if (bv == NULL) - return(ret); - - /* walk through values returned, looking for a match */ - for (p = bv; *p != NULL && !ret; p++) { - val = (*p)->bv_val; - if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr)) - ret = TRUE; - DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val, - ret ? "MATCH!" : "not"), 2); - } - - ldap_value_free_len(bv); /* cleanup */ - - return(ret); -} - -/* - * Walk through search results and return TRUE if we have a runas match, - * else FALSE. RunAs info is optional. - */ -static int -sudo_ldap_check_runas(ld, entry) - LDAP *ld; - LDAPMessage *entry; -{ - int ret; - - if (!entry) - return(FALSE); - - ret = sudo_ldap_check_runas_user(ld, entry) != FALSE && - sudo_ldap_check_runas_group(ld, entry) != FALSE; - - return(ret); -} - -/* - * Walk through search results and return TRUE if we have a command match, - * FALSE if disallowed and UNSPEC if not matched. - */ -static int -sudo_ldap_check_command(ld, entry, setenv_implied) - LDAP *ld; - LDAPMessage *entry; - int *setenv_implied; -{ - struct berval **bv, **p; - char *allowed_cmnd, *allowed_args, *val; - int foundbang, ret = UNSPEC; - - if (!entry) - return(ret); - - bv = ldap_get_values_len(ld, entry, "sudoCommand"); - if (bv == NULL) - return(ret); - - for (p = bv; *p != NULL && ret != FALSE; p++) { - val = (*p)->bv_val; - /* Match against ALL ? */ - if (!strcmp(val, "ALL")) { - ret = TRUE; - if (setenv_implied != NULL) - *setenv_implied = TRUE; - DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2); - continue; - } - - /* check for !command */ - if (*val == '!') { - foundbang = TRUE; - allowed_cmnd = estrdup(1 + val); /* !command */ - } else { - foundbang = FALSE; - allowed_cmnd = estrdup(val); /* command */ - } - - /* split optional args away from command */ - allowed_args = strchr(allowed_cmnd, ' '); - if (allowed_args) - *allowed_args++ = '\0'; - - /* check the command like normal */ - if (command_matches(allowed_cmnd, allowed_args)) { - /* - * If allowed (no bang) set ret but keep on checking. - * If disallowed (bang), exit loop. - */ - ret = foundbang ? FALSE : TRUE; - } - DPRINTF(("ldap sudoCommand '%s' ... %s", val, - ret == TRUE ? "MATCH!" : "not"), 2); - - efree(allowed_cmnd); /* cleanup */ - } - - ldap_value_free_len(bv); /* more cleanup */ - - return(ret); -} - -/* - * Search for boolean "option" in sudoOption. - * Returns TRUE if found and allowed, FALSE if negated, else UNSPEC. - */ -static int -sudo_ldap_check_bool(ld, entry, option) - LDAP *ld; - LDAPMessage *entry; - char *option; -{ - struct berval **bv, **p; - char ch, *var; - int ret = UNSPEC; - - if (entry == NULL) - return(UNSPEC); - - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv == NULL) - return(ret); - - /* walk through options */ - for (p = bv; *p != NULL; p++) { - var = (*p)->bv_val;; - DPRINTF(("ldap sudoOption: '%s'", var), 2); - - if ((ch = *var) == '!') - var++; - if (strcmp(var, option) == 0) - ret = (ch != '!'); - } - - ldap_value_free_len(bv); - - return(ret); -} - -/* - * Read sudoOption and modify the defaults as we go. This is used once - * from the cn=defaults entry and also once when a final sudoRole is matched. - */ -static void -sudo_ldap_parse_options(ld, entry) - LDAP *ld; - LDAPMessage *entry; -{ - struct berval **bv, **p; - char op, *var, *val; - - if (entry == NULL) - return; - - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv == NULL) - return; - - /* walk through options */ - for (p = bv; *p != NULL; p++) { - var = estrdup((*p)->bv_val); - DPRINTF(("ldap sudoOption: '%s'", var), 2); - - /* check for equals sign past first char */ - val = strchr(var, '='); - if (val > var) { - *val++ = '\0'; /* split on = and truncate var */ - op = *(val - 2); /* peek for += or -= cases */ - if (op == '+' || op == '-') { - *(val - 2) = '\0'; /* found, remove extra char */ - /* case var+=val or var-=val */ - set_default(var, val, (int) op); - } else { - /* case var=val */ - set_default(var, val, TRUE); - } - } else if (*var == '!') { - /* case !var Boolean False */ - set_default(var + 1, NULL, FALSE); - } else { - /* case var Boolean True */ - set_default(var, NULL, TRUE); - } - efree(var); - } - - ldap_value_free_len(bv); -} - -/* - * builds together a filter to check against ldap - */ -static char * -sudo_ldap_build_pass1(pw) - struct passwd *pw; -{ - struct group *grp; - size_t sz; - char *buf; - int i; - - /* Start with (|(sudoUser=USERNAME)(sudoUser=ALL)) + NUL */ - sz = 29 + strlen(pw->pw_name); - - /* Add space for groups */ - if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) - sz += 12 + strlen(grp->gr_name); /* primary group */ - for (i = 0; i < user_ngroups; i++) { - if (user_groups[i] == pw->pw_gid) - continue; - if ((grp = sudo_getgrgid(user_groups[i])) != NULL) - sz += 12 + strlen(grp->gr_name); /* supplementary group */ - } - buf = emalloc(sz); - - /* Global OR + sudoUser=user_name filter */ - (void) strlcpy(buf, "(|(sudoUser=", sz); - (void) strlcat(buf, pw->pw_name, sz); - (void) strlcat(buf, ")", sz); - - /* Append primary group */ - if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { - (void) strlcat(buf, "(sudoUser=%", sz); - (void) strlcat(buf, grp->gr_name, sz); - (void) strlcat(buf, ")", sz); - } - - /* Append supplementary groups */ - for (i = 0; i < user_ngroups; i++) { - if (user_groups[i] == pw->pw_gid) - continue; - if ((grp = sudo_getgrgid(user_groups[i])) != NULL) { - (void) strlcat(buf, "(sudoUser=%", sz); - (void) strlcat(buf, grp->gr_name, sz); - (void) strlcat(buf, ")", sz); - } - } - - /* Add ALL to list and end the global OR */ - if (strlcat(buf, "(sudoUser=ALL))", sz) >= sz) - errorx(1, "sudo_ldap_build_pass1 allocation mismatch"); - - return(buf); -} - -/* - * Map yes/true/on to TRUE, no/false/off to FALSE, else -1 - */ -static int -_atobool(s) - const char *s; -{ - switch (*s) { - case 'y': - case 'Y': - if (strcasecmp(s, "yes") == 0) - return(TRUE); - break; - case 't': - case 'T': - if (strcasecmp(s, "true") == 0) - return(TRUE); - break; - case 'o': - case 'O': - if (strcasecmp(s, "on") == 0) - return(TRUE); - if (strcasecmp(s, "off") == 0) - return(FALSE); - break; - case 'n': - case 'N': - if (strcasecmp(s, "no") == 0) - return(FALSE); - break; - case 'f': - case 'F': - if (strcasecmp(s, "false") == 0) - return(FALSE); - break; - } - return(-1); -} - -static void -sudo_ldap_read_secret(path) - const char *path; -{ - FILE *fp; - char buf[LINE_MAX], *cp; - - if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) { - if (fgets(buf, sizeof(buf), fp) != NULL) { - if ((cp = strchr(buf, '\n')) != NULL) - *cp = '\0'; - /* copy to bindpw and binddn */ - efree(ldap_conf.bindpw); - ldap_conf.bindpw = estrdup(buf); - efree(ldap_conf.binddn); - ldap_conf.binddn = ldap_conf.rootbinddn; - ldap_conf.rootbinddn = NULL; - } - fclose(fp); - } -} - -static int -sudo_ldap_read_config() -{ - FILE *fp; - char *cp, *keyword, *value; - struct ldap_config_table *cur; - - /* defaults */ - ldap_conf.version = 3; - ldap_conf.port = -1; - ldap_conf.tls_checkpeer = -1; - ldap_conf.timelimit = -1; - ldap_conf.bind_timelimit = -1; - ldap_conf.use_sasl = -1; - ldap_conf.rootuse_sasl = -1; - - if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL) - return(FALSE); - - while ((cp = sudo_parseln(fp)) != NULL) { - if (*cp == '\0') - continue; /* skip empty line */ - - /* split into keyword and value */ - keyword = cp; - while (*cp && !isblank((unsigned char) *cp)) - cp++; - if (*cp) - *cp++ = '\0'; /* terminate keyword */ - - /* skip whitespace before value */ - while (isblank((unsigned char) *cp)) - cp++; - value = cp; - - /* Look up keyword in config table. */ - for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) { - if (strcasecmp(keyword, cur->conf_str) == 0) { - switch (cur->type) { - case CONF_BOOL: - *(int *)(cur->valp) = _atobool(value); - break; - case CONF_INT: - *(int *)(cur->valp) = atoi(value); - break; - case CONF_STR: - efree(*(char **)(cur->valp)); - *(char **)(cur->valp) = estrdup(value); - break; - case CONF_LIST_STR: - { - struct ldap_config_list_str **p; - size_t len = strlen(value); - - if (len > 0) { - p = (struct ldap_config_list_str **)cur->valp; - while (*p != NULL) - p = &(*p)->next; - *p = emalloc(sizeof(struct ldap_config_list_str) + len); - memcpy((*p)->val, value, len + 1); - (*p)->next = NULL; - } - } - break; - } - break; - } - } - } - fclose(fp); - - if (!ldap_conf.host) - ldap_conf.host = estrdup("localhost"); - - if (ldap_conf.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"); - if (ldap_conf.uri) { - struct ldap_config_list_str *uri = ldap_conf.uri; - - do { - fprintf(stderr, "uri %s\n", uri->val); - } while ((uri = uri->next) != NULL); - } else { - fprintf(stderr, "host %s\n", ldap_conf.host ? - ldap_conf.host : "(NONE)"); - fprintf(stderr, "port %d\n", ldap_conf.port); - } - fprintf(stderr, "ldap_version %d\n", ldap_conf.version); - if (ldap_conf.base) { - struct ldap_config_list_str *base = ldap_conf.base; - - do { - fprintf(stderr, "sudoers_base %s\n", base->val); - } while ((base = base->next) != NULL); - } else { - fprintf(stderr, "sudoers_base %s\n", - "(NONE) <---Sudo will ignore ldap)"); - } - fprintf(stderr, "binddn %s\n", ldap_conf.binddn ? - ldap_conf.binddn : "(anonymous)"); - fprintf(stderr, "bindpw %s\n", ldap_conf.bindpw ? - ldap_conf.bindpw : "(anonymous)"); - if (ldap_conf.bind_timelimit > 0) - fprintf(stderr, "bind_timelimit %d\n", ldap_conf.bind_timelimit); - if (ldap_conf.timelimit > 0) - fprintf(stderr, "timelimit %d\n", ldap_conf.timelimit); - fprintf(stderr, "ssl %s\n", ldap_conf.ssl ? - ldap_conf.ssl : "(no)"); - if (ldap_conf.tls_checkpeer != -1) - fprintf(stderr, "tls_checkpeer %s\n", ldap_conf.tls_checkpeer ? - "(yes)" : "(no)"); - if (ldap_conf.tls_cacertfile != NULL) - fprintf(stderr, "tls_cacertfile %s\n", ldap_conf.tls_cacertfile); - if (ldap_conf.tls_cacertdir != NULL) - fprintf(stderr, "tls_cacertdir %s\n", ldap_conf.tls_cacertdir); - if (ldap_conf.tls_random_file != NULL) - fprintf(stderr, "tls_random_file %s\n", ldap_conf.tls_random_file); - if (ldap_conf.tls_cipher_suite != NULL) - fprintf(stderr, "tls_cipher_suite %s\n", ldap_conf.tls_cipher_suite); - if (ldap_conf.tls_certfile != NULL) - fprintf(stderr, "tls_certfile %s\n", ldap_conf.tls_certfile); - if (ldap_conf.tls_keyfile != NULL) - fprintf(stderr, "tls_keyfile %s\n", ldap_conf.tls_keyfile); -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S - if (ldap_conf.use_sasl != -1) { - fprintf(stderr, "use_sasl %s\n", - ldap_conf.use_sasl ? "yes" : "no"); - fprintf(stderr, "sasl_auth_id %s\n", ldap_conf.sasl_auth_id ? - ldap_conf.sasl_auth_id : "(NONE)"); - fprintf(stderr, "rootuse_sasl %d\n", ldap_conf.rootuse_sasl); - fprintf(stderr, "rootsasl_auth_id %s\n", ldap_conf.rootsasl_auth_id ? - ldap_conf.rootsasl_auth_id : "(NONE)"); - fprintf(stderr, "sasl_secprops %s\n", ldap_conf.sasl_secprops ? - ldap_conf.sasl_secprops : "(NONE)"); - fprintf(stderr, "krb5_ccname %s\n", ldap_conf.krb5_ccname ? - ldap_conf.krb5_ccname : "(NONE)"); - } -#endif - fprintf(stderr, "===================\n"); - } - if (!ldap_conf.base) - return(FALSE); /* if no base is defined, ignore LDAP */ - - /* - * Interpret SSL option - */ - if (ldap_conf.ssl != NULL) { - if (strcasecmp(ldap_conf.ssl, "start_tls") == 0) - ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS; - else if (_atobool(ldap_conf.ssl)) - ldap_conf.ssl_mode = SUDO_LDAP_SSL; - } - -#if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT) - if (ldap_conf.tls_checkpeer != -1) { - ldapssl_set_strength(NULL, - ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK); - } -#endif - -#ifndef HAVE_LDAP_INITIALIZE - /* Convert uri list to host list if no ldap_initialize(). */ - if (ldap_conf.uri) { - struct ldap_config_list_str *uri = ldap_conf.uri; - if (sudo_ldap_parse_uri(uri) != 0) - return(FALSE); - do { - ldap_conf.uri = uri->next; - efree(uri); - } while ((uri = ldap_conf.uri)); - ldap_conf.port = LDAP_PORT; - } -#endif - - if (!ldap_conf.uri) { - /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */ - if (ldap_conf.port < 0) - ldap_conf.port = - ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT; - -#ifdef HAVE_LDAP_CREATE - /* - * Cannot specify port directly to ldap_create(), each host must - * include :port to override the default. - */ - if (ldap_conf.port != LDAP_PORT) - sudo_ldap_conf_add_ports(); -#endif - } - - /* If rootbinddn set, read in /etc/ldap.secret if it exists. */ - if (ldap_conf.rootbinddn) - sudo_ldap_read_secret(_PATH_LDAP_SECRET); - -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S - /* - * Make sure we can open the file specified by krb5_ccname. - */ - if (ldap_conf.krb5_ccname != NULL) { - if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 || - strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) { - value = ldap_conf.krb5_ccname + - (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7); - if ((fp = fopen(value, "r")) != NULL) { - DPRINTF(("using krb5 credential cache: %s", value), 1); - fclose(fp); - } else { - /* Can't open it, just ignore the entry. */ - DPRINTF(("unable to open krb5 credential cache: %s", value), 1); - efree(ldap_conf.krb5_ccname); - ldap_conf.krb5_ccname = NULL; - } - } - } -#endif - return(TRUE); -} - -/* - * Extract the dn from an entry and return the first rdn from it. - */ -static char * -sudo_ldap_get_first_rdn(ld, entry) - LDAP *ld; - LDAPMessage *entry; -{ -#ifdef HAVE_LDAP_STR2DN - char *dn, *rdn = NULL; - LDAPDN tmpDN; - - if ((dn = ldap_get_dn(ld, entry)) == NULL) - return(NULL); - if (ldap_str2dn(dn, &tmpDN, LDAP_DN_FORMAT_LDAP) == LDAP_SUCCESS) { - ldap_rdn2str(tmpDN[0], &rdn, LDAP_DN_FORMAT_UFN); - ldap_dnfree(tmpDN); - } - ldap_memfree(dn); - return(rdn); -#else - char *dn, **edn; - - if ((dn = ldap_get_dn(ld, entry)) == NULL) - return(NULL); - edn = ldap_explode_dn(dn, 1); - ldap_memfree(dn); - return(edn ? edn[0] : NULL); -#endif -} - -/* - * Fetch and display the global Options. - */ -static int -sudo_ldap_display_defaults(nss, pw, lbuf) - struct sudo_nss *nss; - struct passwd *pw; - struct lbuf *lbuf; -{ - struct berval **bv, **p; - struct ldap_config_list_str *base; - LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry, *result; - char *prefix; - int rc, count = 0; - - if (ld == NULL) - goto done; - - for (base = ldap_conf.base; base != NULL; base = base->next) { - result = NULL; - rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, - "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result); - if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv != NULL) { - if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) - prefix = " "; - else - prefix = ", "; - for (p = bv; *p != NULL; p++) { - lbuf_append(lbuf, prefix, (*p)->bv_val, NULL); - prefix = ", "; - count++; - } - ldap_value_free_len(bv); - } - } - if (result) - ldap_msgfree(result); - } -done: - return(count); -} - -/* - * STUB - */ -static int -sudo_ldap_display_bound_defaults(nss, pw, lbuf) - struct sudo_nss *nss; - struct passwd *pw; - struct lbuf *lbuf; -{ - return(0); -} - -/* - * Print a record in the short form, ala file sudoers. - */ -static int -sudo_ldap_display_entry_short(ld, entry, lbuf) - LDAP *ld; - LDAPMessage *entry; - struct lbuf *lbuf; -{ - struct berval **bv, **p; - int count = 0; - - lbuf_append(lbuf, " (", NULL); - - /* get the RunAsUser Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); - if (bv == NULL) - bv = ldap_get_values_len(ld, entry, "sudoRunAs"); - if (bv != NULL) { - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - } - ldap_value_free_len(bv); - } else - lbuf_append(lbuf, def_runas_default, NULL); - - /* get the RunAsGroup Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); - if (bv != NULL) { - lbuf_append(lbuf, " : ", NULL); - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - } - ldap_value_free_len(bv); - } - lbuf_append(lbuf, ") ", NULL); - - /* get the Option Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv != NULL) { - char *cp, *tag; - - for (p = bv; *p != NULL; p++) { - cp = (*p)->bv_val; - if (*cp == '!') - cp++; - tag = NULL; - if (strcmp(cp, "authenticate") == 0) - tag = (*p)->bv_val[0] == '!' ? - "NOPASSWD: " : "PASSWD: "; - else if (strcmp(cp, "noexec") == 0) - tag = (*p)->bv_val[0] == '!' ? - "EXEC: " : "NOEXEC: "; - else if (strcmp(cp, "setenv") == 0) - tag = (*p)->bv_val[0] == '!' ? - "NOSETENV: " : "SETENV: "; - if (tag != NULL) - lbuf_append(lbuf, tag, NULL); - /* XXX - ignores other options */ - } - ldap_value_free_len(bv); - } - - /* get the Command Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoCommand"); - if (bv != NULL) { - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - count++; - } - ldap_value_free_len(bv); - } - lbuf_append(lbuf, "\n", NULL); - - return(count); -} - -/* - * Print a record in the long form. - */ -static int -sudo_ldap_display_entry_long(ld, entry, lbuf) - LDAP *ld; - LDAPMessage *entry; - struct lbuf *lbuf; -{ - struct berval **bv, **p; - char *rdn; - int count = 0; - - /* extract the dn, only show the first rdn */ - rdn = sudo_ldap_get_first_rdn(ld, entry); - lbuf_append(lbuf, "\nLDAP Role: ", rdn ? rdn : "UNKNOWN", "\n", NULL); - if (rdn) - ldap_memfree(rdn); - - /* get the RunAsUser Values from the entry */ - lbuf_append(lbuf, " RunAsUsers: ", NULL); - bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); - if (bv == NULL) - bv = ldap_get_values_len(ld, entry, "sudoRunAs"); - if (bv != NULL) { - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - } - ldap_value_free_len(bv); - } else - lbuf_append(lbuf, def_runas_default, NULL); - lbuf_append(lbuf, "\n", NULL); - - /* get the RunAsGroup Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); - if (bv != NULL) { - lbuf_append(lbuf, " RunAsGroups: ", NULL); - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - } - ldap_value_free_len(bv); - lbuf_append(lbuf, "\n", NULL); - } - - /* get the Option Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoOption"); - if (bv != NULL) { - lbuf_append(lbuf, " Options: ", NULL); - for (p = bv; *p != NULL; p++) { - if (p != bv) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, (*p)->bv_val, NULL); - } - ldap_value_free_len(bv); - lbuf_append(lbuf, "\n", NULL); - } - - /* get the Command Values from the entry */ - bv = ldap_get_values_len(ld, entry, "sudoCommand"); - if (bv != NULL) { - lbuf_append(lbuf, " Commands:\n", NULL); - for (p = bv; *p != NULL; p++) { - lbuf_append(lbuf, "\t", (*p)->bv_val, "\n", NULL); - count++; - } - ldap_value_free_len(bv); - } - - return(count); -} - -/* - * Like sudo_ldap_lookup(), except we just print entries. - */ -static int -sudo_ldap_display_privs(nss, pw, lbuf) - struct sudo_nss *nss; - struct passwd *pw; - struct lbuf *lbuf; -{ - struct ldap_config_list_str *base; - LDAP *ld = (LDAP *) nss->handle; - LDAPMessage *entry, *result; - char *filt; - int rc, do_netgr, count = 0; - - if (ld == NULL) - goto done; - - /* - * 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)) { - - 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); - } -done: - return(count); -} - -static int -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 */ - - if (ld == NULL) - return(1); - - /* - * Okay - time to search for anything that matches this user - * Lets limit it to only two queries of the LDAP server - * - * The first pass will look by the username, groups, and - * the keyword ALL. We will then inspect the results that - * came back from the query. We don't need to inspect the - * sudoUser in this pass since the LDAP server already scanned - * it for us. - * - * The second pass will return all the entries that contain - * user netgroups. Then we take the netgroups returned and - * try to match them against the username. - */ - for (found = FALSE, do_netgr = 0; !found && do_netgr < 2; do_netgr++) { - filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw); - DPRINTF(("ldap search '%s'", filt), 1); - 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); - } - efree(filt); - } - - if (found) - printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd, - user_args ? " " : "", user_args ? user_args : ""); - return(!found); -} - -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S -static int -sudo_ldap_sasl_interact(ld, flags, _auth_id, _interact) - LDAP *ld; - unsigned int flags; - void *_auth_id; - void *_interact; -{ - char *auth_id = (char *)_auth_id; - sasl_interact_t *interact = (sasl_interact_t *)_interact; - - for (; interact->id != SASL_CB_LIST_END; interact++) { - if (interact->id != SASL_CB_USER) - return(LDAP_PARAM_ERROR); - - if (auth_id != NULL) - interact->result = auth_id; - else if (interact->defresult != NULL) - interact->result = interact->defresult; - else - interact->result = ""; - - interact->len = strlen(interact->result); -#if SASL_VERSION_MAJOR < 2 - interact->result = estrdup(interact->result); -#endif /* SASL_VERSION_MAJOR < 2 */ - } - return(LDAP_SUCCESS); -} -#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ - -/* - * Set LDAP options based on the config table. - */ -static int -sudo_ldap_set_options(ld) - LDAP *ld; -{ - struct ldap_config_table *cur; - int rc; - - /* Set ber options */ -#ifdef LBER_OPT_DEBUG_LEVEL - if (ldap_conf.ldap_debug) - ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug); -#endif - - /* Set simple LDAP options */ - for (cur = ldap_conf_table; cur->conf_str != NULL; cur++) { - LDAP *conn; - int ival; - char *sval; - - if (cur->opt_val == -1) - continue; - - conn = cur->connected ? ld : NULL; - switch (cur->type) { - case CONF_BOOL: - case CONF_INT: - ival = *(int *)(cur->valp); - if (ival >= 0) { - rc = ldap_set_option(conn, cur->opt_val, &ival); - if (rc != LDAP_OPT_SUCCESS) { - warningx("ldap_set_option: %s -> %d: %s", - cur->conf_str, ival, ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1); - } - break; - case CONF_STR: - sval = *(char **)(cur->valp); - if (sval != NULL) { - rc = ldap_set_option(conn, cur->opt_val, sval); - if (rc != LDAP_OPT_SUCCESS) { - warningx("ldap_set_option: %s -> %s: %s", - cur->conf_str, sval, ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1); - } - break; - } - } - -#ifdef LDAP_OPT_NETWORK_TIMEOUT - /* Convert bind_timelimit to a timeval */ - if (ldap_conf.bind_timelimit > 0) { - struct timeval tv; - tv.tv_sec = ldap_conf.bind_timelimit / 1000; - tv.tv_usec = 0; - rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); - if (rc != LDAP_OPT_SUCCESS) { - warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s", - (long)tv.tv_sec, ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)", - (long)tv.tv_sec), 1); - } -#endif - -#if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT) - if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) { - int val = LDAP_OPT_X_TLS_HARD; - rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val); - if (rc != LDAP_SUCCESS) { - warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s", - ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1); - } -#endif - return(0); -} - -/* - * Connect to the LDAP server specified by ld - */ -static int -sudo_ldap_bind_s(ld) - LDAP *ld; -{ - int rc; -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S - const char *old_ccname = user_ccname; -# ifdef HAVE_GSS_KRB5_CCACHE_NAME - unsigned int status; -# endif -#endif - -#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S - if (ldap_conf.rootuse_sasl == TRUE || - (ldap_conf.rootuse_sasl != FALSE && ldap_conf.use_sasl == TRUE)) { - void *auth_id = ldap_conf.rootsasl_auth_id ? - ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id; - - if (ldap_conf.krb5_ccname != NULL) { -# ifdef HAVE_GSS_KRB5_CCACHE_NAME - if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname) - != GSS_S_COMPLETE) { - old_ccname = NULL; - DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1); - } -# else - setenv("KRB5CCNAME", ldap_conf.krb5_ccname, TRUE); -# endif - } - rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI", - NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id); - if (ldap_conf.krb5_ccname != NULL) { -# ifdef HAVE_GSS_KRB5_CCACHE_NAME - if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE) - DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1); -# else - if (old_ccname != NULL) - setenv("KRB5CCNAME", old_ccname, TRUE); - else - unsetenv("KRB5CCNAME"); -# endif - } - if (rc != LDAP_SUCCESS) { - warningx("ldap_sasl_interactive_bind_s(): %s", ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1); - } else -#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ -#ifdef HAVE_LDAP_SASL_BIND_S - { - struct berval bv; - - bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : ""; - bv.bv_len = strlen(bv.bv_val); - - rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv, - NULL, NULL, NULL); - if (rc != LDAP_SUCCESS) { - warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_sasl_bind_s() ok"), 1); - } -#else - { - rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw); - if (rc != LDAP_SUCCESS) { - warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_simple_bind_s() ok"), 1); - } -#endif - return(0); -} - -/* - * Open a connection to the LDAP server. - * Returns 0 on success and non-zero on failure. - */ -static int -sudo_ldap_open(nss) - struct sudo_nss *nss; -{ - LDAP *ld; - int rc, ldapnoinit = FALSE; - - if (!sudo_ldap_read_config()) - return(-1); - - /* Prevent reading of user ldaprc and system defaults. */ - if (getenv("LDAPNOINIT") == NULL) { - ldapnoinit = TRUE; - setenv("LDAPNOINIT", "1", TRUE); - } - - /* Connect to LDAP server */ -#ifdef HAVE_LDAP_INITIALIZE - if (ldap_conf.uri != NULL) { - char *buf = sudo_ldap_join_uri(ldap_conf.uri); - DPRINTF(("ldap_initialize(ld, %s)", buf), 2); - rc = ldap_initialize(&ld, buf); - efree(buf); - } else -#endif - rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port); - if (rc != LDAP_SUCCESS) { - warningx("unable to initialize LDAP: %s", ldap_err2string(rc)); - return(-1); - } - - if (ldapnoinit) - unsetenv("LDAPNOINIT"); - - /* Set LDAP options */ - if (sudo_ldap_set_options(ld) < 0) - return(-1); - - if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { -#if defined(HAVE_LDAP_START_TLS_S) - rc = ldap_start_tls_s(ld, NULL, NULL); - if (rc != LDAP_SUCCESS) { - warningx("ldap_start_tls_s(): %s", ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_start_tls_s() ok"), 1); -#elif defined(HAVE_LDAP_SSL_CLIENT_INIT) && defined(HAVE_LDAP_START_TLS_S_NP) - if (ldap_ssl_client_init(NULL, NULL, 0, &rc) != LDAP_SUCCESS) { - warningx("ldap_ssl_client_init(): %s", ldap_err2string(rc)); - return(-1); - } - rc = ldap_start_tls_s_np(ld, NULL); - if (rc != LDAP_SUCCESS) { - warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc)); - return(-1); - } - DPRINTF(("ldap_start_tls_s_np() ok"), 1); -#else - warningx("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()"); -#endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */ - } - - /* Actually connect */ - if (sudo_ldap_bind_s(ld) != 0) - return(-1); - - nss->handle = ld; - return(0); -} - -static int -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 */ - - if (ld == NULL) - return(-1); - - for (base = ldap_conf.base; base != NULL; base = base->next) { - result = NULL; - rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, - "cn=defaults", NULL, 0, NULL, NULL, NULL, 0, &result); - if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { - DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1); - sudo_ldap_parse_options(ld, entry); - } else - DPRINTF(("no default options found in %s", base->val), 1); - - if (result) - ldap_msgfree(result); - } - - return(0); -} - -/* - * like sudoers_lookup() - only LDAP style - */ -static int -sudo_ldap_lookup(nss, ret, pwflag) - struct sudo_nss *nss; - int ret; - int pwflag; -{ - struct 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; - - if (ld == NULL) - return(ret); - - if (pwflag) { - int doauth = UNSPEC; - enum def_tupple pwcheck = - (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; - - for (matched = 0, do_netgr = 0; !matched && do_netgr < 2; do_netgr++) { - filt = do_netgr ? estrdup("sudoUser=+*") : sudo_ldap_build_pass1(pw); - 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); - } - efree(filt); - } - if (matched || user_uid == 0) { - SET(ret, VALIDATE_OK); - CLR(ret, VALIDATE_NOT_OK); - if (def_authenticate) { - switch (pwcheck) { - case always: - SET(ret, FLAG_CHECK_USER); - break; - case all: - case any: - if (doauth == FALSE) - def_authenticate = FALSE; - break; - case never: - def_authenticate = FALSE; - break; - default: - break; - } - } - } - goto done; - } - - /* - * Okay - time to search for anything that matches this user - * 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. - */ - 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); - 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) { - DPRINTF(("nothing found for '%s'", filt), 1); - continue; - } - - /* parse each entry returned from this most recent search */ - 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; - } - } - ldap_msgfree(result); - } - efree(filt); - } - -done: - DPRINTF(("user_matches=%d", ldap_user_matches), 1); - DPRINTF(("host_matches=%d", ldap_host_matches), 1); - - 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); - - return(ret); -} - -/* - * shut down 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); - nss->handle = NULL; - } - return(0); -} - -/* - * STUB - */ -static int -sudo_ldap_parse(nss) - struct sudo_nss *nss; -{ - return(0); -} diff --git a/linux_audit.c b/linux_audit.c deleted file mode 100644 index ba87e78..0000000 --- a/linux_audit.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include - -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#include -#include -#include -#include - -#include "compat.h" -#include "error.h" -#include "alloc.h" -#include "missing.h" -#include "linux_audit.h" - -/* - * Open audit connection if possible. - * Returns audit fd on success and -1 on failure. - */ -static int -linux_audit_open(void) -{ - static int au_fd = -1; - - if (au_fd != -1) - return au_fd; - au_fd = audit_open(); - if (au_fd == -1) { - /* Kernel may not have audit support. */ - if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) - error(1, "unable to open audit system"); - } else { - (void)fcntl(au_fd, F_SETFD, FD_CLOEXEC); - } - return au_fd; -} - -int -linux_audit_command(char *argv[], int result) -{ - int au_fd, rc; - char *command, *cp, **av; - size_t size, n; - - if ((au_fd = linux_audit_open()) == -1) - return -1; - - /* Convert argv to a flat string. */ - for (size = 0, av = argv; *av != NULL; av++) - size += strlen(*av) + 1; - command = cp = emalloc(size); - for (av = argv; *av != NULL; av++) { - n = strlcpy(cp, *av, size - (cp - command)); - if (n >= size - (cp - command)) - errorx(1, "internal error, linux_audit_command() overflow"); - cp += n; - *cp++ = ' '; - } - *--cp = '\0'; - - /* Log command, ignoring EPERM on error. */ - rc = audit_log_user_command(au_fd, AUDIT_USER_CMD, command, NULL, result); - if (rc <= 0) - warning("unable to send audit message"); - - efree(command); - - return rc; -} - -#ifdef HAVE_SELINUX -int -linux_audit_role_change(const char *old_context, - const char *new_context, const char *ttyn) -{ - int au_fd, rc; - char *message; - - if ((au_fd = linux_audit_open()) == -1) - return -1; - - /* audit role change using the same format as newrole(1) */ - easprintf(&message, "newrole: old-context=%s new-context=%s", - old_context, new_context); - rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE, - message, NULL, NULL, ttyn, 1); - if (rc <= 0) - warning("unable to send audit message"); - - efree(message); - - return rc; -} -#endif /* HAVE_SELINUX */ diff --git a/linux_audit.h b/linux_audit.h deleted file mode 100644 index f2574f6..0000000 --- a/linux_audit.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef _SUDO_LINUX_AUDIT_H -#define _SUDO_LINUX_AUDIT_H - -int linux_audit_command(char *argv[], int result); -int linux_audit_role_change(const char *old_context, - const char *new_context, const char *ttyn); - -#endif /* _SUDO_LINUX_AUDIT_H */ diff --git a/list.c b/list.c deleted file mode 100644 index 60c1138..0000000 --- a/list.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2007-2008 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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ - -#include "sudo.h" - -struct list_proto { - struct list_proto *prev; - struct list_proto *next; -}; - -struct list_head_proto { - struct list_proto *first; - struct list_proto *last; -}; - -/* - * Pop the last element off the end of vh. - * Returns the popped element. - */ -void * -tq_pop(vh) - void *vh; -{ - struct list_head_proto *h = (struct list_head_proto *)vh; - void *last = NULL; - - if (!tq_empty(h)) { - last = (void *)h->last; - if (h->first == h->last) { - h->first = NULL; - h->last = NULL; - } else { - h->last = h->last->prev; - h->last->next = NULL; - } - } - return (last); -} - -/* - * Convert from a semi-circle queue to normal doubly-linked list - * with a head node. - */ -void -list2tq(vh, vl) - void *vh; - void *vl; -{ - struct list_head_proto *h = (struct list_head_proto *)vh; - struct list_proto *l = (struct list_proto *)vl; - - if (l != NULL) { -#ifdef DEBUG - if (l->prev == NULL) { - warningx("list2tq called with non-semicircular list"); - abort(); - } -#endif - h->first = l; - h->last = l->prev; /* l->prev points to the last member of l */ - l->prev = NULL; /* zero last ptr now that we have a head */ - } else { - h->first = NULL; - h->last = NULL; - } -} - -/* - * Append one queue (or single entry) to another using the - * circular properties of the prev pointer to simplify the logic. - */ -void -list_append(vl1, vl2) - void *vl1; - void *vl2; -{ - struct list_proto *l1 = (struct list_proto *)vl1; - struct list_proto *l2 = (struct list_proto *)vl2; - void *tail = l2->prev; - - l1->prev->next = l2; - l2->prev = l1->prev; - l1->prev = tail; -} - -/* - * Append the list of entries to the head node and convert - * e from a semi-circle queue to normal doubly-linked list. - */ -void -tq_append(vh, vl) - void *vh; - void *vl; -{ - struct list_head_proto *h = (struct list_head_proto *)vh; - struct list_proto *l = (struct list_proto *)vl; - void *tail = l->prev; - - if (h->first == NULL) - h->first = l; - else - h->last->next = l; - l->prev = h->last; - h->last = tail; -} diff --git a/list.h b/list.h deleted file mode 100644 index 17aab41..0000000 --- a/list.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2007 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_LIST_H -#define _SUDO_LIST_H - -/* - * Convenience macro for declaring a list head. - */ -#ifdef __STDC__ -#define TQ_DECLARE(n) \ -struct n##_list { \ - struct n *first; \ - struct n *last; \ -}; -#else -#define TQ_DECLARE(n) \ -struct n/**/_list { \ - struct n *first; \ - struct n *last; \ -}; -#endif - -/* - * Foreach loops: forward and reverse - */ -#undef tq_foreach_fwd -#define tq_foreach_fwd(h, v) \ - for ((v) = (h)->first; (v) != NULL; (v) = (v)->next) - -#undef tq_foreach_rev -#define tq_foreach_rev(h, v) \ - for ((v) = (h)->last; (v) != NULL; (v) = (v)->prev) - -/* - * Init a list head. - */ -#undef tq_init -#define tq_init(h) do { \ - (h)->first = NULL; \ - (h)->last = NULL; \ -} while (0) - -/* - * Simple macros to avoid exposing first/last and prev/next. - */ -#undef tq_empty -#define tq_empty(h) ((h)->first == NULL) - -#undef tq_first -#define tq_first(h) ((h)->first) - -#undef tq_last -#define tq_last(h) ((h)->last) - -#undef list_next -#define list_next(e) ((e)->next) - -#undef list_prev -#define list_prev(e) ((e)->prev) - -/* - * Prototypes for list.c - */ -void *tq_pop __P((void *)); -void tq_append __P((void *, void *)); -void list_append __P((void *, void *)); -void list2tq __P((void *, void *)); - -#endif /* _SUDO_LIST_H */ diff --git a/logging.c b/logging.c deleted file mode 100644 index 2b32968..0000000 --- a/logging.c +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Copyright (c) 1994-1996, 1998-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. - */ - -#ifdef __TANDEM -# include -#endif - -#include - -#include -#include -#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 */ -#include -#include -#include -#include -#include -#include - -#include "sudo.h" - -static void do_syslog __P((int, char *)); -static void do_logfile __P((char *)); -static void send_mail __P((const char *fmt, ...)); -static int should_mail __P((int)); -static void mysyslog __P((int, const char *, ...)); -static char *new_logline __P((const char *, int)); - -#define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ - -/* - * We do an openlog(3)/closelog(3) for each message because some - * authentication methods (notably PAM) use syslog(3) for their - * own nefarious purposes and may call openlog(3) and closelog(3). - * Note that because we don't want to assume that all systems have - * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded. - * Sadly this is a maze of #ifdefs. - */ -static void -#ifdef __STDC__ -mysyslog(int pri, const char *fmt, ...) -#else -mysyslog(pri, fmt, va_alist) - int pri; - const char *fmt; - va_dcl -#endif -{ -#ifdef BROKEN_SYSLOG - int i; -#endif - char buf[MAXSYSLOGLEN+1]; - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif -#ifdef LOG_NFACILITIES - openlog("sudo", 0, def_syslog); -#else - openlog("sudo", 0); -#endif - vsnprintf(buf, sizeof(buf), fmt, ap); -#ifdef BROKEN_SYSLOG - /* - * Some versions of syslog(3) don't guarantee success and return - * an int (notably HP-UX < 10.0). So, if at first we don't succeed, - * try, try again... - */ - for (i = 0; i < MAXSYSLOGTRIES; i++) - if (syslog(pri, "%s", buf) == 0) - break; -#else - syslog(pri, "%s", buf); -#endif /* BROKEN_SYSLOG */ - va_end(ap); - closelog(); -} - -#define FMT_FIRST "%8s : %s" -#define FMT_CONTD "%8s : (command continued) %s" - -/* - * Log a message to syslog, pre-pending the username and splitting the - * message into parts if it is longer than MAXSYSLOGLEN. - */ -static void -do_syslog(pri, msg) - int pri; - char *msg; -{ - size_t len, maxlen; - char *p, *tmp, save; - const char *fmt; - - /* - * Log the full line, breaking into multiple syslog(3) calls if necessary - */ - fmt = FMT_FIRST; - maxlen = MAXSYSLOGLEN - (sizeof(FMT_FIRST) - 6 + strlen(user_name)); - for (p = msg; *p != '\0'; ) { - len = strlen(p); - if (len > maxlen) { - /* - * Break up the line into what will fit on one syslog(3) line - * Try to avoid breaking words into several lines if possible. - */ - tmp = memrchr(p, ' ', maxlen); - if (tmp == NULL) - tmp = p + maxlen; - - /* NULL terminate line, but save the char to restore later */ - save = *tmp; - *tmp = '\0'; - - mysyslog(pri, fmt, user_name, p); - - *tmp = save; /* restore saved character */ - - /* Advance p and eliminate leading whitespace */ - for (p = tmp; *p == ' '; p++) - ; - } else { - mysyslog(pri, fmt, user_name, p); - p += len; - } - fmt = FMT_CONTD; - maxlen = MAXSYSLOGLEN - (sizeof(FMT_CONTD) - 6 + strlen(user_name)); - } -} - -static void -do_logfile(msg) - char *msg; -{ - char *full_line; - char *beg, *oldend, *end; - FILE *fp; - mode_t oldmask; - size_t maxlen; - - oldmask = umask(077); - maxlen = def_loglinelen > 0 ? def_loglinelen : 0; - fp = fopen(def_logfile, "a"); - (void) umask(oldmask); - if (fp == NULL) { - send_mail("Can't open log file: %s: %s", def_logfile, strerror(errno)); - } else if (!lock_file(fileno(fp), SUDO_LOCK)) { - send_mail("Can't lock log file: %s: %s", def_logfile, strerror(errno)); - } else { - time_t now; - - now = time(NULL); - if (def_loglinelen == 0) { - /* Don't pretty-print long log file lines (hard to grep) */ - if (def_log_host) - (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", - get_timestr(now, def_log_year), user_name, user_shost, msg); - else - (void) fprintf(fp, "%s : %s : %s\n", - get_timestr(now, def_log_year), user_name, msg); - } else { - if (def_log_host) - easprintf(&full_line, "%s : %s : HOST=%s : %s", - get_timestr(now, def_log_year), user_name, user_shost, msg); - else - easprintf(&full_line, "%s : %s : %s", - get_timestr(now, def_log_year), user_name, msg); - - /* - * Print out full_line with word wrap - */ - beg = end = full_line; - while (beg) { - oldend = end; - end = strchr(oldend, ' '); - - if (maxlen > 0 && end) { - *end = '\0'; - if (strlen(beg) > maxlen) { - /* too far, need to back up & print the line */ - - if (beg == (char *)full_line) - maxlen -= 4; /* don't indent first line */ - - *end = ' '; - if (oldend != beg) { - /* rewind & print */ - end = oldend-1; - while (*end == ' ') - --end; - *(++end) = '\0'; - (void) fprintf(fp, "%s\n ", beg); - *end = ' '; - } else { - (void) fprintf(fp, "%s\n ", beg); - } - - /* reset beg to point to the start of the new substr */ - beg = end; - while (*beg == ' ') - ++beg; - } else { - /* we still have room */ - *end = ' '; - } - - /* remove leading whitespace */ - while (*end == ' ') - ++end; - } else { - /* final line */ - (void) fprintf(fp, "%s\n", beg); - beg = NULL; /* exit condition */ - } - } - efree(full_line); - } - (void) fflush(fp); - (void) lock_file(fileno(fp), SUDO_UNLOCK); - (void) fclose(fp); - } -} - -/* - * Log and mail the denial message, optionally informing the user. - */ -void -log_denial(status, inform_user) - int status; - int inform_user; -{ - char *message; - char *logline; - - /* Set error message. */ - if (ISSET(status, FLAG_NO_USER)) - message = "user NOT in sudoers"; - else if (ISSET(status, FLAG_NO_HOST)) - message = "user NOT authorized on host"; - else - message = "command not allowed"; - - logline = new_logline(message, 0); - - if (should_mail(status)) - send_mail("%s", logline); /* send mail based on status */ - - /* Inform the user if they failed to authenticate. */ - if (inform_user) { - if (ISSET(status, FLAG_NO_USER)) - (void) fprintf(stderr, "%s is not in the sudoers file. %s", - user_name, "This incident will be reported.\n"); - else if (ISSET(status, FLAG_NO_HOST)) - (void) fprintf(stderr, "%s is not allowed to run sudo on %s. %s", - user_name, user_shost, "This incident will be reported.\n"); - else if (ISSET(status, FLAG_NO_CHECK)) - (void) fprintf(stderr, "Sorry, user %s may not run sudo on %s.\n", - user_name, user_shost); - else - (void) fprintf(stderr, - "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n", - user_name, user_cmnd, user_args ? " " : "", - user_args ? user_args : "", - list_pw ? list_pw->pw_name : runas_pw ? - runas_pw->pw_name : user_name, runas_gr ? ":" : "", - runas_gr ? runas_gr->gr_name : "", user_host); - } - - /* - * Log via syslog and/or a file. - */ - if (def_syslog) - do_syslog(def_syslog_badpri, logline); - if (def_logfile) - do_logfile(logline); - - efree(logline); -} - -/* - * Log and potentially mail the allowed command. - */ -void -log_allowed(status) - int status; -{ - char *logline; - - logline = new_logline(NULL, 0); - - if (should_mail(status)) - send_mail("%s", logline); /* send mail based on status */ - - /* - * Log via syslog and/or a file. - */ - if (def_syslog) - do_syslog(def_syslog_goodpri, logline); - if (def_logfile) - do_logfile(logline); - - efree(logline); -} - -void -#ifdef __STDC__ -log_error(int flags, const char *fmt, ...) -#else -log_error(flags, fmt, va_alist) - int flags; - const char *fmt; - va_dcl -#endif -{ - int serrno = errno; - char *message; - char *logline; - va_list ap; -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - - /* Become root if we are not already to avoid user interference */ - set_perms(PERM_ROOT|PERM_NOEXIT); - - /* Expand printf-style format + args. */ - evasprintf(&message, fmt, ap); - va_end(ap); - - if (ISSET(flags, MSG_ONLY)) - logline = message; - else - logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); - - /* - * Tell the user. - */ - if (!ISSET(flags, NO_STDERR)) { - if (ISSET(flags, USE_ERRNO)) - warning("%s", message); - else - warningx("%s", message); - } - if (logline != message) - efree(message); - - /* - * Send a copy of the error via mail. - */ - if (!ISSET(flags, NO_MAIL)) - send_mail("%s", logline); - - /* - * Log to syslog and/or a file. - */ - if (def_syslog) - do_syslog(def_syslog_badpri, logline); - if (def_logfile) - do_logfile(logline); - - efree(logline); - - if (!ISSET(flags, NO_EXIT)) { - cleanup(0); - exit(1); - } -} - -#define MAX_MAILFLAGS 63 - -/* - * Send a message to MAILTO user - */ -static void -#ifdef __STDC__ -send_mail(const char *fmt, ...) -#else -send_mail(fmt, va_alist) - const char *fmt; - va_dcl -#endif -{ - FILE *mail; - char *p; - int fd, pfd[2], status; - pid_t pid, rv; - sigaction_t sa; - va_list ap; -#ifndef NO_ROOT_MAILER - static char *root_envp[] = { - "HOME=/", - "PATH=/usr/bin:/bin:/usr/sbin:/sbin", - "LOGNAME=root", - "USERNAME=root", - "USER=root", - NULL - }; -#endif - - /* Just return if mailer is disabled. */ - if (!def_mailerpath || !def_mailto) - return; - - /* Fork and return, child will daemonize. */ - switch (pid = fork()) { - case -1: - /* Error. */ - error(1, "cannot fork"); - break; - case 0: - /* Child. */ - switch (pid = fork()) { - case -1: - /* Error. */ - mysyslog(LOG_ERR, "cannot fork: %m"); - _exit(1); - case 0: - /* Grandchild continues below. */ - break; - default: - /* Parent will wait for us. */ - _exit(0); - } - break; - default: - /* Parent. */ - do { -#ifdef HAVE_WAITPID - rv = waitpid(pid, &status, 0); -#else - rv = wait(&status); -#endif - } while (rv == -1 && errno == EINTR); - return; - } - - /* Daemonize - disassociate from session/tty. */ - if (setsid() == -1) - warning("setsid"); - (void) 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); - } - - /* Close password, group and other fds so we don't leak. */ - sudo_endpwent(); - sudo_endgrent(); - closefrom(STDERR_FILENO + 1); - - /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_INTERRUPT; - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, NULL); - - if (pipe(pfd) == -1) { - mysyslog(LOG_ERR, "cannot open pipe: %m"); - _exit(1); - } - - switch (pid = fork()) { - case -1: - /* Error. */ - mysyslog(LOG_ERR, "cannot fork: %m"); - _exit(1); - break; - case 0: - { - char *argv[MAX_MAILFLAGS + 1]; - char *mpath, *mflags; - int i; - - /* Child, set stdin to output side of the pipe */ - if (pfd[0] != STDIN_FILENO) { - if (dup2(pfd[0], STDIN_FILENO) == -1) { - mysyslog(LOG_ERR, "cannot dup stdin: %m"); - _exit(127); - } - (void) close(pfd[0]); - } - (void) close(pfd[1]); - - /* Build up an argv based on the mailer path and flags */ - mflags = estrdup(def_mailerflags); - mpath = estrdup(def_mailerpath); - if ((argv[0] = strrchr(mpath, ' '))) - argv[0]++; - else - argv[0] = mpath; - - i = 1; - if ((p = strtok(mflags, " \t"))) { - do { - argv[i] = p; - } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t"))); - } - argv[i] = NULL; - - /* - * Depending on the config, either run the mailer as root - * (so user cannot kill it) or as the user (for the paranoid). - */ -#ifndef NO_ROOT_MAILER - set_perms(PERM_ROOT|PERM_NOEXIT); - execve(mpath, argv, root_envp); -#else - set_perms(PERM_FULL_USER|PERM_NOEXIT); - execv(mpath, argv); -#endif /* NO_ROOT_MAILER */ - mysyslog(LOG_ERR, "cannot execute %s: %m", mpath); - _exit(127); - } - break; - } - - (void) close(pfd[0]); - mail = fdopen(pfd[1], "w"); - - /* Pipes are all setup, send message. */ - (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ", - def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated"); - for (p = def_mailsub; *p; p++) { - /* Expand escapes in the subject */ - if (*p == '%' && *(p+1) != '%') { - switch (*(++p)) { - case 'h': - (void) fputs(user_host, mail); - break; - case 'u': - (void) fputs(user_name, mail); - break; - default: - p--; - break; - } - } else - (void) fputc(*p, mail); - } - - (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, - get_timestr(time(NULL), def_log_year), user_name); -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - (void) vfprintf(mail, fmt, ap); - va_end(ap); - fputs("\n\n", mail); - - fclose(mail); - do { -#ifdef HAVE_WAITPID - rv = waitpid(pid, &status, 0); -#else - rv = wait(&status); -#endif - } while (rv == -1 && errno == EINTR); - _exit(0); -} - -/* - * Determine whether we should send mail based on "status" and defaults options. - */ -static int -should_mail(status) - int status; -{ - - return(def_mail_always || ISSET(status, VALIDATE_ERROR) || - (def_mail_no_user && ISSET(status, FLAG_NO_USER)) || - (def_mail_no_host && ISSET(status, FLAG_NO_HOST)) || - (def_mail_no_perms && !ISSET(status, VALIDATE_OK))); -} - -#define LL_TTY_STR "TTY=" -#define LL_CWD_STR "PWD=" /* XXX - should be CWD= */ -#define LL_USER_STR "USER=" -#define LL_GROUP_STR "GROUP=" -#define LL_ENV_STR "ENV=" -#define LL_CMND_STR "COMMAND=" -#define LL_TSID_STR "TSID=" - -/* - * Allocate and fill in a new logline. - */ -static char * -new_logline(message, serrno) - const char *message; - int serrno; -{ - size_t len = 0; - char *evstr = NULL; - char *errstr = NULL; - char *line; - - /* - * Compute line length - */ - if (message != NULL) - len += strlen(message) + 3; - if (serrno) { - errstr = strerror(serrno); - len += strlen(errstr) + 3; - } - len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty); - len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd); - if (runas_pw != NULL) - len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name); - if (runas_gr != NULL) - len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name); - if (sudo_user.sessid[0] != '\0') - len += sizeof(LL_TSID_STR) + 2 + strlen(sudo_user.sessid); - if (sudo_user.env_vars != NULL) { - size_t evlen = 0; - struct list_member *cur; - for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) - evlen += strlen(cur->value) + 1; - evstr = emalloc(evlen); - evstr[0] = '\0'; - for (cur = sudo_user.env_vars; cur != NULL; cur = cur->next) { - strlcat(evstr, cur->value, evlen); - strlcat(evstr, " ", evlen); /* NOTE: last one will fail */ - } - len += sizeof(LL_ENV_STR) + 2 + evlen; - } - len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd); - if (user_args != NULL) - len += strlen(user_args) + 1; - - /* - * Allocate and build up the line. - */ - line = emalloc(++len); - line[0] = '\0'; - - if (message != NULL) { - if (strlcat(line, message, len) >= len || - strlcat(line, errstr ? " : " : " ; ", len) >= len) - goto toobig; - } - if (serrno) { - if (strlcat(line, errstr, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - } - if (strlcat(line, LL_TTY_STR, len) >= len || - strlcat(line, user_tty, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - if (strlcat(line, LL_CWD_STR, len) >= len || - strlcat(line, user_cwd, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - if (runas_pw != NULL) { - if (strlcat(line, LL_USER_STR, len) >= len || - strlcat(line, runas_pw->pw_name, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - } - if (runas_gr != NULL) { - if (strlcat(line, LL_GROUP_STR, len) >= len || - strlcat(line, runas_gr->gr_name, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - } - if (sudo_user.sessid[0] != '\0') { - if (strlcat(line, LL_TSID_STR, len) >= len || - strlcat(line, sudo_user.sessid, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - } - if (evstr != NULL) { - if (strlcat(line, LL_ENV_STR, len) >= len || - strlcat(line, evstr, len) >= len || - strlcat(line, " ; ", len) >= len) - goto toobig; - efree(evstr); - } - if (strlcat(line, LL_CMND_STR, len) >= len || - strlcat(line, user_cmnd, len) >= len) - goto toobig; - if (user_args != NULL) { - if (strlcat(line, " ", len) >= len || - strlcat(line, user_args, len) >= len) - goto toobig; - } - - return (line); -toobig: - errorx(1, "internal error: insufficient space for log line"); -} diff --git a/logging.h b/logging.h deleted file mode 100644 index c95423e..0000000 --- a/logging.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2009 - * 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 _LOGGING_H -#define _LOGGING_H - -#include -#ifdef __STDC__ -# include -#else -# include -#endif - -/* Logging types */ -#define SLOG_SYSLOG 0x01 -#define SLOG_FILE 0x02 -#define SLOG_BOTH 0x03 - -/* Flags for log_error() */ -#define MSG_ONLY 0x01 -#define USE_ERRNO 0x02 -#define NO_MAIL 0x04 -#define NO_EXIT 0x08 -#define NO_STDERR 0x10 - -/* - * Maximum number of characters to log per entry. The syslogger - * will log this much, after that, it truncates the log line. - * We need this here to make sure that we continue with another - * syslog(3) call if the internal buffer is more than 1023 characters. - */ -#ifndef MAXSYSLOGLEN -# define MAXSYSLOGLEN 960 -#endif - -void audit_success __P((char *[])); -void audit_failure __P((char *[], char const * const, ...)); -void log_allowed __P((int)); -void log_denial __P((int, int)); -void log_error __P((int flags, const char *fmt, ...)) - __printflike(2, 3); -RETSIGTYPE reapchild __P((int)); - -#endif /* _LOGGING_H */ diff --git a/ltmain.sh b/ltmain.sh old mode 100644 new mode 100755 index a72f2fd..63ae69d --- a/ltmain.sh +++ b/ltmain.sh @@ -1,9 +1,9 @@ -# Generated from ltmain.m4sh. -# ltmain.sh (GNU libtool) 2.2.6b +# libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc. +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. @@ -32,50 +32,57 @@ # # Provide generalized library-building support services. # -# --config show all configuration variables -# --debug enable verbose shell tracing -# -n, --dry-run display commands without modifying any files -# --features display basic configuration information and exit -# --mode=MODE use operation mode MODE -# --preserve-dup-deps don't remove duplicate dependency libraries -# --quiet, --silent don't print informational messages -# --tag=TAG use configuration variables from tag TAG -# -v, --verbose print informational messages (default) -# --version print version information -# -h, --help print short or long help message +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # -# clean remove files from the build directory -# compile compile a source file into a libtool object -# execute automatically set library path, then run a program -# finish complete the installation of libtool libraries -# install install libraries or executables -# link create a library or an executable -# uninstall remove libraries from an installed directory +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory # -# MODE-ARGS vary depending on the MODE. +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # -# host-triplet: $host -# shell: $SHELL -# compiler: $LTCC -# compiler flags: $LTCFLAGS -# linker: $LD (gnu? $with_gnu_ld) -# $progname: (GNU libtool) 2.2.6b -# automake: $automake_version -# autoconf: $autoconf_version +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 +# automake: $automake_version +# autoconf: $autoconf_version # # Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . -PROGRAM=ltmain.sh +PROGRAM=libtool PACKAGE=libtool -VERSION=2.2.6b +VERSION=2.4.2 TIMESTAMP="" -package_revision=1.3017 +package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then @@ -91,10 +98,15 @@ fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + # NLS nuisances: We save the old values to restore during execute mode. -# Only set LANG and LC_ALL to C if already set. -# These must not be set unconditionally because not all systems understand -# e.g. LANG=C (notably SCO). lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES @@ -107,24 +119,28 @@ do lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL $lt_unset CDPATH +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" : ${CP="cp -f"} -: ${ECHO="echo"} -: ${EGREP="/bin/grep -E"} -: ${FGREP="/bin/grep -F"} -: ${GREP="/bin/grep"} -: ${LN_S="ln -s"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} -: ${SED="/bin/sed"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} @@ -144,6 +160,27 @@ IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: @@ -158,33 +195,183 @@ basename="s,^.*/,," # those functions but instead duplicate the functionality here. func_dirname_and_basename () { - # Extract subdirectory from the argument. - func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi - func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } -# Generated shell functions inserted here. +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done -# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh -# is ksh but when the shell is invoked as "sh" and the current value of -# the _XPG environment variable is not equal to 1 (one), the special -# positional parameter $0, within a function call, is the name of the -# function. -progpath="$0" + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} # The name of this program: -# In the unlikely event $progname began with a '-', it would play havoc with -# func_echo (imagine progname=-n), so we prepend ./ in that case: func_dirname_and_basename "$progpath" progname=$func_basename_result -case $progname in - -*) progname=./$progname ;; -esac # Make sure we have an absolute path for reexecution: case $progpath in @@ -196,7 +383,7 @@ case $progpath in ;; *) save_IFS="$IFS" - IFS=: + IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break @@ -215,6 +402,15 @@ sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. @@ -243,7 +439,7 @@ opt_warning=: # name if it has been set yet. func_echo () { - $ECHO "$progname${mode+: }$mode: $*" + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... @@ -258,18 +454,25 @@ func_verbose () : } +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + # func_error arg... # Echo program name prefixed message to standard error. func_error () { - $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { - $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : @@ -326,9 +529,9 @@ func_mkdir_p () case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop - my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"` + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done - my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'` + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do @@ -378,7 +581,7 @@ func_mktempdir () func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi - $ECHO "X$my_tmpdir" | $Xsed + $ECHO "$my_tmpdir" } @@ -392,7 +595,7 @@ func_quote_for_eval () { case $1 in *[\\\`\"\$]*) - func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;; + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac @@ -419,7 +622,7 @@ func_quote_for_expand () { case $1 in *[\\\`\"]*) - my_arg=`$ECHO "X$1" | $Xsed \ + my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; @@ -488,15 +691,39 @@ func_show_eval_locale () fi } - - +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} # func_version # Echo version message to standard output and exit. func_version () { - $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / { + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ @@ -509,22 +736,28 @@ func_version () # Echo short help message to standard output and exit. func_usage () { - $SED -n '/^# Usage:/,/# -h/ { + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" - $ECHO + echo $ECHO "run \`$progname --help | more' for full usage" exit $? } -# func_help -# Echo long help message to standard output and exit. +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. func_help () { + $opt_debug + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print s/^# // s/^# *$// s*\$progname*'$progname'* @@ -534,11 +767,18 @@ func_help () s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ - s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ - s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p - }' < "$progpath" - exit $? + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi } # func_missing_arg argname @@ -546,63 +786,106 @@ func_help () # exit_cmd. func_missing_arg () { - func_error "missing argument for $1" + $opt_debug + + func_error "missing argument for $1." exit_cmd=exit } -exit_cmd=: +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: -# Check that we have a working $ECHO. -if test "X$1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X$1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then - # Yippee, $ECHO works! - : -else - # Restart under the correct shell, and then maybe $ECHO will work. - exec $SHELL "$progpath" --no-reexec ${1+"$@"} -fi -if test "X$1" = X--fallback-echo; then - # used as fallback echo - shift - cat </dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. @@ -636,16 +919,16 @@ func_config () # Display the features supported by this script. func_features () { - $ECHO "host: $host" + echo "host: $host" if test "$build_libtool_libs" = yes; then - $ECHO "enable shared libraries" + echo "enable shared libraries" else - $ECHO "disable shared libraries" + echo "disable shared libraries" fi if test "$build_old_libs" = yes; then - $ECHO "enable static libraries" + echo "enable static libraries" else - $ECHO "disable static libraries" + echo "disable static libraries" fi exit $? @@ -692,117 +975,209 @@ func_enable_tag () esac } -# Parse options once, thoroughly. This comes as soon as possible in -# the script to make things like `libtool --version' happen quickly. +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () { + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false - # Shorthand for --mode=foo, only valid as the first argument - case $1 in - clean|clea|cle|cl) - shift; set dummy --mode clean ${1+"$@"}; shift - ;; - compile|compil|compi|comp|com|co|c) - shift; set dummy --mode compile ${1+"$@"}; shift - ;; - execute|execut|execu|exec|exe|ex|e) - shift; set dummy --mode execute ${1+"$@"}; shift - ;; - finish|finis|fini|fin|fi|f) - shift; set dummy --mode finish ${1+"$@"}; shift - ;; - install|instal|insta|inst|ins|in|i) - shift; set dummy --mode install ${1+"$@"}; shift - ;; - link|lin|li|l) - shift; set dummy --mode link ${1+"$@"}; shift - ;; - uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) - shift; set dummy --mode uninstall ${1+"$@"}; shift - ;; - esac - # Parse non-mode specific arguments: - while test "$#" -gt 0; do +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do opt="$1" shift - case $opt in - --config) func_config ;; - - --debug) preserve_args="$preserve_args $opt" + --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" - opt_debug='set -x' $opt_debug ;; - - -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break - execute_dlfiles="$execute_dlfiles $1" - shift + --dry-run|--dryrun|-n) + opt_dry_run=: ;; - - --dry-run | -n) opt_dry_run=: ;; - --features) func_features ;; - --finish) mode="finish" ;; - - --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break - case $1 in - # Valid mode arguments: - clean) ;; - compile) ;; - execute) ;; - finish) ;; - install) ;; - link) ;; - relink) ;; - uninstall) ;; - - # Catch anything else as an error - *) func_error "invalid argument for $opt" - exit_cmd=exit - break - ;; - esac - - mode="$1" + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" shift ;; - --preserve-dup-deps) - opt_duplicate_deps=: ;; - - --quiet|--silent) preserve_args="$preserve_args $opt" - opt_silent=: + opt_preserve_dup_deps=: ;; - - --verbose| -v) preserve_args="$preserve_args $opt" + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) opt_silent=false +func_append preserve_args " $opt" ;; - - --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break - preserve_args="$preserve_args $opt $1" - func_enable_tag "$1" # tagname is set here + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" shift ;; + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + # Separate optargs to long options: - -dlopen=*|--mode=*|--tag=*) - func_opt_split "$opt" - set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; - -\?|-h) func_usage ;; - --help) opt_help=: ;; - --version) func_version ;; - - -*) func_fatal_help "unrecognized option \`$opt'" ;; - - *) nonopt="$opt" - break + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) @@ -810,82 +1185,44 @@ func_enable_tag () opt_duplicate_compiler_generated_deps=: ;; *) - opt_duplicate_compiler_generated_deps=$opt_duplicate_deps + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac - # Having warned about all mis-specified options, bail out if - # anything was wrong. - $exit_cmd $EXIT_FAILURE -} + $opt_help || { + # Sanity checks first: + func_check_version_match -# func_check_version_match -# Ensure that we are using m4 macros, and libtool script from the same -# release of libtool. -func_check_version_match () -{ - if test "$package_revision" != "$macro_revision"; then - if test "$VERSION" != "$macro_version"; then - if test -z "$macro_version"; then - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from an older release. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - fi - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, -$progname: but the definition of this LT_INIT comes from revision $macro_revision. -$progname: You should recreate aclocal.m4 with macros from revision $package_revision -$progname: of $PACKAGE $VERSION and run autoconf again. -_LT_EOF + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" fi - exit $EXIT_MISMATCH - fi -} - - -## ----------- ## -## Main. ## -## ----------- ## - -$opt_help || { - # Sanity checks first: - func_check_version_match + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" - if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then - func_fatal_configuration "not configured to build any kind of library" - fi + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi - test -z "$mode" && func_fatal_error "error: you must specify a MODE." + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } - # Darwin sucks - eval std_shrext=\"$shrext_cmds\" + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} - # Only execute mode is allowed to have -dlopen flags. - if test -n "$execute_dlfiles" && test "$mode" != execute; then - func_error "unrecognized option \`-dlopen'" - $ECHO "$help" 1>&2 - exit $EXIT_FAILURE - fi - # Change the help message to a mode-specific one. - generic_help="$help" - help="Try \`$progname --help --mode=$mode' for more information." -} +## ----------- ## +## Main. ## +## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. @@ -950,12 +1287,9 @@ func_ltwrapper_executable_p () # temporary ltwrapper_script. func_ltwrapper_scriptname () { - func_ltwrapper_scriptname_result="" - if func_ltwrapper_executable_p "$1"; then - func_dirname_and_basename "$1" "" "." - func_stripname '' '.exe' "$func_basename_result" - func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" - fi + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file @@ -1001,6 +1335,37 @@ func_source () } +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. @@ -1013,13 +1378,15 @@ func_infer_tag () if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do - func_quote_for_eval "$arg" - CC_quoted="$CC_quoted $func_quote_for_eval_result" + func_append_quoted CC_quoted "$arg" done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;; + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) @@ -1030,11 +1397,13 @@ func_infer_tag () CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. - func_quote_for_eval "$arg" - CC_quoted="$CC_quoted $func_quote_for_eval_result" + func_append_quoted CC_quoted "$arg" done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in - " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. @@ -1097,6 +1466,486 @@ EOF } } + +################################################## +# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS # +################################################## + +# func_convert_core_file_wine_to_w32 ARG +# Helper function used by file name conversion functions when $build is *nix, +# and $host is mingw, cygwin, or some other w32 environment. Relies on a +# correctly configured wine environment available, with the winepath program +# in $build's $PATH. +# +# ARG is the $build file name to be converted to w32 format. +# Result is available in $func_convert_core_file_wine_to_w32_result, and will +# be empty on error (or when ARG is empty) +func_convert_core_file_wine_to_w32 () +{ + $opt_debug + func_convert_core_file_wine_to_w32_result="$1" + if test -n "$1"; then + # Unfortunately, winepath does not exit with a non-zero error code, so we + # are forced to check the contents of stdout. On the other hand, if the + # command is not found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both error code of + # zero AND non-empty stdout, which explains the odd construction: + func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + # func_mode_compile arg... func_mode_compile () { @@ -1137,12 +1986,12 @@ func_mode_compile () ;; -pie | -fpie | -fPIE) - pie_flag="$pie_flag $arg" + func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) - later="$later $arg" + func_append later " $arg" continue ;; @@ -1163,15 +2012,14 @@ func_mode_compile () save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" - func_quote_for_eval "$arg" - lastarg="$lastarg $func_quote_for_eval_result" + func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. - base_compile="$base_compile $lastarg" + func_append base_compile " $lastarg" continue ;; @@ -1187,8 +2035,7 @@ func_mode_compile () esac # case $arg_mode # Aesthetically quote the previous argument. - func_quote_for_eval "$lastarg" - base_compile="$base_compile $func_quote_for_eval_result" + func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in @@ -1213,7 +2060,7 @@ func_mode_compile () *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ - *.[fF][09]? | *.for | *.java | *.obj | *.sx) + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; @@ -1288,7 +2135,7 @@ func_mode_compile () # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then - output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext} + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= @@ -1319,17 +2166,16 @@ compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi - removelist="$removelist $output_obj" + func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist - removelist="$removelist $lockfile" + func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 - if test -n "$fix_srcfile_path"; then - eval srcfile=\"$fix_srcfile_path\" - fi + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result @@ -1349,7 +2195,7 @@ compiler." if test -z "$output_obj"; then # Place PIC objects in $objdir - command="$command -o $lobj" + func_append command " -o $lobj" fi func_show_eval_locale "$command" \ @@ -1396,11 +2242,11 @@ compiler." command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then - command="$command -o $obj" + func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. - command="$command$suppress_output" + func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' @@ -1445,13 +2291,13 @@ compiler." } $opt_help || { -test "$mode" = compile && func_mode_compile ${1+"$@"} + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. - case $mode in + case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. @@ -1482,10 +2328,11 @@ This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes - -prefer-pic try to building PIC objects only - -prefer-non-pic try to building non-PIC objects only + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. @@ -1538,7 +2385,7 @@ either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: - -inst-prefix PREFIX-DIR Use PREFIX-DIR as a staging area for installation + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." @@ -1558,6 +2405,8 @@ The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) @@ -1586,6 +2435,11 @@ The following components of LINK-COMMAND are treated specially: -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. @@ -1619,18 +2473,44 @@ Otherwise, only FILE itself is deleted using RM." ;; *) - func_fatal_help "invalid operation mode \`$mode'" + func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac - $ECHO + echo $ECHO "Try \`$progname --help' for more information about other modes." - - exit $? } - # Now that we've collected a possible --mode arg, show help if necessary - $opt_help && func_mode_help +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi # func_mode_execute arg... @@ -1643,13 +2523,16 @@ func_mode_execute () func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. - for file in $execute_dlfiles; do + for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" @@ -1671,7 +2554,7 @@ func_mode_execute () dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then - dir="$dir/$objdir" + func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" @@ -1712,7 +2595,7 @@ func_mode_execute () for file do case $file in - -*) ;; + -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then @@ -1728,8 +2611,7 @@ func_mode_execute () ;; esac # Quote arguments (to preserve shell metacharacters). - func_quote_for_eval "$file" - args="$args $func_quote_for_eval_result" + func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then @@ -1754,29 +2636,66 @@ func_mode_execute () # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" - $ECHO "export $shlibpath_var" + echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } -test "$mode" = execute && func_mode_execute ${1+"$@"} +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug - libdirs="$nonopt" + libs= + libdirs= admincmds= - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for dir - do - libdirs="$libdirs $dir" - done + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. @@ -1786,7 +2705,7 @@ func_mode_finish () if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" - $opt_dry_run || eval "$cmds" || admincmds="$admincmds + $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done @@ -1795,53 +2714,55 @@ func_mode_finish () # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS - $ECHO "X----------------------------------------------------------------------" | $Xsed - $ECHO "Libraries have been installed in:" - for libdir in $libdirs; do - $ECHO " $libdir" - done - $ECHO - $ECHO "If you ever happen to want to link against installed libraries" - $ECHO "in a given directory, LIBDIR, you must either use libtool, and" - $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'" - $ECHO "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - $ECHO " - add LIBDIR to the \`$shlibpath_var' environment variable" - $ECHO " during execution" - fi - if test -n "$runpath_var"; then - $ECHO " - add LIBDIR to the \`$runpath_var' environment variable" - $ECHO " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval flag=\"$hardcode_libdir_flag_spec\" + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" - $ECHO " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - $ECHO " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - $ECHO " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - $ECHO + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo - $ECHO "See any operating system documentation about shared libraries for" - case $host in - solaris2.[6789]|solaris2.1[0-9]) - $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual" - $ECHO "pages." - ;; - *) - $ECHO "more information, such as the ld(1) and ld.so(8) manual pages." - ;; - esac - $ECHO "X----------------------------------------------------------------------" | $Xsed + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi exit $EXIT_SUCCESS } -test "$mode" = finish && func_mode_finish ${1+"$@"} +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... @@ -1852,7 +2773,7 @@ func_mode_install () # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. - $ECHO "X$nonopt" | $GREP shtool >/dev/null; then + case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " @@ -1866,7 +2787,12 @@ func_mode_install () # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" - install_prog="$install_prog$func_quote_for_eval_result" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac # We need to accept at least all the BSD install flags. dest= @@ -1876,10 +2802,12 @@ func_mode_install () install_type= isdir=no stripme= + no_mode=: for arg do + arg2= if test -n "$dest"; then - files="$files $dest" + func_append files " $dest" dest=$arg continue fi @@ -1887,10 +2815,9 @@ func_mode_install () case $arg in -d) isdir=yes ;; -f) - case " $install_prog " in - *[\\\ /]cp\ *) ;; - *) prev=$arg ;; - esac + if $install_cp; then :; else + prev=$arg + fi ;; -g | -m | -o) prev=$arg @@ -1904,6 +2831,10 @@ func_mode_install () *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi prev= else dest=$arg @@ -1914,7 +2845,11 @@ func_mode_install () # Aesthetically quote the argument. func_quote_for_eval "$arg" - install_prog="$install_prog $func_quote_for_eval_result" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ @@ -1923,6 +2858,13 @@ func_mode_install () test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" @@ -1977,10 +2919,13 @@ func_mode_install () case $file in *.$libext) # Do the static libraries later. - staticlibs="$staticlibs $file" + func_append staticlibs " $file" ;; *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" @@ -1994,23 +2939,23 @@ func_mode_install () if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; - *) current_libdirs="$current_libdirs $libdir" ;; + *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; - *) future_libdirs="$future_libdirs $libdir" ;; + *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" - dir="$dir$objdir" + func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"` + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that @@ -2023,9 +2968,9 @@ func_mode_install () if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. - relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else - relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"` + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" @@ -2043,7 +2988,7 @@ func_mode_install () test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. - func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \ + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in @@ -2083,7 +3028,7 @@ func_mode_install () func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. - test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" + test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) @@ -2183,7 +3128,7 @@ func_mode_install () if test -f "$lib"; then func_source "$lib" fi - libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no @@ -2202,7 +3147,7 @@ func_mode_install () file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. - relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'` + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" @@ -2221,7 +3166,7 @@ func_mode_install () } else # Install the binary that we compiled earlier. - file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"` + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi @@ -2257,11 +3202,13 @@ func_mode_install () # Set up the ranlib parameters. oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then - func_show_eval "$old_striplib $oldlib" 'exit $?' + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. @@ -2280,7 +3227,7 @@ func_mode_install () fi } -test "$mode" = install && func_mode_install ${1+"$@"} +test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p @@ -2323,6 +3270,22 @@ func_generate_dlsyms () extern \"C\" { #endif +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + /* External symbol declarations for the compiler. */\ " @@ -2332,10 +3295,11 @@ extern \"C\" { $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. - progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do - func_verbose "extracting global C symbols from \`$progfile'" - $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then @@ -2371,7 +3335,7 @@ extern \"C\" { eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in - *cygwin | *mingw* | *cegcc* ) + *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; @@ -2384,10 +3348,52 @@ extern \"C\" { func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" - $opt_dry_run || { - eval '$ECHO ": $name " >> "$nlist"' - eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac done $opt_dry_run || { @@ -2415,36 +3421,19 @@ extern \"C\" { if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else - $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms" + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi - $ECHO >> "$output_objdir/$my_dlsyms" "\ + echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; -" - case $host in - *cygwin* | *mingw* | *cegcc* ) - $ECHO >> "$output_objdir/$my_dlsyms" "\ -/* DATA imports from DLLs on WIN32 con't be const, because - runtime relocations are performed -- see ld's documentation - on pseudo-relocs. */" - lt_dlsym_const= ;; - *osf5*) - echo >> "$output_objdir/$my_dlsyms" "\ -/* This system does not cope well with relocations in const data */" - lt_dlsym_const= ;; - *) - lt_dlsym_const=const ;; - esac - - $ECHO >> "$output_objdir/$my_dlsyms" "\ -extern $lt_dlsym_const lt_dlsymlist +extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; -$lt_dlsym_const lt_dlsymlist +LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," @@ -2457,7 +3446,7 @@ lt_${my_prefix}_LTX_preloaded_symbols[] = eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac - $ECHO >> "$output_objdir/$my_dlsyms" "\ + echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; @@ -2484,7 +3473,7 @@ static const void *lt_preloaded_setup() { # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; @@ -2500,7 +3489,7 @@ static const void *lt_preloaded_setup() { for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; - *) symtab_cflags="$symtab_cflags $arg" ;; + *) func_append symtab_cflags " $arg" ;; esac done @@ -2515,16 +3504,16 @@ static const void *lt_preloaded_setup() { case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then - compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else - compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) - compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"` + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; @@ -2538,8 +3527,8 @@ static const void *lt_preloaded_setup() { # really was required. # Nullify the symbol file. - compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"` - finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"` + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } @@ -2549,6 +3538,7 @@ static const void *lt_preloaded_setup() { # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug @@ -2559,9 +3549,11 @@ func_win32_libid () win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | - $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then - win32_nmres=`eval $NM -f posix -A $1 | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ @@ -2590,6 +3582,131 @@ func_win32_libid () $ECHO "$win32_libid_type" } +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} # func_extract_an_archive dir oldlib @@ -2598,7 +3715,18 @@ func_extract_an_archive () $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" - func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?' + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else @@ -2669,7 +3797,7 @@ func_extract_archives () darwin_file= darwin_files= for darwin_file in $darwin_filelist; do - darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ @@ -2684,25 +3812,30 @@ func_extract_archives () func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac - my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } - -# func_emit_wrapper_part1 [arg=no] +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. # -# Emit the first part of a libtool wrapper script on stdout. -# For more information, see the description associated with -# func_emit_wrapper(), below. -func_emit_wrapper_part1 () +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () { - func_emit_wrapper_part1_arg1=no - if test -n "$1" ; then - func_emit_wrapper_part1_arg1=$1 - fi + func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL @@ -2718,7 +3851,6 @@ func_emit_wrapper_part1 () # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. -Xsed='${SED} -e 1s/^X//' sed_quote_subst='$sed_quote_subst' # Be Bourne compatible @@ -2749,31 +3881,135 @@ if test \"\$libtool_install_magic\" = \"$magic\"; then else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then - ECHO=\"$qecho\" - file=\"\$0\" - # Make sure echo works. - if test \"X\$1\" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift - elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then - # Yippee, \$ECHO works! - : - else - # Restart under the correct shell, and then maybe \$ECHO will work. - exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"} - fi - fi\ + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ " - $ECHO "\ + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. - thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\` + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\` + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do - destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\` + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then @@ -2783,30 +4019,13 @@ else esac fi - file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\` + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done -" -} -# end: func_emit_wrapper_part1 - -# func_emit_wrapper_part2 [arg=no] -# -# Emit the second part of a libtool wrapper script on stdout. -# For more information, see the description associated with -# func_emit_wrapper(), below. -func_emit_wrapper_part2 () -{ - func_emit_wrapper_part2_arg1=no - if test -n "$1" ; then - func_emit_wrapper_part2_arg1=$1 - fi - - $ECHO "\ # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1 + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then @@ -2814,7 +4033,7 @@ func_emit_wrapper_part2 () fi # remove .libs from thisdir case \"\$thisdir\" in - *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;; + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi @@ -2869,6 +4088,18 @@ func_emit_wrapper_part2 () if test -f \"\$progdir/\$program\"; then" + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ @@ -2877,253 +4108,28 @@ func_emit_wrapper_part2 () # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\` + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi - # fixup the dll searchpath if we need to. - if test -n "$dllsearchpath"; then - $ECHO "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2* | *-cegcc*) - $ECHO "\ - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $ECHO "\ - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $ECHO "\ - \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 - exit 1 + func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 - $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } -# end: func_emit_wrapper_part2 - - -# func_emit_wrapper [arg=no] -# -# Emit a libtool wrapper script on stdout. -# Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw -# wrapper executable. Must ONLY be called from within -# func_mode_link because it depends on a number of variables -# set therein. -# -# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR -# variable will take. If 'yes', then the emitted script -# will assume that the directory in which it is stored is -# the $objdir directory. This is a cygwin/mingw-specific -# behavior. -func_emit_wrapper () -{ - func_emit_wrapper_arg1=no - if test -n "$1" ; then - func_emit_wrapper_arg1=$1 - fi - - # split this up so that func_emit_cwrapperexe_src - # can call each part independently. - func_emit_wrapper_part1 "${func_emit_wrapper_arg1}" - func_emit_wrapper_part2 "${func_emit_wrapper_arg1}" -} - - -# func_to_host_path arg -# -# Convert paths to host format when used with build tools. -# Intended for use with "native" mingw (where libtool itself -# is running under the msys shell), or in the following cross- -# build environments: -# $build $host -# mingw (msys) mingw [e.g. native] -# cygwin mingw -# *nix + wine mingw -# where wine is equipped with the `winepath' executable. -# In the native mingw case, the (msys) shell automatically -# converts paths for any non-msys applications it launches, -# but that facility isn't available from inside the cwrapper. -# Similar accommodations are necessary for $host mingw and -# $build cygwin. Calling this function does no harm for other -# $host/$build combinations not listed above. -# -# ARG is the path (on $build) that should be converted to -# the proper representation for $host. The result is stored -# in $func_to_host_path_result. -func_to_host_path () -{ - func_to_host_path_result="$1" - if test -n "$1" ; then - case $host in - *mingw* ) - lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - case $build in - *mingw* ) # actually, msys - # awkward: cmd appends spaces to result - lt_sed_strip_trailing_spaces="s/[ ]*\$//" - func_to_host_path_tmp1=`( cmd //c echo "$1" |\ - $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` - func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ - $SED -e "$lt_sed_naive_backslashify"` - ;; - *cygwin* ) - func_to_host_path_tmp1=`cygpath -w "$1"` - func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ - $SED -e "$lt_sed_naive_backslashify"` - ;; - * ) - # Unfortunately, winepath does not exit with a non-zero - # error code, so we are forced to check the contents of - # stdout. On the other hand, if the command is not - # found, the shell will set an exit code of 127 and print - # *an error message* to stdout. So we must check for both - # error code of zero AND non-empty stdout, which explains - # the odd construction: - func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` - if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then - func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\ - $SED -e "$lt_sed_naive_backslashify"` - else - # Allow warning below. - func_to_host_path_result="" - fi - ;; - esac - if test -z "$func_to_host_path_result" ; then - func_error "Could not determine host path corresponding to" - func_error " '$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback: - func_to_host_path_result="$1" - fi - ;; - esac - fi -} -# end: func_to_host_path -# func_to_host_pathlist arg -# -# Convert pathlists to host format when used with build tools. -# See func_to_host_path(), above. This function supports the -# following $build/$host combinations (but does no harm for -# combinations not listed here): -# $build $host -# mingw (msys) mingw [e.g. native] -# cygwin mingw -# *nix + wine mingw -# -# Path separators are also converted from $build format to -# $host format. If ARG begins or ends with a path separator -# character, it is preserved (but converted to $host format) -# on output. -# -# ARG is a pathlist (on $build) that should be converted to -# the proper representation on $host. The result is stored -# in $func_to_host_pathlist_result. -func_to_host_pathlist () -{ - func_to_host_pathlist_result="$1" - if test -n "$1" ; then - case $host in - *mingw* ) - lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - # Remove leading and trailing path separator characters from - # ARG. msys behavior is inconsistent here, cygpath turns them - # into '.;' and ';.', and winepath ignores them completely. - func_to_host_pathlist_tmp2="$1" - # Once set for this call, this variable should not be - # reassigned. It is used in tha fallback case. - func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\ - $SED -e 's|^:*||' -e 's|:*$||'` - case $build in - *mingw* ) # Actually, msys. - # Awkward: cmd appends spaces to result. - lt_sed_strip_trailing_spaces="s/[ ]*\$//" - func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\ - $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""` - func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ - $SED -e "$lt_sed_naive_backslashify"` - ;; - *cygwin* ) - func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"` - func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\ - $SED -e "$lt_sed_naive_backslashify"` - ;; - * ) - # unfortunately, winepath doesn't convert pathlists - func_to_host_pathlist_result="" - func_to_host_pathlist_oldIFS=$IFS - IFS=: - for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do - IFS=$func_to_host_pathlist_oldIFS - if test -n "$func_to_host_pathlist_f" ; then - func_to_host_path "$func_to_host_pathlist_f" - if test -n "$func_to_host_path_result" ; then - if test -z "$func_to_host_pathlist_result" ; then - func_to_host_pathlist_result="$func_to_host_path_result" - else - func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result" - fi - fi - fi - IFS=: - done - IFS=$func_to_host_pathlist_oldIFS - ;; - esac - if test -z "$func_to_host_pathlist_result" ; then - func_error "Could not determine the host path(s) corresponding to" - func_error " '$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback. This may break if $1 contains DOS-style drive - # specifications. The fix is not to complicate the expression - # below, but for the user to provide a working wine installation - # with winepath so that path translation in the cross-to-mingw - # case works properly. - lt_replace_pathsep_nix_to_dos="s|:|;|g" - func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ - $SED -e "$lt_replace_pathsep_nix_to_dos"` - fi - # Now, add the leading and trailing path separators back - case "$1" in - :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" - ;; - esac - case "$1" in - *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;" - ;; - esac - ;; - esac - fi -} -# end: func_to_host_pathlist # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout @@ -3141,31 +4147,23 @@ func_emit_cwrapperexe_src () This wrapper executable should never be moved out of the build directory. If it is, it will not operate correctly. - - Currently, it simply execs the wrapper *script* "$SHELL $output", - but could eventually absorb all of the scripts functionality and - exec $objdir/$outputname directly. */ EOF cat <<"EOF" +#ifdef _MSC_VER +# define _CRT_SECURE_NO_DEPRECATE 1 +#endif #include #include #ifdef _MSC_VER # include # include # include -# define setmode _setmode #else # include # include # ifdef __CYGWIN__ # include -# define HAVE_SETENV -# ifdef __STRICT_ANSI__ -char *realpath (const char *, char *); -int putenv (char *); -int setenv (const char *, const char *, int); -# endif # endif #endif #include @@ -3177,6 +4175,44 @@ int setenv (const char *, const char *, int); #include #include +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) @@ -3192,14 +4228,7 @@ int setenv (const char *, const char *, int); # define S_IXGRP 0 #endif -#ifdef _MSC_VER -# define S_IXUSR _S_IEXEC -# define stat _stat -# ifndef _INTPTR_T_DEFINED -# define intptr_t int -# endif -#endif - +/* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' @@ -3230,10 +4259,6 @@ int setenv (const char *, const char *, int); # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ -#ifdef __CYGWIN__ -# define FOPEN_WB "wb" -#endif - #ifndef FOPEN_WB # define FOPEN_WB "w" #endif @@ -3246,22 +4271,13 @@ int setenv (const char *, const char *, int); if (stale) { free ((void *) stale); stale = 0; } \ } while (0) -#undef LTWRAPPER_DEBUGPRINTF -#if defined DEBUGWRAPPER -# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args -static void -ltwrapper_debugprintf (const char *fmt, ...) -{ - va_list args; - va_start (args, fmt); - (void) vfprintf (stderr, fmt, args); - va_end (args); -} +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; #else -# define LTWRAPPER_DEBUGPRINTF(args) +static int lt_debug = 0; #endif -const char *program_name = NULL; +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); @@ -3271,41 +4287,27 @@ char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); -void lt_fatal (const char *message, ...); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); -void lt_opt_process_env_set (const char *arg); -void lt_opt_process_env_prepend (const char *arg); -void lt_opt_process_env_append (const char *arg); -int lt_split_name_value (const char *arg, char** name, char** value); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); - -static const char *script_text_part1 = -EOF - - func_emit_wrapper_part1 yes | - $SED -e 's/\([\\"]\)/\\\1/g' \ - -e 's/^/ "/' -e 's/$/\\n"/' - echo ";" - cat <"))); + lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n", + nonnull (lt_argv_zero)); for (i = 0; i < newargc; i++) { - LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); + lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n", + i, nonnull (newargz[i])); } EOF @@ -3560,11 +4523,14 @@ EOF mingw*) cat <<"EOF" /* execv doesn't actually work on mingw as expected on unix */ + newargz = prepare_spawn (newargz); rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); if (rval == -1) { /* failed to start process */ - LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); + lt_debugprintf (__FILE__, __LINE__, + "(main) failed to launch target \"%s\": %s\n", + lt_argv_zero, nonnull (strerror (errno))); return 127; } return rval; @@ -3586,7 +4552,7 @@ xmalloc (size_t num) { void *p = (void *) malloc (num); if (!p) - lt_fatal ("Memory exhausted"); + lt_fatal (__FILE__, __LINE__, "memory exhausted"); return p; } @@ -3620,8 +4586,8 @@ check_executable (const char *path) { struct stat st; - LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", - path ? (*path ? path : "EMPTY!") : "NULL!")); + lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n", + nonempty (path)); if ((!path) || (!*path)) return 0; @@ -3638,8 +4604,8 @@ make_executable (const char *path) int rval = 0; struct stat st; - LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", - path ? (*path ? path : "EMPTY!") : "NULL!")); + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); if ((!path) || (!*path)) return 0; @@ -3665,8 +4631,8 @@ find_executable (const char *wrapper) int tmp_len; char *concat_name; - LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", - wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; @@ -3719,7 +4685,8 @@ find_executable (const char *wrapper) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); @@ -3744,7 +4711,8 @@ find_executable (const char *wrapper) } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); @@ -3770,8 +4738,9 @@ chase_symlinks (const char *pathspec) int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { - LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", - tmp_pathspec)); + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) @@ -3793,8 +4762,9 @@ chase_symlinks (const char *pathspec) } else { - char *errstr = strerror (errno); - lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); @@ -3807,7 +4777,8 @@ chase_symlinks (const char *pathspec) tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { - lt_fatal ("Could not follow symlinks for %s", pathspec); + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif @@ -3833,11 +4804,25 @@ strendzap (char *str, const char *pat) return str; } +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + static void -lt_error_core (int exit_status, const char *mode, +lt_error_core (int exit_status, const char *file, + int line, const char *mode, const char *message, va_list ap) { - fprintf (stderr, "%s: %s: ", program_name, mode); + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); @@ -3846,20 +4831,32 @@ lt_error_core (int exit_status, const char *mode, } void -lt_fatal (const char *message, ...) +lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); - lt_error_core (EXIT_FAILURE, "FATAL", message, ap); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + void lt_setenv (const char *name, const char *value) { - LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", - (name ? name : ""), - (value ? value : ""))); + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ @@ -3904,95 +4901,12 @@ lt_extend_str (const char *orig_value, const char *add, int to_end) return new_value; } -int -lt_split_name_value (const char *arg, char** name, char** value) -{ - const char *p; - int len; - if (!arg || !*arg) - return 1; - - p = strchr (arg, (int)'='); - - if (!p) - return 1; - - *value = xstrdup (++p); - - len = strlen (arg) - strlen (*value); - *name = XMALLOC (char, len); - strncpy (*name, arg, len-1); - (*name)[len - 1] = '\0'; - - return 0; -} - -void -lt_opt_process_env_set (const char *arg) -{ - char *name = NULL; - char *value = NULL; - - if (lt_split_name_value (arg, &name, &value) != 0) - { - XFREE (name); - XFREE (value); - lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg); - } - - lt_setenv (name, value); - XFREE (name); - XFREE (value); -} - -void -lt_opt_process_env_prepend (const char *arg) -{ - char *name = NULL; - char *value = NULL; - char *new_value = NULL; - - if (lt_split_name_value (arg, &name, &value) != 0) - { - XFREE (name); - XFREE (value); - lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg); - } - - new_value = lt_extend_str (getenv (name), value, 0); - lt_setenv (name, new_value); - XFREE (new_value); - XFREE (name); - XFREE (value); -} - -void -lt_opt_process_env_append (const char *arg) -{ - char *name = NULL; - char *value = NULL; - char *new_value = NULL; - - if (lt_split_name_value (arg, &name, &value) != 0) - { - XFREE (name); - XFREE (value); - lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg); - } - - new_value = lt_extend_str (getenv (name), value, 1); - lt_setenv (name, new_value); - XFREE (new_value); - XFREE (name); - XFREE (value); -} - void lt_update_exe_path (const char *name, const char *value) { - LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", - (name ? name : ""), - (value ? value : ""))); + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); if (name && *name && value && *value) { @@ -4011,9 +4925,9 @@ lt_update_exe_path (const char *name, const char *value) void lt_update_lib_path (const char *name, const char *value) { - LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", - (name ? name : ""), - (value ? value : ""))); + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); if (name && *name && value && *value) { @@ -4023,11 +4937,158 @@ lt_update_lib_path (const char *name, const char *value) } } +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} EOF } # end: func_emit_cwrapperexe_src +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + # func_mode_link arg... func_mode_link () { @@ -4072,6 +5133,7 @@ func_mode_link () new_inherited_linker_flags= avoid_version=no + bindir= dlfiles= dlprefiles= dlself=no @@ -4164,6 +5226,11 @@ func_mode_link () esac case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. @@ -4195,9 +5262,9 @@ func_mode_link () ;; *) if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" + func_append dlfiles " $arg" else - dlprefiles="$dlprefiles $arg" + func_append dlprefiles " $arg" fi prev= continue @@ -4221,7 +5288,7 @@ func_mode_link () *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; - *) deplibs="$deplibs $qarg.ltframework" # this is fixed later + *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; @@ -4240,7 +5307,7 @@ func_mode_link () moreargs= for fil in `cat "$save_arg"` do -# moreargs="$moreargs $fil" +# func_append moreargs " $fil" arg=$fil # A libtool-controlled object. @@ -4269,7 +5336,7 @@ func_mode_link () if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" + func_append dlfiles " $pic_object" prev= continue else @@ -4281,7 +5348,7 @@ func_mode_link () # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" + func_append dlprefiles " $pic_object" prev= fi @@ -4351,12 +5418,12 @@ func_mode_link () if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; - *) rpath="$rpath $arg" ;; + *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; - *) xrpath="$xrpath $arg" ;; + *) func_append xrpath " $arg" ;; esac fi prev= @@ -4368,28 +5435,28 @@ func_mode_link () continue ;; weak) - weak_libs="$weak_libs $arg" + func_append weak_libs " $arg" prev= continue ;; xcclinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $qarg" + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) - compiler_flags="$compiler_flags $qarg" + func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $wl$qarg" + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" @@ -4425,6 +5492,11 @@ func_mode_link () continue ;; + -bindir) + prev=bindir + continue + ;; + -dlopen) prev=dlfiles continue @@ -4475,15 +5547,16 @@ func_mode_link () ;; -L*) - func_stripname '-L' '' "$arg" - dir=$func_stripname_result - if test -z "$dir"; then + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; @@ -4495,24 +5568,30 @@ func_mode_link () ;; esac case "$deplibs " in - *" -L$dir "*) ;; + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; *) - deplibs="$deplibs -L$dir" - lib_search_path="$lib_search_path $dir" + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'` + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; - *) dllsearchpath="$dllsearchpath:$dir";; + *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; - *) dllsearchpath="$dllsearchpath:$testbindir";; + *) func_append dllsearchpath ":$testbindir";; esac ;; esac @@ -4522,7 +5601,7 @@ func_mode_link () -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; @@ -4536,7 +5615,7 @@ func_mode_link () ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework - deplibs="$deplibs System.ltframework" + func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) @@ -4556,7 +5635,7 @@ func_mode_link () ;; esac fi - deplibs="$deplibs $arg" + func_append deplibs " $arg" continue ;; @@ -4568,21 +5647,22 @@ func_mode_link () # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. - -model|-arch|-isysroot) - compiler_flags="$compiler_flags $arg" + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) - compiler_flags="$compiler_flags $arg" + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; - * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; + * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; @@ -4649,13 +5729,17 @@ func_mode_link () # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; + *) func_append xrpath " $dir" ;; esac continue ;; @@ -4708,8 +5792,8 @@ func_mode_link () for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" - arg="$arg $wl$func_quote_for_eval_result" - compiler_flags="$compiler_flags $func_quote_for_eval_result" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" @@ -4724,9 +5808,9 @@ func_mode_link () for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" - arg="$arg $wl$func_quote_for_eval_result" - compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" - linker_flags="$linker_flags $func_quote_for_eval_result" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" @@ -4754,23 +5838,27 @@ func_mode_link () arg="$func_quote_for_eval_result" ;; - # -64, -mips[0-9] enable 64-bit mode on the SGI compiler - # -r[0-9][0-9]* specifies the processor on the SGI compiler - # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler - # +DA*, +DD* enable 64-bit mode on the HP compiler - # -q* pass through compiler args for the IBM compiler - # -m*, -t[45]*, -txscale* pass through architecture-specific - # compiler args for GCC - # -F/path gives path to uninstalled frameworks, gcc on darwin - # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC - # @file GCC response files + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ - -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*) + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" - compiler_flags="$compiler_flags $arg" + func_append compiler_flags " $arg" continue ;; @@ -4782,7 +5870,7 @@ func_mode_link () *.$objext) # A standard object. - objs="$objs $arg" + func_append objs " $arg" ;; *.lo) @@ -4813,7 +5901,7 @@ func_mode_link () if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" + func_append dlfiles " $pic_object" prev= continue else @@ -4825,7 +5913,7 @@ func_mode_link () # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" + func_append dlprefiles " $pic_object" prev= fi @@ -4870,24 +5958,25 @@ func_mode_link () *.$libext) # An archive. - deplibs="$deplibs $arg" - old_deplibs="$old_deplibs $arg" + func_append deplibs " $arg" + func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. + func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. - dlfiles="$dlfiles $arg" + func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. - dlprefiles="$dlprefiles $arg" + func_append dlprefiles " $func_resolve_sysroot_result" prev= else - deplibs="$deplibs $arg" + func_append deplibs " $func_resolve_sysroot_result" fi continue ;; @@ -4925,7 +6014,7 @@ func_mode_link () if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var - eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\` + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi @@ -4934,6 +6023,8 @@ func_mode_link () func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" @@ -4954,12 +6045,12 @@ func_mode_link () # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do - if $opt_duplicate_deps ; then + if $opt_preserve_dup_deps ; then case "$libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi - libs="$libs $deplib" + func_append libs " $deplib" done if test "$linkmode" = lib; then @@ -4972,9 +6063,9 @@ func_mode_link () if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in - *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac - pre_post_deps="$pre_post_deps $pre_post_dep" + func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= @@ -5041,17 +6132,19 @@ func_mode_link () for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= + func_resolve_sysroot "$lib" case $lib in - *.la) func_source "$lib" ;; + *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do - deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"` + func_basename "$deplib" + deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; - *) deplibs="$deplibs $deplib" ;; + *) func_append deplibs " $deplib" ;; esac done done @@ -5067,16 +6160,17 @@ func_mode_link () lib= found=no case $deplib in - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else - compiler_flags="$compiler_flags $deplib" + func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; - * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi @@ -5161,7 +6255,7 @@ func_mode_link () if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; - * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi @@ -5174,7 +6268,8 @@ func_mode_link () test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" - newlib_search_path="$newlib_search_path $func_stripname_result" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then @@ -5188,7 +6283,8 @@ func_mode_link () finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" - newlib_search_path="$newlib_search_path $func_stripname_result" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" @@ -5199,17 +6295,21 @@ func_mode_link () -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" - dir=$func_stripname_result + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; + *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; - *.la) lib="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" @@ -5227,7 +6327,7 @@ func_mode_link () match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \ + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi @@ -5237,15 +6337,15 @@ func_mode_link () ;; esac if test "$valid_a_lib" != yes; then - $ECHO + echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." - $ECHO "*** I have the capability to make that library automatically link in when" - $ECHO "*** you link to this library. But I can only do this if you have a" - $ECHO "*** shared version of the library, which you do not appear to have" - $ECHO "*** because the file extensions .$libext of this argument makes me believe" - $ECHO "*** that it is just a static archive that I should not use here." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." else - $ECHO + echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" @@ -5272,11 +6372,11 @@ func_mode_link () if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. - newdlprefiles="$newdlprefiles $deplib" + func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else - newdlfiles="$newdlfiles $deplib" + func_append newdlfiles " $deplib" fi fi continue @@ -5318,20 +6418,20 @@ func_mode_link () # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then - tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'` + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; - *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi - dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then - test -n "$dlopen" && dlfiles="$dlfiles $dlopen" - test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then @@ -5342,20 +6442,20 @@ func_mode_link () func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. - convenience="$convenience $ladir/$objdir/$old_library" - old_convenience="$old_convenience $ladir/$objdir/$old_library" + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" - if $opt_duplicate_deps ; then + if $opt_preserve_dup_deps ; then case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi - tmp_libs="$tmp_libs $deplib" + func_append tmp_libs " $deplib" done continue fi # $pass = conv @@ -5363,9 +6463,15 @@ func_mode_link () # Get the name of the library we link against. linklib= - for l in $old_library $library_names; do - linklib="$l" - done + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi @@ -5382,9 +6488,9 @@ func_mode_link () # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. - dlprefiles="$dlprefiles $lib $dependency_libs" + func_append dlprefiles " $lib $dependency_libs" else - newdlfiles="$newdlfiles $lib" + func_append newdlfiles " $lib" fi continue fi # $pass = dlopen @@ -5406,14 +6512,14 @@ func_mode_link () # Find the relevant object directory and library name. if test "X$installed" = Xyes; then - if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else - dir="$libdir" - absdir="$libdir" + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else @@ -5421,12 +6527,12 @@ func_mode_link () dir="$ladir" absdir="$abs_ladir" # Remove this search path later - notinst_path="$notinst_path $abs_ladir" + func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later - notinst_path="$notinst_path $abs_ladir" + func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" @@ -5437,20 +6543,46 @@ func_mode_link () if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - newdlprefiles="$newdlprefiles $dir/$old_library" - # Keep a list of preopened convenience libraries to check - # that they are being used correctly in the link pass. - test -z "$libdir" && \ - dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" - # Otherwise, use the dlname, so that lt_dlopen finds it. - elif test -n "$dlname"; then - newdlprefiles="$newdlprefiles $dir/$dlname" - else - newdlprefiles="$newdlprefiles $dir/$linklib" - fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac fi # $pass = dlpreopen if test -z "$libdir"; then @@ -5468,7 +6600,7 @@ func_mode_link () if test "$linkmode" = prog && test "$pass" != link; then - newlib_search_path="$newlib_search_path $ladir" + func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no @@ -5481,7 +6613,8 @@ func_mode_link () for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" - newlib_search_path="$newlib_search_path $func_stripname_result" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? @@ -5492,12 +6625,12 @@ func_mode_link () # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi - if $opt_duplicate_deps ; then + if $opt_preserve_dup_deps ; then case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi - tmp_libs="$tmp_libs $deplib" + func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... @@ -5512,7 +6645,7 @@ func_mode_link () # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; - *) temp_rpath="$temp_rpath$absdir:" ;; + *) func_append temp_rpath "$absdir:" ;; esac fi @@ -5524,7 +6657,7 @@ func_mode_link () *) case "$compile_rpath " in *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" + *) func_append compile_rpath " $absdir" ;; esac ;; esac @@ -5533,7 +6666,7 @@ func_mode_link () *) case "$finalize_rpath " in *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" + *) func_append finalize_rpath " $libdir" ;; esac ;; esac @@ -5558,12 +6691,12 @@ func_mode_link () case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded - notinst_deplibs="$notinst_deplibs $lib" + func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then - notinst_deplibs="$notinst_deplibs $lib" + func_append notinst_deplibs " $lib" need_relink=yes fi ;; @@ -5580,7 +6713,7 @@ func_mode_link () fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then - $ECHO + echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else @@ -5598,7 +6731,7 @@ func_mode_link () *) case "$compile_rpath " in *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" + *) func_append compile_rpath " $absdir" ;; esac ;; esac @@ -5607,7 +6740,7 @@ func_mode_link () *) case "$finalize_rpath " in *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" + *) func_append finalize_rpath " $libdir" ;; esac ;; esac @@ -5661,7 +6794,7 @@ func_mode_link () linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" - if test "$linkmode" = prog || test "$mode" != relink; then + if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= @@ -5683,9 +6816,9 @@ func_mode_link () if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then - $ECHO - $ECHO "*** And there doesn't seem to be a static archive available" - $ECHO "*** The link will probably fail, sorry" + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi @@ -5712,12 +6845,12 @@ func_mode_link () test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then - add_dir="-L$dir" + add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" + func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi @@ -5739,7 +6872,7 @@ func_mode_link () if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; - *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then @@ -5753,13 +6886,13 @@ func_mode_link () test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi - if test "$linkmode" = prog || test "$mode" = relink; then + if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= @@ -5773,7 +6906,7 @@ func_mode_link () elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; + *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then @@ -5790,7 +6923,7 @@ func_mode_link () if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" + func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi @@ -5825,21 +6958,21 @@ func_mode_link () # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. - $ECHO + echo $ECHO "*** Warning: This system can not link to static lib archive $lib." - $ECHO "*** I have the capability to make that library automatically link in when" - $ECHO "*** you link to this library. But I can only do this if you have a" - $ECHO "*** shared version of the library, which you do not appear to have." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then - $ECHO "*** But as you try to build a module library, libtool will still create " - $ECHO "*** a static module, that should work as long as the dlopening application" - $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime." + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then - $ECHO - $ECHO "*** However, this would only work if libtool was able to extract symbol" - $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" - $ECHO "*** not find such a program. So, this module is probably useless." - $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module @@ -5867,37 +7000,46 @@ func_mode_link () temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; - *) xrpath="$xrpath $temp_xrpath";; + *) func_append xrpath " $temp_xrpath";; esac;; - *) temp_deplibs="$temp_deplibs $libdir";; + *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi - newlib_search_path="$newlib_search_path $absdir" + func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" - if $opt_duplicate_deps ; then + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi - tmp_libs="$tmp_libs $deplib" + func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do + path= case $deplib in -L*) path="$deplib" ;; *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." - dir="$func_dirname_result" + dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; @@ -5924,8 +7066,8 @@ func_mode_link () if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi - compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" - linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi @@ -5958,7 +7100,7 @@ func_mode_link () compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else - compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" @@ -5975,7 +7117,7 @@ func_mode_link () for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; - *) lib_search_path="$lib_search_path $dir" ;; + *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= @@ -6033,10 +7175,10 @@ func_mode_link () -L*) case " $tmp_libs " in *" $deplib "*) ;; - *) tmp_libs="$tmp_libs $deplib" ;; + *) func_append tmp_libs " $deplib" ;; esac ;; - *) tmp_libs="$tmp_libs $deplib" ;; + *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" @@ -6052,7 +7194,7 @@ func_mode_link () ;; esac if test -n "$i" ; then - tmp_libs="$tmp_libs $i" + func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs @@ -6093,7 +7235,7 @@ func_mode_link () # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" - objs="$objs$old_deplibs" + func_append objs "$old_deplibs" ;; lib) @@ -6126,10 +7268,10 @@ func_mode_link () if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else - $ECHO + echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" - libobjs="$libobjs $objs" + func_append libobjs " $objs" fi fi @@ -6188,13 +7330,14 @@ func_mode_link () # which has an extra 1 added just for fun # case $version_type in + # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; - freebsd-aout|freebsd-elf|sunos) + freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" @@ -6304,7 +7447,7 @@ func_mode_link () versuffix="$major.$revision" ;; - linux) + linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" @@ -6327,7 +7470,7 @@ func_mode_link () done # Make executables depend on our current version. - verstring="$verstring:${current}.0" + func_append verstring ":${current}.0" ;; qnx) @@ -6395,10 +7538,10 @@ func_mode_link () fi func_generate_dlsyms "$libname" "$libname" "yes" - libobjs="$libobjs $symfileobj" + func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= - if test "$mode" != relink; then + if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= @@ -6414,7 +7557,7 @@ func_mode_link () continue fi fi - removelist="$removelist $p" + func_append removelist " $p" ;; *) ;; esac @@ -6425,27 +7568,28 @@ func_mode_link () # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - oldlibs="$oldlibs $output_objdir/$libname.$libext" + func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. - oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP` + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do - # lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"` - # deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"` - # dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"` + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do - temp_xrpath="$temp_xrpath -R$libdir" + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; + *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then @@ -6459,7 +7603,7 @@ func_mode_link () for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; - *) dlfiles="$dlfiles $lib" ;; + *) func_append dlfiles " $lib" ;; esac done @@ -6469,19 +7613,19 @@ func_mode_link () for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; - *) dlprefiles="$dlprefiles $lib" ;; + *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*) + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework - deplibs="$deplibs System.ltframework" + func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. @@ -6498,7 +7642,7 @@ func_mode_link () *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then - deplibs="$deplibs -lc" + func_append deplibs " -lc" fi ;; esac @@ -6547,7 +7691,7 @@ EOF if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $i "*) - newdeplibs="$newdeplibs $i" + func_append newdeplibs " $i" i="" ;; esac @@ -6558,21 +7702,21 @@ EOF set dummy $deplib_matches; shift deplib_match=$1 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" + func_append newdeplibs " $i" else droppeddeps=yes - $ECHO + echo $ECHO "*** Warning: dynamic linker does not accept needed library $i." - $ECHO "*** I have the capability to make that library automatically link in when" - $ECHO "*** you link to this library. But I can only do this if you have a" - $ECHO "*** shared version of the library, which I believe you do not have" - $ECHO "*** because a test_compile did reveal that the linker did not use it for" - $ECHO "*** its dynamic dependency list that programs get resolved with at runtime." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which I believe you do not have" + echo "*** because a test_compile did reveal that the linker did not use it for" + echo "*** its dynamic dependency list that programs get resolved with at runtime." fi fi ;; *) - newdeplibs="$newdeplibs $i" + func_append newdeplibs " $i" ;; esac done @@ -6590,7 +7734,7 @@ EOF if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $i "*) - newdeplibs="$newdeplibs $i" + func_append newdeplibs " $i" i="" ;; esac @@ -6601,29 +7745,29 @@ EOF set dummy $deplib_matches; shift deplib_match=$1 if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then - newdeplibs="$newdeplibs $i" + func_append newdeplibs " $i" else droppeddeps=yes - $ECHO + echo $ECHO "*** Warning: dynamic linker does not accept needed library $i." - $ECHO "*** I have the capability to make that library automatically link in when" - $ECHO "*** you link to this library. But I can only do this if you have a" - $ECHO "*** shared version of the library, which you do not appear to have" - $ECHO "*** because a test_compile did reveal that the linker did not use this one" - $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because a test_compile did reveal that the linker did not use this one" + echo "*** as a dynamic dependency that programs can get resolved with at runtime." fi fi else droppeddeps=yes - $ECHO + echo $ECHO "*** Warning! Library $i is needed by this library but I was not able to" - $ECHO "*** make it link in! You will probably need to install it or some" - $ECHO "*** library that it depends on before this library will be fully" - $ECHO "*** functional. Installing it before continuing would be even better." + echo "*** make it link in! You will probably need to install it or some" + echo "*** library that it depends on before this library will be fully" + echo "*** functional. Installing it before continuing would be even better." fi ;; *) - newdeplibs="$newdeplibs $i" + func_append newdeplibs " $i" ;; esac done @@ -6640,15 +7784,27 @@ EOF if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" + func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` + if test -n "$file_magic_glob"; then + libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob` + else + libnameglob=$libname + fi + test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + if test "$want_nocaseglob" = yes; then + shopt -s nocaseglob + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | @@ -6665,13 +7821,13 @@ EOF potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" + func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi @@ -6680,12 +7836,12 @@ EOF fi if test -n "$a_deplib" ; then droppeddeps=yes - $ECHO + echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - $ECHO "*** I have the capability to make that library automatically link in when" - $ECHO "*** you link to this library. But I can only do this if you have a" - $ECHO "*** shared version of the library, which you do not appear to have" - $ECHO "*** because I did check the linker path looking for a file starting" + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else @@ -6696,7 +7852,7 @@ EOF ;; *) # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" + func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. @@ -6712,7 +7868,7 @@ EOF if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" + func_append newdeplibs " $a_deplib" a_deplib="" ;; esac @@ -6723,9 +7879,9 @@ EOF potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test - if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \ + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" + func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi @@ -6734,12 +7890,12 @@ EOF fi if test -n "$a_deplib" ; then droppeddeps=yes - $ECHO + echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - $ECHO "*** I have the capability to make that library automatically link in when" - $ECHO "*** you link to this library. But I can only do this if you have a" - $ECHO "*** shared version of the library, which you do not appear to have" - $ECHO "*** because I did check the linker path looking for a file starting" + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else @@ -6750,32 +7906,32 @@ EOF ;; *) # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" + func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" - tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \ - -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'` + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"` + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi - if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' | - $GREP . >/dev/null; then - $ECHO + case $tmp_deplibs in + *[!\ \ ]*) + echo if test "X$deplibs_check_method" = "Xnone"; then - $ECHO "*** Warning: inter-library dependencies are not supported in this platform." + echo "*** Warning: inter-library dependencies are not supported in this platform." else - $ECHO "*** Warning: inter-library dependencies are not known to be supported." + echo "*** Warning: inter-library dependencies are not known to be supported." fi - $ECHO "*** All declared inter-library dependencies are being dropped." + echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes - fi + ;; + esac ;; esac versuffix=$versuffix_save @@ -6787,23 +7943,23 @@ EOF case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework - newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then - $ECHO - $ECHO "*** Warning: libtool could not satisfy all declared inter-library" + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" - $ECHO "*** a static module, that should work as long as the dlopening" - $ECHO "*** application is linked with the -dlopen flag." + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then - $ECHO - $ECHO "*** However, this would only work if libtool was able to extract symbol" - $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could" - $ECHO "*** not find such a program. So, this module is probably useless." - $ECHO "*** \`nm' from GNU binutils and a full rebuild may help." + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" @@ -6813,16 +7969,16 @@ EOF build_libtool_libs=no fi else - $ECHO "*** The inter-library dependencies that have been dropped here will be" - $ECHO "*** automatically added whenever a program is linked with this library" - $ECHO "*** or is declared to -dlopen it." + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then - $ECHO - $ECHO "*** Since this library must not contain undefined symbols," - $ECHO "*** because either the platform does not support them or" - $ECHO "*** it was explicitly requested with -no-undefined," - $ECHO "*** libtool will only create a static version of it." + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module @@ -6839,9 +7995,9 @@ EOF # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) - newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` - new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` - deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac @@ -6854,7 +8010,7 @@ EOF *) case " $deplibs " in *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; + func_append new_libs " -L$path/$objdir" ;; esac ;; esac @@ -6864,10 +8020,10 @@ EOF -L*) case " $new_libs " in *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; + *) func_append new_libs " $deplib" ;; esac ;; - *) new_libs="$new_libs $deplib" ;; + *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" @@ -6879,15 +8035,22 @@ EOF # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" - test "$mode" != relink && rpath="$compile_rpath$rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else @@ -6896,18 +8059,18 @@ EOF *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" - dep_rpath="$dep_rpath $flag" + func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; + *) func_append perm_rpath " $libdir" ;; esac fi done @@ -6915,17 +8078,13 @@ EOF if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" - if test -n "$hardcode_libdir_flag_spec_ld"; then - eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\" - else - eval dep_rpath=\"$hardcode_libdir_flag_spec\" - fi + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do - rpath="$rpath$dir:" + func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi @@ -6933,7 +8092,7 @@ EOF fi shlibpath="$finalize_shlibpath" - test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi @@ -6959,18 +8118,18 @@ EOF linknames= for link do - linknames="$linknames $link" + func_append linknames " $link" done # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" - delfiles="$delfiles $export_symbols" + func_append delfiles " $export_symbols" fi orig_export_symbols= @@ -7001,13 +8160,45 @@ EOF $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do + for cmd1 in $cmds; do IFS="$save_ifs" - eval cmd=\"$cmd\" - func_len " $cmd" - len=$func_len_result - if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. @@ -7029,7 +8220,7 @@ EOF if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" - $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then @@ -7041,7 +8232,7 @@ EOF # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi @@ -7051,7 +8242,7 @@ EOF case " $convenience " in *" $test_deplib "*) ;; *) - tmp_deplibs="$tmp_deplibs $test_deplib" + func_append tmp_deplibs " $test_deplib" ;; esac done @@ -7071,21 +8262,21 @@ EOF test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" + func_append generated " $gentop" func_extract_archives $gentop $convenience - libobjs="$libobjs $func_extract_archives_result" + func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" - linker_flags="$linker_flags $flag" + func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking - if test "$mode" = relink; then + if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi @@ -7130,7 +8321,8 @@ EOF save_libobjs=$libobjs fi save_output=$output - output_la=`$ECHO "X$output" | $Xsed -e "$basename"` + func_basename "$output" + output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. @@ -7143,13 +8335,16 @@ EOF if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" - $ECHO 'INPUT (' > $output + echo 'INPUT (' > $output for obj in $save_libobjs do - $ECHO "$obj" >> $output + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output done - $ECHO ')' >> $output - delfiles="$delfiles $output" + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" @@ -7163,10 +8358,12 @@ EOF fi for obj do - $ECHO "$obj" >> $output + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output done - delfiles="$delfiles $output" - output=$firstobj\"$file_list_spec$output\" + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." @@ -7190,17 +8387,19 @@ EOF # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. - eval concat_cmds=\"$reload_cmds $objlist $last_robj\" + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. - eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\" + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext - objlist=$obj + objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result @@ -7210,11 +8409,12 @@ EOF # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\" + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi - delfiles="$delfiles $output" + func_append delfiles " $output" else output= @@ -7248,7 +8448,7 @@ EOF lt_exit=$? # Restore the uninstalled library and exit - if test "$mode" = relink; then + if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) @@ -7269,7 +8469,7 @@ EOF if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" - $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"' + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then @@ -7281,7 +8481,7 @@ EOF # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" + func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi @@ -7322,10 +8522,10 @@ EOF # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" + func_append generated " $gentop" func_extract_archives $gentop $dlprefiles - libobjs="$libobjs $func_extract_archives_result" + func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi @@ -7341,7 +8541,7 @@ EOF lt_exit=$? # Restore the uninstalled library and exit - if test "$mode" = relink; then + if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) @@ -7353,7 +8553,7 @@ EOF IFS="$save_ifs" # Restore the uninstalled library and exit - if test "$mode" = relink; then + if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then @@ -7434,18 +8634,21 @@ EOF if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" - reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'` + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" - generated="$generated $gentop" + func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + # Create the old-style object. - reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' @@ -7505,8 +8708,8 @@ EOF case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework - compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` - finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'` + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac @@ -7517,14 +8720,14 @@ EOF if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) - compile_command="$compile_command ${wl}-bind_at_load" - finalize_command="$finalize_command ${wl}-bind_at_load" + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" - compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` - finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'` + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac @@ -7538,7 +8741,7 @@ EOF *) case " $compile_deplibs " in *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; + func_append new_libs " -L$path/$objdir" ;; esac ;; esac @@ -7548,17 +8751,17 @@ EOF -L*) case " $new_libs " in *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; + *) func_append new_libs " $deplib" ;; esac ;; - *) new_libs="$new_libs $deplib" ;; + *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" - compile_command="$compile_command $compile_deplibs" - finalize_command="$finalize_command $finalize_deplibs" + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. @@ -7566,7 +8769,7 @@ EOF # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; + *) func_append finalize_rpath " $libdir" ;; esac done fi @@ -7585,18 +8788,18 @@ EOF *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" + func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; + *) func_append perm_rpath " $libdir" ;; esac fi case $host in @@ -7605,12 +8808,12 @@ EOF case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; - *) dllsearchpath="$dllsearchpath:$libdir";; + *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; - *) dllsearchpath="$dllsearchpath:$testbindir";; + *) func_append dllsearchpath ":$testbindir";; esac ;; esac @@ -7636,18 +8839,18 @@ EOF *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" - rpath="$rpath $flag" + func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; - *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; + *) func_append finalize_perm_rpath " $libdir" ;; esac fi done @@ -7661,8 +8864,8 @@ EOF if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. - compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` - finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP` + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" @@ -7674,15 +8877,15 @@ EOF wrappers_required=yes case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; - *cegcc) - # Disable wrappers for cegcc, we are cross compiling anyway. - wrappers_required=no - ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no @@ -7691,13 +8894,19 @@ EOF esac if test "$wrappers_required" = no; then # Replace the output file specification. - compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' @@ -7720,7 +8929,7 @@ EOF # We should set the runpath_var. rpath= for dir in $perm_rpath; do - rpath="$rpath$dir:" + func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi @@ -7728,7 +8937,7 @@ EOF # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do - rpath="$rpath$dir:" + func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi @@ -7738,11 +8947,18 @@ EOF # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. - link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'` + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + exit $EXIT_SUCCESS fi @@ -7757,7 +8973,7 @@ EOF if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then - relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'` + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= @@ -7769,13 +8985,19 @@ EOF fi # Replace the output file specification. - link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + # Now create the wrapper script. func_verbose "creating $output" @@ -7793,18 +9015,7 @@ EOF fi done relink_command="(cd `pwd`; $relink_command)" - relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` - fi - - # Quote $ECHO for shipping. - if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then - case $progpath in - [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";; - *) qecho="$SHELL `pwd`/$progpath --fallback-echo";; - esac - qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"` - else - qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"` + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. @@ -7884,7 +9095,7 @@ EOF else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then - oldobjs="$oldobjs $symfileobj" + func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" @@ -7892,10 +9103,10 @@ EOF if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" + func_append generated " $gentop" func_extract_archives $gentop $addlibs - oldobjs="$oldobjs $func_extract_archives_result" + func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. @@ -7906,10 +9117,10 @@ EOF # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" + func_append generated " $gentop" func_extract_archives $gentop $dlprefiles - oldobjs="$oldobjs $func_extract_archives_result" + func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have @@ -7925,9 +9136,9 @@ EOF done | sort | sort -uc >/dev/null 2>&1); then : else - $ECHO "copying selected object files to avoid basename conflicts..." + echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" + func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= @@ -7951,18 +9162,30 @@ EOF esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" - oldobjs="$oldobjs $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" ;; - *) oldobjs="$oldobjs $obj" ;; + *) func_append oldobjs " $obj" ;; esac done fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." @@ -8036,7 +9259,7 @@ EOF done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"` + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi @@ -8056,12 +9279,23 @@ EOF *.la) func_basename "$deplib" name="$func_basename_result" - eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" - newdependency_libs="$newdependency_libs $libdir/$name" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" ;; - *) newdependency_libs="$newdependency_libs $deplib" ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" @@ -8075,9 +9309,9 @@ EOF eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" - newdlfiles="$newdlfiles $libdir/$name" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; - *) newdlfiles="$newdlfiles $lib" ;; + *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" @@ -8094,7 +9328,7 @@ EOF eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" - newdlprefiles="$newdlprefiles $libdir/$name" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done @@ -8106,7 +9340,7 @@ EOF [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac - newdlfiles="$newdlfiles $abs" + func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= @@ -8115,15 +9349,33 @@ EOF [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac - newdlprefiles="$newdlprefiles $abs" + func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;; + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; esac $ECHO > $output "\ # $outputname - a libtool library file @@ -8182,7 +9434,7 @@ relink_command=\"$relink_command\"" exit $EXIT_SUCCESS } -{ test "$mode" = link || test "$mode" = relink; } && +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} @@ -8202,9 +9454,9 @@ func_mode_uninstall () for arg do case $arg in - -f) RM="$RM $arg"; rmforce=yes ;; - -*) RM="$RM $arg" ;; - *) files="$files $arg" ;; + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; esac done @@ -8213,24 +9465,23 @@ func_mode_uninstall () rmdirs= - origobjdir="$objdir" for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then - objdir="$origobjdir" + odir="$objdir" else - objdir="$dir/$origobjdir" + odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" - test "$mode" = uninstall && objdir="$dir" + test "$opt_mode" = uninstall && odir="$dir" - # Remember objdir for removal later, being careful to avoid duplicates - if test "$mode" = clean; then + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then case " $rmdirs " in - *" $objdir "*) ;; - *) rmdirs="$rmdirs $objdir" ;; + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; esac fi @@ -8256,18 +9507,17 @@ func_mode_uninstall () # Delete the libtool libraries and symlinks. for n in $library_names; do - rmfiles="$rmfiles $objdir/$n" + func_append rmfiles " $odir/$n" done - test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" + test -n "$old_library" && func_append rmfiles " $odir/$old_library" - case "$mode" in + case "$opt_mode" in clean) - case " $library_names " in - # " " in the beginning catches empty $dlname + case " $library_names " in *" $dlname "*) ;; - *) rmfiles="$rmfiles $objdir/$dlname" ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac - test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then @@ -8295,19 +9545,19 @@ func_mode_uninstall () # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then - rmfiles="$rmfiles $dir/$pic_object" + func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then - rmfiles="$rmfiles $dir/$non_pic_object" + func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) - if test "$mode" = clean ; then + if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) @@ -8317,7 +9567,7 @@ func_mode_uninstall () noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe - rmfiles="$rmfiles $file" + func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. @@ -8326,7 +9576,7 @@ func_mode_uninstall () func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result - rmfiles="$rmfiles $func_ltwrapper_scriptname_result" + func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename @@ -8334,12 +9584,12 @@ func_mode_uninstall () # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles - rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then - rmfiles="$rmfiles $objdir/lt-$name" + func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then - rmfiles="$rmfiles $objdir/lt-${noexename}.c" + func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi @@ -8347,7 +9597,6 @@ func_mode_uninstall () esac func_show_eval "$RM $rmfiles" 'exit_status=1' done - objdir="$origobjdir" # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do @@ -8359,16 +9608,16 @@ func_mode_uninstall () exit $exit_status } -{ test "$mode" = uninstall || test "$mode" = clean; } && +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} -test -z "$mode" && { +test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ - func_fatal_help "invalid operation mode \`$mode'" + func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" diff --git a/m4/libtool.m4 b/m4/libtool.m4 index 39ba996..44e0ecf 100644 --- a/m4/libtool.m4 +++ b/m4/libtool.m4 @@ -1,7 +1,8 @@ # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008 Free Software Foundation, Inc. +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives @@ -10,7 +11,8 @@ m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008 Free Software Foundation, Inc. +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. @@ -37,7 +39,7 @@ m4_define([_LT_COPYING], [dnl # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) -# serial 56 LT_INIT +# serial 57 LT_INIT # LT_PREREQ(VERSION) @@ -66,6 +68,7 @@ esac # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl @@ -82,6 +85,8 @@ AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) @@ -118,7 +123,7 @@ m4_defun([_LT_CC_BASENAME], *) break;; esac done -cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"` +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) @@ -138,6 +143,11 @@ m4_defun([_LT_FILEUTILS_DEFAULTS], m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl @@ -160,10 +170,13 @@ _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our @@ -179,7 +192,6 @@ fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl -_LT_PROG_ECHO_BACKSLASH case $host_os in aix3*) @@ -193,23 +205,6 @@ aix3*) ;; esac -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\([["`\\]]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - # Global variables: ofile=libtool can_build_shared=yes @@ -250,6 +245,28 @@ _LT_CONFIG_COMMANDS ])# _LT_SETUP +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' @@ -408,7 +425,7 @@ m4_define([_lt_decl_all_varnames], # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], -[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`']) +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS @@ -418,7 +435,7 @@ m4_define([_LT_CONFIG_STATUS_DECLARE], # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # -# ='`$ECHO "X$" | $Xsed -e "$delay_single_quote_subst"`' +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) @@ -517,12 +534,20 @@ LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do - case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -533,9 +558,9 @@ done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do - case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" @@ -543,16 +568,38 @@ for var in lt_decl_all_varnames([[ \ esac done -# Fix-up fallback echo if it was mangled by the above quoting rules. -case \$lt_ECHO in -*'\\\[$]0 --fallback-echo"')dnl " - lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\` - ;; -esac - _LT_OUTPUT_LIBTOOL_INIT ]) +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- @@ -562,20 +609,11 @@ _LT_OUTPUT_LIBTOOL_INIT AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) -cat >"$CONFIG_LT" <<_LTEOF -#! $SHELL -# Generated by $as_me. -# Run this file to recreate a libtool stub with the current configuration. - -lt_cl_silent=false -SHELL=\${CONFIG_SHELL-$SHELL} -_LTEOF +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF -AS_SHELL_SANITIZE -_AS_PREPARE - -exec AS_MESSAGE_FD>&1 +lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo @@ -601,7 +639,7 @@ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. -Copyright (C) 2008 Free Software Foundation, Inc. +Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." @@ -646,15 +684,13 @@ chmod +x "$CONFIG_LT" # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. -if test "$no_create" != yes; then - lt_cl_success=: - test "$silent" = yes && - lt_config_lt_args="$lt_config_lt_args --quiet" - exec AS_MESSAGE_LOG_FD>/dev/null - $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false - exec AS_MESSAGE_LOG_FD>>config.log - $lt_cl_success || AS_EXIT(1) -fi +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT @@ -717,15 +753,12 @@ _LT_EOF # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? - sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - _LT_PROG_XSI_SHELLFNS + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) - sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) + _LT_PROG_REPLACE_SHELLFNS - mv -f "$cfgfile" "$ofile" || + mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], @@ -770,6 +803,7 @@ AC_DEFUN([LT_LANG], m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], @@ -791,6 +825,31 @@ m4_defun([_LT_LANG], ])# _LT_LANG +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], @@ -821,6 +880,10 @@ AC_PROVIDE_IFELSE([AC_PROG_GCJ], m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) @@ -831,11 +894,13 @@ AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER @@ -921,7 +986,13 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? - if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD @@ -929,6 +1000,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ rm -rf libconftest.dylib* rm -f conftest.* fi]) + AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no @@ -940,6 +1012,34 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; @@ -967,7 +1067,7 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi - if test "$DSYMUTIL" != ":"; then + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= @@ -977,8 +1077,8 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ ]) -# _LT_DARWIN_LINKER_FEATURES -# -------------------------- +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ @@ -987,7 +1087,13 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES], _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported - _LT_TAGVAR(whole_archive_flag_spec, $1)='' + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in @@ -995,7 +1101,7 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES], *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=echo + output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" @@ -1011,203 +1117,142 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES], fi ]) -# _LT_SYS_MODULE_PATH_AIX -# ----------------------- +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl -AC_LINK_IFELSE(AC_LANG_PROGRAM,[ -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi],[]) -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], -[ifdef([AC_DIVERSION_NOTICE], - [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)], - [AC_DIVERT_PUSH(NOTICE)]) -$1 -AC_DIVERT_POP -])# _LT_SHELL_INIT +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + # _LT_PROG_ECHO_BACKSLASH # ----------------------- -# Add some code to the start of the generated configure script which -# will find an echo command which doesn't interpret backslashes. +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], -[_LT_SHELL_INIT([ -# Check that we are running under the correct shell. -SHELL=${CONFIG_SHELL-/bin/sh} - -case X$lt_ECHO in -X*--fallback-echo) - # Remove one level of quotation (which was required for Make). - ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','` - ;; -esac - -ECHO=${lt_ECHO-echo} -if test "X[$]1" = X--no-reexec; then - # Discard the --no-reexec flag, and continue. - shift -elif test "X[$]1" = X--fallback-echo; then - # Avoid inline document here, it may be left over - : -elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then - # Yippee, $ECHO works! - : +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' else - # Restart under the correct shell. - exec $SHELL "[$]0" --no-reexec ${1+"[$]@"} -fi - -if test "X[$]1" = X--fallback-echo; then - # used as fallback echo - shift - cat <<_LT_EOF -[$]* -_LT_EOF - exit 0 + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' fi -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -if test -z "$lt_ECHO"; then - if test "X${echo_test_string+set}" != Xset; then - # find a string as large as possible, as long as the shell can cope with it - for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do - # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ... - if { echo_test_string=`eval $cmd`; } 2>/dev/null && - { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null - then - break - fi - done - fi - - if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && - echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - : - else - # The Solaris, AIX, and Digital Unix default echo programs unquote - # backslashes. This makes it impossible to quote backslashes using - # echo "$something" | sed 's/\\/\\\\/g' - # - # So, first we look for a working echo in the user's PATH. - - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for dir in $PATH /usr/ucb; do - IFS="$lt_save_ifs" - if (test -f $dir/echo || test -f $dir/echo$ac_exeext) && - test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' && - echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - ECHO="$dir/echo" - break - fi - done - IFS="$lt_save_ifs" - - if test "X$ECHO" = Xecho; then - # We didn't find a better echo, so look for alternatives. - if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' && - echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # This shell has a builtin print -r that does the trick. - ECHO='print -r' - elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } && - test "X$CONFIG_SHELL" != X/bin/ksh; then - # If we have ksh, try running configure again with it. - ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} - export ORIGINAL_CONFIG_SHELL - CONFIG_SHELL=/bin/ksh - export CONFIG_SHELL - exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"} - else - # Try using printf. - ECHO='printf %s\n' - if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' && - echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - # Cool, printf works - : - elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL - export CONFIG_SHELL - SHELL="$CONFIG_SHELL" - export SHELL - ECHO="$CONFIG_SHELL [$]0 --fallback-echo" - elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` && - test "X$echo_testing_string" = 'X\t' && - echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` && - test "X$echo_testing_string" = "X$echo_test_string"; then - ECHO="$CONFIG_SHELL [$]0 --fallback-echo" - else - # maybe with a smaller string... - prev=: - - for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do - if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null - then - break - fi - prev="$cmd" - done +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} - if test "$prev" != 'sed 50q "[$]0"'; then - echo_test_string=`eval $prev` - export echo_test_string - exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"} - else - # Oops. We lost completely, so just stick with echo. - ECHO=echo - fi - fi - fi - fi - fi -fi +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac -# Copy echo and quote the copy suitably for passing to libtool from -# the Makefile, instead of quoting the original, which is used later. -lt_ECHO=$ECHO -if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then - lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo" -fi +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) -AC_SUBST(lt_ECHO) -]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) -_LT_DECL([], [ECHO], [1], - [An echo program that does not interpret backslashes]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], @@ -1236,7 +1281,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '[#]line __oline__ "configure"' > conftest.$ac_ext + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in @@ -1329,14 +1374,27 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) CFLAGS="$SAVE_CFLAGS" fi ;; -sparc*-*solaris*) +*-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in - yes*) LD="${LD-ld} -m elf64_sparc" ;; + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" @@ -1354,14 +1412,47 @@ need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], -[AC_CHECK_TOOL(AR, ar, false) -test -z "$AR" && AR=ar -test -z "$AR_FLAGS" && AR_FLAGS=cru -_LT_DECL([], [AR], [1], [The archiver]) -_LT_DECL([], [AR_FLAGS], [1]) +[_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: @@ -1380,18 +1471,27 @@ old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE @@ -1416,15 +1516,15 @@ AC_CACHE_CHECK([$1], [$2], -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. - $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes @@ -1464,7 +1564,7 @@ AC_CACHE_CHECK([$1], [$2], if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD - $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes @@ -1527,6 +1627,11 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=8192; ;; + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. @@ -1552,6 +1657,11 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl lt_cv_sys_max_cmd_len=196608 ;; + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not @@ -1591,8 +1701,8 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. - while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \ - = "XX$teststring$teststring"; } >/dev/null 2>&1 && + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` @@ -1643,7 +1753,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -[#line __oline__ "configure" +[#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -1684,7 +1794,13 @@ else # endif #endif -void fnord() { int i=42;} +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); @@ -1693,7 +1809,11 @@ int main () if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } /* dlclose (self); */ } else @@ -1869,16 +1989,16 @@ AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD - echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings - $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes @@ -2037,6 +2157,7 @@ m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ @@ -2045,16 +2166,23 @@ if test "$GCC" = yes; then darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'` - else - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= @@ -2067,7 +2195,7 @@ if test "$GCC" = yes; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done - lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk ' + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; @@ -2087,7 +2215,13 @@ BEGIN {RS=" "; FS="/|\n";} { if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` - sys_lib_search_path_spec=`$ECHO $lt_search_path_spec` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) @@ -2113,7 +2247,7 @@ need_version=unknown case $host_os in aix3*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH @@ -2122,7 +2256,7 @@ aix3*) ;; aix[[4-9]]*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes @@ -2175,7 +2309,7 @@ amigaos*) m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; @@ -2187,7 +2321,7 @@ beos*) ;; bsdi[[45]]*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' @@ -2206,8 +2340,9 @@ cygwin* | mingw* | pw32* | cegcc*) need_version=no need_lib_prefix=no - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) + case $GCC,$cc_basename in + yes,*) + # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ @@ -2228,36 +2363,83 @@ cygwin* | mingw* | pw32* | cegcc*) cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib" +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' - sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"` - if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then - # It is most probably a Windows format PATH printed by - # mingw gcc, but we are running on Cygwin. Gcc prints its search - # path with ; separators, and with drive letters. We can handle the - # drive letters (cygwin fileutils understands them), so leave them, - # especially as we might pass files found there to a mingw objdump, - # which wouldn't understand a cygwinified path. Ahh. - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` - else - sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` - fi ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' ;; *) + # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' ;; esac - dynamic_linker='Win32 ld.exe' # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; @@ -2278,7 +2460,7 @@ m4_if([$1], [],[ ;; dgux*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' @@ -2286,10 +2468,6 @@ dgux*) shlibpath_var=LD_LIBRARY_PATH ;; -freebsd1*) - dynamic_linker=no - ;; - freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. @@ -2297,7 +2475,7 @@ freebsd* | dragonfly*) objformat=`/usr/bin/objformat` else case $host_os in - freebsd[[123]]*) objformat=aout ;; + freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi @@ -2315,7 +2493,7 @@ freebsd* | dragonfly*) esac shlibpath_var=LD_LIBRARY_PATH case $host_os in - freebsd2*) + freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) @@ -2335,12 +2513,26 @@ freebsd* | dragonfly*) ;; gnu*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; @@ -2386,12 +2578,14 @@ hpux9* | hpux10* | hpux11*) soname_spec='${libname}${release}${shared_ext}$major' ;; esac - # HP-UX runs *really* slowly unless shared libraries are mode 555. + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 ;; interix[[3-9]]*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' @@ -2407,7 +2601,7 @@ irix5* | irix6* | nonstopux*) nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; @@ -2444,9 +2638,9 @@ linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; -# This must be Linux ELF. -linux* | k*bsd*-gnu) - version_type=linux +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' @@ -2454,16 +2648,21 @@ linux* | k*bsd*-gnu) finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no + # Some binutils ld are patched to set DT_RUNPATH - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ - LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" - AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], - [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], - [shlibpath_overrides_runpath=yes])]) - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install @@ -2472,7 +2671,7 @@ linux* | k*bsd*-gnu) # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '` + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi @@ -2504,7 +2703,7 @@ netbsd*) ;; newsos6) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes @@ -2573,7 +2772,7 @@ rdos*) ;; solaris*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' @@ -2598,7 +2797,7 @@ sunos4*) ;; sysv4 | sysv4.3*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH @@ -2622,7 +2821,7 @@ sysv4 | sysv4.3*) sysv4*MP*) if test -d /usr/nec ;then - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH @@ -2653,7 +2852,7 @@ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' @@ -2663,7 +2862,7 @@ tpf*) ;; uts4*) - version_type=linux + version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH @@ -2705,6 +2904,8 @@ _LT_DECL([], [library_names_spec], [1], The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], @@ -2817,6 +3018,7 @@ AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], @@ -2938,6 +3140,11 @@ case $reload_flag in esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' @@ -2946,8 +3153,8 @@ case $host_os in fi ;; esac -_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl -_LT_DECL([], [reload_cmds], [2])dnl +_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl +_LT_TAGDECL([], [reload_cmds], [2])dnl ])# _LT_CMD_RELOAD @@ -2999,16 +3206,18 @@ mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. - if ( file / ) >/dev/null 2>&1; then + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; -cegcc) +cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' @@ -3038,6 +3247,10 @@ gnu*) lt_cv_deplibs_check_method=pass_all ;; +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in @@ -3046,11 +3259,11 @@ hpux10.20* | hpux11*) lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) - [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'] + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) - lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library' + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac @@ -3071,8 +3284,8 @@ irix5* | irix6* | nonstopux*) lt_cv_deplibs_check_method=pass_all ;; -# This must be Linux ELF. -linux* | k*bsd*-gnu) +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; @@ -3150,6 +3363,21 @@ tpf*) ;; esac ]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown @@ -3157,7 +3385,11 @@ test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], - [Command to use when deplibs_check_method == "file_magic"]) + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD @@ -3214,7 +3446,19 @@ if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. - AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :) + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" @@ -3227,13 +3471,13 @@ _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD - (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD) + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -3248,15 +3492,76 @@ dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' -# LT_LIB_M -# -------- -# check for math library -AC_DEFUN([LT_LIB_M], +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in -*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*) +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) @@ -3284,7 +3589,12 @@ m4_defun([_LT_COMPILER_NO_RTTI], _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then - _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, @@ -3301,6 +3611,7 @@ _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl @@ -3368,8 +3679,8 @@ esac lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= @@ -3393,6 +3704,7 @@ for ac_symprfx in "" "_"; do # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ @@ -3405,6 +3717,7 @@ for ac_symprfx in "" "_"; do else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no @@ -3426,7 +3739,7 @@ _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" @@ -3438,6 +3751,18 @@ _LT_EOF if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + #ifdef __cplusplus extern "C" { #endif @@ -3449,7 +3774,7 @@ _LT_EOF cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ -const struct { +LT@&t@_DLSYM_CONST struct { const char *name; void *address; } @@ -3475,15 +3800,15 @@ static const void *lt_preloaded_setup() { _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext - lt_save_LIBS="$LIBS" - lt_save_CFLAGS="$CFLAGS" + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi - LIBS="$lt_save_LIBS" - CFLAGS="$lt_save_CFLAGS" + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi @@ -3516,6 +3841,13 @@ else AC_MSG_RESULT(ok) fi +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], @@ -3526,6 +3858,8 @@ _LT_DECL([global_symbol_to_c_name_address], _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS @@ -3537,7 +3871,6 @@ _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= -AC_MSG_CHECKING([for $compiler option to produce PIC]) m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then @@ -3588,6 +3921,11 @@ m4_if([$1], [CXX], [ # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. @@ -3637,6 +3975,12 @@ m4_if([$1], [CXX], [ ;; esac ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; dgux*) case $cc_basename in ec++*) @@ -3693,7 +4037,7 @@ m4_if([$1], [CXX], [ ;; esac ;; - linux* | k*bsd*-gnu) + linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler @@ -3726,8 +4070,8 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; - xlc* | xlC*) - # IBM XL 8.0 on PPC + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' @@ -3789,7 +4133,7 @@ m4_if([$1], [CXX], [ ;; solaris*) case $cc_basename in - CC*) + CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' @@ -3893,6 +4237,12 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag @@ -3935,6 +4285,15 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in @@ -3977,7 +4336,7 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; - linux* | k*bsd*-gnu) + linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) @@ -3998,7 +4357,13 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; - pgcc* | pgf77* | pgf90* | pgf95*) + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' @@ -4010,25 +4375,40 @@ m4_if([$1], [CXX], [ # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; - xl*) - # IBM XL C 8.0/Fortran 10.1 on PPC + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; - *Sun\ F*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' - _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; esac ;; @@ -4060,7 +4440,7 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in - f77* | f90* | f95*) + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; @@ -4117,9 +4497,11 @@ case $host_os in _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac -AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) -_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], - [How to pass a linker flag through the compiler]) + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. @@ -4138,6 +4520,8 @@ fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # @@ -4158,6 +4542,7 @@ _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl @@ -4166,27 +4551,37 @@ m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" - ;; + ;; cygwin* | mingw* | cegcc*) - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' - ;; + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - ;; + ;; esac - _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= @@ -4201,7 +4596,6 @@ m4_if([$1], [CXX], [ _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported @@ -4249,7 +4643,33 @@ dnl Note also adjust exclude_expsyms for C++ above. esac _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' @@ -4267,6 +4687,7 @@ dnl Note also adjust exclude_expsyms for C++ above. fi supports_anon_versioning=no case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... @@ -4282,11 +4703,12 @@ dnl Note also adjust exclude_expsyms for C++ above. _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 -*** Warning: the GNU linker, at least up to release 2.9.1, is reported +*** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to modify your PATH -*** so that a non-GNU linker is found, and then restart. +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. _LT_EOF fi @@ -4322,10 +4744,12 @@ _LT_EOF # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' @@ -4343,6 +4767,11 @@ _LT_EOF fi ;; + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no @@ -4358,7 +4787,7 @@ _LT_EOF _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; - gnu* | linux* | tpf* | k*bsd*-gnu) + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in @@ -4368,15 +4797,16 @@ _LT_EOF if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then - tmp_addflag= + tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler - _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; - pgf77* | pgf90* | pgf95*) # Portland Group f77 and f90 compilers - _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; @@ -4387,13 +4817,17 @@ _LT_EOF lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; - xl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 - _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 @@ -4409,17 +4843,16 @@ _LT_EOF fi case $cc_basename in - xlf*) + xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= - _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir' - _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac @@ -4433,8 +4866,8 @@ _LT_EOF _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; @@ -4452,8 +4885,8 @@ _LT_EOF _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi @@ -4499,8 +4932,8 @@ _LT_EOF *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi @@ -4540,8 +4973,10 @@ _LT_EOF else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi @@ -4628,9 +5063,9 @@ _LT_EOF _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. - _LT_SYS_MODULE_PATH_AIX + _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' @@ -4639,14 +5074,19 @@ _LT_EOF else # Determine the default libpath from the value encoded in an # empty executable. - _LT_SYS_MODULE_PATH_AIX + _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' @@ -4678,20 +5118,64 @@ _LT_EOF # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' - # FIXME: Should let the user specify the lib program. - _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' - _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`' - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac ;; darwin* | rhapsody*) @@ -4704,10 +5188,6 @@ _LT_EOF _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; - freebsd1*) - _LT_TAGVAR(ld_shlibs, $1)=no - ;; - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little @@ -4720,7 +5200,7 @@ _LT_EOF ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2*) + freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes @@ -4729,7 +5209,7 @@ _LT_EOF # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no @@ -4737,7 +5217,7 @@ _LT_EOF hpux9*) if test "$GCC" = yes; then - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi @@ -4752,14 +5232,13 @@ _LT_EOF ;; hpux10*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' - _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes @@ -4771,16 +5250,16 @@ _LT_EOF ;; hpux11*) - if test "$GCC" = yes -a "$with_gnu_ld" = no; then + if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else @@ -4792,7 +5271,14 @@ _LT_EOF _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) - _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi @@ -4820,19 +5306,34 @@ _LT_EOF irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - AC_LINK_IFELSE(int foo(void) {}, - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' - ) - LDFLAGS="$save_LDFLAGS" + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' @@ -4894,17 +5395,17 @@ _LT_EOF _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' @@ -4914,13 +5415,13 @@ _LT_EOF osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' @@ -4933,9 +5434,9 @@ _LT_EOF _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) @@ -5111,36 +5612,38 @@ x|xyes) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. - AC_MSG_CHECKING([whether -lc should be explicitly linked in]) - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if AC_TRY_EVAL(ac_compile) 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) - pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) - _LT_TAGVAR(allow_undefined_flag, $1)= - if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) - then - _LT_TAGVAR(archive_cmds_need_lc, $1)=no - else - _LT_TAGVAR(archive_cmds_need_lc, $1)=yes - fi - _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)]) + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi @@ -5177,9 +5680,6 @@ _LT_TAGDECL([], [no_undefined_flag], [1], _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) -_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1], - [[If ld is used when linking, flag to hardcode $libdir into a binary - during linking. This must work even if $libdir does not exist]]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], @@ -5205,8 +5705,6 @@ _LT_TAGDECL([], [inherit_rpath], [0], to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) -_LT_TAGDECL([], [fix_srcfile_path], [1], - [Fix the shell variable $srcfile for the compiler]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], @@ -5217,6 +5715,8 @@ _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented @@ -5310,37 +5810,22 @@ CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG -# _LT_PROG_CXX -# ------------ -# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++ -# compiler, we have our own version here. -m4_defun([_LT_PROG_CXX], -[ -pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes]) -AC_PROG_CXX -if test -n "$CXX" && ( test "X$CXX" != "Xno" && - ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || - (test "X$CXX" != "Xg++"))) ; then - AC_PROG_CXXCPP -else - _lt_caught_CXX_error=yes -fi -popdef([AC_MSG_ERROR]) -])# _LT_PROG_CXX - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([_LT_PROG_CXX], []) - - # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], -[AC_REQUIRE([_LT_PROG_CXX])dnl -m4_require([_LT_FILEUTILS_DEFAULTS])dnl +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no @@ -5352,7 +5837,6 @@ _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported @@ -5362,6 +5846,8 @@ _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no @@ -5393,6 +5879,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Allow CC to be a program name with arguments. lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX @@ -5410,6 +5897,7 @@ if test "$_lt_caught_CXX_error" != yes; then fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) @@ -5431,8 +5919,8 @@ if test "$_lt_caught_CXX_error" != yes; then # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' @@ -5464,7 +5952,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no @@ -5573,10 +6061,10 @@ if test "$_lt_caught_CXX_error" != yes; then _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. - _LT_SYS_MODULE_PATH_AIX + _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" - _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' @@ -5585,14 +6073,19 @@ if test "$_lt_caught_CXX_error" != yes; then else # Determine the default libpath from the value encoded in an # empty executable. - _LT_SYS_MODULE_PATH_AIX + _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' - # Exported symbols can be pulled into shared objects from archives - _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. @@ -5622,28 +6115,75 @@ if test "$_lt_caught_CXX_error" != yes; then ;; cygwin* | mingw* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, - # as there is no search path for DLLs. - _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' - _LT_TAGVAR(allow_undefined_flag, $1)=unsupported - _LT_TAGVAR(always_export_symbols, $1)=no - _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - _LT_TAGVAR(ld_shlibs, $1)=no - fi - ;; + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; @@ -5666,7 +6206,7 @@ if test "$_lt_caught_CXX_error" != yes; then esac ;; - freebsd[[12]]*) + freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no @@ -5685,6 +6225,11 @@ if test "$_lt_caught_CXX_error" != yes; then gnu*) ;; + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: @@ -5709,11 +6254,11 @@ if test "$_lt_caught_CXX_error" != yes; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then - _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no @@ -5774,7 +6319,7 @@ if test "$_lt_caught_CXX_error" != yes; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then @@ -5784,10 +6329,10 @@ if test "$_lt_caught_CXX_error" != yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi @@ -5817,7 +6362,7 @@ if test "$_lt_caught_CXX_error" != yes; then case $cc_basename in CC*) # SGI C++ - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is @@ -5828,9 +6373,9 @@ if test "$_lt_caught_CXX_error" != yes; then *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes @@ -5841,7 +6386,7 @@ if test "$_lt_caught_CXX_error" != yes; then _LT_TAGVAR(inherit_rpath, $1)=yes ;; - linux* | k*bsd*-gnu) + linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler @@ -5859,7 +6404,7 @@ if test "$_lt_caught_CXX_error" != yes; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' @@ -5896,26 +6441,26 @@ if test "$_lt_caught_CXX_error" != yes; then pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in - *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*) + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ - compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"' + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ - $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ - $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; - *) # Version 6 will use weak symbols + *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; @@ -5923,7 +6468,7 @@ if test "$_lt_caught_CXX_error" != yes; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' - _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ @@ -5942,9 +6487,9 @@ if test "$_lt_caught_CXX_error" != yes; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; - xl*) + xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' @@ -5964,13 +6509,13 @@ if test "$_lt_caught_CXX_error" != yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' - _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. - output_verbose_link_cmd='echo' + output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is @@ -6039,7 +6584,7 @@ if test "$_lt_caught_CXX_error" != yes; then _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi - output_verbose_link_cmd=echo + output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi @@ -6074,15 +6619,15 @@ if test "$_lt_caught_CXX_error" != yes; then case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' - _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ - $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; @@ -6098,17 +6643,17 @@ if test "$_lt_caught_CXX_error" != yes; then # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. - output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed' + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac @@ -6118,7 +6663,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support @@ -6154,7 +6699,7 @@ if test "$_lt_caught_CXX_error" != yes; then solaris*) case $cc_basename in - CC*) + CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' @@ -6175,7 +6720,7 @@ if test "$_lt_caught_CXX_error" != yes; then esac _LT_TAGVAR(link_all_deplibs, $1)=yes - output_verbose_link_cmd='echo' + output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is @@ -6195,14 +6740,14 @@ if test "$_lt_caught_CXX_error" != yes; then if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then - _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. @@ -6213,7 +6758,7 @@ if test "$_lt_caught_CXX_error" != yes; then # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. - output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"' + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' @@ -6267,6 +6812,10 @@ if test "$_lt_caught_CXX_error" != yes; then CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' @@ -6322,6 +6871,7 @@ if test "$_lt_caught_CXX_error" != yes; then fi # test -n "$compiler" CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC @@ -6336,6 +6886,29 @@ AC_LANG_POP ])# _LT_LANG_CXX_CONFIG +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose @@ -6344,6 +6917,7 @@ AC_LANG_POP # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= @@ -6393,7 +6967,20 @@ public class foo { } }; _LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF ]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then @@ -6405,7 +6992,7 @@ if AC_TRY_EVAL(ac_compile); then pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do - case $p in + case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. @@ -6414,13 +7001,22 @@ if AC_TRY_EVAL(ac_compile); then test $p = "-R"; then prev=$p continue - else - prev= fi + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac if test "$pre_test_object_deps_done" = no; then - case $p in - -L* | -R*) + case ${prev} in + -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. @@ -6440,8 +7036,10 @@ if AC_TRY_EVAL(ac_compile); then _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi + prev= ;; + *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. @@ -6477,6 +7075,7 @@ else fi $RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], @@ -6513,7 +7112,7 @@ linux*) solaris*) case $cc_basename in - CC*) + CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as @@ -6557,32 +7156,16 @@ _LT_TAGDECL([], [compiler_lib_search_path], [1], ])# _LT_SYS_HIDDEN_LIBDEPS -# _LT_PROG_F77 -# ------------ -# Since AC_PROG_F77 is broken, in that it returns the empty string -# if there is no fortran compiler, we have our own version here. -m4_defun([_LT_PROG_F77], -[ -pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes]) -AC_PROG_F77 -if test -z "$F77" || test "X$F77" = "Xno"; then - _lt_disable_F77=yes -fi -popdef([AC_MSG_ERROR]) -])# _LT_PROG_F77 - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([_LT_PROG_F77], []) - - # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], -[AC_REQUIRE([_LT_PROG_F77])dnl -AC_LANG_PUSH(Fortran 77) +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= @@ -6592,7 +7175,6 @@ _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no @@ -6601,6 +7183,8 @@ _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no @@ -6640,7 +7224,9 @@ if test "$_lt_disable_F77" != yes; then # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} + CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) @@ -6694,38 +7280,24 @@ if test "$_lt_disable_F77" != yes; then GCC=$lt_save_GCC CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG -# _LT_PROG_FC -# ----------- -# Since AC_PROG_FC is broken, in that it returns the empty string -# if there is no fortran compiler, we have our own version here. -m4_defun([_LT_PROG_FC], -[ -pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes]) -AC_PROG_FC -if test -z "$FC" || test "X$FC" = "Xno"; then - _lt_disable_FC=yes -fi -popdef([AC_MSG_ERROR]) -])# _LT_PROG_FC - -dnl aclocal-1.4 backwards compatibility: -dnl AC_DEFUN([_LT_PROG_FC], []) - - # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], -[AC_REQUIRE([_LT_PROG_FC])dnl -AC_LANG_PUSH(Fortran) +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= @@ -6735,7 +7307,6 @@ _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= -_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no @@ -6744,6 +7315,8 @@ _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no @@ -6783,7 +7356,9 @@ if test "$_lt_disable_FC" != yes; then # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} + CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu @@ -6839,7 +7414,8 @@ if test "$_lt_disable_FC" != yes; then fi # test -n "$compiler" GCC=$lt_save_GCC - CC="$lt_save_CC" + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP @@ -6876,10 +7452,12 @@ _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. -lt_save_CC="$CC" +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" @@ -6889,6 +7467,8 @@ _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change @@ -6908,10 +7488,82 @@ fi AC_LANG_RESTORE GCC=$lt_save_GCC -CC="$lt_save_CC" +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler @@ -6943,9 +7595,11 @@ _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} +CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) @@ -6958,7 +7612,8 @@ fi GCC=$lt_save_GCC AC_LANG_RESTORE -CC="$lt_save_CC" +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG @@ -6978,6 +7633,13 @@ dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], @@ -7017,6 +7679,15 @@ _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) # _LT_DECL_SED # ------------ @@ -7110,8 +7781,8 @@ m4_defun([_LT_CHECK_SHELL_FEATURES], # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" - test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ - = c,a/b,, \ + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes @@ -7150,208 +7821,162 @@ _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES -# _LT_PROG_XSI_SHELLFNS -# --------------------- -# Bourne and XSI compatible variants of some useful shell functions. -m4_defun([_LT_PROG_XSI_SHELLFNS], -[case $xsi_shell in - yes) - cat << \_LT_EOF >> "$cfgfile" - -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - case ${1} in - */*) func_dirname_result="${1%/*}${2}" ;; - * ) func_dirname_result="${3}" ;; - esac -} - -# func_basename file -func_basename () -{ - func_basename_result="${1##*/}" -} - -# func_dirname_and_basename file append nondir_replacement -# perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value retuned in "$func_basename_result" -# Implementation must be kept synchronized with func_dirname -# and func_basename. For efficiency, we do not delegate to -# those functions but instead duplicate the functionality here. -func_dirname_and_basename () -{ - case ${1} in - */*) func_dirname_result="${1%/*}${2}" ;; - * ) func_dirname_result="${3}" ;; - esac - func_basename_result="${1##*/}" -} - -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -func_stripname () -{ - # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are - # positional parameters, so assign one to ordinary parameter first. - func_stripname_result=${3} - func_stripname_result=${func_stripname_result#"${1}"} - func_stripname_result=${func_stripname_result%"${2}"} -} - -# func_opt_split -func_opt_split () -{ - func_opt_split_opt=${1%%=*} - func_opt_split_arg=${1#*=} -} - -# func_lo2o object -func_lo2o () -{ - case ${1} in - *.lo) func_lo2o_result=${1%.lo}.${objext} ;; - *) func_lo2o_result=${1} ;; - esac -} - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=${1%.*}.lo -} +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=$(( $[*] )) -} -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=${#1} -} +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) -_LT_EOF - ;; - *) # Bourne compatible functions. - cat << \_LT_EOF >> "$cfgfile" + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - # Extract subdirectory from the argument. - func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi -} + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) -# func_basename file -func_basename () -{ - func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"` -} + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) -dnl func_dirname_and_basename -dnl A portable version of this function is already defined in general.m4sh -dnl so there is no need for it here. + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -# func_strip_suffix prefix name -func_stripname () -{ - case ${2} in - .*) func_stripname_result=`$ECHO "X${3}" \ - | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;; - *) func_stripname_result=`$ECHO "X${3}" \ - | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;; - esac -} + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) -# sed scripts: -my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q' -my_sed_long_arg='1s/^-[[^=]]*=//' + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) -# func_opt_split -func_opt_split () -{ - func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"` - func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"` -} - -# func_lo2o object -func_lo2o () -{ - func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"` -} - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'` -} + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=`expr "$[@]"` -} +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len` -} + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) -_LT_EOF -esac + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi -case $lt_shell_append in - yes) - cat << \_LT_EOF >> "$cfgfile" +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "$[1]+=\$[2]" -} -_LT_EOF +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac ;; - *) - cat << \_LT_EOF >> "$cfgfile" - -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "$[1]=\$$[1]\$[2]" -} - -_LT_EOF + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac ;; - esac + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac ]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 index 34151a3..5d9acd8 100644 --- a/m4/ltoptions.m4 +++ b/m4/ltoptions.m4 @@ -1,13 +1,14 @@ # Helper functions for option handling. -*- Autoconf -*- # -# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. -# serial 6 ltoptions.m4 +# serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) @@ -125,7 +126,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in -*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*) +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) @@ -133,13 +134,13 @@ case $host in esac test -z "$AS" && AS=as -_LT_DECL([], [AS], [0], [Assembler program])dnl +_LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool -_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump -_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], @@ -325,9 +326,24 @@ dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], - [AS_HELP_STRING([--with-pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], - [pic_mode="$withval"], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 index f3c5309..07a8602 100644 --- a/m4/ltversion.m4 +++ b/m4/ltversion.m4 @@ -7,17 +7,17 @@ # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. -# Generated from ltversion.in. +# @configure_input@ -# serial 3017 ltversion.m4 +# serial 3337 ltversion.m4 # This file is part of GNU Libtool -m4_define([LT_PACKAGE_VERSION], [2.2.6b]) -m4_define([LT_PACKAGE_REVISION], [1.3017]) +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], -[macro_version='2.2.6b' -macro_revision='1.3017' +[macro_version='2.4.2' +macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 index 637bb20..c573da9 100644 --- a/m4/lt~obsolete.m4 +++ b/m4/lt~obsolete.m4 @@ -1,13 +1,13 @@ # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # -# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc. +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. -# serial 4 lt~obsolete.m4 +# serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # @@ -77,7 +77,6 @@ m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) -m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) @@ -90,3 +89,10 @@ m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/match.c b/match.c deleted file mode 100644 index 91ec315..0000000 --- a/match.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - * 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 -#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 */ -#ifdef HAVE_FNMATCH -# include -#endif /* HAVE_FNMATCH */ -#ifdef HAVE_EXTENDED_GLOB -# include -#endif /* HAVE_EXTENDED_GLOB */ -#ifdef HAVE_NETGROUP_H -# include -#endif /* HAVE_NETGROUP_H */ -#include -#include -#include -#include -#include -#include -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif - -#include "sudo.h" -#include "interfaces.h" -#include "parse.h" -#include - -#ifndef HAVE_FNMATCH -# include "emul/fnmatch.h" -#endif /* HAVE_FNMATCH */ -#ifndef HAVE_EXTENDED_GLOB -# include "emul/glob.h" -#endif /* HAVE_EXTENDED_GLOB */ -#ifdef USING_NONUNIX_GROUPS -# include "nonunix.h" -#endif /* USING_NONUNIX_GROUPS */ - -static struct member_list empty; - -static int command_matches_dir __P((char *, size_t)); -static int command_matches_glob __P((char *, char *)); -static int command_matches_fnmatch __P((char *, char *)); -static int command_matches_normal __P((char *, char *)); - -/* - * Returns TRUE if string 's' contains meta characters. - */ -#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL) - -/* - * Check for user described by pw in a list of members. - * Returns ALLOW, DENY or UNSPEC. - */ -static int -_userlist_matches(pw, list) - struct passwd *pw; - struct member_list *list; -{ - struct member *m; - struct alias *a; - int rval, matched = UNSPEC; - - tq_foreach_rev(list, m) { - switch (m->type) { - case ALL: - matched = !m->negated; - break; - case NETGROUP: - if (netgr_matches(m->name, NULL, NULL, pw->pw_name)) - matched = !m->negated; - break; - case USERGROUP: - if (usergr_matches(m->name, pw->pw_name, pw)) - matched = !m->negated; - break; - case ALIAS: - if ((a = alias_find(m->name, USERALIAS)) != NULL) { - rval = _userlist_matches(pw, &a->members); - if (rval != UNSPEC) - matched = m->negated ? !rval : rval; - break; - } - /* FALLTHROUGH */ - case WORD: - if (userpw_matches(m->name, pw->pw_name, pw)) - matched = !m->negated; - break; - } - if (matched != UNSPEC) - break; - } - return(matched); -} - -int -userlist_matches(pw, list) - struct passwd *pw; - struct member_list *list; -{ - alias_seqno++; - return(_userlist_matches(pw, list)); -} - -/* - * Check for user described by pw in a list of members. - * If both lists are empty compare against def_runas_default. - * Returns ALLOW, DENY or UNSPEC. - */ -static int -_runaslist_matches(user_list, group_list) - struct member_list *user_list; - struct member_list *group_list; -{ - struct member *m; - struct alias *a; - int rval; - int user_matched = UNSPEC; - int group_matched = UNSPEC; - - if (tq_empty(user_list) && tq_empty(group_list)) - return(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw)); - - if (runas_pw != NULL) { - tq_foreach_rev(user_list, m) { - switch (m->type) { - case ALL: - user_matched = !m->negated; - break; - case NETGROUP: - if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name)) - user_matched = !m->negated; - break; - case USERGROUP: - if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) - user_matched = !m->negated; - break; - case ALIAS: - if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { - rval = _runaslist_matches(&a->members, &empty); - if (rval != UNSPEC) - user_matched = m->negated ? !rval : rval; - break; - } - /* FALLTHROUGH */ - case WORD: - if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) - user_matched = !m->negated; - break; - } - if (user_matched != UNSPEC) - break; - } - } - - if (runas_gr != NULL) { - if (user_matched == UNSPEC) { - if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0) - user_matched = ALLOW; /* only changing group */ - } - tq_foreach_rev(group_list, m) { - switch (m->type) { - case ALL: - group_matched = !m->negated; - break; - case ALIAS: - if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { - rval = _runaslist_matches(&a->members, &empty); - if (rval != UNSPEC) - group_matched = m->negated ? !rval : rval; - break; - } - /* FALLTHROUGH */ - case WORD: - if (group_matches(m->name, runas_gr)) - group_matched = !m->negated; - break; - } - if (group_matched != UNSPEC) - break; - } - } - - if (user_matched == DENY || group_matched == DENY) - return(DENY); - if (user_matched == group_matched || runas_gr == NULL) - return(user_matched); - return(UNSPEC); -} - -int -runaslist_matches(user_list, group_list) - struct member_list *user_list; - struct member_list *group_list; -{ - alias_seqno++; - return(_runaslist_matches(user_list ? user_list : &empty, - group_list ? group_list : &empty)); -} - -/* - * Check for host and shost in a list of members. - * Returns ALLOW, DENY or UNSPEC. - */ -static int -_hostlist_matches(list) - struct member_list *list; -{ - struct member *m; - struct alias *a; - int rval, matched = UNSPEC; - - tq_foreach_rev(list, m) { - switch (m->type) { - case ALL: - matched = !m->negated; - break; - case NETGROUP: - if (netgr_matches(m->name, user_host, user_shost, NULL)) - matched = !m->negated; - break; - case NTWKADDR: - if (addr_matches(m->name)) - matched = !m->negated; - break; - case ALIAS: - if ((a = alias_find(m->name, HOSTALIAS)) != NULL) { - rval = _hostlist_matches(&a->members); - if (rval != UNSPEC) - matched = m->negated ? !rval : rval; - break; - } - /* FALLTHROUGH */ - case WORD: - if (hostname_matches(user_shost, user_host, m->name)) - matched = !m->negated; - break; - } - if (matched != UNSPEC) - break; - } - return(matched); -} - -int -hostlist_matches(list) - struct member_list *list; -{ - alias_seqno++; - return(_hostlist_matches(list)); -} - -/* - * Check for cmnd and args in a list of members. - * Returns ALLOW, DENY or UNSPEC. - */ -static int -_cmndlist_matches(list) - struct member_list *list; -{ - struct member *m; - int matched = UNSPEC; - - tq_foreach_rev(list, m) { - matched = cmnd_matches(m); - if (matched != UNSPEC) - break; - } - return(matched); -} - -int -cmndlist_matches(list) - struct member_list *list; -{ - alias_seqno++; - return(_cmndlist_matches(list)); -} - -/* - * Check cmnd and args. - * Returns ALLOW, DENY or UNSPEC. - */ -int -cmnd_matches(m) - struct member *m; -{ - struct alias *a; - struct sudo_command *c; - int rval, matched = UNSPEC; - - switch (m->type) { - case ALL: - matched = !m->negated; - break; - case ALIAS: - alias_seqno++; - if ((a = alias_find(m->name, CMNDALIAS)) != NULL) { - rval = _cmndlist_matches(&a->members); - if (rval != UNSPEC) - matched = m->negated ? !rval : rval; - } - break; - case COMMAND: - c = (struct sudo_command *)m->name; - if (command_matches(c->cmnd, c->args)) - matched = !m->negated; - break; - } - return(matched); -} - -/* - * If path doesn't end in /, return TRUE iff cmnd & path name the same inode; - * otherwise, return TRUE if user_cmnd names one of the inodes in path. - */ -int -command_matches(sudoers_cmnd, sudoers_args) - char *sudoers_cmnd; - char *sudoers_args; -{ - /* Check for pseudo-commands */ - if (sudoers_cmnd[0] != '/') { - /* - * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND - * a) there are no args in sudoers OR - * b) there are no args on command line and none req by sudoers OR - * c) there are args in sudoers and on command line and they match - */ - if (strcmp(sudoers_cmnd, "sudoedit") != 0 || - strcmp(user_cmnd, "sudoedit") != 0) - return(FALSE); - if (!sudoers_args || - (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || - (sudoers_args && - fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { - efree(safe_cmnd); - safe_cmnd = estrdup(sudoers_cmnd); - return(TRUE); - } else - return(FALSE); - } - - if (has_meta(sudoers_cmnd)) { - /* - * If sudoers_cmnd has meta characters in it, we need to - * use glob(3) and/or fnmatch(3) to do the matching. - */ - if (def_fast_glob) - return(command_matches_fnmatch(sudoers_cmnd, sudoers_args)); - return(command_matches_glob(sudoers_cmnd, sudoers_args)); - } - return(command_matches_normal(sudoers_cmnd, sudoers_args)); -} - -static int -command_matches_fnmatch(sudoers_cmnd, sudoers_args) - char *sudoers_cmnd; - char *sudoers_args; -{ - /* - * Return true if fnmatch(3) succeeds AND - * a) there are no args in sudoers OR - * b) there are no args on command line and none required by sudoers OR - * c) there are args in sudoers and on command line and they match - * else return false. - */ - if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) - return(FALSE); - if (!sudoers_args || - (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || - (sudoers_args && - fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { - if (safe_cmnd) - free(safe_cmnd); - safe_cmnd = estrdup(user_cmnd); - return(TRUE); - } else - return(FALSE); -} - -static int -command_matches_glob(sudoers_cmnd, sudoers_args) - char *sudoers_cmnd; - char *sudoers_args; -{ - struct stat sudoers_stat; - size_t dlen; - char **ap, *base, *cp; - glob_t gl; - - /* - * First check to see if we can avoid the call to glob(3). - * Short circuit if there are no meta chars in the command itself - * and user_base and basename(sudoers_cmnd) don't match. - */ - dlen = strlen(sudoers_cmnd); - if (sudoers_cmnd[dlen - 1] != '/') { - if ((base = strrchr(sudoers_cmnd, '/')) != NULL) { - base++; - if (!has_meta(base) && strcmp(user_base, base) != 0) - return(FALSE); - } - } - /* - * Return true if we find a match in the glob(3) results AND - * a) there are no args in sudoers OR - * b) there are no args on command line and none required by sudoers OR - * c) there are args in sudoers and on command line and they match - * else return false. - */ -#define GLOB_FLAGS (GLOB_NOSORT | GLOB_MARK | GLOB_BRACE | GLOB_TILDE) - if (glob(sudoers_cmnd, GLOB_FLAGS, NULL, &gl) != 0 || gl.gl_pathc == 0) { - globfree(&gl); - return(FALSE); - } - /* For each glob match, compare basename, st_dev and st_ino. */ - for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) { - /* If it ends in '/' it is a directory spec. */ - dlen = strlen(cp); - if (cp[dlen - 1] == '/') { - if (command_matches_dir(cp, dlen)) - return(TRUE); - continue; - } - - /* Only proceed if user_base and basename(cp) match */ - if ((base = strrchr(cp, '/')) != NULL) - base++; - else - base = cp; - if (strcmp(user_base, base) != 0 || - stat(cp, &sudoers_stat) == -1) - continue; - if (user_stat == NULL || - (user_stat->st_dev == sudoers_stat.st_dev && - user_stat->st_ino == sudoers_stat.st_ino)) { - efree(safe_cmnd); - safe_cmnd = estrdup(cp); - break; - } - } - globfree(&gl); - if (cp == NULL) - return(FALSE); - - if (!sudoers_args || - (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || - (sudoers_args && - fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { - efree(safe_cmnd); - safe_cmnd = estrdup(user_cmnd); - return(TRUE); - } - return(FALSE); -} - -static int -command_matches_normal(sudoers_cmnd, sudoers_args) - char *sudoers_cmnd; - char *sudoers_args; -{ - struct stat sudoers_stat; - char *base; - size_t dlen; - - /* If it ends in '/' it is a directory spec. */ - dlen = strlen(sudoers_cmnd); - if (sudoers_cmnd[dlen - 1] == '/') - return(command_matches_dir(sudoers_cmnd, dlen)); - - /* Only proceed if user_base and basename(sudoers_cmnd) match */ - if ((base = strrchr(sudoers_cmnd, '/')) == NULL) - base = sudoers_cmnd; - else - base++; - if (strcmp(user_base, base) != 0 || - stat(sudoers_cmnd, &sudoers_stat) == -1) - return(FALSE); - - /* - * Return true if inode/device matches AND - * a) there are no args in sudoers OR - * b) there are no args on command line and none req by sudoers OR - * c) there are args in sudoers and on command line and they match - */ - if (user_stat != NULL && - (user_stat->st_dev != sudoers_stat.st_dev || - user_stat->st_ino != sudoers_stat.st_ino)) - return(FALSE); - if (!sudoers_args || - (!user_args && sudoers_args && !strcmp("\"\"", sudoers_args)) || - (sudoers_args && - fnmatch(sudoers_args, user_args ? user_args : "", 0) == 0)) { - efree(safe_cmnd); - safe_cmnd = estrdup(sudoers_cmnd); - return(TRUE); - } - return(FALSE); -} - -/* - * Return TRUE if user_cmnd names one of the inodes in dir, else FALSE. - */ -static int -command_matches_dir(sudoers_dir, dlen) - char *sudoers_dir; - size_t dlen; -{ - struct stat sudoers_stat; - struct dirent *dent; - char buf[PATH_MAX]; - DIR *dirp; - - /* - * Grot through directory entries, looking for user_base. - */ - dirp = opendir(sudoers_dir); - if (dirp == NULL) - return(FALSE); - - if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) { - closedir(dirp); - return(FALSE); - } - while ((dent = readdir(dirp)) != NULL) { - /* ignore paths > PATH_MAX (XXX - log) */ - buf[dlen] = '\0'; - if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf)) - continue; - - /* only stat if basenames are the same */ - if (strcmp(user_base, dent->d_name) != 0 || - stat(buf, &sudoers_stat) == -1) - continue; - if (user_stat->st_dev == sudoers_stat.st_dev && - user_stat->st_ino == sudoers_stat.st_ino) { - efree(safe_cmnd); - safe_cmnd = estrdup(buf); - break; - } - } - - closedir(dirp); - return(dent != NULL); -} - -static int -addr_matches_if(n) - char *n; -{ - int i; - union sudo_in_addr_un addr; - struct interface *ifp; -#ifdef HAVE_IN6_ADDR - int j; -#endif - int family; - -#ifdef HAVE_IN6_ADDR - if (inet_pton(AF_INET6, n, &addr.ip6) > 0) { - family = AF_INET6; - } else -#endif - { - family = AF_INET; - addr.ip4.s_addr = inet_addr(n); - } - - for (i = 0; i < num_interfaces; i++) { - ifp = &interfaces[i]; - if (ifp->family != family) - continue; - switch(family) { - case AF_INET: - if (ifp->addr.ip4.s_addr == addr.ip4.s_addr || - (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr) - == addr.ip4.s_addr) - return(TRUE); - break; -#ifdef HAVE_IN6_ADDR - case AF_INET6: - if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr, - sizeof(addr.ip6.s6_addr)) == 0) - return(TRUE); - for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) { - if ((ifp->addr.ip6.s6_addr[j] & ifp->netmask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j]) - break; - } - if (j == sizeof(addr.ip6.s6_addr)) - return(TRUE); -#endif - } - } - - return(FALSE); -} - -static int -addr_matches_if_netmask(n, m) - char *n; - char *m; -{ - int i; - union sudo_in_addr_un addr, mask; - struct interface *ifp; -#ifdef HAVE_IN6_ADDR - int j; -#endif - int family; - -#ifdef HAVE_IN6_ADDR - if (inet_pton(AF_INET6, n, &addr.ip6) > 0) - family = AF_INET6; - else -#endif - { - family = AF_INET; - addr.ip4.s_addr = inet_addr(n); - } - - if (family == AF_INET) { - if (strchr(m, '.')) - mask.ip4.s_addr = inet_addr(m); - else { - i = 32 - atoi(m); - mask.ip4.s_addr = 0xffffffff; - mask.ip4.s_addr >>= i; - mask.ip4.s_addr <<= i; - mask.ip4.s_addr = htonl(mask.ip4.s_addr); - } - } -#ifdef HAVE_IN6_ADDR - else { - if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) { - j = atoi(m); - for (i = 0; i < 16; i++) { - if (j < i * 8) - mask.ip6.s6_addr[i] = 0; - else if (i * 8 + 8 <= j) - mask.ip6.s6_addr[i] = 0xff; - else - mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8); - } - } - } -#endif /* HAVE_IN6_ADDR */ - - for (i = 0; i < num_interfaces; i++) { - ifp = &interfaces[i]; - if (ifp->family != family) - continue; - switch(family) { - case AF_INET: - if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr) - return(TRUE); -#ifdef HAVE_IN6_ADDR - case AF_INET6: - for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) { - if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j]) - break; - } - if (j == sizeof(addr.ip6.s6_addr)) - return(TRUE); -#endif /* HAVE_IN6_ADDR */ - } - } - - return(FALSE); -} - -/* - * Returns TRUE if "n" is one of our ip addresses or if - * "n" is a network that we are on, else returns FALSE. - */ -int -addr_matches(n) - char *n; -{ - char *m; - int retval; - - /* If there's an explicit netmask, use it. */ - if ((m = strchr(n, '/'))) { - *m++ = '\0'; - retval = addr_matches_if_netmask(n, m); - *(m - 1) = '/'; - } else - retval = addr_matches_if(n); - - return(retval); -} - -/* - * Returns TRUE if the hostname matches the pattern, else FALSE - */ -int -hostname_matches(shost, lhost, pattern) - char *shost; - char *lhost; - char *pattern; -{ - if (has_meta(pattern)) { - if (strchr(pattern, '.')) - return(!fnmatch(pattern, lhost, FNM_CASEFOLD)); - else - return(!fnmatch(pattern, shost, FNM_CASEFOLD)); - } else { - if (strchr(pattern, '.')) - return(!strcasecmp(lhost, pattern)); - else - return(!strcasecmp(shost, pattern)); - } -} - -/* - * Returns TRUE if the user/uid from sudoers matches the specified user/uid, - * else returns FALSE. - */ -int -userpw_matches(sudoers_user, user, pw) - char *sudoers_user; - char *user; - struct passwd *pw; -{ - if (pw != NULL && *sudoers_user == '#') { - uid_t uid = (uid_t) atoi(sudoers_user + 1); - if (uid == pw->pw_uid) - return(TRUE); - } - return(strcmp(sudoers_user, user) == 0); -} - -/* - * Returns TRUE if the group/gid from sudoers matches the specified group/gid, - * else returns FALSE. - */ -int -group_matches(sudoers_group, gr) - char *sudoers_group; - struct group *gr; -{ - if (*sudoers_group == '#') { - gid_t gid = (gid_t) atoi(sudoers_group + 1); - if (gid == gr->gr_gid) - return(TRUE); - } - return(strcmp(gr->gr_name, sudoers_group) == 0); -} - -/* - * Returns TRUE if the given user belongs to the named group, - * else returns FALSE. - */ -int -usergr_matches(group, user, pw) - char *group; - char *user; - struct passwd *pw; -{ - /* make sure we have a valid usergroup, sudo style */ - if (*group++ != '%') - return(FALSE); - -#ifdef USING_NONUNIX_GROUPS - if (*group == ':') - return(sudo_nonunix_groupcheck(++group, user, pw)); -#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 (user_in_group(pw, group)) - return(TRUE); - -#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); -#endif /* USING_NONUNIX_GROUPS */ - - return(FALSE); -} - -/* - * Returns TRUE if "host" and "user" belong to the netgroup "netgr", - * else return FALSE. Either of "host", "shost" or "user" may be NULL - * in which case that argument is not checked... - * - * XXX - swap order of host & shost - */ -int -netgr_matches(netgr, lhost, shost, user) - char *netgr; - char *lhost; - char *shost; - char *user; -{ - static char *domain; -#ifdef HAVE_GETDOMAINNAME - static int initialized; -#endif - - /* make sure we have a valid netgroup, sudo style */ - if (*netgr++ != '+') - return(FALSE); - -#ifdef HAVE_GETDOMAINNAME - /* get the domain name (if any) */ - if (!initialized) { - domain = (char *) emalloc(MAXHOSTNAMELEN + 1); - if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') { - efree(domain); - domain = NULL; - } - initialized = 1; - } -#endif /* HAVE_GETDOMAINNAME */ - -#ifdef HAVE_INNETGR - if (innetgr(netgr, lhost, user, domain)) - return(TRUE); - else if (lhost != shost && innetgr(netgr, shost, user, domain)) - return(TRUE); -#endif /* HAVE_INNETGR */ - - return(FALSE); -} diff --git a/memrchr.c b/memrchr.c deleted file mode 100644 index 35e07de..0000000 --- a/memrchr.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2007 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. - */ - -#include -#include -#include - -/* - * Reverse memchr() - * Find the last occurrence of 'c' in the buffer 's' of size 'n'. - */ -void * -memrchr(s, c, n) - const void *s; - int c; - size_t n; -{ - const unsigned char *cp; - - if (n != 0) { - cp = (unsigned char *)s + n; - do { - if (*(--cp) == (unsigned char)c) - return((void *)cp); - } while (--n != 0); - } - return((void *)0); -} diff --git a/missing.h b/missing.h deleted file mode 100644 index 749323a..0000000 --- a/missing.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#ifndef _SUDO_MISSING_H -#define _SUDO_MISSING_H - -#ifdef __STDC__ -# include -#else -# include -#endif - -/* Functions "missing" from libc. */ - -struct timeval; -struct timespec; - -#ifndef HAVE_CLOSEFROM -void closefrom __P((int)); -#endif -#ifndef HAVE_GETCWD -char *getcwd __P((char *, size_t size)); -#endif -#ifndef HAVE_GETLINE -ssize_t getline __P((char **, size_t *, FILE *)); -#endif -#ifndef HAVE_UTIMES -int utimes __P((const char *, const struct timeval *)); -#endif -#ifdef HAVE_FUTIME -int futimes __P((int, const struct timeval *)); -#endif -#ifndef HAVE_SNPRINTF -int snprintf __P((char *, size_t, const char *, ...)) - __printflike(3, 4); -#endif -#ifndef HAVE_VSNPRINTF -int vsnprintf __P((char *, size_t, const char *, va_list)) - __printflike(3, 0); -#endif -#ifndef HAVE_ASPRINTF -int asprintf __P((char **, const char *, ...)) - __printflike(2, 3); -#endif -#ifndef HAVE_VASPRINTF -int vasprintf __P((char **, const char *, va_list)) - __printflike(2, 0); -#endif -#ifndef HAVE_STRCASECMP -int strcasecmp __P((const char *, const char *)); -#endif -#ifndef HAVE_STRLCAT -size_t strlcat __P((char *, const char *, size_t)); -#endif -#ifndef HAVE_STRLCPY -size_t strlcpy __P((char *, const char *, size_t)); -#endif -#ifndef HAVE_MEMRCHR -void *memrchr __P((const void *, int, size_t)); -#endif -#ifndef HAVE_MKSTEMPS -int mkstemps __P((char *, int)); -#endif -#ifndef HAVE_NANOSLEEP -int nanosleep __P((const struct timespec *, struct timespec *)); -#endif -#ifndef HAVE_SETENV -int setenv __P((const char *, const char *, int)); -#endif -#ifndef HAVE_UNSETENV -int unsetenv __P((const char *)); -#endif -#ifndef HAVE_STRSIGNAL -char *strsignal __P((int)); -#endif -#ifndef HAVE_SETSID -pid_t setsid __P((void)); -#endif - -#endif /* _SUDO_MISSING_H */ diff --git a/mkdefaults b/mkdefaults deleted file mode 100755 index 90f3b0c..0000000 --- a/mkdefaults +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/perl -w -# -# Generate sudo_defs_table and associated defines -# -# Input should be formatted thusly: -# -# var_name -# TYPE -# description (or NULL) -# array of struct def_values if TYPE == T_TUPLE - -# Deal with optional -o (output) argument -if ($#ARGV > 0 && $ARGV[0] eq "-o") { - shift; - $header = $cfile = shift; - $header .= '.h'; - $cfile .= '.c'; -} -die "usage: $0 [input_file]\n" unless $#ARGV == -1 || $#ARGV == 0; - -$infile = $ARGV[0] || "def_data.in"; -if (!defined($header)) { - $header = $infile; - $header =~ s/(\.in)?$/.h/; -} -if (!defined($cfile)) { - $cfile = $infile; - $cfile =~ s/(\.in)?$/.c/; -} - -open(IN, "<$infile") || die "$0: can't open $infile: $!\n"; -open(HEADER, ">$header") || die "$0: can't open $header: $!\n"; -open(CFILE, ">$cfile") || die "$0: can't open $cfile: $!\n"; - -$count = 0; -@tuple_values = ( "never" ); -@records = (); -while() { - chomp; - s/\s*#.*$//; - next if /^\s*$/; - - if (/^\S/) { - # Store previous record and begin new one - $records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var); - - $var = $_; - $type = ''; - $desc = undef; - $values = undef; - $callback = undef; - $field = 0; - } else { - $field++; - s/^\s+//; - s/\s+$//; - if ($field == 1) { - # type - $type = $_; - } elsif ($field == 2) { - # description - if ($_ eq "NULL") { - $desc = "NULL"; - } else { - # Strip leading and trailing double quote and escape the rest - s/^"//; - s/"$//; - s/"/\\"/g; - $desc = "\"$_\""; - } - } elsif ($field == 3 || $field == 4) { - if (s/^\*//) { - $callback = $_; - } else { - die "$0: syntax error near line $.\n" if $type !~ /^T_TUPLE/; - $values = [ split ]; - foreach $v (@$values) { - push(@tuple_values, $v) unless grep(/^$v$/, @tuple_values); - } - } - } else { - die "$0: syntax error near line $.\n"; - } - } -} -$records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var); - -# Print out value arrays -for ($i = 0; $i < $count; $i++) { - if (defined($records[$i]->[3])) { - die "Values list specified for non-tupple\n" unless - $records[$i]->[1] =~ /^T_TUPLE/; - printf CFILE "static struct def_values def_data_%s[] = {\n", $records[$i]->[0]; - foreach (@{$records[$i]->[3]}) { - print CFILE " { \"$_\", $_ },\n"; - } - print CFILE " { NULL, 0 },\n"; - print CFILE "};\n\n"; - } -} - -# Print each record -print CFILE "struct sudo_defs_types sudo_defs_table[] = {\n {\n"; -for ($i = 0; $i < $count; $i++) { - &print_record($records[$i], $i); -} -print CFILE "\tNULL, 0, NULL\n }\n};\n"; - -# Print out def_tuple -if (@tuple_values) { - print HEADER "\nenum def_tupple {\n"; - for ($i = 0; $i <= $#tuple_values; $i++) { - printf HEADER "\t%s%s\n", $tuple_values[$i], - $i != $#tuple_values ? "," : ""; - } - print HEADER "};\n"; -} - -close(IN); -close(HEADER); -close(CFILE); - -sub print_record { - my ($rec, $recnum) = @_; - my ($i, $v, $defname); - # each variable gets a macro to access its value - for ($rec->[1]) { - if (/^T_U?INT/) { $v = "ival"; } - elsif (/^T_STR/) { $v = "str"; } - elsif (/^T_FLAG/) { $v = "flag"; } - elsif (/^T_MODE/) { $v = "mode"; } - elsif (/^T_LIST/) { $v = "list"; } - elsif (/^T_LOGFAC/) { $v = "ival"; } - elsif (/^T_LOGPRI/) { $v = "ival"; } - elsif (/^T_TUPLE/) { $v = "tuple"; } - elsif (/^T_FLOAT/) { $v = "fval"; } - else { die "$0: unknown defaults type: $_\n"; } - } - printf HEADER "#define %-23s (sudo_defs_table[$recnum].sd_un.${v})\n", - "def_$rec->[0]"; - - $defname = "I_" . uc($rec->[0]); - printf HEADER "#define %-24s%d", $defname, $recnum; - #print HEADER "\t/* $rec->[2] */" if defined($rec->[2]); - print HEADER "\n"; - - print CFILE "\t\"$rec->[0]\", $rec->[1],\n\t$rec->[2],\n"; - if (defined($rec->[3])) { - printf CFILE "\tdef_data_$rec->[0],\n"; - } else { - printf CFILE "\tNULL,\n"; - } - printf CFILE "\t$rec->[4],\n" if defined($rec->[4]); - print CFILE " }, {\n"; -} diff --git a/mkdep.pl b/mkdep.pl new file mode 100755 index 0000000..3388fd9 --- /dev/null +++ b/mkdep.pl @@ -0,0 +1,226 @@ +#!/usr/bin/env perl + +use File::Temp qw/ :mktemp /; +use Fcntl; +use warnings; + +die "usage: $0 Makefile ...\n" unless $#ARGV >= 0; + +my @incpaths; +my %dir_vars; +my %implicit; +my %generated; + +# Read in MANIFEST fail if present +my %manifest; +if (open(MANIFEST, ") { + chomp; + next unless /([^\/]+\.[cly])$/; + $manifest{$1} = $_; + } +} + +foreach (@ARGV) { + mkdep($_); +} + +sub mkdep { + my $file = $_[0]; + $file =~ s:^\./+::; # strip off leading ./ + + my $makefile; + if (open(MF, "<$file")) { + local $/; # enable "slurp" mode + $makefile = ; + } else { + warn "$0: $file: $!\n"; + return undef; + } + close(MF); + + # New makefile, minus the autogenerated dependencies + my $separator = "# Autogenerated dependencies, do not modify"; + my $new_makefile = $makefile; + $new_makefile =~ s/${separator}.*$//s; + $new_makefile .= "$separator\n"; + + # Old makefile, join lines with continuation characters + $makefile =~ s/\\\n//mg; + + # Expand some configure bits + $makefile =~ s:\@DEV\@::g; + $makefile =~ s:\@COMMON_OBJS\@:aix.lo:; + $makefile =~ s:\@SUDO_OBJS\@:preload.o selinux.o sesh.o sudo_noexec.lo:; + $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo plugin_error.lo:; + # XXX - fill in AUTH_OBJS from contents of the auth dir instead + $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:; + $makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo glob.lo isblank.lo memrchr.lo mksiglist.lo mktemp.lo nanosleep.lo pw_dup.lo siglist.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo utimes.lo globtest.o fnm_test.o:; + + # Parse OBJS lines + my %objs; + while ($makefile =~ /^[A-Z0-9_]*OBJS\s*=\s*(.*)/mg) { + foreach (split/\s+/, $1) { + next if /^\$[\(\{].*[\)\}]$/; # skip included vars for now + $objs{$_} = 1; + } + } + + # Find include paths + @incpaths = (); + while ($makefile =~ /-I(\S+)/mg) { + push(@incpaths, $1) unless $1 eq "."; + } + + # Check for generated files + if ($makefile =~ /GENERATED\s*=\s*(.+)$/m) { + foreach (split(/\s+/, $1)) { + $generated{$_} = 1; + } + } + + # Values of srcdir, top_srcdir, top_builddir, incdir + %dir_vars = (); + $file =~ m:^(.*)/+[^/]+:; + $dir_vars{'srcdir'} = $1 || '.'; + $dir_vars{'devdir'} = $dir_vars{'srcdir'}; + $dir_vars{'authdir'} = $dir_vars{'srcdir'} . "/auth"; + $dir_vars{'top_srcdir'} = '.'; + #$dir_vars{'top_builddir'} = '.'; + $dir_vars{'incdir'} = 'include'; + + # Find implicit rules for generate .o and .lo files + %implicit = (); + while ($makefile =~ /^\.c\.(l?o):\s*\n\t+(.*)$/mg) { + $implicit{$1} = $2; + } + + # Find existing .o and .lo dependencies + my %old_deps; + while ($makefile =~ /^(\w+\.l?o):\s*(\S+\.c)/mg) { + $old_deps{$1} = $2; + } + + # Sort files so we do .lo files first + foreach my $obj (sort keys %objs) { + next unless $obj =~ /(\S+)\.(l?o)$/; + if ($2 eq "o" && exists($objs{"$1.lo"})) { + # If we have both .lo and .o files, make the .o depend on the .lo + $new_makefile .= sprintf("%s: %s.lo\n", $obj, $1); + } else { + # Use old depenencies when mapping objects to their source. + # If no old depenency, use the MANIFEST file to find the source. + my $src = $1 . '.c'; + my $ext = $2; + if (exists $old_deps{$obj}) { + $src = $old_deps{$obj}; + } elsif (exists $manifest{$src}) { + $src = $manifest{$src}; + foreach (sort { length($b) <=> length($a) } keys %dir_vars) { + next if $_ eq "devdir"; + last if $src =~ s:^\Q$dir_vars{$_}/\E:\$\($_\)/:; + } + } else { + warn "$file: unable to find source for $obj\n"; + } + my $imp = $implicit{$ext}; + $imp =~ s/\$ 80) { + my $off = 0; + my $indent = length($obj) + 2; + while (length($deps) - $off > 80 - $indent) { + my $pos; + if ($off != 0) { + $new_makefile .= ' ' x $indent; + $pos = rindex($deps, ' ', $off + 80 - $indent - 2); + } else { + $pos = rindex($deps, ' ', $off + 78); + } + $new_makefile .= substr($deps, $off, $pos - $off) . " \\\n"; + $off = $pos + 1; + } + $new_makefile .= ' ' x $indent; + $new_makefile .= substr($deps, $off) . "\n"; + } else { + $new_makefile .= "$deps\n"; + } + $new_makefile .= "\t$imp\n"; + } + } + + my $newfile = $file . ".new"; + if (!open(MF, ">$newfile")) { + warn("cannot open $newfile: $!\n"); + } else { + print MF $new_makefile || warn("cannot write $newfile: $!\n"); + close(MF) || warn("cannot close $newfile: $!\n");; + rename($newfile, $file); + } +} + +exit(0); + +sub find_depends { + my $src = $_[0]; + my ($deps, $code, @headers); + + if ($src !~ /\//) { + # XXX - want build dir not src dir + $src = "$dir_vars{'srcdir'}/$src"; + } + + # resolve $(srcdir) etc. + foreach (keys %dir_vars) { + $src =~ s/\$[\(\{]$_[\)\}]/$dir_vars{$_}/g; + } + + # find open source file and find headers used by it + if (!open(FILE, "<$src")) { + warn "unable to open $src\n"; + return ""; + } + local $/; # enable "slurp" mode + $code = ; + close(FILE); + + # find all headers + while ($code =~ /^#\s*include\s+["<](\S+)[">]/mg) { + my ($hdr, $hdr_path) = find_header($1); + if (defined($hdr)) { + push(@headers, $hdr); + # Look for other includes in the .h file + push(@headers, find_depends($hdr_path)); + } + } + + @headers; +} + +# find the path to a header file +# returns path or undef if not found +sub find_header { + my $hdr = $_[0]; + + # Look for .h.in files in top_builddir and build dir + return ("\$(top_builddir\)/$hdr", "./${hdr}.in") if -r "./${hdr}.in"; + return ("./$hdr", "$dir_vars{'srcdir'}/${hdr}.in") if -r "$dir_vars{'srcdir'}/${hdr}.in"; + + if (exists $generated{$hdr}) { + my $hdr_path = $dir_vars{'devdir'} . '/' . $hdr; + return ('$(devdir)/' . $hdr, $hdr_path) if -r $hdr_path; + } + foreach my $inc (@incpaths) { + my $hdr_path = "$inc/$hdr"; + # resolve variables in include path + foreach (keys %dir_vars) { + next if $_ eq "devdir"; + $hdr_path =~ s/\$[\(\{]$_[\)\}]/$dir_vars{$_}/g; + } + return ("$inc/$hdr", $hdr_path) if -r $hdr_path; + } + + undef; +} diff --git a/mkpkg b/mkpkg index ae41356..3277123 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,66 +92,80 @@ 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 40 ]; then + # RHEL 4 and up support SELinux + configure_opts="${configure_opts}${configure_opts+$tab}--with-selinux" + fi if [ $osrelease -ge 50 ]; then - # RHEL 5 and up build pies and have audit support - export CFLAGS="$F_PIE" LDFLAGS="-pie" + # RHEL 5 and up build pies, have audit support and use a + # separate PAM config file for "sudo -i". + export CFLAGS="-O2 -g $F_PIE" LDFLAGS="-pie" configure_opts="${configure_opts}${configure_opts+$tab}--with-linux-audit" + configure_opts="${configure_opts}${configure_opts+$tab}--with-pam-login" + 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 - --prefix=$prefix + configure_opts="--prefix=$prefix --with-logging=syslog --with-logfac=authpriv --with-pam - --with-pam-login - --enable-zlib + --enable-zlib=system --with-editor=/bin/vi --with-env-editor --with-ignore-dot --with-tty-tickets --with-ldap - --with-selinux - --with-passprompt=[sudo] password for %p: " + --with-passprompt=[sudo] password for %p: + $configure_opts" ;; sles*) prefix=/usr if [ $osrelease -ge 10 ]; then # SLES 10 and higher build pies - export CFLAGS="$F_PIE" LDFLAGS="-pie" + export CFLAGS="-O2 -g $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 - *64*) libexec=lib64;; - *) libexec=lib;; + libexec=lib + case "$osversion" in + *64*) gcc -v 2>&1 | grep "with-cpu=[^ ]*32" >/dev/null || libexec=lib64 + ;; esac # Note, must indent with tabs, not spaces due to IFS trickery # XXX - SuSE uses secure path but only for env_reset - configure_opts="$configure_opts - --prefix=$prefix + configure_opts="--prefix=$prefix --libexecdir=$prefix/$libexec/sudo --with-logging=syslog --with-logfac=auth @@ -143,19 +175,28 @@ 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: " + --with-passprompt=%p\'s password: + $configure_opts" make_opts='docdir=$(datarootdir)/doc/packages/$(PACKAGE_TARNAME)' ;; 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" + if [ $osrelease -ge 1004 ]; then + export CFLAGS="-O2 -g $F_PIE" LDFLAGS="-pie" + fi + ;; + deb*) + if [ $osrelease -ge 600 ]; then + export CFLAGS="-O2 -g $F_PIE" LDFLAGS="-pie" + fi ;; esac # Note, must indent with tabs, not spaces due to IFS trickery @@ -163,12 +204,10 @@ case "$platform" in configure_opts="${configure_opts}${configure_opts+$tab}--with-ldap --with-ldap-conf-file=/etc/sudo-ldap.conf" fi - configure_opts="$configure_opts - --prefix=/usr + configure_opts="--prefix=/usr --with-all-insults - --with-exempt=sudo --with-pam - --enable-zlib + --enable-zlib=system --with-fqdn --with-logging=syslog --with-logfac=authpriv @@ -183,20 +222,57 @@ case "$platform" in --with-sendmail=/usr/sbin/sendmail --mandir=/usr/share/man --libexecdir=/usr/lib/sudo - --with-secure-path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin" + --with-secure-path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin + $configure_opts" + ;; + macos*) + case "$osversion" in + *i386|*x86_64) + # Build intel-only universal binaries + ARCH_FLAGS="-arch i386 -arch x86_64" + ;; + esac + if test "${osversion}" != "`$top_srcdir/pp --probe`"; then + sdkvers=`echo "${osversion}" | sed 's/^macos\([0-9][0-9]\)\([0-9]*\)-.*$/\1.\2/'` + SDK_FLAGS="-isysroot /Developer/SDKs/MacOSX${sdkvers}.sdk -mmacosx-version-min=${sdkvers}" + fi + export CFLAGS="-O2 -g $ARCH_FLAGS $SDK_FLAGS" + export LDFLAGS="$ARCH_FLAGS $SDK_FLAGS" + if [ $osrelease -ge 105 ]; then + CFLAGS="$CFLAGS $F_PIE" + LDFLAGS="$LDFLAGS -Wl,-pie" + fi + # Note, must indent with tabs, not spaces due to IFS trickery + configure_opts="--prefix=$prefix + --with-pam + --without-tty-tickets + --enable-zlib=system + --with-ldap + --with-insults=disabled + --with-logging=syslog + --with-logfac=authpriv + --with-editor=/usr/bin/vim + --with-env-editor + $configure_opts" ;; *) + # For Solaris, add project support and use let configure choose zlib. + # For all others, use the builtin zlib and disable NLS support. + case "$osversion" in + sol*) configure_opts="${configure_opts}${configure_opts+$tab}--with-project";; + *) configure_opts="${configure_opts}${configure_opts+$tab}--enable-zlib=builtin${tab}--disable-nls";; + esac if test "$flavor" = "ldap"; then configure_opts="${configure_opts}${configure_opts+$tab}--with-ldap" fi # Note, must indent with tabs, not spaces due to IFS trickery - configure_opts="$configure_opts - --prefix=$prefix + configure_opts="--prefix=$prefix --with-insults=disabled --with-logging=syslog --with-logfac=auth --with-editor=/usr/bin/vim:/usr/bin/vi:/bin/vi - --with-env-editor" + --with-env-editor + $configure_opts" ;; esac diff --git a/mksiglist.c b/mksiglist.c deleted file mode 100644 index 09b1414..0000000 --- a/mksiglist.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 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. - */ - - -#include - -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#include - -#include - -int -main(argc, argv) - int argc; - char *argv[]; -{ - static char *my_sys_siglist[NSIG]; - int i; - -#include "mksiglist.h" - - printf("#include \n"); - printf("#include \n"); - printf("#include \n\n"); - printf("const char *const my_sys_siglist[NSIG] = {\n"); - for (i = 0; i < NSIG; i++) { - if (my_sys_siglist[i] != NULL) { - printf(" \"%s\",\n", my_sys_siglist[i]); - } else { - printf(" \"Signal %d\",\n", i); - } - } - printf("};\n"); - - exit(0); -} diff --git a/mksiglist.h b/mksiglist.h deleted file mode 100644 index f9f3294..0000000 --- a/mksiglist.h +++ /dev/null @@ -1,174 +0,0 @@ -/* public domain */ - -#ifdef SIGHUP - if (my_sys_siglist[SIGHUP] == NULL) - my_sys_siglist[SIGHUP] = "Hangup"; -#endif -#ifdef SIGINT - if (my_sys_siglist[SIGINT] == NULL) - my_sys_siglist[SIGINT] = "Interrupt"; -#endif -#ifdef SIGQUIT - if (my_sys_siglist[SIGQUIT] == NULL) - my_sys_siglist[SIGQUIT] = "Quit"; -#endif -#ifdef SIGILL - if (my_sys_siglist[SIGILL] == NULL) - my_sys_siglist[SIGILL] = "Illegal instruction"; -#endif -#ifdef SIGTRAP - if (my_sys_siglist[SIGTRAP] == NULL) - my_sys_siglist[SIGTRAP] = "Trace trap"; -#endif -#ifdef SIGABRT - if (my_sys_siglist[SIGABRT] == NULL) - my_sys_siglist[SIGABRT] = "Abort"; -#endif -#ifdef SIGIOT - if (my_sys_siglist[SIGIOT] == NULL) - my_sys_siglist[SIGIOT] = "IOT instruction"; -#endif -#ifdef SIGEMT - if (my_sys_siglist[SIGEMT] == NULL) - my_sys_siglist[SIGEMT] = "EMT trap"; -#endif -#ifdef SIGFPE - if (my_sys_siglist[SIGFPE] == NULL) - my_sys_siglist[SIGFPE] = "Floating point exception"; -#endif -#ifdef SIGKILL - if (my_sys_siglist[SIGKILL] == NULL) - my_sys_siglist[SIGKILL] = "Killed"; -#endif -#ifdef SIGUNUSED - if (my_sys_siglist[SIGUNUSED] == NULL) - my_sys_siglist[SIGUNUSED] = "Unused"; -#endif -#ifdef SIGBUS - if (my_sys_siglist[SIGBUS] == NULL) - my_sys_siglist[SIGBUS] = "Bus error"; -#endif -#ifdef SIGSEGV - if (my_sys_siglist[SIGSEGV] == NULL) - my_sys_siglist[SIGSEGV] = "Memory fault"; -#endif -#ifdef SIGSYS - if (my_sys_siglist[SIGSYS] == NULL) - my_sys_siglist[SIGSYS] = "Bad system call"; -#endif -#ifdef SIGPIPE - if (my_sys_siglist[SIGPIPE] == NULL) - my_sys_siglist[SIGPIPE] = "Broken pipe"; -#endif -#ifdef SIGALRM - if (my_sys_siglist[SIGALRM] == NULL) - my_sys_siglist[SIGALRM] = "Alarm clock"; -#endif -#ifdef SIGTERM - if (my_sys_siglist[SIGTERM] == NULL) - my_sys_siglist[SIGTERM] = "Terminated"; -#endif -#ifdef SIGSTKFLT - if (my_sys_siglist[SIGSTKFLT] == NULL) - my_sys_siglist[SIGSTKFLT] = "Stack fault"; -#endif -#ifdef SIGIO - if (my_sys_siglist[SIGIO] == NULL) - my_sys_siglist[SIGIO] = "I/O possible"; -#endif -#ifdef SIGXCPU - if (my_sys_siglist[SIGXCPU] == NULL) - my_sys_siglist[SIGXCPU] = "CPU time limit exceeded"; -#endif -#ifdef SIGXFSZ - if (my_sys_siglist[SIGXFSZ] == NULL) - my_sys_siglist[SIGXFSZ] = "File size limit exceeded"; -#endif -#ifdef SIGVTALRM - if (my_sys_siglist[SIGVTALRM] == NULL) - my_sys_siglist[SIGVTALRM] = "Virtual timer expired"; -#endif -#ifdef SIGPROF - if (my_sys_siglist[SIGPROF] == NULL) - my_sys_siglist[SIGPROF] = "Profiling timer expired"; -#endif -#ifdef SIGWINCH - if (my_sys_siglist[SIGWINCH] == NULL) - my_sys_siglist[SIGWINCH] = "Window size change"; -#endif -#ifdef SIGLOST - if (my_sys_siglist[SIGLOST] == NULL) - my_sys_siglist[SIGLOST] = "File lock lost"; -#endif -#ifdef SIGUSR1 - if (my_sys_siglist[SIGUSR1] == NULL) - my_sys_siglist[SIGUSR1] = "User defined signal 1"; -#endif -#ifdef SIGUSR2 - if (my_sys_siglist[SIGUSR2] == NULL) - my_sys_siglist[SIGUSR2] = "User defined signal 2"; -#endif -#ifdef SIGPWR - if (my_sys_siglist[SIGPWR] == NULL) - my_sys_siglist[SIGPWR] = "Power-fail/Restart"; -#endif -#ifdef SIGPOLL - if (my_sys_siglist[SIGPOLL] == NULL) - my_sys_siglist[SIGPOLL] = "Pollable event occurred"; -#endif -#ifdef SIGSTOP - if (my_sys_siglist[SIGSTOP] == NULL) - my_sys_siglist[SIGSTOP] = "Stopped (signal)"; -#endif -#ifdef SIGTSTP - if (my_sys_siglist[SIGTSTP] == NULL) - my_sys_siglist[SIGTSTP] = "Stopped"; -#endif -#ifdef SIGCONT - if (my_sys_siglist[SIGCONT] == NULL) - my_sys_siglist[SIGCONT] = "Continued"; -#endif -#ifdef SIGCHLD - if (my_sys_siglist[SIGCHLD] == NULL) - my_sys_siglist[SIGCHLD] = "Child exited"; -#endif -#ifdef SIGCLD - if (my_sys_siglist[SIGCLD] == NULL) - my_sys_siglist[SIGCLD] = "Child exited"; -#endif -#ifdef SIGTTIN - if (my_sys_siglist[SIGTTIN] == NULL) - my_sys_siglist[SIGTTIN] = "Stopped (tty input)"; -#endif -#ifdef SIGTTOU - if (my_sys_siglist[SIGTTOU] == NULL) - my_sys_siglist[SIGTTOU] = "Stopped (tty output)"; -#endif -#ifdef SIGINFO - if (my_sys_siglist[SIGINFO] == NULL) - my_sys_siglist[SIGINFO] = "Information request"; -#endif -#ifdef SIGURG - if (my_sys_siglist[SIGURG] == NULL) - my_sys_siglist[SIGURG] = "Urgent I/O condition"; -#endif -#ifdef SIGWAITING - if (my_sys_siglist[SIGWAITING] == NULL) - my_sys_siglist[SIGWAITING] = "No runnable LWPs"; -#endif -#ifdef SIGLWP - if (my_sys_siglist[SIGLWP] == NULL) - my_sys_siglist[SIGLWP] = "Inter-LWP signal"; -#endif -#ifdef SIGFREEZE - if (my_sys_siglist[SIGFREEZE] == NULL) - my_sys_siglist[SIGFREEZE] = "Checkpoint freeze"; -#endif -#ifdef SIGTHAW - if (my_sys_siglist[SIGTHAW] == NULL) - my_sys_siglist[SIGTHAW] = "Checkpoint thaw"; -#endif -#ifdef SIGCANCEL - if (my_sys_siglist[SIGCANCEL] == NULL) - my_sys_siglist[SIGCANCEL] = "Thread cancellation"; -#endif diff --git a/mkstemps.c b/mkstemps.c deleted file mode 100644 index 7245f19..0000000 --- a/mkstemps.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2001, 2003, 2004, 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. - */ - -#include "config.h" - -#include -#include -#include - -#include -#include -#include -#include -#ifdef HAVE_STDLIB_H -# include -#endif /* HAVE_STDLIB_H */ -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if TIME_WITH_SYS_TIME -# include -#endif - -#include "sudo.h" - -static unsigned int get_random __P((void)); -static void seed_random __P((void)); - -#define TEMPCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" -#define NUM_CHARS (sizeof(TEMPCHARS) - 1) - -#ifndef INT_MAX -#define INT_MAX 0x7fffffff -#endif - -int -mkstemps(path, slen) - char *path; - int slen; -{ - char *start, *cp, *ep; - const char *tempchars = TEMPCHARS; - unsigned int r, tries; - int fd; - - for (ep = path; *ep; ep++) - ; - if (path + slen >= ep) { - errno = EINVAL; - return(-1); - } - ep -= slen; - - tries = 1; - for (start = ep; start > path && start[-1] == 'X'; start--) { - if (tries < INT_MAX / NUM_CHARS) - tries *= NUM_CHARS; - } - tries *= 2; - - do { - for (cp = start; *cp; cp++) { - r = get_random() % NUM_CHARS; - *cp = tempchars[r]; - } - - fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); - if (fd != -1 || errno != EEXIST) - return(fd); - } while (--tries); - - errno = EEXIST; - return(-1); -} - -#ifdef HAVE_RANDOM -# define RAND random -# define SRAND srandom -# define SEED_T unsigned int -#else -# ifdef HAVE_LRAND48 -# define RAND lrand48 -# define SRAND srand48 -# define SEED_T long -# else -# define RAND rand -# define SRAND srand -# define SEED_T unsigned int -# endif -#endif - -static void -seed_random() -{ - SEED_T seed; - struct timeval tv; - - /* - * Seed from time of day and process id multiplied by small primes. - */ - (void) gettime(&tv); - seed = (tv.tv_sec % 10000) * 523 + tv.tv_usec * 13 + - (getpid() % 1000) * 983; - SRAND(seed); -} - -static unsigned int -get_random() -{ - static int initialized; - - if (!initialized) { - seed_random(); - initialized = 1; - } - - return(RAND() & 0xffffffff); -} diff --git a/nanosleep.c b/nanosleep.c deleted file mode 100644 index ae2208b..0000000 --- a/nanosleep.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#ifdef HAVE_SYS_SELECT_H -#include -#endif /* HAVE_SYS_SELECT_H */ -#if TIME_WITH_SYS_TIME -# include -#endif -#ifndef HAVE_TIMESPEC -# include -#endif -#include - -#include "compat.h" - -int -nanosleep(ts, rts) - const struct timespec *ts; - struct timespec *rts; -{ - struct timeval timeout, endtime, now; - int rval; - - timeout.tv_sec = ts->tv_sec; - timeout.tv_usec = ts->tv_nsec / 1000; - if (rts != NULL) { - gettimeofday(&endtime, NULL); - timevaladd(&endtime, &timeout); - } - rval = select(0, NULL, NULL, NULL, &timeout); - if (rts != NULL && rval == -1 && errno == EINTR) { - gettimeofday(&now, NULL); - timevalsub(&endtime, &now); - rts->tv_sec = endtime.tv_sec; - rts->tv_nsec = endtime.tv_usec * 1000; - } - return(rval); -} diff --git a/nonunix.h b/nonunix.h deleted file mode 100644 index 09de9d2..0000000 --- a/nonunix.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * (c) 2006 Quest Software, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of Quest Software, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _NONUNIX_H -#define _NONUNIX_H - -void -sudo_nonunix_groupcheck_init(void); - -void -sudo_nonunix_groupcheck_cleanup(void); - -int -sudo_nonunix_groupcheck( const char* group, const char* user, const struct passwd* pwd ); - -int -sudo_nonunix_groupcheck_available(void); - -#endif /* _NONUNIX_H */ diff --git a/parse.c b/parse.c deleted file mode 100644 index 97aba79..0000000 --- a/parse.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007-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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#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 */ -#include -#include -#include - -#include "sudo.h" -#include "parse.h" -#include "lbuf.h" -#include - -/* Characters that must be quoted in sudoers */ -#define SUDOERS_QUOTED ":\\,=#\"" - -/* sudoers nsswitch routines */ -struct sudo_nss sudo_nss_file = { - &sudo_nss_file, - NULL, - sudo_file_open, - sudo_file_close, - sudo_file_parse, - sudo_file_setdefs, - sudo_file_lookup, - sudo_file_display_cmnd, - sudo_file_display_defaults, - sudo_file_display_bound_defaults, - sudo_file_display_privs -}; - -/* - * Parser externs. - */ -extern FILE *yyin; -extern char *errorfile; -extern int errorlineno, parse_error; - -/* - * Local prototypes. - */ -static void print_member __P((struct lbuf *, char *, int, int, int)); -static int display_bound_defaults __P((int, struct lbuf *)); - -int -sudo_file_open(nss) - struct sudo_nss *nss; -{ - if (def_ignore_local_sudoers) - return(-1); - nss->handle = open_sudoers(_PATH_SUDOERS, FALSE, NULL); - return(nss->handle ? 0 : -1); -} - -int -sudo_file_close(nss) - struct sudo_nss *nss; -{ - /* Free parser data structures and close sudoers file. */ - init_parser(NULL, 0); - if (nss->handle != NULL) { - fclose(nss->handle); - nss->handle = NULL; - yyin = NULL; - } - return(0); -} - -/* - * Parse the specified sudoers file. - */ -int -sudo_file_parse(nss) - struct sudo_nss *nss; -{ - if (nss->handle == NULL) - return(-1); - - init_parser(_PATH_SUDOERS, 0); - yyin = nss->handle; - if (yyparse() != 0 || parse_error) { - log_error(NO_EXIT, "parse error in %s near line %d", - errorfile, errorlineno); - return(-1); - } - return(0); -} - -/* - * Wrapper around update_defaults() for nsswitch code. - */ -int -sudo_file_setdefs(nss) - struct sudo_nss *nss; -{ - if (nss->handle == NULL) - return(-1); - - if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER)) - return(-1); - return(0); -} - -/* - * Look up the user in the parsed sudoers file and check to see if they are - * allowed to run the specified command on this host as the target user. - */ -int -sudo_file_lookup(nss, validated, pwflag) - struct sudo_nss *nss; - int validated; - int pwflag; -{ - int match, host_match, runas_match, cmnd_match; - struct cmndspec *cs; - struct cmndtag *tags = NULL; - struct privilege *priv; - struct userspec *us; - - if (nss->handle == NULL) - return(validated); - - /* - * Only check the actual command if pwflag is not set. - * It is set for the "validate", "list" and "kill" pseudo-commands. - * Always check the host and user. - */ - if (pwflag) { - int nopass; - enum def_tupple pwcheck; - - pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; - nopass = (pwcheck == all) ? TRUE : FALSE; - - if (list_pw == NULL) - SET(validated, FLAG_NO_CHECK); - CLR(validated, FLAG_NO_USER); - CLR(validated, FLAG_NO_HOST); - match = DENY; - tq_foreach_fwd(&userspecs, us) { - if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) - continue; - tq_foreach_fwd(&us->privileges, priv) { - if (hostlist_matches(&priv->hostlist) != ALLOW) - continue; - tq_foreach_fwd(&priv->cmndlist, cs) { - /* Only check the command when listing another user. */ - if (user_uid == 0 || list_pw == NULL || - user_uid == list_pw->pw_uid || - cmnd_matches(cs->cmnd) == ALLOW) - match = ALLOW; - if ((pwcheck == any && cs->tags.nopasswd == TRUE) || - (pwcheck == all && cs->tags.nopasswd != TRUE)) - nopass = cs->tags.nopasswd; - } - } - } - if (match == ALLOW || user_uid == 0) { - /* User has an entry for this host. */ - SET(validated, VALIDATE_OK); - } else if (match == DENY) - SET(validated, VALIDATE_NOT_OK); - if (pwcheck == always && def_authenticate) - SET(validated, FLAG_CHECK_USER); - else if (pwcheck == never || nopass == TRUE) - def_authenticate = FALSE; - return(validated); - } - - /* Need to be runas user while stat'ing things. */ - set_perms(PERM_RUNAS); - - match = UNSPEC; - tq_foreach_rev(&userspecs, us) { - if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) - continue; - CLR(validated, FLAG_NO_USER); - tq_foreach_rev(&us->privileges, priv) { - host_match = hostlist_matches(&priv->hostlist); - if (host_match == ALLOW) - CLR(validated, FLAG_NO_HOST); - else - continue; - tq_foreach_rev(&priv->cmndlist, cs) { - runas_match = runaslist_matches(&cs->runasuserlist, - &cs->runasgrouplist); - if (runas_match == ALLOW) { - cmnd_match = cmnd_matches(cs->cmnd); - if (cmnd_match != UNSPEC) { - match = cmnd_match; - tags = &cs->tags; -#ifdef HAVE_SELINUX - /* Set role and type if not specified on command line. */ - if (user_role == NULL) - user_role = cs->role ? estrdup(cs->role) : def_role; - if (user_type == NULL) - user_type = cs->type ? estrdup(cs->type) : def_type; -#endif /* HAVE_SELINUX */ - goto matched2; - } - } - } - } - } - matched2: - if (match == ALLOW) { - SET(validated, VALIDATE_OK); - CLR(validated, VALIDATE_NOT_OK); - if (tags != NULL) { - if (tags->nopasswd != UNSPEC) - def_authenticate = !tags->nopasswd; - if (tags->noexec != UNSPEC) - def_noexec = tags->noexec; - if (tags->setenv != UNSPEC) - def_setenv = tags->setenv; - if (tags->log_input != UNSPEC) - def_log_input = tags->log_input; - if (tags->log_output != UNSPEC) - def_log_output = tags->log_output; - } - } else if (match == DENY) { - SET(validated, VALIDATE_NOT_OK); - CLR(validated, VALIDATE_OK); - } - set_perms(PERM_ROOT); - return(validated); -} - -#define TAG_CHANGED(t) \ - (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t) - -static void -sudo_file_append_cmnd(cs, tags, lbuf) - struct cmndspec *cs; - struct cmndtag *tags; - struct lbuf *lbuf; -{ - struct member *m; - -#ifdef HAVE_SELINUX - if (cs->role) - lbuf_append(lbuf, "ROLE=", cs->role, " ", NULL); - if (cs->type) - lbuf_append(lbuf, "TYPE=", cs->type, " ", NULL); -#endif /* HAVE_SELINUX */ - if (TAG_CHANGED(setenv)) { - lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : - "NOSETENV: ", NULL); - tags->setenv = cs->tags.setenv; - } - if (TAG_CHANGED(noexec)) { - lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : - "EXEC: ", NULL); - tags->noexec = cs->tags.noexec; - } - if (TAG_CHANGED(nopasswd)) { - lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : - "PASSWD: ", NULL); - tags->nopasswd = cs->tags.nopasswd; - } - if (TAG_CHANGED(log_input)) { - lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " : - "NOLOG_INPUT: ", NULL); - tags->log_input = cs->tags.log_input; - } - if (TAG_CHANGED(log_output)) { - lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : - "NOLOG_OUTPUT: ", NULL); - tags->log_output = cs->tags.log_output; - } - m = cs->cmnd; - print_member(lbuf, m->name, m->type, m->negated, - CMNDALIAS); -} - -static int -sudo_file_display_priv_short(pw, us, lbuf) - struct passwd *pw; - struct userspec *us; - struct lbuf *lbuf; -{ - struct cmndspec *cs; - struct member *m; - struct privilege *priv; - struct cmndtag tags; - int nfound = 0; - - tq_foreach_fwd(&us->privileges, priv) { - if (hostlist_matches(&priv->hostlist) != ALLOW) - continue; - tags.noexec = UNSPEC; - tags.setenv = UNSPEC; - tags.nopasswd = UNSPEC; - tags.log_input = UNSPEC; - tags.log_output = UNSPEC; - lbuf_append(lbuf, " ", NULL); - tq_foreach_fwd(&priv->cmndlist, cs) { - if (cs != tq_first(&priv->cmndlist)) - lbuf_append(lbuf, ", ", NULL); - lbuf_append(lbuf, "(", NULL); - if (!tq_empty(&cs->runasuserlist)) { - tq_foreach_fwd(&cs->runasuserlist, m) { - if (m != tq_first(&cs->runasuserlist)) - lbuf_append(lbuf, ", ", NULL); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); - } - } else if (tq_empty(&cs->runasgrouplist)) { - lbuf_append(lbuf, def_runas_default, NULL); - } else { - lbuf_append(lbuf, pw->pw_name, NULL); - } - if (!tq_empty(&cs->runasgrouplist)) { - lbuf_append(lbuf, " : ", NULL); - tq_foreach_fwd(&cs->runasgrouplist, m) { - if (m != tq_first(&cs->runasgrouplist)) - lbuf_append(lbuf, ", ", NULL); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); - } - } - lbuf_append(lbuf, ") ", NULL); - sudo_file_append_cmnd(cs, &tags, lbuf); - nfound++; - } - lbuf_append(lbuf, "\n", NULL); - } - return(nfound); -} - -static int -sudo_file_display_priv_long(pw, us, lbuf) - struct passwd *pw; - struct userspec *us; - struct lbuf *lbuf; -{ - struct cmndspec *cs; - struct member *m; - struct privilege *priv; - struct cmndtag tags; - int nfound = 0; - - tq_foreach_fwd(&us->privileges, priv) { - if (hostlist_matches(&priv->hostlist) != ALLOW) - continue; - tags.noexec = UNSPEC; - tags.setenv = UNSPEC; - tags.nopasswd = UNSPEC; - tags.log_input = UNSPEC; - tags.log_output = UNSPEC; - lbuf_append(lbuf, "\nSudoers entry:\n", NULL); - tq_foreach_fwd(&priv->cmndlist, cs) { - lbuf_append(lbuf, " RunAsUsers: ", NULL); - if (!tq_empty(&cs->runasuserlist)) { - tq_foreach_fwd(&cs->runasuserlist, m) { - if (m != tq_first(&cs->runasuserlist)) - lbuf_append(lbuf, ", ", NULL); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); - } - } else if (tq_empty(&cs->runasgrouplist)) { - lbuf_append(lbuf, def_runas_default, NULL); - } else { - lbuf_append(lbuf, pw->pw_name, NULL); - } - lbuf_append(lbuf, "\n", NULL); - if (!tq_empty(&cs->runasgrouplist)) { - lbuf_append(lbuf, " RunAsGroups: ", NULL); - tq_foreach_fwd(&cs->runasgrouplist, m) { - if (m != tq_first(&cs->runasgrouplist)) - lbuf_append(lbuf, ", ", NULL); - print_member(lbuf, m->name, m->type, m->negated, - RUNASALIAS); - } - lbuf_append(lbuf, "\n", NULL); - } - lbuf_append(lbuf, " Commands:\n\t", NULL); - sudo_file_append_cmnd(cs, &tags, lbuf); - lbuf_append(lbuf, "\n", NULL); - nfound++; - } - } - return(nfound); -} - -int -sudo_file_display_privs(nss, pw, lbuf) - struct sudo_nss *nss; - struct passwd *pw; - struct lbuf *lbuf; -{ - struct userspec *us; - int nfound = 0; - - if (nss->handle == NULL) - goto done; - - tq_foreach_fwd(&userspecs, us) { - if (userlist_matches(pw, &us->users) != ALLOW) - continue; - - if (long_list) - nfound += sudo_file_display_priv_long(pw, us, lbuf); - else - nfound += sudo_file_display_priv_short(pw, us, lbuf); - } -done: - return(nfound); -} - -/* - * Display matching Defaults entries for the given user on this host. - */ -int -sudo_file_display_defaults(nss, pw, lbuf) - struct sudo_nss *nss; - struct passwd *pw; - struct lbuf *lbuf; -{ - struct defaults *d; - char *prefix; - int nfound = 0; - - if (nss->handle == NULL) - goto done; - - if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) - prefix = " "; - else - prefix = ", "; - - tq_foreach_fwd(&defaults, d) { - switch (d->type) { - case DEFAULTS_HOST: - if (hostlist_matches(&d->binding) != ALLOW) - continue; - break; - case DEFAULTS_USER: - if (userlist_matches(pw, &d->binding) != ALLOW) - continue; - break; - case DEFAULTS_RUNAS: - case DEFAULTS_CMND: - continue; - } - lbuf_append(lbuf, prefix, NULL); - if (d->val != NULL) { - lbuf_append(lbuf, d->var, d->op == '+' ? "+=" : - d->op == '-' ? "-=" : "=", NULL); - if (strpbrk(d->val, " \t") != NULL) { - lbuf_append(lbuf, "\"", NULL); - lbuf_append_quoted(lbuf, "\"", d->val, NULL); - lbuf_append(lbuf, "\"", NULL); - } else - lbuf_append_quoted(lbuf, SUDOERS_QUOTED, d->val, NULL); - } else - lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL); - prefix = ", "; - nfound++; - } -done: - return(nfound); -} - -/* - * Display Defaults entries that are per-runas or per-command - */ -int -sudo_file_display_bound_defaults(nss, pw, lbuf) - struct sudo_nss *nss; - struct passwd *pw; - struct lbuf *lbuf; -{ - int nfound = 0; - - /* XXX - should only print ones that match what the user can do. */ - nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf); - nfound += display_bound_defaults(DEFAULTS_CMND, lbuf); - - return(nfound); -} - -/* - * Display Defaults entries of the given type. - */ -static int -display_bound_defaults(dtype, lbuf) - int dtype; - struct lbuf *lbuf; -{ - struct defaults *d; - struct member *m, *binding = NULL; - char *dname, *dsep; - int atype, nfound = 0; - - switch (dtype) { - case DEFAULTS_HOST: - atype = HOSTALIAS; - dname = "host"; - dsep = "@"; - break; - case DEFAULTS_USER: - atype = USERALIAS; - dname = "user"; - dsep = ":"; - break; - case DEFAULTS_RUNAS: - atype = RUNASALIAS; - dname = "runas"; - dsep = ">"; - break; - case DEFAULTS_CMND: - atype = CMNDALIAS; - dname = "cmnd"; - dsep = "!"; - break; - default: - return(-1); - } - /* printf("Per-%s Defaults entries:\n", dname); */ - tq_foreach_fwd(&defaults, d) { - if (d->type != dtype) - continue; - - nfound++; - if (binding != tq_first(&d->binding)) { - binding = tq_first(&d->binding); - if (nfound != 1) - lbuf_append(lbuf, "\n", NULL); - lbuf_append(lbuf, " Defaults", dsep, NULL); - for (m = binding; m != NULL; m = m->next) { - if (m != binding) - lbuf_append(lbuf, ",", NULL); - print_member(lbuf, m->name, m->type, m->negated, atype); - lbuf_append(lbuf, " ", NULL); - } - } else - lbuf_append(lbuf, ", ", NULL); - if (d->val != NULL) { - lbuf_append(lbuf, d->var, d->op == '+' ? "+=" : - d->op == '-' ? "-=" : "=", d->val, NULL); - } else - lbuf_append(lbuf, d->op == FALSE ? "!" : "", d->var, NULL); - } - - return(nfound); -} - -int -sudo_file_display_cmnd(nss, pw) - struct sudo_nss *nss; - struct passwd *pw; -{ - struct cmndspec *cs; - struct member *match; - struct privilege *priv; - struct userspec *us; - int rval = 1; - int host_match, runas_match, cmnd_match; - - if (nss->handle == NULL) - goto done; - - match = NULL; - tq_foreach_rev(&userspecs, us) { - if (userlist_matches(pw, &us->users) != ALLOW) - continue; - - tq_foreach_rev(&us->privileges, priv) { - host_match = hostlist_matches(&priv->hostlist); - if (host_match != ALLOW) - continue; - tq_foreach_rev(&priv->cmndlist, cs) { - runas_match = runaslist_matches(&cs->runasuserlist, - &cs->runasgrouplist); - if (runas_match == ALLOW) { - cmnd_match = cmnd_matches(cs->cmnd); - if (cmnd_match != UNSPEC) { - match = host_match && runas_match ? - cs->cmnd : NULL; - goto matched; - } - } - } - } - } - matched: - if (match != NULL && !match->negated) { - printf("%s%s%s\n", safe_cmnd, user_args ? " " : "", - user_args ? user_args : ""); - rval = 0; - } -done: - return(rval); -} - -/* - * Print the contents of a struct member to stdout - */ -static void -_print_member(lbuf, name, type, negated, alias_type) - struct lbuf *lbuf; - char *name; - int type, negated, alias_type; -{ - struct alias *a; - struct member *m; - struct sudo_command *c; - - switch (type) { - case ALL: - lbuf_append(lbuf, negated ? "!ALL" : "ALL", NULL); - break; - case COMMAND: - c = (struct sudo_command *) name; - if (negated) - lbuf_append(lbuf, "!", NULL); - lbuf_append_quoted(lbuf, SUDOERS_QUOTED, c->cmnd, NULL); - if (c->args) { - lbuf_append(lbuf, " ", NULL); - lbuf_append_quoted(lbuf, SUDOERS_QUOTED, c->args, NULL); - } - break; - case ALIAS: - if ((a = alias_find(name, alias_type)) != NULL) { - tq_foreach_fwd(&a->members, m) { - if (m != tq_first(&a->members)) - lbuf_append(lbuf, ", ", NULL); - _print_member(lbuf, m->name, m->type, - negated ? !m->negated : m->negated, alias_type); - } - break; - } - /* FALLTHROUGH */ - default: - lbuf_append(lbuf, negated ? "!" : "", name, NULL); - break; - } -} - -static void -print_member(lbuf, name, type, negated, alias_type) - struct lbuf *lbuf; - char *name; - int type, negated, alias_type; -{ - alias_seqno++; - _print_member(lbuf, name, type, negated, alias_type); -} diff --git a/parse.h b/parse.h deleted file mode 100644 index 90595bf..0000000 --- a/parse.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2000, 2004, 2007-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. - */ - -#ifndef _SUDO_PARSE_H -#define _SUDO_PARSE_H - -#undef UNSPEC -#define UNSPEC -1 -#undef DENY -#define DENY 0 -#undef ALLOW -#define ALLOW 1 -#undef IMPLIED -#define IMPLIED 2 - -/* - * A command with args. XXX - merge into struct member. - */ -struct sudo_command { - char *cmnd; - char *args; -}; - -/* - * Tags associated with a command. - * Possible valus: TRUE, FALSE, UNSPEC. - */ -struct cmndtag { - __signed int nopasswd: 3; - __signed int noexec: 3; - __signed int setenv: 3; - __signed int log_input: 3; - __signed int log_output: 3; -}; - -/* - * SELinux-specific container struct. - * Currently just contains a role and type. - */ -struct selinux_info { - char *role; - char *type; -}; - -/* - * The parses sudoers file is stored as a collection of linked lists, - * modelled after the yacc grammar. - * - * Other than the alias struct, which is stored in a red-black tree, - * the data structure used is basically a doubly-linked tail queue without - * a separate head struct--the first entry acts as the head where the prev - * pointer does double duty as the tail pointer. This makes it possible - * to trivally append sub-lists. In addition, the prev pointer is always - * valid (even if it points to itself). Unlike a circle queue, the next - * pointer of the last entry is NULL and does not point back to the head. - * - * Note that each list struct must contain a "prev" and "next" pointer as - * the first two members of the struct (in that order). - */ - -/* - * Tail queue list head structure. - */ -TQ_DECLARE(defaults) -TQ_DECLARE(userspec) -TQ_DECLARE(member) -TQ_DECLARE(privilege) -TQ_DECLARE(cmndspec) - -/* - * Structure describing a user specification and list thereof. - */ -struct userspec { - struct userspec *prev, *next; - struct member_list users; /* list of users */ - struct privilege_list privileges; /* list of privileges */ -}; - -/* - * Structure describing a privilege specification. - */ -struct privilege { - struct privilege *prev, *next; - struct member_list hostlist; /* list of hosts */ - struct cmndspec_list cmndlist; /* list of Cmnd_Specs */ -}; - -/* - * Structure describing a linked list of Cmnd_Specs. - */ -struct cmndspec { - struct cmndspec *prev, *next; - struct member_list runasuserlist; /* list of runas users */ - struct member_list runasgrouplist; /* list of runas groups */ - struct member *cmnd; /* command to allow/deny */ - struct cmndtag tags; /* tag specificaion */ -#ifdef HAVE_SELINUX - char *role, *type; /* SELinux role and type */ -#endif -}; - -/* - * Generic structure to hold users, hosts, commands. - */ -struct member { - struct member *prev, *next; - char *name; /* member name */ - short type; /* type (see gram.h) */ - short negated; /* negated via '!'? */ -}; - -struct runascontainer { - struct member *runasusers; - struct member *runasgroups; -}; - -/* - * Generic structure to hold {User,Host,Runas,Cmnd}_Alias - * Aliases are stored in a red-black tree, sorted by name and type. - */ -struct alias { - char *name; /* alias name */ - unsigned short type; /* {USER,HOST,RUNAS,CMND}ALIAS */ - unsigned short seqno; /* sequence number */ - struct member_list members; /* list of alias members */ -}; - -/* - * Structure describing a Defaults entry and a list thereof. - */ -struct defaults { - struct defaults *prev, *next; - char *var; /* variable name */ - char *val; /* variable value */ - struct member_list binding; /* user/host/runas binding */ - int type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */ - int op; /* TRUE, FALSE, '+', '-' */ -}; - -/* - * Parsed sudoers info. - */ -extern struct userspec_list userspecs; -extern struct defaults_list defaults; - -/* - * Alias sequence number to avoid loops. - */ -extern unsigned int alias_seqno; - -/* - * Prototypes - */ -char *alias_add __P((char *, int, struct member *)); -int addr_matches __P((char *)); -int cmnd_matches __P((struct member *)); -int cmndlist_matches __P((struct member_list *)); -int command_matches __P((char *, char *)); -int hostlist_matches __P((struct member_list *)); -int hostname_matches __P((char *, char *, char *)); -int netgr_matches __P((char *, char *, char *, char *)); -int no_aliases __P((void)); -int runaslist_matches __P((struct member_list *, struct member_list *)); -int userlist_matches __P((struct passwd *, struct member_list *)); -int usergr_matches __P((char *, char *, struct passwd *)); -int userpw_matches __P((char *, char *, struct passwd *)); -int group_matches __P((char *, struct group *)); -struct alias *alias_find __P((char *, int)); -struct alias *alias_remove __P((char *, int)); -void alias_free __P((void *)); -void alias_apply __P((int (*)(void *, void *), void *)); -void init_aliases __P((void)); -void init_lexer __P((void)); -void init_parser __P((char *, int)); -int alias_compare __P((const void *, const void *)); - -#endif /* _SUDO_PARSE_H */ diff --git a/parse_args.c b/parse_args.c deleted file mode 100644 index 3611b44..0000000 --- a/parse_args.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 1993-1996, 1998-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. - */ - -#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 */ -#include -#include - -#include "sudo.h" -#include "lbuf.h" -#include - -/* - * Local functions - */ -static void usage_excl __P((int)) - __attribute__((__noreturn__)); - -/* - * For sudo.c - */ -extern int NewArgc; -extern char **NewArgv; -extern int user_closefrom; -extern char *runas_user; -extern char *runas_group; - -/* For getopt(3) */ -extern char *optarg; -extern int optind; - -#ifdef HAVE_BSD_AUTH_H -char *login_style; -#endif /* HAVE_BSD_AUTH_H */ - -/* - * Command line argument parsing. - * Sets NewArgc and NewArgv which corresponds to the argc/argv we'll use - * for the command to be run (if we are running one). - */ -int -parse_args(argc, argv) - int argc; - char **argv; -{ - int mode = 0; /* what mode is sudo to be run in? */ - int flags = 0; /* mode flags */ - int valid_flags, ch; - - /* First, check to see if we were invoked as "sudoedit". */ - if (strcmp(getprogname(), "sudoedit") == 0) - mode = MODE_EDIT; - - /* Returns true if the last option string was "--" */ -#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \ - argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0') - - /* Returns true if next option is an environment variable */ -#define is_envar (optind < argc && argv[optind][0] != '/' && \ - strchr(argv[optind], '=') != NULL) - - /* Flags allowed when running a command */ - valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME| - MODE_LOGIN_SHELL|MODE_INVALIDATE|MODE_NONINTERACTIVE| - MODE_PRESERVE_GROUPS|MODE_SHELL; - for (;;) { - /* - * We disable arg permutation for GNU getopt(). - * Some trickiness is required to allow environment variables - * to be interspersed with command line options. - */ - if ((ch = getopt(argc, argv, "+Aa:bC:c:Eeg:HhiKkLlnPp:r:Sst:U:u:Vv")) != -1) { - switch (ch) { - case 'A': - SET(tgetpass_flags, TGP_ASKPASS); - break; -#ifdef HAVE_BSD_AUTH_H - case 'a': - login_style = optarg; - break; -#endif - case 'b': - SET(flags, MODE_BACKGROUND); - break; - case 'C': - if ((user_closefrom = atoi(optarg)) < 3) { - warningx("the argument to -C must be at least 3"); - usage(1); - } - break; -#ifdef HAVE_LOGIN_CAP_H - case 'c': - login_class = optarg; - def_use_loginclass = TRUE; - break; -#endif - case 'E': - SET(flags, MODE_PRESERVE_ENV); - break; - case 'e': - if (mode && mode != MODE_EDIT) - usage_excl(1); - mode = MODE_EDIT; - valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; - break; - case 'g': - runas_group = optarg; - break; - case 'H': - SET(flags, MODE_RESET_HOME); - break; - case 'h': - if (mode && mode != MODE_HELP) { - if (strcmp(getprogname(), "sudoedit") != 0) - usage_excl(1); - } - mode = MODE_HELP; - valid_flags = 0; - break; - case 'i': - SET(flags, MODE_LOGIN_SHELL); - def_env_reset = TRUE; - break; - case 'k': - SET(flags, MODE_INVALIDATE); - break; - case 'K': - if (mode && mode != MODE_KILL) - usage_excl(1); - mode = MODE_KILL; - valid_flags = 0; - break; - case 'L': - if (mode && mode != MODE_LISTDEFS) - usage_excl(1); - mode = MODE_LISTDEFS; - valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; - break; - case 'l': - if (mode) { - if (mode == MODE_LIST) - long_list = 1; - else - usage_excl(1); - } - mode = MODE_LIST; - valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; - break; - case 'n': - SET(flags, MODE_NONINTERACTIVE); - break; - case 'P': - SET(flags, MODE_PRESERVE_GROUPS); - break; - case 'p': - user_prompt = optarg; - def_passprompt_override = TRUE; - break; -#ifdef HAVE_SELINUX - case 'r': - user_role = optarg; - break; - case 't': - user_type = optarg; - break; -#endif - case 'S': - SET(tgetpass_flags, TGP_STDIN); - break; - case 's': - SET(flags, MODE_SHELL); - break; - case 'U': - if ((list_pw = sudo_getpwnam(optarg)) == NULL) - errorx(1, "unknown user: %s", optarg); - break; - case 'u': - runas_user = optarg; - break; - case 'v': - if (mode && mode != MODE_VALIDATE) - usage_excl(1); - mode = MODE_VALIDATE; - valid_flags = MODE_INVALIDATE|MODE_NONINTERACTIVE; - break; - case 'V': - if (mode && mode != MODE_VERSION) - usage_excl(1); - mode = MODE_VERSION; - valid_flags = 0; - break; - default: - usage(1); - } - } else if (!got_end_of_args && is_envar) { - struct list_member *ev; - - /* Store environment variable. */ - ev = emalloc(sizeof(*ev)); - ev->value = argv[optind]; - ev->next = sudo_user.env_vars; - sudo_user.env_vars = ev; - - /* Crank optind and resume getopt. */ - optind++; - } else { - /* Not an option or an environment variable -- we're done. */ - break; - } - } - - NewArgc = argc - optind; - NewArgv = argv + optind; - - if (!mode) { - /* Defer -k mode setting until we know whether it is a flag or not */ - if (ISSET(flags, MODE_INVALIDATE) && NewArgc == 0) { - mode = MODE_INVALIDATE; /* -k by itself */ - CLR(flags, MODE_INVALIDATE); - valid_flags = 0; - } else { - mode = MODE_RUN; /* running a command */ - } - } - - if (NewArgc > 0 && mode == MODE_LIST) - mode = MODE_CHECK; - - if (ISSET(flags, MODE_LOGIN_SHELL)) { - if (ISSET(flags, MODE_SHELL)) { - warningx("you may not specify both the `-i' and `-s' options"); - usage(1); - } - if (ISSET(flags, MODE_PRESERVE_ENV)) { - warningx("you may not specify both the `-i' and `-E' options"); - usage(1); - } - SET(flags, MODE_SHELL); - } - if ((flags & valid_flags) != flags) - usage(1); - if (mode == MODE_EDIT && - (ISSET(flags, MODE_PRESERVE_ENV) || sudo_user.env_vars != NULL)) { - if (ISSET(mode, MODE_PRESERVE_ENV)) - warningx("the `-E' option is not valid in edit mode"); - if (sudo_user.env_vars != NULL) - warningx("you may not specify environment variables in edit mode"); - usage(1); - } - if ((runas_user != NULL || runas_group != NULL) && - !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) { - usage(1); - } - if (list_pw != NULL && mode != MODE_LIST && mode != MODE_CHECK) { - warningx("the `-U' option may only be used with the `-l' option"); - usage(1); - } - if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) { - warningx("the `-A' and `-S' options may not be used together"); - usage(1); - } - if ((NewArgc == 0 && mode == MODE_EDIT) || - (NewArgc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK))) - usage(1); - if (NewArgc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) - SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL)); - - return(mode | flags); -} - -static int -usage_out(buf) - const char *buf; -{ - return fputs(buf, stderr); -} - -/* - * Give usage message and exit. - * The actual usage strings are in sudo_usage.h for configure substitution. - */ -void -usage(exit_val) - int exit_val; -{ - struct lbuf lbuf; - char *uvec[6]; - int i, ulen; - - /* - * Use usage vectors appropriate to the progname. - */ - if (strcmp(getprogname(), "sudoedit") == 0) { - uvec[0] = SUDO_USAGE5 + 3; - uvec[1] = NULL; - } else { - uvec[0] = SUDO_USAGE1; - uvec[1] = SUDO_USAGE2; - uvec[2] = SUDO_USAGE3; - uvec[3] = SUDO_USAGE4; - uvec[4] = SUDO_USAGE5; - uvec[5] = NULL; - } - - /* - * Print usage and wrap lines as needed, depending on the - * tty width. - */ - ulen = (int)strlen(getprogname()) + 8; - lbuf_init(&lbuf, 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); -} - -/* - * Tell which options are mutually exclusive and exit. - */ -static void -usage_excl(exit_val) - int exit_val; -{ - warningx("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"); - usage(exit_val); -} diff --git a/pathnames.h.in b/pathnames.h.in index 96c4523..32bff86 100644 --- a/pathnames.h.in +++ b/pathnames.h.in @@ -55,6 +55,13 @@ #define _PATH_ENVIRONMENT "/etc/environment" #endif /* _PATH_ENVIRONMENT */ +/* + * NOTE: _PATH_SUDO_CONF is usually overridden by the Makefile. + */ +#ifndef _PATH_SUDO_CONF +#define _PATH_SUDO_CONF "/etc/sudo.conf" +#endif /* _PATH_SUDO_CONF */ + /* * NOTE: _PATH_SUDOERS is usually overridden by the Makefile. */ @@ -102,6 +109,10 @@ #undef _PATH_SUDO_ASKPASS #endif /* _PATH_SUDO_ASKPASS */ +#ifndef _PATH_SUDO_PLUGIN_DIR +#undef _PATH_SUDO_PLUGIN_DIR +#endif /* _PATH_SUDO_PLUGIN_DIR */ + #ifndef _PATH_VI #undef _PATH_VI #endif /* _PATH_VI */ @@ -130,6 +141,10 @@ #undef _PATH_MAILDIR #endif /* _PATH_MAILDIR */ +#ifndef _PATH_UTMP +#undef _PATH_UTMP +#endif /* _PATH_UTMP */ + #ifndef _PATH_SUDO_SESH #undef _PATH_SUDO_SESH #endif /* _PATH_SUDO_SESH */ diff --git a/plugins/sample/Makefile.in b/plugins/sample/Makefile.in new file mode 100644 index 0000000..1e7147c --- /dev/null +++ b/plugins/sample/Makefile.in @@ -0,0 +1,126 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ @LT_STATIC@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Libraries +LIBS = $(LIBOBJDIR)/libreplace.la + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# Flags to pass to the link stage +LDFLAGS = @LDFLAGS@ +LTLDFLAGS = @LTLDFLAGS@ + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ +plugindir = @PLUGINDIR@ +soext = @SOEXT@ + +# OS dependent defines +DEFS = @OSDEFS@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +OBJS = sample_plugin.lo + +LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/ + +VERSION = @PACKAGE_VERSION@ + +all: sample_plugin.la + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file plugins/sample/Makefile) + +.SUFFIXES: .o .c .h .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +sample_plugin.la: $(OBJS) + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(LTLDFLAGS) -o $@ $(OBJS) $(LIBS) -module -export-symbols $(srcdir)/sample_plugin.sym -avoid-version -rpath $(plugindir) + +pre-install: + +install: install-plugin + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir) + +install-binaries: + +install-includes: + +install-doc: + +install-plugin: install-dirs sample_plugin.la + $(INSTALL) -b~ -m 0755 .libs/sample_plugin$(soext) $(DESTDIR)$(plugindir) + +uninstall: + -rm -f $(DESTDIR)$(plugindir)/sample_plugin$(soext) + +check: + +clean: + -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +sample_plugin.lo: $(srcdir)/sample_plugin.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/sudo_plugin.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sample_plugin.c diff --git a/plugins/sample/sample_plugin.c b/plugins/sample/sample_plugin.c new file mode 100644 index 0000000..efa4989 --- /dev/null +++ b/plugins/sample/sample_plugin.c @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2010-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. + */ + +#include + +#include +#include +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include +#include + +#include +#include "sudo_plugin.h" +#include "missing.h" + +/* + * Sample plugin module that allows any user who knows the password + * ("test") to run any command as root. Since there is no credential + * caching the validate and invalidate functions are NULL. + */ + +#ifdef __TANDEM +# define ROOT_UID 65535 +#else +# define ROOT_UID 0 +#endif + +static struct plugin_state { + char **envp; + char * const *settings; + char * const *user_info; +} plugin_state; +static sudo_conv_t sudo_conv; +static sudo_printf_t sudo_log; +static FILE *input, *output; +static uid_t runas_uid = ROOT_UID; +static gid_t runas_gid = -1; +static int use_sudoedit = false; + +/* + * Allocate storage for a name=value string and return it. + */ +static char * +fmt_string(const char *var, const char *val) +{ + size_t var_len = strlen(var); + size_t val_len = strlen(val); + char *cp, *str; + + cp = str = malloc(var_len + 1 + val_len + 1); + if (str != NULL) { + memcpy(cp, var, var_len); + cp += var_len; + *cp++ = '='; + memcpy(cp, val, val_len); + cp += val_len; + *cp = '\0'; + } + + return str; +} + +/* + * Plugin policy open function. + */ +static int +policy_open(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], char * const user_env[], char * const args[]) +{ + char * const *ui; + struct passwd *pw; + const char *runas_user = NULL; + struct group *gr; + const char *runas_group = NULL; + + if (!sudo_conv) + sudo_conv = conversation; + if (!sudo_log) + sudo_log = sudo_printf; + + if (SUDO_API_VERSION_GET_MAJOR(version) != SUDO_API_VERSION_MAJOR) { + sudo_log(SUDO_CONV_ERROR_MSG, + "the sample plugin requires API version %d.x\n", + SUDO_API_VERSION_MAJOR); + return -1; + } + + /* Only allow commands to be run as root. */ + for (ui = settings; *ui != NULL; ui++) { + if (strncmp(*ui, "runas_user=", sizeof("runas_user=") - 1) == 0) { + runas_user = *ui + sizeof("runas_user=") - 1; + } + if (strncmp(*ui, "runas_group=", sizeof("runas_group=") - 1) == 0) { + runas_group = *ui + sizeof("runas_group=") - 1; + } +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + if (strncmp(*ui, "progname=", sizeof("progname=") - 1) == 0) { + setprogname(*ui + sizeof("progname=") - 1); + } +#endif + /* Check to see if sudo was called as sudoedit or with -e flag. */ + if (strncmp(*ui, "sudoedit=", sizeof("sudoedit=") - 1) == 0) { + if (strcasecmp(*ui + sizeof("sudoedit=") - 1, "true") == 0) + use_sudoedit = true; + } + /* This plugin doesn't support running sudo with no arguments. */ + if (strncmp(*ui, "implied_shell=", sizeof("implied_shell=") - 1) == 0) { + if (strcasecmp(*ui + sizeof("implied_shell=") - 1, "true") == 0) + return -2; /* usage error */ + } + } + if (runas_user != NULL) { + if ((pw = getpwnam(runas_user)) == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "unknown user %s\n", runas_user); + return 0; + } + runas_uid = pw->pw_uid; + } + if (runas_group != NULL) { + if ((gr = getgrnam(runas_group)) == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "unknown group %s\n", runas_group); + return 0; + } + runas_gid = gr->gr_gid; + } + + /* Plugin state. */ + plugin_state.envp = (char **)user_env; + plugin_state.settings = settings; + plugin_state.user_info = user_info; + + return 1; +} + +static char * +find_in_path(char *command, char **envp) +{ + struct stat sb; + char *path, *path0, **ep, *cp; + char pathbuf[PATH_MAX], *qualified = NULL; + + if (strchr(command, '/') != NULL) + return command; + + path = _PATH_DEFPATH; + for (ep = plugin_state.envp; *ep != NULL; ep++) { + if (strncmp(*ep, "PATH=", 5) == 0) { + path = *ep + 5; + break; + } + } + path = path0 = strdup(path); + do { + if ((cp = strchr(path, ':'))) + *cp = '\0'; + snprintf(pathbuf, sizeof(pathbuf), "%s/%s", *path ? path : ".", + command); + if (stat(pathbuf, &sb) == 0) { + if (S_ISREG(sb.st_mode) && (sb.st_mode & 0000111)) { + qualified = pathbuf; + break; + } + } + path = cp + 1; + } while (cp != NULL); + free(path0); + return qualified ? strdup(qualified) : NULL; +} + +static int +check_passwd(void) +{ + struct sudo_conv_message msg; + struct sudo_conv_reply repl; + + /* Prompt user for password via conversation function. */ + memset(&msg, 0, sizeof(msg)); + msg.msg_type = SUDO_CONV_PROMPT_ECHO_OFF; + msg.msg = "Password: "; + memset(&repl, 0, sizeof(repl)); + sudo_conv(1, &msg, &repl); + if (repl.reply == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "missing password\n"); + return false; + } + if (strcmp(repl.reply, "test") != 0) { + sudo_log(SUDO_CONV_ERROR_MSG, "incorrect password\n"); + return false; + } + return true; +} + +static char ** +build_command_info(char *command) +{ + static char **command_info; + int i = 0; + + /* Setup command info. */ + command_info = calloc(32, sizeof(char *)); + if (command_info == NULL) + return NULL; + if ((command_info[i++] = fmt_string("command", command)) == NULL || + asprintf(&command_info[i++], "runas_euid=%ld", (long)runas_uid) == -1 || + asprintf(&command_info[i++], "runas_uid=%ld", (long)runas_uid) == -1) { + return NULL; + } + if (runas_gid != -1) { + if (asprintf(&command_info[i++], "runas_gid=%ld", (long)runas_gid) == -1 || + asprintf(&command_info[i++], "runas_egid=%ld", (long)runas_gid) == -1) { + return NULL; + } + } + if (use_sudoedit) { + command_info[i] = strdup("sudoedit=true"); + if (command_info[i++] == NULL) + return NULL; + } +#ifdef USE_TIMEOUT + command_info[i++] = "timeout=30"; +#endif + return command_info; +} + +static char * +find_editor(int nfiles, char * const files[], char **argv_out[]) +{ + char *cp, **ep, **nargv, *editor, *editor_path; + int ac, i, nargc, wasblank; + + /* Lookup EDITOR in user's environment. */ + editor = _PATH_VI; + for (ep = plugin_state.envp; *ep != NULL; ep++) { + if (strncmp(*ep, "EDITOR=", 7) == 0) { + editor = *ep + 7; + break; + } + } + editor = strdup(editor); + if (editor == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "unable to allocate memory\n"); + return NULL; + } + + /* + * Split editor into an argument vector; editor is reused (do not free). + * The EDITOR environment variables may contain command + * line args so look for those and alloc space for them too. + */ + nargc = 1; + for (wasblank = 0, cp = editor; *cp != '\0'; cp++) { + if (isblank((unsigned char) *cp)) + wasblank = 1; + else if (wasblank) { + wasblank = 0; + nargc++; + } + } + /* If we can't find the editor in the user's PATH, give up. */ + cp = strtok(editor, " \t"); + if (cp == NULL || + (editor_path = find_in_path(editor, plugin_state.envp)) == NULL) { + return NULL; + } + nargv = (char **) malloc((nargc + 1 + nfiles + 1) * sizeof(char *)); + if (nargv == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "unable to allocate memory\n"); + return NULL; + } + for (ac = 0; cp != NULL && ac < nargc; ac++) { + nargv[ac] = cp; + cp = strtok(NULL, " \t"); + } + nargv[ac++] = "--"; + for (i = 0; i < nfiles; ) + nargv[ac++] = files[i++]; + nargv[ac] = NULL; + + *argv_out = nargv; + return editor_path; +} + +/* + * Plugin policy check function. + * Simple example that prompts for a password, hard-coded to "test". + */ +static int +policy_check(int argc, char * const argv[], + char *env_add[], char **command_info_out[], + char **argv_out[], char **user_env_out[]) +{ + char *command; + + if (!argc || argv[0] == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "no command specified\n"); + return false; + } + + if (!check_passwd()) + return false; + + command = find_in_path(argv[0], plugin_state.envp); + if (command == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "%s: command not found\n", argv[0]); + return false; + } + + /* If "sudo vi" is run, auto-convert to sudoedit. */ + if (strcmp(command, _PATH_VI) == 0) + use_sudoedit = true; + + if (use_sudoedit) { + /* Rebuild argv using editor */ + command = find_editor(argc - 1, argv + 1, argv_out); + if (command == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "unable to find valid editor\n"); + return -1; + } + use_sudoedit = true; + } else { + /* No changes needd to argv */ + *argv_out = (char **)argv; + } + + /* No changes to envp */ + *user_env_out = plugin_state.envp; + + /* Setup command info. */ + *command_info_out = build_command_info(command); + if (*command_info_out == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, "out of memory\n"); + return -1; + } + + return true; +} + +static int +policy_list(int argc, char * const argv[], int verbose, const char *list_user) +{ + /* + * List user's capabilities. + */ + sudo_log(SUDO_CONV_INFO_MSG, "Validated users may run any command\n"); + return true; +} + +static int +policy_version(int verbose) +{ + sudo_log(SUDO_CONV_INFO_MSG, "Sample policy plugin version %s\n", PACKAGE_VERSION); + return true; +} + +static void +policy_close(int exit_status, int error) +{ + /* + * The policy might log the command exit status here. + * In this example, we just print a message. + */ + if (error) { + sudo_log(SUDO_CONV_ERROR_MSG, "Command error: %s\n", strerror(error)); + } else { + if (WIFEXITED(exit_status)) { + sudo_log(SUDO_CONV_INFO_MSG, "Command exited with status %d\n", + WEXITSTATUS(exit_status)); + } else if (WIFSIGNALED(exit_status)) { + sudo_log(SUDO_CONV_INFO_MSG, "Command killed by signal %d\n", + WTERMSIG(exit_status)); + } + } +} + +static int +io_open(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], char * const command_info[], + int argc, char * const argv[], char * const user_env[], char * const args[]) +{ + int fd; + char path[PATH_MAX]; + + if (!sudo_conv) + sudo_conv = conversation; + if (!sudo_log) + sudo_log = sudo_printf; + + /* Open input and output files. */ + snprintf(path, sizeof(path), "/var/tmp/sample-%u.output", + (unsigned int)getpid()); + fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0644); + if (fd == -1) + return false; + output = fdopen(fd, "w"); + + snprintf(path, sizeof(path), "/var/tmp/sample-%u.input", + (unsigned int)getpid()); + fd = open(path, O_WRONLY|O_CREAT|O_EXCL, 0644); + if (fd == -1) + return false; + input = fdopen(fd, "w"); + + return true; +} + +static void +io_close(int exit_status, int error) +{ + fclose(input); + fclose(output); +} + +static int +io_version(int verbose) +{ + sudo_log(SUDO_CONV_INFO_MSG, "Sample I/O plugin version %s\n", + PACKAGE_VERSION); + return true; +} + +static int +io_log_input(const char *buf, unsigned int len) +{ + ignore_result(fwrite(buf, len, 1, input)); + return true; +} + +static int +io_log_output(const char *buf, unsigned int len) +{ + ignore_result(fwrite(buf, len, 1, output)); + return true; +} + +struct policy_plugin sample_policy = { + SUDO_POLICY_PLUGIN, + SUDO_API_VERSION, + policy_open, + policy_close, + policy_version, + policy_check, + policy_list, + NULL, /* validate */ + NULL, /* invalidate */ + NULL, /* init_session */ + NULL, /* register_hooks */ + NULL /* deregister_hooks */ +}; + +/* + * Note: This plugin does not differentiate between tty and pipe I/O. + * It all gets logged to the same file. + */ +struct io_plugin sample_io = { + SUDO_IO_PLUGIN, + SUDO_API_VERSION, + io_open, + io_close, + io_version, + io_log_input, /* tty input */ + io_log_output, /* tty output */ + io_log_input, /* command stdin if not tty */ + io_log_output, /* command stdout if not tty */ + io_log_output /* command stderr if not tty */ +}; diff --git a/plugins/sample/sample_plugin.sym b/plugins/sample/sample_plugin.sym new file mode 100644 index 0000000..9f85094 --- /dev/null +++ b/plugins/sample/sample_plugin.sym @@ -0,0 +1,2 @@ +sample_policy +sample_io diff --git a/plugins/sample_group/Makefile.in b/plugins/sample_group/Makefile.in new file mode 100644 index 0000000..46b2001 --- /dev/null +++ b/plugins/sample_group/Makefile.in @@ -0,0 +1,129 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ @LT_STATIC@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Libraries +LT_LIBS = $(LIBOBJDIR)libreplace.la +LIBS = $(LT_LIBS) + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# Flags to pass to the link stage +LDFLAGS = @LDFLAGS@ +LTLDFLAGS = @LTLDFLAGS@ + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ +plugindir = @PLUGINDIR@ +soext = @SOEXT@ + +# OS dependent defines +DEFS = @OSDEFS@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +OBJS = sample_group.lo getgrent.lo + +LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/ + +VERSION = @PACKAGE_VERSION@ + +all: sample_group.la + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file plugins/sample_group/Makefile) + +.SUFFIXES: .o .c .h .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +sample_group.la: $(OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(LTLDFLAGS) -o $@ $(OBJS) $(LIBS) -module -export-symbols $(srcdir)/sample_group.sym -avoid-version -rpath $(plugindir) + +pre-install: + +install: install-plugin + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir) + +install-binaries: + +install-includes: + +install-doc: + +install-plugin: install-dirs sample_group.la + $(INSTALL) -b~ -m 0755 .libs/sample_group$(soext) $(DESTDIR)$(plugindir) + +uninstall: + -rm -f $(DESTDIR)$(plugindir)/sample_group$(soext) + +check: + +clean: + -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +getgrent.lo: $(srcdir)/getgrent.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getgrent.c +sample_group.lo: $(srcdir)/sample_group.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/sudo_plugin.h \ + $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sample_group.c diff --git a/plugins/sample_group/getgrent.c b/plugins/sample_group/getgrent.c new file mode 100644 index 0000000..aa98c14 --- /dev/null +++ b/plugins/sample_group/getgrent.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2005,2008,2010-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. + */ + +/* + * Trivial replacements for the libc getgr{uid,nam}() routines. + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include "missing.h" + +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + +#undef GRMEM_MAX +#define GRMEM_MAX 200 + +static FILE *grf; +static const char *grfile = "/etc/group"; +static int gr_stayopen; + +void mysetgrfile(const char *); +void mysetgrent(void); +void myendgrent(void); +struct group *mygetgrent(void); +struct group *mygetgrnam(const char *); +struct group *mygetgrgid(gid_t); + +void +mysetgrfile(const char *file) +{ + grfile = file; + if (grf != NULL) + myendgrent(); +} + +void +mysetgrent(void) +{ + if (grf == NULL) { + grf = fopen(grfile, "r"); + if (grf != NULL) + fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); + } else { + rewind(grf); + } + gr_stayopen = 1; +} + +void +myendgrent(void) +{ + if (grf != NULL) { + fclose(grf); + grf = NULL; + } + gr_stayopen = 0; +} + +struct group * +mygetgrent(void) +{ + static struct group gr; + static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1]; + size_t len; + char *cp, *colon; + int n; + + if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL) + return NULL; + + memset(&gr, 0, sizeof(gr)); + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + gr.gr_name = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + gr.gr_passwd = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + gr.gr_gid = atoi(cp); + len = strlen(colon); + if (len > 0 && colon[len - 1] == '\n') + colon[len - 1] = '\0'; + if (*colon != '\0') { + gr.gr_mem = gr_mem; + cp = strtok(colon, ","); + for (n = 0; cp != NULL && n < GRMEM_MAX; n++) { + gr.gr_mem[n] = cp; + cp = strtok(NULL, ","); + } + gr.gr_mem[n++] = NULL; + } else + gr.gr_mem = NULL; + return &gr; +} + +struct group * +mygetgrnam(const char *name) +{ + struct group *gr; + + if (grf == NULL) { + if ((grf = fopen(grfile, "r")) == NULL) + return NULL; + fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); + } else { + rewind(grf); + } + while ((gr = mygetgrent()) != NULL) { + if (strcmp(gr->gr_name, name) == 0) + break; + } + if (!gr_stayopen) { + fclose(grf); + grf = NULL; + } + return gr; +} + +struct group * +mygetgrgid(gid_t gid) +{ + struct group *gr; + + if (grf == NULL) { + if ((grf = fopen(grfile, "r")) == NULL) + return NULL; + fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); + } else { + rewind(grf); + } + while ((gr = mygetgrent()) != NULL) { + if (gr->gr_gid == gid) + break; + } + if (!gr_stayopen) { + fclose(grf); + grf = NULL; + } + return gr; +} diff --git a/plugins/sample_group/plugin_test.c b/plugins/sample_group/plugin_test.c new file mode 100644 index 0000000..87077a5 --- /dev/null +++ b/plugins/sample_group/plugin_test.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2010-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. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sudo_plugin.h" + +/* + * Simple driver to test sudoer group plugins. + * usage: plugin_test [-p "plugin.so plugin_args ..."] user:group ... + */ + +static void *group_handle; +static struct sudoers_group_plugin *group_plugin; + +static int +plugin_printf(int msg_type, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + + switch (msg_type) { + case SUDO_CONV_INFO_MSG: + fp = stdout; + break; + case SUDO_CONV_ERROR_MSG: + fp = stderr; + break; + default: + errno = EINVAL; + return -1; + } + + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); + + return 0; +} + +/* + * Load the specified plugin and run its init function. + * Returns -1 if unable to open the plugin, else it returns + * the value from the plugin's init function. + */ +static int +group_plugin_load(char *plugin_info) +{ + char *args, path[PATH_MAX], savedch; + char **argv = NULL; + int rc; + + /* + * Fill in .so path and split out args (if any). + */ + if ((args = strpbrk(plugin_info, " \t")) != NULL) { + savedch = *args; + *args = '\0'; + } + strncpy(path, plugin_info, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + if (args != NULL) + *args++ = savedch; + + /* Open plugin and map in symbol. */ + group_handle = dlopen(path, RTLD_LAZY); + if (!group_handle) { + fprintf(stderr, "unable to dlopen %s: %s\n", path, dlerror()); + return -1; + } + group_plugin = dlsym(group_handle, "group_plugin"); + if (group_plugin == NULL) { + fprintf(stderr, "unable to find symbol \"group_plugin\" in %s\n", path); + return -1; + } + + if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) { + fprintf(stderr, + "%s: incompatible group plugin major version %d, expected %d\n", + path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version), + GROUP_API_VERSION_MAJOR); + return -1; + } + + /* + * Split args into a vector if specified. + */ + if (args != NULL) { + int ac = 0, wasblank = 1; + char *cp; + + for (cp = args; *cp != '\0'; cp++) { + if (isblank((unsigned char)*cp)) { + wasblank = 1; + } else if (wasblank) { + wasblank = 0; + ac++; + } + } + if (ac != 0) { + argv = malloc(ac * sizeof(char *)); + if (argv == NULL) { + fprintf(stderr, "unable to allocate memory\n"); + return -1; + } + ac = 0; + for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t"))) + argv[ac++] = cp; + } + } + + rc = (group_plugin->init)(GROUP_API_VERSION, plugin_printf, argv); + + free(argv); + + return rc; +} + +static void +group_plugin_unload(void) +{ + (group_plugin->cleanup)(); + dlclose(group_handle); + group_handle = NULL; +} + +static int +group_plugin_query(const char *user, const char *group, + const struct passwd *pwd) +{ + return group_plugin->query)(user, group, pwd; +} + +static void +usage(void) +{ + fprintf(stderr, + "usage: plugin_test [-p \"plugin.so plugin_args ...\"] user:group ...\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int ch, i, found; + char *plugin = "sample_group.so"; + char *user, *group; + struct passwd *pwd; + + while ((ch = getopt(argc, argv, "p:")) != -1) { + switch (ch) { + case 'p': + plugin = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc < 1) + usage(); + + if (group_plugin_load(plugin) != 1) { + fprintf(stderr, "unable to load plugin: %s\n", plugin); + exit(1); + } + + for (i = 0; argv[i] != NULL; i++) { + user = argv[i]; + group = strchr(argv[i], ':'); + if (group == NULL) + continue; + *group++ = '\0'; + pwd = getpwnam(user); + found = group_plugin_query(user, group, pwd); + printf("user %s %s in group %s\n", user, found ? "is" : "NOT ", group); + } + group_plugin_unload(); + + exit(0); +} + diff --git a/plugins/sample_group/sample_group.c b/plugins/sample_group/sample_group.c new file mode 100644 index 0000000..2e3628d --- /dev/null +++ b/plugins/sample_group/sample_group.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include +#include + +#include "sudo_plugin.h" +#include "missing.h" + +/* + * Sample sudoers group plugin that uses an extra group file with the + * same format as /etc/group. + */ + +static sudo_printf_t sudo_log; + +extern void mysetgrfile(const char *); +extern void mysetgrent(void); +extern void myendgrent(void); +extern struct group *mygetgrnam(const char *); + +static int +sample_init(int version, sudo_printf_t sudo_printf, char *const argv[]) +{ + struct stat sb; + + sudo_log = sudo_printf; + + if (GROUP_API_VERSION_GET_MAJOR(version) != GROUP_API_VERSION_MAJOR) { + sudo_log(SUDO_CONV_ERROR_MSG, + "sample_group: incompatible major version %d, expected %d\n", + GROUP_API_VERSION_GET_MAJOR(version), + GROUP_API_VERSION_MAJOR); + return -1; + } + + /* Sanity check the specified group file. */ + if (argv == NULL || argv[0] == NULL) { + sudo_log(SUDO_CONV_ERROR_MSG, + "sample_group: path to group file not specified\n"); + return -1; + } + if (stat(argv[0], &sb) != 0) { + sudo_log(SUDO_CONV_ERROR_MSG, + "sample_group: %s: %s\n", argv[0], strerror(errno)); + return -1; + } + if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { + sudo_log(SUDO_CONV_ERROR_MSG, + "%s must be only be writable by owner\n", argv[0]); + return -1; + } + + mysetgrfile(argv[0]); + mysetgrent(); + + return true; +} + +static void +sample_cleanup(void) +{ + myendgrent(); +} + +/* + * Returns true if "user" is a member of "group", else false. + */ +static int +sample_query(const char *user, const char *group, const struct passwd *pwd) +{ + struct group *grp; + char **member; + + grp = mygetgrnam(group); + if (grp != NULL) { + for (member = grp->gr_mem; *member != NULL; member++) { + if (strcasecmp(user, *member) == 0) + return true; + } + } + + return false; +} + +struct sudoers_group_plugin group_plugin = { + GROUP_API_VERSION, + sample_init, + sample_cleanup, + sample_query +}; diff --git a/plugins/sample_group/sample_group.sym b/plugins/sample_group/sample_group.sym new file mode 100644 index 0000000..a859d6c --- /dev/null +++ b/plugins/sample_group/sample_group.sym @@ -0,0 +1 @@ +group_plugin diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in new file mode 100644 index 0000000..8769d38 --- /dev/null +++ b/plugins/sudoers/Makefile.in @@ -0,0 +1,779 @@ +# +# Copyright (c) 1996, 1998-2005, 2007-2012 +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Sponsored in part by the Defense Advanced Research Projects +# Agency (DARPA) and Air Force Research Laboratory, Air Force +# Materiel Command, USAF, under agreement number F39502-99-1-0512. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +authdir = $(srcdir)/auth +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include +docdir = @docdir@ +timedir = @timedir@ + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ +FLEX = @FLEX@ +YACC = @YACC@ +PERL = perl + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Libraries +LT_LIBS = $(top_builddir)/common/libcommon.la $(LIBOBJDIR)libreplace.la +LIBS = $(LT_LIBS) @LIBINTL@ +NET_LIBS = @NET_LIBS@ +SUDOERS_LIBS = @SUDOERS_LIBS@ @AFS_LIBS@ @GETGROUPS_LIB@ $(LIBS) $(NET_LIBS) @ZLIB@ +REPLAY_LIBS = @REPLAY_LIBS@ @ZLIB@ + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(devdir) -I$(srcdir) -I$(top_srcdir) @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# Flags to pass to the link stage +LDFLAGS = @LDFLAGS@ +SUDOERS_LDFLAGS = $(LDFLAGS) @SUDOERS_LDFLAGS@ +LTLDFLAGS = @LTLDFLAGS@ + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ + +# File extension for shared objects +soext = @SOEXT@ + +# Directory in which to install the sudoers plugin +plugindir = @PLUGINDIR@ + +# Directory in which to install the sudoers file +sudoersdir = $(sysconfdir) + +# Directory in which to install sudoreplay. +replaydir = $(bindir) + +# Directory in which to install visudo +visudodir = $(sbindir) + +# User and group ids the installed files should be "owned" by +install_uid = 0 +install_gid = 0 + +# User, group, and mode the sudoers file should be "owned" by (configure) +sudoers_uid = @SUDOERS_UID@ +sudoers_gid = @SUDOERS_GID@ +sudoers_mode = @SUDOERS_MODE@ + +# Pass in paths and uid/gid + OS dependent defines +DEFS = @OSDEFS@ -D_PATH_SUDOERS=\"$(sudoersdir)/sudoers\" \ + -DSUDOERS_UID=$(sudoers_uid) -DSUDOERS_GID=$(sudoers_gid) \ + -DSUDOERS_MODE=$(sudoers_mode) -DLOCALEDIR=\"$(localedir)\" + +# Set to non-empty for development mode +DEVEL = @DEVEL@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +PROGS = sudoers.la visudo sudoreplay testsudoers + +TEST_PROGS = check_iolog_path check_fill check_wrap check_addr + +AUTH_OBJS = sudo_auth.lo @AUTH_OBJS@ + +LIBPARSESUDOERS_OBJS = alias.lo audit.lo defaults.lo gram.lo match.lo \ + match_addr.lo pwutil.lo timestr.lo toke.lo \ + toke_util.lo redblack.lo + +SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo env.lo goodpath.lo \ + group_plugin.lo find_path.lo interfaces.lo logging.lo \ + logwrap.lo parse.lo set_perms.lo sudoers.lo sudo_nss.lo \ + iolog.lo iolog_path.lo @SUDOERS_OBJS@ + +VISUDO_OBJS = visudo.o goodpath.o find_path.o error.o + +REPLAY_OBJS = getdate.o sudoreplay.o error.o + +TEST_OBJS = interfaces.o testsudoers.o tsgetgrpw.o error.o group_plugin.o \ + net_ifs.o + +CHECK_ADDR_OBJS = check_addr.o match_addr.o interfaces.o error.o + +CHECK_FILL_OBJS = check_fill.o toke_util.o error.o + +CHECK_IOLOG_PATH_OBJS = check_iolog_path.o error.o iolog_path.o pwutil.o \ + redblack.o + +CHECK_WRAP_OBJS = check_wrap.o logwrap.o error.o + +LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/ + +VERSION = @PACKAGE_VERSION@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ + +all: $(PROGS) + +.SUFFIXES: .o .c .h .l .y .lo + +.c.o: + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +# Prevent default rules from building .c files from .l and .y files +.l.c: + +.y.c: + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file plugins/sudoers/Makefile) + +libparsesudoers.la: $(LIBPARSESUDOERS_OBJS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(LIBPARSESUDOERS_OBJS) -no-install + +sudoers.la: $(SUDOERS_OBJS) $(LT_LIBS) libparsesudoers.la + $(LIBTOOL) @LT_STATIC@ --mode=link $(CC) $(SUDOERS_LDFLAGS) $(LTLDFLAGS) -o $@ $(SUDOERS_OBJS) libparsesudoers.la $(SUDOERS_LIBS) -module -export-symbols $(srcdir)/sudoers.sym -avoid-version -rpath $(plugindir) + +visudo: libparsesudoers.la $(VISUDO_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(VISUDO_OBJS) $(LDFLAGS) libparsesudoers.la $(LIBS) $(NET_LIBS) + +sudoreplay: timestr.lo $(REPLAY_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(REPLAY_OBJS) $(LDFLAGS) timestr.lo $(REPLAY_LIBS) $(LIBS) + +testsudoers: libparsesudoers.la $(TEST_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(TEST_OBJS) $(LDFLAGS) libparsesudoers.la $(LIBS) $(NET_LIBS) @LIBDL@ + +check_addr: $(CHECK_ADDR_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(CHECK_ADDR_OBJS) $(LDFLAGS) $(LIBS) $(NET_LIBS) + +check_iolog_path: $(CHECK_IOLOG_PATH_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(CHECK_IOLOG_PATH_OBJS) $(LDFLAGS) $(LIBS) + +check_fill: $(CHECK_FILL_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(CHECK_FILL_OBJS) $(LDFLAGS) $(LIBS) + +check_wrap: $(CHECK_WRAP_OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(CHECK_WRAP_OBJS) $(LDFLAGS) $(LIBS) + +GENERATED = gram.h gram.c toke.c def_data.c def_data.h getdate.c + +$(devdir)/gram.c $(devdir)/gram.h: $(srcdir)/gram.y + @if [ -n "$(DEVEL)" ]; then \ + if test "$(srcdir)" = "."; then \ + gram_y="gram.y"; \ + else \ + gram_y="$(srcdir)/gram.y"; \ + fi; \ + cmd='$(YACC) -d '"$$gram_y"'; echo "#include " > $(devdir)/gram.c; sed "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"gram.c\"/" y.tab.c >> $(devdir)/gram.c; rm -f y.tab.c; mv -f y.tab.h $(devdir)/gram.h'; \ + echo "$$cmd"; eval $$cmd; \ + fi + +$(devdir)/toke.c: $(srcdir)/toke.l + @if [ -n "$(DEVEL)" ]; then \ + if test "$(srcdir)" = "."; then \ + toke_l="toke.l"; \ + else \ + toke_l="$(srcdir)/toke.l"; \ + fi; \ + cmd='$(FLEX) '"$$toke_l"'; echo "#include " > $(devdir)/toke.c; cat lex.yy.c >> $(devdir)/toke.c'; \ + echo "$$cmd"; eval $$cmd; \ + fi + +# Uncomment the lines before -@true if you intend to modify getdate.y +$(devdir)/getdate.c: $(srcdir)/getdate.y + @if [ -n "$(DEVEL)" ]; then \ + echo "expect 10 shift/reduce conflicts"; \ + if test "$(srcdir)" = "."; then \ + getdate_y="getdate.y"; \ + else \ + getdate_y="$(srcdir)/getdate.y"; \ + fi; \ + cmd='$(YACC) '"$$getdate_y"'; echo "#include " > $(devdir)/getdate.c; sed "s/^\\(#line .*\\) \"y\\.tab\\.c\"/\1 \"getdate.c\"/" y.tab.c >> $(devdir)/getdate.c; rm -f y.tab.c'; \ + echo "$$cmd"; eval $$cmd; \ + fi + +# Uncomment the following if you intend to modify def_data.in +$(devdir)/def_data.c $(devdir)/def_data.h: $(srcdir)/def_data.in + @if [ -n "$(DEVEL)" ]; then \ + cmd='$(PERL) $(srcdir)/mkdefaults -o $(devdir)/def_data $(srcdir)/def_data.in'; \ + echo "$$cmd"; eval $$cmd; \ + fi + +sudoers: $(srcdir)/sudoers.in + (cd $(top_builddir) && $(SHELL) config.status --file=plugins/sudoers/$@) + +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-plugin install-binaries install-sudoers install-doc + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir) \ + $(DESTDIR)$(visudodir) $(DESTDIR)$(replaydir) \ + $(DESTDIR)$(sudoersdir) $(DESTDIR)$(docdir) \ + `echo $(DESTDIR)$(timedir)|sed 's,/[^/]*$$,,'` + $(INSTALL) -d -O $(install_uid) -G $(install_gid) -m 0700 $(DESTDIR)$(timedir) + +install-binaries: visudo sudoreplay install-dirs + $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sudoreplay $(DESTDIR)$(replaydir)/sudoreplay + $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 visudo $(DESTDIR)$(visudodir)/visudo + +install-includes: + +install-doc: install-dirs + @LDAP@$(INSTALL) -O $(install_uid) -G $(install_gid) -m 0555 $(srcdir)/sudoers2ldif $(DESTDIR)$(docdir) + +install-plugin: sudoers.la install-dirs + if [ X"$(soext)" != X"" ]; then \ + $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -m 0755 .libs/sudoers$(soext) $(DESTDIR)$(plugindir); \ + fi + +install-sudoers: install-dirs + $(INSTALL) -d -O $(sudoers_uid) -G $(sudoers_gid) -m 0750 \ + $(DESTDIR)$(sudoersdir)/sudoers.d + test -r $(DESTDIR)$(sudoersdir)/sudoers || \ + $(INSTALL) -O $(sudoers_uid) -G $(sudoers_gid) -m $(sudoers_mode) \ + sudoers $(DESTDIR)$(sudoersdir)/sudoers + +uninstall: + -rm -f $(DESTDIR)$(plugindir)/sudoers$(soext) + -rm -f $(DESTDIR)$(replaydir)/sudoreplay + -rm -f $(DESTDIR)$(visudodir)/visudo + -cmp $(DESTDIR)$(sudoersdir)/sudoers $(srcdir)/sudoers >/dev/null && \ + rm -f $(DESTDIR)$(sudoersdir)/sudoers + +check: $(TEST_PROGS) visudo testsudoers + @-rval=0; \ + ./check_addr $(srcdir)/regress/parser/check_addr.in; \ + rval=`expr $$rval + $$?`; \ + ./check_fill; \ + rval=`expr $$rval + $$?`; \ + ./check_iolog_path $(srcdir)/regress/iolog_path/data; \ + rval=`expr $$rval + $$?`; \ + ./check_wrap $(srcdir)/regress/logging/check_wrap.in > check_wrap.out; \ + diff check_wrap.out $(srcdir)/regress/logging/check_wrap.out.ok; \ + rval=`expr $$rval + $$?`; \ + passed=0; failed=0; total=0; \ + for t in $(srcdir)/regress/sudoers/*.in; do \ + dir=`dirname $$t`; \ + dirbase=`basename $$dir`; \ + base=`basename $$t .in`; \ + out="$${base}.out"; \ + toke="$${base}.toke"; \ + ./testsudoers -dt <$$t >$$out 2>$$toke; \ + if cmp $$out $$dir/$$out.ok >/dev/null; then \ + passed=`expr $$passed + 1`; \ + echo "$$dirbase/$$base (parse): OK"; \ + else \ + failed=`expr $$failed + 1`; \ + echo "$$dirbase/$$base: FAIL"; \ + diff $$out $$dir/$$out.ok; \ + fi; \ + total=`expr $$total + 1`; \ + if cmp $$toke $$dir/$$toke.ok >/dev/null; then \ + passed=`expr $$passed + 1`; \ + echo "$$dirbase/$$base (toke): OK"; \ + else \ + failed=`expr $$failed + 1`; \ + echo "$$dirbase/$$base (toke): FAIL"; \ + diff $$out $$dir/$$out.ok; \ + fi; \ + total=`expr $$total + 1`; \ + done; \ + echo "$$dirbase: $$passed/$$total tests passed; $$failed/$$total tests failed"; \ + rval=`expr $$rval + $$failed`; \ + passed=0; failed=0; total=0; \ + for t in $(srcdir)/regress/*/*.sh; do \ + dir=`dirname $$t`; \ + dirbase=`basename $$dir`; \ + base=`basename $$t .sh`; \ + out="$${base}.out"; \ + err="$${base}.err"; \ + $(SHELL) $$t >$$out 2>$$err; \ + if cmp $$out $$dir/$$out.ok >/dev/null; then \ + passed=`expr $$passed + 1`; \ + echo "$$dirbase/$$base: OK"; \ + else \ + failed=`expr $$failed + 1`; \ + echo "$$dirbase/$$base: FAIL"; \ + diff $$out $$dir/$$out.ok; \ + fi; \ + total=`expr $$total + 1`; \ + if test -s $$dir/$$err.ok; then \ + if cmp $$err $$dir/$$err.ok >/dev/null; then \ + passed=`expr $$passed + 1`; \ + echo "$$dirbase/$$base (stderr): OK"; \ + else \ + failed=`expr $$failed + 1`; \ + echo "$$dirbase/$$base (stderr): FAIL"; \ + diff $$out $$dir/$$out.ok; \ + fi; \ + total=`expr $$total + 1`; \ + elif test -s $$err; then \ + cat $$err 1>&2; \ + fi; \ + done; \ + echo "$$dirbase: $$passed/$$total tests passed; $$failed/$$total tests failed"; \ + rval=`expr $$rval + $$failed`; exit $$rval + +clean: + -$(LIBTOOL) --mode=clean rm -f $(PROGS) $(TEST_PROGS) *.lo *.o *.la *.a stamp-* core *.core core.* *.out *.toke *.err + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile sudoers sudoers.lo .libs $(LINKS) + @if [ -n "$(DEVEL)" -a "$(devdir)" != "$(srcdir)" ]; then \ + cmd='rm -rf $(GENERATED)'; \ + echo "$$cmd"; eval $$cmd; \ + fi + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +afs.lo: $(authdir)/afs.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/afs.c +aix_auth.lo: $(authdir)/aix_auth.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ + $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ + $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/aix_auth.c +alias.lo: $(srcdir)/alias.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/parse.h $(srcdir)/redblack.h $(devdir)/gram.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/alias.c +audit.lo: $(srcdir)/audit.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(srcdir)/logging.h $(incdir)/sudo_debug.h $(srcdir)/bsm_audit.h \ + $(srcdir)/linux_audit.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/audit.c +boottime.lo: $(srcdir)/boottime.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/sudo_debug.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/boottime.c +bsdauth.lo: $(authdir)/bsdauth.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/bsdauth.c +bsm_audit.lo: $(srcdir)/bsm_audit.c $(top_builddir)/config.h \ + $(incdir)/gettext.h $(incdir)/error.h $(incdir)/sudo_debug.h \ + $(srcdir)/bsm_audit.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/bsm_audit.c +check.lo: $(srcdir)/check.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/check.c +check_addr.o: $(srcdir)/regress/parser/check_addr.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/parse.h \ + $(srcdir)/interfaces.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/parser/check_addr.c +check_fill.o: $(srcdir)/regress/parser/check_fill.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/list.h \ + $(srcdir)/parse.h $(srcdir)/toke.h $(incdir)/sudo_plugin.h \ + $(devdir)/gram.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/parser/check_fill.c +check_iolog_path.o: $(srcdir)/regress/iolog_path/check_iolog_path.c \ + $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(devdir)/def_data.c + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/iolog_path/check_iolog_path.c +check_wrap.o: $(srcdir)/regress/logging/check_wrap.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/sudo_plugin.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/regress/logging/check_wrap.c +dce.lo: $(authdir)/dce.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/dce.c +defaults.lo: $(srcdir)/defaults.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(srcdir)/parse.h $(devdir)/gram.h \ + $(devdir)/def_data.c + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/defaults.c +env.lo: $(srcdir)/env.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/env.c +error.o: $(top_srcdir)/src/error.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(top_srcdir)/src/error.c +find_path.lo: $(srcdir)/find_path.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/find_path.c +find_path.o: find_path.lo +fwtk.lo: $(authdir)/fwtk.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/fwtk.c +getdate.o: $(devdir)/getdate.c $(top_builddir)/config.h \ + $(top_builddir)/config.h $(incdir)/missing.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/getdate.c +getspwuid.lo: $(srcdir)/getspwuid.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/getspwuid.c +goodpath.lo: $(srcdir)/goodpath.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/goodpath.c +goodpath.o: goodpath.lo +gram.lo: $(devdir)/gram.c $(top_builddir)/config.h $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ + $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ + $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(srcdir)/parse.h $(srcdir)/toke.h $(devdir)/gram.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/gram.c +group_plugin.lo: $(srcdir)/group_plugin.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/dlfcn.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/group_plugin.c +group_plugin.o: group_plugin.lo +interfaces.lo: $(srcdir)/interfaces.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(srcdir)/interfaces.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/interfaces.c +interfaces.o: interfaces.lo +iolog.lo: $(srcdir)/iolog.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/iolog.c +iolog_path.lo: $(srcdir)/iolog_path.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/iolog_path.c +iolog_path.o: iolog_path.lo +kerb5.lo: $(authdir)/kerb5.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/kerb5.c +ldap.lo: $(srcdir)/ldap.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/parse.h $(incdir)/lbuf.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ldap.c +linux_audit.lo: $(srcdir)/linux_audit.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/gettext.h $(incdir)/sudo_debug.h \ + $(srcdir)/linux_audit.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/linux_audit.c +logging.lo: $(srcdir)/logging.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/logging.c +logwrap.lo: $(srcdir)/logwrap.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/logwrap.c +logwrap.o: logwrap.lo +match.lo: $(srcdir)/match.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/parse.h $(devdir)/gram.h $(top_srcdir)/compat/fnmatch.h \ + $(top_srcdir)/compat/glob.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/match.c +match_addr.lo: $(srcdir)/match_addr.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(srcdir)/interfaces.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/match_addr.c +match_addr.o: match_addr.lo +net_ifs.o: $(top_srcdir)/src/net_ifs.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(top_srcdir)/src/net_ifs.c +pam.lo: $(authdir)/pam.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/pam.c +parse.lo: $(srcdir)/parse.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/parse.h $(incdir)/lbuf.h $(devdir)/gram.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/parse.c +passwd.lo: $(authdir)/passwd.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/passwd.c +plugin_error.lo: $(srcdir)/plugin_error.c $(top_builddir)/config.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/sudo_plugin.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/plugin_error.c +pwutil.lo: $(srcdir)/pwutil.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/redblack.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/pwutil.c +pwutil.o: pwutil.lo +redblack.lo: $(srcdir)/redblack.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/sudo_debug.h $(srcdir)/redblack.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/redblack.c +redblack.o: redblack.lo +rfc1938.lo: $(authdir)/rfc1938.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/rfc1938.c +secureware.lo: $(authdir)/secureware.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/secureware.c +securid5.lo: $(authdir)/securid5.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ + $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ + $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/securid5.c +set_perms.lo: $(srcdir)/set_perms.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/set_perms.c +sia.lo: $(authdir)/sia.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/sia.c +sudo_auth.lo: $(authdir)/sudo_auth.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/insults.h \ + $(srcdir)/ins_2001.h $(srcdir)/ins_goons.h \ + $(srcdir)/ins_classic.h $(srcdir)/ins_csops.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(authdir)/sudo_auth.c +sudo_nss.lo: $(srcdir)/sudo_nss.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(incdir)/lbuf.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_nss.c +sudoers.lo: $(srcdir)/sudoers.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/getaddrinfo.h $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ + $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ + $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/interfaces.h \ + $(srcdir)/sudoers_version.h $(srcdir)/auth/sudo_auth.h \ + $(incdir)/secure_path.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudoers.c +sudoreplay.o: $(srcdir)/sudoreplay.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/timespec.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_conf.h $(incdir)/list.h \ + $(incdir)/sudo_debug.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudoreplay.c +testsudoers.o: $(srcdir)/testsudoers.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/fnmatch.h $(srcdir)/tsgetgrpw.h \ + $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(srcdir)/interfaces.h $(srcdir)/parse.h \ + $(incdir)/sudo_conf.h $(incdir)/list.h $(devdir)/gram.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/testsudoers.c +timestr.lo: $(srcdir)/timestr.c $(top_builddir)/config.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/timestr.c +toke.lo: $(devdir)/toke.c $(top_builddir)/config.h $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ + $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ + $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h $(srcdir)/parse.h $(srcdir)/toke.h \ + $(devdir)/gram.h $(incdir)/lbuf.h $(incdir)/secure_path.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(devdir)/toke.c +toke_util.lo: $(srcdir)/toke_util.c $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/alloc.h $(incdir)/list.h \ + $(incdir)/fileops.h $(srcdir)/defaults.h $(devdir)/def_data.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/parse.h \ + $(srcdir)/toke.h $(devdir)/gram.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/toke_util.c +toke_util.o: toke_util.lo +tsgetgrpw.o: $(srcdir)/tsgetgrpw.c $(top_builddir)/config.h \ + $(srcdir)/tsgetgrpw.h $(top_builddir)/config.h \ + $(srcdir)/sudoers.h $(top_srcdir)/compat/stdbool.h \ + $(top_builddir)/pathnames.h $(incdir)/missing.h $(incdir)/error.h \ + $(incdir)/alloc.h $(incdir)/list.h $(incdir)/fileops.h \ + $(srcdir)/defaults.h $(devdir)/def_data.h $(srcdir)/logging.h \ + $(srcdir)/sudo_nss.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/tsgetgrpw.c +visudo.o: $(srcdir)/visudo.c $(top_builddir)/config.h $(srcdir)/sudoers.h \ + $(top_srcdir)/compat/stdbool.h $(top_builddir)/pathnames.h \ + $(incdir)/missing.h $(incdir)/error.h $(incdir)/alloc.h \ + $(incdir)/list.h $(incdir)/fileops.h $(srcdir)/defaults.h \ + $(devdir)/def_data.h $(srcdir)/logging.h $(srcdir)/sudo_nss.h \ + $(incdir)/sudo_plugin.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/interfaces.h $(srcdir)/parse.h $(srcdir)/redblack.h \ + $(incdir)/gettext.h $(srcdir)/sudoers_version.h \ + $(incdir)/sudo_conf.h $(incdir)/list.h $(devdir)/gram.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/visudo.c diff --git a/plugins/sudoers/aixcrypt.exp b/plugins/sudoers/aixcrypt.exp new file mode 100644 index 0000000..5ee024e --- /dev/null +++ b/plugins/sudoers/aixcrypt.exp @@ -0,0 +1,4 @@ +#! +__setkey +__encrypt +__crypt diff --git a/plugins/sudoers/alias.c b/plugins/sudoers/alias.c new file mode 100644 index 0000000..eb95039 --- /dev/null +++ b/plugins/sudoers/alias.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2004-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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include "sudoers.h" +#include "parse.h" +#include "redblack.h" +#include + +/* + * Globals + */ +struct rbtree *aliases; +unsigned int alias_seqno; + +/* + * Comparison function for the red-black tree. + * Aliases are sorted by name with the type used as a tie-breaker. + */ +int +alias_compare(const void *v1, const void *v2) +{ + const struct alias *a1 = (const struct alias *)v1; + const struct alias *a2 = (const struct alias *)v2; + int res; + debug_decl(alias_compare, SUDO_DEBUG_ALIAS) + + if (v1 == NULL) + res = -1; + else if (v2 == NULL) + res = 1; + else if ((res = strcmp(a1->name, a2->name)) == 0) + res = a1->type - a2->type; + debug_return_int(res); +} + +/* + * Search the tree for an alias with the specified name and type. + * Returns a pointer to the alias structure or NULL if not found. + */ +struct alias * +alias_find(char *name, int type) +{ + struct alias key; + struct rbnode *node; + struct alias *a = NULL; + debug_decl(alias_find, SUDO_DEBUG_ALIAS) + + key.name = name; + key.type = type; + if ((node = rbfind(aliases, &key)) != NULL) { + /* + * Compare the global sequence number with the one stored + * in the alias. If they match then we've seen this alias + * before and found a loop. + */ + a = node->data; + if (a->seqno == alias_seqno) { + errno = ELOOP; + debug_return_ptr(NULL); + } + a->seqno = alias_seqno; + } else { + errno = ENOENT; + } + debug_return_ptr(a); +} + +/* + * Add an alias to the aliases redblack tree. + * Returns NULL on success and an error string on failure. + */ +char * +alias_add(char *name, int type, struct member *members) +{ + static char errbuf[512]; + struct alias *a; + debug_decl(alias_add, SUDO_DEBUG_ALIAS) + + a = ecalloc(1, sizeof(*a)); + a->name = name; + a->type = type; + /* a->seqno = 0; */ + list2tq(&a->members, members); + if (rbinsert(aliases, a)) { + snprintf(errbuf, sizeof(errbuf), _("Alias `%s' already defined"), name); + alias_free(a); + debug_return_str(errbuf); + } + debug_return_str(NULL); +} + +/* + * Apply a function to each alias entry and pass in a cookie. + */ +void +alias_apply(int (*func)(void *, void *), void *cookie) +{ + debug_decl(alias_apply, SUDO_DEBUG_ALIAS) + + rbapply(aliases, func, cookie, inorder); + + debug_return; +} + +/* + * Returns true if there are no aliases, else false. + */ +bool +no_aliases(void) +{ + debug_decl(no_aliases, SUDO_DEBUG_ALIAS) + debug_return_bool(rbisempty(aliases)); +} + +/* + * Free memory used by an alias struct and its members. + */ +void +alias_free(void *v) +{ + struct alias *a = (struct alias *)v; + struct member *m; + struct sudo_command *c; + void *next; + debug_decl(alias_free, SUDO_DEBUG_ALIAS) + + efree(a->name); + for (m = a->members.first; m != NULL; m = next) { + next = m->next; + if (m->type == COMMAND) { + c = (struct sudo_command *) m->name; + efree(c->cmnd); + efree(c->args); + } + efree(m->name); + efree(m); + } + efree(a); + + debug_return; +} + +/* + * Find the named alias, remove it from the tree and return it. + */ +struct alias * +alias_remove(char *name, int type) +{ + struct rbnode *node; + struct alias key; + debug_decl(alias_remove, SUDO_DEBUG_ALIAS) + + key.name = name; + key.type = type; + if ((node = rbfind(aliases, &key)) == NULL) { + errno = ENOENT; + return NULL; + } + debug_return_ptr(rbdelete(aliases, node)); +} + +void +init_aliases(void) +{ + debug_decl(init_aliases, SUDO_DEBUG_ALIAS) + + if (aliases != NULL) + rbdestroy(aliases, alias_free); + aliases = rbcreate(alias_compare); + + debug_return; +} diff --git a/plugins/sudoers/audit.c b/plugins/sudoers/audit.c new file mode 100644 index 0000000..d2dcca3 --- /dev/null +++ b/plugins/sudoers/audit.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2009-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. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include + +#include "missing.h" +#include "logging.h" +#include "sudo_debug.h" + +#ifdef HAVE_BSM_AUDIT +# include "bsm_audit.h" +#endif +#ifdef HAVE_LINUX_AUDIT +# include "linux_audit.h" +#endif + +void +audit_success(char *exec_args[]) +{ + debug_decl(audit_success, SUDO_DEBUG_AUDIT) + + if (exec_args != NULL) { +#ifdef HAVE_BSM_AUDIT + bsm_audit_success(exec_args); +#endif +#ifdef HAVE_LINUX_AUDIT + linux_audit_command(exec_args, 1); +#endif + } + + debug_return; +} + +void +audit_failure(char *exec_args[], char const *const fmt, ...) +{ + va_list ap; + debug_decl(audit_success, SUDO_DEBUG_AUDIT) + + if (exec_args != NULL) { + va_start(ap, fmt); +#ifdef HAVE_BSM_AUDIT + bsm_audit_failure(exec_args, fmt, ap); +#endif +#ifdef HAVE_LINUX_AUDIT + linux_audit_command(exec_args, 0); +#endif + va_end(ap); + } + + debug_return; +} diff --git a/plugins/sudoers/auth/API b/plugins/sudoers/auth/API new file mode 100644 index 0000000..62c21d0 --- /dev/null +++ b/plugins/sudoers/auth/API @@ -0,0 +1,121 @@ +NOTE: the Sudo auth API is subject to change + +Purpose: to provide a simple API for authentication methods that + encapsulates things nicely without turning into a maze + of #ifdef's + +The sudo_auth struct looks like this: + +typedef struct sudo_auth { + int flags; /* various flags, see below */ + int status; /* status from verify routine */ + char *name; /* name of the method in string form */ + void *data; /* method-specific data pointer */ + + int (*init)(struct passwd *pw, sudo_auth *auth); + int (*setup)(struct passwd *pw, char **prompt, sudo_auth *auth); + int (*verify)(struct passwd *pw, char *p, sudo_auth *auth); + int (*cleanup)(struct passwd *pw, sudo_auth *auth); + int (*begin_session)(struct passwd *pw, sudo_auth *auth); + int (*end_session)(sudo_auth *auth); +} sudo_auth; + +The variables in the struct are as follows: + flags Bitwise binary flags, see below. + + status Contains the return value from the last run of + the "verify" function. Starts out as AUTH_FAILURE. + + name The name of the authentication method as a C string. + + data A pointer to method-specific data. This is passed to + all the functions of an auth method and is usually + initialized in the "init" or "setup" routines. + +Possible values of sudo_auth.flags: + FLAG_USER Whether or not the auth functions should run with + the euid of the invoking user instead of 0. + + FLAG_DISABLED Set if an "init" or "setup" function fails. + + FLAG_STANDALONE If set, this indicates that the method must + be the only auth method configured, and that + it will prompt for the password itself. + + FLAG_ONEANDONLY If set, this indicates that the method is the + only one in use. Can be used by auth functions + to determine whether to return a fatal or nonfatal + error. + +The member functions can return the following values: + AUTH_SUCCESS Function succeeded. For a ``verify'' function + this means the user correctly authenticated. + + AUTH_FAILURE Function failed. If this is an ``init'' or + ``setup'' routine, the auth method will be + marked as !configured. + + AUTH_FATAL A fatal error occurred. The routine should have + written an error message to stderr and optionally + sent mail to the administrator. (If log_error() + is called to do this, the NO_EXIT flag must be used.) + When verify_user() gets AUTH_FATAL from an auth + function it does an exit(1). + +The functions in the struct are as follows: + + int init(struct passwd *pw, sudo_auth *auth) + Function to do any one-time initialization for the auth + method. All of the "init" functions are run before anything + else. + + int setup(struct passwd *pw, char **prompt, sudo_auth *auth) + Function to do method-specific setup. All the "setup" + routines are run before any of the "verify" routines. A + pointer to the prompt string may be used to add method-specific + info to the prompt. + + int verify(struct passwd *pw, char *p, sudo_auth *auth) + Function to do user verification for this auth method. For + standalone auth methods ``p'' is the prompt string. For + normal auth methods, ``p'' is the password the user entered. + Note that standalone auth methods are responsible for + rerading the password themselves. + + int cleanup(struct passwd *pw, sudo_auth *auth) + Function to do per-auth method cleanup. This is only run + at the end of the authentication process, after the user + has completely failed or succeeded to authenticate. + The ``auth->status'' variable contains the result of the + last authentication attempt which may be interesting. + +A note about standalone methods. Some authentication methods can't +coexist with any others. This may be because they encapsulate other +methods (pam, sia) or because they have a special way of interacting +with the user (securid). + +Adding a new authentication method: + +Each method should live in its own file. Add prototypes for the functions +in sudo_auth.h. + +Add the method to the ``auth_switch'' in sudo_auth.c. Note that +standalone methods must go first. If ``fooauth'' is a normal auth +method, its entry would look like: + +#ifdef HAVE_FOOAUTH +AUTH_ENTRY("foo", 0, foo_init, foo_setup, foo_verify, + foo_cleanup, foo_begin_session, foo_end_session) +#endif + +If this is a standalone method, it would be: + +#ifdef HAVE_FOOAUTH +AUTH_ENTRY("foo", FLAG_STANDALONE, foo_init, foo_setup, foo_verify, + foo_cleanup, foo_begin_session, foo_end_session) +#endif + +If the method needs to run as the user, not root, add FLAG_USER to +the second argument in the AUTH_ENTRY line. If you don't have an +init/setup/cleanup/begin/end routine, just use a NULL for that +field. diff --git a/plugins/sudoers/auth/afs.c b/plugins/sudoers/auth/afs.c new file mode 100644 index 0000000..f9693d0 --- /dev/null +++ b/plugins/sudoers/auth/afs.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1999, 2001-2005, 2007, 2010-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. + * + * 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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +int +sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + struct ktc_encryptionKey afs_key; + struct ktc_token afs_token; + debug_decl(sudo_afs_verify, SUDO_DEBUG_AUTH) + + /* Try to just check the password */ + ka_StringToKey(pass, NULL, &afs_key); + if (ka_GetAdminToken(pw->pw_name, /* name */ + NULL, /* instance */ + NULL, /* realm */ + &afs_key, /* key (contains password) */ + 0, /* lifetime */ + &afs_token, /* token */ + 0) == 0) /* new */ + debug_return_int(AUTH_SUCCESS); + + /* Fall back on old method XXX - needed? */ + setpag(); + if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION+KA_USERAUTH_DOSETPAG, + pw->pw_name, /* name */ + NULL, /* instance */ + NULL, /* realm */ + pass, /* password */ + 0, /* lifetime */ + NULL, /* expiration ptr (unused) */ + 0, /* spare */ + NULL) == 0) /* reason */ + debug_return_int(AUTH_SUCCESS); + + debug_return_int(AUTH_FAILURE); +} diff --git a/plugins/sudoers/auth/aix_auth.c b/plugins/sudoers/auth/aix_auth.c new file mode 100644 index 0000000..7aa5e27 --- /dev/null +++ b/plugins/sudoers/auth/aix_auth.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1999-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. + * + * 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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +/* + * For a description of the AIX authentication API, see + * http://publib16.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf1/authenticate.htm + */ +int +sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth) +{ + char *pass, *message = NULL; + int result = 1, reenter = 0; + int rval = AUTH_SUCCESS; + debug_decl(sudo_aix_verify, SUDO_DEBUG_AUTH) + + do { + pass = auth_getpass(prompt, def_passwd_timeout * 60, + SUDO_CONV_PROMPT_ECHO_OFF); + if (pass == NULL) + break; + efree(message); + message = NULL; + result = authenticate(pw->pw_name, pass, &reenter, &message); + zero_bytes(pass, strlen(pass)); + prompt = message; + } while (reenter); + + if (result != 0) { + /* Display error message, if any. */ + if (message != NULL) { + struct sudo_conv_message msg; + struct sudo_conv_reply repl; + + memset(&msg, 0, sizeof(msg)); + msg.msg_type = SUDO_CONV_ERROR_MSG; + msg.msg = message; + memset(&repl, 0, sizeof(repl)); + sudo_conv(1, &msg, &repl); + } + rval = pass ? AUTH_FAILURE : AUTH_INTR; + } + efree(message); + debug_return_int(rval); +} + +int +sudo_aix_cleanup(struct passwd *pw, sudo_auth *auth) +{ + debug_decl(sudo_aix_cleanup, SUDO_DEBUG_AUTH) + + /* Unset AUTHSTATE as it may not be correct for the runas user. */ + sudo_unsetenv("AUTHSTATE"); + + debug_return_int(AUTH_SUCCESS); +} diff --git a/plugins/sudoers/auth/bsdauth.c b/plugins/sudoers/auth/bsdauth.c new file mode 100644 index 0000000..3597e56 --- /dev/null +++ b/plugins/sudoers/auth/bsdauth.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2000-2005, 2007-2008, 2010-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. + * + * 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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include + +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +# ifndef LOGIN_DEFROOTCLASS +# define LOGIN_DEFROOTCLASS "daemon" +# endif + +extern char *login_style; /* from sudoers.c */ + +struct bsdauth_state { + auth_session_t *as; + login_cap_t *lc; +}; + +int +bsdauth_init(struct passwd *pw, sudo_auth *auth) +{ + static struct bsdauth_state state; + debug_decl(bsdauth_init, SUDO_DEBUG_AUTH) + + /* Get login class based on auth user, which may not be invoking user. */ + if (pw->pw_class && *pw->pw_class) + state.lc = login_getclass(pw->pw_class); + else + state.lc = login_getclass(pw->pw_uid ? LOGIN_DEFCLASS : LOGIN_DEFROOTCLASS); + if (state.lc == NULL) { + log_error(USE_ERRNO|NO_MAIL, + _("unable to get login class for user %s"), pw->pw_name); + debug_return_int(AUTH_FATAL); + } + + if ((state.as = auth_open()) == NULL) { + log_error(USE_ERRNO|NO_MAIL, + _("unable to begin bsd authentication")); + login_close(state.lc); + debug_return_int(AUTH_FATAL); + } + + /* XXX - maybe sanity check the auth style earlier? */ + login_style = login_getstyle(state.lc, login_style, "auth-sudo"); + if (login_style == NULL) { + log_error(NO_MAIL, _("invalid authentication type")); + auth_close(state.as); + login_close(state.lc); + debug_return_int(AUTH_FATAL); + } + + if (auth_setitem(state.as, AUTHV_STYLE, login_style) < 0 || + auth_setitem(state.as, AUTHV_NAME, pw->pw_name) < 0 || + auth_setitem(state.as, AUTHV_CLASS, login_class) < 0) { + log_error(NO_MAIL, _("unable to setup authentication")); + auth_close(state.as); + login_close(state.lc); + debug_return_int(AUTH_FATAL); + } + + auth->data = (void *) &state; + debug_return_int(AUTH_SUCCESS); +} + +int +bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth) +{ + char *pass; + char *s; + size_t len; + int authok = 0; + sigaction_t sa, osa; + auth_session_t *as = ((struct bsdauth_state *) auth->data)->as; + debug_decl(bsdauth_verify, SUDO_DEBUG_AUTH) + + /* save old signal handler */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_DFL; + (void) sigaction(SIGCHLD, &sa, &osa); + + /* + * If there is a challenge then print that instead of the normal + * prompt. If the user just hits return we prompt again with echo + * turned on, which is useful for challenge/response things like + * S/Key. + */ + if ((s = auth_challenge(as)) == NULL) { + pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); + } else { + pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); + if (pass && *pass == '\0') { + if ((prompt = strrchr(s, '\n'))) + prompt++; + else + prompt = s; + + /* + * Append '[echo on]' to the last line of the challenge and + * reprompt with echo turned on. + */ + len = strlen(prompt) - 1; + while (isspace(prompt[len]) || prompt[len] == ':') + prompt[len--] = '\0'; + easprintf(&s, "%s [echo on]: ", prompt); + pass = auth_getpass(prompt, def_passwd_timeout * 60, + SUDO_CONV_PROMPT_ECHO_ON); + free(s); + } + } + + if (pass) { + authok = auth_userresponse(as, pass, 1); + zero_bytes(pass, strlen(pass)); + } + + /* restore old signal handler */ + (void) sigaction(SIGCHLD, &osa, NULL); + + if (authok) + debug_return_int(AUTH_SUCCESS); + + if (!pass) + debug_return_int(AUTH_INTR); + + if ((s = auth_getvalue(as, "errormsg")) != NULL) + log_error(NO_MAIL, "%s", s); + debug_return_int(AUTH_FAILURE); +} + +int +bsdauth_cleanup(struct passwd *pw, sudo_auth *auth) +{ + struct bsdauth_state *state = auth->data; + debug_decl(bsdauth_cleanup, SUDO_DEBUG_AUTH) + + if (state != NULL) { + auth_close(state->as); + login_close(state->lc); + } + + debug_return_int(AUTH_SUCCESS); +} diff --git a/plugins/sudoers/auth/dce.c b/plugins/sudoers/auth/dce.c new file mode 100644 index 0000000..467c08f --- /dev/null +++ b/plugins/sudoers/auth/dce.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 1996, 1998-2005, 2010-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. + */ +/* + * The code below basically comes from the examples supplied on + * the OSF DCE 1.0.3 manpages for the sec_login routines, with + * enough additional polishing to make the routine work with the + * rest of sudo. + * + * This code is known to work on HP 700 and 800 series systems + * running HP-UX 9.X and 10.X, with either HP's version 1.2.1 of DCE. + * (aka, OSF DCE 1.0.3) or with HP's version 1.4 of DCE (aka, OSF + * DCE 1.1). + */ + +#include + +#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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include +#include +#include /* required to call dce_error_inq_text routine */ + +#include "sudoers.h" +#include "sudo_auth.h" + +static int check_dce_status(error_status_t, char *); + +int +sudo_dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth) +{ + struct passwd temp_pw; + sec_passwd_rec_t password_rec; + sec_login_handle_t login_context; + boolean32 reset_passwd; + sec_login_auth_src_t auth_src; + error_status_t status; + debug_decl(sudo_dce_verify, SUDO_DEBUG_AUTH) + + /* + * Create the local context of the DCE principal necessary + * to perform authenticated network operations. The network + * identity set up by this operation cannot be used until it + * is validated via sec_login_validate_identity(). + */ + if (sec_login_setup_identity((unsigned_char_p_t) pw->pw_name, + sec_login_no_flags, &login_context, &status)) { + + if (check_dce_status(status, "sec_login_setup_identity(1):")) + debug_return_int(AUTH_FAILURE); + + password_rec.key.key_type = sec_passwd_plain; + password_rec.key.tagged_union.plain = (idl_char *) plain_pw; + password_rec.pepper = NULL; + password_rec.version_number = sec_passwd_c_version_none; + + /* Validate the login context with the password */ + if (sec_login_validate_identity(login_context, &password_rec, + &reset_passwd, &auth_src, &status)) { + + if (check_dce_status(status, "sec_login_validate_identity(1):")) + debug_return_int(AUTH_FAILURE); + + /* + * Certify that the DCE Security Server used to set + * up and validate a login context is legitimate. Makes + * sure that we didn't get spoofed by another DCE server. + */ + if (!sec_login_certify_identity(login_context, &status)) { + (void) fprintf(stderr, "Whoa! Bogus authentication server!\n"); + (void) check_dce_status(status,"sec_login_certify_identity(1):"); + debug_return_int(AUTH_FAILURE); + } + if (check_dce_status(status, "sec_login_certify_identity(2):")) + debug_return_int(AUTH_FAILURE); + + /* + * Sets the network credentials to those specified + * by the now validated login context. + */ + sec_login_set_context(login_context, &status); + if (check_dce_status(status, "sec_login_set_context:")) + debug_return_int(AUTH_FAILURE); + + /* + * Oops, your credentials were no good. Possibly + * caused by clock times out of adjustment between + * DCE client and DCE security server... + */ + if (auth_src != sec_login_auth_src_network) { + (void) fprintf(stderr, + "You have no network credentials.\n"); + debug_return_int(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"); + debug_return_int(AUTH_FAILURE); + } + + /* + * We should be a valid user by this point. Pull the + * user's password structure from the DCE security + * server just to make sure. If we get it with no + * problems, then we really are legitimate... + */ + sec_login_get_pwent(login_context, (sec_login_passwd_t) &temp_pw, + &status); + if (check_dce_status(status, "sec_login_get_pwent:")) + debug_return_int(AUTH_FAILURE); + + /* + * If we get to here, then the pwent above properly fetched + * the password structure from the DCE registry, so the user + * must be valid. We don't really care what the user's + * registry password is, just that the user could be + * validated. In fact, if we tried to compare the local + * password to the DCE entry at this point, the operation + * would fail if the hidden password feature is turned on, + * because the password field would contain an asterisk. + * Also go ahead and destroy the user's DCE login context + * before we leave here (and don't bother checking the + * status), in order to clean up credentials files in + * /opt/dcelocal/var/security/creds. By doing this, we are + * assuming that the user will not need DCE authentication + * later in the program, only local authentication. If this + * is not true, then the login_context will have to be + * returned to the calling program, and the context purged + * somewhere later in the program. + */ + sec_login_purge_context(&login_context, &status); + debug_return_int(AUTH_SUCCESS); + } else { + if(check_dce_status(status, "sec_login_validate_identity(2):")) + debug_return_int(AUTH_FAILURE); + sec_login_purge_context(&login_context, &status); + if(check_dce_status(status, "sec_login_purge_context:")) + debug_return_int(AUTH_FAILURE); + } + } + (void) check_dce_status(status, "sec_login_setup_identity(2):"); + debug_return_int(AUTH_FAILURE); +} + +/* Returns 0 for DCE "ok" status, 1 otherwise */ +static int +check_dce_status(error_status_t input_status, char *comment) +{ + int error_stat; + unsigned char error_string[dce_c_error_string_len]; + debug_decl(check_dce_status, SUDO_DEBUG_AUTH) + + if (input_status == rpc_s_ok) + debug_return_bool(0); + dce_error_inq_text(input_status, error_string, &error_stat); + (void) fprintf(stderr, "%s %s\n", comment, error_string); + debug_return_bool(1); +} diff --git a/plugins/sudoers/auth/fwtk.c b/plugins/sudoers/auth/fwtk.c new file mode 100644 index 0000000..4855623 --- /dev/null +++ b/plugins/sudoers/auth/fwtk.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1999-2005, 2008, 2010-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. + * + * 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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +int +sudo_fwtk_init(struct passwd *pw, sudo_auth *auth) +{ + static Cfg *confp; /* Configuration entry struct */ + char resp[128]; /* Response from the server */ + debug_decl(sudo_fwtk_init, SUDO_DEBUG_AUTH) + + if ((confp = cfg_read("sudo")) == (Cfg *)-1) { + warningx(_("unable to read fwtk config")); + debug_return_int(AUTH_FATAL); + } + + if (auth_open(confp)) { + warningx(_("unable to connect to authentication server")); + debug_return_int(AUTH_FATAL); + } + + /* Get welcome message from auth server */ + if (auth_recv(resp, sizeof(resp))) { + warningx(_("lost connection to authentication server")); + debug_return_int(AUTH_FATAL); + } + if (strncmp(resp, "Authsrv ready", 13) != 0) { + warningx(_("authentication server error:\n%s"), resp); + debug_return_int(AUTH_FATAL); + } + + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth) +{ + char *pass; /* Password from the user */ + char buf[SUDO_PASS_MAX + 12]; /* General prupose buffer */ + char resp[128]; /* Response from the server */ + int error; + debug_decl(sudo_fwtk_verify, SUDO_DEBUG_AUTH) + + /* Send username to authentication server. */ + (void) snprintf(buf, sizeof(buf), "authorize %s 'sudo'", pw->pw_name); +restart: + if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { + warningx(_("lost connection to authentication server")); + debug_return_int(AUTH_FATAL); + } + + /* Get the password/response from the user. */ + if (strncmp(resp, "challenge ", 10) == 0) { + (void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]); + pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); + if (pass && *pass == '\0') { + pass = auth_getpass("Response [echo on]: ", + def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON); + } + } else if (strncmp(resp, "chalnecho ", 10) == 0) { + pass = auth_getpass(&resp[10], def_passwd_timeout * 60, + SUDO_CONV_PROMPT_ECHO_OFF); + } else if (strncmp(resp, "password", 8) == 0) { + pass = auth_getpass(prompt, def_passwd_timeout * 60, + SUDO_CONV_PROMPT_ECHO_OFF); + } else if (strncmp(resp, "display ", 8) == 0) { + fprintf(stderr, "%s\n", &resp[8]); + strlcpy(buf, "response dummy", sizeof(buf)); + goto restart; + } else { + warningx("%s", resp); + debug_return_int(AUTH_FATAL); + } + if (!pass) { /* ^C or error */ + debug_return_int(AUTH_INTR); + } + + /* Send the user's response to the server */ + (void) snprintf(buf, sizeof(buf), "response '%s'", pass); + if (auth_send(buf) || auth_recv(resp, sizeof(resp))) { + warningx(_("lost connection to authentication server")); + error = AUTH_FATAL; + goto done; + } + + if (strncmp(resp, "ok", 2) == 0) { + error = AUTH_SUCCESS; + goto done; + } + + /* Main loop prints "Permission Denied" or insult. */ + if (strcmp(resp, "Permission Denied.") != 0) + warningx("%s", resp); + error = AUTH_FAILURE; +done: + zero_bytes(pass, strlen(pass)); + zero_bytes(buf, strlen(buf)); + debug_return_int(error); +} + +int +sudo_fwtk_cleanup(struct passwd *pw, sudo_auth *auth) +{ + debug_decl(sudo_fwtk_cleanup, SUDO_DEBUG_AUTH) + + auth_close(); + debug_return_int(AUTH_SUCCESS); +} diff --git a/plugins/sudoers/auth/kerb5.c b/plugins/sudoers/auth/kerb5.c new file mode 100644 index 0000000..ab47c19 --- /dev/null +++ b/plugins/sudoers/auth/kerb5.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 1999-2005, 2007-2008, 2010-2012 + * 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_STRING_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#ifdef HAVE_HEIMDAL +#include +#endif + +#include "sudoers.h" +#include "sudo_auth.h" + +#ifdef HAVE_HEIMDAL +# define extract_name(c, p) krb5_principal_get_comp_string(c, p, 1) +# define krb5_free_data_contents(c, d) krb5_data_free(d) +#else +# define extract_name(c, p) (krb5_princ_component(c, p, 1)->data) +#endif + +#ifndef HAVE_KRB5_VERIFY_USER +static int verify_krb_v5_tgt(krb5_context, krb5_creds *, char *); +#endif +static struct _sudo_krb5_data { + krb5_context sudo_context; + krb5_principal princ; + krb5_ccache ccache; +} sudo_krb5_data = { NULL, NULL, NULL }; +typedef struct _sudo_krb5_data *sudo_krb5_datap; + +#ifdef SUDO_KRB5_INSTANCE +static const char *sudo_krb5_instance = SUDO_KRB5_INSTANCE; +#else +static const char *sudo_krb5_instance = NULL; +#endif + +#ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC +static krb5_error_code +krb5_get_init_creds_opt_alloc(krb5_context context, + krb5_get_init_creds_opt **opts) +{ + *opts = emalloc(sizeof(krb5_get_init_creds_opt)); + krb5_get_init_creds_opt_init(*opts); + return 0; +} + +static void +krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opts) +{ + free(opts); +} +#endif + +int +sudo_krb5_setup(struct passwd *pw, char **promptp, sudo_auth *auth) +{ + static char *krb5_prompt; + debug_decl(sudo_krb5_init, SUDO_DEBUG_AUTH) + + if (krb5_prompt == NULL) { + krb5_context sudo_context; + krb5_principal princ; + char *pname; + krb5_error_code error; + + sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; + princ = ((sudo_krb5_datap) auth->data)->princ; + + /* + * Really, we need to tell the caller not to prompt for password. The + * API does not currently provide this unless the auth is standalone. + */ + if ((error = krb5_unparse_name(sudo_context, princ, &pname))) { + log_error(NO_MAIL, + _("%s: unable to unparse princ ('%s'): %s"), auth->name, + pw->pw_name, error_message(error)); + debug_return_int(AUTH_FAILURE); + } + + /* Only rewrite prompt if user didn't specify their own. */ + /*if (!strcmp(prompt, PASSPROMPT)) { */ + easprintf(&krb5_prompt, "Password for %s: ", pname); + /*}*/ + free(pname); + } + *promptp = krb5_prompt; + + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_krb5_init(struct passwd *pw, sudo_auth *auth) +{ + krb5_context sudo_context; + krb5_error_code error; + char cache_name[64], *pname = pw->pw_name; + debug_decl(sudo_krb5_init, SUDO_DEBUG_AUTH) + + auth->data = (void *) &sudo_krb5_data; /* Stash all our data here */ + + if (sudo_krb5_instance != NULL) { + easprintf(&pname, "%s%s%s", pw->pw_name, + sudo_krb5_instance[0] != '/' ? "/" : "", sudo_krb5_instance); + } + +#ifdef HAVE_KRB5_INIT_SECURE_CONTEXT + error = krb5_init_secure_context(&(sudo_krb5_data.sudo_context)); +#else + error = krb5_init_context(&(sudo_krb5_data.sudo_context)); +#endif + if (error) + goto done; + sudo_context = sudo_krb5_data.sudo_context; + + error = krb5_parse_name(sudo_context, pname, &(sudo_krb5_data.princ)); + if (error) { + log_error(NO_MAIL, + _("%s: unable to parse '%s': %s"), auth->name, pname, + error_message(error)); + goto done; + } + + (void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld", + (long) getpid()); + if ((error = krb5_cc_resolve(sudo_context, cache_name, + &(sudo_krb5_data.ccache)))) { + log_error(NO_MAIL, + _("%s: unable to resolve ccache: %s"), auth->name, + error_message(error)); + goto done; + } + +done: + if (sudo_krb5_instance != NULL) + efree(pname); + debug_return_int(error ? AUTH_FAILURE : AUTH_SUCCESS); +} + +#ifdef HAVE_KRB5_VERIFY_USER +int +sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + krb5_context sudo_context; + krb5_principal princ; + krb5_ccache ccache; + krb5_error_code error; + debug_decl(sudo_krb5_verify, SUDO_DEBUG_AUTH) + + sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; + princ = ((sudo_krb5_datap) auth->data)->princ; + ccache = ((sudo_krb5_datap) auth->data)->ccache; + + error = krb5_verify_user(sudo_context, princ, ccache, pass, 1, NULL); + debug_return_int(error ? AUTH_FAILURE : AUTH_SUCCESS); +} +#else +int +sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + krb5_context sudo_context; + krb5_principal princ; + krb5_creds credbuf, *creds = NULL; + krb5_ccache ccache; + krb5_error_code error; + krb5_get_init_creds_opt *opts = NULL; + debug_decl(sudo_krb5_verify, SUDO_DEBUG_AUTH) + + sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; + princ = ((sudo_krb5_datap) auth->data)->princ; + ccache = ((sudo_krb5_datap) auth->data)->ccache; + + /* Set default flags based on the local config file. */ + error = krb5_get_init_creds_opt_alloc(sudo_context, &opts); + if (error) { + log_error(NO_MAIL, + _("%s: unable to allocate options: %s"), auth->name, + error_message(error)); + goto done; + } +#ifdef HAVE_HEIMDAL + krb5_get_init_creds_opt_set_default_flags(sudo_context, NULL, + krb5_principal_get_realm(sudo_context, princ), opts); +#endif + + /* Note that we always obtain a new TGT to verify the user */ + if ((error = krb5_get_init_creds_password(sudo_context, &credbuf, princ, + pass, krb5_prompter_posix, + NULL, 0, NULL, opts))) { + /* Don't print error if just a bad password */ + if (error != KRB5KRB_AP_ERR_BAD_INTEGRITY) + log_error(NO_MAIL, + _("%s: unable to get credentials: %s"), auth->name, + error_message(error)); + goto done; + } + creds = &credbuf; + + /* Verify the TGT to prevent spoof attacks. */ + if ((error = verify_krb_v5_tgt(sudo_context, creds, auth->name))) + goto done; + + /* Store cred in cred cache. */ + if ((error = krb5_cc_initialize(sudo_context, ccache, princ))) { + log_error(NO_MAIL, + _("%s: unable to initialize ccache: %s"), auth->name, + error_message(error)); + } else if ((error = krb5_cc_store_cred(sudo_context, ccache, creds))) { + log_error(NO_MAIL, + _("%s: unable to store cred in ccache: %s"), auth->name, + error_message(error)); + } + +done: + if (opts) { +#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_TWO_ARGS + krb5_get_init_creds_opt_free(sudo_context, opts); +#else + krb5_get_init_creds_opt_free(opts); +#endif + } + if (creds) + krb5_free_cred_contents(sudo_context, creds); + debug_return_int(error ? AUTH_FAILURE : AUTH_SUCCESS); +} +#endif + +int +sudo_krb5_cleanup(struct passwd *pw, sudo_auth *auth) +{ + krb5_context sudo_context; + krb5_principal princ; + krb5_ccache ccache; + debug_decl(sudo_krb5_cleanup, SUDO_DEBUG_AUTH) + + sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context; + princ = ((sudo_krb5_datap) auth->data)->princ; + ccache = ((sudo_krb5_datap) auth->data)->ccache; + + if (sudo_context) { + if (ccache) + krb5_cc_destroy(sudo_context, ccache); + if (princ) + krb5_free_principal(sudo_context, princ); + krb5_free_context(sudo_context); + } + + debug_return_int(AUTH_SUCCESS); +} + +#ifndef HAVE_KRB5_VERIFY_USER +/* + * Verify the Kerberos ticket-granting ticket just retrieved for the + * user. If the Kerberos server doesn't respond, assume the user is + * trying to fake us out (since we DID just get a TGT from what is + * supposedly our KDC). + * + * Returns 0 for successful authentication, non-zero for failure. + */ +static int +verify_krb_v5_tgt(krb5_context sudo_context, krb5_creds *cred, char *auth_name) +{ + krb5_error_code error; + krb5_principal server; + krb5_verify_init_creds_opt vopt; + debug_decl(verify_krb_v5_tgt, SUDO_DEBUG_AUTH) + + /* + * Get the server principal for the local host. + * (Use defaults of "host" and canonicalized local name.) + */ + if ((error = krb5_sname_to_principal(sudo_context, NULL, NULL, + KRB5_NT_SRV_HST, &server))) { + log_error(NO_MAIL, + _("%s: unable to get host principal: %s"), auth_name, + error_message(error)); + debug_return_int(-1); + } + + /* Initialize verify opts and set secure mode */ + krb5_verify_init_creds_opt_init(&vopt); + krb5_verify_init_creds_opt_set_ap_req_nofail(&vopt, 1); + + /* verify the Kerberos ticket-granting ticket we just retrieved */ + error = krb5_verify_init_creds(sudo_context, cred, server, NULL, + NULL, &vopt); + krb5_free_principal(sudo_context, server); + if (error) + log_error(NO_MAIL, + _("%s: Cannot verify TGT! Possible attack!: %s"), + auth_name, error_message(error)); + debug_return_int(error); +} +#endif diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c new file mode 100644 index 0000000..0ede540 --- /dev/null +++ b/plugins/sudoers/auth/pam.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 1999-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. + * + * 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 */ +#include +#include + +#ifdef HAVE_PAM_PAM_APPL_H +# include +#else +# include +#endif + +#ifdef HAVE_LIBINTL_H +# if defined(__LINUX_PAM__) +# define PAM_TEXT_DOMAIN "Linux-PAM" +# elif defined(__sun__) +# define PAM_TEXT_DOMAIN "SUNW_OST_SYSOSPAM" +# endif +#endif + +#include "sudoers.h" +#include "sudo_auth.h" + +/* Only OpenPAM and Linux PAM use const qualifiers. */ +#if defined(_OPENPAM) || defined(OPENPAM_VERSION) || \ + defined(__LIBPAM_VERSION) || defined(__LINUX_PAM__) +# define PAM_CONST const +#else +# define PAM_CONST +#endif + +static int converse(int, PAM_CONST struct pam_message **, + struct pam_response **, void *); +static char *def_prompt = "Password:"; +static int getpass_error; + +#ifndef PAM_DATA_SILENT +#define PAM_DATA_SILENT 0 +#endif + +static pam_handle_t *pamh; + +int +sudo_pam_init(struct passwd *pw, sudo_auth *auth) +{ + static struct pam_conv pam_conv; + static int pam_status; + debug_decl(sudo_pam_init, SUDO_DEBUG_AUTH) + + /* Initial PAM setup */ + if (auth != NULL) + auth->data = (void *) &pam_status; + pam_conv.conv = converse; +#ifdef HAVE_PAM_LOGIN + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) + pam_status = pam_start("sudo-i", pw->pw_name, &pam_conv, &pamh); + else +#endif + pam_status = pam_start("sudo", pw->pw_name, &pam_conv, &pamh); + if (pam_status != PAM_SUCCESS) { + log_error(USE_ERRNO|NO_MAIL, _("unable to initialize PAM")); + debug_return_int(AUTH_FATAL); + } + + /* + * Set PAM_RUSER to the invoking user (the "from" user). + * We set PAM_RHOST to avoid a bug in Solaris 7 and below. + */ + (void) pam_set_item(pamh, PAM_RUSER, user_name); +#ifdef __sun__ + (void) pam_set_item(pamh, PAM_RHOST, user_host); +#endif + + /* + * Some versions of pam_lastlog have a bug that + * will cause a crash if PAM_TTY is not set so if + * there is no tty, set PAM_TTY to the empty string. + */ + if (user_ttypath == NULL) + (void) pam_set_item(pamh, PAM_TTY, ""); + else + (void) pam_set_item(pamh, PAM_TTY, user_ttypath); + + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth) +{ + const char *s; + int *pam_status = (int *) auth->data; + debug_decl(sudo_pam_verify, SUDO_DEBUG_AUTH) + + def_prompt = prompt; /* for converse */ + + /* PAM_SILENT prevents the authentication service from generating output. */ + *pam_status = pam_authenticate(pamh, PAM_SILENT); + switch (*pam_status) { + case PAM_SUCCESS: + *pam_status = pam_acct_mgmt(pamh, PAM_SILENT); + switch (*pam_status) { + case PAM_SUCCESS: + debug_return_int(AUTH_SUCCESS); + case PAM_AUTH_ERR: + log_error(NO_MAIL, _("account validation failure, " + "is your account locked?")); + debug_return_int(AUTH_FATAL); + case PAM_NEW_AUTHTOK_REQD: + log_error(NO_MAIL, _("Account or password is " + "expired, reset your password and try again")); + *pam_status = pam_chauthtok(pamh, + PAM_CHANGE_EXPIRED_AUTHTOK); + if (*pam_status == PAM_SUCCESS) + debug_return_int(AUTH_SUCCESS); + if ((s = pam_strerror(pamh, *pam_status))) + log_error(NO_MAIL, _("pam_chauthtok: %s"), s); + debug_return_int(AUTH_FAILURE); + case PAM_AUTHTOK_EXPIRED: + log_error(NO_MAIL, + _("Password expired, contact your system administrator")); + debug_return_int(AUTH_FATAL); + case PAM_ACCT_EXPIRED: + log_error(NO_MAIL, + _("Account expired or PAM config lacks an \"account\" " + "section for sudo, contact your system administrator")); + debug_return_int(AUTH_FATAL); + } + /* FALLTHROUGH */ + case PAM_AUTH_ERR: + case PAM_AUTHINFO_UNAVAIL: + if (getpass_error) { + /* error or ^C from tgetpass() */ + debug_return_int(AUTH_INTR); + } + /* FALLTHROUGH */ + case PAM_MAXTRIES: + case PAM_PERM_DENIED: + debug_return_int(AUTH_FAILURE); + default: + if ((s = pam_strerror(pamh, *pam_status))) + log_error(NO_MAIL, _("pam_authenticate: %s"), s); + debug_return_int(AUTH_FATAL); + } +} + +int +sudo_pam_cleanup(struct passwd *pw, sudo_auth *auth) +{ + int *pam_status = (int *) auth->data; + debug_decl(sudo_pam_cleanup, SUDO_DEBUG_AUTH) + + /* If successful, we can't close the session until pam_end_session() */ + if (*pam_status == AUTH_SUCCESS) + debug_return_int(AUTH_SUCCESS); + + *pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT); + pamh = NULL; + debug_return_int(*pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); +} + +int +sudo_pam_begin_session(struct passwd *pw, char **user_envp[], sudo_auth *auth) +{ + int status = PAM_SUCCESS; + debug_decl(sudo_pam_begin_session, SUDO_DEBUG_AUTH) + + /* + * If there is no valid user we cannot open a PAM session. + * This is not an error as sudo can run commands with arbitrary + * uids, it just means we are done from a session management standpoint. + */ + if (pw == NULL) { + if (pamh != NULL) { + (void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); + pamh = NULL; + } + goto done; + } + + /* + * Update PAM_USER to reference the user we are running the command + * as, as opposed to the user we authenticated as. + */ + (void) pam_set_item(pamh, PAM_USER, pw->pw_name); + + /* + * Set credentials (may include resource limits, device ownership, etc). + * We don't check the return value here because in Linux-PAM 0.75 + * it returns the last saved return code, not the return code + * for the setcred module. Because we haven't called pam_authenticate(), + * this is not set and so pam_setcred() returns PAM_PERM_DENIED. + * We can't call pam_acct_mgmt() with Linux-PAM for a similar reason. + */ + (void) pam_setcred(pamh, PAM_ESTABLISH_CRED); + +#ifdef HAVE_PAM_GETENVLIST + /* + * Update environment based on what is stored in pamh. + * If no authentication is done we will only have environment + * variables if pam_env is called via session. + */ + if (user_envp != NULL) { + char **pam_envp = pam_getenvlist(pamh); + if (pam_envp != NULL) { + /* Merge pam env with user env but do not overwrite. */ + env_init(*user_envp); + env_merge(pam_envp, false); + *user_envp = env_get(); + env_init(NULL); + efree(pam_envp); + /* XXX - we leak any duplicates that were in pam_envp */ + } + } +#endif /* HAVE_PAM_GETENVLIST */ + +#ifndef NO_PAM_SESSION + status = pam_open_session(pamh, 0); + if (status != PAM_SUCCESS) { + (void) pam_end(pamh, status | PAM_DATA_SILENT); + pamh = NULL; + } +#endif + +done: + debug_return_int(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); +} + +int +sudo_pam_end_session(struct passwd *pw, sudo_auth *auth) +{ + int status = PAM_SUCCESS; + debug_decl(sudo_pam_end_session, SUDO_DEBUG_AUTH) + + if (pamh != NULL) { + /* + * Update PAM_USER to reference the user we are running the command + * as, as opposed to the user we authenticated as. + * XXX - still needed now that session init is in parent? + */ + (void) pam_set_item(pamh, PAM_USER, pw->pw_name); +#ifndef NO_PAM_SESSION + (void) pam_close_session(pamh, PAM_SILENT); +#endif + (void) pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); + status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); + pamh = NULL; + } + + debug_return_int(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); +} + +/* + * ``Conversation function'' for PAM. + * XXX - does not handle PAM_BINARY_PROMPT + */ +static int +converse(int num_msg, PAM_CONST struct pam_message **msg, + struct pam_response **response, void *appdata_ptr) +{ + struct pam_response *pr; + PAM_CONST struct pam_message *pm; + const char *prompt; + char *pass; + int n, type, std_prompt; + int ret = PAM_AUTH_ERR; + debug_decl(converse, SUDO_DEBUG_AUTH) + + if ((*response = malloc(num_msg * sizeof(struct pam_response))) == NULL) + debug_return_int(PAM_SYSTEM_ERR); + zero_bytes(*response, num_msg * sizeof(struct pam_response)); + + for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { + type = SUDO_CONV_PROMPT_ECHO_OFF; + switch (pm->msg_style) { + case PAM_PROMPT_ECHO_ON: + type = SUDO_CONV_PROMPT_ECHO_ON; + /* FALLTHROUGH */ + case PAM_PROMPT_ECHO_OFF: + prompt = def_prompt; + + /* Error out if the last password read was interrupted. */ + if (getpass_error) + goto done; + + /* Is the sudo prompt standard? (If so, we'l just use PAM's) */ + std_prompt = strncmp(def_prompt, "Password:", 9) == 0 && + (def_prompt[9] == '\0' || + (def_prompt[9] == ' ' && def_prompt[10] == '\0')); + + /* Only override PAM prompt if it matches /^Password: ?/ */ +#if defined(PAM_TEXT_DOMAIN) && defined(HAVE_LIBINTL_H) + if (!def_passprompt_override && (std_prompt || + (strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password: ")) && + strcmp(pm->msg, dgettext(PAM_TEXT_DOMAIN, "Password:"))))) + prompt = pm->msg; +#else + if (!def_passprompt_override && (std_prompt || + strncmp(pm->msg, "Password:", 9) || (pm->msg[9] != '\0' + && (pm->msg[9] != ' ' || pm->msg[10] != '\0')))) + prompt = pm->msg; +#endif + /* Read the password unless interrupted. */ + pass = auth_getpass(prompt, def_passwd_timeout * 60, type); + if (pass == NULL) { + /* Error (or ^C) reading password, don't try again. */ + getpass_error = 1; +#if (defined(__darwin__) || defined(__APPLE__)) && !defined(OPENPAM_VERSION) + pass = ""; +#else + goto done; +#endif + } + pr->resp = estrdup(pass); + zero_bytes(pass, strlen(pass)); + break; + case PAM_TEXT_INFO: + if (pm->msg) + (void) puts(pm->msg); + break; + case PAM_ERROR_MSG: + if (pm->msg) { + (void) fputs(pm->msg, stderr); + (void) fputc('\n', stderr); + } + break; + default: + ret = PAM_CONV_ERR; + goto done; + } + } + ret = PAM_SUCCESS; + +done: + if (ret != PAM_SUCCESS) { + /* Zero and free allocated memory and return an error. */ + for (pr = *response, n = num_msg; n--; pr++) { + if (pr->resp != NULL) { + zero_bytes(pr->resp, strlen(pr->resp)); + free(pr->resp); + pr->resp = NULL; + } + } + zero_bytes(*response, num_msg * sizeof(struct pam_response)); + free(*response); + *response = NULL; + } + debug_return_int(ret); +} diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c new file mode 100644 index 0000000..1736f30 --- /dev/null +++ b/plugins/sudoers/auth/passwd.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1999-2005, 2010-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. + * + * 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 */ +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +#define DESLEN 13 +#define HAS_AGEINFO(p, l) (l == 18 && p[DESLEN] == ',') + +int +sudo_passwd_init(struct passwd *pw, sudo_auth *auth) +{ + debug_decl(sudo_passwd_init, SUDO_DEBUG_AUTH) + +#ifdef HAVE_SKEYACCESS + if (skeyaccess(pw, user_tty, NULL, NULL) == 0) + debug_return_int(AUTH_FAILURE); +#endif + sudo_setspent(); + auth->data = sudo_getepw(pw); + sudo_endspent(); + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + char sav, *epass; + char *pw_epasswd = auth->data; + size_t pw_len; + int error; + debug_decl(sudo_passwd_verify, SUDO_DEBUG_AUTH) + + pw_len = strlen(pw_epasswd); + +#ifdef HAVE_GETAUTHUID + /* Ultrix shadow passwords may use crypt16() */ + error = strcmp(pw_epasswd, (char *) crypt16(pass, pw_epasswd)); + if (!error) + debug_return_int(AUTH_SUCCESS); +#endif /* HAVE_GETAUTHUID */ + + /* + * Truncate to 8 chars if standard DES since not all crypt()'s do this. + * If this turns out not to be safe we will have to use OS #ifdef's (sigh). + */ + sav = pass[8]; + if (pw_len == DESLEN || HAS_AGEINFO(pw_epasswd, pw_len)) + pass[8] = '\0'; + + /* + * Normal UN*X password check. + * HP-UX may add aging info (separated by a ',') at the end so + * only compare the first DESLEN characters in that case. + */ + epass = (char *) crypt(pass, pw_epasswd); + pass[8] = sav; + if (HAS_AGEINFO(pw_epasswd, pw_len) && strlen(epass) == DESLEN) + error = strncmp(pw_epasswd, epass, DESLEN); + else + error = strcmp(pw_epasswd, epass); + + debug_return_int(error ? AUTH_FAILURE : AUTH_SUCCESS); +} + +int +sudo_passwd_cleanup(pw, auth) + struct passwd *pw; + sudo_auth *auth; +{ + char *pw_epasswd = auth->data; + debug_decl(sudo_passwd_cleanup, SUDO_DEBUG_AUTH) + + if (pw_epasswd != NULL) { + zero_bytes(pw_epasswd, strlen(pw_epasswd)); + efree(pw_epasswd); + } + debug_return_int(AUTH_SUCCESS); +} diff --git a/plugins/sudoers/auth/rfc1938.c b/plugins/sudoers/auth/rfc1938.c new file mode 100644 index 0000000..f4ed7c0 --- /dev/null +++ b/plugins/sudoers/auth/rfc1938.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 1994-1996, 1998-2005, 2010-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. + * + * 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 */ +#include + +#if defined(HAVE_SKEY) +# include +# define RFC1938 skey +# ifdef HAVE_RFC1938_SKEYCHALLENGE +# define rfc1938challenge(a,b,c,d) skeychallenge((a),(b),(c),(d)) +# else +# define rfc1938challenge(a,b,c,d) skeychallenge((a),(b),(c)) +# endif +# define rfc1938verify(a,b) skeyverify((a),(b)) +#elif defined(HAVE_OPIE) +# include +# define RFC1938 opie +# define rfc1938challenge(a,b,c,d) opiechallenge((a),(b),(c)) +# define rfc1938verify(a,b) opieverify((a),(b)) +#endif + +#include "sudoers.h" +#include "sudo_auth.h" + +int +sudo_rfc1938_setup(struct passwd *pw, char **promptp, sudo_auth *auth) +{ + char challenge[256]; + static char *orig_prompt = NULL, *new_prompt = NULL; + static int op_len, np_size; + static struct RFC1938 rfc1938; + debug_decl(sudo_rfc1938_setup, SUDO_DEBUG_AUTH) + + /* Stash a pointer to the rfc1938 struct if we have not initialized */ + if (!auth->data) + auth->data = &rfc1938; + + /* Save the original prompt */ + if (orig_prompt == NULL) { + orig_prompt = *promptp; + op_len = strlen(orig_prompt); + + /* Ignore trailing colon (we will add our own) */ + if (orig_prompt[op_len - 1] == ':') + op_len--; + else if (op_len >= 2 && orig_prompt[op_len - 1] == ' ' + && orig_prompt[op_len - 2] == ':') + op_len -= 2; + } + +#ifdef HAVE_SKEY + /* Close old stream */ + if (rfc1938.keyfile) + (void) fclose(rfc1938.keyfile); +#endif + + /* + * Look up the user and get the rfc1938 challenge. + * If the user is not in the OTP db, only post a fatal error if + * we are running alone (since they may just use a normal passwd). + */ + if (rfc1938challenge(&rfc1938, pw->pw_name, challenge, sizeof(challenge))) { + if (IS_ONEANDONLY(auth)) { + warningx(_("you do not exist in the %s database"), auth->name); + debug_return_int(AUTH_FATAL); + } else { + debug_return_int(AUTH_FAILURE); + } + } + + /* Get space for new prompt with embedded challenge */ + if (np_size < op_len + strlen(challenge) + 7) { + np_size = op_len + strlen(challenge) + 7; + new_prompt = (char *) erealloc(new_prompt, np_size); + } + + if (def_long_otp_prompt) + (void) snprintf(new_prompt, np_size, "%s\n%s", challenge, orig_prompt); + else + (void) snprintf(new_prompt, np_size, "%.*s [ %s ]:", op_len, + orig_prompt, challenge); + + *promptp = new_prompt; + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + debug_decl(sudo_rfc1938_verify, SUDO_DEBUG_AUTH) + + if (rfc1938verify((struct RFC1938 *) auth->data, pass) == 0) + debug_return_int(AUTH_SUCCESS); + else + debug_return_int(AUTH_FAILURE); +} diff --git a/plugins/sudoers/auth/secureware.c b/plugins/sudoers/auth/secureware.c new file mode 100644 index 0000000..776b5dd --- /dev/null +++ b/plugins/sudoers/auth/secureware.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 1998-2005, 2010-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. + * + * 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 */ +#include +#ifdef __hpux +# undef MAXINT +# include +#else +# include +#endif /* __hpux */ +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +int +sudo_secureware_init(struct passwd *pw, sudo_auth *auth) +{ +#ifdef __alpha + extern int crypt_type; + debug_decl(sudo_secureware_init, SUDO_DEBUG_AUTH) + + if (crypt_type == INT_MAX) + debug_return_int(AUTH_FAILURE); /* no shadow */ +#else + debug_decl(secureware_init, SUDO_DEBUG_AUTH) +#endif + sudo_setspent(); + auth->data = sudo_getepw(pw); + sudo_endspent(); + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + char *pw_epasswd = auth->data; + debug_decl(sudo_secureware_verify, SUDO_DEBUG_AUTH) +#ifdef __alpha + { + extern int crypt_type; + +# ifdef HAVE_DISPCRYPT + if (strcmp(pw_epasswd, dispcrypt(pass, pw_epasswd, crypt_type)) == 0) + debug_return_int(AUTH_SUCCESS); +# else + if (crypt_type == AUTH_CRYPT_BIGCRYPT) { + if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0) + debug_return_int(AUTH_SUCCESS); + } else if (crypt_type == AUTH_CRYPT_CRYPT16) { + if (strcmp(pw_epasswd, crypt(pass, pw_epasswd)) == 0) + debug_return_int(AUTH_SUCCESS); + } + } +# endif /* HAVE_DISPCRYPT */ +#elif defined(HAVE_BIGCRYPT) + if (strcmp(pw_epasswd, bigcrypt(pass, pw_epasswd)) == 0) + debug_return_int(AUTH_SUCCESS); +#endif /* __alpha */ + + debug_return_int(AUTH_FAILURE); +} + +int +sudo_secureware_cleanup(pw, auth) + struct passwd *pw; + sudo_auth *auth; +{ + char *pw_epasswd = auth->data; + debug_decl(sudo_secureware_cleanup, SUDO_DEBUG_AUTH) + + if (pw_epasswd != NULL) { + zero_bytes(pw_epasswd, strlen(pw_epasswd)); + efree(pw_epasswd); + } + debug_return_int(AUTH_SUCCESS); +} diff --git a/plugins/sudoers/auth/securid5.c b/plugins/sudoers/auth/securid5.c new file mode 100644 index 0000000..6fe7dcb --- /dev/null +++ b/plugins/sudoers/auth/securid5.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1999-2005, 2007, 2010-2011 + * Todd C. Miller + * Copyright (c) 2002 Michael Stroucken + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 */ +#include + +/* Needed for SecurID v5.0 Authentication on UNIX */ +#define UNIX 1 +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +/* + * securid_init - Initialises communications with ACE server + * Arguments in: + * pw - UNUSED + * auth - sudo authentication structure + * + * Results out: + * auth - auth->data contains pointer to new SecurID handle + * return code - Fatal if initialization unsuccessful, otherwise + * success. + */ +int +sudo_securid_init(struct passwd *pw, sudo_auth *auth) +{ + static SDI_HANDLE sd_dat; /* SecurID handle */ + debug_decl(sudo_securid_init, SUDO_DEBUG_AUTH) + + auth->data = (void *) &sd_dat; /* For method-specific data */ + + /* Start communications */ + if (AceInitialize() != SD_FALSE) + debug_return_int(AUTH_SUCCESS); + + warningx(_("failed to initialise the ACE API library")); + debug_return_int(AUTH_FATAL); +} + +/* + * securid_setup - Initialises a SecurID transaction and locks out other + * ACE servers + * + * Arguments in: + * pw - struct passwd for username + * promptp - UNUSED + * auth - sudo authentication structure for SecurID handle + * + * Results out: + * return code - Success if transaction started correctly, fatal + * otherwise + */ +int +sudo_securid_setup(struct passwd *pw, char **promptp, sudo_auth *auth) +{ + SDI_HANDLE *sd = (SDI_HANDLE *) auth->data; + int retval; + debug_decl(sudo_securid_setup, SUDO_DEBUG_AUTH) + + /* Re-initialize SecurID every time. */ + if (SD_Init(sd) != ACM_OK) { + warningx(_("unable to contact the SecurID server")); + debug_return_int(AUTH_FATAL); + } + + /* Lock new PIN code */ + retval = SD_Lock(*sd, pw->pw_name); + + switch (retval) { + case ACM_OK: + warningx(_("User ID locked for SecurID Authentication")); + debug_return_int(AUTH_SUCCESS); + + case ACE_UNDEFINED_USERNAME: + warningx(_("invalid username length for SecurID")); + debug_return_int(AUTH_FATAL); + + case ACE_ERR_INVALID_HANDLE: + warningx(_("invalid Authentication Handle for SecurID")); + debug_return_int(AUTH_FATAL); + + case ACM_ACCESS_DENIED: + warningx(_("SecurID communication failed")); + debug_return_int(AUTH_FATAL); + + default: + warningx(_("unknown SecurID error")); + debug_return_int(AUTH_FATAL); + } +} + +/* + * securid_verify - Authenticates user and handles ACE responses + * + * Arguments in: + * pw - struct passwd for username + * pass - UNUSED + * auth - sudo authentication structure for SecurID handle + * + * Results out: + * return code - Success on successful authentication, failure on + * incorrect authentication, fatal on errors + */ +int +sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth) +{ + SDI_HANDLE *sd = (SDI_HANDLE *) auth->data; + int rval; + debug_decl(sudo_securid_verify, SUDO_DEBUG_AUTH) + + pass = auth_getpass("Enter your PASSCODE: ", + def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); + + /* Have ACE verify password */ + switch (SD_Check(*sd, pass, pw->pw_name)) { + case ACM_OK: + rval = AUTH_SUCESS; + break; + + case ACE_UNDEFINED_PASSCODE: + warningx(_("invalid passcode length for SecurID")); + rval = AUTH_FATAL; + break; + + case ACE_UNDEFINED_USERNAME: + warningx(_("invalid username length for SecurID")); + rval = AUTH_FATAL; + break; + + case ACE_ERR_INVALID_HANDLE: + warningx(_("invalid Authentication Handle for SecurID")); + rval = AUTH_FATAL; + break; + + case ACM_ACCESS_DENIED: + rval = AUTH_FAILURE; + break; + + case ACM_NEXT_CODE_REQUIRED: + /* Sometimes (when current token close to expire?) + ACE challenges for the next token displayed + (entered without the PIN) */ + pass = auth_getpass("\ +!!! ATTENTION !!!\n\ +Wait for the token code to change, \n\ +then enter the new token code.\n", \ + def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF); + + if (SD_Next(*sd, pass) == ACM_OK) { + rval = AUTH_SUCCESS; + break; + } + + rval = AUTH_FAILURE; + break; + + case ACM_NEW_PIN_REQUIRED: + /* + * This user's SecurID has not been activated yet, + * or the pin has been reset + */ + /* XXX - Is setting up a new PIN within sudo's scope? */ + SD_Pin(*sd, ""); + fprintf(stderr, "Your SecurID access has not yet been set up.\n"); + fprintf(stderr, "Please set up a PIN before you try to authenticate.\n"); + rval = AUTH_FATAL; + break; + + default: + warningx(_("unknown SecurID error")); + rval = AUTH_FATAL; + break; + } + + /* Free resources */ + SD_Close(*sd); + + /* Return stored state to calling process */ + debug_return_int(rval); +} diff --git a/plugins/sudoers/auth/sia.c b/plugins/sudoers/auth/sia.c new file mode 100644 index 0000000..d9f685e --- /dev/null +++ b/plugins/sudoers/auth/sia.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 1999-2005, 2007, 2010-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. + * 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 */ +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" + +static int sudo_collect(int, int, uchar_t *, int, prompt_t *); + +static char *def_prompt; +static char **sudo_argv; +static int sudo_argc; + +/* + * Collection routine (callback) for limiting the timeouts in SIA + * prompts and (possibly) setting a custom prompt. + */ +static int +sudo_collect(int timeout, int rendition, uchar_t *title, int nprompts, + prompt_t *prompts) +{ + debug_decl(sudo_collect, SUDO_DEBUG_AUTH) + + switch (rendition) { + case SIAFORM: + case SIAONELINER: + if (timeout <= 0 || timeout > def_passwd_timeout * 60) + timeout = def_passwd_timeout * 60; + /* + * Substitute custom prompt if a) the sudo prompt is not "Password:" + * and b) the SIA prompt is "Password:" (so we know it is safe). + * This keeps us from overwriting things like S/Key challenges. + */ + if (strcmp((char *)prompts[0].prompt, "Password:") == 0 && + strcmp(def_prompt, "Password:") != 0) + prompts[0].prompt = (unsigned char *)def_prompt; + break; + default: + break; + } + + debug_return_int(sia_collect_trm(timeout, rendition, title, nprompts, prompts)); +} + +int +sudo_sia_setup(struct passwd *pw, char **promptp, sudo_auth *auth) +{ + SIAENTITY *siah = NULL; + int i; + extern int NewArgc; + extern char **NewArgv; + debug_decl(sudo_sia_setup, SUDO_DEBUG_AUTH) + + /* Rebuild argv for sia_ses_init() */ + sudo_argc = NewArgc + 1; + sudo_argv = emalloc2(sudo_argc + 1, sizeof(char *)); + sudo_argv[0] = "sudo"; + for (i = 0; i < NewArgc; i++) + sudo_argv[i + 1] = NewArgv[i]; + sudo_argv[sudo_argc] = NULL; + + if (sia_ses_init(&siah, sudo_argc, sudo_argv, NULL, pw->pw_name, user_ttypath, 1, NULL) != SIASUCCESS) { + + log_error(USE_ERRNO|NO_MAIL, + _("unable to initialize SIA session")); + debug_return_int(AUTH_FATAL); + } + + auth->data = (void *) siah; + debug_return_int(AUTH_SUCCESS); +} + +int +sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth) +{ + SIAENTITY *siah = (SIAENTITY *) auth->data; + debug_decl(sudo_sia_verify, SUDO_DEBUG_AUTH) + + def_prompt = prompt; /* for sudo_collect */ + + /* XXX - need a way to detect user hitting return or EOF at prompt */ + if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS) + debug_return_int(AUTH_SUCCESS); + else + debug_return_int(AUTH_FAILURE); +} + +int +sudo_sia_cleanup(struct passwd *pw, sudo_auth *auth) +{ + SIAENTITY *siah = (SIAENTITY *) auth->data; + debug_decl(sudo_sia_cleanup, SUDO_DEBUG_AUTH) + + (void) sia_ses_release(&siah); + efree(sudo_argv); + debug_return_int(AUTH_SUCCESS); +} diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c new file mode 100644 index 0000000..3216582 --- /dev/null +++ b/plugins/sudoers/auth/sudo_auth.c @@ -0,0 +1,380 @@ +/* + * Copyright (c) 1999-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. + */ + +#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 */ +#include +#include +#include + +#include "sudoers.h" +#include "sudo_auth.h" +#include "insults.h" + +static sudo_auth auth_switch[] = { +/* Standalone entries first */ +#ifdef HAVE_PAM + AUTH_ENTRY("pam", FLAG_STANDALONE, sudo_pam_init, NULL, sudo_pam_verify, sudo_pam_cleanup, sudo_pam_begin_session, sudo_pam_end_session) +#endif +#ifdef HAVE_SECURID + AUTH_ENTRY("SecurId", FLAG_STANDALONE, sudo_securid_init, sudo_securid_setup, sudo_securid_verify, NULL, NULL, NULL) +#endif +#ifdef HAVE_SIA_SES_INIT + AUTH_ENTRY("sia", FLAG_STANDALONE, NULL, sudo_sia_setup, sudo_sia_verify, sudo_sia_cleanup, NULL, NULL) +#endif +#ifdef HAVE_AIXAUTH + AUTH_ENTRY("aixauth", FLAG_STANDALONE, NULL, NULL, sudo_aix_verify, sudo_aix_cleanup, NULL, NULL) +#endif +#ifdef HAVE_FWTK + AUTH_ENTRY("fwtk", FLAG_STANDALONE, sudo_fwtk_init, NULL, sudo_fwtk_verify, sudo_fwtk_cleanup, NULL, NULL) +#endif +#ifdef HAVE_BSD_AUTH_H + AUTH_ENTRY("bsdauth", FLAG_STANDALONE, bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup, NULL, NULL) +#endif + +/* Non-standalone entries */ +#ifndef WITHOUT_PASSWD + AUTH_ENTRY("passwd", 0, sudo_passwd_init, NULL, sudo_passwd_verify, sudo_passwd_cleanup, NULL, NULL) +#endif +#if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD) + AUTH_ENTRY("secureware", 0, sudo_secureware_init, NULL, sudo_secureware_verify, sudo_secureware_cleanup, NULL, NULL) +#endif +#ifdef HAVE_AFS + AUTH_ENTRY("afs", 0, NULL, NULL, sudo_afs_verify, NULL, NULL, NULL) +#endif +#ifdef HAVE_DCE + AUTH_ENTRY("dce", 0, NULL, NULL, sudo_dce_verify, NULL, NULL, NULL) +#endif +#ifdef HAVE_KERB5 + AUTH_ENTRY("kerb5", 0, sudo_krb5_init, sudo_krb5_setup, sudo_krb5_verify, sudo_krb5_cleanup, NULL, NULL) +#endif +#ifdef HAVE_SKEY + AUTH_ENTRY("S/Key", 0, NULL, sudo_rfc1938_setup, sudo_rfc1938_verify, NULL, NULL, NULL) +#endif +#ifdef HAVE_OPIE + AUTH_ENTRY("OPIE", 0, NULL, sudo_rfc1938_setup, sudo_rfc1938_verify, NULL, NULL, NULL) +#endif + AUTH_ENTRY(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL) +}; + +static int standalone; + +extern char **NewArgv; /* XXX - for auditing */ + +static void pass_warn(void); + +int +sudo_auth_init(struct passwd *pw) +{ + sudo_auth *auth; + int status = AUTH_SUCCESS; + debug_decl(sudo_auth_init, SUDO_DEBUG_AUTH) + + if (auth_switch[0].name == NULL) + debug_return_int(true); + + /* Make sure we haven't mixed standalone and shared auth methods. */ + standalone = IS_STANDALONE(&auth_switch[0]); + if (standalone && auth_switch[1].name != NULL) { + audit_failure(NewArgv, "invalid authentication methods"); + log_fatal(0, _("Invalid authentication methods compiled into sudo! " + "You may mix standalone and non-standalone authentication.")); + debug_return_int(-1); + } + + /* Set FLAG_ONEANDONLY if there is only one auth method. */ + if (auth_switch[1].name == NULL) + SET(auth_switch[0].flags, FLAG_ONEANDONLY); + + /* Initialize auth methods and unconfigure the method if necessary. */ + for (auth = auth_switch; auth->name; auth++) { + if (auth->init && !IS_DISABLED(auth)) { + if (NEEDS_USER(auth)) + set_perms(PERM_USER); + + status = (auth->init)(pw, auth); + + if (NEEDS_USER(auth)) + restore_perms(); + + if (status == AUTH_FAILURE) + SET(auth->flags, FLAG_DISABLED); + else if (status == AUTH_FATAL) { + /* XXX log */ + audit_failure(NewArgv, "authentication failure"); + break; /* assume error msg already printed */ + } + } + } + debug_return_int(status == AUTH_FATAL ? -1 : true); +} + +int +sudo_auth_cleanup(struct passwd *pw) +{ + sudo_auth *auth; + int status = AUTH_SUCCESS; + debug_decl(sudo_auth_cleanup, SUDO_DEBUG_AUTH) + + /* Call cleanup routines. */ + for (auth = auth_switch; auth->name; auth++) { + if (auth->cleanup && !IS_DISABLED(auth)) { + if (NEEDS_USER(auth)) + set_perms(PERM_USER); + + status = (auth->cleanup)(pw, auth); + + if (NEEDS_USER(auth)) + restore_perms(); + + if (status == AUTH_FATAL) { + /* XXX log */ + audit_failure(NewArgv, "authentication failure"); + break; /* assume error msg already printed */ + } + } + } + debug_return_int(status == AUTH_FATAL ? -1 : true); +} + +int +verify_user(struct passwd *pw, char *prompt) +{ + int counter = def_passwd_tries + 1; + int success = AUTH_FAILURE; + int flags, status, rval; + char *p; + sudo_auth *auth; + sigaction_t sa, osa; + debug_decl(verify_user, SUDO_DEBUG_AUTH) + + /* Enable suspend during password entry. */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_DFL; + (void) sigaction(SIGTSTP, &sa, &osa); + + /* Make sure we have at least one auth method. */ + /* XXX - check FLAG_DISABLED too */ + if (auth_switch[0].name == NULL) { + audit_failure(NewArgv, "no authentication methods"); + log_fatal(0, + _("There are no authentication methods compiled into sudo! " + "If you want to turn off authentication, use the " + "--disable-authentication configure option.")); + debug_return_int(-1); + } + + while (--counter) { + /* Do any per-method setup and unconfigure the method if needed */ + for (auth = auth_switch; auth->name; auth++) { + if (auth->setup && !IS_DISABLED(auth)) { + if (NEEDS_USER(auth)) + set_perms(PERM_USER); + + status = (auth->setup)(pw, &prompt, auth); + + if (NEEDS_USER(auth)) + restore_perms(); + + if (status == AUTH_FAILURE) + SET(auth->flags, FLAG_DISABLED); + else if (status == AUTH_FATAL) { + /* XXX log */ + audit_failure(NewArgv, "authentication failure"); + debug_return_int(-1);/* assume error msg already printed */ + } + } + } + + /* Get the password unless the auth function will do it for us */ + if (standalone) { + p = prompt; + } else { + p = auth_getpass(prompt, def_passwd_timeout * 60, + SUDO_CONV_PROMPT_ECHO_OFF); + if (p == NULL) + break; + } + + /* Call authentication functions. */ + for (auth = auth_switch; auth->name; auth++) { + if (IS_DISABLED(auth)) + continue; + + if (NEEDS_USER(auth)) + set_perms(PERM_USER); + + success = auth->status = (auth->verify)(pw, p, auth); + + if (NEEDS_USER(auth)) + restore_perms(); + + if (auth->status != AUTH_FAILURE) + goto done; + } + if (!standalone) + zero_bytes(p, strlen(p)); + pass_warn(); + } + +done: + switch (success) { + case AUTH_SUCCESS: + (void) sigaction(SIGTSTP, &osa, NULL); + rval = true; + break; + case AUTH_INTR: + case AUTH_FAILURE: + if (counter != def_passwd_tries) { + if (def_mail_badpass || def_mail_always) + flags = 0; + else + flags = NO_MAIL; + log_fatal(flags, ngettext("%d incorrect password attempt", + "%d incorrect password attempts", + def_passwd_tries - counter), def_passwd_tries - counter); + } + audit_failure(NewArgv, "authentication failure"); + rval = false; + break; + case AUTH_FATAL: + default: + audit_failure(NewArgv, "authentication failure"); + rval = -1; + break; + } + + debug_return_int(rval); +} + +int +sudo_auth_begin_session(struct passwd *pw, char **user_env[]) +{ + sudo_auth *auth; + int status; + debug_decl(auth_begin_session, SUDO_DEBUG_AUTH) + + for (auth = auth_switch; auth->name; auth++) { + if (auth->begin_session && !IS_DISABLED(auth)) { + status = (auth->begin_session)(pw, user_env, auth); + if (status == AUTH_FATAL) { + /* XXX log */ + audit_failure(NewArgv, "authentication failure"); + debug_return_bool(-1); /* assume error msg already printed */ + } + } + } + debug_return_bool(true); +} + +int +sudo_auth_end_session(struct passwd *pw) +{ + sudo_auth *auth; + int status; + debug_decl(auth_end_session, SUDO_DEBUG_AUTH) + + for (auth = auth_switch; auth->name; auth++) { + if (auth->end_session && !IS_DISABLED(auth)) { + status = (auth->end_session)(pw, auth); + if (status == AUTH_FATAL) { + /* XXX log */ + debug_return_bool(-1); /* assume error msg already printed */ + } + } + } + debug_return_bool(true); +} + +static void +pass_warn(void) +{ + const char *warning = def_badpass_message; + debug_decl(pass_warn, SUDO_DEBUG_AUTH) + +#ifdef INSULT + if (def_insults) + warning = INSULT; +#endif + sudo_printf(SUDO_CONV_ERROR_MSG, "%s\n", warning); + + debug_return; +} + +char * +auth_getpass(const char *prompt, int timeout, int type) +{ + struct sudo_conv_message msg; + struct sudo_conv_reply repl; + debug_decl(auth_getpass, SUDO_DEBUG_AUTH) + + /* Mask user input if pwfeedback set and echo is off. */ + if (type == SUDO_CONV_PROMPT_ECHO_OFF && def_pwfeedback) + type = SUDO_CONV_PROMPT_MASK; + + /* If visiblepw set, do not error out if there is no tty. */ + if (def_visiblepw) + type |= SUDO_CONV_PROMPT_ECHO_OK; + + /* Call conversation function */ + memset(&msg, 0, sizeof(msg)); + msg.msg_type = type; + msg.timeout = def_passwd_timeout * 60; + msg.msg = prompt; + memset(&repl, 0, sizeof(repl)); + sudo_conv(1, &msg, &repl); + /* XXX - check for ENOTTY? */ + debug_return_str_masked(repl.reply); +} + +void +dump_auth_methods(void) +{ + sudo_auth *auth; + debug_decl(dump_auth_methods, SUDO_DEBUG_AUTH) + + sudo_printf(SUDO_CONV_INFO_MSG, _("Authentication methods:")); + for (auth = auth_switch; auth->name; auth++) + sudo_printf(SUDO_CONV_INFO_MSG, " '%s'", auth->name); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + + debug_return; +} diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h new file mode 100644 index 0000000..a783661 --- /dev/null +++ b/plugins/sudoers/auth/sudo_auth.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1999-2005, 2007-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. + */ + +#ifndef SUDO_AUTH_H +#define SUDO_AUTH_H + +/* Auth function return values. */ +#define AUTH_SUCCESS 0 +#define AUTH_FAILURE 1 +#define AUTH_INTR 2 +#define AUTH_FATAL 3 + +typedef struct sudo_auth { + int flags; /* various flags, see below */ + int status; /* status from verify routine */ + char *name; /* name of the method as a string */ + void *data; /* method-specific data pointer */ + int (*init)(struct passwd *pw, struct sudo_auth *auth); + int (*setup)(struct passwd *pw, char **prompt, struct sudo_auth *auth); + int (*verify)(struct passwd *pw, char *p, struct sudo_auth *auth); + int (*cleanup)(struct passwd *pw, struct sudo_auth *auth); + int (*begin_session)(struct passwd *pw, char **user_env[], struct sudo_auth *auth); + int (*end_session)(struct passwd *pw, struct sudo_auth *auth); +} sudo_auth; + +/* Values for sudo_auth.flags. */ +#define FLAG_USER 0x01 /* functions must run as the user, not root */ +#define FLAG_DISABLED 0x02 /* method disabled */ +#define FLAG_STANDALONE 0x04 /* standalone auth method */ +#define FLAG_ONEANDONLY 0x08 /* one and only auth method */ + +/* Shortcuts for using the flags above. */ +#define NEEDS_USER(x) ((x)->flags & FLAG_USER) +#define IS_DISABLED(x) ((x)->flags & FLAG_DISABLED) +#define IS_STANDALONE(x) ((x)->flags & FLAG_STANDALONE) +#define IS_ONEANDONLY(x) ((x)->flags & FLAG_ONEANDONLY) + +/* Like tgetpass() but uses conversation function */ +char *auth_getpass(const char *prompt, int timeout, int type); + +/* Pointer to conversation function to use with auth_getpass(). */ +extern sudo_conv_t sudo_conv; + +/* Prototypes for standalone methods */ +int bsdauth_init(struct passwd *pw, sudo_auth *auth); +int bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth); +int bsdauth_cleanup(struct passwd *pw, sudo_auth *auth); +int sudo_aix_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_aix_cleanup(struct passwd *pw, sudo_auth *auth); +int sudo_fwtk_init(struct passwd *pw, sudo_auth *auth); +int sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth); +int sudo_fwtk_cleanup(struct passwd *pw, sudo_auth *auth); +int sudo_pam_init(struct passwd *pw, sudo_auth *auth); +int sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth); +int sudo_pam_cleanup(struct passwd *pw, sudo_auth *auth); +int sudo_pam_begin_session(struct passwd *pw, char **user_env[], sudo_auth *auth); +int sudo_pam_end_session(struct passwd *pw, sudo_auth *auth); +int sudo_securid_init(struct passwd *pw, sudo_auth *auth); +int sudo_securid_setup(struct passwd *pw, char **prompt, sudo_auth *auth); +int sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_sia_setup(struct passwd *pw, char **prompt, sudo_auth *auth); +int sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth); +int sudo_sia_cleanup(struct passwd *pw, sudo_auth *auth); + +/* Prototypes for normal methods */ +int sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_dce_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_krb5_init(struct passwd *pw, sudo_auth *auth); +int sudo_krb5_setup(struct passwd *pw, char **prompt, sudo_auth *auth); +int sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_krb5_cleanup(struct passwd *pw, sudo_auth *auth); +int sudo_passwd_init(struct passwd *pw, sudo_auth *auth); +int sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_passwd_cleanup(struct passwd *pw, sudo_auth *auth); +int sudo_rfc1938_setup(struct passwd *pw, char **prompt, sudo_auth *auth); +int sudo_rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_secureware_init(struct passwd *pw, sudo_auth *auth); +int sudo_secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth); +int sudo_secureware_cleanup(struct passwd *pw, sudo_auth *auth); + +/* Fields: name, flags, init, setup, verify, cleanup, begin_sess, end_sess */ +#define AUTH_ENTRY(n, f, i, s, v, c, b, e) \ + { (f), AUTH_FAILURE, (n), NULL, (i), (s), (v), (c) , (b), (e) }, + +#endif /* SUDO_AUTH_H */ diff --git a/plugins/sudoers/boottime.c b/plugins/sudoers/boottime.c new file mode 100644 index 0000000..2c9c074 --- /dev/null +++ b/plugins/sudoers/boottime.c @@ -0,0 +1,154 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#include +#if TIME_WITH_SYS_TIME +# include +#endif +#ifndef __linux__ +# if defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME) +# include +# elif defined(HAVE_GETUTXID) +# include +# elif defined(HAVE_GETUTID) +# include +# endif +#endif /* !__linux__ */ + +#include "missing.h" +#include "sudo_debug.h" + +/* + * Fill in a struct timeval with the time the system booted. + * Returns 1 on success and 0 on failure. + */ + +#if defined(__linux__) +int +get_boottime(struct timeval *tv) +{ + char *line = NULL; + size_t linesize = 0; + ssize_t len; + FILE * fp; + debug_decl(get_boottime, SUDO_DEBUG_UTIL) + + /* read btime from /proc/stat */ + fp = fopen("/proc/stat", "r"); + if (fp != NULL) { + while ((len = getline(&line, &linesize, fp)) != -1) { + if (strncmp(line, "btime ", 6) == 0) { + tv->tv_sec = atoi(line + 6); + tv->tv_usec = 0; + debug_return_bool(1); + } + } + fclose(fp); + free(line); + } + + debug_return_bool(0); +} + +#elif defined(HAVE_SYSCTL) && defined(KERN_BOOTTIME) + +int +get_boottime(struct timeval *tv) +{ + size_t size; + int mib[2]; + debug_decl(get_boottime, SUDO_DEBUG_UTIL) + + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + size = sizeof(*tv); + if (sysctl(mib, 2, tv, &size, NULL, 0) != -1) + debug_return_bool(1); + + debug_return_bool(0); +} + +#elif defined(HAVE_GETUTXID) + +int +get_boottime(struct timeval *tv) +{ + struct utmpx *ut, key; + debug_decl(get_boottime, SUDO_DEBUG_UTIL) + + memset(&key, 0, sizeof(key)); + key.ut_type = BOOT_TIME; + setutxent(); + if ((ut = getutxid(&key)) != NULL) { + tv->tv_sec = ut->ut_tv.tv_sec; + tv->tv_usec = ut->ut_tv.tv_usec; + } + endutxent(); + debug_return_bool(ut != NULL); +} + +#elif defined(HAVE_GETUTID) + +int +get_boottime(struct timeval *tv) +{ + struct utmp *ut, key; + debug_decl(get_boottime, SUDO_DEBUG_UTIL) + + memset(&key, 0, sizeof(key)); + key.ut_type = BOOT_TIME; + setutent(); + if ((ut = getutid(&key)) != NULL) { + tv->tv_sec = ut->ut_time; + tv->tv_usec = 0; + } + endutent(); + debug_return_bool(ut != NULL); +} + +#else + +int +get_boottime(struct timeval *tv) +{ + debug_decl(get_boottime, SUDO_DEBUG_UTIL) + debug_return_bool(0); +} +#endif diff --git a/plugins/sudoers/bsm_audit.c b/plugins/sudoers/bsm_audit.c new file mode 100644 index 0000000..bec1cba --- /dev/null +++ b/plugins/sudoers/bsm_audit.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2009-2011 Todd C. Miller + * Copyright (c) 2009 Christian S.J. Peron + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "gettext.h" +#include "error.h" +#include "sudo_debug.h" +#include "bsm_audit.h" + +/* + * Solaris auditon() returns EINVAL if BSM audit not configured. + * OpenBSM returns ENOSYS for unimplemented options. + */ +#ifdef __sun +# define AUDIT_NOT_CONFIGURED EINVAL +#else +# define AUDIT_NOT_CONFIGURED ENOSYS +#endif + +static int +audit_sudo_selected(int sf) +{ + auditinfo_addr_t ainfo_addr; + struct au_mask *mask; + auditinfo_t ainfo; + int rc, sorf; + debug_decl(audit_sudo_selected, SUDO_DEBUG_AUDIT) + + if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) < 0) { + if (errno == ENOSYS) { + if (getaudit(&ainfo) < 0) + error(1, _("getaudit: failed")); + mask = &ainfo.ai_mask; + } else + error(1, _("getaudit: failed")); + } else + mask = &ainfo_addr.ai_mask; + sorf = (sf == 0) ? AU_PRS_SUCCESS : AU_PRS_FAILURE; + rc = au_preselect(AUE_sudo, mask, sorf, AU_PRS_REREAD); + debug_return_int(rc); +} + +void +bsm_audit_success(char **exec_args) +{ + auditinfo_addr_t ainfo_addr; + auditinfo_t ainfo; + token_t *tok; + au_id_t auid; + long au_cond; + int aufd; + pid_t pid; + debug_decl(bsm_audit_success, SUDO_DEBUG_AUDIT) + + pid = getpid(); + /* + * If we are not auditing, don't cut an audit record; just return. + */ + if (auditon(A_GETCOND, (caddr_t)&au_cond, sizeof(long)) < 0) { + if (errno == AUDIT_NOT_CONFIGURED) + return; + error(1, _("Could not determine audit condition")); + } + if (au_cond == AUC_NOAUDIT) + debug_return; + /* + * Check to see if the preselection masks are interested in seeing + * this event. + */ + if (!audit_sudo_selected(0)) + debug_return; + if (getauid(&auid) < 0) + error(1, _("getauid failed")); + if ((aufd = au_open()) == -1) + error(1, _("au_open: failed")); + if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { + tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(), + getuid(), pid, pid, &ainfo_addr.ai_termid); + } else if (errno == ENOSYS) { + /* + * NB: We should probably watch out for ERANGE here. + */ + if (getaudit(&ainfo) < 0) + error(1, _("getaudit: failed")); + tok = au_to_subject(auid, geteuid(), getegid(), getuid(), + getuid(), pid, pid, &ainfo.ai_termid); + } else + error(1, _("getaudit: failed")); + if (tok == NULL) + error(1, _("au_to_subject: failed")); + au_write(aufd, tok); + tok = au_to_exec_args(exec_args); + if (tok == NULL) + error(1, _("au_to_exec_args: failed")); + au_write(aufd, tok); + tok = au_to_return32(0, 0); + if (tok == NULL) + error(1, _("au_to_return32: failed")); + au_write(aufd, tok); + if (au_close(aufd, 1, AUE_sudo) == -1) + error(1, _("unable to commit audit record")); + debug_return; +} + +void +bsm_audit_failure(char **exec_args, char const *const fmt, va_list ap) +{ + auditinfo_addr_t ainfo_addr; + auditinfo_t ainfo; + char text[256]; + token_t *tok; + long au_cond; + au_id_t auid; + pid_t pid; + int aufd; + debug_decl(bsm_audit_success, SUDO_DEBUG_AUDIT) + + pid = getpid(); + /* + * If we are not auditing, don't cut an audit record; just return. + */ + if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) { + if (errno == AUDIT_NOT_CONFIGURED) + debug_return; + error(1, _("Could not determine audit condition")); + } + if (au_cond == AUC_NOAUDIT) + debug_return; + if (!audit_sudo_selected(1)) + debug_return; + if (getauid(&auid) < 0) + error(1, _("getauid: failed")); + if ((aufd = au_open()) == -1) + error(1, _("au_open: failed")); + if (getaudit_addr(&ainfo_addr, sizeof(ainfo_addr)) == 0) { + tok = au_to_subject_ex(auid, geteuid(), getegid(), getuid(), + getuid(), pid, pid, &ainfo_addr.ai_termid); + } else if (errno == ENOSYS) { + if (getaudit(&ainfo) < 0) + error(1, _("getaudit: failed")); + tok = au_to_subject(auid, geteuid(), getegid(), getuid(), + getuid(), pid, pid, &ainfo.ai_termid); + } else + error(1, _("getaudit: failed")); + if (tok == NULL) + error(1, _("au_to_subject: failed")); + au_write(aufd, tok); + tok = au_to_exec_args(exec_args); + if (tok == NULL) + error(1, _("au_to_exec_args: failed")); + au_write(aufd, tok); + (void) vsnprintf(text, sizeof(text), fmt, ap); + tok = au_to_text(text); + if (tok == NULL) + error(1, _("au_to_text: failed")); + au_write(aufd, tok); + tok = au_to_return32(EPERM, 1); + if (tok == NULL) + error(1, _("au_to_return32: failed")); + au_write(aufd, tok); + if (au_close(aufd, 1, AUE_sudo) == -1) + error(1, _("unable to commit audit record")); + debug_return; +} diff --git a/plugins/sudoers/bsm_audit.h b/plugins/sudoers/bsm_audit.h new file mode 100644 index 0000000..bd29764 --- /dev/null +++ b/plugins/sudoers/bsm_audit.h @@ -0,0 +1,24 @@ +/* + * 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 + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SUDO_BSM_AUDIT_H +#define _SUDO_BSM_AUDIT_H + +void bsm_audit_success(char **); +void bsm_audit_failure(char **, char const * const, va_list); + +#endif /* _SUDO_BSM_AUDIT_H */ diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c new file mode 100644 index 0000000..d66445c --- /dev/null +++ b/plugins/sudoers/check.c @@ -0,0 +1,768 @@ +/* + * Copyright (c) 1993-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. + * + * 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 +#include +#ifdef __linux__ +# include +#endif +#if defined(__sun) && defined(__SVR4) +# include +#endif +#ifndef __TANDEM +# include +#endif +#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 TIME_WITH_SYS_TIME +# include +#endif +#include +#include +#include +#include +#include + +#include "sudoers.h" + +/* Status codes for timestamp_status() */ +#define TS_CURRENT 0 +#define TS_OLD 1 +#define TS_MISSING 2 +#define TS_NOFILE 3 +#define TS_ERROR 4 + +/* Flags for timestamp_status() */ +#define TS_MAKE_DIRS 1 +#define TS_REMOVE 2 + +/* + * Info stored in tty ticket from stat(2) to help with tty matching. + */ +static struct tty_info { + dev_t dev; /* ID of device tty resides on */ + dev_t rdev; /* tty device ID */ + ino_t ino; /* tty inode number */ + struct timeval ctime; /* tty inode change time */ +} tty_info; + +static int build_timestamp(char **, char **); +static int timestamp_status(char *, char *, char *, int); +static char *expand_prompt(char *, char *, char *); +static void lecture(int); +static void update_timestamp(char *, char *); +static bool tty_is_devpts(const char *); +static struct passwd *get_authpw(void); + +/* + * Returns true if the user successfully authenticates, else false. + */ +int +check_user(int validated, int mode) +{ + struct passwd *auth_pw; + char *timestampdir = NULL; + char *timestampfile = NULL; + char *prompt; + struct stat sb; + int status, rval = true; + bool need_pass = def_authenticate; + debug_decl(check_user, SUDO_DEBUG_AUTH) + + /* + * Init authentication system regardless of whether we need a password. + * Required for proper PAM session support. + */ + auth_pw = get_authpw(); + if (sudo_auth_init(auth_pw) == -1) { + rval = -1; + goto done; + } + + if (need_pass) { + /* Always need a password when -k was specified with the command. */ + if (ISSET(mode, MODE_IGNORE_TICKET)) { + SET(validated, FLAG_CHECK_USER); + } else { + /* + * Don't prompt for the root passwd or if the user is exempt. + * If the user is not changing uid/gid, no need for a password. + */ + if (user_uid == 0 || (user_uid == runas_pw->pw_uid && + (!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) + || user_is_exempt()) + need_pass = false; + } + } + if (!need_pass) + goto done; + + /* Stash the tty's ctime for tty ticket comparison. */ + if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) { + tty_info.dev = sb.st_dev; + tty_info.ino = sb.st_ino; + tty_info.rdev = sb.st_rdev; + if (tty_is_devpts(user_ttypath)) + ctim_get(&sb, &tty_info.ctime); + } + + if (build_timestamp(×tampdir, ×tampfile) == -1) { + rval = -1; + goto done; + } + + status = timestamp_status(timestampdir, timestampfile, user_name, + TS_MAKE_DIRS); + + if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) { + /* Bail out if we are non-interactive and a password is required */ + if (ISSET(mode, MODE_NONINTERACTIVE)) { + warningx(_("sorry, a password is required to run %s"), getprogname()); + rval = -1; + goto done; + } + + /* XXX - should not lecture if askpass helper is being used. */ + lecture(status); + + /* Expand any escapes in the prompt. */ + prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, + user_name, user_shost); + + rval = verify_user(auth_pw, prompt); + } + /* Only update timestamp if user was validated. */ + if (rval == true && ISSET(validated, VALIDATE_OK) && + !ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR) + update_timestamp(timestampdir, timestampfile); + efree(timestampdir); + efree(timestampfile); + +done: + sudo_auth_cleanup(auth_pw); + pw_delref(auth_pw); + + debug_return_bool(rval); +} + +#define DEFAULT_LECTURE "\n" \ + "We trust you have received the usual lecture from the local System\n" \ + "Administrator. It usually boils down to these three things:\n\n" \ + " #1) Respect the privacy of others.\n" \ + " #2) Think before you type.\n" \ + " #3) With great power comes great responsibility.\n\n" + +/* + * Standard sudo lecture. + */ +static void +lecture(int status) +{ + FILE *fp; + char buf[BUFSIZ]; + ssize_t nread; + struct sudo_conv_message msg; + struct sudo_conv_reply repl; + debug_decl(lecture, SUDO_DEBUG_AUTH) + + if (def_lecture == never || + (def_lecture == once && status != TS_MISSING && status != TS_ERROR)) + debug_return; + + memset(&msg, 0, sizeof(msg)); + memset(&repl, 0, sizeof(repl)); + + if (def_lecture_file && (fp = fopen(def_lecture_file, "r")) != NULL) { + while ((nread = fread(buf, sizeof(char), sizeof(buf) - 1, fp)) != 0) { + buf[nread] = '\0'; + msg.msg_type = SUDO_CONV_ERROR_MSG; + msg.msg = buf; + sudo_conv(1, &msg, &repl); + } + fclose(fp); + } else { + msg.msg_type = SUDO_CONV_ERROR_MSG; + msg.msg = _(DEFAULT_LECTURE); + sudo_conv(1, &msg, &repl); + } + debug_return; +} + +/* + * Update the time on the timestamp file/dir or create it if necessary. + */ +static void +update_timestamp(char *timestampdir, char *timestampfile) +{ + debug_decl(update_timestamp, SUDO_DEBUG_AUTH) + + /* If using tty timestamps but we have no tty there is nothing to do. */ + if (def_tty_tickets && !user_ttypath) + debug_return; + + if (timestamp_uid != 0) + set_perms(PERM_TIMESTAMP); + if (timestampfile) { + /* + * Store tty info in timestamp file + */ + int fd = open(timestampfile, O_WRONLY|O_CREAT, 0600); + if (fd == -1) + log_error(USE_ERRNO, _("unable to open %s"), timestampfile); + else { + lock_file(fd, SUDO_LOCK); + if (write(fd, &tty_info, sizeof(tty_info)) != sizeof(tty_info)) { + log_error(USE_ERRNO, _("unable to write to %s"), + timestampfile); + } + close(fd); + } + } else { + if (touch(-1, timestampdir, NULL) == -1) { + if (mkdir(timestampdir, 0700) == -1) { + log_error(USE_ERRNO, _("unable to mkdir %s"), + timestampdir); + } + } + } + if (timestamp_uid != 0) + restore_perms(); + debug_return; +} + +/* + * Expand %h and %u escapes in the prompt and pass back the dynamically + * allocated result. Returns the same string if there are no escapes. + */ +static char * +expand_prompt(char *old_prompt, char *user, char *host) +{ + size_t len, n; + int subst; + char *p, *np, *new_prompt, *endp; + debug_decl(expand_prompt, SUDO_DEBUG_AUTH) + + /* How much space do we need to malloc for the prompt? */ + subst = 0; + for (p = old_prompt, len = strlen(old_prompt); *p; p++) { + if (p[0] =='%') { + switch (p[1]) { + case 'h': + p++; + len += strlen(user_shost) - 2; + subst = 1; + break; + case 'H': + p++; + len += strlen(user_host) - 2; + subst = 1; + break; + case 'p': + p++; + if (def_rootpw) + len += 2; + else if (def_targetpw || def_runaspw) + len += strlen(runas_pw->pw_name) - 2; + else + len += strlen(user_name) - 2; + subst = 1; + break; + case 'u': + p++; + len += strlen(user_name) - 2; + subst = 1; + break; + case 'U': + p++; + len += strlen(runas_pw->pw_name) - 2; + subst = 1; + break; + case '%': + p++; + len--; + subst = 1; + break; + default: + break; + } + } + } + + if (subst) { + new_prompt = emalloc(++len); + endp = new_prompt + len; + for (p = old_prompt, np = new_prompt; *p; p++) { + if (p[0] =='%') { + switch (p[1]) { + case 'h': + p++; + n = strlcpy(np, user_shost, np - endp); + if (n >= np - endp) + goto oflow; + np += n; + continue; + case 'H': + p++; + n = strlcpy(np, user_host, np - endp); + if (n >= np - endp) + goto oflow; + np += n; + continue; + case 'p': + p++; + if (def_rootpw) + n = strlcpy(np, "root", np - endp); + else if (def_targetpw || def_runaspw) + n = strlcpy(np, runas_pw->pw_name, np - endp); + else + n = strlcpy(np, user_name, np - endp); + if (n >= np - endp) + goto oflow; + np += n; + continue; + case 'u': + p++; + n = strlcpy(np, user_name, np - endp); + if (n >= np - endp) + goto oflow; + np += n; + continue; + case 'U': + p++; + n = strlcpy(np, runas_pw->pw_name, np - endp); + if (n >= np - endp) + goto oflow; + np += n; + continue; + case '%': + /* convert %% -> % */ + p++; + break; + default: + /* no conversion */ + break; + } + } + *np++ = *p; + if (np >= endp) + goto oflow; + } + *np = '\0'; + } else + new_prompt = old_prompt; + + debug_return_str(new_prompt); + +oflow: + /* We pre-allocate enough space, so this should never happen. */ + errorx(1, _("internal error, expand_prompt() overflow")); +} + +/* + * Checks if the user is exempt from supplying a password. + */ +bool +user_is_exempt(void) +{ + bool rval = false; + debug_decl(user_is_exempt, SUDO_DEBUG_AUTH) + + if (def_exempt_group) + rval = user_in_group(sudo_user.pw, def_exempt_group); + debug_return_bool(rval); +} + +/* + * Fills in timestampdir as well as timestampfile if using tty tickets. + */ +static int +build_timestamp(char **timestampdir, char **timestampfile) +{ + char *dirparent; + int len; + debug_decl(build_timestamp, SUDO_DEBUG_AUTH) + + dirparent = def_timestampdir; + len = easprintf(timestampdir, "%s/%s", dirparent, user_name); + if (len >= PATH_MAX) + goto bad; + + /* + * Timestamp file may be a file in the directory or NUL to use + * the directory as the timestamp. + */ + if (def_tty_tickets) { + char *p; + + if ((p = strrchr(user_tty, '/'))) + p++; + else + p = user_tty; + if (def_targetpw) + len = easprintf(timestampfile, "%s/%s/%s:%s", dirparent, user_name, + p, runas_pw->pw_name); + else + len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, p); + if (len >= PATH_MAX) + goto bad; + } else if (def_targetpw) { + len = easprintf(timestampfile, "%s/%s/%s", dirparent, user_name, + runas_pw->pw_name); + if (len >= PATH_MAX) + goto bad; + } else + *timestampfile = NULL; + + debug_return_int(len); +bad: + log_fatal(0, _("timestamp path too long: %s"), *timestampfile); + debug_return_int(-1); +} + +/* + * Check the timestamp file and directory and return their status. + */ +static int +timestamp_status(char *timestampdir, char *timestampfile, char *user, int flags) +{ + struct stat sb; + struct timeval boottime, mtime; + time_t now; + char *dirparent = def_timestampdir; + int status = TS_ERROR; /* assume the worst */ + debug_decl(timestamp_status, SUDO_DEBUG_AUTH) + + if (timestamp_uid != 0) + set_perms(PERM_TIMESTAMP); + + /* + * Sanity check dirparent and make it if it doesn't already exist. + * We start out assuming the worst (that the dir is not sane) and + * if it is ok upgrade the status to ``no timestamp file''. + * Note that we don't check the parent(s) of dirparent for + * sanity since the sudo dir is often just located in /tmp. + */ + if (lstat(dirparent, &sb) == 0) { + if (!S_ISDIR(sb.st_mode)) + log_error(0, _("%s exists but is not a directory (0%o)"), + dirparent, (unsigned int) sb.st_mode); + else if (sb.st_uid != timestamp_uid) + log_error(0, _("%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(0, + _("%s writable by non-owner (0%o), should be mode 0700"), + dirparent, (unsigned int) sb.st_mode); + else { + if ((sb.st_mode & 0000777) != 0700) + (void) chmod(dirparent, 0700); + status = TS_MISSING; + } + } else if (errno != ENOENT) { + log_error(USE_ERRNO, _("unable to stat %s"), dirparent); + } else { + /* No dirparent, try to make one. */ + if (ISSET(flags, TS_MAKE_DIRS)) { + if (mkdir(dirparent, S_IRWXU)) + log_error(USE_ERRNO, _("unable to mkdir %s"), + dirparent); + else + status = TS_MISSING; + } + } + if (status == TS_ERROR) + goto done; + + /* + * Sanity check the user's ticket dir. We start by downgrading + * the status to TS_ERROR. If the ticket dir exists and is sane + * this will be upgraded to TS_OLD. If the dir does not exist, + * it will be upgraded to TS_MISSING. + */ + status = TS_ERROR; /* downgrade status again */ + if (lstat(timestampdir, &sb) == 0) { + if (!S_ISDIR(sb.st_mode)) { + if (S_ISREG(sb.st_mode)) { + /* convert from old style */ + if (unlink(timestampdir) == 0) + status = TS_MISSING; + } else + log_error(0, _("%s exists but is not a directory (0%o)"), + timestampdir, (unsigned int) sb.st_mode); + } else if (sb.st_uid != timestamp_uid) + log_error(0, _("%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(0, + _("%s writable by non-owner (0%o), should be mode 0700"), + timestampdir, (unsigned int) sb.st_mode); + else { + if ((sb.st_mode & 0000777) != 0700) + (void) chmod(timestampdir, 0700); + status = TS_OLD; /* do date check later */ + } + } else if (errno != ENOENT) { + log_error(USE_ERRNO, _("unable to stat %s"), timestampdir); + } else + status = TS_MISSING; + + /* + * If there is no user ticket dir, AND we are in tty ticket mode, + * AND the TS_MAKE_DIRS flag is set, create the user ticket dir. + */ + if (status == TS_MISSING && timestampfile && ISSET(flags, TS_MAKE_DIRS)) { + if (mkdir(timestampdir, S_IRWXU) == -1) { + status = TS_ERROR; + log_error(USE_ERRNO, _("unable to mkdir %s"), timestampdir); + } + } + + /* + * Sanity check the tty ticket file if it exists. + */ + if (timestampfile && status != TS_ERROR) { + if (status != TS_MISSING) + status = TS_NOFILE; /* dir there, file missing */ + if (def_tty_tickets && !user_ttypath) + goto done; /* no tty, always prompt */ + if (lstat(timestampfile, &sb) == 0) { + if (!S_ISREG(sb.st_mode)) { + status = TS_ERROR; + log_error(0, _("%s exists but is not a regular file (0%o)"), + timestampfile, (unsigned int) sb.st_mode); + } else { + /* If bad uid or file mode, complain and kill the bogus file. */ + if (sb.st_uid != timestamp_uid) { + log_error(0, + _("%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(0, + _("%s writable by non-owner (0%o), should be mode 0600"), + timestampfile, (unsigned int) sb.st_mode); + (void) unlink(timestampfile); + } else { + /* If not mode 0600, fix it. */ + if ((sb.st_mode & 0000777) != 0600) + (void) chmod(timestampfile, 0600); + + /* + * Check for stored tty info. If the file is zero-sized + * it is an old-style timestamp with no tty info in it. + * If removing, we don't care about the contents. + * The actual mtime check is done later. + */ + if (ISSET(flags, TS_REMOVE)) { + status = TS_OLD; + } else if (sb.st_size != 0) { + struct tty_info info; + int fd = open(timestampfile, O_RDONLY, 0644); + if (fd != -1) { + if (read(fd, &info, sizeof(info)) == sizeof(info) && + memcmp(&info, &tty_info, sizeof(info)) == 0) { + status = TS_OLD; + } + close(fd); + } + } + } + } + } else if (errno != ENOENT) { + log_error(USE_ERRNO, _("unable to stat %s"), timestampfile); + status = TS_ERROR; + } + } + + /* + * If the file/dir exists and we are not removing it, check its mtime. + */ + if (status == TS_OLD && !ISSET(flags, TS_REMOVE)) { + mtim_get(&sb, &mtime); + /* Negative timeouts only expire manually (sudo -k). */ + if (def_timestamp_timeout < 0 && mtime.tv_sec != 0) + status = TS_CURRENT; + else { + now = time(NULL); + if (def_timestamp_timeout && + now - mtime.tv_sec < 60 * def_timestamp_timeout) { + /* + * Check for bogus time on the stampfile. The clock may + * have been set back or someone could be trying to spoof us. + */ + if (mtime.tv_sec > now + 60 * def_timestamp_timeout * 2) { + time_t tv_sec = (time_t)mtime.tv_sec; + log_error(0, + _("timestamp too far in the future: %20.20s"), + 4 + ctime(&tv_sec)); + if (timestampfile) + (void) unlink(timestampfile); + else + (void) rmdir(timestampdir); + status = TS_MISSING; + } else if (get_boottime(&boottime) && timevalcmp(&mtime, &boottime, <)) { + status = TS_OLD; + } else { + status = TS_CURRENT; + } + } + } + } + +done: + if (timestamp_uid != 0) + restore_perms(); + debug_return_int(status); +} + +/* + * Remove the timestamp ticket file/dir. + */ +void +remove_timestamp(bool remove) +{ + struct timeval tv; + char *timestampdir, *timestampfile, *path; + int status; + debug_decl(remove_timestamp, SUDO_DEBUG_AUTH) + + if (build_timestamp(×tampdir, ×tampfile) == -1) + debug_return; + + status = timestamp_status(timestampdir, timestampfile, user_name, + TS_REMOVE); + if (status != TS_MISSING && status != TS_ERROR) { + path = timestampfile ? timestampfile : timestampdir; + if (remove) { + if (timestampfile) + status = unlink(timestampfile); + else + status = rmdir(timestampdir); + if (status == -1 && errno != ENOENT) { + log_error(0, + _("unable to remove %s (%s), will reset to the epoch"), + path, strerror(errno)); + remove = false; + } + } + if (!remove) { + timevalclear(&tv); + if (touch(-1, path, &tv) == -1 && errno != ENOENT) + error(1, _("unable to reset %s to the epoch"), path); + } + } + efree(timestampdir); + efree(timestampfile); + + debug_return; +} + +/* + * Returns true if tty lives on a devpts, /dev or /devices filesystem, else + * false. Unlike most filesystems, the ctime of devpts nodes is not updated + * when the device node is written to, only when the inode's status changes, + * typically via the chmod, chown, link, rename, or utimes system calls. + * Since the ctime is "stable" in this case, we can stash it the tty ticket + * file and use it to determine whether the tty ticket file is stale. + */ +static bool +tty_is_devpts(const char *tty) +{ + bool retval = false; +#ifdef __linux__ + struct statfs sfs; + debug_decl(tty_is_devpts, SUDO_DEBUG_PTY) + +#ifndef DEVPTS_SUPER_MAGIC +# define DEVPTS_SUPER_MAGIC 0x1cd1 +#endif + + if (statfs(tty, &sfs) == 0) { + if (sfs.f_type == DEVPTS_SUPER_MAGIC) + retval = true; + } +#elif defined(__sun) && defined(__SVR4) + struct statvfs sfs; + debug_decl(tty_is_devpts, SUDO_DEBUG_PTY) + + if (statvfs(tty, &sfs) == 0) { + if (strcmp(sfs.f_fstr, "dev") == 0 || strcmp(sfs.f_fstr, "devices") == 0) + retval = true; + } +#else + debug_decl(tty_is_devpts, SUDO_DEBUG_PTY) +#endif /* __linux__ */ + debug_return_bool(retval); +} + +/* + * Get passwd entry for the user we are going to authenticate as. + * By default, this is the user invoking sudo. In the most common + * case, this matches sudo_user.pw or runas_pw. + */ +static struct passwd * +get_authpw(void) +{ + struct passwd *pw; + debug_decl(get_authpw, SUDO_DEBUG_AUTH) + + if (def_rootpw) { + if ((pw = sudo_getpwuid(ROOT_UID)) == NULL) + log_fatal(0, _("unknown uid: %u"), ROOT_UID); + } else if (def_runaspw) { + if ((pw = sudo_getpwnam(def_runas_default)) == NULL) + log_fatal(0, _("unknown user: %s"), def_runas_default); + } else if (def_targetpw) { + if (runas_pw->pw_name == NULL) + log_fatal(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; + } + + debug_return_ptr(pw); +} diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c new file mode 100644 index 0000000..3119df8 --- /dev/null +++ b/plugins/sudoers/def_data.c @@ -0,0 +1,348 @@ +static struct def_values def_data_lecture[] = { + { "never", never }, + { "once", once }, + { "always", always }, + { NULL, 0 }, +}; + +static struct def_values def_data_listpw[] = { + { "never", never }, + { "any", any }, + { "all", all }, + { "always", always }, + { NULL, 0 }, +}; + +static struct def_values def_data_verifypw[] = { + { "never", never }, + { "all", all }, + { "any", any }, + { "always", always }, + { NULL, 0 }, +}; + +struct sudo_defs_types sudo_defs_table[] = { + { + "syslog", T_LOGFAC|T_BOOL, + N_("Syslog facility if syslog is being used for logging: %s"), + NULL, + }, { + "syslog_goodpri", T_LOGPRI, + N_("Syslog priority to use when user authenticates successfully: %s"), + NULL, + }, { + "syslog_badpri", T_LOGPRI, + N_("Syslog priority to use when user authenticates unsuccessfully: %s"), + NULL, + }, { + "long_otp_prompt", T_FLAG, + N_("Put OTP prompt on its own line"), + NULL, + }, { + "ignore_dot", T_FLAG, + N_("Ignore '.' in $PATH"), + NULL, + }, { + "mail_always", T_FLAG, + N_("Always send mail when sudo is run"), + NULL, + }, { + "mail_badpass", T_FLAG, + N_("Send mail if user authentication fails"), + NULL, + }, { + "mail_no_user", T_FLAG, + N_("Send mail if the user is not in sudoers"), + NULL, + }, { + "mail_no_host", T_FLAG, + N_("Send mail if the user is not in sudoers for this host"), + NULL, + }, { + "mail_no_perms", T_FLAG, + N_("Send mail if the user is not allowed to run a command"), + NULL, + }, { + "tty_tickets", T_FLAG, + N_("Use a separate timestamp for each user/tty combo"), + NULL, + }, { + "lecture", T_TUPLE|T_BOOL, + N_("Lecture user the first time they run sudo"), + def_data_lecture, + }, { + "lecture_file", T_STR|T_PATH|T_BOOL, + N_("File containing the sudo lecture: %s"), + NULL, + }, { + "authenticate", T_FLAG, + N_("Require users to authenticate by default"), + NULL, + }, { + "root_sudo", T_FLAG, + N_("Root may run sudo"), + NULL, + }, { + "log_host", T_FLAG, + N_("Log the hostname in the (non-syslog) log file"), + NULL, + }, { + "log_year", T_FLAG, + N_("Log the year in the (non-syslog) log file"), + NULL, + }, { + "shell_noargs", T_FLAG, + N_("If sudo is invoked with no arguments, start a shell"), + NULL, + }, { + "set_home", T_FLAG, + N_("Set $HOME to the target user when starting a shell with -s"), + NULL, + }, { + "always_set_home", T_FLAG, + N_("Always set $HOME to the target user's home directory"), + NULL, + }, { + "path_info", T_FLAG, + N_("Allow some information gathering to give useful error messages"), + NULL, + }, { + "fqdn", T_FLAG, + N_("Require fully-qualified hostnames in the sudoers file"), + NULL, + }, { + "insults", T_FLAG, + N_("Insult the user when they enter an incorrect password"), + NULL, + }, { + "requiretty", T_FLAG, + N_("Only allow the user to run sudo if they have a tty"), + NULL, + }, { + "env_editor", T_FLAG, + N_("Visudo will honor the EDITOR environment variable"), + NULL, + }, { + "rootpw", T_FLAG, + N_("Prompt for root's password, not the users's"), + NULL, + }, { + "runaspw", T_FLAG, + N_("Prompt for the runas_default user's password, not the users's"), + NULL, + }, { + "targetpw", T_FLAG, + N_("Prompt for the target user's password, not the users's"), + NULL, + }, { + "use_loginclass", T_FLAG, + N_("Apply defaults in the target user's login class if there is one"), + NULL, + }, { + "set_logname", T_FLAG, + N_("Set the LOGNAME and USER environment variables"), + NULL, + }, { + "stay_setuid", T_FLAG, + N_("Only set the effective uid to the target user, not the real uid"), + NULL, + }, { + "preserve_groups", T_FLAG, + N_("Don't initialize the group vector to that of the target user"), + NULL, + }, { + "loglinelen", T_UINT|T_BOOL, + N_("Length at which to wrap log file lines (0 for no wrap): %d"), + NULL, + }, { + "timestamp_timeout", T_FLOAT|T_BOOL, + N_("Authentication timestamp timeout: %.1f minutes"), + NULL, + }, { + "passwd_timeout", T_FLOAT|T_BOOL, + N_("Password prompt timeout: %.1f minutes"), + NULL, + }, { + "passwd_tries", T_UINT, + N_("Number of tries to enter a password: %d"), + NULL, + }, { + "umask", T_MODE|T_BOOL, + N_("Umask to use or 0777 to use user's: 0%o"), + NULL, + }, { + "logfile", T_STR|T_BOOL|T_PATH, + N_("Path to log file: %s"), + NULL, + }, { + "mailerpath", T_STR|T_BOOL|T_PATH, + N_("Path to mail program: %s"), + NULL, + }, { + "mailerflags", T_STR|T_BOOL, + N_("Flags for mail program: %s"), + NULL, + }, { + "mailto", T_STR|T_BOOL, + N_("Address to send mail to: %s"), + NULL, + }, { + "mailfrom", T_STR|T_BOOL, + N_("Address to send mail from: %s"), + NULL, + }, { + "mailsub", T_STR, + N_("Subject line for mail messages: %s"), + NULL, + }, { + "badpass_message", T_STR, + N_("Incorrect password message: %s"), + NULL, + }, { + "timestampdir", T_STR|T_PATH, + N_("Path to authentication timestamp dir: %s"), + NULL, + }, { + "timestampowner", T_STR, + N_("Owner of the authentication timestamp dir: %s"), + NULL, + }, { + "exempt_group", T_STR|T_BOOL, + N_("Users in this group are exempt from password and PATH requirements: %s"), + NULL, + }, { + "passprompt", T_STR, + N_("Default password prompt: %s"), + NULL, + }, { + "passprompt_override", T_FLAG, + N_("If set, passprompt will override system prompt in all cases."), + NULL, + }, { + "runas_default", T_STR, + N_("Default user to run commands as: %s"), + NULL, + }, { + "secure_path", T_STR|T_BOOL, + N_("Value to override user's $PATH with: %s"), + NULL, + }, { + "editor", T_STR|T_PATH, + N_("Path to the editor for use by visudo: %s"), + NULL, + }, { + "listpw", T_TUPLE|T_BOOL, + N_("When to require a password for 'list' pseudocommand: %s"), + def_data_listpw, + }, { + "verifypw", T_TUPLE|T_BOOL, + N_("When to require a password for 'verify' pseudocommand: %s"), + def_data_verifypw, + }, { + "noexec", T_FLAG, + N_("Preload the dummy exec functions contained in the sudo_noexec library"), + NULL, + }, { + "ignore_local_sudoers", T_FLAG, + N_("If LDAP directory is up, do we ignore local sudoers file"), + NULL, + }, { + "closefrom", T_INT, + N_("File descriptors >= %d will be closed before executing a command"), + NULL, + }, { + "closefrom_override", T_FLAG, + N_("If set, users may override the value of `closefrom' with the -C option"), + NULL, + }, { + "setenv", T_FLAG, + N_("Allow users to set arbitrary environment variables"), + NULL, + }, { + "env_reset", T_FLAG, + N_("Reset the environment to a default set of variables"), + NULL, + }, { + "env_check", T_LIST|T_BOOL, + N_("Environment variables to check for sanity:"), + NULL, + }, { + "env_delete", T_LIST|T_BOOL, + N_("Environment variables to remove:"), + NULL, + }, { + "env_keep", T_LIST|T_BOOL, + N_("Environment variables to preserve:"), + NULL, + }, { + "role", T_STR, + N_("SELinux role to use in the new security context: %s"), + NULL, + }, { + "type", T_STR, + N_("SELinux type to use in the new security context: %s"), + NULL, + }, { + "env_file", T_STR|T_PATH|T_BOOL, + N_("Path to the sudo-specific environment file: %s"), + NULL, + }, { + "sudoers_locale", T_STR, + N_("Locale to use while parsing sudoers: %s"), + NULL, + }, { + "visiblepw", T_FLAG, + N_("Allow sudo to prompt for a password even if it would be visible"), + NULL, + }, { + "pwfeedback", T_FLAG, + N_("Provide visual feedback at the password prompt when there is user input"), + NULL, + }, { + "fast_glob", T_FLAG, + N_("Use faster globbing that is less accurate but does not access the filesystem"), + NULL, + }, { + "umask_override", T_FLAG, + N_("The umask specified in sudoers will override the user's, even if it is more permissive"), + NULL, + }, { + "log_input", T_FLAG, + N_("Log user's input for the command being run"), + NULL, + }, { + "log_output", T_FLAG, + N_("Log the output of the command being run"), + NULL, + }, { + "compress_io", T_FLAG, + N_("Compress I/O logs using zlib"), + NULL, + }, { + "use_pty", T_FLAG, + N_("Always run commands in a pseudo-tty"), + NULL, + }, { + "group_plugin", T_STR, + N_("Plugin for non-Unix group support: %s"), + NULL, + }, { + "iolog_dir", T_STR|T_PATH, + N_("Directory in which to store input/output logs: %s"), + NULL, + }, { + "iolog_file", T_STR, + N_("File in which to store the input/output log: %s"), + NULL, + }, { + "set_utmp", T_FLAG, + N_("Add an entry to the utmp/utmpx file when allocating a pty"), + NULL, + }, { + "utmp_runas", T_FLAG, + N_("Set the user in utmp to the runas user, not the invoking user"), + NULL, + }, { + NULL, 0, NULL + } +}; diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h new file mode 100644 index 0000000..43c2b96 --- /dev/null +++ b/plugins/sudoers/def_data.h @@ -0,0 +1,168 @@ +#define def_syslog (sudo_defs_table[0].sd_un.ival) +#define I_SYSLOG 0 +#define def_syslog_goodpri (sudo_defs_table[1].sd_un.ival) +#define I_SYSLOG_GOODPRI 1 +#define def_syslog_badpri (sudo_defs_table[2].sd_un.ival) +#define I_SYSLOG_BADPRI 2 +#define def_long_otp_prompt (sudo_defs_table[3].sd_un.flag) +#define I_LONG_OTP_PROMPT 3 +#define def_ignore_dot (sudo_defs_table[4].sd_un.flag) +#define I_IGNORE_DOT 4 +#define def_mail_always (sudo_defs_table[5].sd_un.flag) +#define I_MAIL_ALWAYS 5 +#define def_mail_badpass (sudo_defs_table[6].sd_un.flag) +#define I_MAIL_BADPASS 6 +#define def_mail_no_user (sudo_defs_table[7].sd_un.flag) +#define I_MAIL_NO_USER 7 +#define def_mail_no_host (sudo_defs_table[8].sd_un.flag) +#define I_MAIL_NO_HOST 8 +#define def_mail_no_perms (sudo_defs_table[9].sd_un.flag) +#define I_MAIL_NO_PERMS 9 +#define def_tty_tickets (sudo_defs_table[10].sd_un.flag) +#define I_TTY_TICKETS 10 +#define def_lecture (sudo_defs_table[11].sd_un.tuple) +#define I_LECTURE 11 +#define def_lecture_file (sudo_defs_table[12].sd_un.str) +#define I_LECTURE_FILE 12 +#define def_authenticate (sudo_defs_table[13].sd_un.flag) +#define I_AUTHENTICATE 13 +#define def_root_sudo (sudo_defs_table[14].sd_un.flag) +#define I_ROOT_SUDO 14 +#define def_log_host (sudo_defs_table[15].sd_un.flag) +#define I_LOG_HOST 15 +#define def_log_year (sudo_defs_table[16].sd_un.flag) +#define I_LOG_YEAR 16 +#define def_shell_noargs (sudo_defs_table[17].sd_un.flag) +#define I_SHELL_NOARGS 17 +#define def_set_home (sudo_defs_table[18].sd_un.flag) +#define I_SET_HOME 18 +#define def_always_set_home (sudo_defs_table[19].sd_un.flag) +#define I_ALWAYS_SET_HOME 19 +#define def_path_info (sudo_defs_table[20].sd_un.flag) +#define I_PATH_INFO 20 +#define def_fqdn (sudo_defs_table[21].sd_un.flag) +#define I_FQDN 21 +#define def_insults (sudo_defs_table[22].sd_un.flag) +#define I_INSULTS 22 +#define def_requiretty (sudo_defs_table[23].sd_un.flag) +#define I_REQUIRETTY 23 +#define def_env_editor (sudo_defs_table[24].sd_un.flag) +#define I_ENV_EDITOR 24 +#define def_rootpw (sudo_defs_table[25].sd_un.flag) +#define I_ROOTPW 25 +#define def_runaspw (sudo_defs_table[26].sd_un.flag) +#define I_RUNASPW 26 +#define def_targetpw (sudo_defs_table[27].sd_un.flag) +#define I_TARGETPW 27 +#define def_use_loginclass (sudo_defs_table[28].sd_un.flag) +#define I_USE_LOGINCLASS 28 +#define def_set_logname (sudo_defs_table[29].sd_un.flag) +#define I_SET_LOGNAME 29 +#define def_stay_setuid (sudo_defs_table[30].sd_un.flag) +#define I_STAY_SETUID 30 +#define def_preserve_groups (sudo_defs_table[31].sd_un.flag) +#define I_PRESERVE_GROUPS 31 +#define def_loglinelen (sudo_defs_table[32].sd_un.ival) +#define I_LOGLINELEN 32 +#define def_timestamp_timeout (sudo_defs_table[33].sd_un.fval) +#define I_TIMESTAMP_TIMEOUT 33 +#define def_passwd_timeout (sudo_defs_table[34].sd_un.fval) +#define I_PASSWD_TIMEOUT 34 +#define def_passwd_tries (sudo_defs_table[35].sd_un.ival) +#define I_PASSWD_TRIES 35 +#define def_umask (sudo_defs_table[36].sd_un.mode) +#define I_UMASK 36 +#define def_logfile (sudo_defs_table[37].sd_un.str) +#define I_LOGFILE 37 +#define def_mailerpath (sudo_defs_table[38].sd_un.str) +#define I_MAILERPATH 38 +#define def_mailerflags (sudo_defs_table[39].sd_un.str) +#define I_MAILERFLAGS 39 +#define def_mailto (sudo_defs_table[40].sd_un.str) +#define I_MAILTO 40 +#define def_mailfrom (sudo_defs_table[41].sd_un.str) +#define I_MAILFROM 41 +#define def_mailsub (sudo_defs_table[42].sd_un.str) +#define I_MAILSUB 42 +#define def_badpass_message (sudo_defs_table[43].sd_un.str) +#define I_BADPASS_MESSAGE 43 +#define def_timestampdir (sudo_defs_table[44].sd_un.str) +#define I_TIMESTAMPDIR 44 +#define def_timestampowner (sudo_defs_table[45].sd_un.str) +#define I_TIMESTAMPOWNER 45 +#define def_exempt_group (sudo_defs_table[46].sd_un.str) +#define I_EXEMPT_GROUP 46 +#define def_passprompt (sudo_defs_table[47].sd_un.str) +#define I_PASSPROMPT 47 +#define def_passprompt_override (sudo_defs_table[48].sd_un.flag) +#define I_PASSPROMPT_OVERRIDE 48 +#define def_runas_default (sudo_defs_table[49].sd_un.str) +#define I_RUNAS_DEFAULT 49 +#define def_secure_path (sudo_defs_table[50].sd_un.str) +#define I_SECURE_PATH 50 +#define def_editor (sudo_defs_table[51].sd_un.str) +#define I_EDITOR 51 +#define def_listpw (sudo_defs_table[52].sd_un.tuple) +#define I_LISTPW 52 +#define def_verifypw (sudo_defs_table[53].sd_un.tuple) +#define I_VERIFYPW 53 +#define def_noexec (sudo_defs_table[54].sd_un.flag) +#define I_NOEXEC 54 +#define def_ignore_local_sudoers (sudo_defs_table[55].sd_un.flag) +#define I_IGNORE_LOCAL_SUDOERS 55 +#define def_closefrom (sudo_defs_table[56].sd_un.ival) +#define I_CLOSEFROM 56 +#define def_closefrom_override (sudo_defs_table[57].sd_un.flag) +#define I_CLOSEFROM_OVERRIDE 57 +#define def_setenv (sudo_defs_table[58].sd_un.flag) +#define I_SETENV 58 +#define def_env_reset (sudo_defs_table[59].sd_un.flag) +#define I_ENV_RESET 59 +#define def_env_check (sudo_defs_table[60].sd_un.list) +#define I_ENV_CHECK 60 +#define def_env_delete (sudo_defs_table[61].sd_un.list) +#define I_ENV_DELETE 61 +#define def_env_keep (sudo_defs_table[62].sd_un.list) +#define I_ENV_KEEP 62 +#define def_role (sudo_defs_table[63].sd_un.str) +#define I_ROLE 63 +#define def_type (sudo_defs_table[64].sd_un.str) +#define I_TYPE 64 +#define def_env_file (sudo_defs_table[65].sd_un.str) +#define I_ENV_FILE 65 +#define def_sudoers_locale (sudo_defs_table[66].sd_un.str) +#define I_SUDOERS_LOCALE 66 +#define def_visiblepw (sudo_defs_table[67].sd_un.flag) +#define I_VISIBLEPW 67 +#define def_pwfeedback (sudo_defs_table[68].sd_un.flag) +#define I_PWFEEDBACK 68 +#define def_fast_glob (sudo_defs_table[69].sd_un.flag) +#define I_FAST_GLOB 69 +#define def_umask_override (sudo_defs_table[70].sd_un.flag) +#define I_UMASK_OVERRIDE 70 +#define def_log_input (sudo_defs_table[71].sd_un.flag) +#define I_LOG_INPUT 71 +#define def_log_output (sudo_defs_table[72].sd_un.flag) +#define I_LOG_OUTPUT 72 +#define def_compress_io (sudo_defs_table[73].sd_un.flag) +#define I_COMPRESS_IO 73 +#define def_use_pty (sudo_defs_table[74].sd_un.flag) +#define I_USE_PTY 74 +#define def_group_plugin (sudo_defs_table[75].sd_un.str) +#define I_GROUP_PLUGIN 75 +#define def_iolog_dir (sudo_defs_table[76].sd_un.str) +#define I_IOLOG_DIR 76 +#define def_iolog_file (sudo_defs_table[77].sd_un.str) +#define I_IOLOG_FILE 77 +#define def_set_utmp (sudo_defs_table[78].sd_un.flag) +#define I_SET_UTMP 78 +#define def_utmp_runas (sudo_defs_table[79].sd_un.flag) +#define I_UTMP_RUNAS 79 + +enum def_tuple { + never, + once, + always, + any, + all +}; diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in new file mode 100644 index 0000000..7b9d4e4 --- /dev/null +++ b/plugins/sudoers/def_data.in @@ -0,0 +1,255 @@ +# +# Format: +# +# var_name +# TYPE +# description (or NULL) +# array of struct def_values if TYPE == T_TUPLE +# +# NOTE: for tuples that can be used in a boolean context the first +# value corresponds to boolean FALSE and the second to TRUE. +# + +syslog + T_LOGFAC|T_BOOL + "Syslog facility if syslog is being used for logging: %s" +syslog_goodpri + T_LOGPRI + "Syslog priority to use when user authenticates successfully: %s" +syslog_badpri + T_LOGPRI + "Syslog priority to use when user authenticates unsuccessfully: %s" +long_otp_prompt + T_FLAG + "Put OTP prompt on its own line" +ignore_dot + T_FLAG + "Ignore '.' in $PATH" +mail_always + T_FLAG + "Always send mail when sudo is run" +mail_badpass + T_FLAG + "Send mail if user authentication fails" +mail_no_user + T_FLAG + "Send mail if the user is not in sudoers" +mail_no_host + T_FLAG + "Send mail if the user is not in sudoers for this host" +mail_no_perms + T_FLAG + "Send mail if the user is not allowed to run a command" +tty_tickets + T_FLAG + "Use a separate timestamp for each user/tty combo" +lecture + T_TUPLE|T_BOOL + "Lecture user the first time they run sudo" + never once always +lecture_file + T_STR|T_PATH|T_BOOL + "File containing the sudo lecture: %s" +authenticate + T_FLAG + "Require users to authenticate by default" +root_sudo + T_FLAG + "Root may run sudo" +log_host + T_FLAG + "Log the hostname in the (non-syslog) log file" +log_year + T_FLAG + "Log the year in the (non-syslog) log file" +shell_noargs + T_FLAG + "If sudo is invoked with no arguments, start a shell" +set_home + T_FLAG + "Set $HOME to the target user when starting a shell with -s" +always_set_home + T_FLAG + "Always set $HOME to the target user's home directory" +path_info + T_FLAG + "Allow some information gathering to give useful error messages" +fqdn + T_FLAG + "Require fully-qualified hostnames in the sudoers file" +insults + T_FLAG + "Insult the user when they enter an incorrect password" +requiretty + T_FLAG + "Only allow the user to run sudo if they have a tty" +env_editor + T_FLAG + "Visudo will honor the EDITOR environment variable" +rootpw + T_FLAG + "Prompt for root's password, not the users's" +runaspw + T_FLAG + "Prompt for the runas_default user's password, not the users's" +targetpw + T_FLAG + "Prompt for the target user's password, not the users's" +use_loginclass + T_FLAG + "Apply defaults in the target user's login class if there is one" +set_logname + T_FLAG + "Set the LOGNAME and USER environment variables" +stay_setuid + T_FLAG + "Only set the effective uid to the target user, not the real uid" +preserve_groups + T_FLAG + "Don't initialize the group vector to that of the target user" +loglinelen + T_UINT|T_BOOL + "Length at which to wrap log file lines (0 for no wrap): %d" +timestamp_timeout + T_FLOAT|T_BOOL + "Authentication timestamp timeout: %.1f minutes" +passwd_timeout + T_FLOAT|T_BOOL + "Password prompt timeout: %.1f minutes" +passwd_tries + T_UINT + "Number of tries to enter a password: %d" +umask + T_MODE|T_BOOL + "Umask to use or 0777 to use user's: 0%o" +logfile + T_STR|T_BOOL|T_PATH + "Path to log file: %s" +mailerpath + T_STR|T_BOOL|T_PATH + "Path to mail program: %s" +mailerflags + T_STR|T_BOOL + "Flags for mail program: %s" +mailto + T_STR|T_BOOL + "Address to send mail to: %s" +mailfrom + T_STR|T_BOOL + "Address to send mail from: %s" +mailsub + T_STR + "Subject line for mail messages: %s" +badpass_message + T_STR + "Incorrect password message: %s" +timestampdir + T_STR|T_PATH + "Path to authentication timestamp dir: %s" +timestampowner + T_STR + "Owner of the authentication timestamp dir: %s" +exempt_group + T_STR|T_BOOL + "Users in this group are exempt from password and PATH requirements: %s" +passprompt + T_STR + "Default password prompt: %s" +passprompt_override + T_FLAG + "If set, passprompt will override system prompt in all cases." +runas_default + T_STR + "Default user to run commands as: %s" +secure_path + T_STR|T_BOOL + "Value to override user's $PATH with: %s" +editor + T_STR|T_PATH + "Path to the editor for use by visudo: %s" +listpw + T_TUPLE|T_BOOL + "When to require a password for 'list' pseudocommand: %s" + never any all always +verifypw + T_TUPLE|T_BOOL + "When to require a password for 'verify' pseudocommand: %s" + never all any always +noexec + T_FLAG + "Preload the dummy exec functions contained in the sudo_noexec library" +ignore_local_sudoers + T_FLAG + "If LDAP directory is up, do we ignore local sudoers file" +closefrom + T_INT + "File descriptors >= %d will be closed before executing a command" +closefrom_override + T_FLAG + "If set, users may override the value of `closefrom' with the -C option" +setenv + T_FLAG + "Allow users to set arbitrary environment variables" +env_reset + T_FLAG + "Reset the environment to a default set of variables" +env_check + T_LIST|T_BOOL + "Environment variables to check for sanity:" +env_delete + T_LIST|T_BOOL + "Environment variables to remove:" +env_keep + T_LIST|T_BOOL + "Environment variables to preserve:" +role + T_STR + "SELinux role to use in the new security context: %s" +type + T_STR + "SELinux type to use in the new security context: %s" +env_file + T_STR|T_PATH|T_BOOL + "Path to the sudo-specific environment file: %s" +sudoers_locale + T_STR + "Locale to use while parsing sudoers: %s" +visiblepw + T_FLAG + "Allow sudo to prompt for a password even if it would be visible" +pwfeedback + T_FLAG + "Provide visual feedback at the password prompt when there is user input" +fast_glob + T_FLAG + "Use faster globbing that is less accurate but does not access the filesystem" +umask_override + T_FLAG + "The umask specified in sudoers will override the user's, even if it is more permissive" +log_input + T_FLAG + "Log user's input for the command being run" +log_output + T_FLAG + "Log the output of the command being run" +compress_io + T_FLAG + "Compress I/O logs using zlib" +use_pty + T_FLAG + "Always run commands in a pseudo-tty" +group_plugin + T_STR + "Plugin for non-Unix group support: %s" +iolog_dir + T_STR|T_PATH + "Directory in which to store input/output logs: %s" +iolog_file + T_STR + "File in which to store the input/output log: %s" +set_utmp + T_FLAG + "Add an entry to the utmp/utmpx file when allocating a pty" +utmp_runas + T_FLAG + "Set the user in utmp to the runas user, not the invoking user" diff --git a/plugins/sudoers/defaults.c b/plugins/sudoers/defaults.c new file mode 100644 index 0000000..6cab7e4 --- /dev/null +++ b/plugins/sudoers/defaults.c @@ -0,0 +1,799 @@ +/* + * Copyright (c) 1999-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. + * + * 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 */ +#include +#include + +#include "sudoers.h" +#include "parse.h" +#include + +/* + * For converting between syslog numbers and strings. + */ +struct strmap { + char *name; + int num; +}; + +#ifdef LOG_NFACILITIES +static struct strmap facilities[] = { +#ifdef LOG_AUTHPRIV + { "authpriv", LOG_AUTHPRIV }, +#endif + { "auth", LOG_AUTH }, + { "daemon", LOG_DAEMON }, + { "user", LOG_USER }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { NULL, -1 } +}; +#endif /* LOG_NFACILITIES */ + +static struct strmap priorities[] = { + { "alert", LOG_ALERT }, + { "crit", LOG_CRIT }, + { "debug", LOG_DEBUG }, + { "emerg", LOG_EMERG }, + { "err", LOG_ERR }, + { "info", LOG_INFO }, + { "notice", LOG_NOTICE }, + { "warning", LOG_WARNING }, + { NULL, -1 } +}; + +/* + * Local prototypes. + */ +static bool store_int(char *, struct sudo_defs_types *, int); +static bool store_list(char *, struct sudo_defs_types *, int); +static bool store_mode(char *, struct sudo_defs_types *, int); +static bool store_str(char *, struct sudo_defs_types *, int); +static bool store_syslogfac(char *, struct sudo_defs_types *, int); +static bool store_syslogpri(char *, struct sudo_defs_types *, int); +static bool store_tuple(char *, struct sudo_defs_types *, int); +static bool store_uint(char *, struct sudo_defs_types *, int); +static bool store_float(char *, struct sudo_defs_types *, int); +static void list_op(char *, size_t, struct sudo_defs_types *, enum list_ops); +static const char *logfac2str(int); +static const char *logpri2str(int); + +/* + * Table describing compile-time and run-time options. + */ +#include + +/* + * Print version and configure info. + */ +void +dump_defaults(void) +{ + struct sudo_defs_types *cur; + struct list_member *item; + struct def_values *def; + char *desc; + debug_decl(dump_defaults, SUDO_DEBUG_DEFAULTS) + + for (cur = sudo_defs_table; cur->name; cur++) { + if (cur->desc) { + desc = _(cur->desc); + switch (cur->type & T_MASK) { + case T_FLAG: + if (cur->sd_un.flag) + sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); + break; + case T_STR: + if (cur->sd_un.str) { + sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.str); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + } + break; + case T_LOGFAC: + if (cur->sd_un.ival) { + sudo_printf(SUDO_CONV_INFO_MSG, desc, + logfac2str(cur->sd_un.ival)); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + } + break; + case T_LOGPRI: + if (cur->sd_un.ival) { + sudo_printf(SUDO_CONV_INFO_MSG, desc, + logpri2str(cur->sd_un.ival)); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + } + break; + case T_UINT: + case T_INT: + sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.ival); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + break; + case T_FLOAT: + sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.fval); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + break; + case T_MODE: + sudo_printf(SUDO_CONV_INFO_MSG, desc, cur->sd_un.mode); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + break; + case T_LIST: + if (cur->sd_un.list) { + sudo_printf(SUDO_CONV_INFO_MSG, "%s\n", desc); + for (item = cur->sd_un.list; item; item = item->next) { + sudo_printf(SUDO_CONV_INFO_MSG, + "\t%s\n", item->value); + } + } + break; + case T_TUPLE: + for (def = cur->values; def->sval; def++) { + if (cur->sd_un.ival == def->ival) { + sudo_printf(SUDO_CONV_INFO_MSG, desc, def->sval); + break; + } + } + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + break; + } + } + } + debug_return; +} + +/* + * Sets/clears an entry in the defaults structure + * If a variable that takes a value is used in a boolean + * context with op == 0, disable that variable. + * Eg. you may want to turn off logging to a file for some hosts. + * This is only meaningful for variables that are *optional*. + */ +bool +set_default(char *var, char *val, int op) +{ + struct sudo_defs_types *cur; + int num; + debug_decl(set_default, SUDO_DEBUG_DEFAULTS) + + for (cur = sudo_defs_table, num = 0; cur->name; cur++, num++) { + if (strcmp(var, cur->name) == 0) + break; + } + if (!cur->name) { + warningx(_("unknown defaults entry `%s'"), var); + debug_return_bool(false); + } + + switch (cur->type & T_MASK) { + case T_LOGFAC: + if (!store_syslogfac(val, cur, op)) { + if (val) + warningx(_("value `%s' is invalid for option `%s'"), + val, var); + else + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + break; + case T_LOGPRI: + if (!store_syslogpri(val, cur, op)) { + if (val) + warningx(_("value `%s' is invalid for option `%s'"), + val, var); + else + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + break; + case T_STR: + if (!val) { + /* Check for bogus boolean usage or lack of a value. */ + if (!ISSET(cur->type, T_BOOL) || op != false) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + } + if (ISSET(cur->type, T_PATH) && val && *val != '/') { + warningx(_("values for `%s' must start with a '/'"), var); + debug_return_bool(false); + } + if (!store_str(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + case T_INT: + if (!val) { + /* Check for bogus boolean usage or lack of a value. */ + if (!ISSET(cur->type, T_BOOL) || op != false) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + } + if (!store_int(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + case T_UINT: + if (!val) { + /* Check for bogus boolean usage or lack of a value. */ + if (!ISSET(cur->type, T_BOOL) || op != false) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + } + if (!store_uint(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + case T_FLOAT: + if (!val) { + /* Check for bogus boolean usage or lack of a value. */ + if (!ISSET(cur->type, T_BOOL) || op != false) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + } + if (!store_float(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + case T_MODE: + if (!val) { + /* Check for bogus boolean usage or lack of a value. */ + if (!ISSET(cur->type, T_BOOL) || op != false) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + } + if (!store_mode(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + case T_FLAG: + if (val) { + warningx(_("option `%s' does not take a value"), var); + debug_return_bool(false); + } + cur->sd_un.flag = op; + break; + case T_LIST: + if (!val) { + /* Check for bogus boolean usage or lack of a value. */ + if (!ISSET(cur->type, T_BOOL) || op != false) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + } + if (!store_list(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + case T_TUPLE: + if (!val && !ISSET(cur->type, T_BOOL)) { + warningx(_("no value specified for `%s'"), var); + debug_return_bool(false); + } + if (!store_tuple(val, cur, op)) { + warningx(_("value `%s' is invalid for option `%s'"), val, var); + debug_return_bool(false); + } + break; + } + + debug_return_bool(true); +} + +/* + * Set default options to compiled-in values. + * Any of these may be overridden at runtime by a "Defaults" file. + */ +void +init_defaults(void) +{ + static int firsttime = 1; + struct sudo_defs_types *def; + debug_decl(init_defaults, SUDO_DEBUG_DEFAULTS) + + /* Clear any old settings. */ + if (!firsttime) { + for (def = sudo_defs_table; def->name; def++) { + switch (def->type & T_MASK) { + case T_STR: + efree(def->sd_un.str); + def->sd_un.str = NULL; + break; + case T_LIST: + list_op(NULL, 0, def, freeall); + break; + } + zero_bytes(&def->sd_un, sizeof(def->sd_un)); + } + } + + /* First initialize the flags. */ +#ifdef LONG_OTP_PROMPT + def_long_otp_prompt = true; +#endif +#ifdef IGNORE_DOT_PATH + def_ignore_dot = true; +#endif +#ifdef ALWAYS_SEND_MAIL + def_mail_always = true; +#endif +#ifdef SEND_MAIL_WHEN_NO_USER + def_mail_no_user = true; +#endif +#ifdef SEND_MAIL_WHEN_NO_HOST + def_mail_no_host = true; +#endif +#ifdef SEND_MAIL_WHEN_NOT_OK + def_mail_no_perms = true; +#endif +#ifndef NO_TTY_TICKETS + def_tty_tickets = true; +#endif +#ifndef NO_LECTURE + def_lecture = once; +#endif +#ifndef NO_AUTHENTICATION + def_authenticate = true; +#endif +#ifndef NO_ROOT_SUDO + def_root_sudo = true; +#endif +#ifdef HOST_IN_LOG + def_log_host = true; +#endif +#ifdef SHELL_IF_NO_ARGS + def_shell_noargs = true; +#endif +#ifdef SHELL_SETS_HOME + def_set_home = true; +#endif +#ifndef DONT_LEAK_PATH_INFO + def_path_info = true; +#endif +#ifdef FQDN + def_fqdn = true; +#endif +#ifdef USE_INSULTS + def_insults = true; +#endif +#ifdef ENV_EDITOR + def_env_editor = true; +#endif +#ifdef UMASK_OVERRIDE + def_umask_override = true; +#endif + def_iolog_file = estrdup("%{seq}"); + def_iolog_dir = estrdup(_PATH_SUDO_IO_LOGDIR); + def_sudoers_locale = estrdup("C"); + def_env_reset = ENV_RESET; + def_set_logname = true; + def_closefrom = STDERR_FILENO + 1; + + /* Syslog options need special care since they both strings and ints */ +#if (LOGGING & SLOG_SYSLOG) + (void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], true); + (void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI], + true); + (void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI], + true); +#endif + + /* Password flags also have a string and integer component. */ + (void) store_tuple("any", &sudo_defs_table[I_LISTPW], true); + (void) store_tuple("all", &sudo_defs_table[I_VERIFYPW], true); + + /* Then initialize the int-like things. */ +#ifdef SUDO_UMASK + def_umask = SUDO_UMASK; +#else + def_umask = 0777; +#endif + def_loglinelen = MAXLOGFILELEN; + def_timestamp_timeout = TIMEOUT; + def_passwd_timeout = PASSWORD_TIMEOUT; + def_passwd_tries = TRIES_FOR_PASSWORD; +#ifdef HAVE_ZLIB_H + def_compress_io = true; +#endif + + /* Now do the strings */ + def_mailto = estrdup(MAILTO); + def_mailsub = estrdup(_(MAILSUBJECT)); + def_badpass_message = estrdup(_(INCORRECT_PASSWORD)); + def_timestampdir = estrdup(_PATH_SUDO_TIMEDIR); + def_passprompt = estrdup(_(PASSPROMPT)); + def_runas_default = estrdup(RUNAS_DEFAULT); +#ifdef _PATH_SUDO_SENDMAIL + def_mailerpath = estrdup(_PATH_SUDO_SENDMAIL); + def_mailerflags = estrdup("-t"); +#endif +#if (LOGGING & SLOG_FILE) + def_logfile = estrdup(_PATH_SUDO_LOGFILE); +#endif +#ifdef EXEMPTGROUP + def_exempt_group = estrdup(EXEMPTGROUP); +#endif +#ifdef SECURE_PATH + def_secure_path = estrdup(SECURE_PATH); +#endif + def_editor = estrdup(EDITOR); + def_set_utmp = true; + + /* Finally do the lists (currently just environment tables). */ + init_envtables(); + + firsttime = 0; + + debug_return; +} + +/* + * Update the defaults based on what was set by sudoers. + * Pass in an OR'd list of which default types to update. + */ +int +update_defaults(int what) +{ + struct defaults *def; + bool rc = true; + debug_decl(update_defaults, SUDO_DEBUG_DEFAULTS) + + tq_foreach_fwd(&defaults, def) { + switch (def->type) { + case DEFAULTS: + if (ISSET(what, SETDEF_GENERIC) && + !set_default(def->var, def->val, def->op)) + rc = false; + break; + case DEFAULTS_USER: + if (ISSET(what, SETDEF_USER) && + userlist_matches(sudo_user.pw, &def->binding) == ALLOW && + !set_default(def->var, def->val, def->op)) + rc = false; + break; + case DEFAULTS_RUNAS: + if (ISSET(what, SETDEF_RUNAS) && + runaslist_matches(&def->binding, NULL) == ALLOW && + !set_default(def->var, def->val, def->op)) + rc = false; + break; + case DEFAULTS_HOST: + if (ISSET(what, SETDEF_HOST) && + hostlist_matches(&def->binding) == ALLOW && + !set_default(def->var, def->val, def->op)) + rc = false; + break; + case DEFAULTS_CMND: + if (ISSET(what, SETDEF_CMND) && + cmndlist_matches(&def->binding) == ALLOW && + !set_default(def->var, def->val, def->op)) + rc = false; + break; + } + } + debug_return_bool(rc); +} + +static bool +store_int(char *val, struct sudo_defs_types *def, int op) +{ + char *endp; + long l; + debug_decl(store_int, SUDO_DEBUG_DEFAULTS) + + if (op == false) { + def->sd_un.ival = 0; + } else { + l = strtol(val, &endp, 10); + if (*endp != '\0') + debug_return_bool(false); + /* XXX - should check against INT_MAX */ + def->sd_un.ival = (int)l; + } + if (def->callback) + debug_return_bool(def->callback(val)); + debug_return_bool(true); +} + +static bool +store_uint(char *val, struct sudo_defs_types *def, int op) +{ + char *endp; + long l; + debug_decl(store_uint, SUDO_DEBUG_DEFAULTS) + + if (op == false) { + def->sd_un.ival = 0; + } else { + l = strtol(val, &endp, 10); + if (*endp != '\0' || l < 0) + debug_return_bool(false); + /* XXX - should check against INT_MAX */ + def->sd_un.ival = (unsigned int)l; + } + if (def->callback) + debug_return_bool(def->callback(val)); + debug_return_bool(true); +} + +static bool +store_float(char *val, struct sudo_defs_types *def, int op) +{ + char *endp; + double d; + debug_decl(store_float, SUDO_DEBUG_DEFAULTS) + + if (op == false) { + def->sd_un.fval = 0.0; + } else { + d = strtod(val, &endp); + if (*endp != '\0') + debug_return_bool(false); + /* XXX - should check against HUGE_VAL */ + def->sd_un.fval = d; + } + if (def->callback) + debug_return_bool(def->callback(val)); + debug_return_bool(true); +} + +static bool +store_tuple(char *val, struct sudo_defs_types *def, int op) +{ + struct def_values *v; + debug_decl(store_tuple, SUDO_DEBUG_DEFAULTS) + + /* + * Since enums are really just ints we store the value as an ival. + * In the future, there may be multiple enums for different tuple + * types we want to avoid and special knowledge of the tuple type. + * This does assume that the first entry in the tuple enum will + * be the equivalent to a boolean "false". + */ + if (!val) { + def->sd_un.ival = (op == false) ? 0 : 1; + } else { + for (v = def->values; v->sval != NULL; v++) { + if (strcmp(v->sval, val) == 0) { + def->sd_un.ival = v->ival; + break; + } + } + if (v->sval == NULL) + debug_return_bool(false); + } + if (def->callback) + debug_return_bool(def->callback(val)); + debug_return_bool(true); +} + +static bool +store_str(char *val, struct sudo_defs_types *def, int op) +{ + debug_decl(store_str, SUDO_DEBUG_DEFAULTS) + + efree(def->sd_un.str); + if (op == false) + def->sd_un.str = NULL; + else + def->sd_un.str = estrdup(val); + if (def->callback) + debug_return_bool(def->callback(val)); + debug_return_bool(true); +} + +static bool +store_list(char *str, struct sudo_defs_types *def, int op) +{ + char *start, *end; + debug_decl(store_list, SUDO_DEBUG_DEFAULTS) + + /* Remove all old members. */ + if (op == false || op == true) + list_op(NULL, 0, def, freeall); + + /* Split str into multiple space-separated words and act on each one. */ + if (op != false) { + end = str; + do { + /* Remove leading blanks, if nothing but blanks we are done. */ + for (start = end; isblank((unsigned char)*start); start++) + ; + if (*start == '\0') + break; + + /* Find end position and perform operation. */ + for (end = start; *end && !isblank((unsigned char)*end); end++) + ; + list_op(start, end - start, def, op == '-' ? delete : add); + } while (*end++ != '\0'); + } + debug_return_bool(true); +} + +static bool +store_syslogfac(char *val, struct sudo_defs_types *def, int op) +{ + struct strmap *fac; + debug_decl(store_syslogfac, SUDO_DEBUG_DEFAULTS) + + if (op == false) { + def->sd_un.ival = false; + debug_return_bool(true); + } +#ifdef LOG_NFACILITIES + if (!val) + debug_return_bool(false); + for (fac = facilities; fac->name && strcmp(val, fac->name); fac++) + ; + if (fac->name == NULL) + debug_return_bool(false); /* not found */ + + def->sd_un.ival = fac->num; +#else + def->sd_un.ival = -1; +#endif /* LOG_NFACILITIES */ + debug_return_bool(true); +} + +static const char * +logfac2str(int n) +{ +#ifdef LOG_NFACILITIES + struct strmap *fac; + debug_decl(logfac2str, SUDO_DEBUG_DEFAULTS) + + for (fac = facilities; fac->name && fac->num != n; fac++) + ; + debug_return_str(fac->name); +#else + return "default"; +#endif /* LOG_NFACILITIES */ +} + +static bool +store_syslogpri(char *val, struct sudo_defs_types *def, int op) +{ + struct strmap *pri; + debug_decl(store_syslogpri, SUDO_DEBUG_DEFAULTS) + + if (op == false || !val) + debug_return_bool(false); + + for (pri = priorities; pri->name && strcmp(val, pri->name); pri++) + ; + if (pri->name == NULL) + debug_return_bool(false); /* not found */ + + def->sd_un.ival = pri->num; + debug_return_bool(true); +} + +static const char * +logpri2str(int n) +{ + struct strmap *pri; + debug_decl(logpri2str, SUDO_DEBUG_DEFAULTS) + + for (pri = priorities; pri->name && pri->num != n; pri++) + ; + debug_return_str(pri->name); +} + +static bool +store_mode(char *val, struct sudo_defs_types *def, int op) +{ + char *endp; + long l; + debug_decl(store_mode, SUDO_DEBUG_DEFAULTS) + + if (op == false) { + def->sd_un.mode = (mode_t)0777; + } else { + l = strtol(val, &endp, 8); + if (*endp != '\0' || l < 0 || l > 0777) + debug_return_bool(false); + def->sd_un.mode = (mode_t)l; + } + if (def->callback) + debug_return_bool(def->callback(val)); + debug_return_bool(true); +} + +static void +list_op(char *val, size_t len, struct sudo_defs_types *def, enum list_ops op) +{ + struct list_member *cur, *prev, *tmp; + debug_decl(list_op, SUDO_DEBUG_DEFAULTS) + + if (op == freeall) { + for (cur = def->sd_un.list; cur; ) { + tmp = cur; + cur = tmp->next; + efree(tmp->value); + efree(tmp); + } + def->sd_un.list = NULL; + debug_return; + } + + for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) { + if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) { + + if (op == add) + debug_return; /* already exists */ + + /* Delete node */ + if (prev != NULL) + prev->next = cur->next; + else + def->sd_un.list = cur->next; + efree(cur->value); + efree(cur); + break; + } + } + + /* Add new node to the head of the list. */ + if (op == add) { + cur = ecalloc(1, sizeof(struct list_member)); + cur->value = estrndup(val, len); + cur->next = def->sd_un.list; + def->sd_un.list = cur; + } + debug_return; +} diff --git a/plugins/sudoers/defaults.h b/plugins/sudoers/defaults.h new file mode 100644 index 0000000..d6231c7 --- /dev/null +++ b/plugins/sudoers/defaults.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1999-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_DEFAULTS_H +#define _SUDO_DEFAULTS_H + +#include + +struct list_member { + char *value; + struct list_member *next; +}; + +struct def_values { + char *sval; /* string value */ + int ival; /* actually an enum */ +}; + +enum list_ops { + add, + delete, + freeall +}; + +/* + * Structure describing compile-time and run-time options. + */ +struct sudo_defs_types { + char *name; + int type; + char *desc; + struct def_values *values; + int (*callback)(const char *); + union { + int flag; + int ival; + double fval; + enum def_tuple tuple; + char *str; + mode_t mode; + struct list_member *list; + } sd_un; +}; + +/* + * Four types of defaults: strings, integers, and flags. + * Also, T_INT, T_FLOAT or T_STR may be ANDed with T_BOOL to indicate that + * a value is not required. Flags are boolean by nature... + */ +#undef T_INT +#define T_INT 0x001 +#undef T_UINT +#define T_UINT 0x002 +#undef T_STR +#define T_STR 0x003 +#undef T_FLAG +#define T_FLAG 0x004 +#undef T_MODE +#define T_MODE 0x005 +#undef T_LIST +#define T_LIST 0x006 +#undef T_LOGFAC +#define T_LOGFAC 0x007 +#undef T_LOGPRI +#define T_LOGPRI 0x008 +#undef T_TUPLE +#define T_TUPLE 0x009 +#undef T_FLOAT +#define T_FLOAT 0x010 +#undef T_MASK +#define T_MASK 0x0FF +#undef T_BOOL +#define T_BOOL 0x100 +#undef T_PATH +#define T_PATH 0x200 + +/* + * Argument to update_defaults() + */ +#define SETDEF_GENERIC 0x01 +#define SETDEF_HOST 0x02 +#define SETDEF_USER 0x04 +#define SETDEF_RUNAS 0x08 +#define SETDEF_CMND 0x10 +#define SETDEF_ALL (SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER|SETDEF_RUNAS|SETDEF_CMND) + +/* + * Prototypes + */ +void dump_default(void); +void init_defaults(void); +bool set_default(char *, char *, int); +int update_defaults(int); + +extern struct sudo_defs_types sudo_defs_table[]; + +#endif /* _SUDO_DEFAULTS_H */ diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c new file mode 100644 index 0000000..962228c --- /dev/null +++ b/plugins/sudoers/env.c @@ -0,0 +1,1112 @@ +/* + * Copyright (c) 2000-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. + * + * 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 +#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 */ +#ifdef HAVE_LOGIN_CAP_H +# include +# ifndef LOGIN_SETENV +# define LOGIN_SETENV 0 +# endif +#endif /* HAVE_LOGIN_CAP_H */ +#include +#include +#include + +#include "sudoers.h" + +/* + * Flags used in rebuild_env() + */ +#undef DID_TERM +#define DID_TERM 0x0001 +#undef DID_PATH +#define DID_PATH 0x0002 +#undef DID_HOME +#define DID_HOME 0x0004 +#undef DID_SHELL +#define DID_SHELL 0x0008 +#undef DID_LOGNAME +#define DID_LOGNAME 0x0010 +#undef DID_USER +#define DID_USER 0x0020 +#undef DID_USERNAME +#define DID_USERNAME 0x0040 +#undef DID_MAIL +#define DID_MAIL 0x0080 +#undef DID_MAX +#define DID_MAX 0x00ff + +#undef KEPT_TERM +#define KEPT_TERM 0x0100 +#undef KEPT_PATH +#define KEPT_PATH 0x0200 +#undef KEPT_HOME +#define KEPT_HOME 0x0400 +#undef KEPT_SHELL +#define KEPT_SHELL 0x0800 +#undef KEPT_LOGNAME +#define KEPT_LOGNAME 0x1000 +#undef KEPT_USER +#define KEPT_USER 0x2000 +#undef KEPT_USERNAME +#define KEPT_USERNAME 0x4000 +#undef KEPT_MAIL +#define KEPT_MAIL 0x8000 +#undef KEPT_MAX +#define KEPT_MAX 0xff00 + +struct environment { + char * const *old_envp; /* pointer the environment we passed back */ + char **envp; /* pointer to the new environment */ + size_t env_size; /* size of new_environ in char **'s */ + size_t env_len; /* number of slots used, not counting NULL */ +}; + +/* + * Copy of the sudo-managed environment. + */ +static struct environment env; + +/* + * Default table of "bad" variables to remove from the environment. + * XXX - how to omit TERMCAP if it starts with '/'? + */ +static const char *initial_badenv_table[] = { + "IFS", + "CDPATH", + "LOCALDOMAIN", + "RES_OPTIONS", + "HOSTALIASES", + "NLSPATH", + "PATH_LOCALE", + "LD_*", + "_RLD*", +#ifdef __hpux + "SHLIB_PATH", +#endif /* __hpux */ +#ifdef _AIX + "LDR_*", + "LIBPATH", + "AUTHSTATE", +#endif +#ifdef __APPLE__ + "DYLD_*", +#endif +#ifdef HAVE_KERB5 + "KRB5_CONFIG*", + "KRB5_KTNAME", +#endif /* HAVE_KERB5 */ +#ifdef HAVE_SECURID + "VAR_ACE", + "USR_ACE", + "DLC_ACE", +#endif /* HAVE_SECURID */ + "TERMINFO", /* terminfo, exclusive path to terminfo files */ + "TERMINFO_DIRS", /* terminfo, path(s) to terminfo files */ + "TERMPATH", /* termcap, path(s) to termcap files */ + "TERMCAP", /* XXX - only if it starts with '/' */ + "ENV", /* ksh, file to source before script runs */ + "BASH_ENV", /* bash, file to source before script runs */ + "PS4", /* bash, prefix for lines in xtrace mode */ + "GLOBIGNORE", /* bash, globbing patterns to ignore */ + "SHELLOPTS", /* bash, extra command line options */ + "JAVA_TOOL_OPTIONS", /* java, extra command line options */ + "PERLIO_DEBUG ", /* perl, debugging output file */ + "PERLLIB", /* perl, search path for modules/includes */ + "PERL5LIB", /* perl 5, search path for modules/includes */ + "PERL5OPT", /* perl 5, extra command line options */ + "PERL5DB", /* perl 5, command used to load debugger */ + "FPATH", /* ksh, search path for functions */ + "NULLCMD", /* zsh, command for null file redirection */ + "READNULLCMD", /* zsh, command for null file redirection */ + "ZDOTDIR", /* zsh, search path for dot files */ + "TMPPREFIX", /* zsh, prefix for temporary files */ + "PYTHONHOME", /* python, module search path */ + "PYTHONPATH", /* python, search path */ + "PYTHONINSPECT", /* python, allow inspection */ + "PYTHONUSERBASE", /* python, per user site-packages directory */ + "RUBYLIB", /* ruby, library load path */ + "RUBYOPT", /* ruby, extra command line options */ + NULL +}; + +/* + * Default table of variables to check for '%' and '/' characters. + */ +static const char *initial_checkenv_table[] = { + "COLORTERM", + "LANG", + "LANGUAGE", + "LC_*", + "LINGUAS", + "TERM", + NULL +}; + +/* + * Default table of variables to preserve in the environment. + */ +static const char *initial_keepenv_table[] = { + "COLORS", + "DISPLAY", + "HOSTNAME", + "KRB5CCNAME", + "LS_COLORS", + "PATH", + "PS1", + "PS2", + "TZ", + "XAUTHORITY", + "XAUTHORIZATION", + NULL +}; + +/* + * Initialize env based on envp. + */ +void +env_init(char * const envp[]) +{ + char * const *ep; + size_t len; + debug_decl(env_init, SUDO_DEBUG_ENV) + + if (envp == NULL) { + /* Reset to initial state but keep a pointer to what we allocated. */ + envp = env.envp; + memset(&env, 0, sizeof(env)); + env.old_envp = envp; + } else { + /* Make private copy of envp. */ + for (ep = envp; *ep != NULL; ep++) + continue; + len = (size_t)(ep - envp); + + env.env_len = len; + env.env_size = len + 1 + 128; + env.envp = emalloc2(env.env_size, sizeof(char *)); +#ifdef ENV_DEBUG + memset(env.envp, 0, env.env_size * sizeof(char *)); +#endif + memcpy(env.envp, envp, len * sizeof(char *)); + env.envp[len] = '\0'; + + /* Free the old envp we allocated, if any. */ + if (env.old_envp != NULL) + efree((void *)env.old_envp); + } + + debug_return; +} + +/* + * Getter for private copy of the environment. + */ +char ** +env_get(void) +{ + return env.envp; +} + +/* + * Similar to putenv(3) but operates on sudo's private copy of the + * environment (not environ) and it always overwrites. The dupcheck param + * determines whether we need to verify that the variable is not already set. + * Will only overwrite an existing variable if overwrite is set. + * Does not include warnings or debugging to avoid recursive calls. + */ +static int +sudo_putenv_nodebug(char *str, bool dupcheck, bool overwrite) +{ + char **ep; + size_t len; + bool found = false; + + /* Make sure there is room for the new entry plus a NULL. */ + if (env.env_len + 2 > env.env_size) { + char **nenvp; + size_t nsize = env.env_size + 128; + nenvp = env.envp ? realloc(env.envp, nsize * sizeof(char *)) : + malloc(nsize * sizeof(char *)); + if (nenvp == NULL) { + errno = ENOMEM; + return -1; + } + env.envp = nenvp; + env.env_size = nsize; +#ifdef ENV_DEBUG + memset(env.envp + env.env_len, 0, + (env.env_size - env.env_len) * sizeof(char *)); +#endif + } + +#ifdef ENV_DEBUG + if (env.envp[env.env_len] != NULL) { + errno = EINVAL; + return -1; + } +#endif + + if (dupcheck) { + len = (strchr(str, '=') - str) + 1; + for (ep = env.envp; !found && *ep != NULL; ep++) { + if (strncmp(str, *ep, len) == 0) { + if (overwrite) + *ep = str; + found = true; + } + } + /* Prune out duplicate variables. */ + if (found && overwrite) { + while (*ep != NULL) { + if (strncmp(str, *ep, len) == 0) { + char **cur = ep; + while ((*cur = *(cur + 1)) != NULL) + cur++; + } else { + ep++; + } + } + env.env_len = ep - env.envp; + } + } + + if (!found) { + ep = env.envp + env.env_len; + env.env_len++; + *ep++ = str; + *ep = NULL; + } + return 0; +} + +/* + * Similar to putenv(3) but operates on sudo's private copy of the + * environment (not environ) and it always overwrites. The dupcheck param + * determines whether we need to verify that the variable is not already set. + * Will only overwrite an existing variable if overwrite is set. + */ +static int +sudo_putenv(char *str, bool dupcheck, bool overwrite) +{ + int rval; + debug_decl(sudo_putenv, SUDO_DEBUG_ENV) + + rval = sudo_putenv_nodebug(str, dupcheck, overwrite); + if (rval == -1) { +#ifdef ENV_DEBUG + if (env.envp[env.env_len] != NULL) + errorx(1, _("sudo_putenv: corrupted envp, length mismatch")); +#endif + errorx(1, _("unable to allocate memory")); + } + debug_return_int(rval); +} + +/* + * Similar to setenv(3) but operates on a private copy of the environment. + * The dupcheck param determines whether we need to verify that the variable + * is not already set. + */ +static int +sudo_setenv2(const char *var, const char *val, bool dupcheck, bool overwrite) +{ + char *estring; + size_t esize; + debug_decl(sudo_setenv2, SUDO_DEBUG_ENV) + + esize = strlen(var) + 1 + strlen(val) + 1; + estring = emalloc(esize); + + /* Build environment string and insert it. */ + if (strlcpy(estring, var, esize) >= esize || + strlcat(estring, "=", esize) >= esize || + strlcat(estring, val, esize) >= esize) { + + errorx(1, _("internal error, sudo_setenv2() overflow")); + } + debug_return_int(sudo_putenv(estring, dupcheck, overwrite)); +} + +/* + * Similar to setenv(3) but operates on a private copy of the environment. + * Does not include warnings or debugging to avoid recursive calls. + */ +static int +sudo_setenv_nodebug(const char *var, const char *val, int overwrite) +{ + char *estring; + size_t esize; + + esize = strlen(var) + 1 + strlen(val) + 1; + if ((estring = malloc(esize)) == NULL) { + errno = ENOMEM; + return -1; + } + + /* Build environment string and insert it. */ + if (strlcpy(estring, var, esize) >= esize || + strlcat(estring, "=", esize) >= esize || + strlcat(estring, val, esize) >= esize) { + + errno = EINVAL; + return -1; + } + return sudo_putenv_nodebug(estring, true, overwrite); +} + +/* + * Similar to setenv(3) but operates on a private copy of the environment. + */ +int +sudo_setenv(const char *var, const char *val, int overwrite) +{ + int rval; + debug_decl(sudo_setenv, SUDO_DEBUG_ENV) + + rval = sudo_setenv_nodebug(var, val, overwrite); + if (rval == -1) { + if (errno == EINVAL) + errorx(1, _("internal error, sudo_setenv() overflow")); + errorx(1, _("unable to allocate memory")); + } + debug_return_int(rval); +} + +/* + * Similar to unsetenv(3) but operates on a private copy of the environment. + * Does not include warnings or debugging to avoid recursive calls. + */ +static int +sudo_unsetenv_nodebug(const char *var) +{ + char **ep = env.envp; + size_t len; + + if (ep == NULL || var == NULL || *var == '\0' || strchr(var, '=') != NULL) { + errno = EINVAL; + return -1; + } + + len = strlen(var); + while (*ep != NULL) { + if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') { + /* Found it; shift remainder + NULL over by one. */ + char **cur = ep; + while ((*cur = *(cur + 1)) != NULL) + cur++; + /* Keep going, could be multiple instances of the var. */ + } else { + ep++; + } + } + return 0; +} + +/* + * Similar to unsetenv(3) but operates on a private copy of the environment. + */ +int +sudo_unsetenv(const char *name) +{ + int rval; + debug_decl(sudo_unsetenv, SUDO_DEBUG_ENV) + + rval = sudo_unsetenv_nodebug(name); + + debug_return_int(rval); +} + +/* + * Similar to getenv(3) but operates on a private copy of the environment. + * Does not include warnings or debugging to avoid recursive calls. + */ +static char * +sudo_getenv_nodebug(const char *name) +{ + char **ep, *val = NULL; + size_t namelen = 0; + + if (env.env_len != 0) { + /* For BSD compatibility, treat '=' in name like end of string. */ + while (name[namelen] != '\0' && name[namelen] != '=') + namelen++; + for (ep = env.envp; *ep != NULL; ep++) { + if (strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') { + val = *ep + namelen + 1; + break; + } + } + } + return val; +} + +/* + * Similar to getenv(3) but operates on a private copy of the environment. + */ +char * +sudo_getenv(const char *name) +{ + char *val; + debug_decl(sudo_getenv, SUDO_DEBUG_ENV) + + val = sudo_getenv_nodebug(name); + + debug_return_str(val); +} + +/* + * Merge another environment with our private copy. + */ +void +env_merge(char * const envp[], bool overwrite) +{ + char * const *ep; + debug_decl(env_merge, SUDO_DEBUG_ENV) + + for (ep = envp; *ep != NULL; ep++) + sudo_putenv(*ep, true, overwrite); + + debug_return; +} + +/* + * Check the env_delete blacklist. + * Returns true if the variable was found, else false. + */ +static bool +matches_env_delete(const char *var) +{ + struct list_member *cur; + size_t len; + bool iswild; + bool match = false; + debug_decl(matches_env_delete, SUDO_DEBUG_ENV) + + /* Skip anything listed in env_delete. */ + for (cur = def_env_delete; cur; cur = cur->next) { + len = strlen(cur->value); + /* Deal with '*' wildcard */ + if (cur->value[len - 1] == '*') { + len--; + iswild = true; + } else + iswild = false; + if (strncmp(cur->value, var, len) == 0 && + (iswild || var[len] == '=')) { + match = true; + break; + } + } + debug_return_bool(match); +} + +/* + * Apply the env_check list. + * Returns true if the variable is allowed, false if denied + * or -1 if no match. + */ +static int +matches_env_check(const char *var) +{ + struct list_member *cur; + size_t len; + bool iswild; + int keepit = -1; + debug_decl(matches_env_check, SUDO_DEBUG_ENV) + + for (cur = def_env_check; cur; cur = cur->next) { + len = strlen(cur->value); + /* Deal with '*' wildcard */ + if (cur->value[len - 1] == '*') { + len--; + iswild = true; + } else + iswild = false; + if (strncmp(cur->value, var, len) == 0 && + (iswild || var[len] == '=')) { + keepit = !strpbrk(var, "/%"); + break; + } + } + debug_return_bool(keepit); +} + +/* + * Check the env_keep list. + * Returns true if the variable is allowed else false. + */ +static bool +matches_env_keep(const char *var) +{ + struct list_member *cur; + size_t len; + bool iswild, keepit = false; + debug_decl(matches_env_keep, SUDO_DEBUG_ENV) + + /* Preserve SHELL variable for "sudo -s". */ + if (ISSET(sudo_mode, MODE_SHELL) && strncmp(var, "SHELL=", 6) == 0) { + keepit = true; + goto done; + } + + for (cur = def_env_keep; cur; cur = cur->next) { + len = strlen(cur->value); + /* Deal with '*' wildcard */ + if (cur->value[len - 1] == '*') { + len--; + iswild = true; + } else + iswild = false; + if (strncmp(cur->value, var, len) == 0 && + (iswild || var[len] == '=')) { + keepit = true; + break; + } + } +done: + debug_return_bool(keepit); +} + +/* + * Look up var in the env_delete and env_check. + * Returns true if we should delete the variable, else false. + */ +static bool +env_should_delete(const char *var) +{ + int delete_it; + debug_decl(env_should_delete, SUDO_DEBUG_ENV); + + delete_it = matches_env_delete(var); + if (!delete_it) + delete_it = matches_env_check(var) == false; + debug_return_bool(delete_it); +} + +/* + * Lookup var in the env_check and env_keep lists. + * Returns true if the variable is allowed else false. + */ +static bool +env_should_keep(const char *var) +{ + int keepit; + debug_decl(env_should_keep, SUDO_DEBUG_ENV) + + keepit = matches_env_check(var); + if (keepit == -1) + keepit = matches_env_keep(var); + + debug_return_bool(keepit == true); +} + +static void +env_update_didvar(const char *ep, unsigned int *didvar) +{ + switch (*ep) { + case 'H': + if (strncmp(ep, "HOME=", 5) == 0) + SET(*didvar, DID_HOME); + break; + case 'L': + if (strncmp(ep, "LOGNAME=", 8) == 0) + SET(*didvar, DID_LOGNAME); + break; + case 'M': + if (strncmp(ep, "MAIL=", 5) == 0) + SET(*didvar, DID_MAIL); + break; + case 'P': + if (strncmp(ep, "PATH=", 5) == 0) + SET(*didvar, DID_PATH); + break; + case 'S': + if (strncmp(ep, "SHELL=", 6) == 0) + SET(*didvar, DID_SHELL); + break; + case 'T': + if (strncmp(ep, "TERM=", 5) == 0) + SET(*didvar, DID_TERM); + break; + case 'U': + if (strncmp(ep, "USER=", 5) == 0) + SET(*didvar, DID_USER); + if (strncmp(ep, "USERNAME=", 5) == 0) + SET(*didvar, DID_USERNAME); + break; + } +} + +/* + * Build a new environment and ether clear potentially dangerous + * variables from the old one or start with a clean slate. + * Also adds sudo-specific variables (SUDO_*). + */ +void +rebuild_env(void) +{ + char **old_envp, **ep, *cp, *ps1; + char idbuf[MAX_UID_T_LEN]; + unsigned int didvar; + bool reset_home = false; + + /* + * Either clean out the environment or reset to a safe default. + */ + ps1 = NULL; + didvar = 0; + env.env_len = 0; + env.env_size = 128; + old_envp = env.envp; + env.envp = emalloc2(env.env_size, sizeof(char *)); +#ifdef ENV_DEBUG + memset(env.envp, 0, env.env_size * sizeof(char *)); +#else + env.envp[0] = NULL; +#endif + + /* Reset HOME based on target user if configured to. */ + if (ISSET(sudo_mode, MODE_RUN)) { + if (def_always_set_home || + ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || + (ISSET(sudo_mode, MODE_SHELL) && def_set_home)) + reset_home = true; + } + + if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + /* + * If starting with a fresh environment, initialize it based on + * /etc/environment or login.conf. For "sudo -i" we want those + * variables to override the invoking user's environment, so we + * defer reading them until later. + */ + if (!ISSET(sudo_mode, MODE_LOGIN_SHELL)) { +#ifdef HAVE_LOGIN_CAP_H + /* Insert login class environment variables. */ + if (login_class) { + login_cap_t *lc = login_getclass(login_class); + if (lc != NULL) { + setusercontext(lc, runas_pw, runas_pw->pw_uid, + LOGIN_SETPATH|LOGIN_SETENV); + login_close(lc); + } + } +#endif /* HAVE_LOGIN_CAP_H */ +#if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM)) + /* Insert system-wide environment variables. */ + read_env_file(_PATH_ENVIRONMENT, true); +#endif + for (ep = env.envp; *ep; ep++) + env_update_didvar(*ep, &didvar); + } + + /* 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++) { + bool keepit; + + /* Skip variables with values beginning with () (bash functions) */ + if ((cp = strchr(*ep, '=')) != NULL) { + if (strncmp(cp, "=() ", 3) == 0) + continue; + } + + /* + * Look up the variable in the env_check and env_keep lists. + */ + keepit = env_should_keep(*ep); + + /* + * Do SUDO_PS1 -> PS1 conversion. + * This must happen *after* env_should_keep() is called. + */ + if (strncmp(*ep, "SUDO_PS1=", 8) == 0) + ps1 = *ep + 5; + + if (keepit) { + /* Preserve variable. */ + sudo_putenv(*ep, false, false); + env_update_didvar(*ep, &didvar); + } + } + didvar |= didvar << 8; /* convert DID_* to KEPT_* */ + + /* + * Add in defaults. In -i mode these come from the runas user, + * otherwise they may be from the user's environment (depends + * on sudoers options). + */ + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + sudo_setenv2("SHELL", runas_pw->pw_shell, + ISSET(didvar, DID_SHELL), true); + sudo_setenv2("LOGNAME", runas_pw->pw_name, + ISSET(didvar, DID_LOGNAME), true); + sudo_setenv2("USER", runas_pw->pw_name, + ISSET(didvar, DID_USER), true); + sudo_setenv2("USERNAME", runas_pw->pw_name, + ISSET(didvar, DID_USERNAME), true); + } else { + if (!ISSET(didvar, DID_SHELL)) + sudo_setenv2("SHELL", sudo_user.pw->pw_shell, false, true); + if (!ISSET(didvar, DID_LOGNAME)) + sudo_setenv2("LOGNAME", user_name, false, true); + if (!ISSET(didvar, DID_USER)) + sudo_setenv2("USER", user_name, false, true); + if (!ISSET(didvar, DID_USERNAME)) + sudo_setenv2("USERNAME", user_name, false, true); + } + + /* If we didn't keep HOME, reset it based on target user. */ + if (!ISSET(didvar, KEPT_HOME)) + reset_home = true; + + /* + * Set MAIL to target user in -i mode or if MAIL is not preserved + * from user's environment. + */ + if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) { + cp = _PATH_MAILDIR; + if (cp[sizeof(_PATH_MAILDIR) - 2] == '/') + easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name); + else + easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name); + sudo_putenv(cp, ISSET(didvar, DID_MAIL), true); + } + } else { + /* + * Copy environ entries as long as they don't match env_delete or + * env_check. + */ + for (ep = old_envp; *ep; ep++) { + /* Skip variables with values beginning with () (bash functions) */ + if ((cp = strchr(*ep, '=')) != NULL) { + if (strncmp(cp, "=() ", 3) == 0) + continue; + } + + /* Add variable unless it matches a black list. */ + if (!env_should_delete(*ep)) { + if (strncmp(*ep, "SUDO_PS1=", 9) == 0) + ps1 = *ep + 5; + else if (strncmp(*ep, "PATH=", 5) == 0) + SET(didvar, DID_PATH); + else if (strncmp(*ep, "TERM=", 5) == 0) + SET(didvar, DID_TERM); + sudo_putenv(*ep, false, false); + } + } + } + /* Replace the PATH envariable with a secure one? */ + if (def_secure_path && !user_is_exempt()) { + sudo_setenv2("PATH", def_secure_path, true, true); + SET(didvar, DID_PATH); + } + + /* + * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not + * disabled. We skip this if we are running a login shell (because + * they have already been set them) or sudoedit (because we want the + * editor to find the user's startup files). + */ + if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) { + if (!ISSET(didvar, KEPT_LOGNAME)) + sudo_setenv2("LOGNAME", runas_pw->pw_name, true, true); + if (!ISSET(didvar, KEPT_USER)) + sudo_setenv2("USER", runas_pw->pw_name, true, true); + if (!ISSET(didvar, KEPT_USERNAME)) + sudo_setenv2("USERNAME", runas_pw->pw_name, true, true); + } + + /* Set $HOME to target user if not preserving user's value. */ + if (reset_home) + sudo_setenv2("HOME", runas_pw->pw_dir, true, true); + + /* Provide default values for $TERM and $PATH if they are not set. */ + if (!ISSET(didvar, DID_TERM)) + sudo_putenv("TERM=unknown", false, false); + if (!ISSET(didvar, DID_PATH)) + sudo_setenv2("PATH", _PATH_STDPATH, false, true); + + /* Set PS1 if SUDO_PS1 is set. */ + if (ps1 != NULL) + sudo_putenv(ps1, true, true); + + /* Add the SUDO_COMMAND envariable (cmnd + args). */ + if (user_args) { + easprintf(&cp, "%s %s", user_cmnd, user_args); + sudo_setenv2("SUDO_COMMAND", cp, true, true); + efree(cp); + } else { + sudo_setenv2("SUDO_COMMAND", user_cmnd, true, true); + } + + /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */ + sudo_setenv2("SUDO_USER", user_name, true, true); + snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid); + sudo_setenv2("SUDO_UID", idbuf, true, true); + snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid); + sudo_setenv2("SUDO_GID", idbuf, true, true); + + /* Free old environment. */ + efree(old_envp); +} + +void +insert_env_vars(char * const envp[]) +{ + char * const *ep; + + if (envp == NULL) + return; + + /* Add user-specified environment variables. */ + for (ep = envp; *ep != NULL; ep++) + sudo_putenv(*ep, true, true); +} + +/* + * Validate the list of environment variables passed in on the command + * line against env_delete, env_check, and env_keep. + * Calls log_fatal() if any specified variables are not allowed. + */ +void +validate_env_vars(char * const env_vars[]) +{ + char * const *ep; + char *eq, *bad = NULL; + size_t len, blen = 0, bsize = 0; + bool okvar; + + if (env_vars == NULL) + return; + + /* Add user-specified environment variables. */ + for (ep = env_vars; *ep != NULL; ep++) { + if (def_secure_path && !user_is_exempt() && + strncmp(*ep, "PATH=", 5) == 0) { + okvar = false; + } else if (def_env_reset) { + okvar = env_should_keep(*ep); + } else { + okvar = !env_should_delete(*ep); + } + if (okvar == false) { + /* Not allowed, add to error string, allocating as needed. */ + if ((eq = strchr(*ep, '=')) != NULL) + *eq = '\0'; + len = strlen(*ep) + 2; + if (blen + len >= bsize) { + do { + bsize += 1024; + } while (blen + len >= bsize); + bad = erealloc(bad, bsize); + bad[blen] = '\0'; + } + strlcat(bad, *ep, bsize); + strlcat(bad, ", ", bsize); + blen += len; + if (eq != NULL) + *eq = '='; + } + } + if (bad != NULL) { + bad[blen - 2] = '\0'; /* remove trailing ", " */ + log_fatal(NO_MAIL, + _("sorry, you are not allowed to set the following environment variables: %s"), bad); + /* NOTREACHED */ + efree(bad); + } +} + +/* + * Read in /etc/environment ala AIX and Linux. + * Lines may be in either of three formats: + * NAME=VALUE + * NAME="VALUE" + * NAME='VALUE' + * with an optional "export" prefix so the shell can source the file. + * Invalid lines, blank lines, or lines consisting solely of a comment + * character are skipped. + */ +void +read_env_file(const char *path, int overwrite) +{ + FILE *fp; + char *cp, *var, *val; + size_t var_len, val_len; + + if ((fp = fopen(path, "r")) == NULL) + return; + + while ((var = sudo_parseln(fp)) != NULL) { + /* Skip blank or comment lines */ + if (*var == '\0') + continue; + + /* Skip optional "export " */ + if (strncmp(var, "export", 6) == 0 && isspace((unsigned char) var[6])) { + var += 7; + while (isspace((unsigned char) *var)) { + var++; + } + } + + /* Must be of the form name=["']value['"] */ + for (val = var; *val != '\0' && *val != '='; val++) + ; + if (var == val || *val != '=') + continue; + var_len = (size_t)(val - var); + val_len = strlen(++val); + + /* Strip leading and trailing single/double quotes */ + if ((val[0] == '\'' || val[0] == '\"') && val[0] == val[val_len - 1]) { + val[val_len - 1] = '\0'; + val++; + val_len -= 2; + } + + cp = emalloc(var_len + 1 + val_len + 1); + memcpy(cp, var, var_len + 1); /* includes '=' */ + memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */ + + sudo_putenv(cp, true, overwrite); + } + fclose(fp); +} + +void +init_envtables(void) +{ + struct list_member *cur; + const char **p; + + /* Fill in the "env_delete" list. */ + for (p = initial_badenv_table; *p; p++) { + cur = ecalloc(1, sizeof(struct list_member)); + cur->value = estrdup(*p); + cur->next = def_env_delete; + def_env_delete = cur; + } + + /* Fill in the "env_check" list. */ + for (p = initial_checkenv_table; *p; p++) { + cur = ecalloc(1, sizeof(struct list_member)); + cur->value = estrdup(*p); + cur->next = def_env_check; + def_env_check = cur; + } + + /* Fill in the "env_keep" list. */ + for (p = initial_keepenv_table; *p; p++) { + cur = ecalloc(1, sizeof(struct list_member)); + cur->value = estrdup(*p); + cur->next = def_env_keep; + def_env_keep = cur; + } +} + +int +sudoers_hook_getenv(const char *name, char **value, void *closure) +{ + static bool in_progress = false; /* avoid recursion */ + + if (in_progress || env.envp == NULL) + return SUDO_HOOK_RET_NEXT; + + in_progress = true; + *value = sudo_getenv_nodebug(name); + in_progress = false; + return SUDO_HOOK_RET_STOP; +} + +int +sudoers_hook_putenv(char *string, void *closure) +{ + static bool in_progress = false; /* avoid recursion */ + + if (in_progress || env.envp == NULL) + return SUDO_HOOK_RET_NEXT; + + in_progress = true; + sudo_putenv_nodebug(string, true, true); + in_progress = false; + return SUDO_HOOK_RET_STOP; +} + +int +sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure) +{ + static bool in_progress = false; /* avoid recursion */ + + if (in_progress || env.envp == NULL) + return SUDO_HOOK_RET_NEXT; + + in_progress = true; + sudo_setenv_nodebug(name, value, overwrite); + in_progress = false; + return SUDO_HOOK_RET_STOP; +} + +int +sudoers_hook_unsetenv(const char *name, void *closure) +{ + static bool in_progress = false; /* avoid recursion */ + + if (in_progress || env.envp == NULL) + return SUDO_HOOK_RET_NEXT; + + in_progress = true; + sudo_unsetenv_nodebug(name); + in_progress = false; + return SUDO_HOOK_RET_STOP; +} diff --git a/plugins/sudoers/find_path.c b/plugins/sudoers/find_path.c new file mode 100644 index 0000000..208b88e --- /dev/null +++ b/plugins/sudoers/find_path.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1996, 1998-2005, 2010-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. + * + * 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 +#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 */ +#include + +#include "sudoers.h" + +/* + * This function finds the full pathname for a command and + * stores it in a statically allocated array, filling in a pointer + * to the array. Returns FOUND if the command was found, NOT_FOUND + * if it was not found, or NOT_FOUND_DOT if it would have been found + * but it is in '.' and IGNORE_DOT is set. + */ +int +find_path(char *infile, char **outfile, struct stat *sbp, char *path, + int ignore_dot) +{ + static char command[PATH_MAX]; /* qualified filename */ + char *n; /* for traversing path */ + char *origpath; /* so we can free path later */ + bool found = false; /* did we find the command? */ + bool checkdot = false; /* check current dir? */ + int len; /* length parameter */ + debug_decl(find_path, SUDO_DEBUG_UTIL) + + if (strlen(infile) >= PATH_MAX) + errorx(1, _("%s: %s"), infile, strerror(ENAMETOOLONG)); + + /* + * If we were given a fully qualified or relative path + * there is no need to look at $PATH. + */ + if (strchr(infile, '/')) { + strlcpy(command, infile, sizeof(command)); /* paranoia */ + if (sudo_goodpath(command, sbp)) { + *outfile = command; + debug_return_int(FOUND); + } else + debug_return_int(NOT_FOUND); + } + + if (path == NULL) + debug_return_int(NOT_FOUND); + path = estrdup(path); + origpath = path; + + do { + if ((n = strchr(path, ':'))) + *n = '\0'; + + /* + * Search current dir last if it is in PATH This will miss sneaky + * things like using './' or './/' + */ + if (*path == '\0' || (*path == '.' && *(path + 1) == '\0')) { + checkdot = 1; + path = n + 1; + continue; + } + + /* + * Resolve the path and exit the loop if found. + */ + len = snprintf(command, sizeof(command), "%s/%s", path, infile); + if (len <= 0 || len >= sizeof(command)) + errorx(1, _("%s: %s"), infile, strerror(ENAMETOOLONG)); + if ((found = sudo_goodpath(command, sbp))) + break; + + path = n + 1; + + } while (n); + efree(origpath); + + /* + * Check current dir if dot was in the PATH + */ + if (!found && checkdot) { + len = snprintf(command, sizeof(command), "./%s", infile); + if (len <= 0 || len >= sizeof(command)) + errorx(1, _("%s: %s"), infile, strerror(ENAMETOOLONG)); + found = sudo_goodpath(command, sbp); + if (found && ignore_dot) + debug_return_int(NOT_FOUND_DOT); + } + + if (found) { + *outfile = command; + debug_return_int(FOUND); + } else + debug_return_int(NOT_FOUND); +} diff --git a/plugins/sudoers/getdate.c b/plugins/sudoers/getdate.c new file mode 100644 index 0000000..b577e9a --- /dev/null +++ b/plugins/sudoers/getdate.c @@ -0,0 +1,1596 @@ +#include +#include +#include +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +#define YYPREFIX "yy" +#line 2 "getdate.y" +/* +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990; +** +** This grammar has 10 shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#include + +#include "missing.h" + + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; + + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +static int yyerror(char *s); +static int yylex(void); + int yyparse(void); + +#line 107 "getdate.y" +#ifndef YYSTYPE_DEFINED +#define YYSTYPE_DEFINED +typedef union { + time_t Number; + enum _MERIDIAN Meridian; +} YYSTYPE; +#endif /* YYSTYPE_DEFINED */ +#line 125 "getdate.c" +#define tAGO 257 +#define tDAY 258 +#define tDAYZONE 259 +#define tID 260 +#define tMERIDIAN 261 +#define tMINUTE_UNIT 262 +#define tMONTH 263 +#define tMONTH_UNIT 264 +#define tSEC_UNIT 265 +#define tSNUMBER 266 +#define tUNUMBER 267 +#define tZONE 268 +#define tDST 269 +#define YYERRCODE 256 +#if defined(__cplusplus) || defined(__STDC__) +const short yylhs[] = +#else +short yylhs[] = +#endif + { -1, + 0, 0, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 4, 4, 4, 6, 6, 6, 5, + 5, 5, 5, 5, 5, 5, 5, 7, 7, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 8, 1, + 1, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yylen[] = +#else +short yylen[] = +#endif + { 2, + 0, 2, 1, 1, 1, 1, 1, 1, 2, 4, + 4, 6, 6, 1, 1, 2, 1, 2, 2, 3, + 5, 3, 3, 2, 4, 2, 3, 2, 1, 2, + 2, 1, 2, 2, 1, 2, 2, 1, 1, 0, + 1, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yydefred[] = +#else +short yydefred[] = +#endif + { 1, + 0, 0, 15, 32, 0, 38, 35, 0, 0, 0, + 2, 3, 4, 5, 6, 7, 8, 0, 18, 0, + 31, 36, 33, 19, 9, 30, 0, 37, 34, 0, + 0, 0, 16, 28, 0, 23, 27, 22, 0, 0, + 25, 41, 11, 0, 10, 0, 0, 21, 13, 12, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yydgoto[] = +#else +short yydgoto[] = +#endif + { 1, + 45, 11, 12, 13, 14, 15, 16, 17, 18, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yysindex[] = +#else +short yysindex[] = +#endif + { 0, + -249, -38, 0, 0, -260, 0, 0, -240, -47, -248, + 0, 0, 0, 0, 0, 0, 0, -237, 0, -18, + 0, 0, 0, 0, 0, 0, -262, 0, 0, -239, + -238, -236, 0, 0, -235, 0, 0, 0, -56, -19, + 0, 0, 0, -234, 0, -232, -258, 0, 0, 0,}; +#if defined(__cplusplus) || defined(__STDC__) +const short yyrindex[] = +#else +short yyrindex[] = +#endif + { 0, + 0, 1, 0, 0, 0, 0, 0, 0, 69, 12, + 0, 0, 0, 0, 0, 0, 0, 23, 0, 34, + 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 56, 45, + 0, 0, 0, 0, 0, 0, 56, 0, 0, 0,}; +#if defined(__cplusplus) || defined(__STDC__) +const short yygindex[] = +#else +short yygindex[] = +#endif + { 0, + -17, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define YYTABLESIZE 337 +#if defined(__cplusplus) || defined(__STDC__) +const short yytable[] = +#else +short yytable[] = +#endif + { 32, + 17, 44, 42, 36, 37, 19, 20, 49, 2, 3, + 31, 14, 4, 5, 6, 7, 8, 9, 10, 34, + 33, 21, 29, 22, 23, 35, 38, 46, 39, 50, + 40, 41, 47, 24, 48, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 26, 0, 39, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 0, 0, 0, 0, 43, + 24, 0, 0, 25, 26, 27, 28, 29, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, + 0, 0, 17, 17, 17, 17, 17, 17, 17, 14, + 14, 0, 0, 14, 14, 14, 14, 14, 14, 14, + 29, 29, 0, 0, 29, 29, 29, 29, 29, 29, + 29, 24, 24, 0, 0, 24, 24, 24, 24, 24, + 24, 24, 20, 20, 0, 0, 20, 20, 20, 20, + 20, 20, 20, 40, 40, 0, 0, 40, 40, 40, + 40, 0, 40, 40, 26, 26, 0, 39, 26, 26, + 26, 26, 0, 0, 26, 39, 39, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yycheck[] = +#else +short yycheck[] = +#endif + { 47, + 0, 58, 261, 266, 267, 44, 267, 266, 258, 259, + 58, 0, 262, 263, 264, 265, 266, 267, 268, 257, + 269, 262, 0, 264, 265, 44, 266, 47, 267, 47, + 267, 267, 267, 0, 267, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, -1, 0, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 261, -1, -1, -1, -1, 266, + 258, -1, -1, 261, 262, 263, 264, 265, 266, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 258, 259, + -1, -1, 262, 263, 264, 265, 266, 267, 268, 258, + 259, -1, -1, 262, 263, 264, 265, 266, 267, 268, + 258, 259, -1, -1, 262, 263, 264, 265, 266, 267, + 268, 258, 259, -1, -1, 262, 263, 264, 265, 266, + 267, 268, 258, 259, -1, -1, 262, 263, 264, 265, + 266, 267, 268, 258, 259, -1, -1, 262, 263, 264, + 265, -1, 267, 268, 258, 259, -1, 259, 262, 263, + 264, 265, -1, -1, 268, 267, 268, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 269 +#if YYDEBUG +#if defined(__cplusplus) || defined(__STDC__) +const char * const yyname[] = +#else +char *yyname[] = +#endif + { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,"','",0,0,"'/'",0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"tAGO","tDAY", +"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT", +"tSNUMBER","tUNUMBER","tZONE","tDST", +}; +#if defined(__cplusplus) || defined(__STDC__) +const char * const yyrule[] = +#else +char *yyrule[] = +#endif + {"$accept : spec", +"spec :", +"spec : spec item", +"item : time", +"item : zone", +"item : date", +"item : day", +"item : rel", +"item : number", +"time : tUNUMBER tMERIDIAN", +"time : tUNUMBER ':' tUNUMBER o_merid", +"time : tUNUMBER ':' tUNUMBER tSNUMBER", +"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid", +"time : tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER", +"zone : tZONE", +"zone : tDAYZONE", +"zone : tZONE tDST", +"day : tDAY", +"day : tDAY ','", +"day : tUNUMBER tDAY", +"date : tUNUMBER '/' tUNUMBER", +"date : tUNUMBER '/' tUNUMBER '/' tUNUMBER", +"date : tUNUMBER tSNUMBER tSNUMBER", +"date : tUNUMBER tMONTH tSNUMBER", +"date : tMONTH tUNUMBER", +"date : tMONTH tUNUMBER ',' tUNUMBER", +"date : tUNUMBER tMONTH", +"date : tUNUMBER tMONTH tUNUMBER", +"rel : relunit tAGO", +"rel : relunit", +"relunit : tUNUMBER tMINUTE_UNIT", +"relunit : tSNUMBER tMINUTE_UNIT", +"relunit : tMINUTE_UNIT", +"relunit : tSNUMBER tSEC_UNIT", +"relunit : tUNUMBER tSEC_UNIT", +"relunit : tSEC_UNIT", +"relunit : tSNUMBER tMONTH_UNIT", +"relunit : tUNUMBER tMONTH_UNIT", +"relunit : tMONTH_UNIT", +"number : tUNUMBER", +"o_merid :", +"o_merid : tMERIDIAN", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +/* LINTUSED */ +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +int yystacksize; +#line 326 "getdate.y" + +/* Month and day table. */ +static TABLE const MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL } +}; + +/* Time units table. */ +static TABLE const UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, + { "week", tMINUTE_UNIT, 7 * 24 * 60 }, + { "day", tMINUTE_UNIT, 1 * 24 * 60 }, + { "hour", tMINUTE_UNIT, 60 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL } +}; + +/* Assorted relative-time words. */ +static TABLE const OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 2 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL } +}; + +/* The timezone table. */ +/* Some of these are commented out because a time_t can't store a float. */ +static TABLE const TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR( 0) }, + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "wat", tZONE, HOUR( 1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR(11) }, /* Nome */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR(3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Stanard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { NULL } +}; + +/* Military timezone table. */ +static TABLE const MilitaryTable[] = { + { "a", tZONE, HOUR( 1) }, + { "b", tZONE, HOUR( 2) }, + { "c", tZONE, HOUR( 3) }, + { "d", tZONE, HOUR( 4) }, + { "e", tZONE, HOUR( 5) }, + { "f", tZONE, HOUR( 6) }, + { "g", tZONE, HOUR( 7) }, + { "h", tZONE, HOUR( 8) }, + { "i", tZONE, HOUR( 9) }, + { "k", tZONE, HOUR( 10) }, + { "l", tZONE, HOUR( 11) }, + { "m", tZONE, HOUR( 12) }, + { "n", tZONE, HOUR(- 1) }, + { "o", tZONE, HOUR(- 2) }, + { "p", tZONE, HOUR(- 3) }, + { "q", tZONE, HOUR(- 4) }, + { "r", tZONE, HOUR(- 5) }, + { "s", tZONE, HOUR(- 6) }, + { "t", tZONE, HOUR(- 7) }, + { "u", tZONE, HOUR(- 8) }, + { "v", tZONE, HOUR(- 9) }, + { "w", tZONE, HOUR(-10) }, + { "x", tZONE, HOUR(-11) }, + { "y", tZONE, HOUR(-12) }, + { "z", tZONE, HOUR( 0) }, + { NULL } +}; + + + + +/* ARGSUSED */ +static int +yyerror(s) + char *s; +{ + return 0; +} + + +static time_t +ToSeconds(Hours, Minutes, Seconds, Meridian) + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + switch (Meridian) { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; + default: + abort (); + } + /* NOTREACHED */ +} + + +/* Year is either + * A negative number, which means to use its absolute value (why?) + * A number from 0 to 99, which means a year from 1900 to 1999, or + * The actual year (>=100). */ +static time_t +Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) + time_t Month; + time_t Day; + time_t Year; + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; + DSTMODE DSTmode; +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + int i; + + if (Year < 0) + Year = -Year; + if (Year < 69) + Year += 2000; + else if (Year < 100) { + Year += 1900; + if (Year < EPOCH) + Year += 100; + } + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + /* Checking for 2038 bogusly assumes that time_t is 32 bits. But + I'm too lazy to try to check for time_t overflow in another way. */ + if (Year < EPOCH || Year > 2038 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + for (Julian = Day - 1, i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(Start, Future) + time_t Start; + time_t Future; +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(Start, DayOrdinal, DayNumber) + time_t Start; + time_t DayOrdinal; + time_t DayNumber; +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(Start, RelMonth) + time_t Start; + time_t RelMonth; +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord(buff) + char *buff; +{ + char *p; + char *q; + const TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (isupper((unsigned char)*p)) + *p = tolower((unsigned char)*p); + + if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen(buff) == 3) + abbrev = 1; + else if (strlen(buff) == 4 && buff[3] == '.') { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) { + if (abbrev) { + if (strncmp(buff, tp->name, 3) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen(buff) - 1; + if (buff[i] == 's') { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + + +static int +yylex() +{ + char c; + char *p; + char buff[20]; + int Count; + int sign; + + for ( ; ; ) { + while (isspace((unsigned char)*yyInput)) + yyInput++; + + if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + if (!isdigit((unsigned char)*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (isalpha((unsigned char)c)) { + for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; ) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord(buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (a, b) + struct tm *a, *b; +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + int days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay/100 - by/100) + + ((ay/100 >> 2) - (by/100 >> 2)) + /* + difference in years * 365 */ + + (long)(ay-by) * 365 + ); + return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date(p) + char *p; +{ + struct tm *tm, *gmt, gmtbuf; + time_t Start; + time_t tod; + time_t now; + time_t timezone; + + yyInput = p; + (void)time (&now); + + gmt = gmtime (&now); + if (gmt != NULL) + { + /* Make a copy, in case localtime modifies *tm (I think + that comment now applies to *gmt, but I am too + lazy to dig into how gmtime and locatime allocate the + structures they return pointers to). */ + gmtbuf = *gmt; + gmt = &gmtbuf; + } + + if (! (tm = localtime (&now))) + return -1; + + if (gmt != NULL) + timezone = difftm (gmt, tm) / 60; + else + /* We are on a system like VMS, where the system clock is + in local time and the system has no concept of timezones. + Hopefully we can fake this out (for the case in which the + user specifies no timezone) by just saying the timezone + is zero. */ + timezone = 0; + + if(tm->tm_isdst) + timezone += 60; + + tm = localtime(&now); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = timezone; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +int +main(ac, av) + int ac; + char *av[]; +{ + char buff[128]; + time_t d; + + (void)printf("Enter date, or blank line to exit.\n\t> "); + (void)fflush(stdout); + while (gets(buff) && buff[0]) { + d = get_date(buff); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("%s", ctime(&d)); + (void)printf("\t> "); + (void)fflush(stdout); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ +#line 979 "getdate.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +#if defined(__cplusplus) || defined(__STDC__) +static int yygrowstack(void) +#else +static int yygrowstack() +#endif +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + i = yyssp - yyss; +#ifdef SIZE_MAX +#define YY_SIZE_MAX SIZE_MAX +#else +#define YY_SIZE_MAX 0x7fffffff +#endif + if (!newsize || YY_SIZE_MAX / newsize < sizeof *newss) + goto bail; + newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : + (short *)malloc(newsize * sizeof *newss); /* overflow check above */ + if (newss == NULL) + goto bail; + yyss = newss; + yyssp = newss + i; + if (!newsize || YY_SIZE_MAX / newsize < sizeof *newvs) + goto bail; + newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : + (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */ + if (newvs == NULL) + goto bail; + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +bail: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return -1; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +#if defined(__cplusplus) || defined(__STDC__) +yyparse(void) +#else +yyparse() +#endif +{ + int yym, yyn, yystate; +#if YYDEBUG +#if defined(__cplusplus) || defined(__STDC__) + const char *yys; +#else /* !(defined(__cplusplus) || defined(__STDC__)) */ + char *yys; +#endif /* !(defined(__cplusplus) || defined(__STDC__)) */ + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif /* YYDEBUG */ + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + if (yym) + yyval = yyvsp[1-yym]; + else + memset(&yyval, 0, sizeof yyval); + switch (yyn) + { +case 3: +#line 125 "getdate.y" +{ + yyHaveTime++; + } +break; +case 4: +#line 128 "getdate.y" +{ + yyHaveZone++; + } +break; +case 5: +#line 131 "getdate.y" +{ + yyHaveDate++; + } +break; +case 6: +#line 134 "getdate.y" +{ + yyHaveDay++; + } +break; +case 7: +#line 137 "getdate.y" +{ + yyHaveRel++; + } +break; +case 9: +#line 143 "getdate.y" +{ + yyHour = yyvsp[-1].Number; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + } +break; +case 10: +#line 149 "getdate.y" +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yySeconds = 0; + yyMeridian = yyvsp[0].Meridian; + } +break; +case 11: +#line 155 "getdate.y" +{ + yyHour = yyvsp[-3].Number; + yyMinutes = yyvsp[-1].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); + } +break; +case 12: +#line 162 "getdate.y" +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = yyvsp[0].Meridian; + } +break; +case 13: +#line 168 "getdate.y" +{ + yyHour = yyvsp[-5].Number; + yyMinutes = yyvsp[-3].Number; + yySeconds = yyvsp[-1].Number; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60); + } +break; +case 14: +#line 178 "getdate.y" +{ + yyTimezone = yyvsp[0].Number; + yyDSTmode = DSToff; + } +break; +case 15: +#line 182 "getdate.y" +{ + yyTimezone = yyvsp[0].Number; + yyDSTmode = DSTon; + } +break; +case 16: +#line 187 "getdate.y" +{ + yyTimezone = yyvsp[-1].Number; + yyDSTmode = DSTon; + } +break; +case 17: +#line 193 "getdate.y" +{ + yyDayOrdinal = 1; + yyDayNumber = yyvsp[0].Number; + } +break; +case 18: +#line 197 "getdate.y" +{ + yyDayOrdinal = 1; + yyDayNumber = yyvsp[-1].Number; + } +break; +case 19: +#line 201 "getdate.y" +{ + yyDayOrdinal = yyvsp[-1].Number; + yyDayNumber = yyvsp[0].Number; + } +break; +case 20: +#line 207 "getdate.y" +{ + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } +break; +case 21: +#line 211 "getdate.y" +{ + if (yyvsp[-4].Number >= 100) { + yyYear = yyvsp[-4].Number; + yyMonth = yyvsp[-2].Number; + yyDay = yyvsp[0].Number; + } else { + yyMonth = yyvsp[-4].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } + } +break; +case 22: +#line 222 "getdate.y" +{ + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = yyvsp[-2].Number; + yyMonth = -yyvsp[-1].Number; + yyDay = -yyvsp[0].Number; + } +break; +case 23: +#line 228 "getdate.y" +{ + /* e.g. 17-JUN-1992. */ + yyDay = yyvsp[-2].Number; + yyMonth = yyvsp[-1].Number; + yyYear = -yyvsp[0].Number; + } +break; +case 24: +#line 234 "getdate.y" +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[0].Number; + } +break; +case 25: +#line 238 "getdate.y" +{ + yyMonth = yyvsp[-3].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } +break; +case 26: +#line 243 "getdate.y" +{ + yyMonth = yyvsp[0].Number; + yyDay = yyvsp[-1].Number; + } +break; +case 27: +#line 247 "getdate.y" +{ + yyMonth = yyvsp[-1].Number; + yyDay = yyvsp[-2].Number; + yyYear = yyvsp[0].Number; + } +break; +case 28: +#line 254 "getdate.y" +{ + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } +break; +case 30: +#line 261 "getdate.y" +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; + } +break; +case 31: +#line 264 "getdate.y" +{ + yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L; + } +break; +case 32: +#line 267 "getdate.y" +{ + yyRelSeconds += yyvsp[0].Number * 60L; + } +break; +case 33: +#line 270 "getdate.y" +{ + yyRelSeconds += yyvsp[-1].Number; + } +break; +case 34: +#line 273 "getdate.y" +{ + yyRelSeconds += yyvsp[-1].Number; + } +break; +case 35: +#line 276 "getdate.y" +{ + yyRelSeconds++; + } +break; +case 36: +#line 279 "getdate.y" +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 37: +#line 282 "getdate.y" +{ + yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; + } +break; +case 38: +#line 285 "getdate.y" +{ + yyRelMonth += yyvsp[0].Number; + } +break; +case 39: +#line 290 "getdate.y" +{ + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = yyvsp[0].Number; + else { + if(yyvsp[0].Number>10000) { + yyHaveDate++; + yyDay= (yyvsp[0].Number)%100; + yyMonth= (yyvsp[0].Number/100)%100; + yyYear = yyvsp[0].Number/10000; + } + else { + yyHaveTime++; + if (yyvsp[0].Number < 100) { + yyHour = yyvsp[0].Number; + yyMinutes = 0; + } + else { + yyHour = yyvsp[0].Number / 100; + yyMinutes = yyvsp[0].Number % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + } +break; +case 40: +#line 317 "getdate.y" +{ + yyval.Meridian = MER24; + } +break; +case 41: +#line 320 "getdate.y" +{ + yyval.Meridian = yyvsp[0].Meridian; + } +break; +#line 1474 "getdate.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return (1); +yyaccept: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return (0); +} diff --git a/plugins/sudoers/getdate.y b/plugins/sudoers/getdate.y new file mode 100644 index 0000000..5ebe29e --- /dev/null +++ b/plugins/sudoers/getdate.y @@ -0,0 +1,962 @@ +%{ +/* +** Originally written by Steven M. Bellovin while +** at the University of North Carolina at Chapel Hill. Later tweaked by +** a couple of people on Usenet. Completely overhauled by Rich $alz +** and Jim Berets in August, 1990; +** +** This grammar has 10 shift/reduce conflicts. +** +** This code is in the public domain and has no copyright. +*/ +/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */ +/* SUPPRESS 288 on yyerrlab *//* Label unused */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#include + +#include "missing.h" + + +#define EPOCH 1970 +#define HOUR(x) ((time_t)(x) * 60) +#define SECSPERDAY (24L * 60L * 60L) + + +/* +** An entry in the lexical lookup table. +*/ +typedef struct _TABLE { + char *name; + int type; + time_t value; +} TABLE; + + +/* +** Daylight-savings mode: on, off, or not yet known. +*/ +typedef enum _DSTMODE { + DSTon, DSToff, DSTmaybe +} DSTMODE; + +/* +** Meridian: am, pm, or 24-hour style. +*/ +typedef enum _MERIDIAN { + MERam, MERpm, MER24 +} MERIDIAN; + + +/* +** Global variables. We could get rid of most of these by using a good +** union as the yacc stack. (This routine was originally written before +** yacc had the %union construct.) Maybe someday; right now we only use +** the %union very rarely. +*/ +static char *yyInput; +static DSTMODE yyDSTmode; +static time_t yyDayOrdinal; +static time_t yyDayNumber; +static int yyHaveDate; +static int yyHaveDay; +static int yyHaveRel; +static int yyHaveTime; +static int yyHaveZone; +static time_t yyTimezone; +static time_t yyDay; +static time_t yyHour; +static time_t yyMinutes; +static time_t yyMonth; +static time_t yySeconds; +static time_t yyYear; +static MERIDIAN yyMeridian; +static time_t yyRelMonth; +static time_t yyRelSeconds; + +static int yyerror(char *s); +static int yylex(void); + int yyparse(void); + +%} + +%union { + time_t Number; + enum _MERIDIAN Meridian; +} + +%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT +%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST + +%type tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT +%type tSEC_UNIT tSNUMBER tUNUMBER tZONE +%type tMERIDIAN o_merid + +%% + +spec : /* NULL */ + | spec item + ; + +item : time { + yyHaveTime++; + } + | zone { + yyHaveZone++; + } + | date { + yyHaveDate++; + } + | day { + yyHaveDay++; + } + | rel { + yyHaveRel++; + } + | number + ; + +time : tUNUMBER tMERIDIAN { + yyHour = $1; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = $2; + } + | tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = 0; + yyMeridian = $4; + } + | tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($4 % 100 + ($4 / 100) * 60); + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = $6; + } + | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { + yyHour = $1; + yyMinutes = $3; + yySeconds = $5; + yyMeridian = MER24; + yyDSTmode = DSToff; + yyTimezone = - ($6 % 100 + ($6 / 100) * 60); + } + ; + +zone : tZONE { + yyTimezone = $1; + yyDSTmode = DSToff; + } + | tDAYZONE { + yyTimezone = $1; + yyDSTmode = DSTon; + } + | + tZONE tDST { + yyTimezone = $1; + yyDSTmode = DSTon; + } + ; + +day : tDAY { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tDAY ',' { + yyDayOrdinal = 1; + yyDayNumber = $1; + } + | tUNUMBER tDAY { + yyDayOrdinal = $1; + yyDayNumber = $2; + } + ; + +date : tUNUMBER '/' tUNUMBER { + yyMonth = $1; + yyDay = $3; + } + | tUNUMBER '/' tUNUMBER '/' tUNUMBER { + if ($1 >= 100) { + yyYear = $1; + yyMonth = $3; + yyDay = $5; + } else { + yyMonth = $1; + yyDay = $3; + yyYear = $5; + } + } + | tUNUMBER tSNUMBER tSNUMBER { + /* ISO 8601 format. yyyy-mm-dd. */ + yyYear = $1; + yyMonth = -$2; + yyDay = -$3; + } + | tUNUMBER tMONTH tSNUMBER { + /* e.g. 17-JUN-1992. */ + yyDay = $1; + yyMonth = $2; + yyYear = -$3; + } + | tMONTH tUNUMBER { + yyMonth = $1; + yyDay = $2; + } + | tMONTH tUNUMBER ',' tUNUMBER { + yyMonth = $1; + yyDay = $2; + yyYear = $4; + } + | tUNUMBER tMONTH { + yyMonth = $2; + yyDay = $1; + } + | tUNUMBER tMONTH tUNUMBER { + yyMonth = $2; + yyDay = $1; + yyYear = $3; + } + ; + +rel : relunit tAGO { + yyRelSeconds = -yyRelSeconds; + yyRelMonth = -yyRelMonth; + } + | relunit + ; + +relunit : tUNUMBER tMINUTE_UNIT { + yyRelSeconds += $1 * $2 * 60L; + } + | tSNUMBER tMINUTE_UNIT { + yyRelSeconds += $1 * $2 * 60L; + } + | tMINUTE_UNIT { + yyRelSeconds += $1 * 60L; + } + | tSNUMBER tSEC_UNIT { + yyRelSeconds += $1; + } + | tUNUMBER tSEC_UNIT { + yyRelSeconds += $1; + } + | tSEC_UNIT { + yyRelSeconds++; + } + | tSNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tUNUMBER tMONTH_UNIT { + yyRelMonth += $1 * $2; + } + | tMONTH_UNIT { + yyRelMonth += $1; + } + ; + +number : tUNUMBER { + if (yyHaveTime && yyHaveDate && !yyHaveRel) + yyYear = $1; + else { + if($1>10000) { + yyHaveDate++; + yyDay= ($1)%100; + yyMonth= ($1/100)%100; + yyYear = $1/10000; + } + else { + yyHaveTime++; + if ($1 < 100) { + yyHour = $1; + yyMinutes = 0; + } + else { + yyHour = $1 / 100; + yyMinutes = $1 % 100; + } + yySeconds = 0; + yyMeridian = MER24; + } + } + } + ; + +o_merid : /* NULL */ { + $$ = MER24; + } + | tMERIDIAN { + $$ = $1; + } + ; + +%% + +/* Month and day table. */ +static TABLE const MonthDayTable[] = { + { "january", tMONTH, 1 }, + { "february", tMONTH, 2 }, + { "march", tMONTH, 3 }, + { "april", tMONTH, 4 }, + { "may", tMONTH, 5 }, + { "june", tMONTH, 6 }, + { "july", tMONTH, 7 }, + { "august", tMONTH, 8 }, + { "september", tMONTH, 9 }, + { "sept", tMONTH, 9 }, + { "october", tMONTH, 10 }, + { "november", tMONTH, 11 }, + { "december", tMONTH, 12 }, + { "sunday", tDAY, 0 }, + { "monday", tDAY, 1 }, + { "tuesday", tDAY, 2 }, + { "tues", tDAY, 2 }, + { "wednesday", tDAY, 3 }, + { "wednes", tDAY, 3 }, + { "thursday", tDAY, 4 }, + { "thur", tDAY, 4 }, + { "thurs", tDAY, 4 }, + { "friday", tDAY, 5 }, + { "saturday", tDAY, 6 }, + { NULL } +}; + +/* Time units table. */ +static TABLE const UnitsTable[] = { + { "year", tMONTH_UNIT, 12 }, + { "month", tMONTH_UNIT, 1 }, + { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 }, + { "week", tMINUTE_UNIT, 7 * 24 * 60 }, + { "day", tMINUTE_UNIT, 1 * 24 * 60 }, + { "hour", tMINUTE_UNIT, 60 }, + { "minute", tMINUTE_UNIT, 1 }, + { "min", tMINUTE_UNIT, 1 }, + { "second", tSEC_UNIT, 1 }, + { "sec", tSEC_UNIT, 1 }, + { NULL } +}; + +/* Assorted relative-time words. */ +static TABLE const OtherTable[] = { + { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 }, + { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 }, + { "today", tMINUTE_UNIT, 0 }, + { "now", tMINUTE_UNIT, 0 }, + { "last", tUNUMBER, -1 }, + { "this", tMINUTE_UNIT, 0 }, + { "next", tUNUMBER, 2 }, + { "first", tUNUMBER, 1 }, +/* { "second", tUNUMBER, 2 }, */ + { "third", tUNUMBER, 3 }, + { "fourth", tUNUMBER, 4 }, + { "fifth", tUNUMBER, 5 }, + { "sixth", tUNUMBER, 6 }, + { "seventh", tUNUMBER, 7 }, + { "eighth", tUNUMBER, 8 }, + { "ninth", tUNUMBER, 9 }, + { "tenth", tUNUMBER, 10 }, + { "eleventh", tUNUMBER, 11 }, + { "twelfth", tUNUMBER, 12 }, + { "ago", tAGO, 1 }, + { NULL } +}; + +/* The timezone table. */ +/* Some of these are commented out because a time_t can't store a float. */ +static TABLE const TimezoneTable[] = { + { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */ + { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */ + { "utc", tZONE, HOUR( 0) }, + { "wet", tZONE, HOUR( 0) }, /* Western European */ + { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */ + { "wat", tZONE, HOUR( 1) }, /* West Africa */ + { "at", tZONE, HOUR( 2) }, /* Azores */ +#if 0 + /* For completeness. BST is also British Summer, and GST is + * also Guam Standard. */ + { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */ + { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */ +#endif +#if 0 + { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */ + { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */ + { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ +#endif + { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */ + { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ + { "est", tZONE, HOUR( 5) }, /* Eastern Standard */ + { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ + { "cst", tZONE, HOUR( 6) }, /* Central Standard */ + { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */ + { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */ + { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ + { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */ + { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ + { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */ + { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ + { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */ + { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ + { "cat", tZONE, HOUR(10) }, /* Central Alaska */ + { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ + { "nt", tZONE, HOUR(11) }, /* Nome */ + { "idlw", tZONE, HOUR(12) }, /* International Date Line West */ + { "cet", tZONE, -HOUR(1) }, /* Central European */ + { "met", tZONE, -HOUR(1) }, /* Middle European */ + { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */ + { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */ + { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */ + { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */ + { "fwt", tZONE, -HOUR(1) }, /* French Winter */ + { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */ + { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ + { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ +#if 0 + { "it", tZONE, -HOUR(3.5) },/* Iran */ +#endif + { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */ + { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */ +#if 0 + { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */ +#endif + { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */ +#if 0 + /* For completeness. NST is also Newfoundland Stanard, and SST is + * also Swedish Summer. */ + { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */ + { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ +#endif /* 0 */ + { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */ + { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ +#if 0 + { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ +#endif + { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ + { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ +#if 0 + { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */ + { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ +#endif + { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */ + { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ + { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ + { "nzt", tZONE, -HOUR(12) }, /* New Zealand */ + { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */ + { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ + { "idle", tZONE, -HOUR(12) }, /* International Date Line East */ + { NULL } +}; + +/* Military timezone table. */ +static TABLE const MilitaryTable[] = { + { "a", tZONE, HOUR( 1) }, + { "b", tZONE, HOUR( 2) }, + { "c", tZONE, HOUR( 3) }, + { "d", tZONE, HOUR( 4) }, + { "e", tZONE, HOUR( 5) }, + { "f", tZONE, HOUR( 6) }, + { "g", tZONE, HOUR( 7) }, + { "h", tZONE, HOUR( 8) }, + { "i", tZONE, HOUR( 9) }, + { "k", tZONE, HOUR( 10) }, + { "l", tZONE, HOUR( 11) }, + { "m", tZONE, HOUR( 12) }, + { "n", tZONE, HOUR(- 1) }, + { "o", tZONE, HOUR(- 2) }, + { "p", tZONE, HOUR(- 3) }, + { "q", tZONE, HOUR(- 4) }, + { "r", tZONE, HOUR(- 5) }, + { "s", tZONE, HOUR(- 6) }, + { "t", tZONE, HOUR(- 7) }, + { "u", tZONE, HOUR(- 8) }, + { "v", tZONE, HOUR(- 9) }, + { "w", tZONE, HOUR(-10) }, + { "x", tZONE, HOUR(-11) }, + { "y", tZONE, HOUR(-12) }, + { "z", tZONE, HOUR( 0) }, + { NULL } +}; + + + + +/* ARGSUSED */ +static int +yyerror(s) + char *s; +{ + return 0; +} + + +static time_t +ToSeconds(Hours, Minutes, Seconds, Meridian) + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; +{ + if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59) + return -1; + switch (Meridian) { + case MER24: + if (Hours < 0 || Hours > 23) + return -1; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERam: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return (Hours * 60L + Minutes) * 60L + Seconds; + case MERpm: + if (Hours < 1 || Hours > 12) + return -1; + if (Hours == 12) + Hours = 0; + return ((Hours + 12) * 60L + Minutes) * 60L + Seconds; + default: + abort (); + } + /* NOTREACHED */ +} + + +/* Year is either + * A negative number, which means to use its absolute value (why?) + * A number from 0 to 99, which means a year from 1900 to 1999, or + * The actual year (>=100). */ +static time_t +Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode) + time_t Month; + time_t Day; + time_t Year; + time_t Hours; + time_t Minutes; + time_t Seconds; + MERIDIAN Meridian; + DSTMODE DSTmode; +{ + static int DaysInMonth[12] = { + 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + time_t tod; + time_t Julian; + int i; + + if (Year < 0) + Year = -Year; + if (Year < 69) + Year += 2000; + else if (Year < 100) { + Year += 1900; + if (Year < EPOCH) + Year += 100; + } + DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) + ? 29 : 28; + /* Checking for 2038 bogusly assumes that time_t is 32 bits. But + I'm too lazy to try to check for time_t overflow in another way. */ + if (Year < EPOCH || Year > 2038 + || Month < 1 || Month > 12 + /* Lint fluff: "conversion from long may lose accuracy" */ + || Day < 1 || Day > DaysInMonth[(int)--Month]) + return -1; + + for (Julian = Day - 1, i = 0; i < Month; i++) + Julian += DaysInMonth[i]; + for (i = EPOCH; i < Year; i++) + Julian += 365 + (i % 4 == 0); + Julian *= SECSPERDAY; + Julian += yyTimezone * 60L; + if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0) + return -1; + Julian += tod; + if (DSTmode == DSTon + || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst)) + Julian -= 60 * 60; + return Julian; +} + + +static time_t +DSTcorrect(Start, Future) + time_t Start; + time_t Future; +{ + time_t StartDay; + time_t FutureDay; + + StartDay = (localtime(&Start)->tm_hour + 1) % 24; + FutureDay = (localtime(&Future)->tm_hour + 1) % 24; + return (Future - Start) + (StartDay - FutureDay) * 60L * 60L; +} + + +static time_t +RelativeDate(Start, DayOrdinal, DayNumber) + time_t Start; + time_t DayOrdinal; + time_t DayNumber; +{ + struct tm *tm; + time_t now; + + now = Start; + tm = localtime(&now); + now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7); + now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1); + return DSTcorrect(Start, now); +} + + +static time_t +RelativeMonth(Start, RelMonth) + time_t Start; + time_t RelMonth; +{ + struct tm *tm; + time_t Month; + time_t Year; + + if (RelMonth == 0) + return 0; + tm = localtime(&Start); + Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth; + Year = Month / 12; + Month = Month % 12 + 1; + return DSTcorrect(Start, + Convert(Month, (time_t)tm->tm_mday, Year, + (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec, + MER24, DSTmaybe)); +} + + +static int +LookupWord(buff) + char *buff; +{ + char *p; + char *q; + const TABLE *tp; + int i; + int abbrev; + + /* Make it lowercase. */ + for (p = buff; *p; p++) + if (isupper((unsigned char)*p)) + *p = tolower((unsigned char)*p); + + if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) { + yylval.Meridian = MERam; + return tMERIDIAN; + } + if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) { + yylval.Meridian = MERpm; + return tMERIDIAN; + } + + /* See if we have an abbreviation for a month. */ + if (strlen(buff) == 3) + abbrev = 1; + else if (strlen(buff) == 4 && buff[3] == '.') { + abbrev = 1; + buff[3] = '\0'; + } + else + abbrev = 0; + + for (tp = MonthDayTable; tp->name; tp++) { + if (abbrev) { + if (strncmp(buff, tp->name, 3) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + else if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + if (strcmp(buff, "dst") == 0) + return tDST; + + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Strip off any plural and try the units table again. */ + i = strlen(buff) - 1; + if (buff[i] == 's') { + buff[i] = '\0'; + for (tp = UnitsTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + buff[i] = 's'; /* Put back for "this" in OtherTable. */ + } + + for (tp = OtherTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + /* Military timezones. */ + if (buff[1] == '\0' && isalpha((unsigned char)*buff)) { + for (tp = MilitaryTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + } + + /* Drop out any periods and try the timezone table again. */ + for (i = 0, p = q = buff; *q; q++) + if (*q != '.') + *p++ = *q; + else + i++; + *p = '\0'; + if (i) + for (tp = TimezoneTable; tp->name; tp++) + if (strcmp(buff, tp->name) == 0) { + yylval.Number = tp->value; + return tp->type; + } + + return tID; +} + + +static int +yylex() +{ + char c; + char *p; + char buff[20]; + int Count; + int sign; + + for ( ; ; ) { + while (isspace((unsigned char)*yyInput)) + yyInput++; + + if (isdigit((unsigned char)(c = *yyInput)) || c == '-' || c == '+') { + if (c == '-' || c == '+') { + sign = c == '-' ? -1 : 1; + if (!isdigit((unsigned char)*++yyInput)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + for (yylval.Number = 0; isdigit((unsigned char)(c = *yyInput++)); ) + yylval.Number = 10 * yylval.Number + c - '0'; + yyInput--; + if (sign < 0) + yylval.Number = -yylval.Number; + return sign ? tSNUMBER : tUNUMBER; + } + if (isalpha((unsigned char)c)) { + for (p = buff; isalpha((unsigned char)(c = *yyInput++)) || c == '.'; ) + if (p < &buff[sizeof buff - 1]) + *p++ = c; + *p = '\0'; + yyInput--; + return LookupWord(buff); + } + if (c != '(') + return *yyInput++; + Count = 0; + do { + c = *yyInput++; + if (c == '\0') + return c; + if (c == '(') + Count++; + else if (c == ')') + Count--; + } while (Count > 0); + } +} + +#define TM_YEAR_ORIGIN 1900 + +/* Yield A - B, measured in seconds. */ +static long +difftm (a, b) + struct tm *a, *b; +{ + int ay = a->tm_year + (TM_YEAR_ORIGIN - 1); + int by = b->tm_year + (TM_YEAR_ORIGIN - 1); + int days = ( + /* difference in day of year */ + a->tm_yday - b->tm_yday + /* + intervening leap days */ + + ((ay >> 2) - (by >> 2)) + - (ay/100 - by/100) + + ((ay/100 >> 2) - (by/100 >> 2)) + /* + difference in years * 365 */ + + (long)(ay-by) * 365 + ); + return (60*(60*(24*days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} + +time_t +get_date(p) + char *p; +{ + struct tm *tm, *gmt, gmtbuf; + time_t Start; + time_t tod; + time_t now; + time_t timezone; + + yyInput = p; + (void)time (&now); + + gmt = gmtime (&now); + if (gmt != NULL) + { + /* Make a copy, in case localtime modifies *tm (I think + that comment now applies to *gmt, but I am too + lazy to dig into how gmtime and locatime allocate the + structures they return pointers to). */ + gmtbuf = *gmt; + gmt = &gmtbuf; + } + + if (! (tm = localtime (&now))) + return -1; + + if (gmt != NULL) + timezone = difftm (gmt, tm) / 60; + else + /* We are on a system like VMS, where the system clock is + in local time and the system has no concept of timezones. + Hopefully we can fake this out (for the case in which the + user specifies no timezone) by just saying the timezone + is zero. */ + timezone = 0; + + if(tm->tm_isdst) + timezone += 60; + + tm = localtime(&now); + yyYear = tm->tm_year + 1900; + yyMonth = tm->tm_mon + 1; + yyDay = tm->tm_mday; + yyTimezone = timezone; + yyDSTmode = DSTmaybe; + yyHour = 0; + yyMinutes = 0; + yySeconds = 0; + yyMeridian = MER24; + yyRelSeconds = 0; + yyRelMonth = 0; + yyHaveDate = 0; + yyHaveDay = 0; + yyHaveRel = 0; + yyHaveTime = 0; + yyHaveZone = 0; + + if (yyparse() + || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) + return -1; + + if (yyHaveDate || yyHaveTime || yyHaveDay) { + Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds, + yyMeridian, yyDSTmode); + if (Start < 0) + return -1; + } + else { + Start = now; + if (!yyHaveRel) + Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec; + } + + Start += yyRelSeconds; + Start += RelativeMonth(Start, yyRelMonth); + + if (yyHaveDay && !yyHaveDate) { + tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber); + Start += tod; + } + + /* Have to do *something* with a legitimate -1 so it's distinguishable + * from the error return value. (Alternately could set errno on error.) */ + return Start == -1 ? 0 : Start; +} + + +#if defined(TEST) + +/* ARGSUSED */ +int +main(ac, av) + int ac; + char *av[]; +{ + char buff[128]; + time_t d; + + (void)printf("Enter date, or blank line to exit.\n\t> "); + (void)fflush(stdout); + while (gets(buff) && buff[0]) { + d = get_date(buff); + if (d == -1) + (void)printf("Bad format - couldn't convert.\n"); + else + (void)printf("%s", ctime(&d)); + (void)printf("\t> "); + (void)fflush(stdout); + } + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/plugins/sudoers/getspwuid.c b/plugins/sudoers/getspwuid.c new file mode 100644 index 0000000..e98db83 --- /dev/null +++ b/plugins/sudoers/getspwuid.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 1996, 1998-2005, 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. + */ + +#include + +#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 */ +#include +#include +#ifdef HAVE_GETSPNAM +# include +#endif /* HAVE_GETSPNAM */ +#ifdef HAVE_GETPRPWNAM +# ifdef __hpux +# undef MAXINT +# include +# else +# include +# endif /* __hpux */ +# include +#endif /* HAVE_GETPRPWNAM */ +#ifdef HAVE_GETPWANAM +# include +# include +# include +#endif /* HAVE_GETPWANAM */ +#ifdef HAVE_GETAUTHUID +# include +#endif /* HAVE_GETAUTHUID */ + +#include "sudoers.h" + +/* + * Exported for auth/secureware.c + */ +#if defined(HAVE_GETPRPWNAM) && defined(__alpha) +int crypt_type = INT_MAX; +#endif /* HAVE_GETPRPWNAM && __alpha */ + +/* + * Return a copy of the encrypted password for the user described by pw. + * If shadow passwords are in use, look in the shadow file. + */ +char * +sudo_getepw(const struct passwd *pw) +{ + char *epw = NULL; + debug_decl(sudo_getepw, SUDO_DEBUG_AUTH) + + /* If there is a function to check for shadow enabled, use it... */ +#ifdef HAVE_ISCOMSEC + if (!iscomsec()) + goto done; +#endif /* HAVE_ISCOMSEC */ +#ifdef HAVE_ISSECURE + if (!issecure()) + goto done; +#endif /* HAVE_ISSECURE */ + +#ifdef HAVE_GETPRPWNAM + { + struct pr_passwd *spw; + + if ((spw = getprpwnam(pw->pw_name)) && spw->ufld.fd_encrypt) { +# ifdef __alpha + crypt_type = spw->ufld.fd_oldcrypt; +# endif /* __alpha */ + epw = spw->ufld.fd_encrypt; + } + } +#endif /* HAVE_GETPRPWNAM */ +#ifdef HAVE_GETSPNAM + { + struct spwd *spw; + + if ((spw = getspnam(pw->pw_name)) && spw->sp_pwdp) + epw = spw->sp_pwdp; + } +#endif /* HAVE_GETSPNAM */ +#ifdef HAVE_GETSPWUID + { + struct s_passwd *spw; + + if ((spw = getspwuid(pw->pw_uid)) && spw->pw_passwd) + epw = spw->pw_passwd; + } +#endif /* HAVE_GETSPWUID */ +#ifdef HAVE_GETPWANAM + { + struct passwd_adjunct *spw; + + if ((spw = getpwanam(pw->pw_name)) && spw->pwa_passwd) + epw = spw->pwa_passwd; + } +#endif /* HAVE_GETPWANAM */ +#ifdef HAVE_GETAUTHUID + { + AUTHORIZATION *spw; + + if ((spw = getauthuid(pw->pw_uid)) && spw->a_password) + epw = spw->a_password; + } +#endif /* HAVE_GETAUTHUID */ + +#if defined(HAVE_ISCOMSEC) || defined(HAVE_ISSECURE) +done: +#endif + /* If no shadow password, fall back on regular password. */ + debug_return_str(estrdup(epw ? epw : pw->pw_passwd)); +} + +void +sudo_setspent(void) +{ + debug_decl(sudo_setspent, SUDO_DEBUG_AUTH) + +#ifdef HAVE_GETPRPWNAM + setprpwent(); +#endif +#ifdef HAVE_GETSPNAM + setspent(); +#endif +#ifdef HAVE_GETSPWUID + setspwent(); +#endif +#ifdef HAVE_GETPWANAM + setpwaent(); +#endif +#ifdef HAVE_GETAUTHUID + setauthent(); +#endif + debug_return; +} + +void +sudo_endspent(void) +{ + debug_decl(sudo_endspent, SUDO_DEBUG_AUTH) + +#ifdef HAVE_GETPRPWNAM + endprpwent(); +#endif +#ifdef HAVE_GETSPNAM + endspent(); +#endif +#ifdef HAVE_GETSPWUID + endspwent(); +#endif +#ifdef HAVE_GETPWANAM + endpwaent(); +#endif +#ifdef HAVE_GETAUTHUID + endauthent(); +#endif + debug_return; +} diff --git a/plugins/sudoers/goodpath.c b/plugins/sudoers/goodpath.c new file mode 100644 index 0000000..2a8446b --- /dev/null +++ b/plugins/sudoers/goodpath.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1996, 1998-2005, 2010-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. + * + * 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 +#include +#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 */ +#include + +#include "sudoers.h" + +/* + * Verify that path is a normal file and executable by root. + */ +bool +sudo_goodpath(const char *path, struct stat *sbp) +{ + struct stat sb; + bool rval = false; + debug_decl(sudo_goodpath, SUDO_DEBUG_UTIL) + + if (path != NULL && stat(path, &sb) == 0) { + /* Make sure path describes an executable regular file. */ + if (S_ISREG(sb.st_mode) && ISSET(sb.st_mode, 0111)) + rval = true; + else + errno = EACCES; + if (sbp) + (void) memcpy(sbp, &sb, sizeof(struct stat)); + } + + debug_return_bool(rval); +} diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c new file mode 100644 index 0000000..49c45c9 --- /dev/null +++ b/plugins/sudoers/gram.c @@ -0,0 +1,1669 @@ +#include +#include +#include +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#define YYRECOVERING() (yyerrflag!=0) +#define YYPREFIX "yy" +#line 2 "gram.y" +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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. + * 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(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) +# include +#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ +#include + +#include "sudoers.h" /* XXX */ +#include "parse.h" +#include "toke.h" +#include "gram.h" + +/* + * We must define SIZE_MAX for yacc's skeleton.c. + * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t + * could be signed (as it is on SunOS 4.x). + */ +#ifndef SIZE_MAX +# ifdef SIZE_T_MAX +# define SIZE_MAX SIZE_T_MAX +# else +# define SIZE_MAX INT_MAX +# endif /* SIZE_T_MAX */ +#endif /* SIZE_MAX */ + +/* + * Globals + */ +extern int sudolineno; +extern int last_token; +extern char *sudoers; +bool sudoers_warnings = true; +bool parse_error = false; +int errorlineno = -1; +char *errorfile = NULL; + +struct defaults_list defaults; +struct userspec_list userspecs; + +/* + * Local protoypes + */ +static void add_defaults(int, struct member *, struct defaults *); +static void add_userspec(struct member *, struct privilege *); +static struct defaults *new_default(char *, char *, int); +static struct member *new_member(char *, int); + void yyerror(const char *); + +void +yyerror(const char *s) +{ + debug_decl(yyerror, SUDO_DEBUG_PARSER) + + /* If we last saw a newline the error is on the preceding line. */ + if (last_token == COMMENT) + sudolineno--; + + /* Save the line the first error occurred on. */ + if (errorlineno == -1) { + errorlineno = sudolineno; + errorfile = estrdup(sudoers); + } + if (trace_print != NULL) { + LEXTRACE("<*> "); + } else if (sudoers_warnings && s != NULL) { + warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, sudolineno); + } + parse_error = true; + debug_return; +} +#line 117 "gram.y" +#ifndef YYSTYPE_DEFINED +#define YYSTYPE_DEFINED +typedef union { + struct cmndspec *cmndspec; + struct defaults *defaults; + struct member *member; + struct runascontainer *runas; + struct privilege *privilege; + struct sudo_command command; + struct cmndtag tag; + struct selinux_info seinfo; + char *string; + int tok; +} YYSTYPE; +#endif /* YYSTYPE_DEFINED */ +#line 143 "gram.c" +#define COMMAND 257 +#define ALIAS 258 +#define DEFVAR 259 +#define NTWKADDR 260 +#define NETGROUP 261 +#define USERGROUP 262 +#define WORD 263 +#define DEFAULTS 264 +#define DEFAULTS_HOST 265 +#define DEFAULTS_USER 266 +#define DEFAULTS_RUNAS 267 +#define DEFAULTS_CMND 268 +#define NOPASSWD 269 +#define PASSWD 270 +#define NOEXEC 271 +#define EXEC 272 +#define SETENV 273 +#define NOSETENV 274 +#define LOG_INPUT 275 +#define NOLOG_INPUT 276 +#define LOG_OUTPUT 277 +#define NOLOG_OUTPUT 278 +#define ALL 279 +#define COMMENT 280 +#define HOSTALIAS 281 +#define CMNDALIAS 282 +#define USERALIAS 283 +#define RUNASALIAS 284 +#define ERROR 285 +#define TYPE 286 +#define ROLE 287 +#define YYERRCODE 256 +#if defined(__cplusplus) || defined(__STDC__) +const short yylhs[] = +#else +short yylhs[] = +#endif + { -1, + 0, 0, 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 4, 4, 3, 3, + 3, 3, 3, 20, 20, 19, 10, 10, 8, 8, + 8, 8, 8, 2, 2, 1, 6, 6, 23, 24, + 22, 22, 22, 22, 22, 17, 17, 18, 18, 18, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 5, 5, 5, 28, 28, 31, 9, 9, 29, + 29, 32, 7, 7, 30, 30, 33, 27, 27, 34, + 13, 13, 11, 11, 12, 12, 12, 12, 12, 16, + 16, 14, 14, 15, 15, 15, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yylen[] = +#else +short yylen[] = +#endif + { 2, + 0, 1, 1, 2, 1, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 1, 3, 1, 2, + 3, 3, 3, 1, 3, 3, 1, 2, 1, 1, + 1, 1, 1, 1, 3, 4, 1, 2, 3, 3, + 0, 1, 1, 2, 2, 0, 3, 1, 3, 2, + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 3, 3, 1, 3, 1, + 3, 3, 1, 3, 1, 3, 3, 1, 3, 3, + 1, 3, 1, 2, 1, 1, 1, 1, 1, 1, + 3, 1, 2, 1, 1, 1, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yydefred[] = +#else +short yydefred[] = +#endif + { 0, + 0, 85, 87, 88, 89, 0, 0, 0, 0, 0, + 86, 5, 0, 0, 0, 0, 0, 0, 81, 83, + 0, 0, 3, 6, 0, 0, 17, 0, 29, 32, + 31, 33, 30, 0, 27, 0, 68, 0, 0, 64, + 63, 62, 0, 37, 73, 0, 0, 0, 65, 0, + 0, 70, 0, 0, 78, 0, 0, 75, 84, 0, + 0, 24, 0, 4, 0, 0, 0, 20, 0, 28, + 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 0, 0, 21, 22, + 23, 18, 69, 74, 0, 66, 0, 71, 0, 79, + 0, 76, 0, 34, 0, 0, 25, 0, 0, 0, + 0, 0, 0, 51, 0, 0, 94, 96, 95, 0, + 90, 92, 0, 0, 47, 35, 0, 0, 0, 44, + 45, 93, 0, 0, 40, 39, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 36, 91, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yydgoto[] = +#else +short yydgoto[] = +#endif + { 18, + 104, 105, 27, 28, 44, 45, 46, 35, 61, 37, + 19, 20, 21, 121, 122, 123, 106, 110, 62, 63, + 129, 114, 115, 116, 22, 23, 54, 48, 51, 57, + 49, 52, 58, 55, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yysindex[] = +#else +short yysindex[] = +#endif + { 475, + -270, 0, 0, 0, 0, -29, 567, 594, 594, -2, + 0, 0, -240, -222, -216, -212, -241, 0, 0, 0, + -25, 475, 0, 0, -10, -207, 0, 9, 0, 0, + 0, 0, 0, -235, 0, -33, 0, -31, -31, 0, + 0, 0, -242, 0, 0, -30, -7, 3, 0, -6, + 4, 0, -5, 6, 0, -1, 8, 0, 0, 594, + -20, 0, 10, 0, -205, -196, -194, 0, -29, 0, + 567, 9, 9, 9, 0, -2, 9, 567, -240, -2, + -222, 594, -216, 594, -212, 0, 31, 567, 0, 0, + 0, 0, 0, 0, 26, 0, 28, 0, 29, 0, + 29, 0, 541, 0, 32, -247, 0, 86, -15, 33, + 31, 14, 16, 0, -208, -204, 0, 0, 0, -231, + 0, 0, 38, 86, 0, 0, -179, -178, 491, 0, + 0, 0, 86, 38, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,}; +#if defined(__cplusplus) || defined(__STDC__) +const short yyrindex[] = +#else +short yyrindex[] = +#endif + { 87, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 90, 0, 0, 1, 0, 0, 177, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 207, 0, 0, + 237, 0, 0, 271, 0, 0, 300, 0, 0, 0, + 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, + 0, 358, 387, 417, 0, 0, 446, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -26, 0, 0, 0, + 0, 0, 0, 0, 30, 0, 59, 0, 89, 0, + 118, 0, 0, 0, 148, 514, 0, 0, 45, 0, + -26, 0, 0, 0, 537, 565, 0, 0, 0, 0, + 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,}; +#if defined(__cplusplus) || defined(__STDC__) +const short yygindex[] = +#else +short yygindex[] = +#endif + { 0, + -17, 0, 27, 11, 54, -64, 15, 64, 2, 34, + 39, 84, -3, -27, -18, -21, 0, 0, 19, 0, + 0, 0, -12, -4, 0, 88, 0, 0, 0, 0, + 35, 40, 23, 37, +}; +#define YYTABLESIZE 873 +#if defined(__cplusplus) || defined(__STDC__) +const short yytable[] = +#else +short yytable[] = +#endif + { 26, + 19, 26, 26, 26, 38, 39, 46, 34, 36, 24, + 71, 94, 60, 76, 40, 41, 2, 47, 60, 3, + 4, 5, 29, 71, 30, 31, 117, 32, 60, 67, + 43, 118, 66, 19, 67, 50, 42, 11, 112, 113, + 87, 53, 124, 33, 19, 56, 72, 119, 73, 74, + 65, 68, 69, 78, 80, 82, 77, 89, 72, 84, + 79, 81, 67, 83, 147, 85, 90, 88, 91, 71, + 103, 76, 60, 125, 127, 111, 128, 112, 99, 95, + 101, 133, 113, 135, 136, 48, 1, 67, 80, 2, + 50, 72, 49, 126, 97, 92, 75, 70, 86, 109, + 59, 132, 134, 131, 93, 148, 107, 102, 0, 64, + 130, 0, 0, 96, 0, 0, 72, 77, 120, 100, + 98, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 80, 26, 0, 0, + 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 77, 12, 0, 0, 0, + 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 26, 9, 0, 0, 12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 25, 0, 25, 25, 25, + 46, 46, 29, 0, 30, 31, 10, 32, 0, 9, + 0, 0, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 33, 40, 41, 19, 0, 19, 46, + 46, 19, 19, 19, 19, 19, 19, 19, 19, 10, + 8, 0, 0, 0, 0, 0, 42, 0, 0, 19, + 19, 19, 19, 19, 19, 67, 0, 67, 0, 0, + 67, 67, 67, 67, 67, 67, 67, 67, 0, 11, + 0, 0, 0, 8, 0, 0, 0, 0, 67, 67, + 67, 67, 67, 67, 72, 0, 72, 0, 0, 72, + 72, 72, 72, 72, 72, 72, 72, 0, 7, 0, + 0, 0, 11, 0, 0, 0, 0, 72, 72, 72, + 72, 72, 72, 117, 80, 0, 80, 0, 118, 80, + 80, 80, 80, 80, 80, 80, 80, 15, 0, 0, + 0, 7, 0, 0, 119, 0, 0, 80, 80, 80, + 80, 80, 80, 77, 0, 77, 0, 0, 77, 77, + 77, 77, 77, 77, 77, 77, 13, 0, 0, 0, + 15, 0, 0, 0, 0, 0, 77, 77, 77, 77, + 77, 77, 0, 26, 0, 26, 0, 0, 26, 26, + 26, 26, 26, 26, 26, 26, 14, 0, 0, 13, + 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, + 26, 26, 12, 0, 12, 0, 0, 12, 12, 12, + 12, 12, 12, 12, 12, 16, 0, 0, 0, 14, + 0, 0, 0, 0, 0, 12, 12, 12, 12, 12, + 12, 0, 9, 0, 9, 0, 0, 9, 9, 9, + 9, 9, 9, 9, 9, 0, 0, 0, 16, 0, + 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, + 9, 0, 10, 0, 10, 0, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, + 10, 0, 0, 43, 0, 0, 8, 0, 8, 0, + 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, + 0, 0, 0, 0, 0, 0, 41, 0, 0, 8, + 8, 8, 8, 8, 8, 11, 0, 11, 0, 0, + 11, 11, 11, 11, 11, 11, 11, 11, 0, 42, + 0, 0, 0, 17, 0, 0, 0, 0, 11, 11, + 11, 11, 11, 11, 7, 0, 7, 0, 0, 7, + 7, 7, 7, 7, 7, 7, 7, 43, 108, 34, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, + 7, 7, 7, 15, 0, 15, 0, 0, 15, 15, + 15, 15, 15, 15, 15, 15, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, + 15, 15, 13, 0, 13, 0, 0, 13, 13, 13, + 13, 13, 13, 13, 13, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, + 13, 0, 14, 0, 14, 0, 0, 14, 14, 14, + 14, 14, 14, 14, 14, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, + 14, 16, 0, 16, 0, 0, 16, 16, 16, 16, + 16, 16, 16, 16, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, + 1, 0, 2, 0, 0, 3, 4, 5, 6, 7, + 8, 9, 10, 0, 0, 0, 0, 40, 41, 0, + 0, 0, 0, 11, 12, 13, 14, 15, 16, 137, + 138, 139, 140, 141, 142, 143, 144, 145, 146, 42, + 41, 41, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 42, 42, 0, 0, 0, 2, 0, + 0, 3, 4, 5, 0, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 0, 0, 0, 11, + 0, 43, 43, 0, 29, 0, 30, 31, 0, 32, + 0, 0, 0, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 0, 33, 0, 0, 0, 0, + 0, 2, 0, 0, 3, 4, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, +}; +#if defined(__cplusplus) || defined(__STDC__) +const short yycheck[] = +#else +short yycheck[] = +#endif + { 33, + 0, 33, 33, 33, 8, 9, 33, 33, 7, 280, + 44, 76, 44, 44, 257, 258, 258, 258, 44, 261, + 262, 263, 258, 44, 260, 261, 258, 263, 44, 0, + 33, 263, 43, 33, 45, 258, 279, 279, 286, 287, + 61, 258, 58, 279, 44, 258, 36, 279, 38, 39, + 61, 259, 44, 61, 61, 61, 46, 263, 0, 61, + 58, 58, 33, 58, 129, 58, 263, 58, 263, 44, + 40, 44, 44, 41, 61, 44, 61, 286, 82, 78, + 84, 44, 287, 263, 263, 41, 0, 58, 0, 0, + 41, 33, 41, 111, 80, 69, 43, 34, 60, 103, + 17, 120, 124, 116, 71, 133, 88, 85, -1, 22, + 115, -1, -1, 79, -1, -1, 58, 0, 33, 83, + 81, 33, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 58, 0, -1, -1, + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 58, 0, -1, -1, -1, + 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 58, 0, -1, -1, 33, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 259, -1, 259, 259, 259, + 257, 258, 258, -1, 260, 261, 0, 263, -1, 33, + -1, -1, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 279, 257, 258, 256, -1, 258, 286, + 287, 261, 262, 263, 264, 265, 266, 267, 268, 33, + 0, -1, -1, -1, -1, -1, 279, -1, -1, 279, + 280, 281, 282, 283, 284, 256, -1, 258, -1, -1, + 261, 262, 263, 264, 265, 266, 267, 268, -1, 0, + -1, -1, -1, 33, -1, -1, -1, -1, 279, 280, + 281, 282, 283, 284, 256, -1, 258, -1, -1, 261, + 262, 263, 264, 265, 266, 267, 268, -1, 0, -1, + -1, -1, 33, -1, -1, -1, -1, 279, 280, 281, + 282, 283, 284, 258, 256, -1, 258, -1, 263, 261, + 262, 263, 264, 265, 266, 267, 268, 0, -1, -1, + -1, 33, -1, -1, 279, -1, -1, 279, 280, 281, + 282, 283, 284, 256, -1, 258, -1, -1, 261, 262, + 263, 264, 265, 266, 267, 268, 0, -1, -1, -1, + 33, -1, -1, -1, -1, -1, 279, 280, 281, 282, + 283, 284, -1, 256, -1, 258, -1, -1, 261, 262, + 263, 264, 265, 266, 267, 268, 0, -1, -1, 33, + -1, -1, -1, -1, -1, -1, 279, 280, 281, 282, + 283, 284, 256, -1, 258, -1, -1, 261, 262, 263, + 264, 265, 266, 267, 268, 0, -1, -1, -1, 33, + -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, + 284, -1, 256, -1, 258, -1, -1, 261, 262, 263, + 264, 265, 266, 267, 268, -1, -1, -1, 33, -1, + -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, + 284, -1, 256, -1, 258, -1, -1, 261, 262, 263, + 264, 265, 266, 267, 268, -1, -1, 33, -1, -1, + -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, + 284, -1, -1, 33, -1, -1, 256, -1, 258, -1, + -1, 261, 262, 263, 264, 265, 266, 267, 268, -1, + -1, -1, -1, -1, -1, -1, 33, -1, -1, 279, + 280, 281, 282, 283, 284, 256, -1, 258, -1, -1, + 261, 262, 263, 264, 265, 266, 267, 268, -1, 33, + -1, -1, -1, 33, -1, -1, -1, -1, 279, 280, + 281, 282, 283, 284, 256, -1, 258, -1, -1, 261, + 262, 263, 264, 265, 266, 267, 268, 33, 58, 33, + -1, -1, -1, -1, -1, -1, -1, 279, 280, 281, + 282, 283, 284, 256, -1, 258, -1, -1, 261, 262, + 263, 264, 265, 266, 267, 268, 33, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 279, 280, 281, 282, + 283, 284, 256, -1, 258, -1, -1, 261, 262, 263, + 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, + 284, -1, 256, -1, 258, -1, -1, 261, 262, 263, + 264, 265, 266, 267, 268, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 279, 280, 281, 282, 283, + 284, 256, -1, 258, -1, -1, 261, 262, 263, 264, + 265, 266, 267, 268, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 279, 280, 281, 282, 283, 284, + 256, -1, 258, -1, -1, 261, 262, 263, 264, 265, + 266, 267, 268, -1, -1, -1, -1, 257, 258, -1, + -1, -1, -1, 279, 280, 281, 282, 283, 284, 269, + 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 257, 258, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 257, 258, -1, -1, -1, 258, -1, + -1, 261, 262, 263, -1, 269, 270, 271, 272, 273, + 274, 275, 276, 277, 278, 279, -1, -1, -1, 279, + -1, 257, 258, -1, 258, -1, 260, 261, -1, 263, + -1, -1, -1, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, -1, 279, -1, -1, -1, -1, + -1, 258, -1, -1, 261, 262, 263, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 279, +}; +#define YYFINAL 18 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 287 +#if YYDEBUG +#if defined(__cplusplus) || defined(__STDC__) +const char * const yyname[] = +#else +char *yyname[] = +#endif + { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"'!'",0,0,0,0,0,0,"'('","')'",0,"'+'","','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,"':'", +0,0,"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"COMMAND","ALIAS","DEFVAR","NTWKADDR","NETGROUP","USERGROUP","WORD","DEFAULTS", +"DEFAULTS_HOST","DEFAULTS_USER","DEFAULTS_RUNAS","DEFAULTS_CMND","NOPASSWD", +"PASSWD","NOEXEC","EXEC","SETENV","NOSETENV","LOG_INPUT","NOLOG_INPUT", +"LOG_OUTPUT","NOLOG_OUTPUT","ALL","COMMENT","HOSTALIAS","CMNDALIAS","USERALIAS", +"RUNASALIAS","ERROR","TYPE","ROLE", +}; +#if defined(__cplusplus) || defined(__STDC__) +const char * const yyrule[] = +#else +char *yyrule[] = +#endif + {"$accept : file", +"file :", +"file : line", +"line : entry", +"line : line entry", +"entry : COMMENT", +"entry : error COMMENT", +"entry : userlist privileges", +"entry : USERALIAS useraliases", +"entry : HOSTALIAS hostaliases", +"entry : CMNDALIAS cmndaliases", +"entry : RUNASALIAS runasaliases", +"entry : DEFAULTS defaults_list", +"entry : DEFAULTS_USER userlist defaults_list", +"entry : DEFAULTS_RUNAS userlist defaults_list", +"entry : DEFAULTS_HOST hostlist defaults_list", +"entry : DEFAULTS_CMND cmndlist defaults_list", +"defaults_list : defaults_entry", +"defaults_list : defaults_list ',' defaults_entry", +"defaults_entry : DEFVAR", +"defaults_entry : '!' DEFVAR", +"defaults_entry : DEFVAR '=' WORD", +"defaults_entry : DEFVAR '+' WORD", +"defaults_entry : DEFVAR '-' WORD", +"privileges : privilege", +"privileges : privileges ':' privilege", +"privilege : hostlist '=' cmndspeclist", +"ophost : host", +"ophost : '!' host", +"host : ALIAS", +"host : ALL", +"host : NETGROUP", +"host : NTWKADDR", +"host : WORD", +"cmndspeclist : cmndspec", +"cmndspeclist : cmndspeclist ',' cmndspec", +"cmndspec : runasspec selinux cmndtag opcmnd", +"opcmnd : cmnd", +"opcmnd : '!' cmnd", +"rolespec : ROLE '=' WORD", +"typespec : TYPE '=' WORD", +"selinux :", +"selinux : rolespec", +"selinux : typespec", +"selinux : rolespec typespec", +"selinux : typespec rolespec", +"runasspec :", +"runasspec : '(' runaslist ')'", +"runaslist : userlist", +"runaslist : userlist ':' grouplist", +"runaslist : ':' grouplist", +"cmndtag :", +"cmndtag : cmndtag NOPASSWD", +"cmndtag : cmndtag PASSWD", +"cmndtag : cmndtag NOEXEC", +"cmndtag : cmndtag EXEC", +"cmndtag : cmndtag SETENV", +"cmndtag : cmndtag NOSETENV", +"cmndtag : cmndtag LOG_INPUT", +"cmndtag : cmndtag NOLOG_INPUT", +"cmndtag : cmndtag LOG_OUTPUT", +"cmndtag : cmndtag NOLOG_OUTPUT", +"cmnd : ALL", +"cmnd : ALIAS", +"cmnd : COMMAND", +"hostaliases : hostalias", +"hostaliases : hostaliases ':' hostalias", +"hostalias : ALIAS '=' hostlist", +"hostlist : ophost", +"hostlist : hostlist ',' ophost", +"cmndaliases : cmndalias", +"cmndaliases : cmndaliases ':' cmndalias", +"cmndalias : ALIAS '=' cmndlist", +"cmndlist : opcmnd", +"cmndlist : cmndlist ',' opcmnd", +"runasaliases : runasalias", +"runasaliases : runasaliases ':' runasalias", +"runasalias : ALIAS '=' userlist", +"useraliases : useralias", +"useraliases : useraliases ':' useralias", +"useralias : ALIAS '=' userlist", +"userlist : opuser", +"userlist : userlist ',' opuser", +"opuser : user", +"opuser : '!' user", +"user : ALIAS", +"user : ALL", +"user : NETGROUP", +"user : USERGROUP", +"user : WORD", +"grouplist : opgroup", +"grouplist : grouplist ',' opgroup", +"opgroup : group", +"opgroup : '!' group", +"group : ALIAS", +"group : ALL", +"group : WORD", +}; +#endif +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif +#define YYINITSTACKSIZE 200 +/* LINTUSED */ +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +short *yyss; +short *yysslim; +YYSTYPE *yyvs; +int yystacksize; +#line 611 "gram.y" +static struct defaults * +new_default(char *var, char *val, int op) +{ + struct defaults *d; + debug_decl(new_default, SUDO_DEBUG_PARSER) + + d = ecalloc(1, sizeof(struct defaults)); + d->var = var; + d->val = val; + tq_init(&d->binding); + /* d->type = 0; */ + d->op = op; + d->prev = d; + /* d->next = NULL; */ + + debug_return_ptr(d); +} + +static struct member * +new_member(char *name, int type) +{ + struct member *m; + debug_decl(new_member, SUDO_DEBUG_PARSER) + + m = ecalloc(1, sizeof(struct member)); + m->name = name; + m->type = type; + m->prev = m; + /* m->next = NULL; */ + + debug_return_ptr(m); +} + +/* + * Add a list of defaults structures to the defaults list. + * The binding, if non-NULL, specifies a list of hosts, users, or + * runas users the entries apply to (specified by the type). + */ +static void +add_defaults(int type, struct member *bmem, struct defaults *defs) +{ + struct defaults *d; + struct member_list binding; + debug_decl(add_defaults, SUDO_DEBUG_PARSER) + + /* + * We can only call list2tq once on bmem as it will zero + * out the prev pointer when it consumes bmem. + */ + list2tq(&binding, bmem); + + /* + * Set type and binding (who it applies to) for new entries. + */ + for (d = defs; d != NULL; d = d->next) { + d->type = type; + d->binding = binding; + } + tq_append(&defaults, defs); + + debug_return; +} + +/* + * Allocate a new struct userspec, populate it, and insert it at the + * and of the userspecs list. + */ +static void +add_userspec(struct member *members, struct privilege *privs) +{ + struct userspec *u; + debug_decl(add_userspec, SUDO_DEBUG_PARSER) + + u = ecalloc(1, sizeof(*u)); + list2tq(&u->users, members); + list2tq(&u->privileges, privs); + u->prev = u; + /* u->next = NULL; */ + tq_append(&userspecs, u); + + debug_return; +} + +/* + * Free up space used by data structures from a previous parser run and sets + * the current sudoers file to path. + */ +void +init_parser(const char *path, int quiet) +{ + struct defaults *d; + struct member *m, *binding; + struct userspec *us; + struct privilege *priv; + struct cmndspec *cs; + struct sudo_command *c; + debug_decl(init_parser, SUDO_DEBUG_PARSER) + + while ((us = tq_pop(&userspecs)) != NULL) { + while ((m = tq_pop(&us->users)) != NULL) { + efree(m->name); + efree(m); + } + while ((priv = tq_pop(&us->privileges)) != NULL) { + struct member *runasuser = NULL, *runasgroup = NULL; +#ifdef HAVE_SELINUX + char *role = NULL, *type = NULL; +#endif /* HAVE_SELINUX */ + + while ((m = tq_pop(&priv->hostlist)) != NULL) { + efree(m->name); + efree(m); + } + while ((cs = tq_pop(&priv->cmndlist)) != NULL) { +#ifdef HAVE_SELINUX + /* Only free the first instance of a role/type. */ + if (cs->role != role) { + role = cs->role; + efree(cs->role); + } + if (cs->type != type) { + type = cs->type; + efree(cs->type); + } +#endif /* HAVE_SELINUX */ + if (tq_last(&cs->runasuserlist) != runasuser) { + runasuser = tq_last(&cs->runasuserlist); + while ((m = tq_pop(&cs->runasuserlist)) != NULL) { + efree(m->name); + efree(m); + } + } + if (tq_last(&cs->runasgrouplist) != runasgroup) { + runasgroup = tq_last(&cs->runasgrouplist); + while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { + efree(m->name); + efree(m); + } + } + if (cs->cmnd->type == COMMAND) { + c = (struct sudo_command *) cs->cmnd->name; + efree(c->cmnd); + efree(c->args); + } + efree(cs->cmnd->name); + efree(cs->cmnd); + efree(cs); + } + efree(priv); + } + efree(us); + } + tq_init(&userspecs); + + binding = NULL; + while ((d = tq_pop(&defaults)) != NULL) { + if (tq_last(&d->binding) != binding) { + binding = tq_last(&d->binding); + while ((m = tq_pop(&d->binding)) != NULL) { + if (m->type == COMMAND) { + c = (struct sudo_command *) m->name; + efree(c->cmnd); + efree(c->args); + } + efree(m->name); + efree(m); + } + } + efree(d->var); + efree(d->val); + efree(d); + } + tq_init(&defaults); + + init_aliases(); + + init_lexer(); + + efree(sudoers); + sudoers = path ? estrdup(path) : NULL; + + parse_error = false; + errorlineno = -1; + errorfile = sudoers; + sudoers_warnings = !quiet; + + debug_return; +} +#line 778 "gram.c" +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +#if defined(__cplusplus) || defined(__STDC__) +static int yygrowstack(void) +#else +static int yygrowstack() +#endif +{ + int newsize, i; + short *newss; + YYSTYPE *newvs; + + if ((newsize = yystacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return -1; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + i = yyssp - yyss; +#ifdef SIZE_MAX +#define YY_SIZE_MAX SIZE_MAX +#else +#define YY_SIZE_MAX 0x7fffffff +#endif + if (!newsize || YY_SIZE_MAX / newsize < sizeof *newss) + goto bail; + newss = yyss ? (short *)realloc(yyss, newsize * sizeof *newss) : + (short *)malloc(newsize * sizeof *newss); /* overflow check above */ + if (newss == NULL) + goto bail; + yyss = newss; + yyssp = newss + i; + if (!newsize || YY_SIZE_MAX / newsize < sizeof *newvs) + goto bail; + newvs = yyvs ? (YYSTYPE *)realloc(yyvs, newsize * sizeof *newvs) : + (YYSTYPE *)malloc(newsize * sizeof *newvs); /* overflow check above */ + if (newvs == NULL) + goto bail; + yyvs = newvs; + yyvsp = newvs + i; + yystacksize = newsize; + yysslim = yyss + newsize - 1; + return 0; +bail: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return -1; +} + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +#if defined(__cplusplus) || defined(__STDC__) +yyparse(void) +#else +yyparse() +#endif +{ + int yym, yyn, yystate; +#if YYDEBUG +#if defined(__cplusplus) || defined(__STDC__) + const char *yys; +#else /* !(defined(__cplusplus) || defined(__STDC__)) */ + char *yys; +#endif /* !(defined(__cplusplus) || defined(__STDC__)) */ + + if ((yys = getenv("YYDEBUG"))) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif /* YYDEBUG */ + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + if (yyss == NULL && yygrowstack()) goto yyoverflow; + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#if defined(lint) || defined(__GNUC__) + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#if defined(lint) || defined(__GNUC__) + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + if (yym) + yyval = yyvsp[1-yym]; + else + memset(&yyval, 0, sizeof yyval); + switch (yyn) + { +case 1: +#line 192 "gram.y" +{ ; } +break; +case 5: +#line 200 "gram.y" +{ + ; + } +break; +case 6: +#line 203 "gram.y" +{ + yyerrok; + } +break; +case 7: +#line 206 "gram.y" +{ + add_userspec(yyvsp[-1].member, yyvsp[0].privilege); + } +break; +case 8: +#line 209 "gram.y" +{ + ; + } +break; +case 9: +#line 212 "gram.y" +{ + ; + } +break; +case 10: +#line 215 "gram.y" +{ + ; + } +break; +case 11: +#line 218 "gram.y" +{ + ; + } +break; +case 12: +#line 221 "gram.y" +{ + add_defaults(DEFAULTS, NULL, yyvsp[0].defaults); + } +break; +case 13: +#line 224 "gram.y" +{ + add_defaults(DEFAULTS_USER, yyvsp[-1].member, yyvsp[0].defaults); + } +break; +case 14: +#line 227 "gram.y" +{ + add_defaults(DEFAULTS_RUNAS, yyvsp[-1].member, yyvsp[0].defaults); + } +break; +case 15: +#line 230 "gram.y" +{ + add_defaults(DEFAULTS_HOST, yyvsp[-1].member, yyvsp[0].defaults); + } +break; +case 16: +#line 233 "gram.y" +{ + add_defaults(DEFAULTS_CMND, yyvsp[-1].member, yyvsp[0].defaults); + } +break; +case 18: +#line 239 "gram.y" +{ + list_append(yyvsp[-2].defaults, yyvsp[0].defaults); + yyval.defaults = yyvsp[-2].defaults; + } +break; +case 19: +#line 245 "gram.y" +{ + yyval.defaults = new_default(yyvsp[0].string, NULL, true); + } +break; +case 20: +#line 248 "gram.y" +{ + yyval.defaults = new_default(yyvsp[0].string, NULL, false); + } +break; +case 21: +#line 251 "gram.y" +{ + yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, true); + } +break; +case 22: +#line 254 "gram.y" +{ + yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '+'); + } +break; +case 23: +#line 257 "gram.y" +{ + yyval.defaults = new_default(yyvsp[-2].string, yyvsp[0].string, '-'); + } +break; +case 25: +#line 263 "gram.y" +{ + list_append(yyvsp[-2].privilege, yyvsp[0].privilege); + yyval.privilege = yyvsp[-2].privilege; + } +break; +case 26: +#line 269 "gram.y" +{ + struct privilege *p = ecalloc(1, sizeof(*p)); + list2tq(&p->hostlist, yyvsp[-2].member); + list2tq(&p->cmndlist, yyvsp[0].cmndspec); + p->prev = p; + /* p->next = NULL; */ + yyval.privilege = p; + } +break; +case 27: +#line 279 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = false; + } +break; +case 28: +#line 283 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = true; + } +break; +case 29: +#line 289 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, ALIAS); + } +break; +case 30: +#line 292 "gram.y" +{ + yyval.member = new_member(NULL, ALL); + } +break; +case 31: +#line 295 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, NETGROUP); + } +break; +case 32: +#line 298 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, NTWKADDR); + } +break; +case 33: +#line 301 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, WORD); + } +break; +case 35: +#line 307 "gram.y" +{ + list_append(yyvsp[-2].cmndspec, yyvsp[0].cmndspec); +#ifdef HAVE_SELINUX + /* propagate role and type */ + if (yyvsp[0].cmndspec->role == NULL) + yyvsp[0].cmndspec->role = yyvsp[0].cmndspec->prev->role; + if (yyvsp[0].cmndspec->type == NULL) + yyvsp[0].cmndspec->type = yyvsp[0].cmndspec->prev->type; +#endif /* HAVE_SELINUX */ + /* propagate tags and runas list */ + if (yyvsp[0].cmndspec->tags.nopasswd == UNSPEC) + yyvsp[0].cmndspec->tags.nopasswd = yyvsp[0].cmndspec->prev->tags.nopasswd; + if (yyvsp[0].cmndspec->tags.noexec == UNSPEC) + yyvsp[0].cmndspec->tags.noexec = yyvsp[0].cmndspec->prev->tags.noexec; + if (yyvsp[0].cmndspec->tags.setenv == UNSPEC && + yyvsp[0].cmndspec->prev->tags.setenv != IMPLIED) + yyvsp[0].cmndspec->tags.setenv = yyvsp[0].cmndspec->prev->tags.setenv; + if (yyvsp[0].cmndspec->tags.log_input == UNSPEC) + yyvsp[0].cmndspec->tags.log_input = yyvsp[0].cmndspec->prev->tags.log_input; + if (yyvsp[0].cmndspec->tags.log_output == UNSPEC) + yyvsp[0].cmndspec->tags.log_output = yyvsp[0].cmndspec->prev->tags.log_output; + if ((tq_empty(&yyvsp[0].cmndspec->runasuserlist) && + tq_empty(&yyvsp[0].cmndspec->runasgrouplist)) && + (!tq_empty(&yyvsp[0].cmndspec->prev->runasuserlist) || + !tq_empty(&yyvsp[0].cmndspec->prev->runasgrouplist))) { + yyvsp[0].cmndspec->runasuserlist = yyvsp[0].cmndspec->prev->runasuserlist; + yyvsp[0].cmndspec->runasgrouplist = yyvsp[0].cmndspec->prev->runasgrouplist; + } + yyval.cmndspec = yyvsp[-2].cmndspec; + } +break; +case 36: +#line 339 "gram.y" +{ + struct cmndspec *cs = ecalloc(1, sizeof(*cs)); + if (yyvsp[-3].runas != NULL) { + list2tq(&cs->runasuserlist, yyvsp[-3].runas->runasusers); + list2tq(&cs->runasgrouplist, yyvsp[-3].runas->runasgroups); + efree(yyvsp[-3].runas); + } else { + tq_init(&cs->runasuserlist); + tq_init(&cs->runasgrouplist); + } +#ifdef HAVE_SELINUX + cs->role = yyvsp[-2].seinfo.role; + cs->type = yyvsp[-2].seinfo.type; +#endif + cs->tags = yyvsp[-1].tag; + cs->cmnd = yyvsp[0].member; + cs->prev = cs; + cs->next = NULL; + /* sudo "ALL" implies the SETENV tag */ + if (cs->cmnd->type == ALL && !cs->cmnd->negated && + cs->tags.setenv == UNSPEC) + cs->tags.setenv = IMPLIED; + yyval.cmndspec = cs; + } +break; +case 37: +#line 365 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = false; + } +break; +case 38: +#line 369 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = true; + } +break; +case 39: +#line 375 "gram.y" +{ + yyval.string = yyvsp[0].string; + } +break; +case 40: +#line 380 "gram.y" +{ + yyval.string = yyvsp[0].string; + } +break; +case 41: +#line 385 "gram.y" +{ + yyval.seinfo.role = NULL; + yyval.seinfo.type = NULL; + } +break; +case 42: +#line 389 "gram.y" +{ + yyval.seinfo.role = yyvsp[0].string; + yyval.seinfo.type = NULL; + } +break; +case 43: +#line 393 "gram.y" +{ + yyval.seinfo.type = yyvsp[0].string; + yyval.seinfo.role = NULL; + } +break; +case 44: +#line 397 "gram.y" +{ + yyval.seinfo.role = yyvsp[-1].string; + yyval.seinfo.type = yyvsp[0].string; + } +break; +case 45: +#line 401 "gram.y" +{ + yyval.seinfo.type = yyvsp[-1].string; + yyval.seinfo.role = yyvsp[0].string; + } +break; +case 46: +#line 407 "gram.y" +{ + yyval.runas = NULL; + } +break; +case 47: +#line 410 "gram.y" +{ + yyval.runas = yyvsp[-1].runas; + } +break; +case 48: +#line 415 "gram.y" +{ + yyval.runas = ecalloc(1, sizeof(struct runascontainer)); + yyval.runas->runasusers = yyvsp[0].member; + /* $$->runasgroups = NULL; */ + } +break; +case 49: +#line 420 "gram.y" +{ + yyval.runas = ecalloc(1, sizeof(struct runascontainer)); + yyval.runas->runasusers = yyvsp[-2].member; + yyval.runas->runasgroups = yyvsp[0].member; + } +break; +case 50: +#line 425 "gram.y" +{ + yyval.runas = ecalloc(1, sizeof(struct runascontainer)); + /* $$->runasusers = NULL; */ + yyval.runas->runasgroups = yyvsp[0].member; + } +break; +case 51: +#line 432 "gram.y" +{ + yyval.tag.nopasswd = yyval.tag.noexec = yyval.tag.setenv = + yyval.tag.log_input = yyval.tag.log_output = UNSPEC; + } +break; +case 52: +#line 436 "gram.y" +{ + yyval.tag.nopasswd = true; + } +break; +case 53: +#line 439 "gram.y" +{ + yyval.tag.nopasswd = false; + } +break; +case 54: +#line 442 "gram.y" +{ + yyval.tag.noexec = true; + } +break; +case 55: +#line 445 "gram.y" +{ + yyval.tag.noexec = false; + } +break; +case 56: +#line 448 "gram.y" +{ + yyval.tag.setenv = true; + } +break; +case 57: +#line 451 "gram.y" +{ + yyval.tag.setenv = false; + } +break; +case 58: +#line 454 "gram.y" +{ + yyval.tag.log_input = true; + } +break; +case 59: +#line 457 "gram.y" +{ + yyval.tag.log_input = false; + } +break; +case 60: +#line 460 "gram.y" +{ + yyval.tag.log_output = true; + } +break; +case 61: +#line 463 "gram.y" +{ + yyval.tag.log_output = false; + } +break; +case 62: +#line 468 "gram.y" +{ + yyval.member = new_member(NULL, ALL); + } +break; +case 63: +#line 471 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, ALIAS); + } +break; +case 64: +#line 474 "gram.y" +{ + struct sudo_command *c = ecalloc(1, sizeof(*c)); + c->cmnd = yyvsp[0].command.cmnd; + c->args = yyvsp[0].command.args; + yyval.member = new_member((char *)c, COMMAND); + } +break; +case 67: +#line 486 "gram.y" +{ + char *s; + if ((s = alias_add(yyvsp[-2].string, HOSTALIAS, yyvsp[0].member)) != NULL) { + yyerror(s); + YYERROR; + } + } +break; +case 69: +#line 496 "gram.y" +{ + list_append(yyvsp[-2].member, yyvsp[0].member); + yyval.member = yyvsp[-2].member; + } +break; +case 72: +#line 506 "gram.y" +{ + char *s; + if ((s = alias_add(yyvsp[-2].string, CMNDALIAS, yyvsp[0].member)) != NULL) { + yyerror(s); + YYERROR; + } + } +break; +case 74: +#line 516 "gram.y" +{ + list_append(yyvsp[-2].member, yyvsp[0].member); + yyval.member = yyvsp[-2].member; + } +break; +case 77: +#line 526 "gram.y" +{ + char *s; + if ((s = alias_add(yyvsp[-2].string, RUNASALIAS, yyvsp[0].member)) != NULL) { + yyerror(s); + YYERROR; + } + } +break; +case 80: +#line 539 "gram.y" +{ + char *s; + if ((s = alias_add(yyvsp[-2].string, USERALIAS, yyvsp[0].member)) != NULL) { + yyerror(s); + YYERROR; + } + } +break; +case 82: +#line 549 "gram.y" +{ + list_append(yyvsp[-2].member, yyvsp[0].member); + yyval.member = yyvsp[-2].member; + } +break; +case 83: +#line 555 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = false; + } +break; +case 84: +#line 559 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = true; + } +break; +case 85: +#line 565 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, ALIAS); + } +break; +case 86: +#line 568 "gram.y" +{ + yyval.member = new_member(NULL, ALL); + } +break; +case 87: +#line 571 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, NETGROUP); + } +break; +case 88: +#line 574 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, USERGROUP); + } +break; +case 89: +#line 577 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, WORD); + } +break; +case 91: +#line 583 "gram.y" +{ + list_append(yyvsp[-2].member, yyvsp[0].member); + yyval.member = yyvsp[-2].member; + } +break; +case 92: +#line 589 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = false; + } +break; +case 93: +#line 593 "gram.y" +{ + yyval.member = yyvsp[0].member; + yyval.member->negated = true; + } +break; +case 94: +#line 599 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, ALIAS); + } +break; +case 95: +#line 602 "gram.y" +{ + yyval.member = new_member(NULL, ALL); + } +break; +case 96: +#line 605 "gram.y" +{ + yyval.member = new_member(yyvsp[0].string, WORD); + } +break; +#line 1547 "gram.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yyssp, yystate); +#endif + if (yyssp >= yysslim && yygrowstack()) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return (1); +yyaccept: + if (yyss) + free(yyss); + if (yyvs) + free(yyvs); + yyss = yyssp = NULL; + yyvs = yyvsp = NULL; + yystacksize = 0; + return (0); +} diff --git a/plugins/sudoers/gram.h b/plugins/sudoers/gram.h new file mode 100644 index 0000000..2bec420 --- /dev/null +++ b/plugins/sudoers/gram.h @@ -0,0 +1,47 @@ +#define COMMAND 257 +#define ALIAS 258 +#define DEFVAR 259 +#define NTWKADDR 260 +#define NETGROUP 261 +#define USERGROUP 262 +#define WORD 263 +#define DEFAULTS 264 +#define DEFAULTS_HOST 265 +#define DEFAULTS_USER 266 +#define DEFAULTS_RUNAS 267 +#define DEFAULTS_CMND 268 +#define NOPASSWD 269 +#define PASSWD 270 +#define NOEXEC 271 +#define EXEC 272 +#define SETENV 273 +#define NOSETENV 274 +#define LOG_INPUT 275 +#define NOLOG_INPUT 276 +#define LOG_OUTPUT 277 +#define NOLOG_OUTPUT 278 +#define ALL 279 +#define COMMENT 280 +#define HOSTALIAS 281 +#define CMNDALIAS 282 +#define USERALIAS 283 +#define RUNASALIAS 284 +#define ERROR 285 +#define TYPE 286 +#define ROLE 287 +#ifndef YYSTYPE_DEFINED +#define YYSTYPE_DEFINED +typedef union { + struct cmndspec *cmndspec; + struct defaults *defaults; + struct member *member; + struct runascontainer *runas; + struct privilege *privilege; + struct sudo_command command; + struct cmndtag tag; + struct selinux_info seinfo; + char *string; + int tok; +} YYSTYPE; +#endif /* YYSTYPE_DEFINED */ +extern YYSTYPE yylval; diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y new file mode 100644 index 0000000..0315f24 --- /dev/null +++ b/plugins/sudoers/gram.y @@ -0,0 +1,798 @@ +%{ +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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. + * 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(YYBISON) && defined(HAVE_ALLOCA_H) && !defined(__GNUC__) +# include +#endif /* YYBISON && HAVE_ALLOCA_H && !__GNUC__ */ +#include + +#include "sudoers.h" /* XXX */ +#include "parse.h" +#include "toke.h" +#include "gram.h" + +/* + * We must define SIZE_MAX for yacc's skeleton.c. + * If there is no SIZE_MAX or SIZE_T_MAX we have to assume that size_t + * could be signed (as it is on SunOS 4.x). + */ +#ifndef SIZE_MAX +# ifdef SIZE_T_MAX +# define SIZE_MAX SIZE_T_MAX +# else +# define SIZE_MAX INT_MAX +# endif /* SIZE_T_MAX */ +#endif /* SIZE_MAX */ + +/* + * Globals + */ +extern int sudolineno; +extern int last_token; +extern char *sudoers; +bool sudoers_warnings = true; +bool parse_error = false; +int errorlineno = -1; +char *errorfile = NULL; + +struct defaults_list defaults; +struct userspec_list userspecs; + +/* + * Local protoypes + */ +static void add_defaults(int, struct member *, struct defaults *); +static void add_userspec(struct member *, struct privilege *); +static struct defaults *new_default(char *, char *, int); +static struct member *new_member(char *, int); + void yyerror(const char *); + +void +yyerror(const char *s) +{ + debug_decl(yyerror, SUDO_DEBUG_PARSER) + + /* If we last saw a newline the error is on the preceding line. */ + if (last_token == COMMENT) + sudolineno--; + + /* Save the line the first error occurred on. */ + if (errorlineno == -1) { + errorlineno = sudolineno; + errorfile = estrdup(sudoers); + } + if (trace_print != NULL) { + LEXTRACE("<*> "); + } else if (sudoers_warnings && s != NULL) { + warningx(_(">>> %s: %s near line %d <<<"), sudoers, s, sudolineno); + } + parse_error = true; + debug_return; +} +%} + +%union { + struct cmndspec *cmndspec; + struct defaults *defaults; + struct member *member; + struct runascontainer *runas; + struct privilege *privilege; + struct sudo_command command; + struct cmndtag tag; + struct selinux_info seinfo; + char *string; + int tok; +} + +%start file /* special start symbol */ +%token COMMAND /* absolute pathname w/ optional args */ +%token ALIAS /* an UPPERCASE alias name */ +%token DEFVAR /* a Defaults variable name */ +%token NTWKADDR /* ipv4 or ipv6 address */ +%token NETGROUP /* a netgroup (+NAME) */ +%token USERGROUP /* a usergroup (%NAME) */ +%token WORD /* a word */ +%token DEFAULTS /* Defaults entry */ +%token DEFAULTS_HOST /* Host-specific defaults entry */ +%token DEFAULTS_USER /* User-specific defaults entry */ +%token DEFAULTS_RUNAS /* Runas-specific defaults entry */ +%token DEFAULTS_CMND /* Command-specific defaults entry */ +%token NOPASSWD /* no passwd req for command */ +%token PASSWD /* passwd req for command (default) */ +%token NOEXEC /* preload dummy execve() for cmnd */ +%token EXEC /* don't preload dummy execve() */ +%token SETENV /* user may set environment for cmnd */ +%token NOSETENV /* user may not set environment */ +%token LOG_INPUT /* log user's cmnd input */ +%token NOLOG_INPUT /* don't log user's cmnd input */ +%token LOG_OUTPUT /* log cmnd output */ +%token NOLOG_OUTPUT /* don't log cmnd output */ +%token ALL /* ALL keyword */ +%token COMMENT /* comment and/or carriage return */ +%token HOSTALIAS /* Host_Alias keyword */ +%token CMNDALIAS /* Cmnd_Alias keyword */ +%token USERALIAS /* User_Alias keyword */ +%token RUNASALIAS /* Runas_Alias keyword */ +%token ':' '=' ',' '!' '+' '-' /* union member tokens */ +%token '(' ')' /* runas tokens */ +%token ERROR +%token TYPE /* SELinux type */ +%token ROLE /* SELinux role */ + +%type cmndspec +%type cmndspeclist +%type defaults_entry +%type defaults_list +%type cmnd +%type opcmnd +%type cmndlist +%type host +%type hostlist +%type ophost +%type opuser +%type user +%type userlist +%type opgroup +%type group +%type grouplist +%type runasspec +%type runaslist +%type privilege +%type privileges +%type cmndtag +%type selinux +%type rolespec +%type typespec + +%% + +file : { ; } + | line + ; + +line : entry + | line entry + ; + +entry : COMMENT { + ; + } + | error COMMENT { + yyerrok; + } + | userlist privileges { + add_userspec($1, $2); + } + | USERALIAS useraliases { + ; + } + | HOSTALIAS hostaliases { + ; + } + | CMNDALIAS cmndaliases { + ; + } + | RUNASALIAS runasaliases { + ; + } + | DEFAULTS defaults_list { + add_defaults(DEFAULTS, NULL, $2); + } + | DEFAULTS_USER userlist defaults_list { + add_defaults(DEFAULTS_USER, $2, $3); + } + | DEFAULTS_RUNAS userlist defaults_list { + add_defaults(DEFAULTS_RUNAS, $2, $3); + } + | DEFAULTS_HOST hostlist defaults_list { + add_defaults(DEFAULTS_HOST, $2, $3); + } + | DEFAULTS_CMND cmndlist defaults_list { + add_defaults(DEFAULTS_CMND, $2, $3); + } + ; + +defaults_list : defaults_entry + | defaults_list ',' defaults_entry { + list_append($1, $3); + $$ = $1; + } + ; + +defaults_entry : DEFVAR { + $$ = new_default($1, NULL, true); + } + | '!' DEFVAR { + $$ = new_default($2, NULL, false); + } + | DEFVAR '=' WORD { + $$ = new_default($1, $3, true); + } + | DEFVAR '+' WORD { + $$ = new_default($1, $3, '+'); + } + | DEFVAR '-' WORD { + $$ = new_default($1, $3, '-'); + } + ; + +privileges : privilege + | privileges ':' privilege { + list_append($1, $3); + $$ = $1; + } + ; + +privilege : hostlist '=' cmndspeclist { + struct privilege *p = ecalloc(1, sizeof(*p)); + list2tq(&p->hostlist, $1); + list2tq(&p->cmndlist, $3); + p->prev = p; + /* p->next = NULL; */ + $$ = p; + } + ; + +ophost : host { + $$ = $1; + $$->negated = false; + } + | '!' host { + $$ = $2; + $$->negated = true; + } + ; + +host : ALIAS { + $$ = new_member($1, ALIAS); + } + | ALL { + $$ = new_member(NULL, ALL); + } + | NETGROUP { + $$ = new_member($1, NETGROUP); + } + | NTWKADDR { + $$ = new_member($1, NTWKADDR); + } + | WORD { + $$ = new_member($1, WORD); + } + ; + +cmndspeclist : cmndspec + | cmndspeclist ',' cmndspec { + list_append($1, $3); +#ifdef HAVE_SELINUX + /* propagate role and type */ + if ($3->role == NULL) + $3->role = $3->prev->role; + if ($3->type == NULL) + $3->type = $3->prev->type; +#endif /* HAVE_SELINUX */ + /* propagate tags and runas list */ + if ($3->tags.nopasswd == UNSPEC) + $3->tags.nopasswd = $3->prev->tags.nopasswd; + if ($3->tags.noexec == UNSPEC) + $3->tags.noexec = $3->prev->tags.noexec; + if ($3->tags.setenv == UNSPEC && + $3->prev->tags.setenv != IMPLIED) + $3->tags.setenv = $3->prev->tags.setenv; + if ($3->tags.log_input == UNSPEC) + $3->tags.log_input = $3->prev->tags.log_input; + if ($3->tags.log_output == UNSPEC) + $3->tags.log_output = $3->prev->tags.log_output; + if ((tq_empty(&$3->runasuserlist) && + tq_empty(&$3->runasgrouplist)) && + (!tq_empty(&$3->prev->runasuserlist) || + !tq_empty(&$3->prev->runasgrouplist))) { + $3->runasuserlist = $3->prev->runasuserlist; + $3->runasgrouplist = $3->prev->runasgrouplist; + } + $$ = $1; + } + ; + +cmndspec : runasspec selinux cmndtag opcmnd { + struct cmndspec *cs = ecalloc(1, sizeof(*cs)); + if ($1 != NULL) { + list2tq(&cs->runasuserlist, $1->runasusers); + list2tq(&cs->runasgrouplist, $1->runasgroups); + efree($1); + } else { + tq_init(&cs->runasuserlist); + tq_init(&cs->runasgrouplist); + } +#ifdef HAVE_SELINUX + cs->role = $2.role; + cs->type = $2.type; +#endif + cs->tags = $3; + cs->cmnd = $4; + cs->prev = cs; + cs->next = NULL; + /* sudo "ALL" implies the SETENV tag */ + if (cs->cmnd->type == ALL && !cs->cmnd->negated && + cs->tags.setenv == UNSPEC) + cs->tags.setenv = IMPLIED; + $$ = cs; + } + ; + +opcmnd : cmnd { + $$ = $1; + $$->negated = false; + } + | '!' cmnd { + $$ = $2; + $$->negated = true; + } + ; + +rolespec : ROLE '=' WORD { + $$ = $3; + } + ; + +typespec : TYPE '=' WORD { + $$ = $3; + } + ; + +selinux : /* empty */ { + $$.role = NULL; + $$.type = NULL; + } + | rolespec { + $$.role = $1; + $$.type = NULL; + } + | typespec { + $$.type = $1; + $$.role = NULL; + } + | rolespec typespec { + $$.role = $1; + $$.type = $2; + } + | typespec rolespec { + $$.type = $1; + $$.role = $2; + } + ; + +runasspec : /* empty */ { + $$ = NULL; + } + | '(' runaslist ')' { + $$ = $2; + } + ; + +runaslist : userlist { + $$ = ecalloc(1, sizeof(struct runascontainer)); + $$->runasusers = $1; + /* $$->runasgroups = NULL; */ + } + | userlist ':' grouplist { + $$ = ecalloc(1, sizeof(struct runascontainer)); + $$->runasusers = $1; + $$->runasgroups = $3; + } + | ':' grouplist { + $$ = ecalloc(1, sizeof(struct runascontainer)); + /* $$->runasusers = NULL; */ + $$->runasgroups = $2; + } + ; + +cmndtag : /* empty */ { + $$.nopasswd = $$.noexec = $$.setenv = + $$.log_input = $$.log_output = UNSPEC; + } + | cmndtag NOPASSWD { + $$.nopasswd = true; + } + | cmndtag PASSWD { + $$.nopasswd = false; + } + | cmndtag NOEXEC { + $$.noexec = true; + } + | cmndtag EXEC { + $$.noexec = false; + } + | cmndtag SETENV { + $$.setenv = true; + } + | cmndtag NOSETENV { + $$.setenv = false; + } + | cmndtag LOG_INPUT { + $$.log_input = true; + } + | cmndtag NOLOG_INPUT { + $$.log_input = false; + } + | cmndtag LOG_OUTPUT { + $$.log_output = true; + } + | cmndtag NOLOG_OUTPUT { + $$.log_output = false; + } + ; + +cmnd : ALL { + $$ = new_member(NULL, ALL); + } + | ALIAS { + $$ = new_member($1, ALIAS); + } + | COMMAND { + struct sudo_command *c = ecalloc(1, sizeof(*c)); + c->cmnd = $1.cmnd; + c->args = $1.args; + $$ = new_member((char *)c, COMMAND); + } + ; + +hostaliases : hostalias + | hostaliases ':' hostalias + ; + +hostalias : ALIAS '=' hostlist { + char *s; + if ((s = alias_add($1, HOSTALIAS, $3)) != NULL) { + yyerror(s); + YYERROR; + } + } + ; + +hostlist : ophost + | hostlist ',' ophost { + list_append($1, $3); + $$ = $1; + } + ; + +cmndaliases : cmndalias + | cmndaliases ':' cmndalias + ; + +cmndalias : ALIAS '=' cmndlist { + char *s; + if ((s = alias_add($1, CMNDALIAS, $3)) != NULL) { + yyerror(s); + YYERROR; + } + } + ; + +cmndlist : opcmnd + | cmndlist ',' opcmnd { + list_append($1, $3); + $$ = $1; + } + ; + +runasaliases : runasalias + | runasaliases ':' runasalias + ; + +runasalias : ALIAS '=' userlist { + char *s; + if ((s = alias_add($1, RUNASALIAS, $3)) != NULL) { + yyerror(s); + YYERROR; + } + } + ; + +useraliases : useralias + | useraliases ':' useralias + ; + +useralias : ALIAS '=' userlist { + char *s; + if ((s = alias_add($1, USERALIAS, $3)) != NULL) { + yyerror(s); + YYERROR; + } + } + ; + +userlist : opuser + | userlist ',' opuser { + list_append($1, $3); + $$ = $1; + } + ; + +opuser : user { + $$ = $1; + $$->negated = false; + } + | '!' user { + $$ = $2; + $$->negated = true; + } + ; + +user : ALIAS { + $$ = new_member($1, ALIAS); + } + | ALL { + $$ = new_member(NULL, ALL); + } + | NETGROUP { + $$ = new_member($1, NETGROUP); + } + | USERGROUP { + $$ = new_member($1, USERGROUP); + } + | WORD { + $$ = new_member($1, WORD); + } + ; + +grouplist : opgroup + | grouplist ',' opgroup { + list_append($1, $3); + $$ = $1; + } + ; + +opgroup : group { + $$ = $1; + $$->negated = false; + } + | '!' group { + $$ = $2; + $$->negated = true; + } + ; + +group : ALIAS { + $$ = new_member($1, ALIAS); + } + | ALL { + $$ = new_member(NULL, ALL); + } + | WORD { + $$ = new_member($1, WORD); + } + ; + +%% +static struct defaults * +new_default(char *var, char *val, int op) +{ + struct defaults *d; + debug_decl(new_default, SUDO_DEBUG_PARSER) + + d = ecalloc(1, sizeof(struct defaults)); + d->var = var; + d->val = val; + tq_init(&d->binding); + /* d->type = 0; */ + d->op = op; + d->prev = d; + /* d->next = NULL; */ + + debug_return_ptr(d); +} + +static struct member * +new_member(char *name, int type) +{ + struct member *m; + debug_decl(new_member, SUDO_DEBUG_PARSER) + + m = ecalloc(1, sizeof(struct member)); + m->name = name; + m->type = type; + m->prev = m; + /* m->next = NULL; */ + + debug_return_ptr(m); +} + +/* + * Add a list of defaults structures to the defaults list. + * The binding, if non-NULL, specifies a list of hosts, users, or + * runas users the entries apply to (specified by the type). + */ +static void +add_defaults(int type, struct member *bmem, struct defaults *defs) +{ + struct defaults *d; + struct member_list binding; + debug_decl(add_defaults, SUDO_DEBUG_PARSER) + + /* + * We can only call list2tq once on bmem as it will zero + * out the prev pointer when it consumes bmem. + */ + list2tq(&binding, bmem); + + /* + * Set type and binding (who it applies to) for new entries. + */ + for (d = defs; d != NULL; d = d->next) { + d->type = type; + d->binding = binding; + } + tq_append(&defaults, defs); + + debug_return; +} + +/* + * Allocate a new struct userspec, populate it, and insert it at the + * and of the userspecs list. + */ +static void +add_userspec(struct member *members, struct privilege *privs) +{ + struct userspec *u; + debug_decl(add_userspec, SUDO_DEBUG_PARSER) + + u = ecalloc(1, sizeof(*u)); + list2tq(&u->users, members); + list2tq(&u->privileges, privs); + u->prev = u; + /* u->next = NULL; */ + tq_append(&userspecs, u); + + debug_return; +} + +/* + * Free up space used by data structures from a previous parser run and sets + * the current sudoers file to path. + */ +void +init_parser(const char *path, int quiet) +{ + struct defaults *d; + struct member *m, *binding; + struct userspec *us; + struct privilege *priv; + struct cmndspec *cs; + struct sudo_command *c; + debug_decl(init_parser, SUDO_DEBUG_PARSER) + + while ((us = tq_pop(&userspecs)) != NULL) { + while ((m = tq_pop(&us->users)) != NULL) { + efree(m->name); + efree(m); + } + while ((priv = tq_pop(&us->privileges)) != NULL) { + struct member *runasuser = NULL, *runasgroup = NULL; +#ifdef HAVE_SELINUX + char *role = NULL, *type = NULL; +#endif /* HAVE_SELINUX */ + + while ((m = tq_pop(&priv->hostlist)) != NULL) { + efree(m->name); + efree(m); + } + while ((cs = tq_pop(&priv->cmndlist)) != NULL) { +#ifdef HAVE_SELINUX + /* Only free the first instance of a role/type. */ + if (cs->role != role) { + role = cs->role; + efree(cs->role); + } + if (cs->type != type) { + type = cs->type; + efree(cs->type); + } +#endif /* HAVE_SELINUX */ + if (tq_last(&cs->runasuserlist) != runasuser) { + runasuser = tq_last(&cs->runasuserlist); + while ((m = tq_pop(&cs->runasuserlist)) != NULL) { + efree(m->name); + efree(m); + } + } + if (tq_last(&cs->runasgrouplist) != runasgroup) { + runasgroup = tq_last(&cs->runasgrouplist); + while ((m = tq_pop(&cs->runasgrouplist)) != NULL) { + efree(m->name); + efree(m); + } + } + if (cs->cmnd->type == COMMAND) { + c = (struct sudo_command *) cs->cmnd->name; + efree(c->cmnd); + efree(c->args); + } + efree(cs->cmnd->name); + efree(cs->cmnd); + efree(cs); + } + efree(priv); + } + efree(us); + } + tq_init(&userspecs); + + binding = NULL; + while ((d = tq_pop(&defaults)) != NULL) { + if (tq_last(&d->binding) != binding) { + binding = tq_last(&d->binding); + while ((m = tq_pop(&d->binding)) != NULL) { + if (m->type == COMMAND) { + c = (struct sudo_command *) m->name; + efree(c->cmnd); + efree(c->args); + } + efree(m->name); + efree(m); + } + } + efree(d->var); + efree(d->val); + efree(d); + } + tq_init(&defaults); + + init_aliases(); + + init_lexer(); + + efree(sudoers); + sudoers = path ? estrdup(path) : NULL; + + parse_error = false; + errorlineno = -1; + errorfile = sudoers; + sudoers_warnings = !quiet; + + debug_return; +} diff --git a/plugins/sudoers/group_plugin.c b/plugins/sudoers/group_plugin.c new file mode 100644 index 0000000..b7ffcd9 --- /dev/null +++ b/plugins/sudoers/group_plugin.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include +#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 TIME_WITH_SYS_TIME +# include +#endif +#ifdef HAVE_DLOPEN +# include +#else +# include "compat/dlfcn.h" +#endif +#include +#include +#include + +#include "sudoers.h" + +#ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +#endif + +#if defined(HAVE_DLOPEN) || defined(HAVE_SHL_LOAD) + +static void *group_handle; +static struct sudoers_group_plugin *group_plugin; + +/* + * Load the specified plugin and run its init function. + * Returns -1 if unable to open the plugin, else it returns + * the value from the plugin's init function. + */ +int +group_plugin_load(char *plugin_info) +{ + struct stat sb; + char *args, path[PATH_MAX]; + char **argv = NULL; + int len, rc = -1; + debug_decl(group_plugin_load, SUDO_DEBUG_UTIL) + + /* + * Fill in .so path and split out args (if any). + */ + if ((args = strpbrk(plugin_info, " \t")) != NULL) { + len = snprintf(path, sizeof(path), "%s%.*s", + (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", + (int)(args - plugin_info), plugin_info); + args++; + } else { + len = snprintf(path, sizeof(path), "%s%s", + (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info); + } + if (len <= 0 || len >= sizeof(path)) { + warningx(_("%s%s: %s"), + (*plugin_info != '/') ? _PATH_SUDO_PLUGIN_DIR : "", plugin_info, + strerror(ENAMETOOLONG)); + goto done; + } + + /* Sanity check plugin path. */ + if (stat(path, &sb) != 0) { + warning("%s", path); + goto done; + } + if (sb.st_uid != ROOT_UID) { + warningx(_("%s must be owned by uid %d"), path, ROOT_UID); + goto done; + } + if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { + warningx(_("%s must only be writable by owner"), path); + goto done; + } + + /* Open plugin and map in symbol. */ + group_handle = dlopen(path, RTLD_LAZY|RTLD_GLOBAL); + if (!group_handle) { + warningx(_("unable to dlopen %s: %s"), path, dlerror()); + goto done; + } + group_plugin = dlsym(group_handle, "group_plugin"); + if (group_plugin == NULL) { + warningx(_("unable to find symbol \"group_plugin\" in %s"), path); + goto done; + } + + if (GROUP_API_VERSION_GET_MAJOR(group_plugin->version) != GROUP_API_VERSION_MAJOR) { + warningx(_("%s: incompatible group plugin major version %d, expected %d"), + path, GROUP_API_VERSION_GET_MAJOR(group_plugin->version), + GROUP_API_VERSION_MAJOR); + goto done; + } + + /* + * Split args into a vector if specified. + */ + if (args != NULL) { + int ac = 0; + bool wasblank = true; + char *cp; + + for (cp = args; *cp != '\0'; cp++) { + if (isblank((unsigned char)*cp)) { + wasblank = true; + } else if (wasblank) { + wasblank = false; + ac++; + } + } + if (ac != 0) { + argv = emalloc2(ac, sizeof(char *)); + ac = 0; + for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t"))) + argv[ac++] = cp; + } + } + + rc = (group_plugin->init)(GROUP_API_VERSION, sudo_printf, argv); + +done: + efree(argv); + + if (rc != true) { + if (group_handle != NULL) { + dlclose(group_handle); + group_handle = NULL; + group_plugin = NULL; + } + } + + debug_return_bool(rc); +} + +void +group_plugin_unload(void) +{ + debug_decl(group_plugin_unload, SUDO_DEBUG_UTIL) + + if (group_plugin != NULL) { + (group_plugin->cleanup)(); + group_plugin = NULL; + } + if (group_handle != NULL) { + dlclose(group_handle); + group_handle = NULL; + } + debug_return; +} + +int +group_plugin_query(const char *user, const char *group, + const struct passwd *pwd) +{ + debug_decl(group_plugin_query, SUDO_DEBUG_UTIL) + + if (group_plugin == NULL) + debug_return_bool(false); + debug_return_bool((group_plugin->query)(user, group, pwd)); +} + +#else /* !HAVE_DLOPEN && !HAVE_SHL_LOAD */ + +/* + * No loadable shared object support. + */ + +int +group_plugin_load(char *plugin_info) +{ + debug_decl(group_plugin_load, SUDO_DEBUG_UTIL) + debug_return_bool(false); +} + +void +group_plugin_unload(void) +{ + debug_decl(group_plugin_unload, SUDO_DEBUG_UTIL) + debug_return; +} + +int +group_plugin_query(const char *user, const char *group, + const struct passwd *pwd) +{ + debug_decl(group_plugin_query, SUDO_DEBUG_UTIL) + debug_return_bool(false); +} + +#endif /* HAVE_DLOPEN || HAVE_SHL_LOAD */ diff --git a/plugins/sudoers/ins_2001.h b/plugins/sudoers/ins_2001.h new file mode 100644 index 0000000..63a5d64 --- /dev/null +++ b/plugins/sudoers/ins_2001.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1996, 1998, 1999 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_INS_2001_H +#define _SUDO_INS_2001_H + + /* + * HAL insults (paraphrased) from 2001. + */ + + "Just what do you think you're doing Dave?", + "It can only be attributed to human error.", + "That's something I cannot allow to happen.", + "My mind is going. I can feel it.", + "Sorry about this, I know it's a bit silly.", + "Take a stress pill and think things over.", + "This mission is too important for me to allow you to jeopardize it.", + "I feel much better now.", + +#endif /* _SUDO_INS_2001_H */ diff --git a/plugins/sudoers/ins_classic.h b/plugins/sudoers/ins_classic.h new file mode 100644 index 0000000..b1942bd --- /dev/null +++ b/plugins/sudoers/ins_classic.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 1996, 1998, 1999 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_INS_CLASSIC_H +#define _SUDO_INS_CLASSIC_H + + /* + * Insults from the original sudo(8). + */ + + "Wrong! You cheating scum!", +#ifdef PC_INSULTS + "And you call yourself a Rocket Scientist!", +#else + "No soap, honkie-lips.", +#endif + "Where did you learn to type?", + "Are you on drugs?", + "My pet ferret can type better than you!", + "You type like i drive.", + "Do you think like you type?", + "Your mind just hasn't been the same since the electro-shock, has it?", + +#endif /* _SUDO_INS_CLASSIC_H */ diff --git a/plugins/sudoers/ins_csops.h b/plugins/sudoers/ins_csops.h new file mode 100644 index 0000000..20e9b02 --- /dev/null +++ b/plugins/sudoers/ins_csops.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1996, 1998, 1999, 2004 + * 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_INS_CSOPS_H +#define _SUDO_INS_CSOPS_H + + /* + * CSOps insults (may be site dependent). + */ + + "Maybe if you used more than just two fingers...", + "BOB says: You seem to have forgotten your passwd, enter another!", + "stty: unknown mode: doofus", + "I can't hear you -- I'm using the scrambler.", + "The more you drive -- the dumber you get.", +#ifdef PC_INSULTS + "Listen, broccoli brains, I don't have time to listen to this trash.", +#else + "Listen, burrito brains, I don't have time to listen to this trash.", +#endif + "I've seen penguins that can type better than that.", + "Have you considered trying to match wits with a rutabaga?", + "You speak an infinite deal of nothing", + +#endif /* _SUDO_INS_CSOPS_H */ diff --git a/plugins/sudoers/ins_goons.h b/plugins/sudoers/ins_goons.h new file mode 100644 index 0000000..16a262a --- /dev/null +++ b/plugins/sudoers/ins_goons.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 1996, 1998, 1999 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_INS_GOONS_H +#define _SUDO_INS_GOONS_H + + /* + * Insults from the "Goon Show." + */ + + "You silly, twisted boy you.", + "He has fallen in the water!", + "We'll all be murdered in our beds!", + "You can't come in. Our tiger has got flu", + "I don't wish to know that.", + "What, what, what, what, what, what, what, what, what, what?", + "You can't get the wood, you know.", + "You'll starve!", + "... and it used to be so popular...", + "Pauses for audience applause, not a sausage", + "Hold it up to the light --- not a brain in sight!", + "Have a gorilla...", + "There must be cure for it!", + "There's a lot of it about, you know.", + "You do that again and see what happens...", + "Ying Tong Iddle I Po", + "Harm can come to a young lad like that!", + "And with that remarks folks, the case of the Crown vs yourself was proven.", + "Speak English you fool --- there are no subtitles in this scene.", + "You gotta go owwwww!", + "I have been called worse.", + "It's only your word against mine.", + "I think ... err ... I think ... I think I'll go home", + +#endif /* _SUDO_INS_GOONS_H */ diff --git a/plugins/sudoers/insults.h b/plugins/sudoers/insults.h new file mode 100644 index 0000000..bdb3fc6 --- /dev/null +++ b/plugins/sudoers/insults.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1994-1996, 1998-1999, 2004 + * 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_INSULTS_H +#define _SUDO_INSULTS_H + +#if defined(HAL_INSULTS) || defined(GOONS_INSULTS) || defined(CLASSIC_INSULTS) || defined(CSOPS_INSULTS) + +/* + * Use one or more set of insults as determined by configure + */ + +char *insults[] = { + +# ifdef HAL_INSULTS +# include "ins_2001.h" +# endif + +# ifdef GOONS_INSULTS +# include "ins_goons.h" +# endif + +# ifdef CLASSIC_INSULTS +# include "ins_classic.h" +# endif + +# ifdef CSOPS_INSULTS +# include "ins_csops.h" +# endif + + (char *) 0 + +}; + +/* + * How may I insult you? Let me count the ways... + */ +#define NOFINSULTS (sizeof(insults) / sizeof(insults[0]) - 1) + +/* + * return a pseudo-random insult. + */ +#define INSULT (insults[time(NULL) % NOFINSULTS]) + +#endif /* HAL_INSULTS || GOONS_INSULTS || CLASSIC_INSULTS || CSOPS_INSULTS */ + +#endif /* _SUDO_INSULTS_H */ diff --git a/plugins/sudoers/interfaces.c b/plugins/sudoers/interfaces.c new file mode 100644 index 0000000..624882e --- /dev/null +++ b/plugins/sudoers/interfaces.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include + +#include "sudoers.h" +#include "interfaces.h" + +#ifndef INADDR_NONE +# define INADDR_NONE ((unsigned int)-1) +#endif + +/* + * Parse a space-delimited list of IP address/netmask pairs and + * store in a list of interface structures. + */ +void +set_interfaces(const char *ai) +{ + char *addrinfo, *addr, *mask; + struct interface *ifp; + debug_decl(set_interfaces, SUDO_DEBUG_NETIF) + + addrinfo = estrdup(ai); + for (addr = strtok(addrinfo, " \t"); addr != NULL; addr = strtok(NULL, " \t")) { + /* Separate addr and mask. */ + if ((mask = strchr(addr, '/')) == NULL) + continue; + *mask++ = '\0'; + + /* Parse addr and store in list. */ + ifp = ecalloc(1, sizeof(*ifp)); + if (strchr(addr, ':')) { + /* IPv6 */ +#ifdef HAVE_STRUCT_IN6_ADDR + ifp->family = AF_INET6; + if (inet_pton(AF_INET6, addr, &ifp->addr.ip6) != 1 || + inet_pton(AF_INET6, mask, &ifp->netmask.ip6) != 1) +#endif + { + efree(ifp); + continue; + } + } else { + /* IPv4 */ + ifp->family = AF_INET; + ifp->addr.ip4.s_addr = inet_addr(addr); + ifp->netmask.ip4.s_addr = inet_addr(mask); + if (ifp->addr.ip4.s_addr == INADDR_NONE || + ifp->netmask.ip4.s_addr == INADDR_NONE) { + efree(ifp); + continue; + } + } + ifp->next = interfaces; + interfaces = ifp; + } + efree(addrinfo); + debug_return; +} + +void +dump_interfaces(const char *ai) +{ + char *cp, *addrinfo; + debug_decl(set_interfaces, SUDO_DEBUG_NETIF) + + addrinfo = estrdup(ai); + + sudo_printf(SUDO_CONV_INFO_MSG, _("Local IP address and netmask pairs:\n")); + for (cp = strtok(addrinfo, " \t"); cp != NULL; cp = strtok(NULL, " \t")) + sudo_printf(SUDO_CONV_INFO_MSG, "\t%s\n", cp); + + efree(addrinfo); + debug_return; +} diff --git a/plugins/sudoers/interfaces.h b/plugins/sudoers/interfaces.h new file mode 100644 index 0000000..e3a13bf --- /dev/null +++ b/plugins/sudoers/interfaces.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1996, 1998-2005, 2007, 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_INTERFACES_H +#define _SUDO_INTERFACES_H + +/* + * Union to hold either strucr in_addr or in6_add + */ +union sudo_in_addr_un { + struct in_addr ip4; +#ifdef HAVE_STRUCT_IN6_ADDR + struct in6_addr ip6; +#endif +}; + +/* + * IP address and netmask pairs for checking against local interfaces. + */ +struct interface { + int family; /* AF_INET or AF_INET6 */ + union sudo_in_addr_un addr; + union sudo_in_addr_un netmask; + struct interface *next; +}; + +/* + * Prototypes for external functions. + */ +int get_net_ifs(char **addrinfo); +void dump_interfaces(const char *); +void set_interfaces(const char *); + +/* + * Definitions for external variables. + */ +#ifndef _SUDO_MAIN +extern struct interface *interfaces; +#endif + +#endif /* _SUDO_INTERFACES_H */ diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c new file mode 100644 index 0000000..2757b1f --- /dev/null +++ b/plugins/sudoers/iolog.c @@ -0,0 +1,697 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#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 TIME_WITH_SYS_TIME +# include +#endif +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ZLIB_H +# include +#endif + +#include "sudoers.h" + +/* plugin_error.c */ +extern sigjmp_buf error_jmp; + +union io_fd { + FILE *f; +#ifdef HAVE_ZLIB_H + gzFile g; +#endif + void *v; +}; + +struct script_buf { + int len; /* buffer length (how much read in) */ + int off; /* write position (how much already consumed) */ + char buf[16 * 1024]; +}; + +/* XXX - separate sudoers.h and iolog.h? */ +#undef runas_pw +#undef runas_gr + +struct iolog_details { + const char *cwd; + const char *tty; + const char *user; + const char *command; + const char *iolog_path; + struct passwd *runas_pw; + struct group *runas_gr; + int iolog_stdin; + int iolog_stdout; + int iolog_stderr; + int iolog_ttyin; + int iolog_ttyout; +}; + +#define IOFD_STDIN 0 +#define IOFD_STDOUT 1 +#define IOFD_STDERR 2 +#define IOFD_TTYIN 3 +#define IOFD_TTYOUT 4 +#define IOFD_TIMING 5 +#define IOFD_MAX 6 + +#define SESSID_MAX 2176782336U + +static int iolog_compress; +static struct timeval last_time; +static union io_fd io_fds[IOFD_MAX]; +extern struct io_plugin sudoers_io; + +/* + * Create parent directories for path as needed, but not path itself. + */ +static void +mkdir_parents(char *path) +{ + struct stat sb; + char *slash = path; + debug_decl(mkdir_parents, SUDO_DEBUG_UTIL) + + for (;;) { + if ((slash = strchr(slash + 1, '/')) == NULL) + break; + *slash = '\0'; + if (stat(path, &sb) != 0) { + if (mkdir(path, S_IRWXU) != 0) + log_fatal(USE_ERRNO, _("unable to mkdir %s"), path); + } else if (!S_ISDIR(sb.st_mode)) { + log_fatal(0, _("%s: %s"), path, strerror(ENOTDIR)); + } + *slash = '/'; + } + debug_return; +} + +/* + * Read the on-disk sequence number, set sessid to the next + * number, and update the on-disk copy. + * Uses file locking to avoid sequence number collisions. + */ +void +io_nextid(char *iolog_dir, char sessid[7]) +{ + struct stat sb; + char buf[32], *ep; + int fd, i; + unsigned long id = 0; + int len; + ssize_t nread; + char pathbuf[PATH_MAX]; + static const char b36char[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + debug_decl(io_nextid, SUDO_DEBUG_UTIL) + + /* + * Create I/O log directory if it doesn't already exist. + */ + mkdir_parents(iolog_dir); + if (stat(iolog_dir, &sb) != 0) { + if (mkdir(iolog_dir, S_IRWXU) != 0) + log_fatal(USE_ERRNO, _("unable to mkdir %s"), iolog_dir); + } else if (!S_ISDIR(sb.st_mode)) { + log_fatal(0, _("%s exists but is not a directory (0%o)"), + iolog_dir, (unsigned int) sb.st_mode); + } + + /* + * Open sequence file + */ + len = snprintf(pathbuf, sizeof(pathbuf), "%s/seq", iolog_dir); + if (len <= 0 || len >= sizeof(pathbuf)) { + errno = ENAMETOOLONG; + log_fatal(USE_ERRNO, "%s/seq", pathbuf); + } + fd = open(pathbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); + if (fd == -1) + log_fatal(USE_ERRNO, _("unable to open %s"), pathbuf); + lock_file(fd, SUDO_LOCK); + + /* Read seq number (base 36). */ + nread = read(fd, buf, sizeof(buf)); + if (nread != 0) { + if (nread == -1) + log_fatal(USE_ERRNO, _("unable to read %s"), pathbuf); + id = strtoul(buf, &ep, 36); + if (buf == ep || id >= SESSID_MAX) + log_fatal(0, _("invalid sequence number %s"), pathbuf); + } + id++; + + /* + * Convert id to a string and stash in sessid. + * Note that that least significant digits go at the end of the string. + */ + for (i = 5; i >= 0; i--) { + buf[i] = b36char[id % 36]; + id /= 36; + } + buf[6] = '\n'; + + /* Stash id for logging purposes. */ + memcpy(sessid, buf, 6); + sessid[6] = '\0'; + + /* Rewind and overwrite old seq file. */ + if (lseek(fd, 0, SEEK_SET) == (off_t)-1 || write(fd, buf, 7) != 7) + log_fatal(USE_ERRNO, _("unable to write to %s"), pathbuf); + close(fd); + + debug_return; +} + +/* + * Copy iolog_path to pathbuf and create the directory and any intermediate + * directories. If iolog_path ends in 'XXXXXX', use mkdtemp(). + */ +static size_t +mkdir_iopath(const char *iolog_path, char *pathbuf, size_t pathsize) +{ + size_t len; + debug_decl(mkdir_iopath, SUDO_DEBUG_UTIL) + + len = strlcpy(pathbuf, iolog_path, pathsize); + if (len >= pathsize) { + errno = ENAMETOOLONG; + log_fatal(USE_ERRNO, "%s", iolog_path); + } + + /* + * Create path and intermediate subdirs as needed. + * If path ends in at least 6 Xs (ala POSIX mktemp), use mkdtemp(). + */ + mkdir_parents(pathbuf); + if (len >= 6 && strcmp(&pathbuf[len - 6], "XXXXXX") == 0) { + if (mkdtemp(pathbuf) == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } else { + if (mkdir(pathbuf, S_IRWXU) != 0) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } + + debug_return_size_t(len); +} + +/* + * Append suffix to pathbuf after len chars and open the resulting file. + * Note that the size of pathbuf is assumed to be PATH_MAX. + * Uses zlib if docompress is true. + * Returns the open file handle which has the close-on-exec flag set. + */ +static void * +open_io_fd(char *pathbuf, size_t len, const char *suffix, bool docompress) +{ + void *vfd = NULL; + int fd; + debug_decl(open_io_fd, SUDO_DEBUG_UTIL) + + pathbuf[len] = '\0'; + strlcat(pathbuf, suffix, PATH_MAX); + fd = open(pathbuf, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); + if (fd != -1) { + fcntl(fd, F_SETFD, FD_CLOEXEC); +#ifdef HAVE_ZLIB_H + if (docompress) + vfd = gzdopen(fd, "w"); + else +#endif + vfd = fdopen(fd, "w"); + } + debug_return_ptr(vfd); +} + +/* + * Pull out I/O log related data from user_info and command_info arrays. + */ +static void +iolog_deserialize_info(struct iolog_details *details, char * const user_info[], + char * const command_info[]) +{ + const char *runas_uid_str = "0", *runas_euid_str = NULL; + const char *runas_gid_str = "0", *runas_egid_str = NULL; + char id[MAX_UID_T_LEN + 2], *ep; + char * const *cur; + unsigned long ulval; + uid_t runas_uid = 0; + gid_t runas_gid = 0; + debug_decl(iolog_deserialize_info, SUDO_DEBUG_UTIL) + + memset(details, 0, sizeof(*details)); + + for (cur = user_info; *cur != NULL; cur++) { + switch (**cur) { + case 'c': + if (strncmp(*cur, "cwd=", sizeof("cwd=") - 1) == 0) { + details->cwd = *cur + sizeof("cwd=") - 1; + continue; + } + break; + case 't': + if (strncmp(*cur, "tty=", sizeof("tty=") - 1) == 0) { + details->tty = *cur + sizeof("tty=") - 1; + continue; + } + break; + case 'u': + if (strncmp(*cur, "user=", sizeof("user=") - 1) == 0) { + details->user = *cur + sizeof("user=") - 1; + continue; + } + break; + } + } + + for (cur = command_info; *cur != NULL; cur++) { + switch (**cur) { + case 'c': + if (strncmp(*cur, "command=", sizeof("command=") - 1) == 0) { + details->command = *cur + sizeof("command=") - 1; + continue; + } + break; + case 'i': + if (strncmp(*cur, "iolog_path=", sizeof("iolog_path=") - 1) == 0) { + details->iolog_path = *cur + sizeof("iolog_path=") - 1; + continue; + } + if (strncmp(*cur, "iolog_stdin=", sizeof("iolog_stdin=") - 1) == 0) { + if (atobool(*cur + sizeof("iolog_stdin=") - 1) == true) + details->iolog_stdin = true; + continue; + } + if (strncmp(*cur, "iolog_stdout=", sizeof("iolog_stdout=") - 1) == 0) { + if (atobool(*cur + sizeof("iolog_stdout=") - 1) == true) + details->iolog_stdout = true; + continue; + } + if (strncmp(*cur, "iolog_stderr=", sizeof("iolog_stderr=") - 1) == 0) { + if (atobool(*cur + sizeof("iolog_stderr=") - 1) == true) + details->iolog_stderr = true; + continue; + } + if (strncmp(*cur, "iolog_ttyin=", sizeof("iolog_ttyin=") - 1) == 0) { + if (atobool(*cur + sizeof("iolog_ttyin=") - 1) == true) + details->iolog_ttyin = true; + continue; + } + if (strncmp(*cur, "iolog_ttyout=", sizeof("iolog_ttyout=") - 1) == 0) { + if (atobool(*cur + sizeof("iolog_ttyout=") - 1) == true) + details->iolog_ttyout = true; + continue; + } + if (strncmp(*cur, "iolog_compress=", sizeof("iolog_compress=") - 1) == 0) { + if (atobool(*cur + sizeof("iolog_compress=") - 1) == true) + iolog_compress = true; /* must be global */ + continue; + } + break; + case 'r': + if (strncmp(*cur, "runas_gid=", sizeof("runas_gid=") - 1) == 0) { + runas_gid_str = *cur + sizeof("runas_gid=") - 1; + continue; + } + if (strncmp(*cur, "runas_egid=", sizeof("runas_egid=") - 1) == 0) { + runas_egid_str = *cur + sizeof("runas_egid=") - 1; + continue; + } + if (strncmp(*cur, "runas_uid=", sizeof("runas_uid=") - 1) == 0) { + runas_uid_str = *cur + sizeof("runas_uid=") - 1; + continue; + } + if (strncmp(*cur, "runas_euid=", sizeof("runas_euid=") - 1) == 0) { + runas_euid_str = *cur + sizeof("runas_euid=") - 1; + continue; + } + break; + } + } + + /* + * Lookup runas user and group, preferring effective over real uid/gid. + */ + if (runas_euid_str != NULL) + runas_uid_str = runas_euid_str; + if (runas_uid_str != NULL) { + errno = 0; + ulval = strtoul(runas_uid_str, &ep, 0); + if (*runas_uid_str != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + runas_uid = (uid_t)ulval; + } + } + if (runas_egid_str != NULL) + runas_gid_str = runas_egid_str; + if (runas_gid_str != NULL) { + errno = 0; + ulval = strtoul(runas_gid_str, &ep, 0); + if (*runas_gid_str != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + runas_gid = (gid_t)ulval; + } + } + + details->runas_pw = sudo_getpwuid(runas_uid); + if (details->runas_pw == NULL) { + id[0] = '#'; + strlcpy(&id[1], runas_uid_str, sizeof(id) - 1); + details->runas_pw = sudo_fakepwnam(id, runas_gid); + } + + if (runas_gid != details->runas_pw->pw_gid) { + details->runas_gr = sudo_getgrgid(runas_gid); + if (details->runas_gr == NULL) { + id[0] = '#'; + strlcpy(&id[1], runas_gid_str, sizeof(id) - 1); + details->runas_gr = sudo_fakegrnam(id); + } + } + debug_return; +} + +static int +sudoers_io_open(unsigned int version, sudo_conv_t conversation, + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], char * const command_info[], + int argc, char * const argv[], char * const user_env[], char * const args[]) +{ + struct iolog_details details; + char pathbuf[PATH_MAX], sessid[7]; + char *tofree = NULL; + char * const *cur; + const char *debug_flags = NULL; + FILE *io_logfile; + size_t len; + int rval = -1; + debug_decl(sudoers_io_open, SUDO_DEBUG_PLUGIN) + + if (!sudo_conv) + sudo_conv = conversation; + if (!sudo_printf) + sudo_printf = plugin_printf; + + /* If we have no command (because -V was specified) just return. */ + if (argc == 0) + debug_return_bool(true); + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + rval = -1; + goto done; + } + + bindtextdomain("sudoers", LOCALEDIR); + + sudo_setpwent(); + sudo_setgrent(); + + /* + * Check for debug flags in settings list. + */ + for (cur = settings; *cur != NULL; cur++) { + if (strncmp(*cur, "debug_flags=", sizeof("debug_flags=") - 1) == 0) + debug_flags = *cur + sizeof("debug_flags=") - 1; + } + if (debug_flags != NULL) + sudo_debug_init(NULL, debug_flags); + + /* + * Pull iolog settings out of command_info, if any. + */ + iolog_deserialize_info(&details, user_info, command_info); + /* Did policy module disable I/O logging? */ + if (!details.iolog_stdin && !details.iolog_ttyin && + !details.iolog_stdout && !details.iolog_stderr && + !details.iolog_ttyout) { + rval = false; + goto done; + } + + /* If no I/O log path defined we need to figure it out ourselves. */ + if (details.iolog_path == NULL) { + /* Get next session ID and convert it into a path. */ + tofree = emalloc(sizeof(_PATH_SUDO_IO_LOGDIR) + sizeof(sessid) + 2); + memcpy(tofree, _PATH_SUDO_IO_LOGDIR, sizeof(_PATH_SUDO_IO_LOGDIR)); + io_nextid(tofree, sessid); + snprintf(tofree + sizeof(_PATH_SUDO_IO_LOGDIR), sizeof(sessid) + 2, + "%c%c/%c%c/%c%c", sessid[0], sessid[1], sessid[2], sessid[3], + sessid[4], sessid[5]); + details.iolog_path = tofree; + } + + /* + * Make local copy of I/O log path and create it, along with any + * intermediate subdirs. Calls mkdtemp() if iolog_path ends in XXXXXX. + */ + len = mkdir_iopath(details.iolog_path, pathbuf, sizeof(pathbuf)); + if (len >= sizeof(pathbuf)) + goto done; + + /* + * We create 7 files: a log file, a timing file and 5 for input/output. + */ + io_logfile = open_io_fd(pathbuf, len, "/log", false); + if (io_logfile == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + + io_fds[IOFD_TIMING].v = open_io_fd(pathbuf, len, "/timing", + iolog_compress); + if (io_fds[IOFD_TIMING].v == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + + if (details.iolog_ttyin) { + io_fds[IOFD_TTYIN].v = open_io_fd(pathbuf, len, "/ttyin", + iolog_compress); + if (io_fds[IOFD_TTYIN].v == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } else { + sudoers_io.log_ttyin = NULL; + } + if (details.iolog_stdin) { + io_fds[IOFD_STDIN].v = open_io_fd(pathbuf, len, "/stdin", + iolog_compress); + if (io_fds[IOFD_STDIN].v == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } else { + sudoers_io.log_stdin = NULL; + } + if (details.iolog_ttyout) { + io_fds[IOFD_TTYOUT].v = open_io_fd(pathbuf, len, "/ttyout", + iolog_compress); + if (io_fds[IOFD_TTYOUT].v == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } else { + sudoers_io.log_ttyout = NULL; + } + if (details.iolog_stdout) { + io_fds[IOFD_STDOUT].v = open_io_fd(pathbuf, len, "/stdout", + iolog_compress); + if (io_fds[IOFD_STDOUT].v == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } else { + sudoers_io.log_stdout = NULL; + } + if (details.iolog_stderr) { + io_fds[IOFD_STDERR].v = open_io_fd(pathbuf, len, "/stderr", + iolog_compress); + if (io_fds[IOFD_STDERR].v == NULL) + log_fatal(USE_ERRNO, _("unable to create %s"), pathbuf); + } else { + sudoers_io.log_stderr = NULL; + } + + gettimeofday(&last_time, NULL); + + fprintf(io_logfile, "%ld:%s:%s:%s:%s\n", (long)last_time.tv_sec, + details.user ? details.user : "unknown", details.runas_pw->pw_name, + details.runas_gr ? details.runas_gr->gr_name : "", + details.tty ? details.tty : "unknown"); + fputs(details.cwd ? details.cwd : "unknown", io_logfile); + fputc('\n', io_logfile); + fputs(details.command ? details.command : "unknown", io_logfile); + for (cur = &argv[1]; *cur != NULL; cur++) { + fputc(' ', io_logfile); + fputs(*cur, io_logfile); + } + fputc('\n', io_logfile); + fclose(io_logfile); + + rval = true; + +done: + efree(tofree); + if (details.runas_pw) + pw_delref(details.runas_pw); + sudo_endpwent(); + if (details.runas_gr) + gr_delref(details.runas_gr); + sudo_endgrent(); + + debug_return_bool(rval); +} + +static void +sudoers_io_close(int exit_status, int error) +{ + int i; + debug_decl(sudoers_io_close, SUDO_DEBUG_PLUGIN) + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + debug_return; + } + + for (i = 0; i < IOFD_MAX; i++) { + if (io_fds[i].v == NULL) + continue; +#ifdef HAVE_ZLIB_H + if (iolog_compress) + gzclose(io_fds[i].g); + else +#endif + fclose(io_fds[i].f); + } + debug_return; +} + +static int +sudoers_io_version(int verbose) +{ + debug_decl(sudoers_io_version, SUDO_DEBUG_PLUGIN) + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + debug_return_bool(-1); + } + + sudo_printf(SUDO_CONV_INFO_MSG, "Sudoers I/O plugin version %s\n", + PACKAGE_VERSION); + + debug_return_bool(true); +} + +/* + * Generic I/O logging function. Called by the I/O logging entry points. + */ +static int +sudoers_io_log(const char *buf, unsigned int len, int idx) +{ + struct timeval now, delay; + debug_decl(sudoers_io_version, SUDO_DEBUG_PLUGIN) + + gettimeofday(&now, NULL); + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + debug_return_bool(-1); + } + +#ifdef HAVE_ZLIB_H + if (iolog_compress) + ignore_result(gzwrite(io_fds[idx].g, (const voidp)buf, len)); + else +#endif + ignore_result(fwrite(buf, 1, len, io_fds[idx].f)); + delay.tv_sec = now.tv_sec; + delay.tv_usec = now.tv_usec; + timevalsub(&delay, &last_time); +#ifdef HAVE_ZLIB_H + if (iolog_compress) + gzprintf(io_fds[IOFD_TIMING].g, "%d %f %d\n", idx, + delay.tv_sec + ((double)delay.tv_usec / 1000000), len); + else +#endif + fprintf(io_fds[IOFD_TIMING].f, "%d %f %d\n", idx, + delay.tv_sec + ((double)delay.tv_usec / 1000000), len); + last_time.tv_sec = now.tv_sec; + last_time.tv_usec = now.tv_usec; + + debug_return_bool(true); +} + +static int +sudoers_io_log_ttyin(const char *buf, unsigned int len) +{ + return sudoers_io_log(buf, len, IOFD_TTYIN); +} + +static int +sudoers_io_log_ttyout(const char *buf, unsigned int len) +{ + return sudoers_io_log(buf, len, IOFD_TTYOUT); +} + +static int +sudoers_io_log_stdin(const char *buf, unsigned int len) +{ + return sudoers_io_log(buf, len, IOFD_STDIN); +} + +static int +sudoers_io_log_stdout(const char *buf, unsigned int len) +{ + return sudoers_io_log(buf, len, IOFD_STDOUT); +} + +static int +sudoers_io_log_stderr(const char *buf, unsigned int len) +{ + return sudoers_io_log(buf, len, IOFD_STDERR); +} + +struct io_plugin sudoers_io = { + SUDO_IO_PLUGIN, + SUDO_API_VERSION, + sudoers_io_open, + sudoers_io_close, + sudoers_io_version, + sudoers_io_log_ttyin, + sudoers_io_log_ttyout, + sudoers_io_log_stdin, + sudoers_io_log_stdout, + sudoers_io_log_stderr +}; diff --git a/plugins/sudoers/iolog_path.c b/plugins/sudoers/iolog_path.c new file mode 100644 index 0000000..9640680 --- /dev/null +++ b/plugins/sudoers/iolog_path.c @@ -0,0 +1,283 @@ +/* + * 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. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_SETLOCALE +# include +#endif +#include +#include +#include + +#include "sudoers.h" + +struct path_escape { + const char *name; + size_t (*copy_fn)(char *, size_t); +}; + +static size_t fill_seq(char *, size_t); +static size_t fill_user(char *, size_t); +static size_t fill_group(char *, size_t); +static size_t fill_runas_user(char *, size_t); +static size_t fill_runas_group(char *, size_t); +static size_t fill_hostname(char *, size_t); +static size_t fill_command(char *, size_t); + +static struct path_escape escapes[] = { + { "seq", fill_seq }, + { "user", fill_user }, + { "group", fill_group }, + { "runas_user", fill_runas_user }, + { "runas_group", fill_runas_group }, + { "hostname", fill_hostname }, + { "command", fill_command }, + { NULL, NULL } +}; + +static size_t +fill_seq(char *str, size_t strsize) +{ + static char sessid[7]; + int len; + debug_decl(sudoers_io_version, SUDO_DEBUG_UTIL) + + if (sessid[0] == '\0') + io_nextid(def_iolog_dir, sessid); + + /* Path is of the form /var/log/sudo-io/00/00/01. */ + len = snprintf(str, strsize, "%c%c/%c%c/%c%c", sessid[0], + sessid[1], sessid[2], sessid[3], sessid[4], sessid[5]); + if (len < 0) + debug_return_size_t(strsize); /* handle non-standard snprintf() */ + debug_return_size_t(len); +} + +static size_t +fill_user(char *str, size_t strsize) +{ + debug_decl(fill_user, SUDO_DEBUG_UTIL) + debug_return_size_t(strlcpy(str, user_name, strsize)); +} + +static size_t +fill_group(char *str, size_t strsize) +{ + struct group *grp; + size_t len; + debug_decl(fill_group, SUDO_DEBUG_UTIL) + + if ((grp = sudo_getgrgid(user_gid)) != NULL) { + len = strlcpy(str, grp->gr_name, strsize); + gr_delref(grp); + } else { + len = strlen(str); + len = snprintf(str + len, strsize - len, "#%u", + (unsigned int) user_gid); + } + debug_return_size_t(len); +} + +static size_t +fill_runas_user(char *str, size_t strsize) +{ + debug_decl(fill_runas_user, SUDO_DEBUG_UTIL) + debug_return_size_t(strlcpy(str, runas_pw->pw_name, strsize)); +} + +static size_t +fill_runas_group(char *str, size_t strsize) +{ + struct group *grp; + size_t len; + debug_decl(fill_runas_group, SUDO_DEBUG_UTIL) + + if (runas_gr != NULL) { + len = strlcpy(str, runas_gr->gr_name, strsize); + } else { + if ((grp = sudo_getgrgid(runas_pw->pw_gid)) != NULL) { + len = strlcpy(str, grp->gr_name, strsize); + gr_delref(grp); + } else { + len = strlen(str); + len = snprintf(str + len, strsize - len, "#%u", + (unsigned int) runas_pw->pw_gid); + } + } + debug_return_size_t(len); +} + +static size_t +fill_hostname(char *str, size_t strsize) +{ + debug_decl(fill_hostname, SUDO_DEBUG_UTIL) + debug_return_size_t(strlcpy(str, user_shost, strsize)); +} + +static size_t +fill_command(char *str, size_t strsize) +{ + debug_decl(fill_command, SUDO_DEBUG_UTIL) + debug_return_size_t(strlcpy(str, user_base, strsize)); +} + +/* + * Concatenate dir + file, expanding any escape sequences. + * Returns the concatenated path and sets slashp point to + * the path separator between the expanded dir and file. + */ +char * +expand_iolog_path(const char *prefix, const char *dir, const char *file, + char **slashp) +{ + size_t len, prelen = 0; + char *dst, *dst0, *path, *pathend, tmpbuf[PATH_MAX]; + const char *endbrace, *src = dir; + int pass; + bool strfit; + debug_decl(expand_iolog_path, SUDO_DEBUG_UTIL) + + /* Expanded path must be <= PATH_MAX */ + if (prefix != NULL) + prelen = strlen(prefix); + dst = path = emalloc(prelen + PATH_MAX); + *path = '\0'; + pathend = path + prelen + PATH_MAX; + + /* Copy prefix, if present. */ + if (prefix != NULL) { + memcpy(path, prefix, prelen); + dst += prelen; + *dst = '\0'; + } + + /* Trim leading slashes from file component. */ + while (*file == '/') + file++; + + for (pass = 0; pass < 3; pass++) { + strfit = false; + switch (pass) { + case 0: + src = dir; + break; + case 1: + /* Trim trailing slashes from dir component. */ + while (dst - path - 1 > prelen && dst[-1] == '/') + dst--; + if (slashp) + *slashp = dst; + src = "/"; + break; + case 2: + src = file; + break; + } + dst0 = dst; + for (; *src != '\0'; src++) { + if (src[0] == '%') { + if (src[1] == '{') { + endbrace = strchr(src + 2, '}'); + if (endbrace != NULL) { + struct path_escape *esc; + len = (size_t)(endbrace - src - 2); + for (esc = escapes; esc->name != NULL; esc++) { + if (strncmp(src + 2, esc->name, len) == 0 && + esc->name[len] == '\0') + break; + } + if (esc->name != NULL) { + len = esc->copy_fn(dst, (size_t)(pathend - dst)); + if (len >= (size_t)(pathend - dst)) + goto bad; + dst += len; + src = endbrace; + continue; + } + } + } else if (src[1] == '%') { + /* Collapse %% -> % */ + src++; + } else { + /* May need strftime() */ + strfit = 1; + } + } + /* Need at least 2 chars, including the NUL terminator. */ + if (dst + 1 >= pathend) + goto bad; + *dst++ = *src; + } + *dst = '\0'; + + /* Expand strftime escapes as needed. */ + if (strfit) { + time_t now; + struct tm *timeptr; + + time(&now); + timeptr = localtime(&now); + +#ifdef HAVE_SETLOCALE + if (!setlocale(LC_ALL, def_sudoers_locale)) { + warningx(_("unable to set locale to \"%s\", using \"C\""), + def_sudoers_locale); + setlocale(LC_ALL, "C"); + } +#endif + /* We only calls strftime() on the current part of the buffer. */ + tmpbuf[sizeof(tmpbuf) - 1] = '\0'; + len = strftime(tmpbuf, sizeof(tmpbuf), dst0, timeptr); + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + if (len == 0 || tmpbuf[sizeof(tmpbuf) - 1] != '\0') + goto bad; /* strftime() failed, buf too small? */ + + if (len >= (size_t)(pathend - dst0)) + goto bad; /* expanded buffer too big to fit. */ + memcpy(dst0, tmpbuf, len); + dst = dst0 + len; + *dst = '\0'; + } + } + + debug_return_str(path); +bad: + efree(path); + debug_return_str(NULL); +} diff --git a/plugins/sudoers/ldap.c b/plugins/sudoers/ldap.c new file mode 100644 index 0000000..d4ee6f5 --- /dev/null +++ b/plugins/sudoers/ldap.c @@ -0,0 +1,2706 @@ +/* + * Copyright (c) 2003-2011 Todd C. Miller + * + * This code is derived from software contributed by Aaron Spangler. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#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 TIME_WITH_SYS_TIME +# include +#endif +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LBER_H +# include +#endif +#include +#if defined(HAVE_LDAP_SSL_H) +# include +#elif defined(HAVE_MPS_LDAP_SSL_H) +# include +#endif +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S +# ifdef HAVE_SASL_SASL_H +# include +# else +# include +# endif +# if HAVE_GSS_KRB5_CCACHE_NAME +# if defined(HAVE_GSSAPI_GSSAPI_KRB5_H) +# include +# include +# elif defined(HAVE_GSSAPI_GSSAPI_H) +# include +# else +# include +# endif +# endif +#endif + +#include "sudoers.h" +#include "parse.h" +#include "lbuf.h" + +/* Older Netscape LDAP SDKs don't prototype ldapssl_set_strength() */ +#if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(HAVE_LDAP_SSL_H) && !defined(HAVE_MPS_LDAP_SSL_H) +extern int ldapssl_set_strength(LDAP *ldap, int strength); +#endif + +#ifndef LDAP_OPT_SUCCESS +# define LDAP_OPT_SUCCESS LDAP_SUCCESS +#endif + +#ifndef LDAPS_PORT +# define LDAPS_PORT 636 +#endif + +#if defined(HAVE_LDAP_SASL_INTERACTIVE_BIND_S) && !defined(LDAP_SASL_QUIET) +# define LDAP_SASL_QUIET 0 +#endif + +#ifndef HAVE_LDAP_UNBIND_EXT_S +#define ldap_unbind_ext_s(a, b, c) ldap_unbind_s(a) +#endif + +#ifndef HAVE_LDAP_SEARCH_EXT_S +# ifdef HAVE_LDAP_SEARCH_ST +# define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k) \ + ldap_search_st(a, b, c, d, e, f, i, k) +# else +# define ldap_search_ext_s(a, b, c, d, e, f, g, h, i, j, k) \ + ldap_search_s(a, b, c, d, e, f, k) +# endif +#endif + +#define LDAP_FOREACH(var, ld, res) \ + for ((var) = ldap_first_entry((ld), (res)); \ + (var) != NULL; \ + (var) = ldap_next_entry((ld), (var))) + +#define DPRINTF(args, level) if (ldap_conf.debug >= level) warningx args + +#define CONF_BOOL 0 +#define CONF_INT 1 +#define CONF_STR 2 +#define CONF_LIST_STR 4 +#define CONF_DEREF_VAL 5 + +#define SUDO_LDAP_CLEAR 0 +#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 */ + int type; /* CONF_BOOL, CONF_INT, CONF_STR */ + int opt_val; /* LDAP_OPT_* (or -1 for sudo internal) */ + void *valp; /* pointer into ldap_conf */ +}; + +struct ldap_config_list_str { + struct ldap_config_list_str *next; + char val[1]; +}; + +/* LDAP configuration structure */ +static struct ldap_config { + int port; + int version; + int debug; + int ldap_debug; + int tls_checkpeer; + int timelimit; + int timeout; + int bind_timelimit; + int use_sasl; + int rootuse_sasl; + int ssl_mode; + int timed; + int deref; + char *host; + struct ldap_config_list_str *uri; + char *binddn; + char *bindpw; + char *rootbinddn; + struct ldap_config_list_str *base; + char *search_filter; + char *ssl; + char *tls_cacertfile; + char *tls_cacertdir; + char *tls_random_file; + char *tls_cipher_suite; + char *tls_certfile; + char *tls_keyfile; + char *sasl_auth_id; + char *rootsasl_auth_id; + char *sasl_secprops; + char *krb5_ccname; +} ldap_conf; + +static struct ldap_config_table ldap_conf_global[] = { + { "sudoers_debug", CONF_INT, -1, &ldap_conf.debug }, + { "host", CONF_STR, -1, &ldap_conf.host }, + { "port", CONF_INT, -1, &ldap_conf.port }, + { "ssl", CONF_STR, -1, &ldap_conf.ssl }, + { "sslpath", CONF_STR, -1, &ldap_conf.tls_certfile }, + { "uri", CONF_LIST_STR, -1, &ldap_conf.uri }, +#ifdef LDAP_OPT_DEBUG_LEVEL + { "debug", CONF_INT, LDAP_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug }, +#endif +#ifdef LDAP_OPT_X_TLS_REQUIRE_CERT + { "tls_checkpeer", CONF_BOOL, LDAP_OPT_X_TLS_REQUIRE_CERT, + &ldap_conf.tls_checkpeer }, +#else + { "tls_checkpeer", CONF_BOOL, -1, &ldap_conf.tls_checkpeer }, +#endif +#ifdef LDAP_OPT_X_TLS_CACERTFILE + { "tls_cacertfile", CONF_STR, LDAP_OPT_X_TLS_CACERTFILE, + &ldap_conf.tls_cacertfile }, + { "tls_cacert", CONF_STR, LDAP_OPT_X_TLS_CACERTFILE, + &ldap_conf.tls_cacertfile }, +#endif +#ifdef LDAP_OPT_X_TLS_CACERTDIR + { "tls_cacertdir", CONF_STR, LDAP_OPT_X_TLS_CACERTDIR, + &ldap_conf.tls_cacertdir }, +#endif +#ifdef LDAP_OPT_X_TLS_RANDOM_FILE + { "tls_randfile", CONF_STR, LDAP_OPT_X_TLS_RANDOM_FILE, + &ldap_conf.tls_random_file }, +#endif +#ifdef LDAP_OPT_X_TLS_CIPHER_SUITE + { "tls_ciphers", CONF_STR, LDAP_OPT_X_TLS_CIPHER_SUITE, + &ldap_conf.tls_cipher_suite }, +#endif +#ifdef LDAP_OPT_X_TLS_CERTFILE + { "tls_cert", CONF_STR, LDAP_OPT_X_TLS_CERTFILE, + &ldap_conf.tls_certfile }, +#else + { "tls_cert", CONF_STR, -1, &ldap_conf.tls_certfile }, +#endif +#ifdef LDAP_OPT_X_TLS_KEYFILE + { "tls_key", CONF_STR, LDAP_OPT_X_TLS_KEYFILE, + &ldap_conf.tls_keyfile }, +#else + { "tls_key", CONF_STR, -1, &ldap_conf.tls_keyfile }, +#endif + { "binddn", CONF_STR, -1, &ldap_conf.binddn }, + { "bindpw", CONF_STR, -1, &ldap_conf.bindpw }, + { "rootbinddn", CONF_STR, -1, &ldap_conf.rootbinddn }, + { "sudoers_base", CONF_LIST_STR, -1, &ldap_conf.base }, + { "sudoers_timed", CONF_BOOL, -1, &ldap_conf.timed }, + { "sudoers_search_filter", CONF_STR, -1, &ldap_conf.search_filter }, +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + { "use_sasl", CONF_BOOL, -1, &ldap_conf.use_sasl }, + { "sasl_auth_id", CONF_STR, -1, &ldap_conf.sasl_auth_id }, + { "rootuse_sasl", CONF_BOOL, -1, &ldap_conf.rootuse_sasl }, + { "rootsasl_auth_id", CONF_STR, -1, &ldap_conf.rootsasl_auth_id }, + { "krb5_ccname", CONF_STR, -1, &ldap_conf.krb5_ccname }, +#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ + { NULL } +}; + +static struct ldap_config_table ldap_conf_conn[] = { +#ifdef LDAP_OPT_PROTOCOL_VERSION + { "ldap_version", CONF_INT, LDAP_OPT_PROTOCOL_VERSION, + &ldap_conf.version }, +#endif +#ifdef LDAP_OPT_NETWORK_TIMEOUT + { "bind_timelimit", CONF_INT, -1 /* needs timeval, set manually */, + &ldap_conf.bind_timelimit }, + { "network_timeout", CONF_INT, -1 /* needs timeval, set manually */, + &ldap_conf.bind_timelimit }, +#elif defined(LDAP_X_OPT_CONNECT_TIMEOUT) + { "bind_timelimit", CONF_INT, LDAP_X_OPT_CONNECT_TIMEOUT, + &ldap_conf.bind_timelimit }, + { "network_timeout", CONF_INT, LDAP_X_OPT_CONNECT_TIMEOUT, + &ldap_conf.bind_timelimit }, +#endif + { "timelimit", CONF_INT, LDAP_OPT_TIMELIMIT, &ldap_conf.timelimit }, +#ifdef LDAP_OPT_TIMEOUT + { "timeout", CONF_INT, -1 /* needs timeval, set manually */, + &ldap_conf.timeout }, +#endif +#ifdef LDAP_OPT_DEREF + { "deref", CONF_DEREF_VAL, LDAP_OPT_DEREF, &ldap_conf.deref }, +#endif +#ifdef LDAP_OPT_X_SASL_SECPROPS + { "sasl_secprops", CONF_STR, LDAP_OPT_X_SASL_SECPROPS, + &ldap_conf.sasl_secprops }, +#endif + { NULL } +}; + +/* sudo_nss implementation */ +static int sudo_ldap_open(struct sudo_nss *nss); +static int sudo_ldap_close(struct sudo_nss *nss); +static int sudo_ldap_parse(struct sudo_nss *nss); +static int sudo_ldap_setdefs(struct sudo_nss *nss); +static int sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag); +static int sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw); +static int sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf); +static int sudo_ldap_display_bound_defaults(struct sudo_nss *nss, + struct passwd *pw, struct lbuf *lbuf); +static int sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf); +static struct ldap_result *sudo_ldap_result_get(struct sudo_nss *nss, + struct passwd *pw); + +/* + * LDAP sudo_nss handle. + * We store the connection to the LDAP server, the cached ldap_result object + * (if any), and the name of the user the query was performed for. + * If a new query is launched with sudo_ldap_result_get() that specifies a + * different user, the old cached result is freed before the new query is run. + */ +struct sudo_ldap_handle { + LDAP *ld; + struct ldap_result *result; + char *username; + struct group_list *grlist; +}; + +struct sudo_nss sudo_nss_ldap = { + &sudo_nss_ldap, + NULL, + sudo_ldap_open, + sudo_ldap_close, + sudo_ldap_parse, + sudo_ldap_setdefs, + sudo_ldap_lookup, + sudo_ldap_display_cmnd, + sudo_ldap_display_defaults, + sudo_ldap_display_bound_defaults, + sudo_ldap_display_privs +}; + +#ifdef HAVE_LDAP_CREATE +/* + * Rebuild the hosts list and include a specific port for each host. + * ldap_create() does not take a default port parameter so we must + * append one if we want something other than LDAP_PORT. + */ +static void +sudo_ldap_conf_add_ports(void) +{ + + char *host, *port, defport[13]; + char hostbuf[LINE_MAX * 2]; + debug_decl(sudo_ldap_conf_add_ports, SUDO_DEBUG_LDAP) + + hostbuf[0] = '\0'; + if (snprintf(defport, sizeof(defport), ":%d", ldap_conf.port) >= sizeof(defport)) + errorx(1, _("sudo_ldap_conf_add_ports: port too large")); + + for ((host = strtok(ldap_conf.host, " \t")); host; (host = strtok(NULL, " \t"))) { + if (hostbuf[0] != '\0') { + if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + } + + if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + /* Append port if there is not one already. */ + if ((port = strrchr(host, ':')) == NULL || + !isdigit((unsigned char)port[1])) { + if (strlcat(hostbuf, defport, sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + } + } + + efree(ldap_conf.host); + ldap_conf.host = estrdup(hostbuf); + debug_return; + +toobig: + errorx(1, _("sudo_ldap_conf_add_ports: out of space expanding hostbuf")); +} +#endif + +#ifndef HAVE_LDAP_INITIALIZE +/* + * For each uri, convert to host:port pairs. For ldaps:// enable SSL + * Accepts: uris of the form ldap:/// or ldap://hostname:portnum/ + * where the trailing slash is optional. + */ +static int +sudo_ldap_parse_uri(const struct ldap_config_list_str *uri_list) +{ + char *buf, *uri, *host, *cp, *port; + char hostbuf[LINE_MAX]; + int nldap = 0, nldaps = 0; + int rc = -1; + debug_decl(sudo_ldap_parse_uri, SUDO_DEBUG_LDAP) + + do { + buf = estrdup(uri_list->val); + hostbuf[0] = '\0'; + for ((uri = strtok(buf, " \t")); uri != NULL; (uri = strtok(NULL, " \t"))) { + if (strncasecmp(uri, "ldap://", 7) == 0) { + nldap++; + host = uri + 7; + } else if (strncasecmp(uri, "ldaps://", 8) == 0) { + nldaps++; + host = uri + 8; + } else { + warningx(_("unsupported LDAP uri type: %s"), uri); + goto done; + } + + /* trim optional trailing slash */ + if ((cp = strrchr(host, '/')) != NULL && cp[1] == '\0') { + *cp = '\0'; + } + + if (hostbuf[0] != '\0') { + if (strlcat(hostbuf, " ", sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + } + + if (*host == '\0') + host = "localhost"; /* no host specified, use localhost */ + + if (strlcat(hostbuf, host, sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + + /* If using SSL and no port specified, add port 636 */ + if (nldaps) { + if ((port = strrchr(host, ':')) == NULL || + !isdigit((unsigned char)port[1])) + if (strlcat(hostbuf, ":636", sizeof(hostbuf)) >= sizeof(hostbuf)) + goto toobig; + } + } + if (hostbuf[0] == '\0') { + warningx(_("invalid uri: %s"), uri_list->val); + goto done; + } + + if (nldaps != 0) { + if (nldap != 0) { + warningx(_("unable to mix ldap and ldaps URIs")); + goto done; + } + if (ldap_conf.ssl_mode == SUDO_LDAP_STARTTLS) { + warningx(_("unable to mix ldaps and starttls")); + goto done; + } + ldap_conf.ssl_mode = SUDO_LDAP_SSL; + } + + efree(ldap_conf.host); + ldap_conf.host = estrdup(hostbuf); + efree(buf); + } while ((uri_list = uri_list->next)); + + buf = NULL; + rc = 0; + +done: + efree(buf); + debug_return_int(rc); + +toobig: + errorx(1, _("sudo_ldap_parse_uri: out of space building hostbuf")); +} +#else +static char * +sudo_ldap_join_uri(struct ldap_config_list_str *uri_list) +{ + struct ldap_config_list_str *uri; + size_t len = 0; + char *buf, *cp; + debug_decl(sudo_ldap_join_uri, SUDO_DEBUG_LDAP) + + /* Usually just a single entry. */ + if (uri_list->next == NULL) + debug_return_str(estrdup(uri_list->val)); + + for (uri = uri_list; uri != NULL; uri = uri->next) { + len += strlen(uri->val) + 1; + } + buf = cp = emalloc(len); + buf[0] = '\0'; + for (uri = uri_list; uri != NULL; uri = uri->next) { + cp += strlcpy(cp, uri->val, len - (cp - buf)); + *cp++ = ' '; + } + cp[-1] = '\0'; + debug_return_str(buf); +} +#endif /* HAVE_LDAP_INITIALIZE */ + +static int +sudo_ldap_init(LDAP **ldp, const char *host, int port) +{ + LDAP *ld = NULL; + int rc = LDAP_CONNECT_ERROR; + debug_decl(sudo_ldap_init, SUDO_DEBUG_LDAP) + +#ifdef HAVE_LDAPSSL_INIT + if (ldap_conf.ssl_mode != SUDO_LDAP_CLEAR) { + const int defsecure = ldap_conf.ssl_mode == SUDO_LDAP_SSL; + DPRINTF(("ldapssl_clientauth_init(%s, %s)", + ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL", + ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2); + rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL, + ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL); + /* + * Starting with version 5.0, Mozilla-derived LDAP SDKs require + * the cert and key paths to be a directory, not a file. + * If the user specified a file and it fails, try the parent dir. + */ + if (rc != LDAP_SUCCESS) { + bool retry = false; + if (ldap_conf.tls_certfile != NULL) { + char *cp = strrchr(ldap_conf.tls_certfile, '/'); + if (cp != NULL && strncmp(cp + 1, "cert", 4) == 0) { + *cp = '\0'; + retry = true; + } + } + if (ldap_conf.tls_keyfile != NULL) { + char *cp = strrchr(ldap_conf.tls_keyfile, '/'); + if (cp != NULL && strncmp(cp + 1, "key", 3) == 0) { + *cp = '\0'; + retry = true; + } + } + if (retry) { + DPRINTF(("ldapssl_clientauth_init(%s, %s)", + ldap_conf.tls_certfile ? ldap_conf.tls_certfile : "NULL", + ldap_conf.tls_keyfile ? ldap_conf.tls_keyfile : "NULL"), 2); + rc = ldapssl_clientauth_init(ldap_conf.tls_certfile, NULL, + ldap_conf.tls_keyfile != NULL, ldap_conf.tls_keyfile, NULL); + } + } + if (rc != LDAP_SUCCESS) { + warningx(_("unable to initialize SSL cert and key db: %s"), + ldapssl_err2string(rc)); + if (ldap_conf.tls_certfile == NULL) + warningx(_("you must set TLS_CERT in %s to use SSL"), + _PATH_LDAP_CONF); + goto done; + } + + DPRINTF(("ldapssl_init(%s, %d, %d)", host, port, defsecure), 2); + if ((ld = ldapssl_init(host, port, defsecure)) != NULL) + rc = LDAP_SUCCESS; + } else +#endif + { +#ifdef HAVE_LDAP_CREATE + DPRINTF(("ldap_create()"), 2); + if ((rc = ldap_create(&ld)) != LDAP_SUCCESS) + goto done; + DPRINTF(("ldap_set_option(LDAP_OPT_HOST_NAME, %s)", host), 2); + rc = ldap_set_option(ld, LDAP_OPT_HOST_NAME, host); +#else + DPRINTF(("ldap_init(%s, %d)", host, port), 2); + if ((ld = ldap_init(host, port)) != NULL) + rc = LDAP_SUCCESS; +#endif + } + +done: + *ldp = ld; + debug_return_int(rc); +} + +/* + * Walk through search results and return true if we have a matching + * netgroup, else false. + */ +static bool +sudo_ldap_check_user_netgroup(LDAP *ld, LDAPMessage *entry, char *user) +{ + struct berval **bv, **p; + char *val; + int ret = false; + debug_decl(sudo_ldap_check_user_netgroup, SUDO_DEBUG_LDAP) + + if (!entry) + debug_return_bool(ret); + + /* get the values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoUser"); + if (bv == NULL) + debug_return_bool(ret); + + /* walk through values */ + for (p = bv; *p != NULL && !ret; p++) { + val = (*p)->bv_val; + /* match any */ + if (netgr_matches(val, NULL, NULL, user)) + ret = true; + DPRINTF(("ldap sudoUser netgroup '%s' ... %s", val, + ret ? "MATCH!" : "not"), 2 + ((ret) ? 0 : 1)); + } + + ldap_value_free_len(bv); /* cleanup */ + + debug_return_bool(ret); +} + +/* +* Walk through search results and return true if we have a +* host match, else false. +*/ +static bool +sudo_ldap_check_host(LDAP *ld, LDAPMessage *entry) +{ + struct berval **bv, **p; + char *val; + bool ret = false; + debug_decl(sudo_ldap_check_host, SUDO_DEBUG_LDAP) + + if (!entry) + debug_return_bool(ret); + + /* get the values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoHost"); + if (bv == NULL) + debug_return_bool(ret); + + /* walk through values */ + for (p = bv; *p != NULL && !ret; p++) { + val = (*p)->bv_val; + /* match any or address or netgroup or hostname */ + if (!strcmp(val, "ALL") || addr_matches(val) || + netgr_matches(val, user_host, user_shost, NULL) || + hostname_matches(user_shost, user_host, val)) + ret = true; + DPRINTF(("ldap sudoHost '%s' ... %s", val, + ret ? "MATCH!" : "not"), 2); + } + + ldap_value_free_len(bv); /* cleanup */ + + debug_return_bool(ret); +} + +static int +sudo_ldap_check_runas_user(LDAP *ld, LDAPMessage *entry) +{ + struct berval **bv, **p; + char *val; + bool ret = false; + debug_decl(sudo_ldap_check_runas_user, SUDO_DEBUG_LDAP) + + if (!runas_pw) + debug_return_bool(UNSPEC); + + /* get the runas user from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); + if (bv == NULL) + bv = ldap_get_values_len(ld, entry, "sudoRunAs"); /* old style */ + + /* + * BUG: + * + * if runas is not specified on the command line, the only information + * as to which user to run as is in the runas_default option. We should + * check to see if we have the local option present. Unfortunately we + * don't parse these options until after this routine says yes or no. + * The query has already returned, so we could peek at the attribute + * values here though. + * + * For now just require users to always use -u option unless its set + * in the global defaults. This behaviour is no different than the global + * /etc/sudoers. + * + * Sigh - maybe add this feature later + */ + + /* + * If there are no runas entries, match runas_default against + * what the user specified on the command line. + */ + if (bv == NULL) + debug_return_bool(!strcasecmp(runas_pw->pw_name, def_runas_default)); + + /* walk through values returned, looking for a match */ + for (p = bv; *p != NULL && !ret; p++) { + val = (*p)->bv_val; + switch (val[0]) { + case '+': + if (netgr_matches(val, NULL, NULL, runas_pw->pw_name)) + ret = true; + break; + case '%': + if (usergr_matches(val, runas_pw->pw_name, runas_pw)) + ret = true; + break; + case 'A': + if (strcmp(val, "ALL") == 0) { + ret = true; + break; + } + /* FALLTHROUGH */ + default: + if (strcasecmp(val, runas_pw->pw_name) == 0) + ret = true; + break; + } + DPRINTF(("ldap sudoRunAsUser '%s' ... %s", val, + ret ? "MATCH!" : "not"), 2); + } + + ldap_value_free_len(bv); /* cleanup */ + + debug_return_bool(ret); +} + +static int +sudo_ldap_check_runas_group(LDAP *ld, LDAPMessage *entry) +{ + struct berval **bv, **p; + char *val; + bool ret = false; + debug_decl(sudo_ldap_check_runas_group, SUDO_DEBUG_LDAP) + + /* runas_gr is only set if the user specified the -g flag */ + if (!runas_gr) + debug_return_bool(UNSPEC); + + /* get the values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); + if (bv == NULL) + debug_return_bool(ret); + + /* walk through values returned, looking for a match */ + for (p = bv; *p != NULL && !ret; p++) { + val = (*p)->bv_val; + if (strcmp(val, "ALL") == 0 || group_matches(val, runas_gr)) + ret = true; + DPRINTF(("ldap sudoRunAsGroup '%s' ... %s", val, + ret ? "MATCH!" : "not"), 2); + } + + ldap_value_free_len(bv); /* cleanup */ + + debug_return_bool(ret); +} + +/* + * Walk through search results and return true if we have a runas match, + * else false. RunAs info is optional. + */ +static bool +sudo_ldap_check_runas(LDAP *ld, LDAPMessage *entry) +{ + bool ret; + debug_decl(sudo_ldap_check_runas, SUDO_DEBUG_LDAP) + + if (!entry) + debug_return_bool(false); + + ret = sudo_ldap_check_runas_user(ld, entry) != false && + sudo_ldap_check_runas_group(ld, entry) != false; + + debug_return_bool(ret); +} + +/* + * Walk through search results and return true if we have a command match, + * false if disallowed and UNSPEC if not matched. + */ +static int +sudo_ldap_check_command(LDAP *ld, LDAPMessage *entry, int *setenv_implied) +{ + struct berval **bv, **p; + char *allowed_cmnd, *allowed_args, *val; + bool foundbang; + int ret = UNSPEC; + debug_decl(sudo_ldap_check_command, SUDO_DEBUG_LDAP) + + if (!entry) + debug_return_bool(ret); + + bv = ldap_get_values_len(ld, entry, "sudoCommand"); + if (bv == NULL) + debug_return_bool(ret); + + for (p = bv; *p != NULL && ret != false; p++) { + val = (*p)->bv_val; + /* Match against ALL ? */ + if (!strcmp(val, "ALL")) { + ret = true; + if (setenv_implied != NULL) + *setenv_implied = true; + DPRINTF(("ldap sudoCommand '%s' ... MATCH!", val), 2); + continue; + } + + /* check for !command */ + if (*val == '!') { + foundbang = true; + allowed_cmnd = estrdup(1 + val); /* !command */ + } else { + foundbang = false; + allowed_cmnd = estrdup(val); /* command */ + } + + /* split optional args away from command */ + allowed_args = strchr(allowed_cmnd, ' '); + if (allowed_args) + *allowed_args++ = '\0'; + + /* check the command like normal */ + if (command_matches(allowed_cmnd, allowed_args)) { + /* + * If allowed (no bang) set ret but keep on checking. + * If disallowed (bang), exit loop. + */ + ret = foundbang ? false : true; + } + DPRINTF(("ldap sudoCommand '%s' ... %s", val, + ret == true ? "MATCH!" : "not"), 2); + + efree(allowed_cmnd); /* cleanup */ + } + + ldap_value_free_len(bv); /* more cleanup */ + + debug_return_bool(ret); +} + +/* + * Search for boolean "option" in sudoOption. + * Returns true if found and allowed, false if negated, else UNSPEC. + */ +static int +sudo_ldap_check_bool(LDAP *ld, LDAPMessage *entry, char *option) +{ + struct berval **bv, **p; + char ch, *var; + int ret = UNSPEC; + debug_decl(sudo_ldap_check_bool, SUDO_DEBUG_LDAP) + + if (entry == NULL) + debug_return_bool(ret); + + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv == NULL) + debug_return_bool(ret); + + /* walk through options */ + for (p = bv; *p != NULL; p++) { + var = (*p)->bv_val;; + DPRINTF(("ldap sudoOption: '%s'", var), 2); + + if ((ch = *var) == '!') + var++; + if (strcmp(var, option) == 0) + ret = (ch != '!'); + } + + ldap_value_free_len(bv); + + debug_return_bool(ret); +} + +/* + * Read sudoOption and modify the defaults as we go. This is used once + * from the cn=defaults entry and also once when a final sudoRole is matched. + */ +static void +sudo_ldap_parse_options(LDAP *ld, LDAPMessage *entry) +{ + struct berval **bv, **p; + char op, *var, *val; + debug_decl(sudo_ldap_parse_options, SUDO_DEBUG_LDAP) + + if (entry == NULL) + debug_return; + + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv == NULL) + debug_return; + + /* walk through options */ + for (p = bv; *p != NULL; p++) { + var = estrdup((*p)->bv_val); + DPRINTF(("ldap sudoOption: '%s'", var), 2); + + /* check for equals sign past first char */ + val = strchr(var, '='); + if (val > var) { + *val++ = '\0'; /* split on = and truncate var */ + op = *(val - 2); /* peek for += or -= cases */ + if (op == '+' || op == '-') { + *(val - 2) = '\0'; /* found, remove extra char */ + /* case var+=val or var-=val */ + set_default(var, val, (int) op); + } else { + /* case var=val */ + set_default(var, val, true); + } + } else if (*var == '!') { + /* case !var Boolean False */ + set_default(var + 1, NULL, false); + } else { + /* case var Boolean True */ + set_default(var, NULL, true); + } + efree(var); + } + + ldap_value_free_len(bv); + + debug_return; +} + +/* + * Build an LDAP timefilter. + * + * Stores a filter in the buffer that makes sure only entries + * are selected that have a sudoNotBefore in the past and a + * sudoNotAfter in the future, i.e. a filter of the following + * structure (spaced out a little more for better readability: + * + * (& + * (| + * (!(sudoNotAfter=*)) + * (sudoNotAfter>__now__) + * ) + * (| + * (!(sudoNotBefore=*)) + * (sudoNotBefore<__now__) + * ) + * ) + * + * If either the sudoNotAfter or sudoNotBefore attributes are missing, + * no time restriction shall be imposed. + */ +static int +sudo_ldap_timefilter(char *buffer, size_t buffersize) +{ + struct tm *tp; + time_t now; + char timebuffer[16]; + int bytes = 0; + debug_decl(sudo_ldap_timefilter, SUDO_DEBUG_LDAP) + + /* Make sure we have a formatted timestamp for __now__. */ + time(&now); + if ((tp = gmtime(&now)) == NULL) { + warning(_("unable to get GMT time")); + goto done; + } + + /* Format the timestamp according to the RFC. */ + if (strftime(timebuffer, sizeof(timebuffer), "%Y%m%d%H%M%SZ", 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: + debug_return_int(bytes); +} + +/* + * Builds up a filter to search for default settings + */ +static char * +sudo_ldap_build_default_filter(void) +{ + char *filt; + debug_decl(sudo_ldap_build_default_filter, SUDO_DEBUG_LDAP) + + if (ldap_conf.search_filter) + easprintf(&filt, "(&%s(cn=defaults))", ldap_conf.search_filter); + else + filt = estrdup("cn=defaults"); + debug_return_str(filt); +} + +/* + * Determine length of query value after escaping characters + * as per RFC 4515. + */ +static size_t +sudo_ldap_value_len(const char *value) +{ + const char *s; + size_t len = 0; + + for (s = value; *s != '\0'; s++) { + switch (*s) { + case '\\': + case '(': + case ')': + case '*': + len += 2; + break; + } + } + len += (size_t)(s - value); + return len; +} + +/* + * Like strlcat() but escapes characters as per RFC 4515. + */ +static size_t +sudo_ldap_value_cat(char *dst, const char *src, size_t size) +{ + char *d = dst; + const char *s = src; + size_t n = size; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = size - dlen; + + if (n == 0) + return dlen + strlen(s); + while (*s != '\0') { + switch (*s) { + case '\\': + if (n < 3) + goto done; + *d++ = '\\'; + *d++ = '5'; + *d++ = 'c'; + n -= 3; + break; + case '(': + if (n < 3) + goto done; + *d++ = '\\'; + *d++ = '2'; + *d++ = '8'; + n -= 3; + break; + case ')': + if (n < 3) + goto done; + *d++ = '\\'; + *d++ = '2'; + *d++ = '9'; + n -= 3; + break; + case '*': + if (n < 3) + goto done; + *d++ = '\\'; + *d++ = '2'; + *d++ = 'a'; + n -= 3; + break; + default: + if (n < 1) + goto done; + *d++ = *s; + n--; + break; + } + s++; + } +done: + *d = '\0'; + while (*s != '\0') + s++; + return dlen + (s - src); /* count does not include NUL */ +} + +/* + * Builds up a filter to check against LDAP. + */ +static char * +sudo_ldap_build_pass1(struct passwd *pw) +{ + struct group *grp; + char *buf, timebuffer[TIMEFILTER_LENGTH], gidbuf[MAX_UID_T_LEN]; + struct group_list *grlist; + size_t sz = 0; + int i; + debug_decl(sudo_ldap_build_pass1, SUDO_DEBUG_LDAP) + + /* 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 + sudo_ldap_value_len(pw->pw_name); + + /* Add space for primary and supplementary groups and gids */ + if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { + sz += 12 + sudo_ldap_value_len(grp->gr_name); + } + sz += 13 + MAX_UID_T_LEN; + if ((grlist = get_group_list(pw)) != NULL) { + for (i = 0; i < grlist->ngroups; i++) { + if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0) + continue; + sz += 12 + sudo_ldap_value_len(grlist->groups[i]); + } + for (i = 0; i < grlist->ngids; i++) { + if (pw->pw_gid == grlist->gids[i]) + continue; + sz += 13 + MAX_UID_T_LEN; + } + } + + /* If timed, add space for time limits. */ + if (ldap_conf.timed) + sz += TIMEFILTER_LENGTH; + buf = emalloc(sz); + *buf = '\0'; + + /* + * If timed or using a search filter, start a global AND clause to + * contain the search filter, search criteria, and time restriction. + */ + if (ldap_conf.timed || ldap_conf.search_filter) + (void) strlcpy(buf, "(&", sz); + + if (ldap_conf.search_filter) + (void) strlcat(buf, ldap_conf.search_filter, sz); + + /* Global OR + sudoUser=user_name filter */ + (void) strlcat(buf, "(|(sudoUser=", sz); + (void) sudo_ldap_value_cat(buf, pw->pw_name, sz); + (void) strlcat(buf, ")", sz); + + /* Append primary group and gid */ + if (grp != NULL) { + (void) strlcat(buf, "(sudoUser=%", sz); + (void) sudo_ldap_value_cat(buf, grp->gr_name, sz); + (void) strlcat(buf, ")", sz); + } + (void) snprintf(gidbuf, sizeof(gidbuf), "%u", (unsigned int)pw->pw_gid); + (void) strlcat(buf, "(sudoUser=%#", sz); + (void) strlcat(buf, gidbuf, sz); + (void) strlcat(buf, ")", sz); + + /* Append supplementary groups and gids */ + if (grlist != NULL) { + for (i = 0; i < grlist->ngroups; i++) { + if (grp != NULL && strcasecmp(grlist->groups[i], grp->gr_name) == 0) + continue; + (void) strlcat(buf, "(sudoUser=%", sz); + (void) sudo_ldap_value_cat(buf, grlist->groups[i], sz); + (void) strlcat(buf, ")", sz); + } + for (i = 0; i < grlist->ngids; i++) { + if (pw->pw_gid == grlist->gids[i]) + continue; + (void) snprintf(gidbuf, sizeof(gidbuf), "%u", + (unsigned int)grlist->gids[i]); + (void) strlcat(buf, "(sudoUser=%#", sz); + (void) strlcat(buf, gidbuf, sz); + (void) strlcat(buf, ")", sz); + } + } + + /* Done with groups. */ + if (grlist != NULL) + grlist_delref(grlist); + if (grp != NULL) + gr_delref(grp); + + /* Add ALL to list and end the global OR */ + if (strlcat(buf, "(sudoUser=ALL)", sz) >= sz) + errorx(1, _("sudo_ldap_build_pass1 allocation mismatch")); + + /* Add the time restriction, or simply end the global OR. */ + if (ldap_conf.timed) { + strlcat(buf, ")", sz); /* closes the global OR */ + sudo_ldap_timefilter(timebuffer, sizeof(timebuffer)); + strlcat(buf, timebuffer, sz); + } else if (ldap_conf.search_filter) { + strlcat(buf, ")", sz); /* closes the global OR */ + } + strlcat(buf, ")", sz); /* closes the global OR or the global AND */ + + debug_return_str(buf); +} + +/* + * Builds up a filter to check against netgroup entries in LDAP. + */ +static char * +sudo_ldap_build_pass2(void) +{ + char *filt, timebuffer[TIMEFILTER_LENGTH]; + debug_decl(sudo_ldap_build_pass2, SUDO_DEBUG_LDAP) + + 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) ? ")" : ""); + + debug_return_str(filt); +} + +static void +sudo_ldap_read_secret(const char *path) +{ + FILE *fp; + char buf[LINE_MAX], *cp; + debug_decl(sudo_ldap_read_secret, SUDO_DEBUG_LDAP) + + if ((fp = fopen(_PATH_LDAP_SECRET, "r")) != NULL) { + if (fgets(buf, sizeof(buf), fp) != NULL) { + if ((cp = strchr(buf, '\n')) != NULL) + *cp = '\0'; + /* copy to bindpw and binddn */ + efree(ldap_conf.bindpw); + ldap_conf.bindpw = estrdup(buf); + efree(ldap_conf.binddn); + ldap_conf.binddn = ldap_conf.rootbinddn; + ldap_conf.rootbinddn = NULL; + } + fclose(fp); + } + debug_return; +} + +/* + * Look up keyword in config tables. + * Returns true if found, else false. + */ +static bool +sudo_ldap_parse_keyword(const char *keyword, const char *value, + struct ldap_config_table *table) +{ + struct ldap_config_table *cur; + debug_decl(sudo_ldap_parse_keyword, SUDO_DEBUG_LDAP) + + /* Look up keyword in config tables */ + for (cur = table; cur->conf_str != NULL; cur++) { + if (strcasecmp(keyword, cur->conf_str) == 0) { + switch (cur->type) { + case CONF_DEREF_VAL: + if (strcasecmp(value, "searching") == 0) + *(int *)(cur->valp) = LDAP_DEREF_SEARCHING; + else if (strcasecmp(value, "finding") == 0) + *(int *)(cur->valp) = LDAP_DEREF_FINDING; + else if (strcasecmp(value, "always") == 0) + *(int *)(cur->valp) = LDAP_DEREF_ALWAYS; + else + *(int *)(cur->valp) = LDAP_DEREF_NEVER; + break; + case CONF_BOOL: + *(int *)(cur->valp) = atobool(value) == true; + break; + case CONF_INT: + *(int *)(cur->valp) = atoi(value); + break; + case CONF_STR: + efree(*(char **)(cur->valp)); + *(char **)(cur->valp) = estrdup(value); + break; + case CONF_LIST_STR: + { + struct ldap_config_list_str **p; + size_t len = strlen(value); + + if (len > 0) { + p = (struct ldap_config_list_str **)cur->valp; + while (*p != NULL) + p = &(*p)->next; + *p = emalloc(sizeof(struct ldap_config_list_str) + len); + memcpy((*p)->val, value, len + 1); + (*p)->next = NULL; + } + } + break; + } + debug_return_bool(true); + } + } + debug_return_bool(false); +} + +static bool +sudo_ldap_read_config(void) +{ + FILE *fp; + char *cp, *keyword, *value; + debug_decl(sudo_ldap_read_config, SUDO_DEBUG_LDAP) + + /* defaults */ + ldap_conf.version = 3; + ldap_conf.port = -1; + ldap_conf.tls_checkpeer = -1; + ldap_conf.timelimit = -1; + ldap_conf.timeout = -1; + ldap_conf.bind_timelimit = -1; + ldap_conf.use_sasl = -1; + ldap_conf.rootuse_sasl = -1; + ldap_conf.deref = -1; + + if ((fp = fopen(_PATH_LDAP_CONF, "r")) == NULL) + debug_return_bool(false); + + while ((cp = sudo_parseln(fp)) != NULL) { + if (*cp == '\0') + continue; /* skip empty line */ + + /* split into keyword and value */ + keyword = cp; + while (*cp && !isblank((unsigned char) *cp)) + cp++; + if (*cp) + *cp++ = '\0'; /* terminate keyword */ + + /* skip whitespace before value */ + while (isblank((unsigned char) *cp)) + cp++; + value = cp; + + /* Look up keyword in config tables */ + if (!sudo_ldap_parse_keyword(keyword, value, ldap_conf_global)) + sudo_ldap_parse_keyword(keyword, value, ldap_conf_conn); + } + fclose(fp); + + if (!ldap_conf.host) + ldap_conf.host = estrdup("localhost"); + + if (ldap_conf.debug > 1) { + sudo_printf(SUDO_CONV_ERROR_MSG, "LDAP Config Summary\n"); + sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n"); + if (ldap_conf.uri) { + struct ldap_config_list_str *uri = ldap_conf.uri; + + do { + sudo_printf(SUDO_CONV_ERROR_MSG, "uri %s\n", + uri->val); + } while ((uri = uri->next) != NULL); + } else { + sudo_printf(SUDO_CONV_ERROR_MSG, "host %s\n", + ldap_conf.host ? ldap_conf.host : "(NONE)"); + sudo_printf(SUDO_CONV_ERROR_MSG, "port %d\n", + ldap_conf.port); + } + sudo_printf(SUDO_CONV_ERROR_MSG, "ldap_version %d\n", + ldap_conf.version); + + if (ldap_conf.base) { + struct ldap_config_list_str *base = ldap_conf.base; + do { + sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n", + base->val); + } while ((base = base->next) != NULL); + } else { + sudo_printf(SUDO_CONV_ERROR_MSG, "sudoers_base %s\n", + "(NONE: LDAP disabled)"); + } + if (ldap_conf.search_filter) { + sudo_printf(SUDO_CONV_ERROR_MSG, "search_filter %s\n", + ldap_conf.search_filter); + } + sudo_printf(SUDO_CONV_ERROR_MSG, "binddn %s\n", + ldap_conf.binddn ? ldap_conf.binddn : "(anonymous)"); + sudo_printf(SUDO_CONV_ERROR_MSG, "bindpw %s\n", + ldap_conf.bindpw ? ldap_conf.bindpw : "(anonymous)"); + if (ldap_conf.bind_timelimit > 0) { + sudo_printf(SUDO_CONV_ERROR_MSG, "bind_timelimit %d\n", + ldap_conf.bind_timelimit); + } + if (ldap_conf.timelimit > 0) { + sudo_printf(SUDO_CONV_ERROR_MSG, "timelimit %d\n", + ldap_conf.timelimit); + } + if (ldap_conf.deref != -1) { + sudo_printf(SUDO_CONV_ERROR_MSG, "deref %d\n", + ldap_conf.deref); + } + sudo_printf(SUDO_CONV_ERROR_MSG, "ssl %s\n", + ldap_conf.ssl ? ldap_conf.ssl : "(no)"); + if (ldap_conf.tls_checkpeer != -1) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_checkpeer %s\n", + ldap_conf.tls_checkpeer ? "(yes)" : "(no)"); + } + if (ldap_conf.tls_cacertfile != NULL) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertfile %s\n", + ldap_conf.tls_cacertfile); + } + if (ldap_conf.tls_cacertdir != NULL) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cacertdir %s\n", + ldap_conf.tls_cacertdir); + } + if (ldap_conf.tls_random_file != NULL) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_random_file %s\n", + ldap_conf.tls_random_file); + } + if (ldap_conf.tls_cipher_suite != NULL) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_cipher_suite %s\n", + ldap_conf.tls_cipher_suite); + } + if (ldap_conf.tls_certfile != NULL) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_certfile %s\n", + ldap_conf.tls_certfile); + } + if (ldap_conf.tls_keyfile != NULL) { + sudo_printf(SUDO_CONV_ERROR_MSG, "tls_keyfile %s\n", + ldap_conf.tls_keyfile); + } +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + if (ldap_conf.use_sasl != -1) { + sudo_printf(SUDO_CONV_ERROR_MSG, "use_sasl %s\n", + ldap_conf.use_sasl ? "yes" : "no"); + sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_auth_id %s\n", + ldap_conf.sasl_auth_id ? ldap_conf.sasl_auth_id : "(NONE)"); + sudo_printf(SUDO_CONV_ERROR_MSG, "rootuse_sasl %d\n", + ldap_conf.rootuse_sasl); + sudo_printf(SUDO_CONV_ERROR_MSG, "rootsasl_auth_id %s\n", + ldap_conf.rootsasl_auth_id ? ldap_conf.rootsasl_auth_id : "(NONE)"); + sudo_printf(SUDO_CONV_ERROR_MSG, "sasl_secprops %s\n", + ldap_conf.sasl_secprops ? ldap_conf.sasl_secprops : "(NONE)"); + sudo_printf(SUDO_CONV_ERROR_MSG, "krb5_ccname %s\n", + ldap_conf.krb5_ccname ? ldap_conf.krb5_ccname : "(NONE)"); + } +#endif + sudo_printf(SUDO_CONV_ERROR_MSG, "===================\n"); + } + if (!ldap_conf.base) + debug_return_bool(false); /* if no base is defined, ignore LDAP */ + + if (ldap_conf.bind_timelimit > 0) + ldap_conf.bind_timelimit *= 1000; /* convert to ms */ + + /* + * Interpret SSL option + */ + if (ldap_conf.ssl != NULL) { + if (strcasecmp(ldap_conf.ssl, "start_tls") == 0) + ldap_conf.ssl_mode = SUDO_LDAP_STARTTLS; + else if (atobool(ldap_conf.ssl) == true) + ldap_conf.ssl_mode = SUDO_LDAP_SSL; + } + +#if defined(HAVE_LDAPSSL_SET_STRENGTH) && !defined(LDAP_OPT_X_TLS_REQUIRE_CERT) + if (ldap_conf.tls_checkpeer != -1) { + ldapssl_set_strength(NULL, + ldap_conf.tls_checkpeer ? LDAPSSL_AUTH_CERT : LDAPSSL_AUTH_WEAK); + } +#endif + +#ifndef HAVE_LDAP_INITIALIZE + /* Convert uri list to host list if no ldap_initialize(). */ + if (ldap_conf.uri) { + struct ldap_config_list_str *uri = ldap_conf.uri; + if (sudo_ldap_parse_uri(uri) != 0) + debug_return_bool(false); + do { + ldap_conf.uri = uri->next; + efree(uri); + } while ((uri = ldap_conf.uri)); + ldap_conf.port = LDAP_PORT; + } +#endif + + if (!ldap_conf.uri) { + /* Use port 389 for plaintext LDAP and port 636 for SSL LDAP */ + if (ldap_conf.port < 0) + ldap_conf.port = + ldap_conf.ssl_mode == SUDO_LDAP_SSL ? LDAPS_PORT : LDAP_PORT; + +#ifdef HAVE_LDAP_CREATE + /* + * Cannot specify port directly to ldap_create(), each host must + * include :port to override the default. + */ + if (ldap_conf.port != LDAP_PORT) + sudo_ldap_conf_add_ports(); +#endif + } + + /* If search filter is not parenthesized, make it so. */ + if (ldap_conf.search_filter && ldap_conf.search_filter[0] != '(') { + size_t len = strlen(ldap_conf.search_filter); + cp = ldap_conf.search_filter; + ldap_conf.search_filter = emalloc(len + 3); + ldap_conf.search_filter[0] = '('; + memcpy(ldap_conf.search_filter + 1, cp, len); + ldap_conf.search_filter[len + 1] = ')'; + ldap_conf.search_filter[len + 2] = '\0'; + efree(cp); + } + + /* If rootbinddn set, read in /etc/ldap.secret if it exists. */ + if (ldap_conf.rootbinddn) + sudo_ldap_read_secret(_PATH_LDAP_SECRET); + +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + /* + * Make sure we can open the file specified by krb5_ccname. + */ + if (ldap_conf.krb5_ccname != NULL) { + if (strncasecmp(ldap_conf.krb5_ccname, "FILE:", 5) == 0 || + strncasecmp(ldap_conf.krb5_ccname, "WRFILE:", 7) == 0) { + value = ldap_conf.krb5_ccname + + (ldap_conf.krb5_ccname[4] == ':' ? 5 : 7); + if ((fp = fopen(value, "r")) != NULL) { + DPRINTF(("using krb5 credential cache: %s", value), 1); + fclose(fp); + } else { + /* Can't open it, just ignore the entry. */ + DPRINTF(("unable to open krb5 credential cache: %s", value), 1); + efree(ldap_conf.krb5_ccname); + ldap_conf.krb5_ccname = NULL; + } + } + } +#endif + debug_return_bool(true); +} + +/* + * Extract the dn from an entry and return the first rdn from it. + */ +static char * +sudo_ldap_get_first_rdn(LDAP *ld, LDAPMessage *entry) +{ +#ifdef HAVE_LDAP_STR2DN + char *dn, *rdn = NULL; + LDAPDN tmpDN; + debug_decl(sudo_ldap_get_first_rdn, SUDO_DEBUG_LDAP) + + if ((dn = ldap_get_dn(ld, entry)) == NULL) + debug_return_str(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); + debug_return_str(rdn); +#else + char *dn, **edn; + debug_decl(sudo_ldap_get_first_rdn, SUDO_DEBUG_LDAP) + + if ((dn = ldap_get_dn(ld, entry)) == NULL) + return NULL; + edn = ldap_explode_dn(dn, 1); + ldap_memfree(dn); + debug_return_str(edn ? edn[0] : NULL); +#endif +} + +/* + * Fetch and display the global Options. + */ +static int +sudo_ldap_display_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + struct berval **bv, **p; + struct timeval tv, *tvp = NULL; + struct ldap_config_list_str *base; + struct sudo_ldap_handle *handle = nss->handle; + LDAP *ld; + LDAPMessage *entry, *result; + char *prefix, *filt; + int rc, count = 0; + debug_decl(sudo_ldap_display_defaults, SUDO_DEBUG_LDAP) + + if (handle == NULL || handle->ld == NULL) + goto done; + ld = handle->ld; + + filt = sudo_ldap_build_default_filter(); + for (base = ldap_conf.base; base != NULL; base = base->next) { + if (ldap_conf.timeout > 0) { + tv.tv_sec = ldap_conf.timeout; + tv.tv_usec = 0; + tvp = &tv; + } + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, + filt, NULL, 0, NULL, NULL, tvp, 0, &result); + if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv != NULL) { + if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) + prefix = " "; + else + prefix = ", "; + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", prefix, (*p)->bv_val); + prefix = ", "; + count++; + } + ldap_value_free_len(bv); + } + } + if (result) + ldap_msgfree(result); + } + efree(filt); +done: + debug_return_int(count); +} + +/* + * STUB + */ +static int +sudo_ldap_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + debug_decl(sudo_ldap_display_bound_defaults, SUDO_DEBUG_LDAP) + debug_return_int(0); +} + +/* + * Print a record in the short form, ala file sudoers. + */ +static int +sudo_ldap_display_entry_short(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf) +{ + struct berval **bv, **p; + int count = 0; + debug_decl(sudo_ldap_display_entry_short, SUDO_DEBUG_LDAP) + + lbuf_append(lbuf, " ("); + + /* get the RunAsUser Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); + if (bv == NULL) + bv = ldap_get_values_len(ld, entry, "sudoRunAs"); + if (bv != NULL) { + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val); + } + ldap_value_free_len(bv); + } else + lbuf_append(lbuf, "%s", def_runas_default); + + /* get the RunAsGroup Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); + if (bv != NULL) { + lbuf_append(lbuf, " : "); + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val); + } + ldap_value_free_len(bv); + } + lbuf_append(lbuf, ") "); + + /* get the Option Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv != NULL) { + for (p = bv; *p != NULL; p++) { + char *cp = (*p)->bv_val; + if (*cp == '!') + cp++; + if (strcmp(cp, "authenticate") == 0) + lbuf_append(lbuf, (*p)->bv_val[0] == '!' ? + "NOPASSWD: " : "PASSWD: "); + else if (strcmp(cp, "noexec") == 0) + lbuf_append(lbuf, (*p)->bv_val[0] == '!' ? + "EXEC: " : "NOEXEC: "); + else if (strcmp(cp, "setenv") == 0) + lbuf_append(lbuf, (*p)->bv_val[0] == '!' ? + "NOSETENV: " : "SETENV: "); + } + ldap_value_free_len(bv); + } + + /* get the Command Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoCommand"); + if (bv != NULL) { + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val); + count++; + } + ldap_value_free_len(bv); + } + lbuf_append(lbuf, "\n"); + + debug_return_int(count); +} + +/* + * Print a record in the long form. + */ +static int +sudo_ldap_display_entry_long(LDAP *ld, LDAPMessage *entry, struct lbuf *lbuf) +{ + struct berval **bv, **p; + char *rdn; + int count = 0; + debug_decl(sudo_ldap_display_entry_long, SUDO_DEBUG_LDAP) + + /* extract the dn, only show the first rdn */ + rdn = sudo_ldap_get_first_rdn(ld, entry); + if (rdn != NULL) + lbuf_append(lbuf, _("\nLDAP Role: %s\n"), rdn); + else + lbuf_append(lbuf, _("\nLDAP Role: UNKNOWN\n")); + if (rdn) + ldap_memfree(rdn); + + /* get the RunAsUser Values from the entry */ + lbuf_append(lbuf, " RunAsUsers: "); + bv = ldap_get_values_len(ld, entry, "sudoRunAsUser"); + if (bv == NULL) + bv = ldap_get_values_len(ld, entry, "sudoRunAs"); + if (bv != NULL) { + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val); + } + ldap_value_free_len(bv); + } else + lbuf_append(lbuf, "%s", def_runas_default); + lbuf_append(lbuf, "\n"); + + /* get the RunAsGroup Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoRunAsGroup"); + if (bv != NULL) { + lbuf_append(lbuf, " RunAsGroups: "); + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val); + } + ldap_value_free_len(bv); + lbuf_append(lbuf, "\n"); + } + + /* get the Option Values from the entry */ + bv = ldap_get_values_len(ld, entry, "sudoOption"); + if (bv != NULL) { + lbuf_append(lbuf, " Options: "); + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "%s%s", p != bv ? ", " : "", (*p)->bv_val); + } + ldap_value_free_len(bv); + lbuf_append(lbuf, "\n"); + } + + /* + * 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: %s\n"), (*bv)->bv_val); + } + 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")); + for (p = bv; *p != NULL; p++) { + lbuf_append(lbuf, "\t%s\n", (*p)->bv_val); + count++; + } + ldap_value_free_len(bv); + } + + debug_return_int(count); +} + +/* + * Like sudo_ldap_lookup(), except we just print entries. + */ +static int +sudo_ldap_display_privs(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + struct sudo_ldap_handle *handle = nss->handle; + LDAP *ld; + struct ldap_result *lres; + LDAPMessage *entry; + int i, count = 0; + debug_decl(sudo_ldap_display_privs, SUDO_DEBUG_LDAP) + + if (handle == NULL || handle->ld == NULL) + goto done; + ld = handle->ld; + + DPRINTF(("ldap search for command list"), 1); + lres = sudo_ldap_result_get(nss, pw); + + /* Display all matching entries. */ + for (i = 0; i < lres->nentries; i++) { + entry = lres->entries[i].entry; + if (long_list) + count += sudo_ldap_display_entry_long(ld, entry, lbuf); + else + count += sudo_ldap_display_entry_short(ld, entry, lbuf); + } + +done: + debug_return_int(count); +} + +static int +sudo_ldap_display_cmnd(struct sudo_nss *nss, struct passwd *pw) +{ + struct sudo_ldap_handle *handle = nss->handle; + LDAP *ld; + struct ldap_result *lres; + LDAPMessage *entry; + bool found = false; + int i; + debug_decl(sudo_ldap_display_cmnd, SUDO_DEBUG_LDAP) + + if (handle == NULL || handle->ld == NULL) + goto done; + ld = handle->ld; + + /* + * The sudo_ldap_result_get() function returns all nodes that match + * the user and the host. + */ + DPRINTF(("ldap search for command list"), 1); + lres = sudo_ldap_result_get(nss, pw); + for (i = 0; i < lres->nentries; i++) { + entry = lres->entries[i].entry; + if (sudo_ldap_check_command(ld, entry, NULL) && + sudo_ldap_check_runas(ld, entry)) { + found = true; + goto done; + } + } + +done: + if (found) + printf("%s%s%s\n", safe_cmnd ? safe_cmnd : user_cmnd, + user_args ? " " : "", user_args ? user_args : ""); + debug_return_bool(!found); +} + +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S +static int +sudo_ldap_sasl_interact(LDAP *ld, unsigned int flags, void *_auth_id, + void *_interact) +{ + char *auth_id = (char *)_auth_id; + sasl_interact_t *interact = (sasl_interact_t *)_interact; + debug_decl(sudo_ldap_sasl_interact, SUDO_DEBUG_LDAP) + + for (; interact->id != SASL_CB_LIST_END; interact++) { + if (interact->id != SASL_CB_USER) + debug_return_int(LDAP_PARAM_ERROR); + + if (auth_id != NULL) + interact->result = auth_id; + else if (interact->defresult != NULL) + interact->result = interact->defresult; + else + interact->result = ""; + + interact->len = strlen(interact->result); +#if SASL_VERSION_MAJOR < 2 + interact->result = estrdup(interact->result); +#endif /* SASL_VERSION_MAJOR < 2 */ + } + debug_return_int(LDAP_SUCCESS); +} +#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ + + +/* + * Set LDAP options from the specified options table + */ +static int +sudo_ldap_set_options_table(LDAP *ld, struct ldap_config_table *table) +{ + struct ldap_config_table *cur; + int ival, rc; + char *sval; + debug_decl(sudo_ldap_set_options_table, SUDO_DEBUG_LDAP) + + for (cur = table; cur->conf_str != NULL; cur++) { + if (cur->opt_val == -1) + continue; + + switch (cur->type) { + case CONF_BOOL: + case CONF_INT: + ival = *(int *)(cur->valp); + if (ival >= 0) { + rc = ldap_set_option(ld, cur->opt_val, &ival); + if (rc != LDAP_OPT_SUCCESS) { + warningx("ldap_set_option: %s -> %d: %s", + cur->conf_str, ival, ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_set_option: %s -> %d", cur->conf_str, ival), 1); + } + break; + case CONF_STR: + sval = *(char **)(cur->valp); + if (sval != NULL) { + rc = ldap_set_option(ld, cur->opt_val, sval); + if (rc != LDAP_OPT_SUCCESS) { + warningx("ldap_set_option: %s -> %s: %s", + cur->conf_str, sval, ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_set_option: %s -> %s", cur->conf_str, sval), 1); + } + break; + } + } + debug_return_int(0); +} + +/* + * Set LDAP options based on the global config table. + */ +static int +sudo_ldap_set_options_global(void) +{ + int rc; + debug_decl(sudo_ldap_set_options_global, SUDO_DEBUG_LDAP) + + /* Set ber options */ +#ifdef LBER_OPT_DEBUG_LEVEL + if (ldap_conf.ldap_debug) + ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL, &ldap_conf.ldap_debug); +#endif + + /* Parse global LDAP options table. */ + rc = sudo_ldap_set_options_table(NULL, ldap_conf_global); + if (rc == -1) + debug_return_int(-1); + debug_return_int(0); +} + +/* + * Set LDAP options based on the per-connection config table. + */ +static int +sudo_ldap_set_options_conn(LDAP *ld) +{ + int rc; + debug_decl(sudo_ldap_set_options_conn, SUDO_DEBUG_LDAP) + + /* Parse per-connection LDAP options table. */ + rc = sudo_ldap_set_options_table(ld, ldap_conf_conn); + if (rc == -1) + debug_return_int(-1); + +#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)); + debug_return_int(-1); + } + DPRINTF(("ldap_set_option(LDAP_OPT_TIMEOUT, %ld)", + (long)tv.tv_sec), 1); + } +#endif +#ifdef LDAP_OPT_NETWORK_TIMEOUT + /* Convert bind_timelimit to a timeval */ + if (ldap_conf.bind_timelimit > 0) { + struct timeval tv; + tv.tv_sec = ldap_conf.bind_timelimit / 1000; + tv.tv_usec = 0; + rc = ldap_set_option(ld, LDAP_OPT_NETWORK_TIMEOUT, &tv); + if (rc != LDAP_OPT_SUCCESS) { + warningx("ldap_set_option(NETWORK_TIMEOUT, %ld): %s", + (long)tv.tv_sec, ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT, %ld)", + (long)tv.tv_sec), 1); + } +#endif + +#if defined(LDAP_OPT_X_TLS) && !defined(HAVE_LDAPSSL_INIT) + if (ldap_conf.ssl_mode == SUDO_LDAP_SSL) { + int val = LDAP_OPT_X_TLS_HARD; + rc = ldap_set_option(ld, LDAP_OPT_X_TLS, &val); + if (rc != LDAP_SUCCESS) { + warningx("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD): %s", + ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_set_option(LDAP_OPT_X_TLS, LDAP_OPT_X_TLS_HARD)"), 1); + } +#endif + debug_return_int(0); +} + +/* + * Create a new sudo_ldap_result structure. + */ +static struct ldap_result * +sudo_ldap_result_alloc(void) +{ + struct ldap_result *result; + debug_decl(sudo_ldap_result_alloc, SUDO_DEBUG_LDAP) + + debug_return_ptr(ecalloc(1, sizeof(*result))); +} + +/* + * Free the ldap result structure + */ +static void +sudo_ldap_result_free(struct ldap_result *lres) +{ + struct ldap_search_list *s; + debug_decl(sudo_ldap_result_free, SUDO_DEBUG_LDAP) + + 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); + } + debug_return; +} + +/* + * Add a search result to the ldap_result structure. + */ +static struct ldap_search_list * +sudo_ldap_result_add_search(struct ldap_result *lres, LDAP *ldap, + LDAPMessage *searchresult) +{ + struct ldap_search_list *s, *news; + debug_decl(sudo_ldap_result_add_search, SUDO_DEBUG_LDAP) + + news = ecalloc(1, sizeof(struct ldap_search_list)); + news->ldap = ldap; + news->searchresult = searchresult; + /* news->next = NULL; */ + + /* 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; + } + debug_return_ptr(news); +} + +/* + * Connect to the LDAP server specified by ld + */ +static int +sudo_ldap_bind_s(LDAP *ld) +{ + int rc; +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + const char *old_ccname = user_ccname; +# ifdef HAVE_GSS_KRB5_CCACHE_NAME + unsigned int status; +# endif +#endif + debug_decl(sudo_ldap_bind_s, SUDO_DEBUG_LDAP) + +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + if (ldap_conf.rootuse_sasl == true || + (ldap_conf.rootuse_sasl != false && ldap_conf.use_sasl == true)) { + void *auth_id = ldap_conf.rootsasl_auth_id ? + ldap_conf.rootsasl_auth_id : ldap_conf.sasl_auth_id; + + if (ldap_conf.krb5_ccname != NULL) { +# ifdef HAVE_GSS_KRB5_CCACHE_NAME + if (gss_krb5_ccache_name(&status, ldap_conf.krb5_ccname, &old_ccname) + != GSS_S_COMPLETE) { + old_ccname = NULL; + DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1); + } +# else + sudo_setenv("KRB5CCNAME", ldap_conf.krb5_ccname, true); +# endif + } + rc = ldap_sasl_interactive_bind_s(ld, ldap_conf.binddn, "GSSAPI", + NULL, NULL, LDAP_SASL_QUIET, sudo_ldap_sasl_interact, auth_id); + if (ldap_conf.krb5_ccname != NULL) { +# ifdef HAVE_GSS_KRB5_CCACHE_NAME + if (gss_krb5_ccache_name(&status, old_ccname, NULL) != GSS_S_COMPLETE) + DPRINTF(("gss_krb5_ccache_name() failed: %d", status), 1); +# else + if (old_ccname != NULL) + sudo_setenv("KRB5CCNAME", old_ccname, true); + else + sudo_unsetenv("KRB5CCNAME"); +# endif + } + if (rc != LDAP_SUCCESS) { + warningx("ldap_sasl_interactive_bind_s(): %s", + ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_sasl_interactive_bind_s() ok"), 1); + } else +#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ +#ifdef HAVE_LDAP_SASL_BIND_S + { + struct berval bv; + + bv.bv_val = ldap_conf.bindpw ? ldap_conf.bindpw : ""; + bv.bv_len = strlen(bv.bv_val); + + rc = ldap_sasl_bind_s(ld, ldap_conf.binddn, LDAP_SASL_SIMPLE, &bv, + NULL, NULL, NULL); + if (rc != LDAP_SUCCESS) { + warningx("ldap_sasl_bind_s(): %s", ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_sasl_bind_s() ok"), 1); + } +#else + { + rc = ldap_simple_bind_s(ld, ldap_conf.binddn, ldap_conf.bindpw); + if (rc != LDAP_SUCCESS) { + warningx("ldap_simple_bind_s(): %s", ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_simple_bind_s() ok"), 1); + } +#endif + debug_return_int(0); +} + +/* + * Open a connection to the LDAP server. + * Returns 0 on success and non-zero on failure. + */ +static int +sudo_ldap_open(struct sudo_nss *nss) +{ + LDAP *ld; + int rc; + bool ldapnoinit = false; + struct sudo_ldap_handle *handle; + debug_decl(sudo_ldap_open, SUDO_DEBUG_LDAP) + + if (!sudo_ldap_read_config()) + debug_return_int(-1); + + /* Prevent reading of user ldaprc and system defaults. */ + if (sudo_getenv("LDAPNOINIT") == NULL) { + ldapnoinit = true; + sudo_setenv("LDAPNOINIT", "1", true); + } + + /* Set global LDAP options */ + if (sudo_ldap_set_options_global() < 0) + debug_return_int(-1); + + /* Connect to LDAP server */ +#ifdef HAVE_LDAP_INITIALIZE + if (ldap_conf.uri != NULL) { + char *buf = sudo_ldap_join_uri(ldap_conf.uri); + DPRINTF(("ldap_initialize(ld, %s)", buf), 2); + rc = ldap_initialize(&ld, buf); + efree(buf); + if (rc != LDAP_SUCCESS) + warningx(_("unable to initialize LDAP: %s"), ldap_err2string(rc)); + } else +#endif + rc = sudo_ldap_init(&ld, ldap_conf.host, ldap_conf.port); + if (rc != LDAP_SUCCESS) + debug_return_int(-1); + + /* Set LDAP per-connection options */ + if (sudo_ldap_set_options_conn(ld) < 0) + debug_return_int(-1); + + if (ldapnoinit) + sudo_unsetenv("LDAPNOINIT"); + + 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)); + debug_return_int(-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)); + debug_return_int(-1); + } + rc = ldap_start_tls_s_np(ld, NULL); + if (rc != LDAP_SUCCESS) { + warningx("ldap_start_tls_s_np(): %s", ldap_err2string(rc)); + debug_return_int(-1); + } + DPRINTF(("ldap_start_tls_s_np() ok"), 1); +#else + warningx(_("start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()")); +#endif /* !HAVE_LDAP_START_TLS_S && !HAVE_LDAP_START_TLS_S_NP */ + } + + /* Actually connect */ + if (sudo_ldap_bind_s(ld) != 0) + debug_return_int(-1); + + /* Create a handle container. */ + handle = ecalloc(1, sizeof(struct sudo_ldap_handle)); + handle->ld = ld; + /* handle->result = NULL; */ + /* handle->username = NULL; */ + /* handle->grlist = NULL; */ + nss->handle = handle; + + debug_return_int(0); +} + +static int +sudo_ldap_setdefs(struct sudo_nss *nss) +{ + struct ldap_config_list_str *base; + struct sudo_ldap_handle *handle = nss->handle; + struct timeval tv, *tvp = NULL; + LDAP *ld; + LDAPMessage *entry, *result; + char *filt; + int rc; + debug_decl(sudo_ldap_setdefs, SUDO_DEBUG_LDAP) + + if (handle == NULL || handle->ld == NULL) + debug_return_int(-1); + ld = handle->ld; + + filt = sudo_ldap_build_default_filter(); + DPRINTF(("Looking for cn=defaults: %s", filt), 1); + + for (base = ldap_conf.base; base != NULL; base = base->next) { + if (ldap_conf.timeout > 0) { + tv.tv_sec = ldap_conf.timeout; + tv.tv_usec = 0; + tvp = &tv; + } + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, + filt, NULL, 0, NULL, NULL, tvp, 0, &result); + if (rc == LDAP_SUCCESS && (entry = ldap_first_entry(ld, result))) { + DPRINTF(("found:%s", ldap_get_dn(ld, entry)), 1); + sudo_ldap_parse_options(ld, entry); + } else + DPRINTF(("no default options found in %s", base->val), 1); + + if (result) + ldap_msgfree(result); + } + efree(filt); + + debug_return_int(0); +} + +/* + * like sudoers_lookup() - only LDAP style + */ +static int +sudo_ldap_lookup(struct sudo_nss *nss, int ret, int pwflag) +{ + struct sudo_ldap_handle *handle = nss->handle; + LDAP *ld; + LDAPMessage *entry; + int i, rc, setenv_implied; + struct ldap_result *lres = NULL; + debug_decl(sudo_ldap_lookup, SUDO_DEBUG_LDAP) + + if (handle == NULL || handle->ld == NULL) + debug_return_int(ret); + ld = handle->ld; + + /* Fetch list of sudoRole entries that match user and host. */ + lres = sudo_ldap_result_get(nss, sudo_user.pw); + + /* + * The following queries are only determine whether or not a + * password is required, so the order of the entries doesn't matter. + */ + if (pwflag) { + int doauth = UNSPEC; + int matched = UNSPEC; + enum def_tuple pwcheck = + (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; + + DPRINTF(("perform search for pwflag %d", pwflag), 1); + for (i = 0; i < lres->nentries; i++) { + entry = lres->entries[i].entry; + if ((pwcheck == any && doauth != false) || + (pwcheck == all && doauth == false)) { + doauth = sudo_ldap_check_bool(ld, entry, "authenticate"); + } + /* Only check the command when listing another user. */ + if (user_uid == 0 || list_pw == NULL || + user_uid == list_pw->pw_uid || + sudo_ldap_check_command(ld, entry, NULL)) { + matched = true; + break; + } + } + if (matched || user_uid == 0) { + SET(ret, VALIDATE_OK); + CLR(ret, VALIDATE_NOT_OK); + if (def_authenticate) { + switch (pwcheck) { + case always: + SET(ret, FLAG_CHECK_USER); + break; + case all: + case any: + if (doauth == false) + def_authenticate = false; + break; + case never: + def_authenticate = false; + break; + default: + break; + } + } + } + goto done; + } + + DPRINTF(("searching LDAP for sudoers entries"), 1); + + setenv_implied = false; + for (i = 0; i < lres->nentries; i++) { + entry = lres->entries[i].entry; + if (!sudo_ldap_check_runas(ld, entry)) + continue; + rc = sudo_ldap_check_command(ld, entry, &setenv_implied); + if (rc != UNSPEC) { + /* We have a match. */ + DPRINTF(("Command %sallowed", rc == true ? "" : "NOT "), 1); + 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); + + debug_return_int(ret); +} + +/* + * Comparison function for ldap_entry_wrapper structures, descending order. + */ +static int +ldap_entry_compare(const void *a, const void *b) +{ + const struct ldap_entry_wrapper *aw = a; + const struct ldap_entry_wrapper *bw = b; + debug_decl(ldap_entry_compare, SUDO_DEBUG_LDAP) + + debug_return_int(bw->order < aw->order ? -1 : + (bw->order > aw->order ? 1 : 0)); +} + +/* + * Find the last entry in the list of searches, usually the + * one currently being used to add entries. + * XXX - use a tailq instead? + */ +static struct ldap_search_list * +sudo_ldap_result_last_search(struct ldap_result *lres) +{ + struct ldap_search_list *result = lres->searches; + debug_decl(sudo_ldap_result_last_search, SUDO_DEBUG_LDAP) + + if (result) { + while (result->next) + result = result->next; + } + debug_return_ptr(result); +} + +/* + * Add an entry to the result structure. + */ +static struct ldap_entry_wrapper * +sudo_ldap_result_add_entry(struct ldap_result *lres, LDAPMessage *entry) +{ + struct ldap_search_list *last; + struct berval **bv; + double order = 0.0; + char *ep; + debug_decl(sudo_ldap_result_add_entry, SUDO_DEBUG_LDAP) + + /* 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; + + debug_return_ptr(&lres->entries[lres->nentries - 1]); +} + +/* + * Free the ldap result structure in the sudo_nss handle. + */ +static void +sudo_ldap_result_free_nss(struct sudo_nss *nss) +{ + struct sudo_ldap_handle *handle = nss->handle; + debug_decl(sudo_ldap_result_free_nss, SUDO_DEBUG_LDAP) + + 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->grlist = NULL; + handle->result = NULL; + } + debug_return; +} + +/* + * Perform the LDAP query for the user or return a cached query if + * there is one for this user. + */ +static struct ldap_result * +sudo_ldap_result_get(struct sudo_nss *nss, struct passwd *pw) +{ + struct sudo_ldap_handle *handle = nss->handle; + struct ldap_config_list_str *base; + struct ldap_result *lres; + struct timeval tv, *tvp = NULL; + LDAPMessage *entry, *result; + LDAP *ld = handle->ld; + int do_netgr, rc; + char *filt; + debug_decl(sudo_ldap_result_get, SUDO_DEBUG_LDAP) + + /* + * 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->grlist == user_group_list && + strcmp(pw->pw_name, handle->username) == 0) { + DPRINTF(("reusing previous result (user %s) with %d entries", + handle->username, handle->result->nentries), 1); + debug_return_ptr(handle->result); + } + /* User mismatch, cached result cannot be used. */ + DPRINTF(("removing result (user %s), new search (user %s)", + handle->username, pw->pw_name), 1); + sudo_ldap_result_free_nss(nss); + } + + /* + * Okay - time to search for anything that matches this user + * Lets limit it to only two queries of the LDAP server + * + * The first pass will look by the username, groups, and + * the keyword ALL. We will then inspect the results that + * came back from the query. We don't need to inspect the + * sudoUser in this pass since the LDAP server already scanned + * it for us. + * + * The second pass will return all the entries that contain + * user netgroups. Then we take the netgroups returned and + * try to match them against the username. + * + * Since we have to sort the possible entries before we make a + * decision, we perform the queries and store all of the results in + * an ldap_result object. The results are then sorted by sudoOrder. + */ + lres = sudo_ldap_result_alloc(); + for (do_netgr = 0; do_netgr < 2; do_netgr++) { + filt = do_netgr ? sudo_ldap_build_pass2() : sudo_ldap_build_pass1(pw); + DPRINTF(("ldap search '%s'", filt), 1); + for (base = ldap_conf.base; base != NULL; base = base->next) { + DPRINTF(("searching from base '%s'", base->val), 1); + if (ldap_conf.timeout > 0) { + tv.tv_sec = ldap_conf.timeout; + tv.tv_usec = 0; + tvp = &tv; + } + result = NULL; + rc = ldap_search_ext_s(ld, base->val, LDAP_SCOPE_SUBTREE, filt, + NULL, 0, NULL, NULL, tvp, 0, &result); + if (rc != LDAP_SUCCESS) { + DPRINTF(("nothing found for '%s'", filt), 1); + continue; + } + lres->user_matches = true; + + /* Add the seach result to list of search results. */ + DPRINTF(("adding search result"), 1); + sudo_ldap_result_add_search(lres, ld, result); + LDAP_FOREACH(entry, ld, result) { + if ((!do_netgr || + sudo_ldap_check_user_netgroup(ld, entry, pw->pw_name)) && + sudo_ldap_check_host(ld, entry)) { + lres->host_matches = true; + sudo_ldap_result_add_entry(lres, entry); + } + } + DPRINTF(("result now has %d entries", lres->nentries), 1); + } + efree(filt); + } + + /* Sort the entries by the sudoOrder attribute. */ + DPRINTF(("sorting remaining %d entries", lres->nentries), 1); + qsort(lres->entries, lres->nentries, sizeof(lres->entries[0]), + ldap_entry_compare); + + /* Store everything in the sudo_nss handle. */ + handle->result = lres; + handle->username = estrdup(pw->pw_name); + handle->grlist = user_group_list; + + debug_return_ptr(lres); +} + +/* + * Shut down the LDAP connection. + */ +static int +sudo_ldap_close(struct sudo_nss *nss) +{ + struct sudo_ldap_handle *handle = nss->handle; + debug_decl(sudo_ldap_close, SUDO_DEBUG_LDAP) + + 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; + } + debug_return_int(0); +} + +/* + * STUB + */ +static int +sudo_ldap_parse(struct sudo_nss *nss) +{ + return 0; +} + +#if 0 +/* + * Create an ldap_result from an LDAP search result. + * + * This function is currently not used anywhere, it is left here as + * an example of how to use the cached searches. + */ +static struct ldap_result * +sudo_ldap_result_from_search(LDAP *ldap, LDAPMessage *searchresult) +{ + /* + * An ldap_result is built from several search results, which are + * organized in a list. The head of the list is maintained in the + * ldap_result structure, together with the wrappers that point + * to individual entries, this has to be initialized first. + */ + struct ldap_result *result = sudo_ldap_result_alloc(); + + /* + * Build a new list node for the search result, this creates the + * list node. + */ + struct ldap_search_list *last = sudo_ldap_result_add_search(result, + ldap, searchresult); + + /* + * Now add each entry in the search result to the array of of entries + * in the ldap_result object. + */ + LDAPMessage *entry; + LDAP_FOREACH(entry, last->ldap, last->searchresult) { + sudo_ldap_result_add_entry(result, entry); + } + DPRINTF(("sudo_ldap_result_from_search: %d entries found", + result->nentries), 2); + return result; +} +#endif diff --git a/plugins/sudoers/linux_audit.c b/plugins/sudoers/linux_audit.c new file mode 100644 index 0000000..71f9e5e --- /dev/null +++ b/plugins/sudoers/linux_audit.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include +#include +#include +#include + +#include "missing.h" +#include "error.h" +#include "alloc.h" +#include "gettext.h" +#include "sudo_debug.h" +#include "linux_audit.h" + +/* + * Open audit connection if possible. + * Returns audit fd on success and -1 on failure. + */ +int +static linux_audit_open(void) +{ + static int au_fd = -1; + debug_decl(linux_audit_open, SUDO_DEBUG_AUDIT) + + if (au_fd != -1) + debug_return_int(au_fd); + au_fd = audit_open(); + if (au_fd == -1) { + /* Kernel may not have audit support. */ + if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT) + error(1, _("unable to open audit system")); + } else { + (void)fcntl(au_fd, F_SETFD, FD_CLOEXEC); + } + debug_return_int(au_fd); +} + +int +linux_audit_command(char *argv[], int result) +{ + int au_fd, rc; + char *command, *cp, **av; + size_t size, n; + debug_decl(linux_audit_command, SUDO_DEBUG_AUDIT) + + if ((au_fd = linux_audit_open()) == -1) + debug_return_int(-1); + + /* Convert argv to a flat string. */ + for (size = 0, av = argv; *av != NULL; av++) + size += strlen(*av) + 1; + command = cp = emalloc(size); + for (av = argv; *av != NULL; av++) { + n = strlcpy(cp, *av, size - (cp - command)); + if (n >= size - (cp - command)) + errorx(1, _("internal error, linux_audit_command() overflow")); + cp += n; + *cp++ = ' '; + } + *--cp = '\0'; + + /* Log command, ignoring ECONNREFUSED on error. */ + rc = audit_log_user_command(au_fd, AUDIT_USER_CMD, command, NULL, result); + if (rc <= 0 && errno != ECONNREFUSED) + warning(_("unable to send audit message")); + + efree(command); + + debug_return_int(rc); +} diff --git a/plugins/sudoers/linux_audit.h b/plugins/sudoers/linux_audit.h new file mode 100644 index 0000000..8f4d46c --- /dev/null +++ b/plugins/sudoers/linux_audit.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _SUDO_LINUX_AUDIT_H +#define _SUDO_LINUX_AUDIT_H + +int linux_audit_command(char *argv[], int result); + +#endif /* _SUDO_LINUX_AUDIT_H */ diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c new file mode 100644 index 0000000..4d3e13e --- /dev/null +++ b/plugins/sudoers/logging.c @@ -0,0 +1,783 @@ +/* + * Copyright (c) 1994-1996, 1998-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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#ifdef __TANDEM +# include +#endif + +#include + +#include +#include +#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 */ +#ifdef HAVE_SETLOCALE +# include +#endif /* HAVE_SETLOCALE */ +#ifdef HAVE_NL_LANGINFO +# include +#endif /* HAVE_NL_LANGINFO */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sudoers.h" + +static void do_syslog(int, char *); +static void do_logfile(char *); +static void send_mail(const char *fmt, ...); +static int should_mail(int); +static void mysyslog(int, const char *, ...); +static char *new_logline(const char *, int); + +extern sigjmp_buf error_jmp; + +#define MAXSYSLOGTRIES 16 /* num of retries for broken syslogs */ + +/* + * We do an openlog(3)/closelog(3) for each message because some + * authentication methods (notably PAM) use syslog(3) for their + * own nefarious purposes and may call openlog(3) and closelog(3). + * Note that because we don't want to assume that all systems have + * vsyslog(3) (HP-UX doesn't) "%m" will not be expanded. + * Sadly this is a maze of #ifdefs. + */ +static void +mysyslog(int pri, const char *fmt, ...) +{ +#ifdef BROKEN_SYSLOG + int i; +#endif + char buf[MAXSYSLOGLEN+1]; + va_list ap; + debug_decl(mysyslog, SUDO_DEBUG_LOGGING) + + va_start(ap, fmt); +#ifdef LOG_NFACILITIES + openlog("sudo", 0, def_syslog); +#else + openlog("sudo", 0); +#endif + vsnprintf(buf, sizeof(buf), fmt, ap); +#ifdef BROKEN_SYSLOG + /* + * Some versions of syslog(3) don't guarantee success and return + * an int (notably HP-UX < 10.0). So, if at first we don't succeed, + * try, try again... + */ + for (i = 0; i < MAXSYSLOGTRIES; i++) + if (syslog(pri, "%s", buf) == 0) + break; +#else + syslog(pri, "%s", buf); +#endif /* BROKEN_SYSLOG */ + va_end(ap); + closelog(); + debug_return; +} + +#define FMT_FIRST "%8s : %s" +#define FMT_CONTD "%8s : (command continued) %s" + +/* + * Log a message to syslog, pre-pending the username and splitting the + * message into parts if it is longer than MAXSYSLOGLEN. + */ +static void +do_syslog(int pri, char *msg) +{ + size_t len, maxlen; + char *p, *tmp, save; + const char *fmt; + debug_decl(do_syslog, SUDO_DEBUG_LOGGING) + +#ifdef HAVE_SETLOCALE + const char *old_locale = estrdup(setlocale(LC_ALL, NULL)); + if (!setlocale(LC_ALL, def_sudoers_locale)) + setlocale(LC_ALL, "C"); +#endif /* HAVE_SETLOCALE */ + + /* + * Log the full line, breaking into multiple syslog(3) calls if necessary + */ + fmt = _(FMT_FIRST); + maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); + for (p = msg; *p != '\0'; ) { + len = strlen(p); + if (len > maxlen) { + /* + * Break up the line into what will fit on one syslog(3) line + * Try to avoid breaking words into several lines if possible. + */ + tmp = memrchr(p, ' ', maxlen); + if (tmp == NULL) + tmp = p + maxlen; + + /* NULL terminate line, but save the char to restore later */ + save = *tmp; + *tmp = '\0'; + + mysyslog(pri, fmt, user_name, p); + + *tmp = save; /* restore saved character */ + + /* Advance p and eliminate leading whitespace */ + for (p = tmp; *p == ' '; p++) + ; + } else { + mysyslog(pri, fmt, user_name, p); + p += len; + } + fmt = _(FMT_CONTD); + maxlen = MAXSYSLOGLEN - (strlen(fmt) - 5 + strlen(user_name)); + } + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, old_locale); + efree((void *)old_locale); +#endif /* HAVE_SETLOCALE */ + + debug_return; +} + +static void +do_logfile(char *msg) +{ + char *full_line; + size_t len; + mode_t oldmask; + time_t now; + FILE *fp; + debug_decl(do_logfile, SUDO_DEBUG_LOGGING) + + oldmask = umask(077); + fp = fopen(def_logfile, "a"); + (void) umask(oldmask); + if (fp == NULL) { + send_mail(_("unable to open log file: %s: %s"), + def_logfile, strerror(errno)); + } else if (!lock_file(fileno(fp), SUDO_LOCK)) { + send_mail(_("unable to lock log file: %s: %s"), + def_logfile, strerror(errno)); + } else { +#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 < sizeof(LOG_INDENT)) { + /* Don't pretty-print long log file lines (hard to grep) */ + if (def_log_host) + (void) fprintf(fp, "%s : %s : HOST=%s : %s\n", + get_timestr(now, def_log_year), user_name, user_shost, msg); + else + (void) fprintf(fp, "%s : %s : %s\n", + get_timestr(now, def_log_year), user_name, msg); + } else { + if (def_log_host) + len = easprintf(&full_line, "%s : %s : HOST=%s : %s", + get_timestr(now, def_log_year), user_name, user_shost, msg); + else + len = easprintf(&full_line, "%s : %s : %s", + get_timestr(now, def_log_year), user_name, msg); + + /* + * Print out full_line with word wrap around def_loglinelen chars. + */ + writeln_wrap(fp, full_line, len, def_loglinelen); + efree(full_line); + } + (void) fflush(fp); + (void) lock_file(fileno(fp), SUDO_UNLOCK); + (void) fclose(fp); + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, old_locale); + efree((void *)old_locale); +#endif /* HAVE_SETLOCALE */ + } + debug_return; +} + +/* + * Log and mail the denial message, optionally informing the user. + */ +void +log_denial(int status, int inform_user) +{ + char *logline, *message; + debug_decl(log_denial, SUDO_DEBUG_LOGGING) + + /* Set error message. */ + if (ISSET(status, FLAG_NO_USER)) + message = _("user NOT in sudoers"); + else if (ISSET(status, FLAG_NO_HOST)) + message = _("user NOT authorized on host"); + else + message = _("command not allowed"); + + logline = new_logline(message, 0); + + if (should_mail(status)) + send_mail("%s", logline); /* send mail based on status */ + + /* Inform the user if they failed to authenticate. */ + if (inform_user) { + if (ISSET(status, FLAG_NO_USER)) { + sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not in the sudoers " + "file. This incident will be reported.\n"), user_name); + } else if (ISSET(status, FLAG_NO_HOST)) { + sudo_printf(SUDO_CONV_ERROR_MSG, _("%s is not allowed to run sudo " + "on %s. This incident will be reported.\n"), + user_name, user_shost); + } else if (ISSET(status, FLAG_NO_CHECK)) { + sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s may not run " + "sudo on %s.\n"), user_name, user_shost); + } else { + sudo_printf(SUDO_CONV_ERROR_MSG, _("Sorry, user %s is not allowed " + "to execute '%s%s%s' as %s%s%s on %s.\n"), + user_name, user_cmnd, user_args ? " " : "", + user_args ? user_args : "", + list_pw ? list_pw->pw_name : runas_pw ? + runas_pw->pw_name : user_name, runas_gr ? ":" : "", + runas_gr ? runas_gr->gr_name : "", user_host); + } + } + + /* + * Log via syslog and/or a file. + */ + if (def_syslog) + do_syslog(def_syslog_badpri, logline); + if (def_logfile) + do_logfile(logline); + + efree(logline); + debug_return; +} + +/* + * Log and potentially mail the allowed command. + */ +void +log_allowed(int status) +{ + char *logline; + debug_decl(log_allowed, SUDO_DEBUG_LOGGING) + + logline = new_logline(NULL, 0); + + if (should_mail(status)) + send_mail("%s", logline); /* send mail based on status */ + + /* + * Log via syslog and/or a file. + */ + if (def_syslog) + do_syslog(def_syslog_goodpri, logline); + if (def_logfile) + do_logfile(logline); + + efree(logline); + debug_return; +} + +/* + * Perform logging for log_error()/log_fatal() + */ +static void +vlog_error(int flags, const char *fmt, va_list ap) +{ + int serrno = errno; + char *logline, *message; + debug_decl(vlog_error, SUDO_DEBUG_LOGGING) + + /* Expand printf-style format + args. */ + evasprintf(&message, fmt, ap); + + /* Become root if we are not already to avoid user interference */ + set_perms(PERM_ROOT|PERM_NOEXIT); + + if (ISSET(flags, MSG_ONLY)) + logline = message; + else + logline = new_logline(message, ISSET(flags, USE_ERRNO) ? serrno : 0); + + /* + * Tell the user. + */ + if (!ISSET(flags, NO_STDERR)) { + if (ISSET(flags, USE_ERRNO)) + warning("%s", message); + else + warningx("%s", message); + } + if (logline != message) + efree(message); + + /* + * Send a copy of the error via mail. + */ + if (!ISSET(flags, NO_MAIL)) + send_mail("%s", logline); + + /* + * Log to syslog and/or a file. + */ + if (def_syslog) + do_syslog(def_syslog_badpri, logline); + if (def_logfile) + do_logfile(logline); + + efree(logline); + + restore_perms(); + + debug_return; +} + +void +log_error(int flags, const char *fmt, ...) +{ + va_list ap; + debug_decl(log_error, SUDO_DEBUG_LOGGING) + + /* Log the error. */ + va_start(ap, fmt); + vlog_error(flags, fmt, ap); + va_end(ap); + + debug_return; +} + +void +log_fatal(int flags, const char *fmt, ...) +{ + va_list ap; + debug_decl(log_error, SUDO_DEBUG_LOGGING) + + /* Log the error. */ + va_start(ap, fmt); + vlog_error(flags, fmt, ap); + va_end(ap); + + /* Exit the plugin. */ + plugin_cleanup(0); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + siglongjmp(error_jmp, 1); +} + +#define MAX_MAILFLAGS 63 + +/* + * Send a message to MAILTO user + */ +static void +send_mail(const char *fmt, ...) +{ + FILE *mail; + char *p; + int fd, pfd[2], status; + pid_t pid, rv; + sigaction_t sa; + va_list ap; +#ifndef NO_ROOT_MAILER + static char *root_envp[] = { + "HOME=/", + "PATH=/usr/bin:/bin:/usr/sbin:/sbin", + "LOGNAME=root", + "USERNAME=root", + "USER=root", + NULL + }; +#endif /* NO_ROOT_MAILER */ + debug_decl(send_mail, SUDO_DEBUG_LOGGING) + + /* Just return if mailer is disabled. */ + if (!def_mailerpath || !def_mailto) + debug_return; + + /* Fork and return, child will daemonize. */ + switch (pid = sudo_debug_fork()) { + case -1: + /* Error. */ + error(1, _("unable to fork")); + break; + case 0: + /* Child. */ + switch (pid = fork()) { + case -1: + /* Error. */ + mysyslog(LOG_ERR, _("unable to fork: %m")); + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to fork: %s", + strerror(errno)); + _exit(1); + case 0: + /* Grandchild continues below. */ + break; + default: + /* Parent will wait for us. */ + _exit(0); + } + break; + default: + /* Parent. */ + do { + rv = waitpid(pid, &status, 0); + } while (rv == -1 && errno == EINTR); + return; /* not debug */ + } + + /* Daemonize - disassociate from session/tty. */ + if (setsid() == -1) + warning("setsid"); + if (chdir("/") == -1) + warning("chdir(/)"); + if ((fd = open(_PATH_DEVNULL, O_RDWR, 0644)) != -1) { + (void) dup2(fd, STDIN_FILENO); + (void) dup2(fd, STDOUT_FILENO); + (void) dup2(fd, STDERR_FILENO); + } + +#ifdef HAVE_SETLOCALE + if (!setlocale(LC_ALL, def_sudoers_locale)) { + setlocale(LC_ALL, "C"); + efree(def_sudoers_locale); + def_sudoers_locale = estrdup("C"); + } +#endif /* HAVE_SETLOCALE */ + + /* Close password, group and other fds so we don't leak. */ + sudo_endpwent(); + sudo_endgrent(); + closefrom(STDERR_FILENO + 1); + + /* Ignore SIGPIPE in case mailer exits prematurely (or is missing). */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_INTERRUPT; + sa.sa_handler = SIG_IGN; + (void) sigaction(SIGPIPE, &sa, NULL); + + if (pipe(pfd) == -1) { + mysyslog(LOG_ERR, _("unable to open pipe: %m")); + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to open pipe: %s", + strerror(errno)); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + _exit(1); + } + + switch (pid = sudo_debug_fork()) { + case -1: + /* Error. */ + mysyslog(LOG_ERR, _("unable to fork: %m")); + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to fork: %s", + strerror(errno)); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + _exit(1); + break; + case 0: + { + char *argv[MAX_MAILFLAGS + 1]; + char *mpath, *mflags; + int i; + + /* Child, set stdin to output side of the pipe */ + if (pfd[0] != STDIN_FILENO) { + if (dup2(pfd[0], STDIN_FILENO) == -1) { + mysyslog(LOG_ERR, _("unable to dup stdin: %m")); + sudo_debug_printf(SUDO_DEBUG_ERROR, + "unable to dup stdin: %s", strerror(errno)); + _exit(127); + } + (void) close(pfd[0]); + } + (void) close(pfd[1]); + + /* Build up an argv based on the mailer path and flags */ + mflags = estrdup(def_mailerflags); + mpath = estrdup(def_mailerpath); + if ((argv[0] = strrchr(mpath, ' '))) + argv[0]++; + else + argv[0] = mpath; + + i = 1; + if ((p = strtok(mflags, " \t"))) { + do { + argv[i] = p; + } while (++i < MAX_MAILFLAGS && (p = strtok(NULL, " \t"))); + } + argv[i] = NULL; + + /* + * Depending on the config, either run the mailer as root + * (so user cannot kill it) or as the user (for the paranoid). + */ +#ifndef NO_ROOT_MAILER + set_perms(PERM_ROOT|PERM_NOEXIT); + execve(mpath, argv, root_envp); +#else + set_perms(PERM_FULL_USER|PERM_NOEXIT); + execv(mpath, argv); +#endif /* NO_ROOT_MAILER */ + mysyslog(LOG_ERR, _("unable to execute %s: %m"), mpath); + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to execute %s: %s", + mpath, strerror(errno)); + _exit(127); + } + break; + } + + (void) close(pfd[0]); + mail = fdopen(pfd[1], "w"); + + /* Pipes are all setup, send message. */ + (void) fprintf(mail, "To: %s\nFrom: %s\nAuto-Submitted: %s\nSubject: ", + def_mailto, def_mailfrom ? def_mailfrom : user_name, "auto-generated"); + for (p = def_mailsub; *p; p++) { + /* Expand escapes in the subject */ + if (*p == '%' && *(p+1) != '%') { + switch (*(++p)) { + case 'h': + (void) fputs(user_host, mail); + break; + case 'u': + (void) fputs(user_name, mail); + break; + default: + p--; + break; + } + } else + (void) fputc(*p, mail); + } + +#ifdef HAVE_NL_LANGINFO + if (strcmp(def_sudoers_locale, "C") != 0) + (void) fprintf(mail, "\nContent-Type: text/plain; charset=\"%s\"\nContent-Transfer-Encoding: 8bit", nl_langinfo(CODESET)); +#endif /* HAVE_NL_LANGINFO */ + + (void) fprintf(mail, "\n\n%s : %s : %s : ", user_host, + get_timestr(time(NULL), def_log_year), user_name); + va_start(ap, fmt); + (void) vfprintf(mail, fmt, ap); + va_end(ap); + fputs("\n\n", mail); + + fclose(mail); + do { + rv = waitpid(pid, &status, 0); + } while (rv == -1 && errno == EINTR); + sudo_debug_exit(__func__, __FILE__, __LINE__, sudo_debug_subsys); + _exit(0); +} + +/* + * Determine whether we should send mail based on "status" and defaults options. + */ +static int +should_mail(int status) +{ + debug_decl(should_mail, SUDO_DEBUG_LOGGING) + + debug_return_bool(def_mail_always || ISSET(status, VALIDATE_ERROR) || + (def_mail_no_user && ISSET(status, FLAG_NO_USER)) || + (def_mail_no_host && ISSET(status, FLAG_NO_HOST)) || + (def_mail_no_perms && !ISSET(status, VALIDATE_OK))); +} + +#define LL_TTY_STR "TTY=" +#define LL_CWD_STR "PWD=" /* XXX - should be CWD= */ +#define LL_USER_STR "USER=" +#define LL_GROUP_STR "GROUP=" +#define LL_ENV_STR "ENV=" +#define LL_CMND_STR "COMMAND=" +#define LL_TSID_STR "TSID=" + +#define IS_SESSID(s) ( \ + isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ + (s)[2] == '/' && \ + isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \ + (s)[5] == '/' && \ + isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ + (s)[8] == '\0') + +/* + * Allocate and fill in a new logline. + */ +static char * +new_logline(const char *message, int serrno) +{ + size_t len = 0; + char *errstr = NULL; + char *evstr = NULL; + char *line, sessid[7], *tsid = NULL; + debug_decl(new_logline, SUDO_DEBUG_LOGGING) + + /* A TSID may be a sudoers-style session ID or a free-form string. */ + if (sudo_user.iolog_file != NULL) { + if (IS_SESSID(sudo_user.iolog_file)) { + sessid[0] = sudo_user.iolog_file[0]; + sessid[1] = sudo_user.iolog_file[1]; + sessid[2] = sudo_user.iolog_file[3]; + sessid[3] = sudo_user.iolog_file[4]; + sessid[4] = sudo_user.iolog_file[6]; + sessid[5] = sudo_user.iolog_file[7]; + sessid[6] = '\0'; + tsid = sessid; + } else { + tsid = sudo_user.iolog_file; + } + } + + /* + * Compute line length + */ + if (message != NULL) + len += strlen(message) + 3; + if (serrno) { + errstr = strerror(serrno); + len += strlen(errstr) + 3; + } + len += sizeof(LL_TTY_STR) + 2 + strlen(user_tty); + len += sizeof(LL_CWD_STR) + 2 + strlen(user_cwd); + if (runas_pw != NULL) + len += sizeof(LL_USER_STR) + 2 + strlen(runas_pw->pw_name); + if (runas_gr != NULL) + len += sizeof(LL_GROUP_STR) + 2 + strlen(runas_gr->gr_name); + if (tsid != NULL) + len += sizeof(LL_TSID_STR) + 2 + strlen(tsid); + if (sudo_user.env_vars != NULL) { + size_t evlen = 0; + char * const *ep; + + for (ep = sudo_user.env_vars; *ep != NULL; ep++) + evlen += strlen(*ep) + 1; + evstr = emalloc(evlen); + evstr[0] = '\0'; + for (ep = sudo_user.env_vars; *ep != NULL; ep++) { + strlcat(evstr, *ep, evlen); + strlcat(evstr, " ", evlen); /* NOTE: last one will fail */ + } + len += sizeof(LL_ENV_STR) + 2 + evlen; + } + if (user_cmnd != NULL) { + /* Note: we log "sudo -l command arg ..." as "list command arg ..." */ + len += sizeof(LL_CMND_STR) - 1 + strlen(user_cmnd); + if (ISSET(sudo_mode, MODE_CHECK)) + len += sizeof("list ") - 1; + if (user_args != NULL) + len += strlen(user_args) + 1; + } + + /* + * Allocate and build up the line. + */ + line = emalloc(++len); + line[0] = '\0'; + + if (message != NULL) { + if (strlcat(line, message, len) >= len || + strlcat(line, errstr ? " : " : " ; ", len) >= len) + goto toobig; + } + if (serrno) { + if (strlcat(line, errstr, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (strlcat(line, LL_TTY_STR, len) >= len || + strlcat(line, user_tty, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + if (strlcat(line, LL_CWD_STR, len) >= len || + strlcat(line, user_cwd, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + if (runas_pw != NULL) { + if (strlcat(line, LL_USER_STR, len) >= len || + strlcat(line, runas_pw->pw_name, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (runas_gr != NULL) { + if (strlcat(line, LL_GROUP_STR, len) >= len || + strlcat(line, runas_gr->gr_name, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (tsid != NULL) { + if (strlcat(line, LL_TSID_STR, len) >= len || + strlcat(line, tsid, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + } + if (evstr != NULL) { + if (strlcat(line, LL_ENV_STR, len) >= len || + strlcat(line, evstr, len) >= len || + strlcat(line, " ; ", len) >= len) + goto toobig; + efree(evstr); + } + if (user_cmnd != NULL) { + if (strlcat(line, LL_CMND_STR, len) >= len) + goto toobig; + if (ISSET(sudo_mode, MODE_CHECK) && strlcat(line, "list ", len) >= len) + goto toobig; + if (strlcat(line, user_cmnd, len) >= len) + goto toobig; + if (user_args != NULL) { + if (strlcat(line, " ", len) >= len || + strlcat(line, user_args, len) >= len) + goto toobig; + } + } + + debug_return_str(line); +toobig: + errorx(1, _("internal error: insufficient space for log line")); +} diff --git a/plugins/sudoers/logging.h b/plugins/sudoers/logging.h new file mode 100644 index 0000000..d8611ec --- /dev/null +++ b/plugins/sudoers/logging.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1999-2005, 2009-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. + */ + +#ifndef _LOGGING_H +#define _LOGGING_H + +#include +#ifdef __STDC__ +# include +#else +# include +#endif + +/* Logging types */ +#define SLOG_SYSLOG 0x01 +#define SLOG_FILE 0x02 +#define SLOG_BOTH 0x03 + +/* Flags for log_error()/log_fatal() */ +#define MSG_ONLY 0x01 +#define USE_ERRNO 0x02 +#define NO_MAIL 0x04 +#define NO_STDERR 0x08 + +/* + * Maximum number of characters to log per entry. The syslogger + * will log this much, after that, it truncates the log line. + * We need this here to make sure that we continue with another + * syslog(3) call if the internal buffer is more than 1023 characters. + */ +#ifndef MAXSYSLOGLEN +# define MAXSYSLOGLEN 960 +#endif + +/* + * Indentation level for file-based logs when word wrap is enabled. + */ +#define LOG_INDENT " " + +void audit_success(char *[]); +void audit_failure(char *[], char const * const, ...); +void log_allowed(int); +void log_denial(int, int); +void log_error(int flags, const char *fmt, ...) __printflike(2, 3); +void log_fatal(int flags, const char *fmt, ...) __printflike(2, 3) __attribute__((__noreturn__)); +void reapchild(int); +void writeln_wrap(FILE *fp, char *line, size_t len, size_t maxlen); + +#endif /* _LOGGING_H */ diff --git a/plugins/sudoers/logwrap.c b/plugins/sudoers/logwrap.c new file mode 100644 index 0000000..4adfc94 --- /dev/null +++ b/plugins/sudoers/logwrap.c @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#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 */ + +#include "sudoers.h" + +void +writeln_wrap(FILE *fp, char *line, size_t len, size_t maxlen) +{ + char *indent = ""; + char *beg = line; + char *end; + debug_decl(writeln_wrap, SUDO_DEBUG_LOGGING) + + /* + * Print out line with word wrap around maxlen characters. + */ + beg = line; + while (len > maxlen) { + end = beg + maxlen; + while (end != beg && *end != ' ') + end--; + if (beg == end) { + /* Unable to find word break within maxlen, look beyond. */ + end = strchr(beg + maxlen, ' '); + if (end == NULL) + break; /* no word break */ + } + fprintf(fp, "%s%.*s\n", indent, (int)(end - beg), beg); + while (*end == ' ') + end++; + len -= (end - beg); + beg = end; + if (indent[0] == '\0') { + indent = LOG_INDENT; + maxlen -= sizeof(LOG_INDENT) - 1; + } + } + /* Print remainder, if any. */ + if (len) + fprintf(fp, "%s%s\n", indent, beg); + + debug_return; +} diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c new file mode 100644 index 0000000..f0c5dc1 --- /dev/null +++ b/plugins/sudoers/match.c @@ -0,0 +1,748 @@ +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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. + * 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 +#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 */ +#ifdef HAVE_FNMATCH +# include +#endif /* HAVE_FNMATCH */ +#ifdef HAVE_GLOB +# include +#endif /* HAVE_GLOB */ +#ifdef HAVE_NETGROUP_H +# include +#endif /* HAVE_NETGROUP_H */ +#include +#include +#include +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#include "sudoers.h" +#include "parse.h" +#include + +#ifndef HAVE_FNMATCH +# include "compat/fnmatch.h" +#endif /* HAVE_FNMATCH */ +#ifndef HAVE_GLOB +# include "compat/glob.h" +#endif /* HAVE_GLOB */ + +static struct member_list empty; + +static bool command_matches_dir(char *, size_t); +static bool command_matches_glob(char *, char *); +static bool command_matches_fnmatch(char *, char *); +static bool command_matches_normal(char *, char *); + +/* + * Returns true if string 's' contains meta characters. + */ +#define has_meta(s) (strpbrk(s, "\\?*[]") != NULL) + +/* + * Check for user described by pw in a list of members. + * Returns ALLOW, DENY or UNSPEC. + */ +static int +_userlist_matches(struct passwd *pw, struct member_list *list) +{ + struct member *m; + struct alias *a; + int rval, matched = UNSPEC; + debug_decl(_userlist_matches, SUDO_DEBUG_MATCH) + + tq_foreach_rev(list, m) { + switch (m->type) { + case ALL: + matched = !m->negated; + break; + case NETGROUP: + if (netgr_matches(m->name, NULL, NULL, pw->pw_name)) + matched = !m->negated; + break; + case USERGROUP: + if (usergr_matches(m->name, pw->pw_name, pw)) + matched = !m->negated; + break; + case ALIAS: + if ((a = alias_find(m->name, USERALIAS)) != NULL) { + rval = _userlist_matches(pw, &a->members); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; + break; + } + /* FALLTHROUGH */ + case WORD: + if (userpw_matches(m->name, pw->pw_name, pw)) + matched = !m->negated; + break; + } + if (matched != UNSPEC) + break; + } + debug_return_bool(matched); +} + +int +userlist_matches(struct passwd *pw, struct member_list *list) +{ + alias_seqno++; + return _userlist_matches(pw, list); +} + +/* + * Check for user described by pw in a list of members. + * If both lists are empty compare against def_runas_default. + * Returns ALLOW, DENY or UNSPEC. + */ +static int +_runaslist_matches(struct member_list *user_list, struct member_list *group_list) +{ + struct member *m; + struct alias *a; + int rval; + int user_matched = UNSPEC; + int group_matched = UNSPEC; + debug_decl(_runaslist_matches, SUDO_DEBUG_MATCH) + + 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)) + debug_return_int(userpw_matches(def_runas_default, runas_pw->pw_name, runas_pw)); + + tq_foreach_rev(user_list, m) { + switch (m->type) { + case ALL: + user_matched = !m->negated; + break; + case NETGROUP: + if (netgr_matches(m->name, NULL, NULL, runas_pw->pw_name)) + user_matched = !m->negated; + break; + case USERGROUP: + if (usergr_matches(m->name, runas_pw->pw_name, runas_pw)) + user_matched = !m->negated; + break; + case ALIAS: + if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { + rval = _runaslist_matches(&a->members, &empty); + if (rval != UNSPEC) + user_matched = m->negated ? !rval : rval; + break; + } + /* FALLTHROUGH */ + case WORD: + if (userpw_matches(m->name, runas_pw->pw_name, runas_pw)) + user_matched = !m->negated; + break; + } + if (user_matched != UNSPEC) + break; + } + } + + if (runas_gr != NULL) { + if (user_matched == UNSPEC) { + if (runas_pw == NULL || strcmp(runas_pw->pw_name, user_name) == 0) + user_matched = ALLOW; /* only changing group */ + } + tq_foreach_rev(group_list, m) { + switch (m->type) { + case ALL: + group_matched = !m->negated; + break; + case ALIAS: + if ((a = alias_find(m->name, RUNASALIAS)) != NULL) { + rval = _runaslist_matches(&empty, &a->members); + if (rval != UNSPEC) + group_matched = m->negated ? !rval : rval; + break; + } + /* FALLTHROUGH */ + case WORD: + if (group_matches(m->name, runas_gr)) + group_matched = !m->negated; + break; + } + if (group_matched != UNSPEC) + break; + } + if (group_matched == UNSPEC) { + if (runas_pw != NULL && runas_pw->pw_gid == runas_gr->gr_gid) + group_matched = ALLOW; /* runas group matches passwd db */ + } + } + + if (user_matched == DENY || group_matched == DENY) + debug_return_int(DENY); + if (user_matched == group_matched || runas_gr == NULL) + debug_return_int(user_matched); + debug_return_int(UNSPEC); +} + +int +runaslist_matches(struct member_list *user_list, struct member_list *group_list) +{ + alias_seqno++; + return _runaslist_matches(user_list ? user_list : &empty, + group_list ? group_list : &empty); +} + +/* + * Check for host and shost in a list of members. + * Returns ALLOW, DENY or UNSPEC. + */ +static int +_hostlist_matches(struct member_list *list) +{ + struct member *m; + struct alias *a; + int rval, matched = UNSPEC; + debug_decl(_hostlist_matches, SUDO_DEBUG_MATCH) + + tq_foreach_rev(list, m) { + switch (m->type) { + case ALL: + matched = !m->negated; + break; + case NETGROUP: + if (netgr_matches(m->name, user_host, user_shost, NULL)) + matched = !m->negated; + break; + case NTWKADDR: + if (addr_matches(m->name)) + matched = !m->negated; + break; + case ALIAS: + if ((a = alias_find(m->name, HOSTALIAS)) != NULL) { + rval = _hostlist_matches(&a->members); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; + break; + } + /* FALLTHROUGH */ + case WORD: + if (hostname_matches(user_shost, user_host, m->name)) + matched = !m->negated; + break; + } + if (matched != UNSPEC) + break; + } + debug_return_bool(matched); +} + +int +hostlist_matches(struct member_list *list) +{ + alias_seqno++; + return _hostlist_matches(list); +} + +/* + * Check for cmnd and args in a list of members. + * Returns ALLOW, DENY or UNSPEC. + */ +static int +_cmndlist_matches(struct member_list *list) +{ + struct member *m; + int matched = UNSPEC; + debug_decl(_cmndlist_matches, SUDO_DEBUG_MATCH) + + tq_foreach_rev(list, m) { + matched = cmnd_matches(m); + if (matched != UNSPEC) + break; + } + debug_return_bool(matched); +} + +int +cmndlist_matches(struct member_list *list) +{ + alias_seqno++; + return _cmndlist_matches(list); +} + +/* + * Check cmnd and args. + * Returns ALLOW, DENY or UNSPEC. + */ +int +cmnd_matches(struct member *m) +{ + struct alias *a; + struct sudo_command *c; + int rval, matched = UNSPEC; + debug_decl(cmnd_matches, SUDO_DEBUG_MATCH) + + switch (m->type) { + case ALL: + matched = !m->negated; + break; + case ALIAS: + alias_seqno++; + if ((a = alias_find(m->name, CMNDALIAS)) != NULL) { + rval = _cmndlist_matches(&a->members); + if (rval != UNSPEC) + matched = m->negated ? !rval : rval; + } + break; + case COMMAND: + c = (struct sudo_command *)m->name; + if (command_matches(c->cmnd, c->args)) + matched = !m->negated; + break; + } + debug_return_bool(matched); +} + +static bool +command_args_match(sudoers_cmnd, sudoers_args) + char *sudoers_cmnd; + char *sudoers_args; +{ + int flags = 0; + debug_decl(command_args_match, SUDO_DEBUG_MATCH) + + /* + * 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))) + debug_return_bool(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) + debug_return_bool(true); + } + debug_return_bool(false); +} + +/* + * If path doesn't end in /, return true iff cmnd & path name the same inode; + * otherwise, return true if user_cmnd names one of the inodes in path. + */ +bool +command_matches(char *sudoers_cmnd, char *sudoers_args) +{ + debug_decl(command_matches, SUDO_DEBUG_MATCH) + + /* Check for pseudo-commands */ + if (sudoers_cmnd[0] != '/') { + /* + * Return true if both sudoers_cmnd and user_cmnd are "sudoedit" AND + * a) there are no args in sudoers OR + * b) there are no args on command line and none req by sudoers OR + * c) there are args in sudoers and on command line and they match + */ + if (strcmp(sudoers_cmnd, "sudoedit") != 0 || + strcmp(user_cmnd, "sudoedit") != 0) + debug_return_bool(false); + if (command_args_match(sudoers_cmnd, sudoers_args)) { + efree(safe_cmnd); + safe_cmnd = estrdup(sudoers_cmnd); + debug_return_bool(true); + } else + debug_return_bool(false); + } + + if (has_meta(sudoers_cmnd)) { + /* + * If sudoers_cmnd has meta characters in it, we need to + * use glob(3) and/or fnmatch(3) to do the matching. + */ + if (def_fast_glob) + debug_return_bool(command_matches_fnmatch(sudoers_cmnd, sudoers_args)); + debug_return_bool(command_matches_glob(sudoers_cmnd, sudoers_args)); + } + debug_return_bool(command_matches_normal(sudoers_cmnd, sudoers_args)); +} + +static bool +command_matches_fnmatch(char *sudoers_cmnd, char *sudoers_args) +{ + debug_decl(command_matches_fnmatch, SUDO_DEBUG_MATCH) + + /* + * Return true if fnmatch(3) succeeds AND + * a) there are no args in sudoers OR + * b) there are no args on command line and none required by sudoers OR + * c) there are args in sudoers and on command line and they match + * else return false. + */ + if (fnmatch(sudoers_cmnd, user_cmnd, FNM_PATHNAME) != 0) + debug_return_bool(false); + if (command_args_match(sudoers_cmnd, sudoers_args)) { + if (safe_cmnd) + free(safe_cmnd); + safe_cmnd = estrdup(user_cmnd); + debug_return_bool(true); + } + debug_return_bool(false); +} + +static bool +command_matches_glob(char *sudoers_cmnd, char *sudoers_args) +{ + struct stat sudoers_stat; + size_t dlen; + char **ap, *base, *cp; + glob_t gl; + debug_decl(command_matches_glob, SUDO_DEBUG_MATCH) + + /* + * First check to see if we can avoid the call to glob(3). + * Short circuit if there are no meta chars in the command itself + * and user_base and basename(sudoers_cmnd) don't match. + */ + dlen = strlen(sudoers_cmnd); + if (sudoers_cmnd[dlen - 1] != '/') { + if ((base = strrchr(sudoers_cmnd, '/')) != NULL) { + base++; + if (!has_meta(base) && strcmp(user_base, base) != 0) + debug_return_bool(false); + } + } + /* + * Return true if we find a match in the glob(3) results AND + * a) there are no args in sudoers OR + * b) there are no args on command line and none required by sudoers OR + * c) there are args in sudoers and on command line and they match + * else return false. + */ + if (glob(sudoers_cmnd, GLOB_NOSORT, NULL, &gl) != 0 || gl.gl_pathc == 0) { + globfree(&gl); + debug_return_bool(false); + } + /* For each glob match, compare basename, st_dev and st_ino. */ + for (ap = gl.gl_pathv; (cp = *ap) != NULL; ap++) { + /* If it ends in '/' it is a directory spec. */ + dlen = strlen(cp); + if (cp[dlen - 1] == '/') { + if (command_matches_dir(cp, dlen)) + debug_return_bool(true); + continue; + } + + /* Only proceed if user_base and basename(cp) match */ + if ((base = strrchr(cp, '/')) != NULL) + base++; + else + base = cp; + if (strcmp(user_base, base) != 0 || + stat(cp, &sudoers_stat) == -1) + continue; + if (user_stat == NULL || + (user_stat->st_dev == sudoers_stat.st_dev && + user_stat->st_ino == sudoers_stat.st_ino)) { + efree(safe_cmnd); + safe_cmnd = estrdup(cp); + break; + } + } + globfree(&gl); + if (cp == NULL) + debug_return_bool(false); + + if (command_args_match(sudoers_cmnd, sudoers_args)) { + efree(safe_cmnd); + safe_cmnd = estrdup(user_cmnd); + debug_return_bool(true); + } + debug_return_bool(false); +} + +static bool +command_matches_normal(char *sudoers_cmnd, char *sudoers_args) +{ + struct stat sudoers_stat; + char *base; + size_t dlen; + debug_decl(command_matches_normal, SUDO_DEBUG_MATCH) + + /* If it ends in '/' it is a directory spec. */ + dlen = strlen(sudoers_cmnd); + if (sudoers_cmnd[dlen - 1] == '/') + debug_return_bool(command_matches_dir(sudoers_cmnd, dlen)); + + /* Only proceed if user_base and basename(sudoers_cmnd) match */ + if ((base = strrchr(sudoers_cmnd, '/')) == NULL) + base = sudoers_cmnd; + else + base++; + if (strcmp(user_base, base) != 0 || + stat(sudoers_cmnd, &sudoers_stat) == -1) + debug_return_bool(false); + + /* + * Return true if inode/device matches AND + * a) there are no args in sudoers OR + * b) there are no args on command line and none req by sudoers OR + * c) there are args in sudoers and on command line and they match + */ + if (user_stat != NULL && + (user_stat->st_dev != sudoers_stat.st_dev || + user_stat->st_ino != sudoers_stat.st_ino)) + debug_return_bool(false); + if (command_args_match(sudoers_cmnd, sudoers_args)) { + efree(safe_cmnd); + safe_cmnd = estrdup(sudoers_cmnd); + debug_return_bool(true); + } + debug_return_bool(false); +} + +/* + * Return true if user_cmnd names one of the inodes in dir, else false. + */ +static bool +command_matches_dir(char *sudoers_dir, size_t dlen) +{ + struct stat sudoers_stat; + struct dirent *dent; + char buf[PATH_MAX]; + DIR *dirp; + debug_decl(command_matches_dir, SUDO_DEBUG_MATCH) + + /* + * Grot through directory entries, looking for user_base. + */ + dirp = opendir(sudoers_dir); + if (dirp == NULL) + debug_return_bool(false); + + if (strlcpy(buf, sudoers_dir, sizeof(buf)) >= sizeof(buf)) { + closedir(dirp); + debug_return_bool(false); + } + while ((dent = readdir(dirp)) != NULL) { + /* ignore paths > PATH_MAX (XXX - log) */ + buf[dlen] = '\0'; + if (strlcat(buf, dent->d_name, sizeof(buf)) >= sizeof(buf)) + continue; + + /* only stat if basenames are the same */ + if (strcmp(user_base, dent->d_name) != 0 || + stat(buf, &sudoers_stat) == -1) + continue; + if (user_stat == NULL || + (user_stat->st_dev == sudoers_stat.st_dev && + user_stat->st_ino == sudoers_stat.st_ino)) { + efree(safe_cmnd); + safe_cmnd = estrdup(buf); + break; + } + } + + closedir(dirp); + debug_return_bool(dent != NULL); +} + +/* + * Returns true if the hostname matches the pattern, else false + */ +bool +hostname_matches(char *shost, char *lhost, char *pattern) +{ + debug_decl(hostname_matches, SUDO_DEBUG_MATCH) + + if (has_meta(pattern)) { + if (strchr(pattern, '.')) + debug_return_bool(!fnmatch(pattern, lhost, FNM_CASEFOLD)); + else + debug_return_bool(!fnmatch(pattern, shost, FNM_CASEFOLD)); + } else { + if (strchr(pattern, '.')) + debug_return_bool(!strcasecmp(lhost, pattern)); + else + debug_return_bool(!strcasecmp(shost, pattern)); + } +} + +/* + * Returns true if the user/uid from sudoers matches the specified user/uid, + * else returns false. + */ +bool +userpw_matches(char *sudoers_user, char *user, struct passwd *pw) +{ + debug_decl(userpw_matches, SUDO_DEBUG_MATCH) + + if (pw != NULL && *sudoers_user == '#') { + uid_t uid = (uid_t) atoi(sudoers_user + 1); + if (uid == pw->pw_uid) + debug_return_bool(true); + } + debug_return_bool(strcmp(sudoers_user, user) == 0); +} + +/* + * Returns true if the group/gid from sudoers matches the specified group/gid, + * else returns false. + */ +bool +group_matches(char *sudoers_group, struct group *gr) +{ + debug_decl(group_matches, SUDO_DEBUG_MATCH) + + if (*sudoers_group == '#') { + gid_t gid = (gid_t) atoi(sudoers_group + 1); + if (gid == gr->gr_gid) + debug_return_bool(true); + } + debug_return_bool(strcmp(gr->gr_name, sudoers_group) == 0); +} + +/* + * Returns true if the given user belongs to the named group, + * else returns false. + */ +bool +usergr_matches(char *group, char *user, struct passwd *pw) +{ + int matched = false; + struct passwd *pw0 = NULL; + debug_decl(usergr_matches, SUDO_DEBUG_MATCH) + + /* make sure we have a valid usergroup, sudo style */ + if (*group++ != '%') + goto done; + + if (*group == ':' && def_group_plugin) { + matched = group_plugin_query(user, group + 1, pw); + goto done; + } + + /* look up user's primary gid in the passwd file */ + if (pw == NULL) { + if ((pw0 = sudo_getpwnam(user)) == NULL) + goto done; + pw = pw0; + } + + if (user_in_group(pw, group)) { + matched = true; + goto done; + } + + /* not a Unix group, could be an external group */ + if (def_group_plugin && group_plugin_query(user, group, pw)) { + matched = true; + goto done; + } + +done: + if (pw0 != NULL) + pw_delref(pw0); + + debug_return_bool(matched); +} + +/* + * Returns true if "host" and "user" belong to the netgroup "netgr", + * else return false. Either of "host", "shost" or "user" may be NULL + * in which case that argument is not checked... + * + * XXX - swap order of host & shost + */ +bool +netgr_matches(char *netgr, char *lhost, char *shost, char *user) +{ + static char *domain; +#ifdef HAVE_GETDOMAINNAME + static int initialized; +#endif + debug_decl(netgr_matches, SUDO_DEBUG_MATCH) + + /* make sure we have a valid netgroup, sudo style */ + if (*netgr++ != '+') + debug_return_bool(false); + +#ifdef HAVE_GETDOMAINNAME + /* get the domain name (if any) */ + if (!initialized) { + domain = (char *) emalloc(MAXHOSTNAMELEN + 1); + if (getdomainname(domain, MAXHOSTNAMELEN + 1) == -1 || *domain == '\0') { + efree(domain); + domain = NULL; + } + initialized = 1; + } +#endif /* HAVE_GETDOMAINNAME */ + +#ifdef HAVE_INNETGR + if (innetgr(netgr, lhost, user, domain)) + debug_return_bool(true); + else if (lhost != shost && innetgr(netgr, shost, user, domain)) + debug_return_bool(true); +#endif /* HAVE_INNETGR */ + + debug_return_bool(false); +} diff --git a/plugins/sudoers/match_addr.c b/plugins/sudoers/match_addr.c new file mode 100644 index 0000000..23e6867 --- /dev/null +++ b/plugins/sudoers/match_addr.c @@ -0,0 +1,201 @@ +/* + * 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. + * 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 */ +#include +#include +#include + +#include "sudoers.h" +#include "interfaces.h" + +static bool +addr_matches_if(char *n) +{ + union sudo_in_addr_un addr; + struct interface *ifp; +#ifdef HAVE_STRUCT_IN6_ADDR + int j; +#endif + int family; + debug_decl(addr_matches_if, SUDO_DEBUG_MATCH) + +#ifdef HAVE_STRUCT_IN6_ADDR + if (inet_pton(AF_INET6, n, &addr.ip6) > 0) { + family = AF_INET6; + } else +#endif /* HAVE_STRUCT_IN6_ADDR */ + { + family = AF_INET; + addr.ip4.s_addr = inet_addr(n); + } + + for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { + if (ifp->family != family) + continue; + switch (family) { + case AF_INET: + if (ifp->addr.ip4.s_addr == addr.ip4.s_addr || + (ifp->addr.ip4.s_addr & ifp->netmask.ip4.s_addr) + == addr.ip4.s_addr) + debug_return_bool(true); + break; +#ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: + if (memcmp(ifp->addr.ip6.s6_addr, addr.ip6.s6_addr, + sizeof(addr.ip6.s6_addr)) == 0) + debug_return_bool(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)) + debug_return_bool(true); + break; +#endif /* HAVE_STRUCT_IN6_ADDR */ + } + } + + debug_return_bool(false); +} + +static bool +addr_matches_if_netmask(char *n, char *m) +{ + int i; + union sudo_in_addr_un addr, mask; + struct interface *ifp; +#ifdef HAVE_STRUCT_IN6_ADDR + int j; +#endif + int family; + debug_decl(addr_matches_if, SUDO_DEBUG_MATCH) + +#ifdef HAVE_STRUCT_IN6_ADDR + if (inet_pton(AF_INET6, n, &addr.ip6) > 0) + family = AF_INET6; + else +#endif /* HAVE_STRUCT_IN6_ADDR */ + { + family = AF_INET; + addr.ip4.s_addr = inet_addr(n); + } + + if (family == AF_INET) { + if (strchr(m, '.')) { + mask.ip4.s_addr = inet_addr(m); + } else { + i = atoi(m); + if (i == 0) + mask.ip4.s_addr = 0; + else if (i == 32) + mask.ip4.s_addr = 0xffffffff; + else + mask.ip4.s_addr = 0xffffffff - (1 << (32 - i)) + 1; + mask.ip4.s_addr = htonl(mask.ip4.s_addr); + } + addr.ip4.s_addr &= mask.ip4.s_addr; + } +#ifdef HAVE_STRUCT_IN6_ADDR + else { + if (inet_pton(AF_INET6, m, &mask.ip6) <= 0) { + j = atoi(m); + for (i = 0; i < sizeof(addr.ip6.s6_addr); i++) { + if (j < i * 8) + mask.ip6.s6_addr[i] = 0; + else if (i * 8 + 8 <= j) + mask.ip6.s6_addr[i] = 0xff; + else + mask.ip6.s6_addr[i] = 0xff00 >> (j - i * 8); + addr.ip6.s6_addr[i] &= mask.ip6.s6_addr[i]; + } + } + } +#endif /* HAVE_STRUCT_IN6_ADDR */ + + for (ifp = interfaces; ifp != NULL; ifp = ifp->next) { + if (ifp->family != family) + continue; + switch (family) { + case AF_INET: + if ((ifp->addr.ip4.s_addr & mask.ip4.s_addr) == addr.ip4.s_addr) + debug_return_bool(true); + break; +#ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: + for (j = 0; j < sizeof(addr.ip6.s6_addr); j++) { + if ((ifp->addr.ip6.s6_addr[j] & mask.ip6.s6_addr[j]) != addr.ip6.s6_addr[j]) + break; + } + if (j == sizeof(addr.ip6.s6_addr)) + debug_return_bool(true); + break; +#endif /* HAVE_STRUCT_IN6_ADDR */ + } + } + + debug_return_bool(false); +} + +/* + * Returns true if "n" is one of our ip addresses or if + * "n" is a network that we are on, else returns false. + */ +bool +addr_matches(char *n) +{ + char *m; + bool retval; + debug_decl(addr_matches, SUDO_DEBUG_MATCH) + + /* If there's an explicit netmask, use it. */ + if ((m = strchr(n, '/'))) { + *m++ = '\0'; + retval = addr_matches_if_netmask(n, m); + *(m - 1) = '/'; + } else + retval = addr_matches_if(n); + + debug_return_bool(retval); +} diff --git a/plugins/sudoers/mkdefaults b/plugins/sudoers/mkdefaults new file mode 100755 index 0000000..427cff7 --- /dev/null +++ b/plugins/sudoers/mkdefaults @@ -0,0 +1,155 @@ +#!/usr/bin/perl -w +# +# Generate sudo_defs_table and associated defines +# +# Input should be formatted thusly: +# +# var_name +# TYPE +# description (or NULL) +# array of struct def_values if TYPE == T_TUPLE + +# Deal with optional -o (output) argument +if ($#ARGV > 0 && $ARGV[0] eq "-o") { + shift; + $header = $cfile = shift; + $header .= '.h'; + $cfile .= '.c'; +} +die "usage: $0 [input_file]\n" unless $#ARGV == -1 || $#ARGV == 0; + +$infile = $ARGV[0] || "def_data.in"; +if (!defined($header)) { + $header = $infile; + $header =~ s/(\.in)?$/.h/; +} +if (!defined($cfile)) { + $cfile = $infile; + $cfile =~ s/(\.in)?$/.c/; +} + +open(IN, "<$infile") || die "$0: can't open $infile: $!\n"; +open(HEADER, ">$header") || die "$0: can't open $header: $!\n"; +open(CFILE, ">$cfile") || die "$0: can't open $cfile: $!\n"; + +$count = 0; +@tuple_values = ( "never" ); +@records = (); +while() { + chomp; + s/\s*#.*$//; + next if /^\s*$/; + + if (/^\S/) { + # Store previous record and begin new one + $records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var); + + $var = $_; + $type = ''; + $desc = undef; + $values = undef; + $callback = undef; + $field = 0; + } else { + $field++; + s/^\s+//; + s/\s+$//; + if ($field == 1) { + # type + $type = $_; + } elsif ($field == 2) { + # description + if ($_ eq "NULL") { + $desc = "NULL"; + } else { + # Strip leading and trailing double quote and escape the rest + s/^"//; + s/"$//; + s/"/\\"/g; + $desc = "N_(\"$_\")"; + } + } elsif ($field == 3 || $field == 4) { + if (s/^\*//) { + $callback = $_; + } else { + die "$0: syntax error near line $.\n" if $type !~ /^T_TUPLE/; + $values = [ split ]; + foreach $v (@$values) { + push(@tuple_values, $v) unless grep(/^$v$/, @tuple_values); + } + } + } else { + die "$0: syntax error near line $.\n"; + } + } +} +$records[$count++] = [$var, $type, $desc, $values, $callback] if defined($var); + +# Print out value arrays +for ($i = 0; $i < $count; $i++) { + if (defined($records[$i]->[3])) { + die "Values list specified for non-tuple\n" unless + $records[$i]->[1] =~ /^T_TUPLE/; + printf CFILE "static struct def_values def_data_%s[] = {\n", $records[$i]->[0]; + foreach (@{$records[$i]->[3]}) { + print CFILE " { \"$_\", $_ },\n"; + } + print CFILE " { NULL, 0 },\n"; + print CFILE "};\n\n"; + } +} + +# Print each record +print CFILE "struct sudo_defs_types sudo_defs_table[] = {\n {\n"; +for ($i = 0; $i < $count; $i++) { + &print_record($records[$i], $i); +} +print CFILE "\tNULL, 0, NULL\n }\n};\n"; + +# Print out def_tuple +if (@tuple_values) { + print HEADER "\nenum def_tuple {\n"; + for ($i = 0; $i <= $#tuple_values; $i++) { + printf HEADER "\t%s%s\n", $tuple_values[$i], + $i != $#tuple_values ? "," : ""; + } + print HEADER "};\n"; +} + +close(IN); +close(HEADER); +close(CFILE); + +sub print_record { + my ($rec, $recnum) = @_; + my ($i, $v, $defname); + # each variable gets a macro to access its value + for ($rec->[1]) { + if (/^T_U?INT/) { $v = "ival"; } + elsif (/^T_STR/) { $v = "str"; } + elsif (/^T_FLAG/) { $v = "flag"; } + elsif (/^T_MODE/) { $v = "mode"; } + elsif (/^T_LIST/) { $v = "list"; } + elsif (/^T_LOGFAC/) { $v = "ival"; } + elsif (/^T_LOGPRI/) { $v = "ival"; } + elsif (/^T_TUPLE/) { $v = "tuple"; } + elsif (/^T_FLOAT/) { $v = "fval"; } + else { die "$0: unknown defaults type: $_\n"; } + } + printf HEADER "#define %-23s (sudo_defs_table[$recnum].sd_un.${v})\n", + "def_$rec->[0]"; + + $defname = "I_" . uc($rec->[0]); + printf HEADER "#define %-24s%d", $defname, $recnum; + #print HEADER "\t/* $rec->[2] */" if defined($rec->[2]); + print HEADER "\n"; + + print CFILE "\t\"$rec->[0]\", $rec->[1],\n\t$rec->[2],\n"; + if (defined($rec->[3])) { + printf CFILE "\tdef_data_$rec->[0],\n"; + } else { + printf CFILE "\tNULL,\n"; + } + printf CFILE "\t$rec->[4],\n" if defined($rec->[4]); + print CFILE " }, {\n"; +} diff --git a/plugins/sudoers/parse.c b/plugins/sudoers/parse.c new file mode 100644 index 0000000..4937145 --- /dev/null +++ b/plugins/sudoers/parse.c @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2004-2005, 2007-2012 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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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 */ +#include +#include +#include + +#include "sudoers.h" +#include "parse.h" +#include "lbuf.h" +#include + +/* Characters that must be quoted in sudoers */ +#define SUDOERS_QUOTED ":\\,=#\"" + +/* sudoers nsswitch routines */ +struct sudo_nss sudo_nss_file = { + &sudo_nss_file, + NULL, + sudo_file_open, + sudo_file_close, + sudo_file_parse, + sudo_file_setdefs, + sudo_file_lookup, + sudo_file_display_cmnd, + sudo_file_display_defaults, + sudo_file_display_bound_defaults, + sudo_file_display_privs +}; + +/* + * Parser externs. + */ +extern FILE *yyin; +extern char *errorfile; +extern int errorlineno; +extern bool parse_error; + +/* + * Local prototypes. + */ +static void print_member(struct lbuf *, char *, int, int, int); +static int display_bound_defaults(int, struct lbuf *); + +int +sudo_file_open(struct sudo_nss *nss) +{ + debug_decl(sudo_file_open, SUDO_DEBUG_NSS) + + if (def_ignore_local_sudoers) + debug_return_int(-1); + nss->handle = open_sudoers(sudoers_file, false, NULL); + debug_return_int(nss->handle ? 0 : -1); +} + +int +sudo_file_close(struct sudo_nss *nss) +{ + debug_decl(sudo_file_close, SUDO_DEBUG_NSS) + + /* Free parser data structures and close sudoers file. */ + init_parser(NULL, 0); + if (nss->handle != NULL) { + fclose(nss->handle); + nss->handle = NULL; + yyin = NULL; + } + debug_return_int(0); +} + +/* + * Parse the specified sudoers file. + */ +int +sudo_file_parse(struct sudo_nss *nss) +{ + debug_decl(sudo_file_close, SUDO_DEBUG_NSS) + + if (nss->handle == NULL) + debug_return_int(-1); + + init_parser(sudoers_file, 0); + yyin = nss->handle; + if (yyparse() != 0 || parse_error) { + if (errorlineno != -1) { + log_error(0, _("parse error in %s near line %d"), + errorfile, errorlineno); + } else { + log_error(0, _("parse error in %s"), errorfile); + } + debug_return_int(-1); + } + debug_return_int(0); +} + +/* + * Wrapper around update_defaults() for nsswitch code. + */ +int +sudo_file_setdefs(struct sudo_nss *nss) +{ + debug_decl(sudo_file_setdefs, SUDO_DEBUG_NSS) + + if (nss->handle == NULL) + debug_return_int(-1); + + if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER)) + debug_return_int(-1); + debug_return_int(0); +} + +/* + * Look up the user in the parsed sudoers file and check to see if they are + * allowed to run the specified command on this host as the target user. + */ +int +sudo_file_lookup(struct sudo_nss *nss, int validated, int pwflag) +{ + int match, host_match, runas_match, cmnd_match; + struct cmndspec *cs; + struct cmndtag *tags = NULL; + struct privilege *priv; + struct userspec *us; + debug_decl(sudo_file_lookup, SUDO_DEBUG_NSS) + + if (nss->handle == NULL) + debug_return_int(validated); + + /* + * Only check the actual command if pwflag is not set. + * It is set for the "validate", "list" and "kill" pseudo-commands. + * Always check the host and user. + */ + if (pwflag) { + int nopass; + enum def_tuple pwcheck; + + pwcheck = (pwflag == -1) ? never : sudo_defs_table[pwflag].sd_un.tuple; + nopass = (pwcheck == all) ? true : false; + + if (list_pw == NULL) + SET(validated, FLAG_NO_CHECK); + CLR(validated, FLAG_NO_USER); + CLR(validated, FLAG_NO_HOST); + match = DENY; + tq_foreach_fwd(&userspecs, us) { + if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) + continue; + tq_foreach_fwd(&us->privileges, priv) { + if (hostlist_matches(&priv->hostlist) != ALLOW) + continue; + tq_foreach_fwd(&priv->cmndlist, cs) { + /* Only check the command when listing another user. */ + if (user_uid == 0 || list_pw == NULL || + user_uid == list_pw->pw_uid || + cmnd_matches(cs->cmnd) == ALLOW) + match = ALLOW; + if ((pwcheck == any && cs->tags.nopasswd == true) || + (pwcheck == all && cs->tags.nopasswd != true)) + nopass = cs->tags.nopasswd; + } + } + } + if (match == ALLOW || user_uid == 0) { + /* User has an entry for this host. */ + SET(validated, VALIDATE_OK); + } else if (match == DENY) + SET(validated, VALIDATE_NOT_OK); + if (pwcheck == always && def_authenticate) + SET(validated, FLAG_CHECK_USER); + else if (pwcheck == never || nopass == true) + def_authenticate = false; + debug_return_int(validated); + } + + /* Need to be runas user while stat'ing things. */ + set_perms(PERM_RUNAS); + + match = UNSPEC; + tq_foreach_rev(&userspecs, us) { + if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) + continue; + CLR(validated, FLAG_NO_USER); + tq_foreach_rev(&us->privileges, priv) { + host_match = hostlist_matches(&priv->hostlist); + if (host_match == ALLOW) + CLR(validated, FLAG_NO_HOST); + else + continue; + tq_foreach_rev(&priv->cmndlist, cs) { + runas_match = runaslist_matches(&cs->runasuserlist, + &cs->runasgrouplist); + if (runas_match == ALLOW) { + cmnd_match = cmnd_matches(cs->cmnd); + if (cmnd_match != UNSPEC) { + match = cmnd_match; + tags = &cs->tags; +#ifdef HAVE_SELINUX + /* Set role and type if not specified on command line. */ + if (user_role == NULL) + user_role = cs->role ? estrdup(cs->role) : def_role; + if (user_type == NULL) + user_type = cs->type ? estrdup(cs->type) : def_type; +#endif /* HAVE_SELINUX */ + goto matched2; + } + } + } + } + } + matched2: + if (match == ALLOW) { + SET(validated, VALIDATE_OK); + CLR(validated, VALIDATE_NOT_OK); + if (tags != NULL) { + if (tags->nopasswd != UNSPEC) + def_authenticate = !tags->nopasswd; + if (tags->noexec != UNSPEC) + def_noexec = tags->noexec; + if (tags->setenv != UNSPEC) + def_setenv = tags->setenv; + if (tags->log_input != UNSPEC) + def_log_input = tags->log_input; + if (tags->log_output != UNSPEC) + def_log_output = tags->log_output; + } + } else if (match == DENY) { + SET(validated, VALIDATE_NOT_OK); + CLR(validated, VALIDATE_OK); + if (tags != NULL && tags->nopasswd != UNSPEC) + def_authenticate = !tags->nopasswd; + } + restore_perms(); + debug_return_int(validated); +} + +#define TAG_CHANGED(t) \ + (cs->tags.t != UNSPEC && cs->tags.t != IMPLIED && cs->tags.t != tags->t) + +static void +sudo_file_append_cmnd(struct cmndspec *cs, struct cmndtag *tags, + struct lbuf *lbuf) +{ + struct member *m; + debug_decl(sudo_file_append_cmnd, SUDO_DEBUG_NSS) + +#ifdef HAVE_SELINUX + if (cs->role) + lbuf_append(lbuf, "ROLE=%s ", cs->role); + if (cs->type) + lbuf_append(lbuf, "TYPE=%s ", cs->type); +#endif /* HAVE_SELINUX */ + if (TAG_CHANGED(setenv)) { + lbuf_append(lbuf, cs->tags.setenv ? "SETENV: " : "NOSETENV: "); + tags->setenv = cs->tags.setenv; + } + if (TAG_CHANGED(noexec)) { + lbuf_append(lbuf, cs->tags.noexec ? "NOEXEC: " : "EXEC: "); + tags->noexec = cs->tags.noexec; + } + if (TAG_CHANGED(nopasswd)) { + lbuf_append(lbuf, cs->tags.nopasswd ? "NOPASSWD: " : "PASSWD: "); + tags->nopasswd = cs->tags.nopasswd; + } + if (TAG_CHANGED(log_input)) { + lbuf_append(lbuf, cs->tags.log_input ? "LOG_INPUT: " : "NOLOG_INPUT: "); + tags->log_input = cs->tags.log_input; + } + if (TAG_CHANGED(log_output)) { + lbuf_append(lbuf, cs->tags.log_output ? "LOG_OUTPUT: " : "NOLOG_OUTPUT: "); + tags->log_output = cs->tags.log_output; + } + m = cs->cmnd; + print_member(lbuf, m->name, m->type, m->negated, + CMNDALIAS); + debug_return; +} + +static int +sudo_file_display_priv_short(struct passwd *pw, struct userspec *us, + struct lbuf *lbuf) +{ + struct cmndspec *cs; + struct member *m; + struct privilege *priv; + struct cmndtag tags; + int nfound = 0; + debug_decl(sudo_file_display_priv_short, SUDO_DEBUG_NSS) + + tq_foreach_fwd(&us->privileges, priv) { + if (hostlist_matches(&priv->hostlist) != ALLOW) + continue; + tags.noexec = UNSPEC; + tags.setenv = UNSPEC; + tags.nopasswd = UNSPEC; + tags.log_input = UNSPEC; + tags.log_output = UNSPEC; + lbuf_append(lbuf, " "); + tq_foreach_fwd(&priv->cmndlist, cs) { + if (cs != tq_first(&priv->cmndlist)) + lbuf_append(lbuf, ", "); + lbuf_append(lbuf, "("); + if (!tq_empty(&cs->runasuserlist)) { + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m != tq_first(&cs->runasuserlist)) + lbuf_append(lbuf, ", "); + print_member(lbuf, m->name, m->type, m->negated, + RUNASALIAS); + } + } else if (tq_empty(&cs->runasgrouplist)) { + lbuf_append(lbuf, "%s", def_runas_default); + } else { + lbuf_append(lbuf, "%s", pw->pw_name); + } + if (!tq_empty(&cs->runasgrouplist)) { + lbuf_append(lbuf, " : "); + tq_foreach_fwd(&cs->runasgrouplist, m) { + if (m != tq_first(&cs->runasgrouplist)) + lbuf_append(lbuf, ", "); + print_member(lbuf, m->name, m->type, m->negated, + RUNASALIAS); + } + } + lbuf_append(lbuf, ") "); + sudo_file_append_cmnd(cs, &tags, lbuf); + nfound++; + } + lbuf_append(lbuf, "\n"); + } + debug_return_int(nfound); +} + +static int +sudo_file_display_priv_long(struct passwd *pw, struct userspec *us, + struct lbuf *lbuf) +{ + struct cmndspec *cs; + struct member *m; + struct privilege *priv; + struct cmndtag tags; + int nfound = 0; + debug_decl(sudo_file_display_priv_long, SUDO_DEBUG_NSS) + + tq_foreach_fwd(&us->privileges, priv) { + if (hostlist_matches(&priv->hostlist) != ALLOW) + continue; + tags.noexec = UNSPEC; + tags.setenv = UNSPEC; + tags.nopasswd = UNSPEC; + tags.log_input = UNSPEC; + tags.log_output = UNSPEC; + lbuf_append(lbuf, _("\nSudoers entry:\n")); + tq_foreach_fwd(&priv->cmndlist, cs) { + lbuf_append(lbuf, _(" RunAsUsers: ")); + if (!tq_empty(&cs->runasuserlist)) { + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m != tq_first(&cs->runasuserlist)) + lbuf_append(lbuf, ", "); + print_member(lbuf, m->name, m->type, m->negated, + RUNASALIAS); + } + } else if (tq_empty(&cs->runasgrouplist)) { + lbuf_append(lbuf, "%s", def_runas_default); + } else { + lbuf_append(lbuf, "%s", pw->pw_name); + } + lbuf_append(lbuf, "\n"); + if (!tq_empty(&cs->runasgrouplist)) { + lbuf_append(lbuf, _(" RunAsGroups: ")); + tq_foreach_fwd(&cs->runasgrouplist, m) { + if (m != tq_first(&cs->runasgrouplist)) + lbuf_append(lbuf, ", "); + print_member(lbuf, m->name, m->type, m->negated, + RUNASALIAS); + } + lbuf_append(lbuf, "\n"); + } + lbuf_append(lbuf, _(" Commands:\n\t")); + sudo_file_append_cmnd(cs, &tags, lbuf); + lbuf_append(lbuf, "\n"); + nfound++; + } + } + debug_return_int(nfound); +} + +int +sudo_file_display_privs(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + struct userspec *us; + int nfound = 0; + debug_decl(sudo_file_display_priv, SUDO_DEBUG_NSS) + + if (nss->handle == NULL) + goto done; + + tq_foreach_fwd(&userspecs, us) { + if (userlist_matches(pw, &us->users) != ALLOW) + continue; + + if (long_list) + nfound += sudo_file_display_priv_long(pw, us, lbuf); + else + nfound += sudo_file_display_priv_short(pw, us, lbuf); + } +done: + debug_return_int(nfound); +} + +/* + * Display matching Defaults entries for the given user on this host. + */ +int +sudo_file_display_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + struct defaults *d; + char *prefix; + int nfound = 0; + debug_decl(sudo_file_display_defaults, SUDO_DEBUG_NSS) + + if (nss->handle == NULL) + goto done; + + if (lbuf->len == 0 || isspace((unsigned char)lbuf->buf[lbuf->len - 1])) + prefix = " "; + else + prefix = ", "; + + tq_foreach_fwd(&defaults, d) { + switch (d->type) { + case DEFAULTS_HOST: + if (hostlist_matches(&d->binding) != ALLOW) + continue; + break; + case DEFAULTS_USER: + if (userlist_matches(pw, &d->binding) != ALLOW) + continue; + break; + case DEFAULTS_RUNAS: + case DEFAULTS_CMND: + continue; + } + if (d->val != NULL) { + lbuf_append(lbuf, "%s%s%s", prefix, d->var, + d->op == '+' ? "+=" : d->op == '-' ? "-=" : "="); + if (strpbrk(d->val, " \t") != NULL) { + lbuf_append(lbuf, "\""); + lbuf_append_quoted(lbuf, "\"", "%s", d->val); + lbuf_append(lbuf, "\""); + } else + lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", d->val); + } else + lbuf_append(lbuf, "%s%s%s", prefix, + d->op == false ? "!" : "", d->var); + prefix = ", "; + nfound++; + } +done: + debug_return_int(nfound); +} + +/* + * Display Defaults entries that are per-runas or per-command + */ +int +sudo_file_display_bound_defaults(struct sudo_nss *nss, struct passwd *pw, + struct lbuf *lbuf) +{ + int nfound = 0; + debug_decl(sudo_file_display_bound_defaults, SUDO_DEBUG_NSS) + + /* XXX - should only print ones that match what the user can do. */ + nfound += display_bound_defaults(DEFAULTS_RUNAS, lbuf); + nfound += display_bound_defaults(DEFAULTS_CMND, lbuf); + + debug_return_int(nfound); +} + +/* + * Display Defaults entries of the given type. + */ +static int +display_bound_defaults(int dtype, struct lbuf *lbuf) +{ + struct defaults *d; + struct member *m, *binding = NULL; + char *dsep; + int atype, nfound = 0; + debug_decl(display_bound_defaults, SUDO_DEBUG_NSS) + + switch (dtype) { + case DEFAULTS_HOST: + atype = HOSTALIAS; + dsep = "@"; + break; + case DEFAULTS_USER: + atype = USERALIAS; + dsep = ":"; + break; + case DEFAULTS_RUNAS: + atype = RUNASALIAS; + dsep = ">"; + break; + case DEFAULTS_CMND: + atype = CMNDALIAS; + dsep = "!"; + break; + default: + debug_return_int(-1); + } + tq_foreach_fwd(&defaults, d) { + if (d->type != dtype) + continue; + + nfound++; + if (binding != tq_first(&d->binding)) { + binding = tq_first(&d->binding); + if (nfound != 1) + lbuf_append(lbuf, "\n"); + lbuf_append(lbuf, " Defaults%s", dsep); + for (m = binding; m != NULL; m = m->next) { + if (m != binding) + lbuf_append(lbuf, ","); + print_member(lbuf, m->name, m->type, m->negated, atype); + lbuf_append(lbuf, " "); + } + } else + lbuf_append(lbuf, ", "); + if (d->val != NULL) { + lbuf_append(lbuf, "%s%s%s", d->var, d->op == '+' ? "+=" : + d->op == '-' ? "-=" : "=", d->val); + } else + lbuf_append(lbuf, "%s%s", d->op == false ? "!" : "", d->var); + } + + debug_return_int(nfound); +} + +int +sudo_file_display_cmnd(struct sudo_nss *nss, struct passwd *pw) +{ + struct cmndspec *cs; + struct member *match; + struct privilege *priv; + struct userspec *us; + int rval = 1; + int host_match, runas_match, cmnd_match; + debug_decl(sudo_file_display_cmnd, SUDO_DEBUG_NSS) + + if (nss->handle == NULL) + goto done; + + match = NULL; + tq_foreach_rev(&userspecs, us) { + if (userlist_matches(pw, &us->users) != ALLOW) + continue; + + tq_foreach_rev(&us->privileges, priv) { + host_match = hostlist_matches(&priv->hostlist); + if (host_match != ALLOW) + continue; + tq_foreach_rev(&priv->cmndlist, cs) { + runas_match = runaslist_matches(&cs->runasuserlist, + &cs->runasgrouplist); + if (runas_match == ALLOW) { + cmnd_match = cmnd_matches(cs->cmnd); + if (cmnd_match != UNSPEC) { + match = host_match && runas_match ? cs->cmnd : NULL; + goto matched; + } + } + } + } + } + matched: + if (match != NULL && !match->negated) { + sudo_printf(SUDO_CONV_INFO_MSG, "%s%s%s\n", + safe_cmnd, user_args ? " " : "", user_args ? user_args : ""); + rval = 0; + } +done: + debug_return_int(rval); +} + +/* + * Print the contents of a struct member to stdout + */ +static void +_print_member(struct lbuf *lbuf, char *name, int type, int negated, + int alias_type) +{ + struct alias *a; + struct member *m; + struct sudo_command *c; + debug_decl(_print_member, SUDO_DEBUG_NSS) + + switch (type) { + case ALL: + lbuf_append(lbuf, "%sALL", negated ? "!" : ""); + break; + case COMMAND: + c = (struct sudo_command *) name; + if (negated) + lbuf_append(lbuf, "!"); + lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->cmnd); + if (c->args) { + lbuf_append(lbuf, " "); + lbuf_append_quoted(lbuf, SUDOERS_QUOTED, "%s", c->args); + } + break; + case ALIAS: + if ((a = alias_find(name, alias_type)) != NULL) { + tq_foreach_fwd(&a->members, m) { + if (m != tq_first(&a->members)) + lbuf_append(lbuf, ", "); + _print_member(lbuf, m->name, m->type, + negated ? !m->negated : m->negated, alias_type); + } + break; + } + /* FALLTHROUGH */ + default: + lbuf_append(lbuf, "%s%s", negated ? "!" : "", name); + break; + } + debug_return; +} + +static void +print_member(struct lbuf *lbuf, char *name, int type, int negated, + int alias_type) +{ + alias_seqno++; + _print_member(lbuf, name, type, negated, alias_type); +} diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h new file mode 100644 index 0000000..3b1a5b5 --- /dev/null +++ b/plugins/sudoers/parse.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 1996, 1998-2000, 2004, 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. + */ + +#ifndef _SUDO_PARSE_H +#define _SUDO_PARSE_H + +#undef UNSPEC +#define UNSPEC -1 +#undef DENY +#define DENY 0 +#undef ALLOW +#define ALLOW 1 +#undef IMPLIED +#define IMPLIED 2 + +/* + * A command with args. XXX - merge into struct member. + */ +struct sudo_command { + char *cmnd; + char *args; +}; + +/* + * Tags associated with a command. + * Possible values: true, false, UNSPEC. + */ +struct cmndtag { + __signed int nopasswd: 3; + __signed int noexec: 3; + __signed int setenv: 3; + __signed int log_input: 3; + __signed int log_output: 3; +}; + +/* + * SELinux-specific container struct. + * Currently just contains a role and type. + */ +struct selinux_info { + char *role; + char *type; +}; + +/* + * The parses sudoers file is stored as a collection of linked lists, + * modelled after the yacc grammar. + * + * Other than the alias struct, which is stored in a red-black tree, + * the data structure used is basically a doubly-linked tail queue without + * a separate head struct--the first entry acts as the head where the prev + * pointer does double duty as the tail pointer. This makes it possible + * to trivally append sub-lists. In addition, the prev pointer is always + * valid (even if it points to itself). Unlike a circle queue, the next + * pointer of the last entry is NULL and does not point back to the head. + * + * Note that each list struct must contain a "prev" and "next" pointer as + * the first two members of the struct (in that order). + */ + +/* + * Tail queue list head structure. + */ +TQ_DECLARE(defaults) +TQ_DECLARE(userspec) +TQ_DECLARE(member) +TQ_DECLARE(privilege) +TQ_DECLARE(cmndspec) + +/* + * Structure describing a user specification and list thereof. + */ +struct userspec { + struct userspec *prev, *next; + struct member_list users; /* list of users */ + struct privilege_list privileges; /* list of privileges */ +}; + +/* + * Structure describing a privilege specification. + */ +struct privilege { + struct privilege *prev, *next; + struct member_list hostlist; /* list of hosts */ + struct cmndspec_list cmndlist; /* list of Cmnd_Specs */ +}; + +/* + * Structure describing a linked list of Cmnd_Specs. + */ +struct cmndspec { + struct cmndspec *prev, *next; + struct member_list runasuserlist; /* list of runas users */ + struct member_list runasgrouplist; /* list of runas groups */ + struct member *cmnd; /* command to allow/deny */ + struct cmndtag tags; /* tag specificaion */ +#ifdef HAVE_SELINUX + char *role, *type; /* SELinux role and type */ +#endif +}; + +/* + * Generic structure to hold users, hosts, commands. + */ +struct member { + struct member *prev, *next; + char *name; /* member name */ + short type; /* type (see gram.h) */ + short negated; /* negated via '!'? */ +}; + +struct runascontainer { + struct member *runasusers; + struct member *runasgroups; +}; + +/* + * Generic structure to hold {User,Host,Runas,Cmnd}_Alias + * Aliases are stored in a red-black tree, sorted by name and type. + */ +struct alias { + char *name; /* alias name */ + unsigned short type; /* {USER,HOST,RUNAS,CMND}ALIAS */ + unsigned short seqno; /* sequence number */ + struct member_list members; /* list of alias members */ +}; + +/* + * Structure describing a Defaults entry and a list thereof. + */ +struct defaults { + struct defaults *prev, *next; + char *var; /* variable name */ + char *val; /* variable value */ + struct member_list binding; /* user/host/runas binding */ + int type; /* DEFAULTS{,_USER,_RUNAS,_HOST} */ + int op; /* true, false, '+', '-' */ +}; + +/* + * Parsed sudoers info. + */ +extern struct userspec_list userspecs; +extern struct defaults_list defaults; + +/* + * Alias sequence number to avoid loops. + */ +extern unsigned int alias_seqno; + +/* + * Prototypes + */ +char *alias_add(char *, int, struct member *); +bool addr_matches(char *); +int cmnd_matches(struct member *); +int cmndlist_matches(struct member_list *); +bool command_matches(char *, char *); +int hostlist_matches(struct member_list *); +bool hostname_matches(char *, char *, char *); +bool netgr_matches(char *, char *, char *, char *); +bool no_aliases(void); +int runaslist_matches(struct member_list *, struct member_list *); +int userlist_matches(struct passwd *, struct member_list *); +bool usergr_matches(char *, char *, struct passwd *); +bool userpw_matches(char *, char *, struct passwd *); +bool group_matches(char *, struct group *); +struct alias *alias_find(char *, int); +struct alias *alias_remove(char *, int); +void alias_free(void *); +void alias_apply(int (*)(void *, void *), void *); +void init_aliases(void); +void init_lexer(void); +void init_parser(const char *, int); +int alias_compare(const void *, const void *); + +#endif /* _SUDO_PARSE_H */ diff --git a/plugins/sudoers/plugin_error.c b/plugins/sudoers/plugin_error.c new file mode 100644 index 0000000..142eddc --- /dev/null +++ b/plugins/sudoers/plugin_error.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2004-2005, 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. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "sudo_plugin.h" + +#define DEFAULT_TEXT_DOMAIN "sudoers" +#include "gettext.h" + +static void _warning(int, const char *, va_list); + void plugin_cleanup(int); + +extern sigjmp_buf error_jmp; + +extern sudo_conv_t sudo_conv; + +void +error2(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warning(1, fmt, ap); + va_end(ap); + plugin_cleanup(0); + siglongjmp(error_jmp, eval); +} + +void +errorx2(int eval, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warning(0, fmt, ap); + va_end(ap); + plugin_cleanup(0); + siglongjmp(error_jmp, eval); +} + +void +warning2(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + _warning(1, fmt, ap); + va_end(ap); +} + +void +warningx2(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _warning(0, fmt, ap); + va_end(ap); +} + +static void +_warning(int use_errno, const char *fmt, va_list ap) +{ + struct sudo_conv_message msg[6]; + struct sudo_conv_reply repl[6]; + char *str; + int nmsgs = 4; + + evasprintf(&str, fmt, ap); + + /* Call conversation function */ + memset(&msg, 0, sizeof(msg)); + msg[0].msg_type = SUDO_CONV_ERROR_MSG; + msg[0].msg = getprogname(); + msg[1].msg_type = SUDO_CONV_ERROR_MSG; + msg[1].msg = _(": "); + msg[2].msg_type = SUDO_CONV_ERROR_MSG; + msg[2].msg = str; + if (use_errno) { + msg[3].msg_type = SUDO_CONV_ERROR_MSG; + msg[3].msg = _(": "); + msg[4].msg_type = SUDO_CONV_ERROR_MSG; + msg[4].msg = strerror(errno); + nmsgs = 6; + } + msg[nmsgs - 1].msg_type = SUDO_CONV_ERROR_MSG; + msg[nmsgs - 1].msg = "\n"; + memset(&repl, 0, sizeof(repl)); + sudo_conv(nmsgs, msg, repl); + efree(str); +} diff --git a/plugins/sudoers/po/README b/plugins/sudoers/po/README new file mode 100644 index 0000000..ff9b845 --- /dev/null +++ b/plugins/sudoers/po/README @@ -0,0 +1,14 @@ +NLS Translations for sudo are coordinated through the Translation +Project, at http://translationproject.org/ + +If you would like to contribute a translation for sudo, please join +a translation team at the Translation Project instead of contributing +a po file directly. This will avoid duplicated work if there is +already a translation in progress. If you would like to become a +member of a translation team, please follow the instructions at +http://translationproject.org/html/translators.html + +The messages in sudo are split into two domains: sudo and sudoers. +The former is used by the sudo front-end and utility functions. +The latter is used by the sudoers policy and I/O logging plug-ins +as well as the sudoers-specific commands visudo and sudoreplay. diff --git a/plugins/sudoers/po/da.mo b/plugins/sudoers/po/da.mo new file mode 100644 index 0000000..4f8d6b7 Binary files /dev/null and b/plugins/sudoers/po/da.mo differ diff --git a/plugins/sudoers/po/da.po b/plugins/sudoers/po/da.po new file mode 100644 index 0000000..82e112e --- /dev/null +++ b/plugins/sudoers/po/da.po @@ -0,0 +1,1775 @@ +# Danish translation of sudoers. +# This file is put in the public domain. +# Joe Hansen , 2011, 2012. +# +# audit -> overvÃ¥gning +# dummy -> attrap +# epoch -> epoke +# execute -> udføre (run -> kør) +# overflow -> overløb +# runas -> runas ? (eller mÃ¥ske bedre med kør som. den er valgt indtil videre) +# stat -> stat +# +# der bliver brugt masser af forskellige citationstegn i den her ('' \" \" ``, +# nogle gange ogsÃ¥ tre styk). De er alle lavet med »« pÃ¥ dansk. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-13 16:21-0400\n" +"PO-Revision-Date: 2012-04-18 23:06+0100\n" +"Last-Translator: Joe Hansen \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Alias »%s« er allerede defineret" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: fejlede" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "Kunne ikke bestemme overvÃ¥gningsbetingelse" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid fejlede" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: fejlede" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: fejlede" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: fejlede" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32: fejlede" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "kan ikke indsende overvÃ¥gningspost" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: fejlede" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: fejlede" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "beklager men en adgangskode er krævet for at køre %s" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "kan ikke Ã¥bne %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "kan ikke skrive til %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "kan ikke mkdir %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "intern fejl, expand_prompt()-overløb" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "tidsstempelsti er for lang: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s findes men er ikke en mappe (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s ejet af uid %u, bør være uid %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s er skrivbar for ikkeejer (0%o), bør være tilstand 0700" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "kan ikke stat %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s findes men er ikke en regulær fil (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s skrivbar af ikkeejer (0%o), bør være tilstand 0600" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "tidsstempel for langt ude i fremtiden: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "kan ikke fjerne %s (%s), vil nulstille til epoken" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "kan ikke nulstille %s til epoken" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "ukendt uid: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "ukendt bruger: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Syslog-facilitet hvis syslog bruges til logning: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Syslog-prioritet at bruge nÃ¥r brugergodkendelser gÃ¥r igennem: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Syslog-prioritet at bruge nÃ¥r brugergodkendelser ikke gÃ¥r igennem: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "Placer OTP-prompter pÃ¥ deres egen linje" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Ignorer ».« i $PATH" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Send altid post nÃ¥r sudo køres" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "Send post hvis brugergodkendelse fejler" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "Send post hvis brugeren ikke er i suoders" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "Send post hvis brugeren ikke er i sudoers for denne vært" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "Send post hvis brugeren ikke har tilladelse til at køre en kommando" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "Brug et separat tidsstempel for hver bruger/tty-kombination" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Undervis brugere den første gang de kører sudo" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Fil indeholdende sudo-undervisningen: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Kræv som standard at brugere skal godkendes" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Root kan køre sudo" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "Log værtsnavnet i logfilen (non-syslog)" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "Log Ã¥ret i logfilen (non-syslog)" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "Hvis sudo er startet op uden argumenter sÃ¥ start en skal" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Angiv $HOME for mÃ¥lbrugeren nÃ¥r der startes en skal med -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Angiv altid $HOME for mÃ¥lbrugerens hjemmemappe" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "Tillad lidt informationsindsamling for at lave brugbare fejlbeskeder" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "Kræv fuldkvalificerede værtsnavne i sudoersfilen" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Fornærm brugeren nÃ¥r de indtaster en forkert adgangskode" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "Tillad kun brugeren at køre sudo hvis de har en tty" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo vil overholde EDITOR-miljøvariablen" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Spørg om adgangskoden for root, ikke brugerens" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Spørg om brugerens kør som_standard adgangskode, ikke brugernes" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Spørg om mÃ¥lbrugerens adgangskode, ikke brugernes" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "Brug standarder i mÃ¥lbrugerens logindklasse hvis der er en" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Angiv LOGNAME- og USER-miljøvariablerne" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "Angiv kun den effektive uid til mÃ¥lbrugeren, ikke den reelle uid" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "Initialiser ikke gruppevektoren til mÃ¥lbrugerens" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "Længde hvor logfillinjer skal ombrydes (0 for ingen ombrydning): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "Tidsudløb for godkendelsestidsstempel: %.1f minutter" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "Tidsudløb for adgangskodeprompt: %.1f minutter" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Antal forsøg for indtastning af adgangskode: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Umask at bruge eller 0777 for at bruge brugers: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Sti til logfil: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Stil til postprogram: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Flag for postprogram: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Adresse at sende post til: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Adresse at sende post fra: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Emnelinje for postbeskeder: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Ugyldig adgangskodebesked: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "Sti til mappe for godkendelsestidsstempel: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "Ejer af mappen for godkendelsestidsstempel: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "Brugere i denne gruppe er undtaget fra adgangskode og STI-krav: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "Standard for adgangskodeprompt: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "Hvis angivet vil adgangsprompt overskrive systemprompt i alle tilfælde." + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "Standardbruger at køre kommandoer som: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "Værdi at overskrive brugers $PATH med: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "Sti til redigeringsprogrammet for brug af visudo: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "HvornÃ¥r der skal kræves en adgangskode for »list« pseudokommando: %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "HvornÃ¥r der skal kræves en adgangskode for »verify« pseudokommando: %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "Præindlæs attrap-udførelsesfunktioner indeholdt i biblioteket sudo_noexec" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "Hvis LDAP-mappe er sat op, ignorer vi sÃ¥ lokal sudoersfil" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "Filbeskrivelser >= %d vil blive lukket før udførelse af en kommando" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "Hvis angivet kan brugere overskrive værdien af »closeform« med tilvalget -C" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "Tillad at brugere kan angive arbitrære miljøvariabler" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "Nulstil miljøet til et standardsæt af variabler" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "Miljøvariabler at indstillingskontrollere:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Miljøvariabler at fjerne:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Miljøvariabler at bevare:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "SELinux-rolle at bruge i den nye sikkerhedskontekst: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "SELinux-type at bruge i den nye sikkerhedskontekst: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "Sti til den sudo-specifikke miljøfil: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Sprog at bruge under fortolkning af sudoers: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "Tillad at sudo spørger om en adgangskode selv om den vil være synlig" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "Tilbyd visuel tilbagemeldning ved adgangskodeprompten nÃ¥r der er brugerinddata" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "Brug hurtigere globbing som er mindre præcis, men som ikke tilgÃ¥r filsystemet" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "Umask'en angivet i sudoers vil overskrive brugerens, ogsÃ¥ selv om den er mere tilladende" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "Log brugers inddata for kommandoen der bliver kørt" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "Log uddata for kommandoen der bliver kørt" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "Komprimer I/O-log med brug af zlib" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "Kør altid kommandoer i en pseudo-tty" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "Udvidelsesmodul for ikke-Unix-gruppeunderstøttelse: %s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "Mappe at gemme inddata-/uddatalogge i: %s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "Fil at gemme inddata-/uddatalog i: %s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "Tilføjer et punkt til utmp/utmpx-filen nÃ¥r der allokeres en pty" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "Angiv brugeren i utmp til brugeren kør som, ikke den opstartende bruger" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "ukendt standardpunkt »%s«" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "værdi »%s« er ugyldig for indstilling »%s«" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "ingen værdi angivet for »%s«" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "værdier for »%s« skal begynde med en »/«" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "indstilling »%s« kan ikke modtage en værdi" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: ødelagt envp, forskellig længde" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 toke.l:682 toke.l:812 +#: toke.l:870 toke.l:966 plugins/sudoers/toke_util.c:113 +#: plugins/sudoers/toke_util.c:167 plugins/sudoers/toke_util.c:207 +#, c-format +msgid "unable to allocate memory" +msgstr "kan ikke allokere hukommelse" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "intern fejl, sudo_setenv2()-overløb" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "intern fejl, sudo_setenv()-overløb" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "beklager, du har ikke tilladelse til at angive de følgende miljøvariabler: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 toke.l:678 +#: toke.l:866 plugins/sudoers/sudoers.c:950 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s nær linje %d <<<" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s skal være ejet af uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s skal være skrivbar af ejer" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "kan ikke dlopen %s: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "kan ikke finde symbol »group_plugin« i %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: inkompatibel gruppeudvidelsesmodul for hovedversion %d, forventede %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "Lokal IP-adresse og netmaskepar:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "kan ikke læse %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "ugyldig sekvenstal %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "kan ikke oprette %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "kan ikke angive sprog til »%s«, bruger »C«" + +#: plugins/sudoers/ldap.c:374 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: port for stor" + +#: plugins/sudoers/ldap.c:397 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: stigende mellemlager for vært (hostbuf) har ikke nok plads" + +#: plugins/sudoers/ldap.c:427 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "ikkeunderstøttet LDAP uri-type: %s" + +#: plugins/sudoers/ldap.c:456 +#, c-format +msgid "invalid uri: %s" +msgstr "ugyldig uri: %s" + +#: plugins/sudoers/ldap.c:462 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "kan ikke blande ldap og ldaps URI'er" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "kan ikke blande ldaps og starttls" + +#: plugins/sudoers/ldap.c:485 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: opbyggende mellemlager for vært (hostbuf) har ikke nok plads" + +#: plugins/sudoers/ldap.c:550 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "kan ikke initialisere SSL-cert og key db: %s" + +#: plugins/sudoers/ldap.c:958 +#, c-format +msgid "unable to get GMT time" +msgstr "kan ikke indhente GMT-tid" + +#: plugins/sudoers/ldap.c:964 +#, c-format +msgid "unable to format timestamp" +msgstr "kan ikke formatere tidsstempel" + +#: plugins/sudoers/ldap.c:972 +#, c-format +msgid "unable to build time filter" +msgstr "kan ikke bygge tidsfilter" + +#: plugins/sudoers/ldap.c:1187 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "sudo_ldap_build_pass1 forskellige allokeringer" + +#: plugins/sudoers/ldap.c:1707 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP-rolle: %s\n" + +#: plugins/sudoers/ldap.c:1709 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP-rolle: UKENDT\n" + +#: plugins/sudoers/ldap.c:1756 +#, c-format +msgid " Order: %s\n" +msgstr " Rækkefølge: %s\n" + +#: plugins/sudoers/ldap.c:1764 +#, c-format +msgid " Commands:\n" +msgstr " Kommandoer:\n" + +#: plugins/sudoers/ldap.c:2156 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "kan ikke initialisere LDAP: %s" + +#: plugins/sudoers/ldap.c:2187 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "start_tls angivet men LDAP libs understøtter ikke ldap_start_tls_s() eller ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2423 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "ugyldig sudoOrder-attribut: %s" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "for mange niveauer af includes (inkluderinger)" + +#: toke.l:829 plugins/sudoers/sudoers.c:1004 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s er ejet af uid %u, bør være %u" + +#: toke.l:836 plugins/sudoers/sudoers.c:1008 +#, c-format +msgid "%s is world writable" +msgstr "%s er skrivbar for alle" + +#: toke.l:841 plugins/sudoers/sudoers.c:1011 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s er eget af gid %u, bør være %u" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "kan ikke Ã¥bne overvÃ¥gningssystem" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "intern fejl, linux_audit_command()-overløb" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "kan ikke sende overvÃ¥gningsbesked" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "kan ikke Ã¥bne logfil: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "kan ikke lÃ¥se logfil: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "bruger IKKE i sudoers" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "bruger IKKE autoriseret pÃ¥ vært" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "kommando ikke tilladt" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s er ikke sudoersfilen. Denne handling vil blive rapporteret.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s har ikke tilladelse til at køre sudo pÃ¥ %s. Denne handling vil blive rapporteret.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Beklager. Bruger %s mÃ¥ ikke køre sudo pÃ¥ %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Beklager. Bruger %s har ikke tilladelse til at køre »%s%s%s« som %s%s%s pÃ¥ %s.\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "kan ikke forgrene" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "kan ikke forgrene: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "kan ikke Ã¥bne datakanal: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "kan ikke dup stdin: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "kan ikke køre %s: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "intern fejl: utilstrækkelig plads for loglinje" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "fortolkningsfejl i %s nær linje %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "fortolkningsfejl i %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Sudoers-punkt:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " KørSomBrugere: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " KørSomGrupper: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Kommandoer:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "kan ikke cache uid %u (%s), findes allerede" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "kan ikke cache uid %u, findes allerede" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "kan ikke cache bruger %s, findes allerede" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "kan ikke cache gid %u (%s), findes allerede" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "kan ikke cache gid %u, findes allerede" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "kan ikke cache gruppe %s, findes allerede" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "permanent stakoverløb" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "permanent stakunderløb" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "kan ikke ændre til kør som gid" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "kan ikke ændre til kør som uid" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "kan ikke ændre til sudoers gid" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "for mange processer" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "kan ikke angive kør som gruppevektor" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "Matchende standardpunkter for %s pÃ¥ denne vært:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "Kør som og kommandospecifikke standarder for %s:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Bruger %s mÃ¥ ikke køre de følgende kommandoer pÃ¥ denne vært:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Bruger %s har ikke tilladelse til at køre sudo pÃ¥ %s.\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "problem med standardpunkter" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "ingen gyldige sudoerskilder fundet, afslutter" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "kan ikke udføre %s: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers angiver at administrator (root) ikke har tilladelse til sudo" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "du har ikke tilladelse til at bruge tilvalget -C" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "tidsstempelejer (%s): Ingen sÃ¥dan bruger" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "ingen tty" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "beklager, du skal bruge en tty for at køre sudo" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "Ingen bruger eller vært" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: Kommando ikke fundet" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"ignorerer »%s« fundet i ».«\n" +"Brug »sudo ./%s« hvis dette er »%s«, du ønsker at køre." + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "valideringsfejl" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "kommando i aktuel mappe" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "beklager men du har ikke tilladelse til at bevare miljøet" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "intern fejl, runas_groups-overløb" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "intern fejl, set_cmnd()-overløb" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s er ikke en regulær fil" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "kun administrator (root) kan bruge »-c %s«" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "ukendt logindklasse: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "kan ikke slÃ¥ vært %s op" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "ukendt gruppe: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Udvidelsesmodulversion %s for sudoerspolitik\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Grammatikversion %d for sudoersfil\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Sudoers-sti: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "nsswitch-sti: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ldap.conf-sti: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ldap.secret-sti: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "ugyldigt filtertilvalg: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "ugyldig maks ventetid: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "ugyldig hastighedsfaktor: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s version %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/timing: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/timing: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "Genafspiller sudosession: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "Advarsel: Din terminal er for lille til korrekt at afspille loggen.\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "Loggeometri er %d x %d, din terminals geometri er %d x %d." + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "kan ikke angive tty til rÃ¥ (raw) tilstand" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "ugyldig timingfillinje: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "skriver til standarduddata" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "tvetydigt udtryk »%s«" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "for mange udtryk i parentes, maks %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "manglende »)« i udtryk" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "ukendt søgeterm »%s«" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s kræver et argument" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "ugyldigt regulært udtryk: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "kunne ikke fortolke dato »%s«" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "mangler »(« i udtryk" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "ugyldig kæde »or« (eller)" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "ugyldig kæde »!«" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "ugyldigt regulært udtryk: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "brug: %s [-h] [-d mappe] [-m maks_ventetid] [-s hastighedsfaktor] ID\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "brug: %s [-h] [-d mappe] -l [søgeudtryk]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - genafspil sudosessionslogge\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"Tilvalg:\n" +" -d mappe angiv mappe for sessionslogge\n" +" -f filter angiv hvilken I/O-type at vise\n" +" -h vis denne hjælpetekst og afslut\n" +" -l [udtryk] vis tilgængelilge sessions-ID'er som overholder\n" +" udtryk\n" +" -m maks_vent maks antal sekunder at vente mellem hændelser\n" +" -s hastighedsfaktor øg eller sænk uddata\n" +" -V vis versionsinformation og afslut" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "intern fejl, init_vars()-overløb" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\thost matchede ikke" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Kommando tilladt" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Kommando nægtet" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"Kommando ikke matchet" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: overløb for mellemlager" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s grammatikversion %d\n" + +#: plugins/sudoers/visudo.c:220 plugins/sudoers/auth/rfc1938.c:104 +#, c-format +msgid "you do not exist in the %s database" +msgstr "du findes ikke i %s-databasen" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "tryk retur for at redigere %s: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "skrivefejl" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "kan ikke stat midlertidig fil (%s), %s unchanged" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "midlertidig fil med nullængde (%s), %s uændret" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "redigeringsprogram (%s) fejlede, %s uændret" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s uændret" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "kan ikke genÃ¥bne midlertidig fil (%s), %s uændrede." + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "kan ikke fortolke midlertidig fil (%s), ukendt fejl" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "intern fejl, kan ikke finde %s pÃ¥ listen!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "kan ikke angive (uid, gid) af %s til (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "kan ikke ændre tilstand pÃ¥ %s til 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s og %s er ikke pÃ¥ det samme filsystem, bruger mv til at omdøbe" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "kommando fejlede: »%s %s %s«, %s uændret" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "fejl under omdøbing af %s, %s uændret" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "Hvad nu? " + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Tilvalg er:\n" +" r(e)diger sudoersfil igen\n" +" afslut(x) uden at gemme ændringer til sudoersfil\n" +" afslut(Q) og gem ændringer til sudoersfil (FARLIGT!)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "kan ikke udføre %s" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "kan ikke køre %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: forkert ejer (uid, gid) bør være (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: ugyldige rettigheder, bør være tilstand 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "kunne ikke fortolke %s-fil, ukendt fejl" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "fortolkningsfejl i %s nær linje %d\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "fortolkningsfejl i %s\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: fortolket o.k.\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s travl, forsøg igen senere" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "angivet redigeringsprogram (%s) findes ikke" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "kan ikke stat redigeringsprogram (%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "intet redigeringsprogram fundet (sti for redigeringsprogram = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "Fejl: Cyklus i %s_Alias »%s«" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "Advarsel: Cyklus i %s_Alias »%s«" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "Fejl: %s_Alias »%s« refereret men ikke defineret" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "Advarsel: %s_Alias »%s« refereret men ikke defineret" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s: ubrugt %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - rediger sikkert sudoersfilen\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"Tilvalg:\n" +" -c kun kontroltilstand\n" +" -f sudoers angiv placering for sudoersfil\n" +" -h vis denne hjælpetekst og afslut\n" +" -q mindre uddybende (stille) beskeder for syntaksfejl\n" +" -s streng syntakskontrol\n" +" -V vis information om version og afslut" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "kan ikke hente logindklasse for bruger %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "kan ikke starte bsd-godkendelse" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "ugyldig godkendelsestype" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "kan ikke opsætte godkendelse" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "kan ikke læse fwtk-konfiguration" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "kan ikke forbinde til godkendelsesserver" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "mistede forbindelsen til godkendelseserveren" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"godkendelsesserverfejl:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s: Kan ikke fjerne fortolkning af princ (»%s«): %s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: Kan ikke fortolke »%s«: %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: Kan ikke løse ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: Kan ikke allokere tilvalg: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: Kan ikke indhente akkreditiver: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: Kan ikke initialisere ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: Kan ikke gemme cred i ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: Kan ikke indhente værtshovedstol: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: Kan ikke verifiere TGT! Muligt angreb!: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "kan ikke initialisere PAM" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "valideringsfejl for konto, er din konto lÃ¥st?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Konto eller adgangskoder er udløbet, nulstil din adgangskode og forsøg igen" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Adgangskode udløbet, kontakt din systemadministrator" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "Konto udløbet eller PAM-konfiguration mangler et »kontoafsnit« for sudo. Kontakt din systemadministrator" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:330 +msgid "Password: " +msgstr "Adgangskode: " + +#: plugins/sudoers/auth/pam.c:331 +msgid "Password:" +msgstr "Adgangskode:" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "kunne ikke initialisere ACE API-biblioteket" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "kan ikke kontakte SecurID-serveren" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "Bruger-ID lÃ¥st for SecurID-godkendelse" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "ugyldigt brugernavnslængde for SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "ugyldigt godkendelseshÃ¥ndtag for SecurID" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "SecurID-kommunikation fejlede" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "ukendt SecurID-fejl" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "ugyldig adgangskodelængde for SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "kan ikke initialisere SIA-session" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "Ugyldige godkendelsesmetoder kompileret ind i sudo! Du kan blande alenestÃ¥ende og ikkealenestÃ¥ende godkendelse." + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "Der er ingen godkendelsesmetoder kompileret ind i sudo! Hvis du ønsker at fravælge godkendelse sÃ¥ brug konfigurationstilvalget --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d ukorrekt adgangskodeforsøg" +msgstr[1] "%d ukorrekte adgangskodeforsøg" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Godkendelsesmetoder:" + +#~ msgid "invalid log file %s" +#~ msgstr "ugyldig logfil %s" + +#~ msgid "fixed mode on %s" +#~ msgstr "fast tilstand pÃ¥ %s" + +#~ msgid "set group on %s" +#~ msgstr "angiv gruppe pÃ¥ %s" + +#~ msgid "unable to set group on %s" +#~ msgstr "kan ikke angive gruppe pÃ¥ %s" + +#~ msgid "unable to fix mode on %s" +#~ msgstr "kan ikke rette tilstand pÃ¥ %s" + +#~ msgid "%s is mode 0%o, should be 0%o" +#~ msgstr "%s er tilstand 0%o, bør være 0%o" + +#~ msgid "File containing dummy exec functions: %s" +#~ msgstr "Fil der indeholder attrap-udførelsesfunktioner: %s" + +#~ msgid "" +#~ "Available options in a sudoers ``Defaults'' line:\n" +#~ "\n" +#~ msgstr "" +#~ "Tilgængelige indstillinger i en sudoers »standardlinje«:\n" +#~ "\n" + +#~ msgid "%s: %s\n" +#~ msgstr "%s: %s\n" + +#~ msgid "%s: %.*s\n" +#~ msgstr "%s: %.*s\n" diff --git a/plugins/sudoers/po/eo.mo b/plugins/sudoers/po/eo.mo new file mode 100644 index 0000000..266c4a7 Binary files /dev/null and b/plugins/sudoers/po/eo.mo differ diff --git a/plugins/sudoers/po/eo.po b/plugins/sudoers/po/eo.po new file mode 100644 index 0000000..c9150f2 --- /dev/null +++ b/plugins/sudoers/po/eo.po @@ -0,0 +1,1751 @@ +# Esperanto translations for sudo package. +# This file is put in the public domain. +# Keith Bowes , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 19:01-0400\n" +"Last-Translator: Keith Bowes \n" +"Language-Team: Esperanto \n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s apud linio %d <<<" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Kromnomo '%s' jam ekzistas" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "ne eblas akiri ensalutan klason por uzanto %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "ne eblas komenci bsd-konstatadn" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "nevalida konstata tipo" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "ne eblas starigi konstatadon" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "ne eblas legi fwtk-agordon" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "ne eblas konektiĝi al konstatanta servilo" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "konekto al konstatanta servilo perdita" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"eraro de konstatanta servilo:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s ne eblas analizi princ-on ('%s'): %s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: ne eblas analizi: '%s': %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: ne eblas trovi ccache-on: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: ne eblas generi elektojn: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: ne eblas akiri atestilojn: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: ne eblas iniciati ccache-on: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: ne eblas konservi atestilon en ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: ne eblas atingi ĉefgastiganto: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: Ne eblas konstati TGT-on! Ebla atako!: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "ne eblas iniciati PAM-on" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "malsukceso ĉe konta validigo, ĉu via konto estas ŝlosita?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Konto aÅ­ pasvorto eksvalidiĝis, restarigu vian pasvorton kaj reprovu" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Pasvorto eksvalidiĝis, kontaktu vian sistemestron" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "Konto eksvalidiĝis aÅ­ PAM-agordon malhavas sekcion \"account\" por sudo, kontaktu vian sistemestron" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "Pasvorto: " + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "Pasvorto:" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "vi ne ekzistas en la datumbazo %s" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "malsukcesis iniciati la bibliotekon de la API ACE" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "ne eblas kontakti la servilon de SecurID" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "Uzanto identigilo ŝlosita pro konstatado en SecurID" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "nevalida salutnoma longo por SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "nevalida konstatilo por SecurID" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "Komunikiĝo kun SecurID malsukcesis" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "nekonata SecurID-eraro" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "nevalida paskoda longo por SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "ne eblas iniciati SIA-seascon" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "Nevalidaj konstatantaj metodoj muntitaj en sudo! Vi rajtas miksi dependan kaj sendependan konstatadon." + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "Ekzistas neniaj konstatantaj metodoj muntitaj en sudo! Se vi volas malŝalti konstatadon, uzu la munta parametro --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d malĝusta pasvorta provo" +msgstr[1] "%d malĝustaj pasvortaj provoj" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Konstatantaj metodoj:" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "Ne eblis determini revizian kondiĉon" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "getaudit: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "ne eblis konservi revizian rekordon" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: malsukcesis" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: malsukcesis" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "bedaÅ­ri pasvorto estas bezonata por plenumi: %s" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "ne eblas malfermi: %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "ne eblas skribi al %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "ne eblas mkdir-i: %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "ena eraro, superfluo en expand_prompt()" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "tempo-indikila pado tro longa: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s ekzistas sed ne dosierujo (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s estas estrita de uid %u, devas esti uid %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s skribebla de ne-estro (0%o), devas esti reĝimo 0700" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "ne eblas stat-i: %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s ekzistas sed ne estas normala dosiero (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s skribebla de ne-estro (0%o), devas esti reĝimo 0600" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "tempo-indikilo tro estonte: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "ne eblas forigi: %s (%s); restarigos al la epoko" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "ne eblas restarigi al la epoko: %s" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "nekonata uid: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "nekonata uzanto: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Syslog-trajto se syslog estas uzata por protokoli: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Syslog-prioritato por uzi, kiam uzanta sukcese konstatas: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Syslog-prioritato por uzi kiam uzanto malsukcese konstatas: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "Meti OTP-demandilon en sia propra linio" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Ignoro punkton en $PATH" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Ĉiam sendi retmesaĝon kiam sudo plenumiĝas" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "Sendi retmesaĝon se uzanto-konstato malsukcesas" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "Sendi retmesaĝon se la uzanto ne estas en sudoers" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "Sendi retmesaĝon se la uzanto ne estas en sudors por la gastiganto" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "Sendi retmesaĝon se la uzanto ne estas permesata plenumigi komandon" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "Uzi apartan tempo-indikilon por ĉiu uzanto/tty-kombino" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Averti uzanton dum la unua fojo ĝi plenumigas je sudo" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Dosiero havanta la sudo-averton: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Postulas, ke uzantoj konstatas aÅ­tomate" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Ĉefuzanto rajtas plenumigi: sudo" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "Protokoli la gastignomon en la (ne syslog) protokolo" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "Protokoli la jaron en la (ne syslog) protokolo" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "Se sudo estas vokata kun neniuj parametroj, komencu ŝelon" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Valorizi medivariablon $HOME al la cela uzanto dum komenci ŝelon kun -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Ĉiam valorizi medivariablon $HOME al la hejma dosierujo de la cela uzanto" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "Permesi, ke iu informokolektado por doni utilajn eraromesaĝojn" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "Postuli tute kvalifikitajn gastiganto-nomojn en la dosiero sudoers" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Insulti la uzanton, kiam si enmetas malĝustan pasvorton" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "Nur permesi, ke uzanto plenumigu sudo-on se si havas tty-on" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo honoru la medivariablon EDITOR" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Peti la ĉefuzantan pasvorton, ne la uzanto-pasvorton" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Peti la pasvorton de runas_default, ne de la uzanto" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Peti la pasvorton de la cela uzanto, ne la nuna uzanto" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "Apliki aÅ­tomataĵojn en la ensaluta klaso de la cela uzanto, se ĝi ekzistas" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Valorizi la medivariablojn LOGNAME kaj USER" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "Nur valorizi la efikan uid-on al la cela uzanto, ne la realan uid-on" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "Ne iniciati la grupon vektoron al tio de la cela uzanto" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "Longo je kiu linfaldi la protokolon (0 por senfalda): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "Eksvalidiĝo de la konstata tempo-indikilo: %.1f minutoj" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "Eksvalidiĝo de la pasvortilo: %.1f minutoj" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Nombro da provoj por enmeti pasvorton: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Umask uzi aÅ­ 07777 por uzi uzanton: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Pado al protokolo: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Pado al retpoŝtilo: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Parametroj por retpoŝtilo: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Retpoŝtadreso adresata: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Retpoŝtadreso adresanta: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Subjekta linio por ĉiuj mesaĝoj: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Neĝusta pasvorta mesaĝo: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "Pado al dosierujo de konstata tempostampo: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "Estro de la dosierujo de konstata tempostampo: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "Uzantoj en la grupo en devas plenumi la postulojn de posvorto kaj PATH: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "DefaÅ­lta pasvorta peto: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "Se aktivigita, passprompt superregas sistemajn invitojn ĉiuokaze." + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "DefaÅ­lta uzanto por plenumigi komandojn: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "Valoro per kiu superregi la PATH-on de uzanto: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "Pado al la tekstoredaktilo uzota de visudo: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "Kiam postuli pasvorton por la pseÅ­dokomando 'list': %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "Kiam postuli pasvorton por la pseÅ­dokamando 'verify': %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "Anstaŭŝargi la falsan exec-funkciojn enhavatajn en la biblioteko sudo_noexec" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "Se LDAP-dosierujo estas aktiva, ni ignoru la lokan suders-dosieron" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "Dosiero-priskribiloj >= %d fermiĝos antaÅ­ ol plenumigi komandon" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "Se aktiva, uzantoj rajtas superregi la voloron de 'closefrom' per la parametro -C" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "Permesi, ke uzantoj valorizu arbitrajn medivariablojn" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "Restarigi la medion al apriora aro da variabloj" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "Medivariabloj por kontroli por sano:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Medivariabloj por forigi:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Medivariabloj konservi:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "SELinux-rolo por uzi en la nova sekureca kunteksto: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "SELinux-tipo por uzi en la nova sekureca kunteksto: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "Pado al media dosiero specifa al sudo: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Lokaĵaro por uzi dum analizi dosieron sudoers: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "Permesi, ke sudo peti pasvorton eĉ se ĝi estus videbla" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "Doni vidajn indikojn je la pasvorta enmetanta kiam ekzistas enmeto" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "Uzi pli rapida kunigo, kiu estas malpli ĝusta sed ne atingas la dosiersistemon" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "La umask specifa en sudors superregos tio de la uzanto, eĉ se ĝi estas pli permesema." + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "Protokoli enmeton de uzanto por la komando, kiun si plenumigas" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "Protokoli la eligon de la komando, kiu estas plenumiĝi" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "Kunpremi eneligaj protokoloj per zlib" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "Ĉiam protokoli komandojn en pseÅ­da tty" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "Kromprogramo por kompreno de ne-uniksaj grupoj: %s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "Dosierujo en kiu konservi eneligaj protokoloj: %s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "Dosiero en kiu konservi la eneliga protokolo: %s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "Aldoni eron al la utmp/utmpx-dosiero dum generi pty-on" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "Valorizi uzanton en utmp al la plenumigkiela uzanto, ne la vokanta uzanto" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "nekonata ero '%s' en defaults" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "valoro '%s' estas nevalida por parametro '%s'" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "neniu valoro specifita por '%s'" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "Valoroj por '%s' devas komenciĝi per '/'" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "parametro '%s' ne povas havi valoron" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: medio tro granda" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "ne eblas generi memoron" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "ena eraro, superfluo en sudo_setenv2()" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "ena eraro, superfluo en sudo_setenv()" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "bedaÅ­re vi ne estas permesata valorizi la jenajn medivariablojn: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s devas esti estrata de uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s devas esti skribebla nur de estro" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "ne eblas dlopen: %s: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "ne eblas trovi simbolon \"group_plugin\" en %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: nekongrua grupa kromprogramo: ĉefa eldono %d, atendita %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "Loka IP-adresa kaj retmaska paroj:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "ne eblas legi %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "nevalida sinsekva numero %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "ne eblas krei: %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "ne eblas elekti lokaĵaron \"%s\", uzanta lokaĵaron \"C\"" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: pordo tro granda" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: eluzis spacon etendanta la bufron" + +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "nekonata retadresa tipo de LDAP: %s" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "nevalida retadreso: %s" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "ne eblas miksi sekurajn kaj nesekurajn retadresojn de LDAP" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "ne eblas miksi protokolojn ldaps kaj starttls" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: eluzis spacon muntanta la bufron" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "ne eblas iniciati SSL-asertilon kaj ŝlosilan datumbazon: %s" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "TLS_CERT devas havi valoron en %s antaÅ­ ol SSL uzeblos" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "ne eblas atingi GMT-tempon" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "ne eblas aranĝi tempostampon" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "ne eblas munti tempan filtrilon" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "sudo_ldap_build_pass1: genra malkongruaĵo" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP-rolo: %s\n" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP-rolo: NEKONATA\n" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr " Ordo: %s\n" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr " Komandoj:\n" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "ne eblas iniciati LDAP-on: %s" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "start_tls specifita sed LDAP-bibliotekoj ne havas la funkciojn ldap_start_tls_s() kaj ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "nevalida atributo de sudoOrdo: %s" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "ne eblas malfermi revizian sistemon" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "ena eraro, superfluo en linux_audit_command()" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "ne eblas sendi revizian mesaĝon" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "ne eblas malfermi protokolon: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "ne eblas ŝlosi protokolon: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "uzanto NE estas en sudoers" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "uzanto NE permesata en gastiganto" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "komando ne permesata" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s ne estas en la dosiero sudoers. Ĉi tiu estos raportita.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s estas ne permesata plenumigi sudo-on en %s. Ĉi tio estos raportita\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "BedaÅ­re uzanto %s ne rajtas plenumigi sudo-on en %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "BedaÅ­re uzanto %s ne rajtas plenumigi '%s%s%s'-on kiel %s%s%s en %s.\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "ne eblas forki" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "ne eblas forki: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "ne eblas malfermi tubon: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "ne eblas kopii enigon: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "ne eblas plenumigi %s-on: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "ena eraro: nesufiĉa spaco por protokola linio" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "analiza eraro en %s proksime al linio %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "analiza eraro en %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Ero en sudoers:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " RunAsUsers: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " RunAsGroups: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Komandoj:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "ne eblas konservi uid-on %u (%s), jam ekzistas" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "ne eblas konservi uid-on %u, jam ekzistas" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "ne eblas konservi uzanton %s, jam ekzistas" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "ne eblas konservi gid-on %u (%s), jam ekzistas" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "ne eblas konservi gid-on %u, jam ekzistas" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "ne eblas konservi grupon %s, jam ekzistas" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "permeso-staka superfluo" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "permeso-staka subfluo" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "ne eblas ŝanĝi al plenumigkiela gid" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "ne eblas ŝanĝi al plenumigkiela uid" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "ne eblas ŝanĝi al gid de sudo-redaktantoj" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "tro da procezoj" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "ne eblas elekti vektoron de plenumigkiela grupo" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "Kongruantaj eroj de Defaults: %s en ĉi tiu gastiganto:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "Plenumigkiela komando-specifaj aÅ­tomataĵoj por %s:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Uzanto %s rajtas plenumigi la jenajn komandojn en ĉi tiu gastiganto:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Uzanto %s ne rajtas plenumigi sudo-on en %s.\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "problemoj kun aÅ­tomataj eroj" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "ne validaj fontotekstoj de sudoers trovita, ĉesiganta" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "ne eblas plenumigi %s-on: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers specifas, ke ĉefuzanto ne rajtas sudo-i" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "vi ne rajtas uzi la parametron -C" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "posedanto de tempindiko estas %s -- sed tiu uzanto ne ekzistas" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "neniu tty" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "bedaÅ­re vi devas havi tty-on por plenumigi sudo-on" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "Neniu uzanto aÅ­ gastiganto" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: komando ne trovita" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"Ignoranta '%s'-on trovita en '.'\n" +"Uzu 'sudo ./%s'-on se tio estas la '%s', kiun vi volas plenumigi." + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "validiga malsukceso" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "komando en nuna dosierujo" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "bedaÅ­re vi ne rajtas konservi la medion" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "ena eraro, runas_groups superfluo" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "ena eraro, superfluo en set_cmnd()" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s ne estas normala dosiero" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s estas estrita de uid %u, devas esti %u" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "%s estas skribebla de ĉiuj" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s estas estrita de gid %u, devas esti %u" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "nur ĉefuzanto rajtas uzi '-c %s'" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "nekonata ensaluta klaso: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "ne eblas trovi gastiganton %s" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "nekonata grupo: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Eldono %s de la konduta kromprogramo\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Eldono %d de la gramatikilo de sudoers\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Pado de sudoers: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "pado de nsswitch: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "pado de ldap.conf: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "pado de ldap.secret: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "nevalida filtrila elekto: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "nevalida maksimuma atendo: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "nevalida rapida faktoro: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s eldono %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s tempo-registrado: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/tempo-registrado: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "Refaranta sudo-seancon: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "Averto: via terminalo estas tro malgranda por konvene reskribi la protokolon.\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "Protokola grando estas %dx%d, sed via terminala grando estas %dx%d." + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "ne eblas elekti tty-on en nudan reĝimon" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "nevalida linio en la tempo-registran dosieron: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "skribanta al eligo" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "ambigua esprimo \"%s\"" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "tro da esprimoj en krampoj; maksimumo estas %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "esprimo kun ')' sen samnivela '('" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "nekonata serĉaĵo \"%s\"" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s bezonas parametron" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "nevalida regulesprimo: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "ne eblis analizi daton \"%s\"" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "esprimo kun '(' sen samnivela ')'" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "nevalida posta \"or\"" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "nevalida posta \"!\"" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "nevalida regulesprimo: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "uzado: %s [-h] [-d dosierujo] [-m maksimuma_atendo] [-s rapida_faktoro] identigilo\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "uzado: %s [-h] [-d dosierujo] -l [serĉaĵo]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - refari sudo-seancajn protokolojn\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"Parametroj:\n" +" -d dosierujo specifi dosierujon por seancaj protokoloj\n" +" -f filtrilo specifi kiajn eneligajn tipojn por montri\n" +" -h montri helpan mesaĝon kaj eliri -l [esprimo] listigi haveblajn seancajn identigilojn, kiuj kongruas kun esprimo\n" +" -m [atendo] maksimuma nombro da sekundoj por atendi inter okazoj\n" +" -s [rapido] rapidigi aÅ­ malrapidigi eligon\n" +" -V eligi eldonan informon kaj eliri" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "ena eraro, superfluo en init_vars()" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\thost sen egalo" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Komando permesata" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Komando rifuzata" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"Komando sen egalo" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: bufra superfluo" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s gramatika eldono %d\n" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "premu enen-klavon por redakti %s-on: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "skriba eraro" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "ne eblas stat-i provizoron dosieron (%s), %s neŝanĝita" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "nul-longa provizora dosiero (%s), %s neŝanĝita" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "redaktilo (%s) malsukcesis, %s neŝanĝita" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s neŝanĝita" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "ne eblas remalfermi provizoran dosieron (%s), %s neŝanĝita." + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "ne eblas analizi provizoran dosieron (%s), nekonata eraro" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "ena eraro, ne eblas trovi '%s'-on en listo!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "ne eblas ŝanĝi (uid, gid) de %s al (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "ne eblas ŝanĝi reĝimon de %s al 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s kaj %s ne estas la sama dosiersistemo, uzanta mv-on por alinomi" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "komando malsukcesis: '%s %s %s', %s neŝanĝita" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "eraro dum alinomi %s-on; %s neŝanĝita" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "Kion nun? " + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Elektoj estas:\n" +" r(e)dakti refoje sudoers-dosieron\n" +" x) eliri sen konservi ŝanĝojn al sudoers-dosiero\n" +" q) Eliri kaj konservi ŝanĝojn al sudoers-dosiero (DANĜERA!)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "ne eblas plenumigi: %s" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "ne eblas plenumigi: %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: malĝusta estro (uid, gid) devas esti (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: misaj permesoj, devas esti reĝimo 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "malsukcesis analizi dosieron %s, nekonata eraro" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "analiza eraro en %s proksime al linio %d\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "analiza eraro en %s\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: analizita senerare\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s okupata, reprovu pli malfrue" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "specifita tekstoredaktilo (%s) ne ekzistas" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "ne eblas stat-i tekstoredaktilon (%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "neniu tekstoredaktilo trovita (pado = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "Eraro: ciklo en %s_Alias '%s'" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "Averto: ciklo en %s_Alias '%s'" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "Eraro: %s_Alias '%s' referinta sed ne difinita" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "Averto: %s_Alias '%s' referinta sed ne difinita" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s neuzata %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - sekure redakti la dosieron sudoers\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"Parametroj:\n" +" -c nur kontroli\n" +" -f sudoers specifi lokon de la dosiero sudoers\n" +" -h montri helpan mesaĝon kaj eliri\n" +" -q silenta pri sintaksaj eraroj\n" +" -s malsevera kontrolado de sintakso\n" +" -V montri eldonon kaj eliri" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "tro da niveloj de inkluzivaĵoj" + +#~ msgid "invalid log file %s" +#~ msgstr "nevalida protokolo %s" + +#~ msgid "fixed mode on %s" +#~ msgstr "fiksita reĝimo en %s" + +#~ msgid "set group on %s" +#~ msgstr "elekti grupon en %s" + +#~ msgid "unable to set group on %s" +#~ msgstr "ne eblas elekti grupon en %s" + +#~ msgid "unable to fix mode on %s" +#~ msgstr "ne eblas fiksi reĝimon en %s" + +#~ msgid "%s is mode 0%o, should be 0%o" +#~ msgstr "%s estas reĝimo 0%o, devas esti 0%o" diff --git a/plugins/sudoers/po/eu.mo b/plugins/sudoers/po/eu.mo new file mode 100644 index 0000000..9d58549 Binary files /dev/null and b/plugins/sudoers/po/eu.mo differ diff --git a/plugins/sudoers/po/eu.po b/plugins/sudoers/po/eu.po new file mode 100644 index 0000000..bda562a --- /dev/null +++ b/plugins/sudoers/po/eu.po @@ -0,0 +1,1678 @@ +# Basque translation of sudoers. +# Copyright (C) 2011 Free Software Foundation, Inc. +# This file is distributed under the same license as the sudo package. +# Mikel Olasagasti Uranga , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers-1.8.2-rc2\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2011-06-04 18:27-0400\n" +"PO-Revision-Date: 2011-06-06 19:15+0100\n" +"Last-Translator: Mikel Olasagasti Uranga \n" +"Language-Team: Basque \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: plugins/sudoers/alias.c:122 +#, c-format +msgid "Alias `%s' already defined" +msgstr "`%s' alias-a lehendik ere definitua dago" + +#: plugins/sudoers/bsm_audit.c:58 plugins/sudoers/bsm_audit.c:61 +#: plugins/sudoers/bsm_audit.c:109 plugins/sudoers/bsm_audit.c:113 +#: plugins/sudoers/bsm_audit.c:163 plugins/sudoers/bsm_audit.c:167 +msgid "getaudit: failed" +msgstr "getaudit: huts egin du" + +#: plugins/sudoers/bsm_audit.c:87 plugins/sudoers/bsm_audit.c:148 +msgid "Could not determine audit condition" +msgstr "Ezin izan da auditoretza baldintza finkatu" + +#: plugins/sudoers/bsm_audit.c:98 +msgid "getauid failed" +msgstr "getauid-ek huts egin du" + +#: plugins/sudoers/bsm_audit.c:100 plugins/sudoers/bsm_audit.c:157 +msgid "au_open: failed" +msgstr "au_open: huts egin du" + +#: plugins/sudoers/bsm_audit.c:115 plugins/sudoers/bsm_audit.c:169 +msgid "au_to_subject: failed" +msgstr "au_to_subject: huts egin du" + +#: plugins/sudoers/bsm_audit.c:119 plugins/sudoers/bsm_audit.c:173 +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: huts egin du" + +#: plugins/sudoers/bsm_audit.c:123 plugins/sudoers/bsm_audit.c:182 +msgid "au_to_return32: failed" +msgstr "au_to_return32: huts egin du" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:185 +msgid "unable to commit audit record" +msgstr "ezin da auditoretza sarrera gorde" + +#: plugins/sudoers/bsm_audit.c:155 +msgid "getauid: failed" +msgstr "getauid: huts egin du" + +#: plugins/sudoers/bsm_audit.c:178 +msgid "au_to_text: failed" +msgstr "au_to_text: huts egin du" + +#: plugins/sudoers/check.c:141 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "barkatu, pasahitz bat behar da %s abiarazteko" + +#: plugins/sudoers/check.c:225 plugins/sudoers/iolog.c:169 +#: plugins/sudoers/sudoers.c:939 plugins/sudoers/sudoreplay.c:325 +#: plugins/sudoers/sudoreplay.c:334 plugins/sudoers/sudoreplay.c:675 +#: plugins/sudoers/sudoreplay.c:767 plugins/sudoers/visudo.c:700 +#, c-format +msgid "unable to open %s" +msgstr "ezin da %s ireki" + +#: plugins/sudoers/check.c:229 plugins/sudoers/iolog.c:199 +#, c-format +msgid "unable to write to %s" +msgstr "ezin da %s-(e)ra idatzi" + +#: plugins/sudoers/check.c:237 plugins/sudoers/check.c:475 +#: plugins/sudoers/check.c:525 plugins/sudoers/iolog.c:122 +#: plugins/sudoers/iolog.c:153 +#, c-format +msgid "unable to mkdir %s" +msgstr "ezin da mkdir %s egin" + +#: plugins/sudoers/check.c:370 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "barne errorea, expand_prompt() overflow" + +#: plugins/sudoers/check.c:426 +#, c-format +msgid "timestamp path too long: %s" +msgstr "" + +#: plugins/sudoers/check.c:454 plugins/sudoers/check.c:498 +#: plugins/sudoers/iolog.c:155 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s existitzen da baina ez da direktorio bat (0%o)" + +#: plugins/sudoers/check.c:457 plugins/sudoers/check.c:501 +#: plugins/sudoers/check.c:546 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s-(r)en jabea %u uid-a da, %u uid-a beharko luke" + +#: plugins/sudoers/check.c:462 plugins/sudoers/check.c:506 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "" + +#: plugins/sudoers/check.c:470 plugins/sudoers/check.c:514 +#: plugins/sudoers/check.c:582 plugins/sudoers/sudoers.c:925 +#: plugins/sudoers/visudo.c:284 plugins/sudoers/visudo.c:500 +#, c-format +msgid "unable to stat %s" +msgstr "ezin da stat egin %s-(r)engan" + +#: plugins/sudoers/check.c:540 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "" + +#: plugins/sudoers/check.c:552 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "" + +#: plugins/sudoers/check.c:606 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "" + +#: plugins/sudoers/check.c:652 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:659 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:713 plugins/sudoers/check.c:719 +#, c-format +msgid "unknown uid: %u" +msgstr "uid ezezaguna: %u" + +#: plugins/sudoers/check.c:716 plugins/sudoers/sudoers.c:736 +#: plugins/sudoers/sudoers.c:802 plugins/sudoers/sudoers.c:803 +#: plugins/sudoers/sudoers.c:1056 plugins/sudoers/sudoers.c:1057 +#: plugins/sudoers/testsudoers.c:200 plugins/sudoers/testsudoers.c:330 +#, c-format +msgid "unknown user: %s" +msgstr "erabiltzaile ezezaguna: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "root-ek sudo abiarizi lezake" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo-k EDITOR ingurune aldagaia erabiliko du" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in 'noexec_file'" +msgstr "" + +#: plugins/sudoers/def_data.c:247 +#, c-format +msgid "File containing dummy exec functions: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:251 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:255 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "" + +#: plugins/sudoers/def_data.c:259 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "" + +#: plugins/sudoers/def_data.c:263 +msgid "Allow users to set arbitrary environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:267 +msgid "Reset the environment to a default set of variables" +msgstr "" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to check for sanity:" +msgstr "" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to remove:" +msgstr "" + +#: plugins/sudoers/def_data.c:279 +msgid "Environment variables to preserve:" +msgstr "" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:295 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:299 +msgid "Allow sudo to prompt for a password even if it would be visisble" +msgstr "" + +#: plugins/sudoers/def_data.c:303 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "" + +#: plugins/sudoers/def_data.c:307 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "" + +#: plugins/sudoers/def_data.c:311 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "" + +#: plugins/sudoers/def_data.c:315 +msgid "Log user's input for the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:319 +msgid "Log the output of the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:323 +msgid "Compress I/O logs using zlib" +msgstr "Trinkotu S/E gertaerak zlib erabiliz" + +#: plugins/sudoers/def_data.c:327 +msgid "Always run commands in a pseudo-tty" +msgstr "" + +#: plugins/sudoers/def_data.c:331 +msgid "Plugin for non-Unix group support" +msgstr "" + +#: plugins/sudoers/def_data.c:335 +msgid "Directory in which to store input/output logs" +msgstr "" + +#: plugins/sudoers/def_data.c:339 +msgid "File in which to store the input/output log" +msgstr "" + +#: plugins/sudoers/def_data.c:343 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "" + +#: plugins/sudoers/def_data.c:347 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "" + +#: plugins/sudoers/defaults.c:197 +msgid "" +"Available options in a sudoers ``Defaults'' line:\n" +"\n" +msgstr "" + +#: plugins/sudoers/defaults.c:204 plugins/sudoers/defaults.c:215 +#, c-format +msgid "%s: %s\n" +msgstr "%s: %s\n" + +#: plugins/sudoers/defaults.c:211 +#, c-format +msgid "%s: %.*s\n" +msgstr "%s: %.*s\n" + +#: plugins/sudoers/defaults.c:241 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:249 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:279 plugins/sudoers/defaults.c:292 +#: plugins/sudoers/defaults.c:305 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:331 plugins/sudoers/defaults.c:351 +#: plugins/sudoers/defaults.c:361 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "`%s' balorea baliogabea da `%s' aukerarentzat" + +#: plugins/sudoers/defaults.c:252 plugins/sudoers/defaults.c:262 +#: plugins/sudoers/defaults.c:270 plugins/sudoers/defaults.c:287 +#: plugins/sudoers/defaults.c:300 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:326 plugins/sudoers/defaults.c:346 +#: plugins/sudoers/defaults.c:357 +#, c-format +msgid "no value specified for `%s'" +msgstr "ez da baliorik ezarri `%s'-(r)entzat" + +#: plugins/sudoers/defaults.c:275 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "" + +#: plugins/sudoers/defaults.c:337 +#, c-format +msgid "option `%s' does not take a value" +msgstr "" + +#: plugins/sudoers/env.c:259 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "" + +#: plugins/sudoers/env.c:289 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "" + +#: plugins/sudoers/env.c:694 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "" + +#: plugins/sudoers/find_path.c:68 plugins/sudoers/find_path.c:107 +#: plugins/sudoers/find_path.c:122 plugins/sudoers/iolog.c:124 +#: plugins/sudoers/sudoers.c:868 toke.l:663 toke.l:814 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: gram.y:103 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr "" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "" + +#: plugins/sudoers/interfaces.c:109 +msgid "Local IP address and netmask pairs:\n" +msgstr "" + +#: plugins/sudoers/iolog.c:176 plugins/sudoers/sudoers.c:946 +#, c-format +msgid "unable to read %s" +msgstr "ezin da %s irakurri" + +#: plugins/sudoers/iolog.c:179 +#, c-format +msgid "invalid sequence number %s" +msgstr "" + +#: plugins/sudoers/iolog.c:225 plugins/sudoers/iolog.c:228 +#: plugins/sudoers/iolog.c:478 plugins/sudoers/iolog.c:483 +#: plugins/sudoers/iolog.c:489 plugins/sudoers/iolog.c:497 +#: plugins/sudoers/iolog.c:505 plugins/sudoers/iolog.c:513 +#: plugins/sudoers/iolog.c:521 +#, c-format +msgid "unable to create %s" +msgstr "ezin da %s sortu" + +#: plugins/sudoers/iolog_path.c:245 plugins/sudoers/sudoers.c:361 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "" + +#: plugins/sudoers/ldap.c:363 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: port too large" + +#: plugins/sudoers/ldap.c:386 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: out of space expanding hostbuf" + +#: plugins/sudoers/ldap.c:415 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:444 +#, c-format +msgid "invalid uri: %s" +msgstr "baliogabeko uri-a: %s" + +#: plugins/sudoers/ldap.c:450 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "" + +#: plugins/sudoers/ldap.c:454 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "" + +#: plugins/sudoers/ldap.c:473 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:536 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:932 +#, c-format +msgid "unable to get GMT time" +msgstr "" + +#: plugins/sudoers/ldap.c:938 +#, c-format +msgid "unable to format timestamp" +msgstr "" + +#: plugins/sudoers/ldap.c:946 +#, c-format +msgid "unable to build time filter" +msgstr "" + +#: plugins/sudoers/ldap.c:1044 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "" + +#: plugins/sudoers/ldap.c:1539 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1541 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1588 +#, c-format +msgid " Order: %s\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1596 +#, c-format +msgid " Commands:\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1983 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:2014 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "" + +#: plugins/sudoers/ldap.c:2245 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "" + +#: plugins/sudoers/linux_audit.c:55 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: plugins/sudoers/linux_audit.c:79 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "" + +#: plugins/sudoers/linux_audit.c:88 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: plugins/sudoers/logging.c:193 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "" + +#: plugins/sudoers/logging.c:196 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "" + +#: plugins/sudoers/logging.c:295 +msgid "user NOT in sudoers" +msgstr "erabiltzailea ez dago sudoers-en" + +#: plugins/sudoers/logging.c:297 +msgid "user NOT authorized on host" +msgstr "erabiltzailea ez dago baimendutako ostalarian" + +#: plugins/sudoers/logging.c:299 +msgid "command not allowed" +msgstr "komandua ez dago baimenduta" + +#: plugins/sudoers/logging.c:309 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s ez dago sudoers fitxatzegian. Gertaeraren berri emango da.\n" + +#: plugins/sudoers/logging.c:312 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s ez dago baimenduta sudo abiarazteko %s-(e)n. Gertaeraren berri emango da.\n" + +#: plugins/sudoers/logging.c:316 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Barkatu, %s erabiltzaileak ez luke sudo abiariazi beharko %s-(e)n.\n" + +#: plugins/sudoers/logging.c:319 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Barkatu, %s erabiltzaileak ez du '%s%s%s' %s%s%s bezala exekutatzeko baimenik %s-(e)n.\n" + +#: plugins/sudoers/logging.c:454 +#, c-format +msgid "unable to fork" +msgstr "" + +#: plugins/sudoers/logging.c:461 plugins/sudoers/logging.c:518 +#, c-format +msgid "unable to fork: %m" +msgstr "" + +#: plugins/sudoers/logging.c:511 +#, c-format +msgid "unable to open pipe: %m" +msgstr "" + +#: plugins/sudoers/logging.c:530 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "" + +#: plugins/sudoers/logging.c:564 +#, c-format +msgid "unable to execute %s: %m" +msgstr "" + +#: plugins/sudoers/logging.c:774 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "" + +#: plugins/sudoers/parse.c:115 +#, c-format +msgid "parse error in %s near line %d" +msgstr "" + +#: plugins/sudoers/parse.c:369 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" + +#: plugins/sudoers/parse.c:371 +#, c-format +msgid " RunAsUsers: " +msgstr "" + +#: plugins/sudoers/parse.c:386 +#, c-format +msgid " RunAsGroups: " +msgstr "" + +#: plugins/sudoers/parse.c:395 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:244 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:252 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:288 plugins/sudoers/pwutil.c:297 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:511 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:519 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:548 plugins/sudoers/pwutil.c:557 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "" + +#: plugins/sudoers/set_perms.c:249 plugins/sudoers/set_perms.c:476 +#: plugins/sudoers/set_perms.c:710 +#, c-format +msgid "unable to change to sudoers gid" +msgstr "" + +#: plugins/sudoers/set_perms.c:290 plugins/sudoers/set_perms.c:514 +#: plugins/sudoers/set_perms.c:748 plugins/sudoers/set_perms.c:882 +msgid "too many processes" +msgstr "prozesu gehiegi" + +#: plugins/sudoers/set_perms.c:943 plugins/sudoers/set_perms.c:959 +msgid "unable to set runas group vector" +msgstr "" + +#: plugins/sudoers/set_perms.c:952 +msgid "unable to get runas group vector" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:217 +msgid "unable to reset group vector" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:223 +msgid "unable to get group vector" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:266 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:292 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:302 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:206 plugins/sudoers/sudoers.c:241 +#: plugins/sudoers/sudoers.c:876 +msgid "problem with defaults entries" +msgstr "" + +#: plugins/sudoers/sudoers.c:210 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "ezin da %s exekutatu: %s" + +#: plugins/sudoers/sudoers.c:311 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "" + +#: plugins/sudoers/sudoers.c:318 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "" + +#: plugins/sudoers/sudoers.c:407 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "data-zigiluaren jabea (%s): ez dago horrelako erabiltzailerik" + +#: plugins/sudoers/sudoers.c:423 +msgid "no tty" +msgstr "tty gabe" + +#: plugins/sudoers/sudoers.c:424 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "barkatu, tty bat behar duzu sudo abiarazteko" + +#: plugins/sudoers/sudoers.c:470 +msgid "No user or host" +msgstr "Ez dago erabiltzaile edo ostalaririk" + +#: plugins/sudoers/sudoers.c:484 plugins/sudoers/sudoers.c:505 +#: plugins/sudoers/sudoers.c:506 plugins/sudoers/sudoers.c:1413 +#: plugins/sudoers/sudoers.c:1414 +#, c-format +msgid "%s: command not found" +msgstr "%s: komandoa ez da aurkitu" + +#: plugins/sudoers/sudoers.c:486 plugins/sudoers/sudoers.c:502 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" + +#: plugins/sudoers/sudoers.c:491 +msgid "validation failure" +msgstr "balidazio hutsegitea" + +#: plugins/sudoers/sudoers.c:501 +msgid "command in current directory" +msgstr "" + +#: plugins/sudoers/sudoers.c:513 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "" + +#: plugins/sudoers/sudoers.c:860 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "" + +#: plugins/sudoers/sudoers.c:904 +#, c-format +msgid "fixed mode on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:908 +#, c-format +msgid "set group on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:911 +#, c-format +msgid "unable to set group on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:914 +#, c-format +msgid "unable to fix mode on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:927 +#, c-format +msgid "%s is not a regular file" +msgstr "" + +#: plugins/sudoers/sudoers.c:929 +#, c-format +msgid "%s is mode 0%o, should be 0%o" +msgstr "" + +#: plugins/sudoers/sudoers.c:933 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "" + +#: plugins/sudoers/sudoers.c:936 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "" + +#: plugins/sudoers/sudoers.c:980 +#, c-format +msgid "only root can use `-c %s'" +msgstr "soilik root-ek erabili dezake `-c %s'" + +#: plugins/sudoers/sudoers.c:990 +#, c-format +msgid "unknown login class: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1024 +#, c-format +msgid "unable to resolve host %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1076 plugins/sudoers/testsudoers.c:342 +#, c-format +msgid "unknown group: %s" +msgstr "talde ezezaguna: %s" + +#: plugins/sudoers/sudoers.c:1108 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1110 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1114 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Sudoers-en bidea: %s\n" + +#: plugins/sudoers/sudoers.c:1117 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "nsswitch-en bidea: %s\n" + +#: plugins/sudoers/sudoers.c:1119 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ldap.conf-en bidea: %s\n" + +#: plugins/sudoers/sudoers.c:1120 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ldap.secret-en bidea: %s\n" + +#: plugins/sudoers/sudoreplay.c:265 +#, c-format +msgid "invalid filter option: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:278 +#, c-format +msgid "invalid max wait: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:284 +#, c-format +msgid "invalid speed factor: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:287 plugins/sudoers/visudo.c:174 +#, c-format +msgid "%s version %s\n" +msgstr "%s bertsioa %s\n" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:316 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:341 +#, c-format +msgid "invalid log file %s" +msgstr "baliogabeko %s log fitxategia" + +#: plugins/sudoers/sudoreplay.c:343 +#, c-format +msgid "Replaying sudo session: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:383 +#, c-format +msgid "invalid timing file line: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:425 +#, c-format +msgid "writing to standard output" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:455 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:503 plugins/sudoers/sudoreplay.c:528 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:545 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:556 +#, c-format +msgid "unmatched ')' in expression" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:562 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:576 +#, c-format +msgid "%s requires an argument" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:580 +#, c-format +msgid "invalid regular expression: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:586 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:599 +#, c-format +msgid "unmatched '(' in expression" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:601 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:603 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:819 +#, c-format +msgid "invalid regex: %s" +msgstr "baliogabeko regex-a: %s" + +#: plugins/sudoers/sudoreplay.c:941 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:944 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:953 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:955 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/testsudoers.c:228 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "" + +#: plugins/sudoers/testsudoers.c:304 +msgid "\thost unmatched" +msgstr "" + +#: plugins/sudoers/testsudoers.c:307 +msgid "" +"\n" +"Command allowed" +msgstr "" + +#: plugins/sudoers/testsudoers.c:308 +msgid "" +"\n" +"Command denied" +msgstr "" + +#: plugins/sudoers/testsudoers.c:308 +msgid "" +"\n" +"Command unmatched" +msgstr "" + +#: toke.l:667 toke.l:793 toke.l:818 toke.l:904 plugins/sudoers/toke_util.c:111 +#: plugins/sudoers/toke_util.c:163 plugins/sudoers/toke_util.c:202 +msgid "unable to allocate memory" +msgstr "" + +#: toke.l:786 +msgid "too many levels of includes" +msgstr "include maila gehiegi" + +#: plugins/sudoers/toke_util.c:213 +msgid "fill_args: buffer overflow" +msgstr "fill_args: buffer overflow" + +#: plugins/sudoers/visudo.c:175 +#, c-format +msgid "%s grammar version %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:208 plugins/sudoers/auth/rfc1938.c:103 +#, c-format +msgid "you do not exist in the %s database" +msgstr "ez zara %s datubasean existitzen" + +#: plugins/sudoers/visudo.c:238 plugins/sudoers/visudo.c:470 +#, c-format +msgid "press return to edit %s: " +msgstr "sakatu intro %s editatzeko:" + +#: plugins/sudoers/visudo.c:300 plugins/sudoers/visudo.c:306 +#, c-format +msgid "write error" +msgstr "idazketa errorea" + +#: plugins/sudoers/visudo.c:360 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:365 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:371 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:394 +#, c-format +msgid "%s unchanged" +msgstr "%s aldatu gabea" + +#: plugins/sudoers/visudo.c:418 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "" + +#: plugins/sudoers/visudo.c:463 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "" + +#: plugins/sudoers/visudo.c:502 plugins/sudoers/visudo.c:511 +#, c-format +msgid "unable to set (uid, gid) of %s to (%d, %d)" +msgstr "" + +#: plugins/sudoers/visudo.c:506 plugins/sudoers/visudo.c:516 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "" + +#: plugins/sudoers/visudo.c:533 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "" + +#: plugins/sudoers/visudo.c:547 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:557 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:617 +msgid "What now? " +msgstr "Eta orain?" + +#: plugins/sudoers/visudo.c:631 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" + +#: plugins/sudoers/visudo.c:668 +#, c-format +msgid "unable to execute %s" +msgstr "ezin da %s exekutatu" + +#: plugins/sudoers/visudo.c:675 +#, c-format +msgid "unable to run %s" +msgstr "ezin da %s abiarazi" + +#: plugins/sudoers/visudo.c:706 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "" + +#: plugins/sudoers/visudo.c:718 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:721 +#, c-format +msgid "parse error in %s\n" +msgstr "" + +#: plugins/sudoers/visudo.c:723 +#, c-format +msgid "%s: parsed OK\n" +msgstr "" + +#: plugins/sudoers/visudo.c:737 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%d, %d)\n" +msgstr "" + +#: plugins/sudoers/visudo.c:744 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "" + +#: plugins/sudoers/visudo.c:783 +#, c-format +msgid "%s busy, try again later" +msgstr "%s okupatuta, saiatu berriz beranduago" + +#: plugins/sudoers/visudo.c:826 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "" + +#: plugins/sudoers/visudo.c:849 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "" + +#: plugins/sudoers/visudo.c:897 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "" + +#: plugins/sudoers/visudo.c:986 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:987 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:990 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:991 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1128 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "" + +#: plugins/sudoers/visudo.c:1185 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" + +#: plugins/sudoers/visudo.c:1187 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:64 +msgid "unable to begin bsd authentication" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:71 +msgid "invalid authentication type" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:79 +msgid "unable to setup authentication" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:59 +#, c-format +msgid "unable to read fwtk config" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:64 +#, c-format +msgid "unable to connect to authentication server" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:70 plugins/sudoers/auth/fwtk.c:93 +#: plugins/sudoers/auth/fwtk.c:126 +#, c-format +msgid "lost connection to authentication server" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:74 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:114 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:127 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:144 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:188 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:204 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:217 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:221 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:284 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:299 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:99 +msgid "unable to initialize PAM" +msgstr "ezin da PAM hasieratu" + +#: plugins/sudoers/auth/pam.c:142 +msgid "account validation failure, is your account locked?" +msgstr "" + +#: plugins/sudoers/auth/pam.c:146 +msgid "Account or password is expired, reset your password and try again" +msgstr "" + +#: plugins/sudoers/auth/pam.c:153 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:157 +msgid "Password expired, contact your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:161 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:176 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:296 +msgid "Password: " +msgstr "Pasahitza: " + +#: plugins/sudoers/auth/pam.c:297 +msgid "Password:" +msgstr "Pasahitza:" + +#: plugins/sudoers/auth/securid.c:82 plugins/sudoers/auth/securid5.c:106 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:115 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:119 plugins/sudoers/auth/securid5.c:169 +#, c-format +msgid "invalid username length for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:123 plugins/sudoers/auth/securid5.c:174 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:127 +#, c-format +msgid "SecurID communication failed" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:131 plugins/sudoers/auth/securid5.c:213 +#, c-format +msgid "unknown SecurID error" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:164 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "" + +#: plugins/sudoers/auth/sia.c:106 +msgid "unable to initialize SIA session" +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:124 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:134 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:243 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "pasahitz sartze saiakera oker %d" +msgstr[1] "%d pasahitz sartze saiakera oker" + +#: plugins/sudoers/auth/sudo_auth.c:335 +msgid "Authentication methods:" +msgstr "Autentikazio metodoak:" diff --git a/plugins/sudoers/po/fi.mo b/plugins/sudoers/po/fi.mo new file mode 100644 index 0000000..fab24cf Binary files /dev/null and b/plugins/sudoers/po/fi.mo differ diff --git a/plugins/sudoers/po/fi.po b/plugins/sudoers/po/fi.po new file mode 100644 index 0000000..e93b870 --- /dev/null +++ b/plugins/sudoers/po/fi.po @@ -0,0 +1,1801 @@ +# Finnish messages for sudoers. +# This file is put in the public domain. +# Copyright © 2011, 2012 Free Software Foundation, Inc. +# This file is distributed under the same license as the sudo package. +# Jorma Karvonen , 2011-2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 10:05+0200\n" +"Last-Translator: Jorma Karvonen \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s lähellä riviä %d <<<" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Alias ”%s” on jo määritelty" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "ei kyetä saamaan kirjautumisluokkaa käyttäjälle %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "ei kyetä aloittamaan bsd-todentamista" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "virheellinen todennustyyppi" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "ei kyetä asettamaan todentamista" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "ei kyetä lukemaan fwtk config -asetusta" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "ei kyetä yhdistämään todentamispalvelimelle" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "kadotettiin yhteys todentamispalvelimelle" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"todentamispalvelinvirhe:\n" +"%s" + +# Sana princ viittaa krb5_principal -määrittelyyn +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s: ei kyetä poistamaan valtuutetun (’%s’) jäsentämistä: %s" + +# Ensimmäinen parametri on auth name +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: ei kyetä jäsentämään todentamisnimeä ’%s’: %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: ei kyetä ratkaisemaan ccache-välimuistia: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: ei kyetä varaamaan valitsimia: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: ei kyetä hakemaan valtuustietoja: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: ei kyetä alustamaan ccache-välimuistia: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: ei kyetä tallentamaan valtuustietoja ccache-välimuistiin: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: ei kyetä hakemaan tietokoneen valtuutettua: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: Ei voida todentaa TGT-lippua! Mahdollinen hyökkäys!: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "ei kyetä alustamaan PAM:ia" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "tilikelpuutushäiriö, onko tilisi lukittu?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Tili tai salasana on vanhentunut, nollaa salasanasi tai yritä uudelleen" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Salasana vanhentunut, ota yhteyttä järjestelmän ylläpitäjään" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "Tili vanhentunut tai PAM-asetuksista puuttuu ”account”-lohko sudo-komennolle, ota yhteyttä järjestelmän ylläpitäjään" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "Salasana: " + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "Salasana:" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "ei ole olemassa %s-tietokannassa" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "epäonnistui ACE API -kirjaston alustamisessa" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "ei kyetä ottamaan yhteyttä SecurID-palvelimeen" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "Käyttäjätunniste lukittu SecurID-todennukselle" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "virheellinen käyttäjänimipituus kohteelle SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "virheellinen todentamiskäsittelijä kohteelle SecurID" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "SecurID-viestintä epäonnistui" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "tuntematon SecurID-virhe" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "virheellinen salasanakoodipituus kohteelle SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "ei kyetä alustamaan SIA-istuntoa" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "Virheellisiä todennusmenetelmiä käännetty sudo-ohjelmaan! Yksittäisiä ja ei-yksittäisiä todennuksia on ehkä sekoitettu keskenään." + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "Sudo-ohjelmaan ei ole käännetty todentamismenelmiä! Jos haluat kääntää pois todentamisen, käytä asetusvalitsinta --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d väärä salasana yritetty" +msgstr[1] "%d väärää salasanaa yritetty" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Todennusmenetelmät:" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: epäonnistui" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "Ei voitu määritellä audit-ehtoa" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid epäonnistui" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: epäonnistui" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: epäonnistui" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: epäonnistui" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32: epäonnistui" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "ei kyetä suorittamaan commit-toimintoa audit-tietueelle" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: epäonnistui" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: epäonnistui" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "kohteen %s suorittamiseen vaaditaan salasana" + +# Avaamisen kohde voi olla timestamp file, sudoers file tai pathbuf +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "ei kyetä avaamaan kohdetta %s" + +# Kirjoittamisen kohde voi olla timestamp file tai pathbuf +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "ei kyetä kirjoittamaan kohteeseen %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "ei kyetä suorittamaan käskyä mkdir %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "sisäinen virhe, expand_prompt()-ylivuoto" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "aikaleimapolku on liian pitkä: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s on olemassa, mutta ei ole hakemisto (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s on uid %u:n omistama, pitäisi olla uid %u:n omistama" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s on kirjoitettava ei-omistajalle (0%o), pitäisi olla tila 0700" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "ei kyetä kutsumaan funktiota stat %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s on olemassa, mutta ei ole tavallinen tiedosto (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s on kirjoitettava ei-omistajalle (0%o), pitäisi olla tila 0600" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "aikaleima liian kaukana tulevaisuudessa: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "ei kyetä poistamaan %s (%s), nollataan aika" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "ei kyetä nollaamaan %s ajaksi" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "tuntematon uid-käyttäjätunniste: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "tuntematon käyttäjä: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Syslog-apuneuvo, jos syslog-lokia käytetään kirjautumista varten: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Käytettävä syslog-prioriteetti, kun käyttäjä todennetaan onnistuneesti: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Käytettävä syslog-prioriteetti, kun käyttäjän todennus epäonnistui: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "Laita OPT-kehote omalle rivilleen" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Ohita ’.’ $PATH-asetuksessa" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Lähetä aina sähkopostia, kun sudo suoritetaan" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "Lähetä sähköpostia, jos käyttäjän todennus epäonnistuu" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "Lähetä sähköpostia, jos käyttäjä ei ole sudoers-määrittelyssä" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "Lähetä sähköpostia, jos käyttäjä ei ole tällä tietokoneella sudoers-määrittelyssä" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "Lähetä sähköpostia, jos käyttäjän ei sallita suorittaa komentoa" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "Käytä erillistä aikaleimaa jokaiselle käyttäjä/tty -yhdistelmälle" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Saarnaa ensimmäistä kertaa sudo-ohjelmaa käyttävälle" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Tiedosto, joka sisältää sudo-saarnan: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Vaadi käyttäjien todennus oletuksena" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Root voi suorittaa sudo-ohjelman" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "Kirjaa tietokonenimi (ei-syslog)lokitiedostoon" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "Kirjaa vuosi (ei-syslog)lokitiedostoon" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "Jos sudo-ohjelmaa kutsutaan ilman argumentteja, käynnistä käyttöjärjestelmäkuori" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Aseta $HOME-muuttujaksi kohdekäyttäjä kun käyttöjärjestelmäkuori käynnistetään valitsimella -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Aseta $HOME-muuttujaksi aina kohdekäyttäjän kotihakemisto" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "Salli jotain tietojenkeräystä hyödyllisten virheilmoitusten tarjoamiseksi" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "Vaadi täysin rakennettu tietokonenimi suoders-tiedostossa" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Solvaa käyttäjiä, kun he kirjoittavat väärän salasanan" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "Salli käyttäjien suorittaa sudo-ohjelma vain jos heillä on tty" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo noudattaa EDITOR-ympäristömuuttujaa" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Kysy root-käyttäjän salasana, ei käyttäjän" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Kysy runas_default-käyttäjän salasana, ei käyttäjän" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Kysy kohdekäyttäjän salasana, ei käyttäjän" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "Käytä oletuksia kohdekäyttäjän kirjautumisluokassa, jos siinä on yhtään" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Aseta LOGNAME- ja USER-ympäristömuuttujat" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "Aseta vain voimassa oleva uid-käyttäjätunniste kohdekäyttäjälle, ei oikeaa uid-tunnistetta" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "Älä alusta ryhmävektoria kohdekäyttäjän vastaavaan arvoon" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "Pituus, jossa pitkät lokitiedostorivit jaetaan seuraavalle riville (0 ei jaeta): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "Todennusaikaleiman aikavalvonta: %.1f minuuttia" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "Salasanakehotteen aikavalvonta: %.1f minuuttia" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Salasanayritysten lukumäärä: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Käytettävä umask-määrittely tai 0777 käytettäväksi käyttäjän umask-määrittelyksi: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Polku lokitiedostoon: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Polku sähköpostiohjelmaan: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Sähköpostiohjelman liput: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Osoite, johon sähköposti lähetetään: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Osoite, josta sähköposti lähetetään: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Sähköpostiviestin Aihe-rivi: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Virheellinen salasanaviesti: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "Polku todennusaikaleimahakemistoon: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "Todennusaikaleimahakemiston omistaja: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "Käyttäjät tässä ryhmässä on vapautettu salasana- ja PATH-vaatimuksista: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "Oletussalasanakehote: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "Jos asetettu, salasankehote korvaa järjestelmäkehotteen kaikissa tapauksissa." + +# Tämä on tekemisessä runas_default -määrittelyn kanssa +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "Oletuskäyttäjä suorittaa komennot käyttäjänä: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "Arvo, jolla korvataan käyttäjän $PATH-asetus: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "Visudo-editorin käyttämä polku: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "Kun vaaditaan salasana ’list’-näennäiskomennolle: %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "Kun vaaditaan salasana ’verify’-näennäiskomennolle: %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "Esilataa vale-exec-funktiot, jotka sisältyvät sudo_noexec-kirjastoon" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "Jos LDAP-hakemisto on ylhäällä, ohitammeko paikallisen sudoers-tiedoston" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "Tiedostokuvaajat >= %d suljetaan ennen komennon suoritusta" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "Jos asetettu, käyttäjä voi korvata ’closefrom’-arvon valitsimella -C" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "Salli käyttäjien asettaa mielivaltaisia ympäristömuuttujia" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "Nollaa ympäristö muuttujien oletusjoukoksi" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "Ympäristömuuttujat, joille tehdään järkevyystarkistus:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Poistettavat ympäristömuuttujat:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Säilytettävät ympäristömuuttujat:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "Uudessa turva-asiayhteydessä käytettävä SELinux-rooli: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "Uudessa turva-asiayhteydessä käytettävä SELinux-tyyppi: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "Polku sudo-kohtaiseen ympäristötiedostoon: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Locale-asetus, jota käytetään sudoers-jäsentämisessä: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "Salli sudo-ohjelman kysyä salasana vieläpä jos se olisi näkyvä" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "Tarjoa visuaalista palautetta salasanakehotteelta silloin kun on käyttäjäsyöte" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "Käyttää nopeampaa jokerimerkkien korvausta, joka on epätarkempi, mutta ei lue tiedostojärjestelmää" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "Sudoers umask korvaa käyttäjän umask-määrittelyn, vieläpä jos se on sallivampi" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "Kirjaa lokiin käyttäjän syöte suoritettavalle komennolle" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "Kirjaa lokiin suoritettavan komennon tuloste" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "Tiivistä siirräntälokit käyttäen zlib-ohjelmaa" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "Suorita aina komennot näennäis-tty:ssä" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "Lisäosa ei-Unix-ryhmätuelle: %s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "Hakemisto, johon tallennetaan syöte-/tulostelokit: %s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "Tiedosto, johon tallennetaan syöte-/tulosteloki: %s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "Lisää rivi utmp-/utmpx-tiedostoon, kun varataan pty" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "Aseta käyttäjäksi utmp-tiedostoon suorittava käyttäjä, ei kutsuva käyttäjä" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "tuntematon oletusrivi ”%s”" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "arvo ”%s” on virheellinen valitsimelle ”%s”" + +# parametrinä on variable +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "arvoa ei ole määritelty muuttujalle ”%s”" + +# Parametri on muuttuja +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "muuttujan ”%s” arvojen on alettava merkillä ’/’" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "valitsin ”%s” ei ota arvoa" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: rikkoutunut envp, pituus ei täsmää" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "ei kyetä varaamaan muistia" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "sisäinen virhe, sudo_setenv2()-ylivuoto" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "sisäinen virhe, sudo_setenv()-ylivuoto" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "seuraavia ympäristömuuttujia ei ole lupa asettaa: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s-omistajan on oltava uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s on vain omistajan kirjoitettava" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "ei kyetä kutsumaan funktiota dlopen %s: %s" + +# parametrina on path +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "ei kyetä löytämään symbolia ”group_plugin” polusta %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: yhteensopimaton ryhmälisäosan major-versio %d, odotettiin %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "Paikallinen ip-osoite ja verkkopeiteparit:\n" + +# Parametrinä on sudoers-tiedosto tai pathbuf +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "ei kyetä lukemaan kohdetta %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "virheellinen sarjanumero %s" + +# Parametrina on pathbuf +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "ei kyetä luomaan hakemistopolkua %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "ei kyetä asettamaan locale-asetukseksi ”%s”, käytetään ”C”" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: portti on liian suuri" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: hostbuf-puskuritila loppui" + +# URL on verkko-osoite, loogisesti URI on verkkoresurssi(osoite) +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "tukematon LDAP-verkkoresurssin tunnustyyppi: %s" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "virheellinen verkkoresurssin tunnus: %s" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "ei kyetä sekottamaan ldap:n ja ldap-kohteiden verkkoresurssitunnuksia" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "ei kyetä sekoittamaan ldap- ja starttl-kohteita" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: hostbuf-puskuritila loppui" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "ei kyetä alustamaan SSL-varmenne- ja -avaintietokantaa: %s" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "kohteessa %s TLS_CERT on asetettava käyttämään SSL:ää" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "ei kyetä saamaan GMT-aikaa" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "ei kyetä muotoilemaan aikaleimaa" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "ei kyetä rakentamaan aikasuodatinta" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "sudo_ldap_build_pass1-varaustäsmäämättömyys" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP-rooli: %s\n" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP-rooli: TUNTEMATON\n" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr " Järjestys: %s\n" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr " Komennot:\n" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "ei kyetä alustamaan kohdetta LDAP: %s" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "start_tls määritelty mutta LDAP-kirjastot ei tue funktiota ldap_start_tls_s() tai funktiota ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "virheellinen sudoOrder-attribuutti: %s" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "ei kyetä avaamaan audit-järjestelmää" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "sisäinen virhe, linux_audit_command()-ylivuoto" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "ei kyetä lähettämään audit-viestiä" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "ei kyetä avaamaan lokitiedostoa: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "ei kyetä lukitsemaan lokitiedostoa: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "käyttäjä EI ole sudoers-tiedostossa" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "käyttäjä ei ole varmennettu tietokoneella" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "komento ei ole sallittu" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "käyttäjä %s ei ole sudoers-tiedostossa. Tästä tapahtumasta ilmoitetaan.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "käyttäjä %s ei saa suorittaa komentoa sudo tietokoneella %s. Tästä tapahtumasta ilmoitetaan.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Käyttäjä %s ei voi suorittaa komentoa sudo tietokoneella %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Käyttäjän %s ei sallita suorittaa ’%s%s%s’ käyttäjänä %s%s%s tietokoneella %s.\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "ei kyetä kutsumaan fork-funktiota" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "ei kyetä kutsumaan fork-funktiota: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "ei kyetä avaamaan putkea: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "ei kyetä kutsumaan funktiota dup vakiosyötteellä: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "ei kyetä suorittamaan %s: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "sisäinen virhe: riittämättömästi tilaa lokiriville" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "jäsentämisvirhe tiedostossa %s lähellä riviä %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "jäsentämisvirhe tiedostossa %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Sudoers-rivi:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " SuoritaKäyttäjänä: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " SuoritaRyhmänä: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Komennot:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "ei kyetä laittamaan välimuistiin uid %u (%s) -käyttäjää, on jo siellä" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "ei kyetä laittamaan välimuistiin uid %u -käyttäjää, on jo siellä" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "ei kyetä laittamaan välimuistiin käyttäjää %s, on jo siellä" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "ei kyetä laittamaan välimuistiin gid %u (%s) -ryhmää, on jo siellä" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "ei kyetä laittamaan välimuistiin gid %u -ryhmää, on jo siellä" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "ei kyetä laittamaan välimuistiin ryhmää %s, on jo siellä" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "käyttöoikeuspinoylivuoto" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "käyttöoikeuspinovajaus" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "ei kyetä vaihtamaan runas gid -tunnisteeksi" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "ei kyetä vaihtamaan runas gid -tunnisteeksi" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "ei kyetä vaihtamaan sudoers gid-tunnisteeksi" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "liian monta prosessia" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "ei kyetä asettaan runas-ryhmävektoria" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "Täsmäävät Defaults-rivit kohteelle %s tällä tietokoneella:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "Runas- ja Command-kohtaiset oletukset kohteelle %s:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Käyttäjä %s voi suorittaa seuraavat komennot tällä tietokoneella:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Käyttäjä %s ei saa suorittaa komentoa sudo tietokoneella %s.\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "oletusrivien pulma" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "ei löytynyt kelvollisia sudoers-lähteitä, poistutaan" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "ei kyetä suorittamaan komentoa %s: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers määrittelee, että root ei saa suorittaa sudo-komentoa" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "ei käyttöoikeuksia valitsimelle -C" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "aikaleimaomistaja (%s): Tuntematon käyttäjä" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "ei tty:tä" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "sudo-komennon suorittamiseksi on oltava tty" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "Ei käyttäjä eikä tietokone" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: komentoa ei löytynyt" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"ohitetaan komento ”%s”, joka löytyi kohteesta ’.’\n" +"Käytä ”sudo ./%s”, jos tämä on ”%s”-komento, joka halutaan suorittaa." + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "kelpuutushäiriö" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "komento nykyisessä hakemistossa" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "ympäristöä ei ole lupa säilyttää" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "sisäinen virhe, runas_groups-ylivuoto" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "sisäinen virhe, set_cmnd()-ylivuoto" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s ei ole tavallinen tiedosto" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s on uid %u -käyttäjän omistama, pitäisi olla %u" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "%s on yleiskirjoitettava" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s on gid %u -ryhmän omistama, pitäisi olla %u" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "vain root-käyttäjä voi käyttää valitsinta ”-c %s”" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "tuntematon kirjautumisluokka: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "ei kyetä ratkaisemaan tietokonetta %s" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "tuntematon ryhmä: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Sudoers-menettelytapalisäosaversio %s\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Sudoers-tiedostokielioppiversio %d\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Sudoers-polku: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "nsswitch-polku: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ldap.conf-polku: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ldap.secret-polku: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "virheellinen suodatinvalitsin: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "virheellinen enimmäisodotusaika: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "virheellinen nopeustekijä: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s versio %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/ajoitus: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/ajoitus: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "Toistetaan sudo-istunto: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "Varoitus: pääteikkunasi on liian pieni tämän lokin toistamiseksi oikein.\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "Lokigeometria on %d x %d, pääteikkunasi geometria on %d x %d." + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "ei kyetä asettamaa tty:ta raakatilaan" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "virheellinen ajoitustiedostorivi: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "kirjoitetaan vakiotulosteeseen" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "monimerkityksellinen lauseke ”%s”" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "liian monta sulkumerkillistä lauseketta, enintään %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "täsmäämätön ’)’ lausekkeessa" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "tuntematon hakutermi ”%s”" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s vaatii argumentin" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "virheellinen säännöllinen lauseke: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "ei voitu jäsentää päivämäärää ”%s”" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "täsmäämätön ’(’ lausekkeessa" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "virheellinen jäljessä oleva ”or”" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "virheellinen jäljessä oleva ”!”" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "virheellinen säännöllinen lauseke: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "käyttö: %s [-h] [-d hakemisto] [-m enimmäisodotusaika] [-s nopeustekijä] ID-tunniste\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "käyttö: %s [-h] [-d hakemisto] -l [hakulauseke]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - toista sudo-istuntolokit\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"Valitsimet:\n" +" -d hakemisto määrittele istuntolokien hakemisto\n" +" -f suodatin määrittele, mitä siirräntätyyppiä näytetään\n" +" -h näytä opasteviesti ja poistu\n" +" -l [lauseke] luettele käytettävissä oleva istuntotunnisteet, jotka täsmäävät lausekkeeseen\n" +" -m maksimisodotusaika tapahtumien välien enimmäisodotusaika sekunteina\n" +" -s nopeustekijä nopeuta tai hidasta tulostusta\n" +" -V näytä versiotiedot ja poistu" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "sisäinen virhe, init_vars()-ylivuoto" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\ttietokone täsmäämätön" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Komento sallittu" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Komento kielletty" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"Täsmäämätön komento" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: puskuriylivuoto" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s kielioppiversio %d\n" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "muokkaa %s painamalla enter-painiketta: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "kirjoitusvirhe" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "ei kyetä kutsumaan stat-funktiota tilapäiselle tiedostolle (%s), %s ennallaan" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "nollapituinen tilapäinen tiedosto (%s), %s ennallaan" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "editori (%s) epäonnistui, %s ennallaan" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s ennallaan" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "ei kyetä avaamaan uudelleen tilapäistä tiedostoa (%s), %s ennallaan." + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "ei kyetä jäsentämään tilapäistä tiedostoa (%s), tuntematon virhe" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "sisäinen virhe, ei kyetä löytämään %s luettelosta!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "ei kyetä asettamaan kohdetta %s (uid, gid) arvoihin (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "ei kyetä muuttamaan %s-tilaa arvoon 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s ja %s eivät ole samassa tiedostojärjestelmässä, käytetään komentoa mv uudelleennimeämiseen" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "komento epäonnistui: ’%s %s %s’, %s ennallaan" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "virhe nimettäessä %s uudelleen, %s ennallaan" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "Mitä nyt?" + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Valitsimia ovat:\n" +" (e) muokkaa sudoers-tiedostoa uudelleen\n" +" (x) poistu tallentamatta sudoers-tiedoston muutoksia\n" +" (Q) poistu ja tallenna muutokset sudoers-tiedostoon (VAARA!)\n" + +# Parametri on path, mutta saattaa sisältää suoritettavan ohjelman +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "ei kyetä suorittamaan kohdetta %s" + +# Parametri on path, mutta saattaa sisältää suoritettavan ohjelman +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "ei kyetä suorittamaan kohdetta %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: väärä omistaja (uid, gid), pitäisi olla (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: väärät käyttöoikeudet, pitäisi olla tila 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "tiedoston %s jäsentäminen epäonnistui, tuntematon virhe" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "jäsentämisvirhe tiedostossa %s lähellä riviä %d\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "jäsentämisvirhe tiedostossa %s\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: jäsentäminen valmis\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s varattu, yritä myöhemmin uudelleen" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "määritelty editori (%s) ei ole olemassa" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "ei kyetä kutsumaan funktiota stat editori (%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "editoria ei löytynyt (editoripolku = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "Virhe: jakso kohteessa %s_Alias ”%s”" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "Varoitus: jakso kohteessa %s_Alias ”%s”" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "Virhe: %s_Alias ”%s” uudelleenviitattu, mutta ei määritelty" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "Varoitus: %s_Alias ”%s” uudelleenviitattu, mutta ei määritelty" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s: käyttämätön %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - muokkaa sudoers-tiedostoa turvallisesti\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"Valitsimet:\n" +" -c vain tarkistus -tila\n" +" -f sudoers määrittele sudoers-tiedoston sijainti\n" +" -h näytä opasteteksti ja poistu\n" +" -q vähemmän laveat (hiljaiset) syntaksivirheviestit\n" +" -s tiukka syntaksitarkistus\n" +" -V näytä versiotiedot ja poistu" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "liian monta include-tasoa" + +#~ msgid "invalid log file %s" +#~ msgstr "virheellinen lokitiedosto %s" + +# Parametri on sudoers file +#~ msgid "fixed mode on %s" +#~ msgstr "korjattu tila tiedostossa %s" + +# Parametri on suoders file +#~ msgid "set group on %s" +#~ msgstr "aseta ryhmä tiedostossa %s" + +# Parametri on sudoers file +#~ msgid "unable to set group on %s" +#~ msgstr "ei kyetä asettamaan ryhmää tiedostossa %s" + +#~ msgid "unable to fix mode on %s" +#~ msgstr "ei kyetä korjaamaan tilaa tiedostossa %s" + +#~ msgid "%s is mode 0%o, should be 0%o" +#~ msgstr "%s on tila 0%o, pitäisi olla 0%o" + +#~ msgid "File containing dummy exec functions: %s" +#~ msgstr "Tiedosto, joka sisältää vale-exec-funktioita: %s" + +#~ msgid "" +#~ "Available options in a sudoers ``Defaults'' line:\n" +#~ "\n" +#~ msgstr "" +#~ "Käytettävissä olevat valitsimet sudoers ’’Defaults’’ -rivillä:\n" +#~ "\n" + +#~ msgid "%s: %s\n" +#~ msgstr "%s: %s\n" + +#~ msgid "%s: %.*s\n" +#~ msgstr "%s: %.*s\n" + +#~ msgid "unable to get runas group vector" +#~ msgstr "ei kyetä hakemaan runas-ryhmävektoria" + +#~ msgid "unable to reset group vector" +#~ msgstr "ei kyetä nollaamaan ryhmävektoria" + +#~ msgid "unable to get group vector" +#~ msgstr "ei kyetä hakemaan ryhmävektoria" + +#~ msgid "%s: %s_Alias `%s' references self" +#~ msgstr "%s: %s_Alias ”%s” viittaa itseensä" + +#~ msgid "unable to parse temporary file (%s), unknown error" +#~ msgstr "ei kyetä jäsentämään tilapäistä tiedostoa (%s), tuntematon virhe" diff --git a/plugins/sudoers/po/hr.mo b/plugins/sudoers/po/hr.mo new file mode 100644 index 0000000..c78283e Binary files /dev/null and b/plugins/sudoers/po/hr.mo differ diff --git a/plugins/sudoers/po/hr.po b/plugins/sudoers/po/hr.po new file mode 100644 index 0000000..9f32d54 --- /dev/null +++ b/plugins/sudoers/po/hr.po @@ -0,0 +1,1731 @@ +# Translation of sudoers to Croatian. +# This file is put in the public domain. +# Tomislav Krznar , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-13 16:21-0400\n" +"PO-Revision-Date: 2012-04-18 01:56+0200\n" +"Last-Translator: Tomislav Krznar \n" +"Language-Team: Croatian \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Alias „%s” je već definiran" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: nije uspio" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "Ne mogu odrediti uvjet revizije" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid nije uspio" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: nije uspio" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: nije uspio" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: nije uspio" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32: nije uspio" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "ne mogu poslati zapis revizije" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: nije uspio" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: nije uspio" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "žao mi je, potrebna je lozinka za pokretanje %s" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "ne mogu otvoriti %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "ne mogu pisati u %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "ne mogu napraviti direktorij %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "interna greÅ¡ka, expand_prompt() preljev" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "putanja vremenske oznake predugačka: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s postoji, ali nije direktorij (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "vlasnik %s je uid %u, treba biti uid %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "nevlasnici imaju dozvolu za pisanje u %s (0%o), treba biti mod 0700" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "ne mogu izvrÅ¡iti stat %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s postoji, ali nije obična datoteka (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "nevlasnici imaju dozvolu za pisanje u %s (0%o), treba biti mod 0600" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "vremenska oznaka predaleko u budućnosti: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "ne mogu ukloniti %s (%s), vratit ću na početnu epohu" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "ne mogu vratiti %s na početnu epohu" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "nepoznat uid: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "nepoznat korisnik: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Syslog jedinica ako se koristi syslog za zapisivanje dnevnika: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Syslog prioritet koji se koristi pri uspjeÅ¡noj autentifikaciji korisnika: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Syslog prioritet koji se koristi pri neuspjeÅ¡noj autentifikaciji korisnika: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "Postavi OTP upit u vlastiti redak" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Zanemari „.” u $PATH" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Uvijek poÅ¡alji poÅ¡tu kad se pokrene sudo" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "PoÅ¡alji poÅ¡tu ako autentifikacija korisnika nije uspjela" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "PoÅ¡alji poÅ¡tu ako korisnik nije u sudoers" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "PoÅ¡alji poÅ¡tu ako korisnik nije u sudoers na ovom računalu" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "PoÅ¡alji poÅ¡tu ako korisnik nema dozvolu za pokretanje naredbe" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "Koristi posebnu vremensku oznaku za svaku kombinaciju korisnik/terminal" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Održi lekciju korisniku kad prvi put pokrene sudo" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Datoteka koja sadrži sudo lekciju: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Uobičajeno traži autentifikaciju korisnika" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Root može pokrenuti sudo" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "ZapiÅ¡i ime računala u (ne-syslog) dnevničku datoteku" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "ZapiÅ¡i godinu u (ne-syslog) dnevničku datoteku" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "Ako se sudo pozove bez argumenata, pokreni ljusku" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Postavi $HOME na početni direktorij odrediÅ¡nog korisnika pri pokretanju ljuske sa -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Uvijek postavi $HOME na početni direktorij odrediÅ¡nog korisnika" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "Dozvoli prikupljanje nekih informacija za ispis korisnih poruka greÅ¡aka" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "Traži potpuno kvalificirana imena računala u datoteci sudoers" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Uvrijedi korisnika kad upiÅ¡e netočnu lozinku" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "Dozvoli korisniku pokretanje sudo samo ako ima tty" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo će poÅ¡tivati varijablu okoline EDITOR" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Zatraži lozinku administratora umjesto korisnika" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Zatraži lozinku runas_default korisnika umjesto trenutnog" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Zatraži lozinku odrediÅ¡nog korisnika umjesto trenutnog" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "Primijeni zadane postavke u razredu prijave odrediÅ¡nog korisnika ako postoje" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Postavi varijable okoline LOGNAME i USER" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "Postavi samo efektivni uid na onaj odrediÅ¡nog korisnika umjesto stvarnog uid-a" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "Ne inicijaliziraj grupni vektor u onaj odrediÅ¡nog korisnika" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "Duljina prelamanja redaka dnevničke datoteke (0 isključuje): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "Istek vremenske oznake autentifikacije: %.1f minuta" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "Istek traženja lozinke: %.1f minuta" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Broj pokuÅ¡aja unosa lozinke: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Umask za koriÅ¡tenje ili 0777 za korisničku: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Putanja do dnevničke datoteke: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Putanja do programa poÅ¡te: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Zastavice za program poÅ¡te: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Adresa na koju se Å¡alje poÅ¡ta: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Adresa s koje se Å¡alje poÅ¡ta: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Predmet poruka poÅ¡te: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Neispravna poruka lozinke: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "Putanja do direktorija vremenske oznake autentifikacije: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "Vlasnik direktorija vremenske oznake autentifikacije: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "Korisnici u ovoj grupi su izuzeti od traženja lozinke i PATH zahtjeva: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "Uobičajeno traženje lozinke: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "Ako je postavljen, passprompt će zaobići sustavski u svim slučajevima." + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "Zadani korisnik za pokretanje naredbi: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "Vrijednost za zaobilaženje korisničke $PATH: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "Putanja do uređivača koji će koristiti visudo: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "Kada tražiti lozinku za pseudonaredbu „list”: %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "Kada tražiti lozinku za pseudonaredbu „verify”: %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "Prethodno učitaj prividne izvrÅ¡ne funkcije sadržane u biblioteci sudo_noexec" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "Ako je LDAP direktorij aktivan, zanemaruje li se lokalna datoteka sudoers" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "Opisnici datoteka >= %d će se zatvoriti prije izvrÅ¡avanja naredbe" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "Ako je postavljen, korisnici mogu zaobići vrijednost „closeform” opcijom -C" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "Dozvoli korisnicima postavljanje proizvoljnih varijabli okoline" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "Vrati okolinu u početni zadani skup varijabli" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "Varijable okoline čija će se ispravnost provjeriti:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Varijable okoline za uklanjanje:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Varijable okoline za očuvanje:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "SELinux uloga za koriÅ¡tenje u novom sigurnosnom kontekstu: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "SELinux vrsta za koriÅ¡tenje u novom sigurnosnom kontekstu: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "Putanja do datoteke okoline karakteristične za sudo: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Lokal za koriÅ¡tenje pri obradi sudoers: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "Dozvoli da sudo traži lozinku čak i ako će biti vidljiva" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "Prikaži vizualne povratne informacije pri traženju lozinke kad postoji korisnički unos" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "Koristi bržu usporedbu uzoraka koja je nepreciznija, ali ne pristupa datotečnom sustavu" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "Umask naveden u sudoers će zaobići korisnički, čak i ako dozvoljava viÅ¡e" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "ZapiÅ¡i korisnički unos za pokrenute naredbe" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "ZapiÅ¡i izlaz pokrenute naredbe" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "Komprimiraj U/I zapise koriÅ¡tenjem zlib" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "Uvijek pokreni naredbe u pseudoterminalu" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "Priključak za podrÅ¡ku za ne-Unix grupe: %s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "Direktorij za spremanje ulazno/izlaznih dnevnika: %s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "Datoteka za spremanje ulazno/izlaznog dnevnika: %s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "Dodaj stavku u utmp/utmpx datoteku pri alokaciji pseudoterminala" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "Postavi korisnika u utmp u „pokreni kao” korisnika umjesto pozivatelja" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "nepoznata stavka zadanih vrijednosti „%s”" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "vrijednost „%s” nije ispravna za opciju „%s”" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "nije navedena vrijednost za „%s”" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "vrijednost za „%s” mora početi s „/”" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "opcija „%s” ne prihvaća vrijednost" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: oÅ¡tećen envp, duljina ne odgovara" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 toke.l:682 toke.l:812 +#: toke.l:870 toke.l:966 plugins/sudoers/toke_util.c:113 +#: plugins/sudoers/toke_util.c:167 plugins/sudoers/toke_util.c:207 +#, c-format +msgid "unable to allocate memory" +msgstr "ne mogu alocirati memoriju" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "interna greÅ¡ka, sudo_setenv2() preljev" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "interna greÅ¡ka, sudo_setenv() preljev" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "žao mi je, nemate dozvolu za postavljanje sljedećih varijabli okoline: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 toke.l:678 +#: toke.l:866 plugins/sudoers/sudoers.c:950 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s kod retka %d <<<" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "vlasnik %s mora biti uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "samo vlasnik smije imati dozvole za pisanje %s" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "ne mogu izvrÅ¡iti dlopen %s: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "ne mogu pronaći simbol „group_plugin” u %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: nekompatibilna glavna inačica grupnog priključka %d, očekujem %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "Parovi lokalnih IP adresa i mrežnih maski:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "ne mogu čitati %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "neispravan broj niza %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "ne mogu napraviti %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "ne mogu postaviti lokal u „%s”, koristim „C”" + +#: plugins/sudoers/ldap.c:374 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: port je prevelik" + +#: plugins/sudoers/ldap.c:397 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: nema dovoljno prostora za proÅ¡irenje međuspremnika računala" + +#: plugins/sudoers/ldap.c:427 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "nepodržana vrsta LDAP uri-ja: %s" + +#: plugins/sudoers/ldap.c:456 +#, c-format +msgid "invalid uri: %s" +msgstr "neispravan uri: %s" + +#: plugins/sudoers/ldap.c:462 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "ne mogu mijeÅ¡ati ldap i ldaps URI-je" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "ne mogu mijeÅ¡ati ldaps i starttls" + +#: plugins/sudoers/ldap.c:485 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: nema dovoljno prostora za izgradnju međuspremnika računala" + +#: plugins/sudoers/ldap.c:550 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "ne mogu inicijalizirati SSL certifikat i bazu podataka ključeva: %s" + +#: plugins/sudoers/ldap.c:958 +#, c-format +msgid "unable to get GMT time" +msgstr "ne mogu dohvatiti GMT vrijeme" + +#: plugins/sudoers/ldap.c:964 +#, c-format +msgid "unable to format timestamp" +msgstr "ne mogu oblikovati vremensku oznaku" + +#: plugins/sudoers/ldap.c:972 +#, c-format +msgid "unable to build time filter" +msgstr "ne mogu izgraditi filtar vremena" + +#: plugins/sudoers/ldap.c:1187 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "neodgovarajuća sudo_ldap_build_pass1 alokacija" + +#: plugins/sudoers/ldap.c:1707 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP uloga: %s\n" + +#: plugins/sudoers/ldap.c:1709 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP uloga: NEPOZNATA\n" + +#: plugins/sudoers/ldap.c:1756 +#, c-format +msgid " Order: %s\n" +msgstr " Redoslijed: %s\n" + +#: plugins/sudoers/ldap.c:1764 +#, c-format +msgid " Commands:\n" +msgstr " Naredbe:\n" + +#: plugins/sudoers/ldap.c:2156 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "ne mogu inicijalizirati LDAP: %s" + +#: plugins/sudoers/ldap.c:2187 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "naveden je start_tls, ali LDAP biblioteke ne podržavaju ldap_start_tls_s() ili ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2423 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "neispravno sudoOrder svojstvo: %s" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "previÅ¡e razina uključivanja" + +#: toke.l:829 plugins/sudoers/sudoers.c:1004 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "vlasnik %s je uid %u, treba biti %u" + +#: toke.l:836 plugins/sudoers/sudoers.c:1008 +#, c-format +msgid "%s is world writable" +msgstr "%s ima dozvole za pisanje svih korisnika" + +#: toke.l:841 plugins/sudoers/sudoers.c:1011 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "vlasnik %s je gid %u, treba biti %u" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "ne mogu otvoriti sustav revizije" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "interna greÅ¡ka, linux_audit_command() preljev" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "ne mogu poslati poruku revizije" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "ne mogu otvoriti dnevičku datoteku: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "ne mogu zaključati dnevničku datoteku: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "korisnik NIJE u sudoers" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "korisnik NIJE ovlaÅ¡ten na računalu" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "naredba nije dozvoljena" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s nije u datoteci sudoers. Ovaj će incident biti prijavljen.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "Korisniku %s nije dozvoljeno pokrenuti sudo na %s. Ovaj će incident biti prijavljen.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Žao mi je, korisnik %s ne može pokrenuti sudo na %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Žao mi je, korisniku %s nije dozvoljeno izvrÅ¡iti „%s%s%s” kao %s%s%s na %s.\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "ne mogu razdvojiti" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "ne mogu razdvojiti: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "ne mogu otvoriti cjevovod: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "ne mogu izvrÅ¡iti dup stdin: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "ne mogu izvrÅ¡iti %s: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "interna greÅ¡ka: nema dovoljno prostora za redak dnevnika" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "greÅ¡ka analize u %s kod retka %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "greÅ¡ka analize u %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Sudoers stavka:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " PokreniKaoKorisnici: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " PokreniKaoGrupe: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Naredbe:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "ne mogu staviti uid %u (%s) u spremnik, već postoji" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "ne mogu staviti uid %u u spremnik, već postoji" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "ne mogu staviti korisnika %s u spremnik, već postoji" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "ne mogu staviti gid %u (%s) u spremnik, već postoji" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "ne mogu staviti gid %u u spremnik, već postoji" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "ne mogu staviti grupu %s u spremnik, već postoji" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "preljev trajnog stoga" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "podljev trajnog stoga" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "ne mogu promijeniti u „pokreni kao” gid" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "ne mogu promijeniti u „pokreni kao” uid" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "ne mogu promijeniti u sudoers gid" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "previÅ¡e procesa" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "ne mogu postaviti „pokreni kao” grupni vektor" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "Spajam stavke zadanih vrijednosti za %s na ovom računalu:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "Zadane vrijednosti „pokreni kao” i specifične za naredbe za %s:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Korisnik %s može pokrenuti sljedeće naredbe na ovom računalu:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Korisniku %s nije dozvoljeno pokrenuti sudo na %s.\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "problem sa stavkama zadanih vrijednosti" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "nisu pronađeni ispravni sudoers izvori, izlazim" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "ne mogu izvrÅ¡iti %s: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers navodi da root ne može koristiti sudo" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "nemate dozvolu za koriÅ¡tenje opcije -C" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "vlasnik vremenske oznake (%s): Nema takvog korisnika" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "nema terminala" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "žao mi je, morate imati terminal za pokretanje sudo" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "Nema korisnika ili računala" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: naredba nije pronađena" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"zanemarujem „%s” pronađen u „.”\n" +"Koristite „sudo ./%s” ako je ovo „%s” koji želite pokrenuti." + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "provjera nije uspjela" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "naredba u trenutnom direktoriju" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "žao mi je, nemate dozvolu za očuvanje okoline" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "interna greÅ¡ka, runas_groups preljev" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "interna greÅ¡ka, set_cmnd() preljev" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s nije obična datoteka" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "samo root smije koristiti „-c %s”" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "nepoznat razred prijave: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "ne mogu pronaći računalo %s" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "nepoznata grupa: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Inačica sudoers priključka police %s\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Inačica sudoers gramatike datoteke %d\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Sudoers putanja: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "nsswitch putanja: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ldap.conf putanja: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ldap.secret putanja: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "neispravna opcija filtra: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "neispravno najveće čekanje: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "neispravni faktor brzine: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s inačica %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/vrijeme: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/vrijeme: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "Prikazujem sudo sjednicu: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "Upozorenje: vaÅ¡ terminal je premalen za ispravno prikazivanje dnevnika.\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "Veličina dnevnika je %d x %d, a veličina vaÅ¡eg terminala %d x %d." + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "ne mogu postaviti terminal u sirovi način" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "neispravan redak datoteke mjerenja vremena: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "ispisujem na standardni izlaz" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "viÅ¡eznačni izraz „%s”" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "previÅ¡e izraza u zagradama, najviÅ¡e %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "nesparena „)” u izrazu" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "nepoznat pojam pretrage „%s”" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s zahtijeva argument" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "neispravan regularni izraz: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "ne mogu analizirati datum „%s”" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "nesparena „(” u izrazu" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "nedozvoljeni „or” na kraju" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "nedozvoljeni „!” na kraju" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "neispravni regularni izraz: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "uporaba: %s [-h] [-d direktorij] [-m max_čekanje] [-s faktor_brzine] ID\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "uporaba: %s [-h] [-d direktorij] -l [izraz pretrage]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - prikaži dnevnike sudo sjednica\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"Opcije:\n" +" -d direktorij navedi direktorij za dnevnike sjednica\n" +" -f filtar navedi U/I vrste za prikaz\n" +" -h prikaži poruku pomoći i izađi\n" +" -l [izraz] prikaži dostupne identifikatore sjednica koje\n" +" odgovaraju izrazu\n" +" -m max_čekanje najveći broj sekundi za čekanje između događaja\n" +" -s faktor_brzine ubrzaj ili uspori ispis\n" +" -V prikaži informacije o inačici i izađi" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "interna greÅ¡ka, init_vars() preljev" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\tračunalo nije pronađeno" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Naredba dozvoljena" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Naredba zabranjena" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"Naredba nije pronađena" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: preljev međuspremnika" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s inačica gramatike %d\n" + +#: plugins/sudoers/visudo.c:220 plugins/sudoers/auth/rfc1938.c:104 +#, c-format +msgid "you do not exist in the %s database" +msgstr "niste navedeni u %s bazi podataka" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "pritisnite return za uređivanje %s: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "greÅ¡ka pisanja" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "na mogu izvrÅ¡iti stat privremene datoteke (%s), %s nepromijenjen" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "privremena datoteka duljine nula (%s), %s nepromijenjen" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "uređivač (%s) nije uspio, %s nepromijenjen" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s nepromijenjen" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "ne mogu ponovo otvoriti privremenu datoteku (%s), %s nepromijenjen." + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "ne mogu analizirati privremenu datoteku (%s), nepoznata greÅ¡ka" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "interna greÅ¡ka, ne mogu pronaći %s na popisu!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "na mogu postaviti (uid, gid) od %s na (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "ne mogu promijeniti mod od %s u 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s i %s nisu na istom datotečnom sustavu, koristim mv za preimenovanje" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "naredba nije uspjela: „%s %s %s”, %s nepromijenjen" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "greÅ¡ka preimenovanja %s, %s nepromijenjen" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "Å to sada? " + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Opcije su:\n" +" (e) ponovo uredi datoteku sudoers\n" +" (x) izađi bez spremanja promjena u datoteku sudoers\n" +" (Q) izađi i spremi promjene u datoteku sudoers (OPASNO!)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "ne mogu izvrÅ¡iti %s" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "ne mogu pokrenuti %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: krivi vlasnički (uid, gid), treba biti (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: neispravne dozvole, treba biti mod 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "nisam uspio analizirati %s datoteku, nepoznata greÅ¡ka" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "greÅ¡ka analize u %s kod retka %d\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "greÅ¡ka analize u %s\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: analiza u redu\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s je zauzet, pokuÅ¡ajte ponovo kasnije" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "navedeni uređivač (%s) ne postoji" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "ne mogu odrediti stanje uređivača (%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "nije pronađen uređivač (putanja uređivača = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "GreÅ¡ka: petlja u %s_Alias „%s”" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "Upozorenje: petlja u %s_Alias „%s”" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "GreÅ¡ka: %s_Alias „%s” je referenciran, ali nije definiran" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "Upozorenje: %s_Alias „%s” je referenciran, ali nije definiran" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s: nekoriÅ¡teni %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - sigurno uređivanje datoteke sudoers\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"Opcije:\n" +" -c način samo za provjeravanje\n" +" -f sudoers navedi položaj datoteke sudoers\n" +" -h prikaži poruku pomoći i izađi\n" +" -q manje opÅ¡irne (tihe) poruke sintaksnih greÅ¡aka\n" +" -s strogo provjeravanje sintakse\n" +" -V prikaži informacije o inačici i izađi" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "ne mogu dobiti razred prijave korisnika %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "ne mogu započeti bsd autentifikaciju" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "neispravna vrsta autentifikacije" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "ne mogu postaviti autentifikaciju" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "ne mogu čitati fwtk konfiguraciju" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "ne mogu se spojiti na autentifikacijski poslužitelj" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "izgubljena veza na autentifikacijski poslužitelj" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"greÅ¡ka autentifikacijskog poslužitelja:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s: ne mogu ukloniti analizu upravitelja („%s”): %s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: ne mogu analizirati „%s”: %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: ne mogu pronaći ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: ne mogu alocirati opcije: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: ne mogu dobiti vjerodajnice: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: ne mogu inicijalizirati ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: ne mogu spremiti vjerodajnicu u ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: ne mogu dobiti upravitelja računala: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: Ne mogu provjeriti TGT! Moguć napad!: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "ne mogu inicijalizirati PAM" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "potvrđivanje računa nije uspjelo, je li vaÅ¡ račun zaključan?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Račun ili lozinka su istekli, vratite izvornu lozinku i pokuÅ¡ajte ponovo" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Lozinka je istekla, javite vaÅ¡em administratoru sustava" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "Račun je istekao ili PAM konfiguracija nema odjeljak „account” za sudo, javite vaÅ¡em administratoru sustava" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:330 +msgid "Password: " +msgstr "Lozinka: " + +#: plugins/sudoers/auth/pam.c:331 +msgid "Password:" +msgstr "Lozinka:" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "nisam uspio inicijalizirati ACE API biblioteku" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "ne mogu uspostaviti vezu s SecurID poslužiteljem" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "Korisnički ID zaključan za SecurID autentifikaciju" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "neispravna duljina korisničkog imena za SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "neispravni postupak autentifikacije za SecurID" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "SecurID komunikacija nije uspjela" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "nepoznata SecurID greÅ¡ka" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "neispravna duljina lozinke za SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "ne mogu inicijalizirati SIA sjednicu" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "Neispravne autentifikacijske metode kompajlirane u sudo! Možete mijeÅ¡ati samostalne i nesamostalne autentifikacije." + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "Nema autentifikacijskih metoda kompajliranih u sudo! Ako želite isključiti autentifikaciju, koristite konfiguracijsku opciju --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d netočan pokuÅ¡aj unosa lozinke" +msgstr[1] "%d netočna pokuÅ¡aja unosa lozinke" +msgstr[2] "%d netočnih pokuÅ¡aja unosa lozinke" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Metode autentifikacije:" diff --git a/plugins/sudoers/po/ja.mo b/plugins/sudoers/po/ja.mo new file mode 100644 index 0000000..b545b8b Binary files /dev/null and b/plugins/sudoers/po/ja.mo differ diff --git a/plugins/sudoers/po/ja.po b/plugins/sudoers/po/ja.po new file mode 100644 index 0000000..a40b4c9 --- /dev/null +++ b/plugins/sudoers/po/ja.po @@ -0,0 +1,1757 @@ +# Japanese messages for sudoers +# This file is put in the public domain. +# Yasuaki Taniguchi , 2011. +# Takeshi Hamasaki , 2012. +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-30 16:10+0900\n" +"Last-Translator: Takeshi Hamasaki \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Poedit-Basepath: /factory/ja-po/sudoers/sudo-1.8.5rc3\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s (%d行付近) <<<" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "別名 `%s' はすでに定義されています" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "ユーザー%s のログインクラスを得ることができません" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "BSD 認証を開始できません" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "無効な認証タイプです" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "認証をセットアップできません" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "fwtk 設定を読み込めません" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "認証サーバーに接続できません" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "認証サーバーへの接続が失われました" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"認証サーバーエラーです:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s: princ ('%s') を符号化できません: %s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: '%s' を構文解析できません: %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: 資格情報キャッシュ (ccache) を解決できません: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: オプションを設定できません: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: 資格情報を取得できません: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: 資格情報キャッシュ (ccache) を初期化できません: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: 資格情報を資格情報キャッシュ (ccache) 内に保存できません: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: ホストプリンシパルを取得できません: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: TGT を検証できません! おそらく攻撃です!: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "PAM を初期化できません" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "アカウントの有効性検証に失敗しました。あなたのアカウントはロックされていませんか?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "アカウントまたはパスワードが期限切れです。パスワードをリセットして再試行してください" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "パスワードが期限切れです。システム管理者に連絡してください" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "アカウントの期限切れ、または sudo 用の PAM 設定に \"account\" セクションがありません。システム管理者に連絡してください" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "パスワード: " + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "パスワード:" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "あなたは %s データベース内に存在しません" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "ACE API ライブラリの初期化に失敗しました" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "SecurID サーバーに接続できません" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "SecurID 認証のユーザーIDがロックされています" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "SecurID 用のユーザー名の長さが無効です" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "SecurID 用の認証ハンドルが無効です" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "SecurID 通信に失敗しました" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "不明な SecurID エラーです" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "SecurID 用のパスコード長が無効です" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "SIA セッションを初期化できません" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "無効な認証方法が sudo のコンパイル時に組み込まれています! スタンドアローンと非スタンドアローン認証を組み合わせているようです。" + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "認証方法が sudo のコンパイル時に組み込まれていません! 認証を無効にする場合には、configure オプションで --disable-authentication を指定してください。" + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d 回パスワード試行を間違えました" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "認証方法:" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: 失敗しました" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "監査条件を決定できませんでした" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid に失敗しました" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: 失敗しました" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: 失敗しました" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: 失敗しました" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32: 失敗しました" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "監査レコードをコミットできません" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: 失敗しました" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: 失敗しました" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "%s を実行するにはパスワードが必要です。すみません" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "%s を開けません" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "%s へ書き込むことができません" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "ディレクトリ %s を作成できません" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "内部エラー、expand_prompt() がオーバーフローしました" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "タイムスタンプ用パスが長すぎます: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s が存在しますがディレクトリではありません (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s はユーザーID (uid) %u によって所有されています。これはユーザーID %u であるべきです" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s は所有者以外でも書き込み可能 (0%o) です。アクセス権限のモードは 0700 であるべきです" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "%s の状態取得 (stat) ができません" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s が存在しますが通常ファイル (0%o) ではありません" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s は所有者以外でも書き込み可能 (0%o) です。アクセス権限のモードは 0600 であるべきです" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "タイムスタンプが遠すぎる将来になっています: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "%s (%s) を削除できません。エポックにリセットします" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "%s をエポックにリセットできません" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "不明なユーザーID (uid) です: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "不明なユーザーです: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "ログ記録時に syslog を使用する場合の syslog facility: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "ログ記録時に syslog を使用する場合の syslog priority: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "ユーザー認証に失敗したと時に使用される syslog priority: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "ワンタイムパスワード入力要求をそれのみの行に表示します" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "$PATH 内にある '.' を無視します" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "sudo を実行した時に、常にメールを送信します" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "ユーザー認証に失敗した場合にメールを送信します" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "ユーザー他 sudoers 内に存在しない場合にメールを送信します" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "ユーザーがこのホスト用の sudoers 内に存在しない場合にメールを送信します" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "ユーザーが許可されていないコマンドを実行しようとした場合にメールを送信します" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "ユーザー/tty の組み合わせごとに分離したタイムスタンプを使用します" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "ユーザーが最初に sudo を実行した時に講義を行う" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "sudo の講義が含まれているファイル: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "デフォルトでユーザーが認証されていることを必要とします" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "root が sudo を実行するかもしれません" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr " ログファイル (syslog 以外) に記録する時にホスト名を含めます" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "ログファイル (syslog 以外) に記録する時に年情報を含めます" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "sudo を引数無しで起動した場合、シェルを開始します" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "シェルを -s で開始した時に $HOME を変更後のユーザーのホームディレクトリに設定します" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "$HOME を常に変更後のユーザーのホームディレクトリに設定します" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "役に立つエラーメッセージを表示するためにいくつかの情報を収集することを許可します" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "sudoers ファイルに完全修飾ホスト名 (FQDN) を要求します" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "間違ったパスワードを入力した時にユーザーを侮辱します" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "tty がある場合のみ sudo の実行を許可します" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "visudo が EDITOR 環境変数を尊重して使用します" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "ユーザーのパスワードではなく、root のパスワードの入力を要求します" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "ユーザーのパスワードではなく、 runas_default ユーザーのパスワードの入力を要求します" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "現在のユーザーのパスワードではなく、変更先ユーザーのパスワードの入力を要求します" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "変更先ユーザーのログインクラスのデフォルトが存在する場合は、デフォルトを適用します" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "LOGNAME および USER 環境変数を設定します" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "実効ユーザーIDのみ変更先ユーザーの UID に設定し、実ユーザーIDは変更しない" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "グループベクトルを変更先ユーザーの値で初期化しない" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "ログファイルの改行する長さ (0 の場合は改行しない): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "認証タイムスタンプのタイムアウト値: %.1f 分" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "パスワード入力要求のタイムアウト値: %.1f 分" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "パスワード入力の試行回数: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "使用する umask 値 (0777 の場合はユーザーの設定値を使用します): 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "ログファイルのパス: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "メールプログラムのパス: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "メールプログラムの引数フラグ: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "メールの送信先アドレス: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "メールの送信元アドレス: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "メールの件名 (Subject) 行: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "パスワードを間違った時のメッセージ: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "認証タイムスタンプディレクトリのパス: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "認証タイムスタンプディレクトリの所有者: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "パスワード入力と PATH の要求が免除されるグループに属するユーザー: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "パスワード入力要求時に表示される文字列: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "設定した場合、すべての場合において passprompt がシステムの入力要求表示を上書きします" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "コマンドを実行するデフォルトの変更先ユーザー: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "ユーザーの $PATH を上書きする時の値: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "visudo で使用されるエディターのパス: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "'list' 疑似コマンド使用するためにパスワードを要求される時: %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "'verify' 疑似コマンドを使用するためにパスワードを要求される時: %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "sudo_noexec ライブラリに含まれるダミーの exec 関数群を事前ロードします" + +# do はたぶん強調の do +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "LDAP ディレクトリが実行中の場合、ローカルの sudoers ファイルを無視します" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "%d 以上の値をもつファイル記述子をコマンド実行前に閉じます" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "設定した場合、ユーザーが `closefrom' の値を -C オプションで上書きするかもしれません" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "ユーザーが任意の環境変数を設定することを許可します" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "環境変数の集合をデフォルトに設定します" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "正当性の確認を行う環境変数:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "削除する環境変数:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "保護する環境変数:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "新しいセキュリティコンテキスト内で使用する SELinux の役割: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "新しいセキュリティコンテキスト内で使用する SELinux のタイプ: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "sudo 固有の環境ファイルのパス: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "sudoers を構文解析する時に使用するロケール: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "パスワードが表示されてしまう状態であっても sudo がパスワード入力を要求することを許可します" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "パスワード入力要求でユーザーの入力があった時に、視覚的なフィードバックを提供します" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "ファイルシステムにアクセスしないがより正確では無い、素早い一致確認処理を行います" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "sudoers で指定した umask 値でユーザーの umask 値を上書きします (ユーザーの umask 値より緩い場合でも)" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "コマンドを実行した時のユーザー入力をログに記録します" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "コマンドを実行した時の出力をログに記録します" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "I/O ログを zlib を使用して圧縮します" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "常に疑似 tty 内でコマンドを実行します" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "UNIX 以外のグループをサポートするためのプラグインです:%s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "入出力 (I/O) ログを保存するディレクトリです:%s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "入出力 (I/O) ログを保存するファイルです:%s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "pty を割り当てた時に utmp/utmpx ファイルに記録を加えます" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "utmp に記録するユーザーを、実行したユーザーではなく、変更後のユーザーにします" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "不明なデフォルト項目 `%s' です" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "オプション `%2$s' の値 `%1$s' は無効です" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "`%s' に値が指定されていません" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "`%s' の値は '/' で開始しなければいけません" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "オプション `%s' は値をとりません" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: envp が破損しています。長さが合いません" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "メモリ割り当てを行えませんでした" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "内部エラー、 sudo_setenv2() がオーバーフローしました" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "内部エラー、 sudo_setenv() がオーバーフローしました" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "すみませんが、あなたは次の環境変数を設定することを許可されていません: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s の所有者は uid %d でなければいけません" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s は所有者のみ書き込み可能でなければいけません" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "dlopen %s を行うことができません: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "%s 内にシンボル \"group_plugin\" がありません" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: 互換性のないグループプラグインメジャーバージョン %d です。予期されるのは %d です" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "ローカル IP アドレスとネットマスクの組:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "%s を読み込めません" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "無効な順序番号です: %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "%s を作成できません" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "ロケールを \"%s\" に設定できません。 \"C\" を使用します" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: ポートが大きすぎます" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: hostbuf を拡張中にメモリ空間が不足しました" + +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "サポートされてない LDAP URI タイプです: %s" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "無効な URI です: %s" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "ldap と ldaps の URI を混ぜて使用できません" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "ldaps と starttls を混ぜて使用できません" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: hostbuf を構築中にメモリ空間が不足しました" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "SSL 証明書と鍵データベースを初期化できません: %s" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "SSL を使用するためには %s の中の TLS_CERT を設定する必要があります" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "GMT 時刻を取得できません" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "タイムスタンプを書式整形できません" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "時刻フィルターを構築できません" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "sudo_ldap_build_pass1 配置が一致しません" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP 役割: %s\n" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP 役割: 不明\n" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr " Order: %s\n" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr " コマンド:\n" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "LDAP を初期化できません: %s" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "start_tls が指定されていますが、LDAP ライブラリが ldap_start_tls_s() または ldap_start_tls_s_np() をサポートしていません" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "無効な sudoOrder 属性です: %s" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "監査システムを開くことができません" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "内部エラー、linux_audit_command() がオーバーフローしました" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "監査メッセージを送ることができません" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "ログファイルを開けません: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "ログファイルをロックできません: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "ユーザーが sudoers 内にありません" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "ホスト上でユーザーが認証されていません" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "コマンドが許可されていません" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s は sudoers ファイル内にありません。この事象は記録・報告されます。\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s は %s 上で sudo を実行することを許可されていません。この事象は記録・報告されます。\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "ユーザー %s は %s 上で sudo を実行できません。すみません。\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "ユーザー %s は'%s%s%s' を %s%s%s として %s 上で実行することは許可されていません。すみません。\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "fork できません" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "fork できません: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "パイプを開けません: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "標準入力を複製できません: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "%s を実行できません: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "内部エラー: ログの行に十分な空間がありません" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "%s 内 %d 行付近で構文解析エラーが発生しました" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "%s 内で構文解析エラーが発生しました" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"sudoers 項目:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " RunAsUsers: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " RunAsGroups: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" コマンド:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "ユーザーID %u (%s) をキャッシュできません。すでに存在します" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "ユーザーID %u をキャッシュできません。すでに存在します" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "ユーザー %s をキャッシュできません。すでに存在します" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "グループID %u (%s) をキャッシュできません。すでに存在します" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "グループID %u をキャッシュできません。すでに存在します" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "グループ %s をキャッシュできません。すでに存在します" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "perm スタックがオーバーフローしました" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "perm スタックがアンダーフローしました" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "実行するためのグループIDに変更できません" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "実行するためのユーザーIDに変更できません" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "sudoers のグループIDへ変更できません" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "プロセスが多すぎます" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "グループベクトルを実行するためのものに変更できません" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "このホスト上でユーザー %s に一致したデフォルト項目:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "ユーザー %s 用の Runas およびコマンド特有のデフォルト:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "ユーザー %s は次のコマンドをこのホスト上で実行できます:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "ユーザー %s は %s 上で sudo を実行することを許可されていません。\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "デフォルト項目で問題が発生しました" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "有効な sudoers のソースが見つかりません。終了します" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "%s を実行できません: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers の指定により root が sudo を使用することは禁止されています" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "-C オプションを使用することは許可されていません" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "タイムスタンプの所有者 (%s): そのようなユーザーはありません" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "tty がありません" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "sudo を実行するには tty がなければいけません。すみません" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "ユーザーまたはホストがありません" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: コマンドが見つかりません" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"'.' 内で見つかった `%1$s' を無視します\n" +"この `%3$s' を実行したい場合は `sudo ./%2$s' を使用してください。" + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "検証に失敗しました" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "コマンドがカレントディレクトリにあります" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "あなたは環境変数を保護することを許可されていません。すみません" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "内部エラー、runas_groups がオーバーフローしました" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "内部エラー、set_cmnd() がオーバーフローしました" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s は通常ファイルではありません" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s はユーザーID %u によって所有されています。これは %u であるべきです" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "%s は誰でも書き込み可能です" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s のグループIDは %u になっています。これは %u であるべきです" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "root のみ `-c %s' を使用できます" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "不明なログインクラスです: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "ホスト %s の名前解決ができません" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "不明なグループです: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "sudoers ポリシープラグイン バージョン %s\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "sudoers ファイル文法バージョン %d\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"sudoers のパス: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "nsswitch のパス: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ldap.conf のパス: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ldap.secret のパス: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "無効なフィルターオプションです: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "無効な最大待機時間です: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "無効な speed_factor の値です: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s バージョン %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/タイミング: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/タイミング: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "リプレイする sudo セッション: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "警告: ログをきちんとリプレイするには端末が小さすぎます。\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "ログの大きさは %d x %d で、端末の大きさは %d x %d です。" + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "tty を raw モードに設定できません" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "無効なタイミングファイルの行です: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "標準出力に書き込んでいます" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "曖昧な式 \"%s です\"" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "式内の小括弧のくくりが多すぎます。最大は %d です。" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "式内で ')' が不一致です" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "不明な検索語 \"%s\" です" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s は引数が必要です" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "無効な正規表現です: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "日付 \"%s\" を構文解析できませんでした" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "式内で '(' が不一致です" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "末尾に \"or\" を配置できません" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "末尾に \"!\" を配置できません" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "無効な正規表現です: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "使用法: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "使用法: %s [-h] [-d directory] -l [search expression]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - sudo セッションログをリプレイします\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"オプション:\n" +" -d directory セッションログのディレクトリを指定する\n" +" -f filter 表示する I/O タイプを指定する\n" +" -h ヘルプメッセージを表示して終了する\n" +" -l [expression] expression に一致する使用可能なセッションID\n" +" を一覧表示する\n" +" -m max_wait イベント間の待ち時間の最大秒数を指定する\n" +" -s speed_factor 出力速度を速くする、または遅くする\n" +" -V バージョン情報を表示して終了する" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "内部エラー、init_vars() がオーバーフローしました" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\tホストが一致しません" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"コマンドが許可されました" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"コマンドが拒否されました" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"コマンドが一致しませんでした" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: バッファオーバーフローが発生しました" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s 文法バージョン %d\n" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "%s を編集するためにリターンを押してください: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "書き込みエラーです" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "一時ファイル (%s) の状態取得 (stat) ができません。%s は変更されません" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "一時ファイル (%s) の大きさが 0 です。%s は変更されません" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "エディター (%s) が異常終了しました。%s は変更されません" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s は変更されません" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "一時ファイル (%s) を再度開くことができません。%s は変更されません。" + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "一時ファイル (%s) の構文解析ができません。不明なエラーです" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "内部エラー、リスト内に %s が見つかりません!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "%s の (ユーザーID, グループID) を (%u, %u) に設定できません" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "%s のアクセス権限のモードを 0%o に変更できません" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s と %s は同じファイルシステム上にありません。名前を変更するために mv を使用しています" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "コマンドの失敗です: '%s %s %s'。%s は変更されません" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "%s の名前変更に失敗しました。%s は変更されません" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "次は何でしょうか? " + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"オプション:\n" +" e -- sudoers ファイルを再度編集します\n" +" x -- sudoers ファイルへの変更を保存せずに終了します\n" +" Q -- sudoers ファイルへの変更を保存して終了します (*危険です!*)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "%s を実行できません" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "%s を実行できません" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: 所有権に誤りがあります。(ユーザーID, グループID) は (%u, %u) であるべきです\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: アクセス権限に誤りがあります。モードは 0%o であるべきです\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "%s ファイルの構文解析に失敗しました。不明なエラーです" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "%s 内 %d 行付近で構文解析エラーが発生しました\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "%s 内で構文解析エラーが発生しました\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: 正しく構文解析されました\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s がビジー状態です。後で再試行してください" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "指定したエディター (%s) が存在しません" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "エディター (%s) の状態取得 (stat) ができません" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "エディターが見つかりません (エディターのパス = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "エラー: %s_Alias `%s' 内に循環があります" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "警告: %s_Alias `%s' 内に循環があります" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "エラー: %s_Alias `%s' は参照されていますが定義されていません" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "警告: %s_Alias `%s' は参照されていますが定義されていません" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s: %s_Alias %s は使用されていません" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - sudoers ファイルを安全に編集する\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"オプション:\n" +" -c 検査のみを行う\n" +" -f sudoers sudoers ファイルの位置を指定する\n" +" -h ヘルプメッセージを表示して終了する\n" +" -q 文法エラーメッセージをより少なく (静かに) する\n" +" -s 厳密な文法検査を行う\n" +" -V バージョン情報を表示して終了する" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "インクルードの階層が大きすぎます" + +#~ msgid "invalid log file %s" +#~ msgstr "ログファイル %s は無効です" + +#~ msgid "fixed mode on %s" +#~ msgstr "%s のアクセス権限のモードを修正しました" + +#~ msgid "set group on %s" +#~ msgstr "%s のグループを設定しました" + +#~ msgid "unable to set group on %s" +#~ msgstr "%s のグループを設定できません" + +#~ msgid "unable to fix mode on %s" +#~ msgstr "%s のアクセス権限のモードを修正できません" + +#~ msgid "%s is mode 0%o, should be 0%o" +#~ msgstr "%s のアクセス権限のモードは 0%o です。これは 0%o であるべきです" + +#~ msgid "File containing dummy exec functions: %s" +#~ msgstr "偽の exec 関数が含まれるファイル: %s" diff --git a/plugins/sudoers/po/lt.mo b/plugins/sudoers/po/lt.mo new file mode 100644 index 0000000..56ba51d Binary files /dev/null and b/plugins/sudoers/po/lt.mo differ diff --git a/plugins/sudoers/po/lt.po b/plugins/sudoers/po/lt.po new file mode 100644 index 0000000..1d6e621 --- /dev/null +++ b/plugins/sudoers/po/lt.po @@ -0,0 +1,1681 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# Algimantas Margevičius , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.4rc1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-02-06 15:48-0500\n" +"PO-Revision-Date: 2012-02-25 11:56+0200\n" +"Last-Translator: Algimantas Margevičius \n" +"Language-Team: Lithuanian \n" +"Language: lt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:61 plugins/sudoers/bsm_audit.c:64 +#: plugins/sudoers/bsm_audit.c:113 plugins/sudoers/bsm_audit.c:117 +#: plugins/sudoers/bsm_audit.c:169 plugins/sudoers/bsm_audit.c:173 +msgid "getaudit: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:91 plugins/sudoers/bsm_audit.c:154 +msgid "Could not determine audit condition" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:102 +msgid "getauid failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:104 plugins/sudoers/bsm_audit.c:163 +msgid "au_open: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:119 plugins/sudoers/bsm_audit.c:175 +msgid "au_to_subject: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:123 plugins/sudoers/bsm_audit.c:179 +msgid "au_to_exec_args: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:127 plugins/sudoers/bsm_audit.c:188 +msgid "au_to_return32: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:130 plugins/sudoers/bsm_audit.c:191 +msgid "unable to commit audit record" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:161 +msgid "getauid: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:184 +msgid "au_to_text: failed" +msgstr "" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:992 plugins/sudoers/sudoreplay.c:348 +#: plugins/sudoers/sudoreplay.c:357 plugins/sudoers/sudoreplay.c:703 +#: plugins/sudoers/sudoreplay.c:797 plugins/sudoers/visudo.c:790 +#, c-format +msgid "unable to open %s" +msgstr "" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:978 +#: plugins/sudoers/visudo.c:320 plugins/sudoers/visudo.c:582 +#, c-format +msgid "unable to stat %s" +msgstr "" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:829 plugins/sudoers/sudoers.c:833 +#, c-format +msgid "unknown uid: %u" +msgstr "" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:770 +#: plugins/sudoers/sudoers.c:1108 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in \"_PATH_SUDO_NOEXEC" +msgstr "" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "" + +#: plugins/sudoers/env.c:258 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "" + +#: plugins/sudoers/env.c:291 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "" + +#: plugins/sudoers/env.c:710 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:923 toke.l:668 toke.l:823 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr "" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s turi priklausyti uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s turi bÅ«ti įraÅ¡omas tik savininkui" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:999 +#, c-format +msgid "unable to read %s" +msgstr "" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:362 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "" + +#: plugins/sudoers/ldap.c:374 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "" + +#: plugins/sudoers/ldap.c:397 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:427 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:456 +#, c-format +msgid "invalid uri: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:462 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "" + +#: plugins/sudoers/ldap.c:485 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:550 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:958 +#, c-format +msgid "unable to get GMT time" +msgstr "" + +#: plugins/sudoers/ldap.c:964 +#, c-format +msgid "unable to format timestamp" +msgstr "" + +#: plugins/sudoers/ldap.c:972 +#, c-format +msgid "unable to build time filter" +msgstr "" + +#: plugins/sudoers/ldap.c:1185 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "" + +#: plugins/sudoers/ldap.c:1705 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1707 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1754 +#, c-format +msgid " Order: %s\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1762 +#, c-format +msgid " Commands:\n" +msgstr "" + +#: plugins/sudoers/ldap.c:2161 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:2192 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "" + +#: plugins/sudoers/ldap.c:2428 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s nėra „sudoers“ faile. Apie šį įvykį bus praneÅ¡ta.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s neleidžiama vykdyti „sudo“ kompiuteryje %s. Apie šį įvykį bus praneÅ¡ta.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Deja, naudotojas %s negali vykdyti „sudo“ kompiuteryje %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Deja, naudotojui %s neleidžiama vykdyti „%s%s%s“ kaip %s%s%s kompiuteryje %s.\n" + +#: plugins/sudoers/logging.c:420 +#, c-format +msgid "unable to fork" +msgstr "" + +#: plugins/sudoers/logging.c:427 plugins/sudoers/logging.c:489 +#, c-format +msgid "unable to fork: %m" +msgstr "" + +#: plugins/sudoers/logging.c:479 +#, c-format +msgid "unable to open pipe: %m" +msgstr "" + +#: plugins/sudoers/logging.c:504 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "" + +#: plugins/sudoers/logging.c:540 +#, c-format +msgid "unable to execute %s: %m" +msgstr "" + +#: plugins/sudoers/logging.c:755 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr "" + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr "" + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:655 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:663 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:693 plugins/sudoers/pwutil.c:702 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "" + +#: plugins/sudoers/set_perms.c:114 plugins/sudoers/set_perms.c:365 +#: plugins/sudoers/set_perms.c:601 plugins/sudoers/set_perms.c:837 +msgid "perm stack overflow" +msgstr "" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:373 +#: plugins/sudoers/set_perms.c:609 plugins/sudoers/set_perms.c:845 +msgid "perm stack underflow" +msgstr "" + +#: plugins/sudoers/set_perms.c:228 plugins/sudoers/set_perms.c:466 +#: plugins/sudoers/set_perms.c:706 +msgid "unable to change to runas gid" +msgstr "" + +#: plugins/sudoers/set_perms.c:236 plugins/sudoers/set_perms.c:473 +#: plugins/sudoers/set_perms.c:713 +msgid "unable to change to runas uid" +msgstr "" + +#: plugins/sudoers/set_perms.c:250 plugins/sudoers/set_perms.c:486 +#: plugins/sudoers/set_perms.c:726 +#, c-format +msgid "unable to change to sudoers gid" +msgstr "" + +#: plugins/sudoers/set_perms.c:291 plugins/sudoers/set_perms.c:524 +#: plugins/sudoers/set_perms.c:764 plugins/sudoers/set_perms.c:906 +msgid "too many processes" +msgstr "" + +#: plugins/sudoers/set_perms.c:970 +msgid "unable to set runas group vector" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Naudotojui %s neleidžiama vykdyti „sudo“ kompiuteryje %s.\n" + +#: plugins/sudoers/sudoers.c:201 plugins/sudoers/sudoers.c:232 +#: plugins/sudoers/sudoers.c:931 +msgid "problem with defaults entries" +msgstr "" + +#: plugins/sudoers/sudoers.c:205 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "" + +#: plugins/sudoers/sudoers.c:257 +#, c-format +msgid "unable to execute %s: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:311 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "" + +#: plugins/sudoers/sudoers.c:318 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "" + +#: plugins/sudoers/sudoers.c:408 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "" + +#: plugins/sudoers/sudoers.c:424 +msgid "no tty" +msgstr "" + +#: plugins/sudoers/sudoers.c:425 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "" + +#: plugins/sudoers/sudoers.c:464 +msgid "No user or host" +msgstr "" + +#: plugins/sudoers/sudoers.c:478 plugins/sudoers/sudoers.c:499 +#: plugins/sudoers/sudoers.c:500 plugins/sudoers/sudoers.c:1509 +#: plugins/sudoers/sudoers.c:1510 +#, c-format +msgid "%s: command not found" +msgstr "" + +#: plugins/sudoers/sudoers.c:480 plugins/sudoers/sudoers.c:496 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" + +#: plugins/sudoers/sudoers.c:485 +msgid "validation failure" +msgstr "" + +#: plugins/sudoers/sudoers.c:495 +msgid "command in current directory" +msgstr "" + +#: plugins/sudoers/sudoers.c:507 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "" + +#: plugins/sudoers/sudoers.c:657 plugins/sudoers/sudoers.c:664 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "" + +#: plugins/sudoers/sudoers.c:914 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "" + +#: plugins/sudoers/sudoers.c:957 +#, c-format +msgid "fixed mode on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:961 +#, c-format +msgid "set group on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:964 +#, c-format +msgid "unable to set group on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:967 +#, c-format +msgid "unable to fix mode on %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:980 +#, c-format +msgid "%s is not a regular file" +msgstr "" + +#: plugins/sudoers/sudoers.c:982 +#, c-format +msgid "%s is mode 0%o, should be 0%o" +msgstr "" + +#: plugins/sudoers/sudoers.c:986 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s priklauso uid %u, nors turėtų %u" + +#: plugins/sudoers/sudoers.c:989 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s priklauso gid %u, nors turėtų %u" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "„-c %s“ gali naudoti tik „root“ naudotojas" + +#: plugins/sudoers/sudoers.c:1049 +#, c-format +msgid "unknown login class: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1077 +#, c-format +msgid "unable to resolve host %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1129 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1178 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1180 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1184 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1189 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1190 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:286 +#, c-format +msgid "invalid filter option: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:299 +#, c-format +msgid "invalid max wait: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:305 +#, c-format +msgid "invalid speed factor: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:308 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:333 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:339 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:364 +#, c-format +msgid "invalid log file %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:366 +#, c-format +msgid "Replaying sudo session: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:392 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:406 +#, c-format +msgid "invalid timing file line: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:448 +#, c-format +msgid "writing to standard output" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:480 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:529 plugins/sudoers/sudoreplay.c:554 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:571 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:582 +#, c-format +msgid "unmatched ')' in expression" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:602 +#, c-format +msgid "%s requires an argument" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:606 +#, c-format +msgid "invalid regular expression: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:625 +#, c-format +msgid "unmatched '(' in expression" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:627 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:629 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:851 +#, c-format +msgid "invalid regex: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:976 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:979 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:988 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:990 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" + +#: toke.l:672 toke.l:802 toke.l:827 toke.l:923 plugins/sudoers/toke_util.c:113 +#: plugins/sudoers/toke_util.c:167 plugins/sudoers/toke_util.c:207 +msgid "unable to allocate memory" +msgstr "" + +#: toke.l:795 +msgid "too many levels of includes" +msgstr "" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:221 plugins/sudoers/auth/rfc1938.c:104 +#, c-format +msgid "you do not exist in the %s database" +msgstr "" + +#: plugins/sudoers/visudo.c:253 plugins/sudoers/visudo.c:539 +#, c-format +msgid "press return to edit %s: " +msgstr "" + +#: plugins/sudoers/visudo.c:336 plugins/sudoers/visudo.c:342 +#, c-format +msgid "write error" +msgstr "" + +#: plugins/sudoers/visudo.c:424 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:429 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:435 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:458 +#, c-format +msgid "%s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:484 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "" + +#: plugins/sudoers/visudo.c:494 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "" + +#: plugins/sudoers/visudo.c:532 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "" + +#: plugins/sudoers/visudo.c:584 plugins/sudoers/visudo.c:593 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "" + +#: plugins/sudoers/visudo.c:588 plugins/sudoers/visudo.c:598 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "" + +#: plugins/sudoers/visudo.c:615 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "" + +#: plugins/sudoers/visudo.c:629 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:639 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:702 +msgid "What now? " +msgstr "" + +#: plugins/sudoers/visudo.c:716 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" + +#: plugins/sudoers/visudo.c:757 +#, c-format +msgid "unable to execute %s" +msgstr "" + +#: plugins/sudoers/visudo.c:764 +#, c-format +msgid "unable to run %s" +msgstr "" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "" + +#: plugins/sudoers/visudo.c:808 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:811 +#, c-format +msgid "parse error in %s\n" +msgstr "" + +#: plugins/sudoers/visudo.c:814 plugins/sudoers/visudo.c:816 +#, c-format +msgid "%s: parsed OK\n" +msgstr "" + +#: plugins/sudoers/visudo.c:826 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "" + +#: plugins/sudoers/visudo.c:833 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "" + +#: plugins/sudoers/visudo.c:880 +#, c-format +msgid "%s busy, try again later" +msgstr "" + +#: plugins/sudoers/visudo.c:924 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "" + +#: plugins/sudoers/visudo.c:947 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "" + +#: plugins/sudoers/visudo.c:995 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "" + +#: plugins/sudoers/visudo.c:1089 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:1090 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:1093 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1094 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1229 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "" + +#: plugins/sudoers/visudo.c:1286 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" + +#: plugins/sudoers/visudo.c:1288 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:178 +#, c-format +msgid "pam_authenticate: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:306 +msgid "Password: " +msgstr "Slaptažodis: " + +#: plugins/sudoers/auth/pam.c:307 +msgid "Password:" +msgstr "Slaptažodis:" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "" +msgstr[1] "" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "" diff --git a/plugins/sudoers/po/pl.mo b/plugins/sudoers/po/pl.mo new file mode 100644 index 0000000..aee78a1 Binary files /dev/null and b/plugins/sudoers/po/pl.mo differ diff --git a/plugins/sudoers/po/pl.po b/plugins/sudoers/po/pl.po new file mode 100644 index 0000000..d78cbfd --- /dev/null +++ b/plugins/sudoers/po/pl.po @@ -0,0 +1,1735 @@ +# Polish translation for sudo/sudoers. +# This file is put in the public domain. +# Jakub Bogusz , 2011-2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-05-06 21:40+0200\n" +"Last-Translator: Jakub Bogusz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s w okolicy linii %d <<<" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Alias `%s' jest już zdefiniowany" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "nie udało się uzyskać klasy logowania dla użytkownika %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "nie udało się rozpocząć uwierzytelnienia BSD" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "błędny rodzaj uwierzytelnienia" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "nie udało się ustawić parametrów uwierzytelnienia" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "nie udało się odczytać konfiguracji fwtk" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "nie udało się połączyć z serwerem uwierzytelniającym" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "utracono połączenie z serwerem uwierzytelniającym" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"błąd serwera uwierzytelniającego:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s: nie udało się złożyć princ ('%s'): %s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: nie udało się przeanalizować '%s': %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: nie udało się rozwiązać ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: nie udało się przydzielić opcji: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: nie udało się pobrać danych uwierzytelniających: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: nie udało się zainicjować ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: nie udało się zapisać danych uwierzytelniających w ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: nie udało się pobrać głównego hosta: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: Nie można zweryfikować TGT! Możliwy atak!: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "nie udało się zainicjować PAM" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "błąd kontroli poprawności konta - konto zablokowane?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Konto lub hasło wygasło, należy ustawić ponownie hasło i spróbować jeszcze raz" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Hasło wygasło, proszę skontaktować się z administratorem systemu" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "Konto wygasło lub w konfiguracji PAM brak sekcji \"account\" dla sudo, proszę skontaktować się z administratorem systemu" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "Hasło: " + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "Hasło:" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "nie istniejesz w bazie danych %s" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "nie udało się zainicjować biblioteki ACE API" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "nie udało się połączyć z serwerem SecurID" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "ID użytkownika zablokowany dla uwierzytelnienia SecurID" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "błędna długość nazwy użytkownika dla SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "błędny uchwyt uwierzytelnienia dla SecurID" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "błąd komunikacji SecurID" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "nieznany błąd SecurID" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "błędna długość hasła dla SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "nie udało się zainicjować sesji SIA" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "W sudo wkompilowano błędne metody uwierzytelniania! Można mieszać samodzielne i niesamodzielne sposoby uwierzytelniania." + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "W sudo nie wkompilowano żadnych metod uwierzytelniania! Aby wyłączyć uwierzytelnianie, proszę użyć opcji konfiguracyjnej --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d błędna próba wprowadzenia hasła" +msgstr[1] "%d błędne próby wprowadzenia hasła" +msgstr[2] "%d błędnych prób wprowadzenia hasła" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Metody uwierzytelniania:" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: niepowodzenie" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "Nie udało się określić warunku audytowego" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid nie powiodło się" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: niepowodzenie" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: niepowodzenie" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: niepowodzenie" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32: niepowodzenie" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "nie udało się zatwierdzić rekordu audytowego" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: niepowodzenie" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: niepowodzenie" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "niestety do uruchomienia %s wymagane jest hasło" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "nie udało się otworzyć %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "nie udało się zapisać do %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "nie udało się wykonać mkdir %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "błąd wewnętrzny, przepełnienie expand_prompt()" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "ścieżka znacznika czasu zbyt długa: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s istnieje, ale nie jest katalogiem (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "właścicielem %s jest uid %u, powinien być uid %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s zapisywalny nie tylko dla właściciela (uprawnienia 0%o, powinny być 0700)" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "nie udało się wykonać stat na %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s istnieje, ale nie jest zwykłym plikiem (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s zapisywalny nie tylko dla właściciela (uprawnienia 0%o, powinny być 0600)" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "znacznik czasu zbyt daleko w przyszłości: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "nie udało się usunąć %s (%s), zostanie zresetowany do epoch" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "nie udało się zresetować %s do epoch" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "nieznany uid: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "nieznany użytkownik: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Rodzaj komunikatu sysloga, jeśli syslog jest używany: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Priorytet komunikatu sysloga w przypadku udanego uwierzytelnienia: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Priorytet komunikatu sysloga w przypadku nieudanego uwierzytelnienia: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "Umieszczenie zachęty OTP we własnej linii" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Ignorowanie '.' w $PATH" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Wysyłanie listu zawsze przy uruchomieniu sudo" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "Wysyłanie listu przy błędnym uwierzytelnieniu" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "Wysyłanie listu jeśli użytkownik nie jest w sudoers" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "Wysyłanie listu jeśli użytkownik nie jest w sudoers dla tego hosta" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "Wysyłanie listu jeśli użytkownik nie ma prawa do uruchomienia polecenia" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "Użycie osobnego znacznika czasu dla każdej pary użytkownik/tty" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Poinstruowanie użytkownika przy pierwszym uruchomieniu sudo" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Plik zawierający instrukcję do sudo: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Domyślne wymaganie uwierzytelnienia przez użytkowników" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Możliwość uruchamiania sudo przez roota" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "Logowanie nazwy hosta w pliku logu (niesyslogowym)" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "Logowanie roku w pliku logu (niesyslogowym)" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "Uruchomienie powłoki przy wywołaniu sudo bez argumentów" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Ustawianie $HOME na katalog użytkownika docelowego przy uruchamianiu powłoki z -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Ustawianie $HOME zawsze na katalog domowy użytkownika docelowego" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "Zezwolenie na zbieranie niektórych informacji do przydatnych komunikatów błędów" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "Wymaganie pełnych nazw hostów w pliku sudoers" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Lżenie użytkownika po podaniu błędnego hasła" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "Możliwość uruchamiania sudo tylko z poziomu terminala" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Honorowanie zmiennej środowiskowej EDITOR przez visudo" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Pytanie o hasło roota zamiast hasła użytkownika" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Pytanie o hasło użytkownika runas_default zamiast uruchamiającego" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Pytanie o hasło użytkownika docelowego zamiast uruchamiającego" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "Użycie ustawień domyślnych z klasy logowania użytkownika docelowego (jeśli są)" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Ustawianie zmiennych środowiskowych LOGNAME i USER" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "Ustawianie na użytkownika docelowego tylko efektywnego uid-a, nie rzeczywistego uid-a" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "Pomijanie inicjalizacji wektora grup na grupy użytkownika docelowego" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "Długość, na której zawijać linie logu (0 bez zawijania): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "Limit czasu znacznika uwierzytelniania (w minutach): %.1f" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "Limit czasu pytania o hasło (w minutach): %.1f" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Liczba prób wpisania hasła: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Wartość umask lub 0777, aby użyć wartości użytkownika: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Ścieżka do pliku logu: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Ścieżka do programu mail: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Flagi dla programu mail: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Adres, na który mają być wysyłane listy: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Adres, z którego mają być wysyłane listy: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Temat wysyłanych listów: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Komunikat o błędnym haśle: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "Ścieżka katalogu znaczników czasu uwierzytelniania: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "Właściciel katalogu znaczników czasu uwierzytelniania: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "Grupa, której użytkownicy są zwolnieni z wymagań dot. haseł i PATH: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "Domyślne pytanie o hasło: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "Czy passprompt ma być używane zamiast systemowego zapytania we wszystkich przypadkach" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "Domyślny użytkownik do uruchamiania poleceń: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "Wartość do podstawienia za $PATH użytkownika: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "Ścieżka do edytora, który ma być używany przez visudo: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "Kiedy ma być wymagane hasło dla pseudopolecenia 'list': %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "Kiedy ma być wymagane hasło dla pseudopolecenia 'verify': %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "Wczytanie pustych funkcji exec zawartych w bibliotece sudo_noexec" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "Jeśli istnieje katalog LDAP, czy ignorować lokalny plik sudoers" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "Deskryptory plików >= %d będą zamykane przed uruchomieniem polecenia" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "Czy użytkownicy mogą zmieniać wartość `closefrom' opcją -C" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "Zezwolenie użytkownikom na ustawianie dowolnych zmiennych środowiskowych" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "Wyczyszczenie środowiska do domyślnego zbioru zmiennych" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "Zmienne środowiskowe do sprawdzania poprawności:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Zmienne środowiskowe do usunięcia:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Zmienne środowiskowe do zachowania:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "Rola SELinuksa do używania w nowym kontekście bezpieczeństwa: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "Typ SELinuksa do używania w nowym kontekście bezpieczeństwa: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "Ścieżka do pliku środowiska specyficznego dla sudo: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Lokalizacja, jak ma być używana przy analizie pliku sudoers: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "Zezwolenie sudo na pytanie o hasło nawet gdyby miało być widoczne" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "Uwidocznienie wprowadzania hasła przez użytkownika w miarę wpisywania" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "Użycie szybszych masek (glob) - mniej dokładnych, ale nie odwołujących się do systemu plików" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "Wartość umask podana w sudoers ma zastąpić wartość użytkownika, nawet jeśli pozwala na więcej" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "Logowanie wejścia użytkownika dla uruchamianych poleceń" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "Logowanie wyjścia z uruchamianych poleceń" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "Kompresja logów we/wy przy użyciu zliba" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "Uruchamianie poleceń zawsze na pseudoterminalu" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "Wtyczka do obsługi grup nieuniksowych: %s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "Katalog do zapisu logów wejścia/wyjścia: %s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "Plik do zapisu logu wejścia/wyjścia: %s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "Dodawanie wpisu do pliku utmp/utmpx przy przydzielaniu pty" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "Ustawianie użytkownika w utmp jako docelowego, nie wywołującego" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "nieznany wpis domyślny `%s'" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "błędna wartość `%s' dla opcji `%s'" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "nie podano wartości dla `%s'" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "wartości `%s' muszą zaczynać się od '/'" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "opcja `%s' nie przyjmuje wartości" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: uszkodzone envp, niezgodność długości" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "nie udało się przydzielić pamięci" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "błąd wewnętrzny, przepełnienie sudo_setenv2()" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "błąd wewnętrzny, przepełnienie sudo_setenv()" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "niestety nie jest dozwolone ustawianie następujących zmiennych środowiskowych: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "właścicielem %s musi być uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "prawo zapisu do %s może mieć tylko właściciel" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "nie udało się wykonać dlopen %s: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "nie udało się odnaleźć symbolu \"group_plugin\" w %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: niezgodna główna wersja wtyczki grup %d, oczekiwano %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "Pary lokalnych adresów IP i masek:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "nie udało się odczytać %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "błędny numer sekwencyjny %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "nie udało się utworzyć %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "nie udało się ustawić lokalizacji na \"%s\", użyto \"C\"" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: port zbyt duży" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: brak miejsca podczas rozszerzania hostbuf" + +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "nieobsługiwany rodzaj URI LDAP: %s" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "błędny URI: %s" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "nie można mieszać URI ldap i ldaps" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "nie można mieszać ldaps i starttls" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: brak miejsca podczas konstruowania hostbuf" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "nie udało się zainicjować bazy certyfikatów i kluczy SSL: %s" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "aby używać SSL, trzeba ustawić TLS_CERT w %s" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "nie udało się pobrać czasu GMT" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "nie udało się sformatować znacznika czasu" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "nie udało się stworzyć filtra czasu" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "niezgodność przydzielenia sudo_ldap_build_pass1" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"Rola LDAP: %s\n" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"Rola LDAP: NIEZNANA\n" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr " Porządek: %s\n" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr " Polecenia:\n" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "nie udało się zainicjować LDAP: %s" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "wybrano start_tls, ale biblioteki LDAP nie obsługują ldap_start_tls_s() ani ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "błędny atrybut sudoOrder: %s" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "nie udało się otworzyć systemu audytowego" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "błąd wewnętrzny, przepełnienie linux_audit_command()" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "nie udało się wysłać komunikatu audytowego" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "nie udało się otworzyć pliku logu: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "nie udało się zablokować pliku logu: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "użytkownik NIE występuje w sudoers" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "użytkownik NIE jest autoryzowany na hoście" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "polecenie niedozwolone" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s nie występuje w pliku sudoers. Ten incydent zostanie zgłoszony.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s nie ma uprawnień do uruchamiania sudo na %s. Ten incydent zostanie zgłoszony.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Niestety użytkownik %s nie może uruchamiać sudo na %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Niestety użytkownik %s nie ma uprawnień do uruchamiania '%s%s%s' jako %s%s%s na %s.\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "nie udało się wykonać fork" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "nie udało się wykonać fork: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "nie udało się otworzyć potoku: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "nie udało się wykonać dup na stdin: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "nie udało się wywołać %s: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "błąd wewnętrzny: za mało miejsca na linię logu" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "błąd składni w %s w okolicy linii %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "błąd składni w %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Wpis sudoers:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " Jako użytkownicy: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " Jako grupy: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Polecenia:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "nie udało się zapamiętać uid-a %u (%s), już istnieje" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "nie udało się zapamiętać uid-a %u, już istnieje" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "nie udało się zapamiętać użytkownika %s, już istnieje" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "nie udało się zapamiętać gid-a %u (%s), już istnieje" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "nie udało się zapamiętać gid-a %u, już istnieje" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "nie udało się zapamiętać grupy %s, już istnieje" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "przepełnienie stosu uprawnień" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "niedopełnienie stosu uprawnień" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "nie udało się zmienić na docelowy gid" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "nie udało się zmienić na docelowy uid" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "nie udało się zmienić na gid sudoers" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "zbyt dużo procesów" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "nie udało się ustawić wektora grup docelowych" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "Pasujące wpisy Defaults dla %s na tym hoście:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "Wartości specyficzne dla Runas i Command dla %s:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Użytkownik %s może uruchamiać na tym hoście następujące polecenia:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Użytkownik %s nie ma uprawnień do uruchamiania sudo na %s.\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "problem z wpisami domyślnymi" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "nie znaleziono poprawnych źródeł sudoers, zakończenie" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "nie udało się wywołać %s: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "wg sudoers root nie ma prawa używać sudo" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "brak uprawnień do używania opcji -C" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "właściciel znacznika czasu (%s): nie ma takiego użytkownika" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "brak tty" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "niestety do uruchomienia sudo konieczny jest tty" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "Brak użytkownika lub hosta" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: nie znaleziono polecenia" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"zignorowano plik `%s' znaleziony w '.'\n" +"Proszę użyć `sudo ./%s', jeśli to `%s' ma być uruchomiony." + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "błąd kontroli poprawności" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "polecenie w bieżącym katalogu" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "niestety brak uprawnień do zachowania środowiska" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "błąd wewnętrzny, przepełnienie runas_groups" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "błąd wewnętrzny, przepełnienie set_cmnd()" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s nie jest zwykłym plikiem" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "właścicielem %s jest uid %u, powinien być %u" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "%s jest zapisywalny dla świata" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "właścicielem %s jest gid %u, powinien być %u" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "tylko root może używać `-c %s'" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "nieznana klasa logowania: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "nie udało się rozwiązać nazwy hosta %s" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "nieznana grupa: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Wersja wtyczki polityki sudoers %s\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Wersja gramatyki pliku sudoers %d\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Ścieżka do sudoers: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "ścieżka do nsswitch: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ścieżka do ldap.conf: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ścieżka do ldap.secret: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "błędna opcja filtra: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "błędny maksymalny czas oczekiwania: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "błędny współczynnik szybkości: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s wersja %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/czas: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/czas: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "Odtwarzanie sesji sudo: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "Uwaga: ten terminal jest za mały, aby właściwie odtworzyć log.\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "Geometria logu to %d x %d, geometria terminala to %d x %d." + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "nie udało się przestawić tty w tryb surowy" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "błędna linia pliku czasu: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "zapis na standardowe wyjście" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanospeep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "niejednoznaczne wyrażenie \"%s\"" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "zbyt dużo zagnieżdżonych wyrażeń w nawiasach, maksimum to %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "niesparowany ')' w wyrażeniu" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "nieznany warunek wyszukiwania \"%s\"" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s wymaga argumentu" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "błędne wyrażenie regularne: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "nie udało się przeanalizować daty \"%s\"" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "niesparowany '(' w wyrażeniu" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "niedozwolone kończące \"or\"" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "niedozwolony kończący \"!\"" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "błędne wyrażenie regularne: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "Składnia: %s [-h] [-d katalog] [-m maks_oczek] [-s wsp_szybkości] ID\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "Składnia: %s [-h] [-d katalog] -k [wyrażenie wyszukiwania]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - odtwarzanie logów sesji sudo\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"Opcje:\n" +" -d katalog podanie katalogu na logi sesji\n" +" -f filtr określenie rodzaju we/wy do wyświetlania\n" +" -h wyświetlenie opisu i zakończenie\n" +" -l [wyrażenie] lista dostępnych ID sesji pasujących do wyrażenia\n" +" -m maks_oczek maksymalna liczba sekund oczekiwania między zdarzeniami\n" +" -s wsp_szybkości przyspieszenie lub spowolnienie wyjścia\n" +" -V wyświetlenie informacji o wersji i zakończenie" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "błąd wewnętrzny, przepełnienie init_vars()" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\thost nie znaleziony" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Polecenie dozwolone" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Polecenie niedozwolone" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"Polecenie nie znalezione" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: przepełnienie bufora" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s, wersja gramatyki %d\n" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "wciśnięcie return przejdzie do edycji %s: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "błąd zapisu" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "nie udało się wykonać stat na pliku tymczasowym (%s), %s nie zmieniony" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "plik tymczasowy (%s) zerowej długości, %s nie zmieniony" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "błąd edytora (%s), %s nie zmieniony" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s nie zmieniony" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "nie udało się ponownie otworzyć pliku tymczasowego (%s), %s nie zmieniony." + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "nie udało się przeanalizować pliku tymczasowego (%s), nieznany błąd" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "błąd wewnętrzny, nie znaleziono %s na liście!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "nie udało się ustawić (uid, gid) %s na (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "nie udało się zmienić uprawnień %s na 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s i %s nie są na tym samym systemie plików, użycie mv do zmiany nazwy" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "polecenie nie powiodło się: '%s %s %s', %s nie zmieniony" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "błąd podczas zmiany nazwy %s, %s nie zmieniony" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "Co teraz? " + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Możliwe opcje:\n" +" (e) ponowna edycja pliku sudoers\n" +" (x) wyjście bez zapisu zmian do pliku sudoers\n" +" (Q) wyjście i zapisanie zmian w pliku sudoers (NIEBEZPIECZNE!)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "nie udało się wywołać %s" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "nie udało się uruchomić %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: błędny właściciel, (uid, gid) powinny wynosić (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: błędne uprawnienia, powinny być 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "nie udało się przeanalizować pliku %s, nieznany błąd" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "błąd składni w %s w okolicy linii %d\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "błąd składni w %s\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: składnia poprawna\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s zajęty, proszę spróbować później" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "podany edytor (%s) nie istnieje" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "nie udało się wykonać stat na edytorze (%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "nie znaleziono edytora (ścieżka = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "Błąd: cykl w %s_Alias `%s'" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "Uwaga: cykl w %s_Alias `%s'" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "Błąd: %s_Alias `%s' użyty, ale nie zdefiniowany" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "Uwaga: %s_Alias `%s' użyty, ale nie zdefiniowany" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s: nie użyty %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - bezpieczna edycja pliku sudoers\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"Opcje:\n" +" -c tryb wyłącznie sprawdzający\n" +" -f sudoers podanie położenia pliku sudoers\n" +" -h wyświetlenie opisu i zakończenie\n" +" -q mniej obszerne (\"cichsze\") komunikaty o błędach składni\n" +" -s ścisłe sprawdzanie składni\n" +" -V wyświetlenie informacji o wersji i zakończenie" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "za dużo poziomów include" diff --git a/plugins/sudoers/po/sudoers.pot b/plugins/sudoers/po/sudoers.pot new file mode 100644 index 0000000..2208614 --- /dev/null +++ b/plugins/sudoers/po/sudoers.pot @@ -0,0 +1,1702 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr "" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:163 +msgid "" +"Account expired or PAM config lacks an \"account\" section for sudo, contact " +"your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "" + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "" +"Invalid authentication methods compiled into sudo! You may mix standalone " +"and non-standalone authentication." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "" +"There are no authentication methods compiled into sudo! If you want to turn " +"off authentication, use the --disable-authentication configure option." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "" +msgstr[1] "" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "" + +#: plugins/sudoers/def_data.c:303 +msgid "" +"Use faster globbing that is less accurate but does not access the filesystem" +msgstr "" + +#: plugins/sudoers/def_data.c:307 +msgid "" +"The umask specified in sudoers will override the user's, even if it is more " +"permissive" +msgstr "" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "" +"sorry, you are not allowed to set the following environment variables: %s" +msgstr "" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr "" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr "" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "" +"start_tls specified but LDAP libs do not support ldap_start_tls_s() or " +"ldap_start_tls_s_np()" +msgstr "" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr "" + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr "" + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr "" + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "" + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "" + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "" + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "" + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "" diff --git a/plugins/sudoers/po/sv.mo b/plugins/sudoers/po/sv.mo new file mode 100644 index 0000000..ea9c65a Binary files /dev/null and b/plugins/sudoers/po/sv.mo differ diff --git a/plugins/sudoers/po/sv.po b/plugins/sudoers/po/sv.po new file mode 100644 index 0000000..5236f75 --- /dev/null +++ b/plugins/sudoers/po/sv.po @@ -0,0 +1,1694 @@ +# Swedish translation for sudoers. +# Copyright (C) 2012 Free Software Foundation, Inc. +# This file is put in the public domain. +# Daniel Nylander , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5-b1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-03-14 14:20-0400\n" +"PO-Revision-Date: 2012-03-24 12:18+0100\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Aliaset \"%s\" är redan definierad" + +#: plugins/sudoers/bsm_audit.c:61 plugins/sudoers/bsm_audit.c:64 +#: plugins/sudoers/bsm_audit.c:113 plugins/sudoers/bsm_audit.c:117 +#: plugins/sudoers/bsm_audit.c:169 plugins/sudoers/bsm_audit.c:173 +msgid "getaudit: failed" +msgstr "getaudit: misslyckades" + +#: plugins/sudoers/bsm_audit.c:91 plugins/sudoers/bsm_audit.c:154 +msgid "Could not determine audit condition" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:102 +msgid "getauid failed" +msgstr "getauid misslyckades" + +#: plugins/sudoers/bsm_audit.c:104 plugins/sudoers/bsm_audit.c:163 +msgid "au_open: failed" +msgstr "au_open: misslyckades" + +#: plugins/sudoers/bsm_audit.c:119 plugins/sudoers/bsm_audit.c:175 +msgid "au_to_subject: failed" +msgstr "au_to_subject: misslyckades" + +#: plugins/sudoers/bsm_audit.c:123 plugins/sudoers/bsm_audit.c:179 +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: misslyckades" + +#: plugins/sudoers/bsm_audit.c:127 plugins/sudoers/bsm_audit.c:188 +msgid "au_to_return32: failed" +msgstr "au_to_return32: misslyckades" + +#: plugins/sudoers/bsm_audit.c:130 plugins/sudoers/bsm_audit.c:191 +msgid "unable to commit audit record" +msgstr "" + +#: plugins/sudoers/bsm_audit.c:161 +msgid "getauid: failed" +msgstr "getauid: misslyckades" + +#: plugins/sudoers/bsm_audit.c:184 +msgid "au_to_text: failed" +msgstr "au_to_text: misslyckades" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "tyvärr, ett lösenord krävs för att köra %s" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:970 plugins/sudoers/sudoreplay.c:348 +#: plugins/sudoers/sudoreplay.c:357 plugins/sudoers/sudoreplay.c:703 +#: plugins/sudoers/sudoreplay.c:797 plugins/sudoers/visudo.c:816 +#, c-format +msgid "unable to open %s" +msgstr "kunde inte öppna %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "kunde inte skriva till %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "kunde inte skapa katalogen %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "internt fel, stackspill i expand_prompt()" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s finns men är inte en katalog (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s ägs av uid %u, ska vara uid %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:989 +#: plugins/sudoers/visudo.c:320 plugins/sudoers/visudo.c:582 +#, c-format +msgid "unable to stat %s" +msgstr "kunde inte ta status på %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s finns men är inte en vanlig fil (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "tidsstämpeln är för långt in i framtiden: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:847 plugins/sudoers/sudoers.c:851 +#, c-format +msgid "unknown uid: %u" +msgstr "okänt uid: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:788 +#: plugins/sudoers/sudoers.c:1109 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "okänd användare: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Syslog-facilitet om syslog används för loggning: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Syslog-prioritet att använda när användaren lyckas med autentisering: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Syslog-prioritet att använda när användaren misslyckas med autentisering: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Ignorera \".\" i $PATH" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Skicka alltid e-post när sudo körs" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "Skicka e-post om användarens autentisering misslyckas" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "Skicka e-post om användaren inte finns med i sudoers" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "Skicka e-post om användaren inte finns med i sudoers för denna värddator" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "Skicka e-post om användaren inte tillåts att köra ett kommando" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Lär upp användaren första gången de kör sudo" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Fil som innehåller sudo-upplärning: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Kräv att användare autentiseras som standard" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Root får köra sudo" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Ställ in $HOME till målanvändaren när ett skal startas med -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Ställ alltid in $HOME till målanvändarens hemkatalog" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Förolämpa användaren när de anger ett felaktigt lösenord" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Fråga efter root-lösenordet, inte användarens" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Fråga efter runas_default-användarens lösenord, inte användarens" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Fråga efter målanvändarens lösenord, inte användarens" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Ställ in miljövariablerna LOGNAME och USER" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Antal försök att ange ett lösenord: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Umask att använda eller 0777 för att använda användarens: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Sökväg till loggfil: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Sökväg till e-postprogram: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Flaggor för e-postprogram: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Adress att skicka e-post till: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Adress att skicka e-post från: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Ämnesrad för e-postmeddelanden: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Meddelande vid felaktigt lösenord: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Miljövariabler att ta bort:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Miljövariabler att behålla:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Lokalanpassning att använda vid tolkning av sudoers: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "värdet \"%s\" är ogiltigt för flaggan \"%s\"" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "inget värde angivet för \"%s\"" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "värden för \"%s\" måste börja med ett \"/\"" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "flaggan \"%s\" tar inte emot något värde" + +#: plugins/sudoers/env.c:329 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "" + +#: plugins/sudoers/env.c:331 plugins/sudoers/env.c:401 toke.l:680 toke.l:810 +#: toke.l:868 toke.l:964 plugins/sudoers/toke_util.c:113 +#: plugins/sudoers/toke_util.c:167 plugins/sudoers/toke_util.c:207 +#, c-format +msgid "unable to allocate memory" +msgstr "kunde inte allokera minne" + +#: plugins/sudoers/env.c:356 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "internt fel, stackspill i sudo_setenv2()" + +#: plugins/sudoers/env.c:400 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "internt fel, stackspill i sudo_setenv()" + +#: plugins/sudoers/env.c:896 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 toke.l:676 +#: toke.l:864 plugins/sudoers/sudoers.c:941 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s nära rad %d <<<" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s måste ägas av uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s får endast vara skrivbar av ägaren" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "kunde inte köra dlopen %s: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "kunde inte hitta symbolen \"group_plugin\" i %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:977 +#, c-format +msgid "unable to read %s" +msgstr "kunde inte läsa %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "ogiltigt sekvensnummer %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "kunde inte skapa %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:367 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "kunde inte ställa in lokalanpassning till \"%s\", använder \"C\"" + +#: plugins/sudoers/ldap.c:374 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: port är för stor" + +#: plugins/sudoers/ldap.c:397 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:427 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:456 +#, c-format +msgid "invalid uri: %s" +msgstr "ogiltig uri: %s" + +#: plugins/sudoers/ldap.c:462 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "kunde inte blanda ldaps och starttls" + +#: plugins/sudoers/ldap.c:485 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "" + +#: plugins/sudoers/ldap.c:550 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "" + +#: plugins/sudoers/ldap.c:958 +#, c-format +msgid "unable to get GMT time" +msgstr "kunde inte få GMT-tid" + +#: plugins/sudoers/ldap.c:964 +#, c-format +msgid "unable to format timestamp" +msgstr "kunde inte formatera tidsstämpel" + +#: plugins/sudoers/ldap.c:972 +#, c-format +msgid "unable to build time filter" +msgstr "kunde inte bygga tidsfilter" + +#: plugins/sudoers/ldap.c:1187 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "" + +#: plugins/sudoers/ldap.c:1707 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP-roll: %s\n" + +#: plugins/sudoers/ldap.c:1709 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP-roll: OKÄND\n" + +#: plugins/sudoers/ldap.c:1756 +#, c-format +msgid " Order: %s\n" +msgstr " Ordning: %s\n" + +#: plugins/sudoers/ldap.c:1764 +#, c-format +msgid " Commands:\n" +msgstr " Kommandon:\n" + +#: plugins/sudoers/ldap.c:2163 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "kunde inte initiera LDAP: %s" + +#: plugins/sudoers/ldap.c:2194 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "" + +#: plugins/sudoers/ldap.c:2430 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "" + +#: toke.l:803 +msgid "too many levels of includes" +msgstr "" + +#: toke.l:827 plugins/sudoers/sudoers.c:995 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s ägs av uid %u, ska vara %u" + +#: toke.l:834 plugins/sudoers/sudoers.c:999 +#, c-format +msgid "%s is world writable" +msgstr "%s är skrivbar för alla" + +#: toke.l:839 plugins/sudoers/sudoers.c:1002 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s ägs av gid %u, ska vara %u" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "internt fel, stackspill i linux_audit_command()" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "kunde inte öppna loggfil: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "kunde inte låsa loggfil: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "användare finns INTE i sudoers" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "användaren är INTE auktoriserad på värddatorn" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "kommandot tillåts inte" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s finns inte i filen sudoers. Denna incident kommer att rapporteras.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s tillåts inte att köra sudo på %s. Denna incident kommer att rapporteras.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Tyvärr, användaren %s får inte köra sudo på %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Tyvärr, användaren %s tillåts inte att köra \"%s%s%s\" som %s%s%s på %s.\n" + +#: plugins/sudoers/logging.c:420 +#, c-format +msgid "unable to fork" +msgstr "kunde inte grena process" + +#: plugins/sudoers/logging.c:427 plugins/sudoers/logging.c:489 +#, c-format +msgid "unable to fork: %m" +msgstr "kunde inte grena process: %m" + +#: plugins/sudoers/logging.c:479 +#, c-format +msgid "unable to open pipe: %m" +msgstr "kunde inte öppna rör: %m" + +#: plugins/sudoers/logging.c:504 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "" + +#: plugins/sudoers/logging.c:540 +#, c-format +msgid "unable to execute %s: %m" +msgstr "kunde inte köra %s: %m" + +#: plugins/sudoers/logging.c:755 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "internt fel: otillräckligt utrymme för loggrad" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "tolkningsfel i %s nära rad %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "tolkningsfel i %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr "" + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr "" + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Kommandon:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "kunde inte mellanlagra uid %u (%s), finns redan" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "kunde inte mellanlagra uid %u, finns redan" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "kunde inte mellanlagra användaren %s, finns redan" + +#: plugins/sudoers/pwutil.c:655 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "kunde inte mellanlagra gid %u (%s), finns redan" + +#: plugins/sudoers/pwutil.c:663 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "kunde inte mellanlagra gid %u, finns redan" + +#: plugins/sudoers/pwutil.c:693 plugins/sudoers/pwutil.c:702 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "kunde inte mellanlagra gruppen %s, finns redan" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:439 +#: plugins/sudoers/set_perms.c:806 plugins/sudoers/set_perms.c:1095 +#: plugins/sudoers/set_perms.c:1380 +msgid "perm stack overflow" +msgstr "" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:447 +#: plugins/sudoers/set_perms.c:814 plugins/sudoers/set_perms.c:1103 +#: plugins/sudoers/set_perms.c:1388 +msgid "perm stack underflow" +msgstr "" + +#: plugins/sudoers/set_perms.c:272 plugins/sudoers/set_perms.c:585 +#: plugins/sudoers/set_perms.c:937 plugins/sudoers/set_perms.c:1226 +msgid "unable to change to runas gid" +msgstr "kunde inte ändra till runas gid" + +#: plugins/sudoers/set_perms.c:284 plugins/sudoers/set_perms.c:597 +#: plugins/sudoers/set_perms.c:947 plugins/sudoers/set_perms.c:1236 +msgid "unable to change to runas uid" +msgstr "kunde inte ändra till runas uid" + +#: plugins/sudoers/set_perms.c:302 plugins/sudoers/set_perms.c:615 +#: plugins/sudoers/set_perms.c:963 plugins/sudoers/set_perms.c:1252 +msgid "unable to change to sudoers gid" +msgstr "kunde inte ändra till sudoers gid" + +#: plugins/sudoers/set_perms.c:356 plugins/sudoers/set_perms.c:687 +#: plugins/sudoers/set_perms.c:1010 plugins/sudoers/set_perms.c:1299 +#: plugins/sudoers/set_perms.c:1461 +msgid "too many processes" +msgstr "för många processer" + +#: plugins/sudoers/set_perms.c:1529 +msgid "unable to set runas group vector" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Användaren %s får köra följande kommandon på denna värddator:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Användaren %s tillåts inte att köra sudo på %s.\n" + +#: plugins/sudoers/sudoers.c:206 plugins/sudoers/sudoers.c:237 +#: plugins/sudoers/sudoers.c:949 +msgid "problem with defaults entries" +msgstr "" + +#: plugins/sudoers/sudoers.c:210 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "inga giltiga sudoers-källor hittades, avslutar" + +#: plugins/sudoers/sudoers.c:262 +#, c-format +msgid "unable to execute %s: %s" +msgstr "kunde inte köra %s: %s" + +#: plugins/sudoers/sudoers.c:316 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers anger att root inte tillåts att använda sudo" + +#: plugins/sudoers/sudoers.c:323 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "du tillåts inte att använda flaggan -C" + +#: plugins/sudoers/sudoers.c:413 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "tidsstämpelägare (%s): Det finns ingen sådan användare" + +#: plugins/sudoers/sudoers.c:429 +msgid "no tty" +msgstr "ingen tty" + +#: plugins/sudoers/sudoers.c:430 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "tyvärr, du måste ha en tty för att köra sudo" + +#: plugins/sudoers/sudoers.c:469 +msgid "No user or host" +msgstr "Ingen användare eller värddator" + +#: plugins/sudoers/sudoers.c:483 plugins/sudoers/sudoers.c:504 +#: plugins/sudoers/sudoers.c:505 plugins/sudoers/sudoers.c:1516 +#: plugins/sudoers/sudoers.c:1517 +#, c-format +msgid "%s: command not found" +msgstr "%s: kommandot hittades inte" + +#: plugins/sudoers/sudoers.c:485 plugins/sudoers/sudoers.c:501 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"ignorerar \"%s\" som hittades i \".\"\n" +"Använd \"sudo ./%s\" om detta är den \"%s\" som du vill köra." + +#: plugins/sudoers/sudoers.c:490 +msgid "validation failure" +msgstr "valideringsfel" + +#: plugins/sudoers/sudoers.c:500 +msgid "command in current directory" +msgstr "kommando i aktuell katalog" + +#: plugins/sudoers/sudoers.c:512 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "tyvärr, du tillåts inte att behålla miljövariabler" + +#: plugins/sudoers/sudoers.c:672 plugins/sudoers/sudoers.c:679 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "internt fel, stackspill i runas_groups" + +#: plugins/sudoers/sudoers.c:932 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "internt fel, stackspill i set_cmnd()" + +#: plugins/sudoers/sudoers.c:992 +#, c-format +msgid "%s is not a regular file" +msgstr "%s är inte en vanlig fil" + +#: plugins/sudoers/sudoers.c:1039 +#, c-format +msgid "only root can use `-c %s'" +msgstr "endast root kan använda \"-c %s\"" + +#: plugins/sudoers/sudoers.c:1050 +#, c-format +msgid "unknown login class: %s" +msgstr "okänd inloggningsklass: %s" + +#: plugins/sudoers/sudoers.c:1078 +#, c-format +msgid "unable to resolve host %s" +msgstr "kunde inte slå upp värddatorn %s" + +#: plugins/sudoers/sudoers.c:1130 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "okänd grupp: %s" + +#: plugins/sudoers/sudoers.c:1179 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1181 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Sökväg till sudoers: %s\n" + +#: plugins/sudoers/sudoers.c:1188 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "Sökväg till nsswitch: %s\n" + +#: plugins/sudoers/sudoers.c:1190 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "Sökväg till ldap.conf: %s\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "Sökväg till ldap.secret: %s\n" + +#: plugins/sudoers/sudoreplay.c:286 +#, c-format +msgid "invalid filter option: %s" +msgstr "ogiltig filterflagga: %s" + +#: plugins/sudoers/sudoreplay.c:299 +#, c-format +msgid "invalid max wait: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:305 +#, c-format +msgid "invalid speed factor: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:308 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s version %s\n" + +#: plugins/sudoers/sudoreplay.c:333 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:339 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:364 +#, c-format +msgid "invalid log file %s" +msgstr "ogiltig loggfil %s" + +#: plugins/sudoers/sudoreplay.c:366 +#, c-format +msgid "Replaying sudo session: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:392 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:406 +#, c-format +msgid "invalid timing file line: %s" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:448 +#, c-format +msgid "writing to standard output" +msgstr "skriver till standard ut" + +#: plugins/sudoers/sudoreplay.c:480 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:529 plugins/sudoers/sudoreplay.c:554 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "tvetydigt uttryck \"%s\"" + +#: plugins/sudoers/sudoreplay.c:571 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:582 +#, c-format +msgid "unmatched ')' in expression" +msgstr "omatchat \")\" i uttryck" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "okänt sökvillkor \"%s\"" + +#: plugins/sudoers/sudoreplay.c:602 +#, c-format +msgid "%s requires an argument" +msgstr "%s kräver ett argument" + +#: plugins/sudoers/sudoreplay.c:606 +#, c-format +msgid "invalid regular expression: %s" +msgstr "ogiltigt reguljärt uttryck: %s" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "kunde inte tolka datumet \"%s\"" + +#: plugins/sudoers/sudoreplay.c:625 +#, c-format +msgid "unmatched '(' in expression" +msgstr "omatchat \"(\" i uttryck" + +#: plugins/sudoers/sudoreplay.c:627 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:629 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:851 +#, c-format +msgid "invalid regex: %s" +msgstr "ogiltigt reguljärt uttryck: %s" + +#: plugins/sudoers/sudoreplay.c:976 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "" + +#: plugins/sudoers/sudoreplay.c:979 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "användning: %s [-h] [-d katalog] -l [sökuttryck]\n" + +#: plugins/sudoers/sudoreplay.c:988 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - spela upp loggar från sudo-session\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:990 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "internt fel, stackspill i init_vars()" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Kommandot tillåts" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Kommandot nekades" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: buffertöverflöde" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "" + +#: plugins/sudoers/visudo.c:221 plugins/sudoers/auth/rfc1938.c:104 +#, c-format +msgid "you do not exist in the %s database" +msgstr "du finns inte i %s-databasen" + +#: plugins/sudoers/visudo.c:253 plugins/sudoers/visudo.c:539 +#, c-format +msgid "press return to edit %s: " +msgstr "tryck på return för att redigera %s: " + +#: plugins/sudoers/visudo.c:336 plugins/sudoers/visudo.c:342 +#, c-format +msgid "write error" +msgstr "skrivfel" + +#: plugins/sudoers/visudo.c:424 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:429 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "" + +#: plugins/sudoers/visudo.c:435 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "redigeraren (%s) misslyckades, %s är oförändrad" + +#: plugins/sudoers/visudo.c:458 +#, c-format +msgid "%s unchanged" +msgstr "%s oförändrad" + +#: plugins/sudoers/visudo.c:484 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "kunde inte återöppna temporärfilen (%s), %s är oförändrad." + +#: plugins/sudoers/visudo.c:494 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "kunde inte tolka temporärfilen (%s), okänt fel" + +#: plugins/sudoers/visudo.c:532 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "internt fel, kunde inte hitta %s i listan!" + +#: plugins/sudoers/visudo.c:584 plugins/sudoers/visudo.c:593 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "kunde inte ställa in (uid, gid) för %s till (%u, %u)" + +#: plugins/sudoers/visudo.c:588 plugins/sudoers/visudo.c:598 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "" + +#: plugins/sudoers/visudo.c:615 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s och %s finns inte på samma filsystem, använder mv för att byta namn" + +#: plugins/sudoers/visudo.c:629 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "kommandot misslyckades: \"%s %s %s\", %s är oförändrad" + +#: plugins/sudoers/visudo.c:639 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "fel vid namnbyte för %s, %s är oförändrad" + +#: plugins/sudoers/visudo.c:702 +msgid "What now? " +msgstr "Nu då? " + +#: plugins/sudoers/visudo.c:716 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Alternativen är:\n" +" r(e)digera sudoers-filen igen\n" +" avsluta (x) utan att spara ändringar i sudoers-filen\n" +" Avsluta (Q) och spara ändringar i sudoers-filen (FARLIGT!)\n" + +#: plugins/sudoers/visudo.c:757 +#, c-format +msgid "unable to execute %s" +msgstr "kunde inte köra %s" + +#: plugins/sudoers/visudo.c:764 +#, c-format +msgid "unable to run %s" +msgstr "kunde inte köra %s" + +#: plugins/sudoers/visudo.c:790 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: felaktig ägare (uid, gid) ska vara (%u, %u)\n" + +#: plugins/sudoers/visudo.c:797 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "" + +#: plugins/sudoers/visudo.c:822 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "misslyckades med att tolka %s-filen, okänt fel" + +#: plugins/sudoers/visudo.c:835 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "tolkningsfel i %s nära rad %d\n" + +#: plugins/sudoers/visudo.c:838 +#, c-format +msgid "parse error in %s\n" +msgstr "tolkningsfel i %s\n" + +#: plugins/sudoers/visudo.c:845 plugins/sudoers/visudo.c:850 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: tolkad OK\n" + +#: plugins/sudoers/visudo.c:897 +#, c-format +msgid "%s busy, try again later" +msgstr "%s är upptagen, försök igen senare" + +#: plugins/sudoers/visudo.c:941 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "angiven redigerare (%s) finns inte" + +#: plugins/sudoers/visudo.c:964 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "" + +#: plugins/sudoers/visudo.c:1012 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:1107 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1111 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "" + +#: plugins/sudoers/visudo.c:1246 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "" + +#: plugins/sudoers/visudo.c:1303 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - redigera sudoers-filen på ett säkert sätt\n" +"\n" + +#: plugins/sudoers/visudo.c:1305 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "kunde inte få inloggningsklass för användaren %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "ogiltig autentiseringstyp" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "kunde inte konfigurera autentiseringen" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "kunde inte ansluta till autentiseringsservern" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "förlorade kontakten med autentiseringsservern" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"fel i autentiseringsservern:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: kunde inte tolka \"%s\": %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: kunde inte allokera flaggor: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "kunde inte initiera PAM" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "kontovalidering misslyckades. Är ditt konto låst?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Kontot eller lösenordet har gått ut. Återställ ditt lösenord och försök igen" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Lösenordet har gått ut. Kontakta din systemadministratör" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "" + +#: plugins/sudoers/auth/pam.c:178 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:306 +msgid "Password: " +msgstr "Lösenord: " + +#: plugins/sudoers/auth/pam.c:307 +msgid "Password:" +msgstr "Lösenord:" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "misslyckades med att initiera ACE API-biblioteket" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "kunde inte kontakta SecurID-servern" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "ogiltig användarnamnslängd för SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "SecurID-kommunikation misslyckades" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "okänt SecurID-fel" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "ogiltig lösenordslängd för SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "kunde inte initiera SIA-session" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "" + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "Det finns inga autentiseringsmetoder inbyggda i sudo! Om du vill aktivera autentisering, använd konfigurationsflaggan --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d felaktigt lösenordsförsök" +msgstr[1] "%d felaktiga lösenordsförsök" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Autentiseringsmetoder:" diff --git a/plugins/sudoers/po/uk.mo b/plugins/sudoers/po/uk.mo new file mode 100644 index 0000000..764958c Binary files /dev/null and b/plugins/sudoers/po/uk.mo differ diff --git a/plugins/sudoers/po/uk.po b/plugins/sudoers/po/uk.po new file mode 100644 index 0000000..0f38803 --- /dev/null +++ b/plugins/sudoers/po/uk.po @@ -0,0 +1,1783 @@ +# Ukrainian translation for sudoers. +# This file is put in the public domain. +# +# Yuri Chornoivan , 2011, 2012. +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 12:00+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Lokalize 1.5\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s: %s поблизу рядка %d <<<" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "Замінник «%s» вже визначено" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "не вдалося отримати клас входу до системи для користувача %s" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "не вдалося розпочати розпізнавання за BSD" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "некоректний тип розпізнавання" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "не вдалося налаштувати розпізнавання" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "не вдалося прочитати налаштування fwtk" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "не вдалося встановити з’єднання з сервером розпізнавання" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "втрачено зв’язок з сервером розпізнавання" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"помилка сервера розпізнавання:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s: не вдалося зібрати princ ('%s'): %s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s: не вдалося обробити «%s»: %s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s: не вдалося визначити ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s: не вдалося розмістити параметри: %s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s: не вдалося отримати реєстраційні дані: %s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s: не вдалося ініціалізувати ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s: не вдалося зберегти реєстраційні дані у ccache: %s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s: не вдалося отримати реєстраційний запис вузла: %s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s: спроба перевірки TGT зазнала невдачі! Ймовірно, вас атаковано: %s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "не вдалося ініціалізувати PAM" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "помилка під час спроби перевірки облікового запису. Ваш обліковий запис заблоковано?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "Строк дії облікового запису або пароля збіг, визначте новий пароль і повторіть спробу" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok: %s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "Строк дії пароля збіг, зверніться до адміністратора вашої системи щодо поновлення пароля" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "Строк дії облікового запису збіг або у файлі налаштувань PAM немає розділу \"account\" для sudo. Повідомте про це адміністратора вашої системи." + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate: %s" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "Пароль: " + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "Пароль:" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "вас немає у базі даних %s" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "не вдалося ініціалізувати бібліотеку програмного інтерфейсу до ACE" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "не вдалося встановити зв’язок з сервером SecurID" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "Ідентифікатор користувача заблоковано для розпізнавання SecurID" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "некоректна довжина імені користувача для SecurID" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "некоректний дескриптор розпізнавання для SecurID" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "спроба обміну даними з SecurID зазнала невдачі" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "невідома помилка SecurID" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "некоректна довжина коду пароля для SecurID" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "не вдалося ініціалізувати сеанс SIA" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "sudo зібрано з підтримкою некоректних способів розпізнавання! Можливе змішування власних і зовнішніх способів розпізнавання." + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "sudo зібрано без можливостей з взаємодії з інструментами розпізнавання! Якщо ви хочете вимкнути розпізнавання, скористайтеся параметром налаштування --disable-authentication." + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d невдала спроба введення пароля" +msgstr[1] "%d невдалих спроби введення пароля" +msgstr[2] "%d невдалих спроб введення пароля" +msgstr[3] "одна невдала спроба введення пароля" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "Способи розпізнавання:" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit: помилка" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "Не вдалося визначити умови аудита" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "помилка getauid" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open: помилка" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject: помилка" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args: помилка" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32: помилка" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "не вдалося надіслати запис аудита" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid: помилка" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text: помилка" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "вибачте, для виконання %s слід вказати пароль" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "не вдалося відкрити %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "не вдалося виконати запис до %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "не вдалося створити каталог %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "внутрішня помилка, переповнення expand_prompt()" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "шлях часового штампа є занадто довгим: %s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s існує, але не є каталогом (0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "власником %s є uid %u, має бути uid %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s доступний до запису невласником (0%o), має бути встановлено режим 0700" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "не вдалося виконати stat для %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s існує, але не є звичайним файлом (0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s доступний до запису невласником (0%o), має бути встановлено режим 0600" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "занадто далекий часовий штамп у майбутньому: %20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "на вдалося вилучити %s (%s), час буде змінено відповідно до епохи" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "не вдалося встановити для %s час епохи" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "невідоме значення uid: %u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "невідомий користувач: %s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "Інструмент ведення журналу, якщо використано syslog: %s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "Пріоритетність, яка використовуватиметься у syslog для успішних розпізнавань: %s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "Пріоритетність, яка використовуватиметься у syslog для неуспішних розпізнавань: %s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "Розташовувати запит щодо OTP у окремому рядку" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "Ігнорувати «.» у $PATH" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "Завжди надсилати листа, коли викликано sudo" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "Надсилати листа, якщо користувачу не вдалося пройти розпізнавання" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "Надсилати листа, якщо користувача немає серед sudoers" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "Надсилати листа, якщо користувача немає у списку sudoers цього вузла" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "Надсилати листа, якщо користувачеві заборонено виконувати команду" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "Окремий часовий штамп для кожної комбінації користувач/tty" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "Показувати настанови користувачеві під час першого запуску sudo" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "Файл з настановами щодо sudo: %s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "Типово, вимагати розпізнавання" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "Root може виконувати sudo" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "Записувати назву вузла до файла журналу (не syslog)" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "Записувати рік до файла журналу (не syslog)" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "Якщо sudo викликано без параметрів, запускати командну оболонку" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "Встановлювати $HOME відповідно до вказаного користувача для запуску оболонки з -s" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "Завжди встановлювати значенням $HOME домашній каталог вказаного користувача" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "Дозволити збирання даних з метою формування зрозумілих повідомлень про помилки" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "У файлі sudoers слід вказати повні назви вузлів" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "Знущатися з користувача, якщо введено помилковий пароль" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "Дозволяти користувачеві виконувати sudo, лише якщо з ним пов’язано tty" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo зважатимwill honor the EDITOR environment variable" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "Надсилати запит на пароль root, а не користувача" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "Надсилати запит щодо пароля runas_default, але пароля самого користувача" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "Надсилати запит щодо пароля потрібного користувача, але пароля самого користувача" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "Застосовувати типові параметри у класі вказаного користувача, якщо такий клас є" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "Встановити значення змінних середовища LOGNAME і USER" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "Встановлювати для потрібного користувача ефективний uid, а не справжній uid" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "Не ініціалізувати вектор групи відповідно до вказаного користувача" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "Позиція, на якій слід переносити рядки файла журналу (0 — без перенесення): %d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "Час очікування на часовий штамп розпізнавання: %.1f хвилина" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "Час очікування на введення пароля: %.1f хвилина" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "Кількість спроб введення пароля: %d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "Потрібне значення umask або 0777 для користувачевого: 0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "Шлях до файла журналу: %s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "Шлях до програми ел. пошти: %s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "Параметри програми ел. пошти: %s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "Адреса, на яку надсилатимуться листи: %s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "Адреса, з якої надсилатимуться листи: %s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "Тема листів: %s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "Повідомлення про помилковий пароль: %s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "Шлях до каталогу часових штампів розпізнавання: %s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "Власник каталогу часових штампів розпізнавання: %s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "Користувачів цієї групи звільнено від потреби у введенні пароля і PATH: %s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "Типовий запит пароля: %s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "Якщо встановлено, запит щодо паролю замінюватиме запит системи." + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "Типовий користувач для запуску команд: %s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "Значення для заміни $PATH користувача: %s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "Шлях до редактора, який використовуватиме visudo: %s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "Умови запиту пароля для псевдокоманди «list»: %s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "Умови запиту пароля для псевдокоманди «verify»: %s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "Попередньо завантажувати фіктивні функції виконання з бібліотеки sudo_noexec" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "Чи слід ігнорувати локальний файл sudoers, якщо є доступ до каталогу LDAP" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr "Дескриптори файлів >= %d буде закрито перед виконанням команди" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "Якщо встановлено, користувачі можуть перевизначати значення «closefrom» за допомогою параметра -C" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "Дозволити користувачам встановлювати значення довільних змінних середовища" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "Відновити типовий набір змінних середовища" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "Змінні середовища, коректність яких слід перевіряти:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "Змінні середовища, які слід вилучити:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "Змінні середовища, які слід зберегти:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "Роль SELinux, яку слід використати у новому контексті захисту: %s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "Тип SELinux, який слід використати у новому контексті захисту: %s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "Шлях до специфічного для sudo файла середовища: %s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "Локаль, яку слід використати під час обробки sudoers: %s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "Дозволити sudo надсилати запит щодо пароля, навіть якщо цей пароль буде видимим" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "Супроводжувати введення користувачем пароля показом замінників символів пароля" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "Швидше встановлення відповідності, менш точне, але без доступу до файлової системи" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "Значення umask, вказане у sudoers, перевизначатиме значення користувача, навіть якщо це значення відкриває ширший доступ" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "Записувати дані, вказані користувачем під час виконання команди" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "Записувати дані, виведені командою під час виконання" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "Стискати журнали за допомогою zlib" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "Завжди запускати команди у псевдо-tty" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "Додаток для підтримки не-Unix груп: %s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "Каталог, у якому слід зберігати журнали введення/виведення: %s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "Файл, у якому слід зберігати журнал введення/виведення даних: %s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "Додати запис до файла utmp/utmpx під час розміщення pty" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "Встановити користувача у utmp у значення користувача, від імені якого виконується команда" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "невідомий запис типових параметрів «%s»" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "значення «%s» є некоректним для параметра «%s»" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "не вказано значення для «%s»" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "значення для «%s» має починатися з «/»" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "параметру «%s» не потрібно передавати значення" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv: помилкове значення envp, невідповідність довжин" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "не вдалося отримати потрібний об’єм пам’яті" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "внутрішня помилка, переповнення sudo_setenv2()" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "внутрішня помилка, переповнення sudo_setenv()" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "вибачте, вам не дозволено встановлювати такі змінні середовища: %s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s має належати користувачеві з uid %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s має бути доступним до запису лише для власника" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "не вдалося виконати dlopen для %s: %s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "не вдалося знайти символ «group_plugin» у %s" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s: несумісна основна версія додатка обробки груп %d, мало бути — %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "Пари локальних IP-адрес і масок мережі:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "не вдалося прочитати %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "некоректний номер у послідовності %s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "не вдалося створити %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "не вдалося встановити локаль у значення «%s», використовуємо локаль «C»" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports: занадто великий номер порту" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports: вихід за межі розширеного буфера вузла" + +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "непідтримуваний тип адреси LDAP: %s" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "некоректна адреса: %s" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "не можна використовувати суміш з адрес ldap і ldaps" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "не можна використовувати суміш з ldaps і starttls" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri: вихід за межі пам’яті під час побудови буфера вузла" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "не вдалося ініціалізувати базу даних сертифікатів і ключів SSL: %s" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "щоб скористатися SSL, вам слід встановити для TLS_CERT значення %s" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "не вдалося отримати гринвіцький час" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "не вдалося виконати форматування часового штампа" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "не вдалося побудувати фільтр часу" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "sudo_ldap_build_pass1: невідповідність розміщення" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"Роль LDAP: %s\n" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"Роль у LDAP: НЕВІДОМА\n" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr " Порядок: %s\n" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr " Команди:\n" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "не вдалося ініціалізувати LDAP: %s" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "start_tls вказано, але у бібліотеках LDAP не передбачено підтримки ldap_start_tls_s() або ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "некоректний атрибут sudoOrder: %s" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "не вдалося відкрити систему аудита" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "внутрішня помилка, переповнення linux_audit_command()" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "не вдалося надіслати повідомлення аудита" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "не вдалося відкрити файл журналу: %s: %s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "не вдалося заблокувати файл журналу: %s: %s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "користувача немає у списку sudoers" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "користувача не уповноважено на дії на вузлі" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "виконання команди заборонено" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s немає у файлі sudoers. Запис про подію додано до звіту.\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s заборонено виконувати sudo на %s. Запис про подію додано до звіту.\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "Вибачте, користувач %s не має права виконувати sudo на %s.\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "Вибачте, користувач %s не має права виконувати «%s%s%s» від імені %s%s%s на %s.\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "не вдалося створити відгалуження" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "не вдалося створити відгалуження: %m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "не вдалося відкрити канал: %m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "не вдалося здублювати stdin: %m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "не вдалося виконати %s: %m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "внутрішня помилка: недостатньо місця для рядка журналу" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "помилка обробки у %s поблизу рядка %d" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "помилка обробки у %s" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Запис sudoers:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " Користувачі для запуску: " + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " Групи для запуску: " + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" Команди:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ": " + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "не вдалося кешувати uid %u (%s), запис вже існує" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "не вдалося кешувати uid %u, запис вже існує" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "не вдалося кешувати користувача %s, запис вже існує" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "не вдалося кешувати gid %u (%s), запис вже існує" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "не вдалося кешувати gid %u, запис вже існує" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "не вдалося кешувати групу %s, запис вже існує" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "переповнення стека доступу" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "вичерпання стека доступу" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "не вдалося змінити gid на runas" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "не вдалося змінити uid на runas" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "не вдалося змінити gid на sudoers" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "забагато процесів" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "не вдалося встановити вектор групи виконання" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "Відповідність записів Defaults для %s на цьому вузлі:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "Типові значення для запуску від імені і команд для %s:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "Користувач %s має право виконувати на цьому вузлі такі команди:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "Користувач %s не має права виконувати sudo на %s.\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "проблема з типовими записами" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "не знайдено коректних джерел даних sudoers, завершення роботи" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "не вдалося виконати %s: %s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers вказує, що sudo не можна користуватися для виконання команд від root" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "вам не дозволено використовувати параметр -C" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "власник часового штампа (%s): не знайдено користувача з таким іменем" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "немає tty" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "вибачте, для виконання sudo вашому користувачеві потрібен tty" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "Немає користувача або вузла" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s: команду не знайдено" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"пропущено «%s» знайдений у «.»\n" +"Скористайтеся командою «sudo ./%s», якщо вам потрібно виконати саме «%s»." + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "помилка під час спроби перевірки" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "команда у поточному каталозі" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "вибачте, вам не дозволено зберігати середовище" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "внутрішня помилка, переповнення runas_groups" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "внутрішня помилка, переповнення set_cmnd()" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s не є звичайним файлом" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s належить uid %u, має належати %u" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "Запис до «%s» можливий для довільного користувача" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s належить gid %u, має належати %u" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "використовувати «-c %s» може лише root" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "невідомий клас входу: %s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "не вдалося визначити адресу вузла %s" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "невідома група: %s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Додаток правил sudoers версії %s\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Граматична перевірка файла sudoers версії %d\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Шлях до sudoers: %s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "Шлях до nsswitch: %s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "Шлях до ldap.conf: %s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "Шлях до ldap.secret: %s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "некоректний параметр фільтрування: %s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "некоректне значення макс. очікування: %s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "некоректний коефіцієнт швидкості: %s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s, версія %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/timing: %s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/timing: %s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "Відтворення сеансу sudo: %s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "Попередження: розміри вашого термінала є замалими для належного показу журналу.\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "Встановлено формат журналу %d x %d, тоді як формат термінала — %d x %d." + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "не вдалося перевести tty у режим без обробки даних" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "некоректний рядок у файлі timing: %s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "запис до стандартного виводу даних" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep: tv_sec %ld, tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "неоднозначний вираз «%s»" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "забагато виразів у дужках, максимальна можлива кількість — %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "зайва дужка, «)», у виразі" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "невідомий ключ пошуку «%s»" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s потребує визначення аргументу" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "некоректний формальний вираз: %s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "не вдалося обробити дату «%s»" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "зайва дужка, «(», у виразі" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "помилкове завершальне «or»" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "помилкове завершальне «!»" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "некоректний формальний вираз: %s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "використання: %s [-h] [-d каталог] [-m макс_очік] [-s коеф_швидкості] ідентифікатор\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "використання: %s [-h] [-d каталог] -l [вираз для пошуку]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s — відтворення журналів сеансів sudo\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"Параметри:\n" +" -d каталог вказати каталог для журналів сеансу\n" +" -f фільтр вказати, який тип вводу-виводу слід показувати\n" +" -h показати довідкове повідомлення і завершити роботу\n" +" -l [вираз] показати список можливих ідентифікаторів сеансів, відповідних до виразу\n" +" -m макс_очік максимальний час (у секундах) очікування між подіями\n" +" -s коеф_швидк коефіцієнт прискорення або сповільнення виводу даних\n" +" -V показати дані щодо версії і завершити роботу" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "внутрішня помилка, переповнення init_vars()" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\tвідповідника вузла не знайдено" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"Команду дозволено" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"Команду заборонено" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"Не знайдено відповідника команди" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args: переповнення буфера" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "Граматична перевірка %s, версія %d\n" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "натисніть Enter для редагування %s: " + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "помилка запису" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "не вдалося обробити stat файл тимчасових даних (%s), %s не змінено" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "файл тимчасових даних має нульовий об’єм (%s), %s не змінено" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "помилка редактора (%s), %s не змінено" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s не змінено" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "не вдалося повторно відкрити файл тимчасових даних (%s), %s не змінено." + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "не вдалося обробити файл тимчасових даних (%s), невідома помилка" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "внутрішня помилка, не вдалося знайти %s у списку!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "не вдалося встановити (uid, gid) %s у значення (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "не вдалося змінити режим доступу до %s на значення 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s і %s не перебувають у одній файловій системі, використовуємо mv для перейменування" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "помилка команди: «%s %s %s», %s не змінено" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "помилка перейменування %s, %s не змінено" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "А зараз що? " + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"Параметри:\n" +" (e) — повторне редагування файла sudoers\n" +" (x) — вийти без внесення змін до файла sudoers\n" +" (Q) — вийти зі збереженням файла sudoers (НЕБЕЗПЕЧНО!)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "не вдалося виконати %s" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "не вдалося виконати %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s: помилковий власник (uid, gid), має бути (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s: помилкові права доступу, режим доступу має бути 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "не вдалося обробити файл %s, невідома помилка" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "помилка обробки у %s поблизу рядка %d\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "помилка обробки у %s\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s: вдала обробка\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s зайнято, повторіть спробу пізніше" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "вказаного редактора (%s) не існує" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "не вдалося виконати stat для редактора (%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "не знайдено жодного редактора (шлях до редактора = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "Помилка: цикл у %s_Alias «%s»" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "Попередження: цикл у %s_Alias «%s»" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "Помилка: виявлено посилання %s_Alias «%s», яке не визначено" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "Попередження: виявлено посилання %s_Alias «%s», яке не визначено" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s: невикористаний %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s — безпечне редагування файла sudoers\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"Параметри:\n" +" -c режим лише перевірки\n" +" -f sudoers вказати розташування файла sudoers\n" +" -h показати довідкове повідомлення і завершити роботу\n" +" -q стислі повідомлення щодо синтаксичних помилок\n" +" -s строга перевірка синтаксису\n" +" -V показати дані щодо версії і завершити роботу" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "занадто високий рівень вкладеності" + +#~ msgid "invalid log file %s" +#~ msgstr "некоректний файл журналу %s" + +#~ msgid "fixed mode on %s" +#~ msgstr "виправлено режим на %s" + +#~ msgid "set group on %s" +#~ msgstr "встановлено групу у %s" + +#~ msgid "unable to set group on %s" +#~ msgstr "не вдалося встановити групу на %s" + +#~ msgid "unable to fix mode on %s" +#~ msgstr "не вдалося виправити режим на %s" + +#~ msgid "%s is mode 0%o, should be 0%o" +#~ msgstr "%s має режим доступу 0%o, має бути 0%o" + +#~ msgid "File containing dummy exec functions: %s" +#~ msgstr "Файл, що містить фіктивні функції виконання: %s" + +#~ msgid "" +#~ "Available options in a sudoers ``Defaults'' line:\n" +#~ "\n" +#~ msgstr "" +#~ "Можливі параметри у рядку «Defaults» sudoers:\n" +#~ "\n" + +#~ msgid "%s: %s\n" +#~ msgstr "%s: %s\n" + +#~ msgid "%s: %.*s\n" +#~ msgstr "%s: %.*s\n" + +#~ msgid "unable to get runas group vector" +#~ msgstr "не вдалося отримати вектор групи виконання" + +#~ msgid "unable to reset group vector" +#~ msgstr "не вдалося відновити початкове значення вектора групи" + +#~ msgid "unable to get group vector" +#~ msgstr "не вдалося отримати вектор групи" + +#~ msgid "%s: %s_Alias `%s' references self" +#~ msgstr "%s: %s_Alias «%s» рекурсивно посилається на себе" diff --git a/plugins/sudoers/po/zh_CN.mo b/plugins/sudoers/po/zh_CN.mo new file mode 100644 index 0000000..505ccd3 Binary files /dev/null and b/plugins/sudoers/po/zh_CN.mo differ diff --git a/plugins/sudoers/po/zh_CN.po b/plugins/sudoers/po/zh_CN.po new file mode 100644 index 0000000..1cb750c --- /dev/null +++ b/plugins/sudoers/po/zh_CN.po @@ -0,0 +1,1780 @@ +# Chinese simplified translation for sudoers. +# This file is put in the public domain. +# Wylmer Wang , 2011, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudoers 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 17:01+0800\n" +"Last-Translator: Wylmer Wang \n" +"Language-Team: Chinese (simplified) \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: gram.y:110 +#, c-format +msgid ">>> %s: %s near line %d <<<" +msgstr ">>> %s:%s 在行 %d 附近<<<" + +#: plugins/sudoers/alias.c:125 +#, c-format +msgid "Alias `%s' already defined" +msgstr "别名“%s”已定义" + +#: plugins/sudoers/auth/bsdauth.c:78 +#, c-format +msgid "unable to get login class for user %s" +msgstr "无法获取用户 %s 的登录类别(login class)" + +#: plugins/sudoers/auth/bsdauth.c:84 +msgid "unable to begin bsd authentication" +msgstr "无法开始 bsd 认证" + +#: plugins/sudoers/auth/bsdauth.c:92 +msgid "invalid authentication type" +msgstr "无效的认证类型" + +#: plugins/sudoers/auth/bsdauth.c:101 +msgid "unable to setup authentication" +msgstr "无法设置认证" + +#: plugins/sudoers/auth/fwtk.c:60 +#, c-format +msgid "unable to read fwtk config" +msgstr "无法读取 fwtk 配置" + +#: plugins/sudoers/auth/fwtk.c:65 +#, c-format +msgid "unable to connect to authentication server" +msgstr "无法连接到认证服务器" + +#: plugins/sudoers/auth/fwtk.c:71 plugins/sudoers/auth/fwtk.c:95 +#: plugins/sudoers/auth/fwtk.c:128 +#, c-format +msgid "lost connection to authentication server" +msgstr "丢失了到认证服务器的连接" + +#: plugins/sudoers/auth/fwtk.c:75 +#, c-format +msgid "" +"authentication server error:\n" +"%s" +msgstr "" +"认证服务器错误:\n" +"%s" + +#: plugins/sudoers/auth/kerb5.c:117 +#, c-format +msgid "%s: unable to unparse princ ('%s'): %s" +msgstr "%s:无法解析 princ(“%s”):%s" + +#: plugins/sudoers/auth/kerb5.c:160 +#, c-format +msgid "%s: unable to parse '%s': %s" +msgstr "%s:无法解析“%s”:%s" + +#: plugins/sudoers/auth/kerb5.c:170 +#, c-format +msgid "%s: unable to resolve ccache: %s" +msgstr "%s:无法解析 ccache:%s" + +#: plugins/sudoers/auth/kerb5.c:218 +#, c-format +msgid "%s: unable to allocate options: %s" +msgstr "%s:无法分配选项:%s" + +#: plugins/sudoers/auth/kerb5.c:234 +#, c-format +msgid "%s: unable to get credentials: %s" +msgstr "%s:无法获取凭据:%s" + +#: plugins/sudoers/auth/kerb5.c:247 +#, c-format +msgid "%s: unable to initialize ccache: %s" +msgstr "%s:无法初始化 ccache:%s" + +#: plugins/sudoers/auth/kerb5.c:251 +#, c-format +msgid "%s: unable to store cred in ccache: %s" +msgstr "%s:无法在 ccache 中储存凭据:%s" + +#: plugins/sudoers/auth/kerb5.c:316 +#, c-format +msgid "%s: unable to get host principal: %s" +msgstr "%s:无法获取主机主体(principal):%s" + +#: plugins/sudoers/auth/kerb5.c:331 +#, c-format +msgid "%s: Cannot verify TGT! Possible attack!: %s" +msgstr "%s:无法验证目标!可能遭到了攻击!:%s" + +#: plugins/sudoers/auth/pam.c:100 +msgid "unable to initialize PAM" +msgstr "无法初始化 PAM" + +#: plugins/sudoers/auth/pam.c:144 +msgid "account validation failure, is your account locked?" +msgstr "账户验证失败,您的账户是不是上锁了?" + +#: plugins/sudoers/auth/pam.c:148 +msgid "Account or password is expired, reset your password and try again" +msgstr "账户或密码过期,重置您的密码并重试" + +#: plugins/sudoers/auth/pam.c:155 +#, c-format +msgid "pam_chauthtok: %s" +msgstr "pam_chauthtok:%s" + +#: plugins/sudoers/auth/pam.c:159 +msgid "Password expired, contact your system administrator" +msgstr "密码过期,联系您的系统管理员" + +#: plugins/sudoers/auth/pam.c:163 +msgid "Account expired or PAM config lacks an \"account\" section for sudo, contact your system administrator" +msgstr "账户过期,或 PAM 配置缺少 sudo 使用的“account”节,联系您的系统管理员" + +#: plugins/sudoers/auth/pam.c:180 +#, c-format +msgid "pam_authenticate: %s" +msgstr "pam_authenticate:%s" + +#: plugins/sudoers/auth/pam.c:332 +msgid "Password: " +msgstr "密码:" + +#: plugins/sudoers/auth/pam.c:333 +msgid "Password:" +msgstr "密码:" + +#: plugins/sudoers/auth/rfc1938.c:104 plugins/sudoers/visudo.c:220 +#, c-format +msgid "you do not exist in the %s database" +msgstr "%s 数据库中没有您" + +#: plugins/sudoers/auth/securid5.c:81 +#, c-format +msgid "failed to initialise the ACE API library" +msgstr "初始化 ACE API 库失败" + +#: plugins/sudoers/auth/securid5.c:107 +#, c-format +msgid "unable to contact the SecurID server" +msgstr "无法联络 SecurID 服务器" + +#: plugins/sudoers/auth/securid5.c:116 +#, c-format +msgid "User ID locked for SecurID Authentication" +msgstr "为进行 SecurID 认证,已锁定用户 ID" + +#: plugins/sudoers/auth/securid5.c:120 plugins/sudoers/auth/securid5.c:171 +#, c-format +msgid "invalid username length for SecurID" +msgstr "SecurID 的用户名长度无效" + +#: plugins/sudoers/auth/securid5.c:124 plugins/sudoers/auth/securid5.c:176 +#, c-format +msgid "invalid Authentication Handle for SecurID" +msgstr "SecurID 的认证句柄无效" + +#: plugins/sudoers/auth/securid5.c:128 +#, c-format +msgid "SecurID communication failed" +msgstr "SecurID 通讯失败" + +#: plugins/sudoers/auth/securid5.c:132 plugins/sudoers/auth/securid5.c:215 +#, c-format +msgid "unknown SecurID error" +msgstr "未知的 SecurID 错误" + +#: plugins/sudoers/auth/securid5.c:166 +#, c-format +msgid "invalid passcode length for SecurID" +msgstr "无效的 SecurID 密码长度" + +#: plugins/sudoers/auth/sia.c:109 +msgid "unable to initialize SIA session" +msgstr "无法初始化 SIA 会话" + +#: plugins/sudoers/auth/sudo_auth.c:117 +msgid "Invalid authentication methods compiled into sudo! You may mix standalone and non-standalone authentication." +msgstr "编译进 sudo 的认证方法无效!您可能混用了独立和非独立认证。" + +#: plugins/sudoers/auth/sudo_auth.c:199 +msgid "There are no authentication methods compiled into sudo! If you want to turn off authentication, use the --disable-authentication configure option." +msgstr "sudo 编译时没有加入任何认证方法!如果您想关闭认证,使用 --disable-authentication 配置选项。" + +#: plugins/sudoers/auth/sudo_auth.c:271 +#, c-format +msgid "%d incorrect password attempt" +msgid_plural "%d incorrect password attempts" +msgstr[0] "%d 次错误密码尝试" + +#: plugins/sudoers/auth/sudo_auth.c:374 +msgid "Authentication methods:" +msgstr "认证方法:" + +#: plugins/sudoers/bsm_audit.c:60 plugins/sudoers/bsm_audit.c:63 +#: plugins/sudoers/bsm_audit.c:112 plugins/sudoers/bsm_audit.c:116 +#: plugins/sudoers/bsm_audit.c:168 plugins/sudoers/bsm_audit.c:172 +#, c-format +msgid "getaudit: failed" +msgstr "getaudit:失败" + +#: plugins/sudoers/bsm_audit.c:90 plugins/sudoers/bsm_audit.c:153 +#, c-format +msgid "Could not determine audit condition" +msgstr "无法确定审核条件" + +#: plugins/sudoers/bsm_audit.c:101 +#, c-format +msgid "getauid failed" +msgstr "getauid 失败" + +#: plugins/sudoers/bsm_audit.c:103 plugins/sudoers/bsm_audit.c:162 +#, c-format +msgid "au_open: failed" +msgstr "au_open:失败" + +#: plugins/sudoers/bsm_audit.c:118 plugins/sudoers/bsm_audit.c:174 +#, c-format +msgid "au_to_subject: failed" +msgstr "au_to_subject:失败" + +#: plugins/sudoers/bsm_audit.c:122 plugins/sudoers/bsm_audit.c:178 +#, c-format +msgid "au_to_exec_args: failed" +msgstr "au_to_exec_args:失败" + +#: plugins/sudoers/bsm_audit.c:126 plugins/sudoers/bsm_audit.c:187 +#, c-format +msgid "au_to_return32: failed" +msgstr "au_to_return32:失败" + +#: plugins/sudoers/bsm_audit.c:129 plugins/sudoers/bsm_audit.c:190 +#, c-format +msgid "unable to commit audit record" +msgstr "无法提交审核记录" + +#: plugins/sudoers/bsm_audit.c:160 +#, c-format +msgid "getauid: failed" +msgstr "getauid:失败" + +#: plugins/sudoers/bsm_audit.c:183 +#, c-format +msgid "au_to_text: failed" +msgstr "au_to_text:失败" + +#: plugins/sudoers/check.c:158 +#, c-format +msgid "sorry, a password is required to run %s" +msgstr "抱歉,执行 %s 需要密码" + +#: plugins/sudoers/check.c:249 plugins/sudoers/iolog.c:172 +#: plugins/sudoers/sudoers.c:979 plugins/sudoers/sudoreplay.c:353 +#: plugins/sudoers/sudoreplay.c:709 plugins/sudoers/sudoreplay.c:866 +#: plugins/sudoers/visudo.c:815 +#, c-format +msgid "unable to open %s" +msgstr "无法打开 %s" + +#: plugins/sudoers/check.c:253 plugins/sudoers/iolog.c:202 +#, c-format +msgid "unable to write to %s" +msgstr "无法写入 %s" + +#: plugins/sudoers/check.c:261 plugins/sudoers/check.c:506 +#: plugins/sudoers/check.c:556 plugins/sudoers/iolog.c:123 +#: plugins/sudoers/iolog.c:156 +#, c-format +msgid "unable to mkdir %s" +msgstr "无法创建目录 %s" + +#: plugins/sudoers/check.c:396 +#, c-format +msgid "internal error, expand_prompt() overflow" +msgstr "内部错误,expand_prompt() 溢出" + +#: plugins/sudoers/check.c:456 +#, c-format +msgid "timestamp path too long: %s" +msgstr "时间戳路径过长:%s" + +#: plugins/sudoers/check.c:485 plugins/sudoers/check.c:529 +#: plugins/sudoers/iolog.c:158 +#, c-format +msgid "%s exists but is not a directory (0%o)" +msgstr "%s 存在,但不是目录(0%o)" + +#: plugins/sudoers/check.c:488 plugins/sudoers/check.c:532 +#: plugins/sudoers/check.c:577 +#, c-format +msgid "%s owned by uid %u, should be uid %u" +msgstr "%s 属于用户 ID %u,应为用户 ID %u" + +#: plugins/sudoers/check.c:493 plugins/sudoers/check.c:537 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0700" +msgstr "%s 对非所有者可写(0%o),模式应该为 0700" + +#: plugins/sudoers/check.c:501 plugins/sudoers/check.c:545 +#: plugins/sudoers/check.c:613 plugins/sudoers/sudoers.c:998 +#: plugins/sudoers/visudo.c:319 plugins/sudoers/visudo.c:581 +#, c-format +msgid "unable to stat %s" +msgstr "无法 stat %s" + +#: plugins/sudoers/check.c:571 +#, c-format +msgid "%s exists but is not a regular file (0%o)" +msgstr "%s 存在,但不是常规文件(0%o)" + +#: plugins/sudoers/check.c:583 +#, c-format +msgid "%s writable by non-owner (0%o), should be mode 0600" +msgstr "%s 对非所有者可写(0%o),模式应该为 0600" + +#: plugins/sudoers/check.c:637 +#, c-format +msgid "timestamp too far in the future: %20.20s" +msgstr "时间戳太超前:%20.20s" + +#: plugins/sudoers/check.c:684 +#, c-format +msgid "unable to remove %s (%s), will reset to the epoch" +msgstr "无法移除 %s (%s),将重设为戳记" + +#: plugins/sudoers/check.c:692 +#, c-format +msgid "unable to reset %s to the epoch" +msgstr "无法将 %s 重设为戳记" + +#: plugins/sudoers/check.c:752 plugins/sudoers/check.c:758 +#: plugins/sudoers/sudoers.c:856 plugins/sudoers/sudoers.c:860 +#, c-format +msgid "unknown uid: %u" +msgstr "未知的用户 ID:%u" + +#: plugins/sudoers/check.c:755 plugins/sudoers/sudoers.c:797 +#: plugins/sudoers/sudoers.c:1115 plugins/sudoers/testsudoers.c:218 +#: plugins/sudoers/testsudoers.c:362 +#, c-format +msgid "unknown user: %s" +msgstr "未知用户:%s" + +#: plugins/sudoers/def_data.c:27 +#, c-format +msgid "Syslog facility if syslog is being used for logging: %s" +msgstr "若使用了 syslog,用于记录日志的 syslog 设施:%s" + +#: plugins/sudoers/def_data.c:31 +#, c-format +msgid "Syslog priority to use when user authenticates successfully: %s" +msgstr "用户认证成功时使用的 syslog 优先级:%s" + +#: plugins/sudoers/def_data.c:35 +#, c-format +msgid "Syslog priority to use when user authenticates unsuccessfully: %s" +msgstr "用户认证不成功时使用的 syslog 优先级:%s" + +#: plugins/sudoers/def_data.c:39 +msgid "Put OTP prompt on its own line" +msgstr "将 OPT 提示放在独自的行中" + +#: plugins/sudoers/def_data.c:43 +msgid "Ignore '.' in $PATH" +msgstr "忽略 $PATH 中的“.”" + +#: plugins/sudoers/def_data.c:47 +msgid "Always send mail when sudo is run" +msgstr "在运行 sudo 时总是发送邮件" + +#: plugins/sudoers/def_data.c:51 +msgid "Send mail if user authentication fails" +msgstr "在用户认证失败时发送邮件" + +#: plugins/sudoers/def_data.c:55 +msgid "Send mail if the user is not in sudoers" +msgstr "在用户不在 sudoers 列表中时发送邮件" + +#: plugins/sudoers/def_data.c:59 +msgid "Send mail if the user is not in sudoers for this host" +msgstr "在用户不在此主机的 sudoers 列表中时发送邮件" + +#: plugins/sudoers/def_data.c:63 +msgid "Send mail if the user is not allowed to run a command" +msgstr "在用户不允许执行某个命令时发送邮件" + +#: plugins/sudoers/def_data.c:67 +msgid "Use a separate timestamp for each user/tty combo" +msgstr "对每个用户/终端组合使用独立的时间戳" + +#: plugins/sudoers/def_data.c:71 +msgid "Lecture user the first time they run sudo" +msgstr "在用户第一次运行 sudo 时向他致辞" + +#: plugins/sudoers/def_data.c:75 +#, c-format +msgid "File containing the sudo lecture: %s" +msgstr "包含 sudo 致辞的文件:%s" + +#: plugins/sudoers/def_data.c:79 +msgid "Require users to authenticate by default" +msgstr "默认要求用户认证" + +#: plugins/sudoers/def_data.c:83 +msgid "Root may run sudo" +msgstr "root 可以运行 sudo" + +#: plugins/sudoers/def_data.c:87 +msgid "Log the hostname in the (non-syslog) log file" +msgstr "将主机名记录在(非 syslog)的日志文件中" + +#: plugins/sudoers/def_data.c:91 +msgid "Log the year in the (non-syslog) log file" +msgstr "将年份记录在(非 syslog)的日志文件中" + +#: plugins/sudoers/def_data.c:95 +msgid "If sudo is invoked with no arguments, start a shell" +msgstr "如果不带参数调用 sudo,启动一个 shell" + +#: plugins/sudoers/def_data.c:99 +msgid "Set $HOME to the target user when starting a shell with -s" +msgstr "若使用 -s 选项启动 shell,将 $HOME 设为目标用户的主目录" + +#: plugins/sudoers/def_data.c:103 +msgid "Always set $HOME to the target user's home directory" +msgstr "总是将 $HOME 设为目标用户的主目录" + +#: plugins/sudoers/def_data.c:107 +msgid "Allow some information gathering to give useful error messages" +msgstr "允许收集一些信息,以提供有用的错误消息" + +#: plugins/sudoers/def_data.c:111 +msgid "Require fully-qualified hostnames in the sudoers file" +msgstr "要求 sudoers 文件中包含完全限定的主机名" + +#: plugins/sudoers/def_data.c:115 +msgid "Insult the user when they enter an incorrect password" +msgstr "在用户输入错误密码时对他们进行(玩笑式的)嘲讽" + +#: plugins/sudoers/def_data.c:119 +msgid "Only allow the user to run sudo if they have a tty" +msgstr "只允许拥有终端的用户执行 sudo" + +#: plugins/sudoers/def_data.c:123 +msgid "Visudo will honor the EDITOR environment variable" +msgstr "Visudo 将优先考虑 EDITOR 环境变量" + +#: plugins/sudoers/def_data.c:127 +msgid "Prompt for root's password, not the users's" +msgstr "询问 root 用户的密码而非用户的密码" + +#: plugins/sudoers/def_data.c:131 +msgid "Prompt for the runas_default user's password, not the users's" +msgstr "询问 runas_default 用户的密码,而非用户密码" + +#: plugins/sudoers/def_data.c:135 +msgid "Prompt for the target user's password, not the users's" +msgstr "询问目标用户的密码,而非用户密码" + +#: plugins/sudoers/def_data.c:139 +msgid "Apply defaults in the target user's login class if there is one" +msgstr "应用目标用户登录类别中的默认设置,如果没有设置的话" + +#: plugins/sudoers/def_data.c:143 +msgid "Set the LOGNAME and USER environment variables" +msgstr "设置 LOGNAME 和 USER 环境变量" + +#: plugins/sudoers/def_data.c:147 +msgid "Only set the effective uid to the target user, not the real uid" +msgstr "只将有效用户 ID 设为目标用户的,而不是实际用户 ID" + +#: plugins/sudoers/def_data.c:151 +msgid "Don't initialize the group vector to that of the target user" +msgstr "不将组向量初始化为目标用户的" + +#: plugins/sudoers/def_data.c:155 +#, c-format +msgid "Length at which to wrap log file lines (0 for no wrap): %d" +msgstr "日志文件折行的长度(0 则不折行):%d" + +#: plugins/sudoers/def_data.c:159 +#, c-format +msgid "Authentication timestamp timeout: %.1f minutes" +msgstr "认证时间戳延时:%.1f 分钟" + +#: plugins/sudoers/def_data.c:163 +#, c-format +msgid "Password prompt timeout: %.1f minutes" +msgstr "密码提示延时:%.1f 分钟" + +#: plugins/sudoers/def_data.c:167 +#, c-format +msgid "Number of tries to enter a password: %d" +msgstr "输入密码的尝试次数:%d" + +#: plugins/sudoers/def_data.c:171 +#, c-format +msgid "Umask to use or 0777 to use user's: 0%o" +msgstr "要使用的 umask,或 0777 使用用户的:0%o" + +#: plugins/sudoers/def_data.c:175 +#, c-format +msgid "Path to log file: %s" +msgstr "日志文件路径:%s" + +#: plugins/sudoers/def_data.c:179 +#, c-format +msgid "Path to mail program: %s" +msgstr "邮件程序路径:%s" + +#: plugins/sudoers/def_data.c:183 +#, c-format +msgid "Flags for mail program: %s" +msgstr "邮件程序标志:%s" + +#: plugins/sudoers/def_data.c:187 +#, c-format +msgid "Address to send mail to: %s" +msgstr "发送邮件的地址:%s" + +#: plugins/sudoers/def_data.c:191 +#, c-format +msgid "Address to send mail from: %s" +msgstr "接收邮件的地址:%s" + +#: plugins/sudoers/def_data.c:195 +#, c-format +msgid "Subject line for mail messages: %s" +msgstr "邮件消息的主题行:%s" + +#: plugins/sudoers/def_data.c:199 +#, c-format +msgid "Incorrect password message: %s" +msgstr "密码错误消息:%s" + +#: plugins/sudoers/def_data.c:203 +#, c-format +msgid "Path to authentication timestamp dir: %s" +msgstr "认证时间戳文件夹的路径:%s" + +#: plugins/sudoers/def_data.c:207 +#, c-format +msgid "Owner of the authentication timestamp dir: %s" +msgstr "认证时间戳的所有者:%s" + +#: plugins/sudoers/def_data.c:211 +#, c-format +msgid "Users in this group are exempt from password and PATH requirements: %s" +msgstr "此组的用户不要求密码和 PATH:%s" + +#: plugins/sudoers/def_data.c:215 +#, c-format +msgid "Default password prompt: %s" +msgstr "默认密码提示:%s" + +#: plugins/sudoers/def_data.c:219 +msgid "If set, passprompt will override system prompt in all cases." +msgstr "如果设置,密码提示将覆盖各种情况下的系统提示。" + +#: plugins/sudoers/def_data.c:223 +#, c-format +msgid "Default user to run commands as: %s" +msgstr "运行命令的默认用户:%s" + +#: plugins/sudoers/def_data.c:227 +#, c-format +msgid "Value to override user's $PATH with: %s" +msgstr "覆盖用户的 $PATH 变量的值:%s" + +#: plugins/sudoers/def_data.c:231 +#, c-format +msgid "Path to the editor for use by visudo: %s" +msgstr "visudo 所使用的编辑器的路径:%s" + +#: plugins/sudoers/def_data.c:235 +#, c-format +msgid "When to require a password for 'list' pseudocommand: %s" +msgstr "何时为“list”伪命令请求密码:%s" + +#: plugins/sudoers/def_data.c:239 +#, c-format +msgid "When to require a password for 'verify' pseudocommand: %s" +msgstr "何时为“verify”伪命令请求密码:%s" + +#: plugins/sudoers/def_data.c:243 +msgid "Preload the dummy exec functions contained in the sudo_noexec library" +msgstr "预加载“sudo_noexec”库中包含的哑 exec 函数" + +#: plugins/sudoers/def_data.c:247 +msgid "If LDAP directory is up, do we ignore local sudoers file" +msgstr "如果 LDAP 目录有效,是不是忽略本地的 sudoers 文件" + +#: plugins/sudoers/def_data.c:251 +#, c-format +msgid "File descriptors >= %d will be closed before executing a command" +msgstr ">= %d 的文件描述符将会在执行命令前关闭" + +#: plugins/sudoers/def_data.c:255 +msgid "If set, users may override the value of `closefrom' with the -C option" +msgstr "如果设置,用户可以通过 -C 选项覆盖“closefrom”的值" + +#: plugins/sudoers/def_data.c:259 +msgid "Allow users to set arbitrary environment variables" +msgstr "允许用户设置任意的环境变量" + +#: plugins/sudoers/def_data.c:263 +msgid "Reset the environment to a default set of variables" +msgstr "将环境重设为默认的变量集" + +#: plugins/sudoers/def_data.c:267 +msgid "Environment variables to check for sanity:" +msgstr "要检查完整性的环境变量:" + +#: plugins/sudoers/def_data.c:271 +msgid "Environment variables to remove:" +msgstr "要移除的环境变量:" + +#: plugins/sudoers/def_data.c:275 +msgid "Environment variables to preserve:" +msgstr "要保留的环境变量:" + +#: plugins/sudoers/def_data.c:279 +#, c-format +msgid "SELinux role to use in the new security context: %s" +msgstr "在新的安全环境中使用的 SELinux 角色:%s" + +#: plugins/sudoers/def_data.c:283 +#, c-format +msgid "SELinux type to use in the new security context: %s" +msgstr "在新的安全环境中使用的 SELinux 类型:%s" + +#: plugins/sudoers/def_data.c:287 +#, c-format +msgid "Path to the sudo-specific environment file: %s" +msgstr "sudo 特定环境文件的路径:%s" + +#: plugins/sudoers/def_data.c:291 +#, c-format +msgid "Locale to use while parsing sudoers: %s" +msgstr "解析 sudoers 时使用的区域设置:%s" + +#: plugins/sudoers/def_data.c:295 +msgid "Allow sudo to prompt for a password even if it would be visible" +msgstr "允许 sudo 询问密码,即使它不可见" + +#: plugins/sudoers/def_data.c:299 +msgid "Provide visual feedback at the password prompt when there is user input" +msgstr "用户在询问密码窗口输入时提供视觉反馈" + +#: plugins/sudoers/def_data.c:303 +msgid "Use faster globbing that is less accurate but does not access the filesystem" +msgstr "使用不太精确但不访问文件系统的较快通配方法" + +#: plugins/sudoers/def_data.c:307 +msgid "The umask specified in sudoers will override the user's, even if it is more permissive" +msgstr "sudoers 中指定的 umask 会覆盖用户的,即使它允许的权限更多" + +#: plugins/sudoers/def_data.c:311 +msgid "Log user's input for the command being run" +msgstr "记录用户在所执行命令中的输入" + +#: plugins/sudoers/def_data.c:315 +msgid "Log the output of the command being run" +msgstr "记录所执行命令的输出" + +#: plugins/sudoers/def_data.c:319 +msgid "Compress I/O logs using zlib" +msgstr "使用 zlib 压缩 I/O 日志" + +#: plugins/sudoers/def_data.c:323 +msgid "Always run commands in a pseudo-tty" +msgstr "总是在伪终端中运行命令" + +#: plugins/sudoers/def_data.c:327 +#, c-format +msgid "Plugin for non-Unix group support: %s" +msgstr "用于非 Unix 组支持的插件:%s" + +#: plugins/sudoers/def_data.c:331 +#, c-format +msgid "Directory in which to store input/output logs: %s" +msgstr "用于保存输入/输出日志的目录:%s" + +#: plugins/sudoers/def_data.c:335 +#, c-format +msgid "File in which to store the input/output log: %s" +msgstr "用于保存输入/输出日志的文件:%s" + +#: plugins/sudoers/def_data.c:339 +msgid "Add an entry to the utmp/utmpx file when allocating a pty" +msgstr "在分配伪终端时向 utmp/utmpx 文件中添加一条记录" + +#: plugins/sudoers/def_data.c:343 +msgid "Set the user in utmp to the runas user, not the invoking user" +msgstr "将 utmp 中的用户设为 runas 用户,而不是调用用户" + +#: plugins/sudoers/defaults.c:208 +#, c-format +msgid "unknown defaults entry `%s'" +msgstr "未知的默认条目“%s”" + +#: plugins/sudoers/defaults.c:216 plugins/sudoers/defaults.c:226 +#: plugins/sudoers/defaults.c:246 plugins/sudoers/defaults.c:259 +#: plugins/sudoers/defaults.c:272 plugins/sudoers/defaults.c:285 +#: plugins/sudoers/defaults.c:298 plugins/sudoers/defaults.c:318 +#: plugins/sudoers/defaults.c:328 +#, c-format +msgid "value `%s' is invalid for option `%s'" +msgstr "值“%s”对选项“%s”无效" + +#: plugins/sudoers/defaults.c:219 plugins/sudoers/defaults.c:229 +#: plugins/sudoers/defaults.c:237 plugins/sudoers/defaults.c:254 +#: plugins/sudoers/defaults.c:267 plugins/sudoers/defaults.c:280 +#: plugins/sudoers/defaults.c:293 plugins/sudoers/defaults.c:313 +#: plugins/sudoers/defaults.c:324 +#, c-format +msgid "no value specified for `%s'" +msgstr "没有给“%s”指定值" + +#: plugins/sudoers/defaults.c:242 +#, c-format +msgid "values for `%s' must start with a '/'" +msgstr "“%s”的值必须以“/”开头" + +#: plugins/sudoers/defaults.c:304 +#, c-format +msgid "option `%s' does not take a value" +msgstr "“%s”选项不带值" + +#: plugins/sudoers/env.c:339 +#, c-format +msgid "sudo_putenv: corrupted envp, length mismatch" +msgstr "sudo_putenv:envp 损坏,长度不符" + +#: plugins/sudoers/env.c:341 plugins/sudoers/env.c:411 +#: plugins/sudoers/toke_util.c:113 plugins/sudoers/toke_util.c:167 +#: plugins/sudoers/toke_util.c:207 toke.l:682 toke.l:812 toke.l:870 toke.l:966 +#, c-format +msgid "unable to allocate memory" +msgstr "无法分配内存" + +#: plugins/sudoers/env.c:366 +#, c-format +msgid "internal error, sudo_setenv2() overflow" +msgstr "内部错误,sudo_setenv2() 溢出" + +#: plugins/sudoers/env.c:410 +#, c-format +msgid "internal error, sudo_setenv() overflow" +msgstr "内部错误,sudo_setenv()溢出" + +#: plugins/sudoers/env.c:955 +#, c-format +msgid "sorry, you are not allowed to set the following environment variables: %s" +msgstr "对不起,您无权设置以下环境变量:%s" + +#: plugins/sudoers/find_path.c:69 plugins/sudoers/find_path.c:108 +#: plugins/sudoers/find_path.c:123 plugins/sudoers/iolog.c:125 +#: plugins/sudoers/sudoers.c:950 toke.l:678 toke.l:866 +#, c-format +msgid "%s: %s" +msgstr "%s:%s" + +#: plugins/sudoers/group_plugin.c:91 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s:%s" + +#: plugins/sudoers/group_plugin.c:103 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s 必须属于用户 ID %d" + +#: plugins/sudoers/group_plugin.c:107 +#, c-format +msgid "%s must only be writable by owner" +msgstr "%s 必须只对所有者可写" + +#: plugins/sudoers/group_plugin.c:114 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "无法执行 dlopen %s:%s" + +#: plugins/sudoers/group_plugin.c:119 +#, c-format +msgid "unable to find symbol \"group_plugin\" in %s" +msgstr "无法在 %s 中找到符号“group_plugin”" + +#: plugins/sudoers/group_plugin.c:124 +#, c-format +msgid "%s: incompatible group plugin major version %d, expected %d" +msgstr "%s:不兼容的组插件主版本号 %d,应为 %d" + +#: plugins/sudoers/interfaces.c:112 +msgid "Local IP address and netmask pairs:\n" +msgstr "本地 IP 地址和网络掩码对:\n" + +#: plugins/sudoers/iolog.c:179 plugins/sudoers/sudoers.c:986 +#, c-format +msgid "unable to read %s" +msgstr "无法读取 %s" + +#: plugins/sudoers/iolog.c:182 +#, c-format +msgid "invalid sequence number %s" +msgstr "无效的序列号:%s" + +#: plugins/sudoers/iolog.c:231 plugins/sudoers/iolog.c:234 +#: plugins/sudoers/iolog.c:499 plugins/sudoers/iolog.c:504 +#: plugins/sudoers/iolog.c:510 plugins/sudoers/iolog.c:518 +#: plugins/sudoers/iolog.c:526 plugins/sudoers/iolog.c:534 +#: plugins/sudoers/iolog.c:542 +#, c-format +msgid "unable to create %s" +msgstr "无法创建 %s" + +#: plugins/sudoers/iolog_path.c:256 plugins/sudoers/sudoers.c:373 +#, c-format +msgid "unable to set locale to \"%s\", using \"C\"" +msgstr "无法将区域设置为“%s”,将使用“C”" + +#: plugins/sudoers/ldap.c:378 +#, c-format +msgid "sudo_ldap_conf_add_ports: port too large" +msgstr "sudo_ldap_conf_add_ports:端口太大" + +#: plugins/sudoers/ldap.c:401 +#, c-format +msgid "sudo_ldap_conf_add_ports: out of space expanding hostbuf" +msgstr "sudo_ldap_conf_add_ports:扩展主机缓存时空间不足" + +#: plugins/sudoers/ldap.c:431 +#, c-format +msgid "unsupported LDAP uri type: %s" +msgstr "不支持的 LDAP URI 类型:%s" + +#: plugins/sudoers/ldap.c:460 +#, c-format +msgid "invalid uri: %s" +msgstr "无效的 URI:%s" + +#: plugins/sudoers/ldap.c:466 +#, c-format +msgid "unable to mix ldap and ldaps URIs" +msgstr "无法混合 ldap 和 ldaps URI" + +#: plugins/sudoers/ldap.c:470 +#, c-format +msgid "unable to mix ldaps and starttls" +msgstr "无法混合 ldaps 和 starttls" + +#: plugins/sudoers/ldap.c:489 +#, c-format +msgid "sudo_ldap_parse_uri: out of space building hostbuf" +msgstr "sudo_ldap_parse_uri:构建主机缓存时空间不足" + +#: plugins/sudoers/ldap.c:563 +#, c-format +msgid "unable to initialize SSL cert and key db: %s" +msgstr "无法初始化 SSL 证书和密钥数据库:%s" + +#: plugins/sudoers/ldap.c:566 +#, c-format +msgid "you must set TLS_CERT in %s to use SSL" +msgstr "要使用 SSL,您必须在 %s 中设置 TLS_CERT" + +#: plugins/sudoers/ldap.c:973 +#, c-format +msgid "unable to get GMT time" +msgstr "无法获取 GMT 时间" + +#: plugins/sudoers/ldap.c:979 +#, c-format +msgid "unable to format timestamp" +msgstr "无法格式化时间戳" + +#: plugins/sudoers/ldap.c:987 +#, c-format +msgid "unable to build time filter" +msgstr "无法构建时间过滤器" + +#: plugins/sudoers/ldap.c:1202 +#, c-format +msgid "sudo_ldap_build_pass1 allocation mismatch" +msgstr "sudo_ldap_build_pass1 分配不匹配" + +#: plugins/sudoers/ldap.c:1738 +#, c-format +msgid "" +"\n" +"LDAP Role: %s\n" +msgstr "" +"\n" +"LDAP 角色:%s\n" + +#: plugins/sudoers/ldap.c:1740 +#, c-format +msgid "" +"\n" +"LDAP Role: UNKNOWN\n" +msgstr "" +"\n" +"LDAP 角色:未知\n" + +#: plugins/sudoers/ldap.c:1787 +#, c-format +msgid " Order: %s\n" +msgstr " 顺序:%s\n" + +#: plugins/sudoers/ldap.c:1795 +#, c-format +msgid " Commands:\n" +msgstr " 命令:\n" + +#: plugins/sudoers/ldap.c:2216 +#, c-format +msgid "unable to initialize LDAP: %s" +msgstr "无法初始化 LDAP:%s" + +#: plugins/sudoers/ldap.c:2250 +#, c-format +msgid "start_tls specified but LDAP libs do not support ldap_start_tls_s() or ldap_start_tls_s_np()" +msgstr "指定了 start_tls,但 LDAP 库不支持 ldap_start_tls_s() 或 ldap_start_tls_s_np()" + +#: plugins/sudoers/ldap.c:2486 +#, c-format +msgid "invalid sudoOrder attribute: %s" +msgstr "无效的 sudoOrder 属性:%s" + +#: plugins/sudoers/linux_audit.c:57 +#, c-format +msgid "unable to open audit system" +msgstr "无法打开审核系统" + +#: plugins/sudoers/linux_audit.c:82 +#, c-format +msgid "internal error, linux_audit_command() overflow" +msgstr "内部错误,linux_audit_command() 溢出" + +#: plugins/sudoers/linux_audit.c:91 +#, c-format +msgid "unable to send audit message" +msgstr "无法发送审核消息" + +#: plugins/sudoers/logging.c:198 +#, c-format +msgid "unable to open log file: %s: %s" +msgstr "无法打开日志文件:%s:%s" + +#: plugins/sudoers/logging.c:201 +#, c-format +msgid "unable to lock log file: %s: %s" +msgstr "无法锁定日志文件:%s:%s" + +#: plugins/sudoers/logging.c:256 +msgid "user NOT in sudoers" +msgstr "用户不在 sudoers 中" + +#: plugins/sudoers/logging.c:258 +msgid "user NOT authorized on host" +msgstr "用户未获得此主机上的授权" + +#: plugins/sudoers/logging.c:260 +msgid "command not allowed" +msgstr "命令禁止使用" + +#: plugins/sudoers/logging.c:270 +#, c-format +msgid "%s is not in the sudoers file. This incident will be reported.\n" +msgstr "%s 不在 sudoers 文件中。此事将被报告。\n" + +#: plugins/sudoers/logging.c:273 +#, c-format +msgid "%s is not allowed to run sudo on %s. This incident will be reported.\n" +msgstr "%s 无权在 %s 上运行 sudo。此事将被报告。\n" + +#: plugins/sudoers/logging.c:277 +#, c-format +msgid "Sorry, user %s may not run sudo on %s.\n" +msgstr "对不起,用户 %s 不能在 %s 上运行 sudo。\n" + +#: plugins/sudoers/logging.c:280 +#, c-format +msgid "Sorry, user %s is not allowed to execute '%s%s%s' as %s%s%s on %s.\n" +msgstr "对不起,用户 %1$s 无权以 %5$s%6$s%7$s 的身份在 %8$s 上执行 %2$s%3$s%4$s。\n" + +#: plugins/sudoers/logging.c:447 +#, c-format +msgid "unable to fork" +msgstr "无法执行 fork" + +#: plugins/sudoers/logging.c:454 plugins/sudoers/logging.c:516 +#, c-format +msgid "unable to fork: %m" +msgstr "无法执行 fork:%m" + +#: plugins/sudoers/logging.c:506 +#, c-format +msgid "unable to open pipe: %m" +msgstr "无法打开管道:%m" + +#: plugins/sudoers/logging.c:531 +#, c-format +msgid "unable to dup stdin: %m" +msgstr "无法 dup stdin:%m" + +#: plugins/sudoers/logging.c:567 +#, c-format +msgid "unable to execute %s: %m" +msgstr "无法执行 %s:%m" + +#: plugins/sudoers/logging.c:782 +#, c-format +msgid "internal error: insufficient space for log line" +msgstr "内部错误:没有足够的空间存放日志行" + +#: plugins/sudoers/parse.c:123 +#, c-format +msgid "parse error in %s near line %d" +msgstr "%s 中第 %d 行附近有解析错误" + +#: plugins/sudoers/parse.c:126 +#, c-format +msgid "parse error in %s" +msgstr "%s 中出现解析错误" + +#: plugins/sudoers/parse.c:389 +#, c-format +msgid "" +"\n" +"Sudoers entry:\n" +msgstr "" +"\n" +"Sudoers 条目:\n" + +#: plugins/sudoers/parse.c:391 +#, c-format +msgid " RunAsUsers: " +msgstr " RunAs 用户:" + +#: plugins/sudoers/parse.c:406 +#, c-format +msgid " RunAsGroups: " +msgstr " RunAs 组:" + +#: plugins/sudoers/parse.c:415 +#, c-format +msgid "" +" Commands:\n" +"\t" +msgstr "" +" 命令:\n" +"\t" + +#: plugins/sudoers/plugin_error.c:100 plugins/sudoers/plugin_error.c:105 +msgid ": " +msgstr ":" + +#: plugins/sudoers/pwutil.c:260 +#, c-format +msgid "unable to cache uid %u (%s), already exists" +msgstr "无法缓存用户 ID %u(%s),已存在" + +#: plugins/sudoers/pwutil.c:268 +#, c-format +msgid "unable to cache uid %u, already exists" +msgstr "无法缓存用户 ID %u,已存在" + +#: plugins/sudoers/pwutil.c:305 plugins/sudoers/pwutil.c:314 +#, c-format +msgid "unable to cache user %s, already exists" +msgstr "无法缓存用户 %s,已存在" + +#: plugins/sudoers/pwutil.c:653 +#, c-format +msgid "unable to cache gid %u (%s), already exists" +msgstr "无法缓存组 ID %u(%s),已存在" + +#: plugins/sudoers/pwutil.c:661 +#, c-format +msgid "unable to cache gid %u, already exists" +msgstr "无法缓存组 ID %u,已存在" + +#: plugins/sudoers/pwutil.c:691 plugins/sudoers/pwutil.c:700 +#, c-format +msgid "unable to cache group %s, already exists" +msgstr "无法缓存组 %s,已存在" + +#: plugins/sudoers/set_perms.c:122 plugins/sudoers/set_perms.c:436 +#: plugins/sudoers/set_perms.c:828 plugins/sudoers/set_perms.c:1114 +#: plugins/sudoers/set_perms.c:1396 +msgid "perm stack overflow" +msgstr "权限堆栈上溢" + +#: plugins/sudoers/set_perms.c:130 plugins/sudoers/set_perms.c:444 +#: plugins/sudoers/set_perms.c:836 plugins/sudoers/set_perms.c:1122 +#: plugins/sudoers/set_perms.c:1404 +msgid "perm stack underflow" +msgstr "权限堆栈下溢" + +#: plugins/sudoers/set_perms.c:270 plugins/sudoers/set_perms.c:580 +#: plugins/sudoers/set_perms.c:957 plugins/sudoers/set_perms.c:1243 +msgid "unable to change to runas gid" +msgstr "无法切换为 runas 组 ID" + +#: plugins/sudoers/set_perms.c:282 plugins/sudoers/set_perms.c:592 +#: plugins/sudoers/set_perms.c:967 plugins/sudoers/set_perms.c:1253 +msgid "unable to change to runas uid" +msgstr "无法切换为 runas 用户 ID" + +#: plugins/sudoers/set_perms.c:300 plugins/sudoers/set_perms.c:610 +#: plugins/sudoers/set_perms.c:983 plugins/sudoers/set_perms.c:1269 +msgid "unable to change to sudoers gid" +msgstr "无法切换为 sudoers 组 ID" + +#: plugins/sudoers/set_perms.c:353 plugins/sudoers/set_perms.c:681 +#: plugins/sudoers/set_perms.c:1029 plugins/sudoers/set_perms.c:1315 +#: plugins/sudoers/set_perms.c:1474 +msgid "too many processes" +msgstr "进程过多" + +#: plugins/sudoers/set_perms.c:1542 +msgid "unable to set runas group vector" +msgstr "无法设置 runas 组向量" + +#: plugins/sudoers/sudo_nss.c:243 +#, c-format +msgid "Matching Defaults entries for %s on this host:\n" +msgstr "匹配此主机上 %s 的默认条目:\n" + +#: plugins/sudoers/sudo_nss.c:256 +#, c-format +msgid "Runas and Command-specific defaults for %s:\n" +msgstr "%s Runas 和命令特定的默认值:\n" + +#: plugins/sudoers/sudo_nss.c:269 +#, c-format +msgid "User %s may run the following commands on this host:\n" +msgstr "用户 %s 可以在该主机上运行以下命令:\n" + +#: plugins/sudoers/sudo_nss.c:279 +#, c-format +msgid "User %s is not allowed to run sudo on %s.\n" +msgstr "用户 %s 无权在 %s 上运行 sudo。\n" + +#: plugins/sudoers/sudoers.c:208 plugins/sudoers/sudoers.c:239 +#: plugins/sudoers/sudoers.c:958 +msgid "problem with defaults entries" +msgstr "默认条目有问题" + +#: plugins/sudoers/sudoers.c:212 +#, c-format +msgid "no valid sudoers sources found, quitting" +msgstr "没有找到有效的 sudoers 资源,退出" + +#: plugins/sudoers/sudoers.c:264 +#, c-format +msgid "unable to execute %s: %s" +msgstr "无法执行 %s:%s" + +#: plugins/sudoers/sudoers.c:322 +#, c-format +msgid "sudoers specifies that root is not allowed to sudo" +msgstr "sudoers 指定 root 不允许执行 sudo" + +#: plugins/sudoers/sudoers.c:329 +#, c-format +msgid "you are not permitted to use the -C option" +msgstr "您无权使用 -C 选项" + +#: plugins/sudoers/sudoers.c:422 +#, c-format +msgid "timestamp owner (%s): No such user" +msgstr "时间戳所有者(%s):无此用户" + +#: plugins/sudoers/sudoers.c:438 +msgid "no tty" +msgstr "无终端" + +#: plugins/sudoers/sudoers.c:439 +#, c-format +msgid "sorry, you must have a tty to run sudo" +msgstr "抱歉,您必须拥有一个终端来执行 sudo" + +#: plugins/sudoers/sudoers.c:478 +msgid "No user or host" +msgstr "无用户或主机" + +#: plugins/sudoers/sudoers.c:492 plugins/sudoers/sudoers.c:513 +#: plugins/sudoers/sudoers.c:514 plugins/sudoers/sudoers.c:1522 +#: plugins/sudoers/sudoers.c:1523 +#, c-format +msgid "%s: command not found" +msgstr "%s:找不到命令" + +#: plugins/sudoers/sudoers.c:494 plugins/sudoers/sudoers.c:510 +#, c-format +msgid "" +"ignoring `%s' found in '.'\n" +"Use `sudo ./%s' if this is the `%s' you wish to run." +msgstr "" +"忽略在“.”中找到的“%s”\n" +"请使用“sudo ./%s”,如果这是您想运行的“%s”。" + +#: plugins/sudoers/sudoers.c:499 +msgid "validation failure" +msgstr "校验失败" + +#: plugins/sudoers/sudoers.c:509 +msgid "command in current directory" +msgstr "当前目录中的命令" + +#: plugins/sudoers/sudoers.c:521 +#, c-format +msgid "sorry, you are not allowed to preserve the environment" +msgstr "抱歉,您无权保留环境" + +#: plugins/sudoers/sudoers.c:681 plugins/sudoers/sudoers.c:688 +#, c-format +msgid "internal error, runas_groups overflow" +msgstr "内部错误,runas_groups 溢出" + +#: plugins/sudoers/sudoers.c:941 +#, c-format +msgid "internal error, set_cmnd() overflow" +msgstr "内部错误:set_cmnd() 溢出" + +#: plugins/sudoers/sudoers.c:1001 +#, c-format +msgid "%s is not a regular file" +msgstr "%s 不是常规文件" + +#: plugins/sudoers/sudoers.c:1004 toke.l:829 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s 属于用户 ID %u,应为 %u" + +#: plugins/sudoers/sudoers.c:1008 toke.l:836 +#, c-format +msgid "%s is world writable" +msgstr "%s 可被任何人写" + +#: plugins/sudoers/sudoers.c:1011 toke.l:841 +#, c-format +msgid "%s is owned by gid %u, should be %u" +msgstr "%s 属于组 ID %u,应为 %u" + +#: plugins/sudoers/sudoers.c:1038 +#, c-format +msgid "only root can use `-c %s'" +msgstr "只有 root 才能使用“-c %s”" + +#: plugins/sudoers/sudoers.c:1055 plugins/sudoers/sudoers.c:1057 +#, c-format +msgid "unknown login class: %s" +msgstr "未知的登录类别:%s" + +#: plugins/sudoers/sudoers.c:1084 +#, c-format +msgid "unable to resolve host %s" +msgstr "无法解析主机:%s" + +#: plugins/sudoers/sudoers.c:1136 plugins/sudoers/testsudoers.c:380 +#, c-format +msgid "unknown group: %s" +msgstr "未知组:%s" + +#: plugins/sudoers/sudoers.c:1185 +#, c-format +msgid "Sudoers policy plugin version %s\n" +msgstr "Sudoers 策略插件版本 %s\n" + +#: plugins/sudoers/sudoers.c:1187 +#, c-format +msgid "Sudoers file grammar version %d\n" +msgstr "Sudoers 文件语法版本 %d\n" + +#: plugins/sudoers/sudoers.c:1191 +#, c-format +msgid "" +"\n" +"Sudoers path: %s\n" +msgstr "" +"\n" +"Sudoers 路径:%s\n" + +#: plugins/sudoers/sudoers.c:1194 +#, c-format +msgid "nsswitch path: %s\n" +msgstr "nsswitch 路径:%s\n" + +#: plugins/sudoers/sudoers.c:1196 +#, c-format +msgid "ldap.conf path: %s\n" +msgstr "ldap.conf 路径:%s\n" + +#: plugins/sudoers/sudoers.c:1197 +#, c-format +msgid "ldap.secret path: %s\n" +msgstr "ldap.secret 路径:%s\n" + +#: plugins/sudoers/sudoreplay.c:291 +#, c-format +msgid "invalid filter option: %s" +msgstr "无效的过滤器选项:%s" + +#: plugins/sudoers/sudoreplay.c:304 +#, c-format +msgid "invalid max wait: %s" +msgstr "无效的最大等待:%s" + +#: plugins/sudoers/sudoreplay.c:310 +#, c-format +msgid "invalid speed factor: %s" +msgstr "无法的速度系数:%s" + +#: plugins/sudoers/sudoreplay.c:313 plugins/sudoers/visudo.c:187 +#, c-format +msgid "%s version %s\n" +msgstr "%s 版本 %s\n" + +#: plugins/sudoers/sudoreplay.c:338 +#, c-format +msgid "%s/%.2s/%.2s/%.2s/timing: %s" +msgstr "%s/%.2s/%.2s/%.2s/时序:%s" + +#: plugins/sudoers/sudoreplay.c:344 +#, c-format +msgid "%s/%s/timing: %s" +msgstr "%s/%s/时序:%s" + +#: plugins/sudoers/sudoreplay.c:362 +#, c-format +msgid "Replaying sudo session: %s\n" +msgstr "回放 sudo 会话:%s\n" + +#: plugins/sudoers/sudoreplay.c:368 +#, c-format +msgid "Warning: your terminal is too small to properly replay the log.\n" +msgstr "警告:您的终端尺寸太小,不能正常地回放日志。\n" + +#: plugins/sudoers/sudoreplay.c:369 +#, c-format +msgid "Log geometry is %d x %d, your terminal's geometry is %d x %d." +msgstr "日志的几何尺寸为 %dx%d,您终端的几何尺寸为 %dx%d。" + +#: plugins/sudoers/sudoreplay.c:399 +#, c-format +msgid "unable to set tty to raw mode" +msgstr "无法将终端设为原始模式" + +#: plugins/sudoers/sudoreplay.c:412 +#, c-format +msgid "invalid timing file line: %s" +msgstr "无效的时序文件行:%s" + +#: plugins/sudoers/sudoreplay.c:454 +#, c-format +msgid "writing to standard output" +msgstr "写入标准输出" + +#: plugins/sudoers/sudoreplay.c:486 +#, c-format +msgid "nanosleep: tv_sec %ld, tv_nsec %ld" +msgstr "nanosleep:tv_sec %ld,tv_nsec %ld" + +#: plugins/sudoers/sudoreplay.c:535 plugins/sudoers/sudoreplay.c:560 +#, c-format +msgid "ambiguous expression \"%s\"" +msgstr "有歧义的表达式“%s”" + +#: plugins/sudoers/sudoreplay.c:577 +#, c-format +msgid "too many parenthesized expressions, max %d" +msgstr "括号表达式过多,最多 %d" + +#: plugins/sudoers/sudoreplay.c:588 +#, c-format +msgid "unmatched ')' in expression" +msgstr "表达式中的“)”不匹配" + +#: plugins/sudoers/sudoreplay.c:594 +#, c-format +msgid "unknown search term \"%s\"" +msgstr "未知的搜索词“%s”" + +#: plugins/sudoers/sudoreplay.c:608 +#, c-format +msgid "%s requires an argument" +msgstr "%s 需要参数" + +#: plugins/sudoers/sudoreplay.c:612 +#, c-format +msgid "invalid regular expression: %s" +msgstr "无效的正则表达式:%s" + +#: plugins/sudoers/sudoreplay.c:618 +#, c-format +msgid "could not parse date \"%s\"" +msgstr "无法解析日期“%s”" + +#: plugins/sudoers/sudoreplay.c:631 +#, c-format +msgid "unmatched '(' in expression" +msgstr "表达式中的“(”不匹配" + +#: plugins/sudoers/sudoreplay.c:633 +#, c-format +msgid "illegal trailing \"or\"" +msgstr "非法的结尾字符“or”" + +#: plugins/sudoers/sudoreplay.c:635 +#, c-format +msgid "illegal trailing \"!\"" +msgstr "非法的结尾字符“!”" + +#: plugins/sudoers/sudoreplay.c:942 +#, c-format +msgid "invalid regex: %s" +msgstr "无效的正则表达式:%s" + +#: plugins/sudoers/sudoreplay.c:1066 +#, c-format +msgid "usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n" +msgstr "用法:%s [-h] [-d 目录] [-m 最长等待] [-s 速度系数] ID\n" + +#: plugins/sudoers/sudoreplay.c:1069 +#, c-format +msgid "usage: %s [-h] [-d directory] -l [search expression]\n" +msgstr "用法:%s [-h] [-d 目录] -l [搜索表达式]\n" + +#: plugins/sudoers/sudoreplay.c:1078 +#, c-format +msgid "" +"%s - replay sudo session logs\n" +"\n" +msgstr "" +"%s - 回放 sudo 会话记录\n" +"\n" + +#: plugins/sudoers/sudoreplay.c:1080 +msgid "" +"\n" +"Options:\n" +" -d directory specify directory for session logs\n" +" -f filter specify which I/O type to display\n" +" -h display help message and exit\n" +" -l [expression] list available session IDs that match expression\n" +" -m max_wait max number of seconds to wait between events\n" +" -s speed_factor speed up or slow down output\n" +" -V display version information and exit" +msgstr "" +"\n" +"选项:\n" +" -d 目录 指定会话日志目录\n" +" -f 过滤器 指定要显示的 I/O 类型\n" +" -h 显示帮助信息并退出\n" +" -l [表达式] 列出与表达式匹配的可用会话 ID\n" +" -m 最长等待 事件间等待的最大秒数\n" +" -s 速度系数 加速或减慢输出\n" +" -V 显示版本信息并退出" + +#: plugins/sudoers/testsudoers.c:246 +#, c-format +msgid "internal error, init_vars() overflow" +msgstr "内部错误,init_vars() 溢出" + +#: plugins/sudoers/testsudoers.c:331 +msgid "\thost unmatched" +msgstr "\t主机不匹配" + +#: plugins/sudoers/testsudoers.c:334 +msgid "" +"\n" +"Command allowed" +msgstr "" +"\n" +"命令允许" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command denied" +msgstr "" +"\n" +"命令被拒" + +#: plugins/sudoers/testsudoers.c:335 +msgid "" +"\n" +"Command unmatched" +msgstr "" +"\n" +"命令不匹配" + +#: plugins/sudoers/toke_util.c:218 +msgid "fill_args: buffer overflow" +msgstr "fill_args:缓存溢出" + +#: plugins/sudoers/visudo.c:188 +#, c-format +msgid "%s grammar version %d\n" +msgstr "%s 语法版本 %d\n" + +#: plugins/sudoers/visudo.c:252 plugins/sudoers/visudo.c:538 +#, c-format +msgid "press return to edit %s: " +msgstr "按回车键编辑 %s:" + +#: plugins/sudoers/visudo.c:335 plugins/sudoers/visudo.c:341 +#, c-format +msgid "write error" +msgstr "写错误" + +#: plugins/sudoers/visudo.c:423 +#, c-format +msgid "unable to stat temporary file (%s), %s unchanged" +msgstr "无法 stat 临时文件(%s),%s 未更改" + +#: plugins/sudoers/visudo.c:428 +#, c-format +msgid "zero length temporary file (%s), %s unchanged" +msgstr "零长度的临时文件(%s),%s 未更改" + +#: plugins/sudoers/visudo.c:434 +#, c-format +msgid "editor (%s) failed, %s unchanged" +msgstr "编辑器(%s)失败,%s 未更改" + +#: plugins/sudoers/visudo.c:457 +#, c-format +msgid "%s unchanged" +msgstr "%s 未更改" + +#: plugins/sudoers/visudo.c:483 +#, c-format +msgid "unable to re-open temporary file (%s), %s unchanged." +msgstr "无法重新打开临时文件(%s),%s 未更改" + +#: plugins/sudoers/visudo.c:493 +#, c-format +msgid "unabled to parse temporary file (%s), unknown error" +msgstr "无法解析临时文件(%s),未知错误" + +#: plugins/sudoers/visudo.c:531 +#, c-format +msgid "internal error, unable to find %s in list!" +msgstr "内部错误,在列表中找不到 %s!" + +#: plugins/sudoers/visudo.c:583 plugins/sudoers/visudo.c:592 +#, c-format +msgid "unable to set (uid, gid) of %s to (%u, %u)" +msgstr "无法将 %s 的 (uid, gid) 设为 (%u, %u)" + +#: plugins/sudoers/visudo.c:587 plugins/sudoers/visudo.c:597 +#, c-format +msgid "unable to change mode of %s to 0%o" +msgstr "无法将 %s 的模式更改为 0%o" + +#: plugins/sudoers/visudo.c:614 +#, c-format +msgid "%s and %s not on the same file system, using mv to rename" +msgstr "%s 和 %s 不在同一个文件系统,使用 mv 进行重命名" + +#: plugins/sudoers/visudo.c:628 +#, c-format +msgid "command failed: '%s %s %s', %s unchanged" +msgstr "命令失败:“%s %s %s”,%s 未更改" + +#: plugins/sudoers/visudo.c:638 +#, c-format +msgid "error renaming %s, %s unchanged" +msgstr "重命名 %s 出错,%s 未更改" + +#: plugins/sudoers/visudo.c:701 +msgid "What now? " +msgstr "现在做什么?" + +#: plugins/sudoers/visudo.c:715 +msgid "" +"Options are:\n" +" (e)dit sudoers file again\n" +" e(x)it without saving changes to sudoers file\n" +" (Q)uit and save changes to sudoers file (DANGER!)\n" +msgstr "" +"选项有:\n" +" 重新编辑 sudoers 文件(e)\n" +" 退出,不保存对 sudoers 文件的更改(x)\n" +" 退出并将更改保存到 sudoers 文件(危险!)(Q)\n" + +#: plugins/sudoers/visudo.c:756 +#, c-format +msgid "unable to execute %s" +msgstr "无法执行 %s" + +#: plugins/sudoers/visudo.c:763 +#, c-format +msgid "unable to run %s" +msgstr "无法运行 %s" + +#: plugins/sudoers/visudo.c:789 +#, c-format +msgid "%s: wrong owner (uid, gid) should be (%u, %u)\n" +msgstr "%s:错误的所有者(uid, gid),应为 (%u, %u)\n" + +#: plugins/sudoers/visudo.c:796 +#, c-format +msgid "%s: bad permissions, should be mode 0%o\n" +msgstr "%s:权限不正确,模式应该是 0%o\n" + +#: plugins/sudoers/visudo.c:821 +#, c-format +msgid "failed to parse %s file, unknown error" +msgstr "解析 %s 文件失败,未知错误" + +#: plugins/sudoers/visudo.c:834 +#, c-format +msgid "parse error in %s near line %d\n" +msgstr "%s 中第 %d 行附近出现解析错误\n" + +#: plugins/sudoers/visudo.c:837 +#, c-format +msgid "parse error in %s\n" +msgstr "%s 中出现解析错误\n" + +#: plugins/sudoers/visudo.c:844 plugins/sudoers/visudo.c:849 +#, c-format +msgid "%s: parsed OK\n" +msgstr "%s:解析正确\n" + +#: plugins/sudoers/visudo.c:896 +#, c-format +msgid "%s busy, try again later" +msgstr "%s 忙,请稍后重试" + +#: plugins/sudoers/visudo.c:940 +#, c-format +msgid "specified editor (%s) doesn't exist" +msgstr "指定的编辑器(%s)不存在" + +#: plugins/sudoers/visudo.c:963 +#, c-format +msgid "unable to stat editor (%s)" +msgstr "无法 stat 编辑器(%s)" + +#: plugins/sudoers/visudo.c:1011 +#, c-format +msgid "no editor found (editor path = %s)" +msgstr "未找到编辑器(编辑器路径 = %s)" + +#: plugins/sudoers/visudo.c:1105 +#, c-format +msgid "Error: cycle in %s_Alias `%s'" +msgstr "错误:在 %s_Alias “%s”中循环" + +#: plugins/sudoers/visudo.c:1106 +#, c-format +msgid "Warning: cycle in %s_Alias `%s'" +msgstr "警告:在 %s_Alias “%s”中循环" + +#: plugins/sudoers/visudo.c:1109 +#, c-format +msgid "Error: %s_Alias `%s' referenced but not defined" +msgstr "错误:引用了 %s_Alias “%s”但尚未定义" + +#: plugins/sudoers/visudo.c:1110 +#, c-format +msgid "Warning: %s_Alias `%s' referenced but not defined" +msgstr "警告:引用了 %s_Alias “%s”但尚未定义" + +#: plugins/sudoers/visudo.c:1245 +#, c-format +msgid "%s: unused %s_Alias %s" +msgstr "%s:未使用的 %s_Alias %s" + +#: plugins/sudoers/visudo.c:1301 +#, c-format +msgid "" +"%s - safely edit the sudoers file\n" +"\n" +msgstr "" +"%s - 安全地编辑 sudoers 文件\n" +"\n" + +#: plugins/sudoers/visudo.c:1303 +msgid "" +"\n" +"Options:\n" +" -c check-only mode\n" +" -f sudoers specify sudoers file location\n" +" -h display help message and exit\n" +" -q less verbose (quiet) syntax error messages\n" +" -s strict syntax checking\n" +" -V display version information and exit" +msgstr "" +"\n" +"选项:\n" +" -c 纯检查模式\n" +" -f sudoers 指定 sudoers 文件的位置\n" +" -h 显示帮助信息并退出\n" +" -q 较简略(安静)的语法错误信息\n" +" -s 严格语法检查\n" +" -V 显示版本信息并退出" + +#: toke.l:805 +msgid "too many levels of includes" +msgstr "include 嵌套层数过多" + +#~ msgid "invalid log file %s" +#~ msgstr "无效的日志文件 %s" + +#, fuzzy +#~ msgid "fixed mode on %s" +#~ msgstr "对 %s 修正了模式" + +#~ msgid "set group on %s" +#~ msgstr "对 %s 设置组" + +#~ msgid "unable to set group on %s" +#~ msgstr "无法对 %s 设置组" + +#~ msgid "unable to fix mode on %s" +#~ msgstr "无法对 %s 修正模式" + +#~ msgid "%s is mode 0%o, should be 0%o" +#~ msgstr "%s 的模式为 0%o,应为 0%o" + +#~ msgid "File containing dummy exec functions: %s" +#~ msgstr "含有哑 exec 函数的文件:%s" + +#~ msgid "" +#~ "Available options in a sudoers ``Defaults'' line:\n" +#~ "\n" +#~ msgstr "" +#~ "sudoers 中“Defaults”行中的可用选项:\n" +#~ "\n" + +#~ msgid "%s: %s\n" +#~ msgstr "%s:%s\n" + +#~ msgid "%s: %.*s\n" +#~ msgstr "%s:%.*s\n" + +#~ msgid "unable to get runas group vector" +#~ msgstr "无法获取 runas 组向量" + +#~ msgid "unable to reset group vector" +#~ msgstr "无法重设组向量" + +#~ msgid "unable to get group vector" +#~ msgstr "无法获取组向量" + +#~ msgid "%s: %s_Alias `%s' references self" +#~ msgstr "%s:%s_Alias “%s”引用了自己" diff --git a/plugins/sudoers/pwutil.c b/plugins/sudoers/pwutil.c new file mode 100644 index 0000000..e18c6b0 --- /dev/null +++ b/plugins/sudoers/pwutil.c @@ -0,0 +1,971 @@ +/* + * 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. + * + * 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 +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_SETAUTHDB +# include +#endif /* HAVE_SETAUTHDB */ +#ifdef HAVE_UTMPX_H +# include +#else +# include +#endif /* HAVE_UTMPX_H */ +#include +#include +#include + +#include "sudoers.h" +#include "redblack.h" + +/* + * The passwd and group caches. + */ +static struct rbtree *pwcache_byuid, *pwcache_byname; +static struct rbtree *grcache_bygid, *grcache_byname; +static struct rbtree *grlist_cache; + +static int cmp_pwuid(const void *, const void *); +static int cmp_pwnam(const void *, const void *); +static int cmp_grgid(const void *, const void *); + +#define cmp_grnam cmp_pwnam + +#define ptr_to_item(p) ((struct cache_item *)((char *)p - offsetof(struct cache_item_##p, p))) + +/* + * Generic cache element. + */ +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; + struct group_list *grlist; + } d; +}; + +/* + * Container structs to simpify size and offset calculations and guarantee + * proper aligment of struct passwd, group and group_list. + */ +struct cache_item_pw { + struct cache_item cache; + struct passwd pw; +}; + +struct cache_item_gr { + struct cache_item cache; + struct group gr; +}; + +struct cache_item_grlist { + struct cache_item cache; + struct group_list grlist; + /* actually bigger */ +}; + +/* + * Compare by uid. + */ +static int +cmp_pwuid(const void *v1, const void *v2) +{ + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + return ci1->k.uid - ci2->k.uid; +} + +/* + * Compare by user name. + */ +static int +cmp_pwnam(const void *v1, const void *v2) +{ + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + return strcmp(ci1->k.name, ci2->k.name); +} + +#define FIELD_SIZE(src, name, size) \ +do { \ + if (src->name) { \ + size = strlen(src->name) + 1; \ + total += size; \ + } \ +} while (0) + +#define FIELD_COPY(src, dst, name, size) \ +do { \ + if (src->name) { \ + memcpy(cp, src->name, size); \ + dst->name = cp; \ + cp += size; \ + } \ +} while (0) + +/* + * Dynamically allocate space for a struct item plus the key and data + * elements. If name is non-NULL it is used as the key, else the + * uid is the key. Fills in datum from struct password. + */ +static struct cache_item * +make_pwitem(const struct passwd *pw, const char *name) +{ + char *cp; + const char *pw_shell; + size_t nsize, psize, csize, gsize, dsize, ssize, total; + struct cache_item_pw *pwitem; + struct passwd *newpw; + debug_decl(make_pwitem, SUDO_DEBUG_NSS) + + /* If shell field is empty, expand to _PATH_BSHELL. */ + pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0') + ? _PATH_BSHELL : pw->pw_shell; + + /* Allocate in one big chunk for easy freeing. */ + nsize = psize = csize = gsize = dsize = ssize = 0; + total = sizeof(*pwitem); + FIELD_SIZE(pw, pw_name, nsize); + FIELD_SIZE(pw, pw_passwd, psize); +#ifdef HAVE_LOGIN_CAP_H + FIELD_SIZE(pw, pw_class, csize); +#endif + FIELD_SIZE(pw, pw_gecos, gsize); + FIELD_SIZE(pw, pw_dir, dsize); + /* Treat shell specially since we expand "" -> _PATH_BSHELL */ + ssize = strlen(pw_shell) + 1; + total += ssize; + if (name != NULL) + total += strlen(name) + 1; + + /* Allocate space for struct item, struct passwd and the strings. */ + pwitem = ecalloc(1, total); + newpw = &pwitem->pw; + + /* + * Copy in passwd contents and make strings relative to space + * at the end of the struct. + */ + memcpy(newpw, pw, sizeof(*pw)); + cp = (char *)(pwitem + 1); + FIELD_COPY(pw, newpw, pw_name, nsize); + FIELD_COPY(pw, newpw, pw_passwd, psize); +#ifdef HAVE_LOGIN_CAP_H + FIELD_COPY(pw, newpw, pw_class, csize); +#endif + FIELD_COPY(pw, newpw, pw_gecos, gsize); + FIELD_COPY(pw, newpw, pw_dir, dsize); + /* Treat shell specially since we expand "" -> _PATH_BSHELL */ + memcpy(cp, pw_shell, ssize); + newpw->pw_shell = cp; + cp += ssize; + + /* Set key and datum. */ + if (name != NULL) { + memcpy(cp, name, strlen(name) + 1); + pwitem->cache.k.name = cp; + } else { + pwitem->cache.k.uid = pw->pw_uid; + } + pwitem->cache.d.pw = newpw; + pwitem->cache.refcnt = 1; + + debug_return_ptr(&pwitem->cache); +} + +void +pw_addref(struct passwd *pw) +{ + debug_decl(pw_addref, SUDO_DEBUG_NSS) + ptr_to_item(pw)->refcnt++; + debug_return; +} + +static void +pw_delref_item(void *v) +{ + struct cache_item *item = v; + debug_decl(pw_delref_item, SUDO_DEBUG_NSS) + + if (--item->refcnt == 0) + efree(item); + + debug_return; +} + +void +pw_delref(struct passwd *pw) +{ + debug_decl(pw_delref, SUDO_DEBUG_NSS) + pw_delref_item(ptr_to_item(pw)); + debug_return; +} + +/* + * Get a password entry by uid and allocate space for it. + */ +struct passwd * +sudo_getpwuid(uid_t uid) +{ + struct cache_item key, *item; + struct rbnode *node; + debug_decl(sudo_getpwuid, SUDO_DEBUG_NSS) + + key.k.uid = uid; + if ((node = rbfind(pwcache_byuid, &key)) != NULL) { + item = (struct cache_item *) node->data; + goto done; + } + /* + * Cache passwd db entry if it exists or a negative response if not. + */ +#ifdef HAVE_SETAUTHDB + aix_setauthdb(IDtouser(uid)); +#endif + if ((key.d.pw = getpwuid(uid)) != NULL) { + item = make_pwitem(key.d.pw, NULL); + if (rbinsert(pwcache_byuid, item) != NULL) + errorx(1, _("unable to cache uid %u (%s), already exists"), + (unsigned int) uid, item->d.pw->pw_name); + } else { + item = ecalloc(1, sizeof(*item)); + item->refcnt = 1; + item->k.uid = uid; + /* item->d.pw = NULL; */ + if (rbinsert(pwcache_byuid, item) != NULL) + errorx(1, _("unable to cache uid %u, already exists"), + (unsigned int) uid); + } +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif +done: + item->refcnt++; + debug_return_ptr(item->d.pw); +} + +/* + * Get a password entry by name and allocate space for it. + */ +struct passwd * +sudo_getpwnam(const char *name) +{ + struct cache_item key, *item; + struct rbnode *node; + size_t len; + debug_decl(sudo_getpwnam, SUDO_DEBUG_NSS) + + key.k.name = (char *) name; + if ((node = rbfind(pwcache_byname, &key)) != NULL) { + item = (struct cache_item *) node->data; + goto done; + } + /* + * Cache passwd db entry if it exists or a negative response if not. + */ +#ifdef HAVE_SETAUTHDB + aix_setauthdb((char *) name); +#endif + if ((key.d.pw = getpwnam(name)) != NULL) { + item = make_pwitem(key.d.pw, name); + if (rbinsert(pwcache_byname, item) != NULL) + errorx(1, _("unable to cache user %s, already exists"), name); + } else { + len = strlen(name) + 1; + item = ecalloc(1, sizeof(*item) + len); + item->refcnt = 1; + item->k.name = (char *) item + sizeof(*item); + memcpy(item->k.name, name, len); + /* item->d.pw = NULL; */ + if (rbinsert(pwcache_byname, item) != NULL) + errorx(1, _("unable to cache user %s, already exists"), name); + } +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif +done: + item->refcnt++; + debug_return_ptr(item->d.pw); +} + +/* + * Take a user, uid and gid and return a faked up passwd struct. + */ +struct passwd * +sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid) +{ + struct cache_item_pw *pwitem; + struct passwd *pw; + struct rbnode *node; + size_t len, namelen; + int i; + debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS) + + namelen = strlen(user); + len = sizeof(*pwitem) + namelen + 1 /* pw_name */ + + sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + + sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL); + + for (i = 0; i < 2; i++) { + pwitem = ecalloc(1, len); + pw = &pwitem->pw; + pw->pw_uid = uid; + pw->pw_gid = gid; + pw->pw_name = (char *)(pwitem + 1); + 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)); + + pwitem->cache.refcnt = 1; + pwitem->cache.d.pw = pw; + if (i == 0) { + /* Store by uid, overwriting cached version. */ + pwitem->cache.k.uid = pw->pw_uid; + if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) { + pw_delref_item(node->data); + node->data = &pwitem->cache; + } + } else { + /* Store by name, overwriting cached version. */ + pwitem->cache.k.name = pw->pw_name; + if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) { + pw_delref_item(node->data); + node->data = &pwitem->cache; + } + } + } + pwitem->cache.refcnt++; + debug_return_ptr(pw); +} + +/* + * Take a uid in string form "#123" and return a faked up passwd struct. + */ +struct passwd * +sudo_fakepwnam(const char *user, gid_t gid) +{ + uid_t uid; + + uid = (uid_t) atoi(user + 1); + return sudo_fakepwnamid(user, uid, gid); +} + +void +sudo_setpwent(void) +{ + debug_decl(sudo_setpwent, SUDO_DEBUG_NSS) + + setpwent(); + if (pwcache_byuid == NULL) + pwcache_byuid = rbcreate(cmp_pwuid); + if (pwcache_byname == NULL) + pwcache_byname = rbcreate(cmp_pwnam); + + debug_return; +} + +void +sudo_freepwcache(void) +{ + debug_decl(sudo_freepwcache, SUDO_DEBUG_NSS) + + if (pwcache_byuid != NULL) { + rbdestroy(pwcache_byuid, pw_delref_item); + pwcache_byuid = NULL; + } + if (pwcache_byname != NULL) { + rbdestroy(pwcache_byname, pw_delref_item); + pwcache_byname = NULL; + } + + debug_return; +} + +void +sudo_endpwent(void) +{ + debug_decl(sudo_endpwent, SUDO_DEBUG_NSS) + + endpwent(); + sudo_freepwcache(); + + debug_return; +} + +/* + * Compare by gid. + */ +static int +cmp_grgid(const void *v1, const void *v2) +{ + const struct cache_item *ci1 = (const struct cache_item *) v1; + const struct cache_item *ci2 = (const struct cache_item *) v2; + return ci1->k.gid - ci2->k.gid; +} + +/* + * Dynamically allocate space for a struct item plus the key and data + * elements. If name is non-NULL it is used as the key, else the + * gid is the key. Fills in datum from struct group. + */ +static struct cache_item * +make_gritem(const struct group *gr, const char *name) +{ + char *cp; + size_t nsize, psize, nmem, total, len; + struct cache_item_gr *gritem; + struct group *newgr; + debug_decl(make_gritem, SUDO_DEBUG_NSS) + + /* Allocate in one big chunk for easy freeing. */ + nsize = psize = nmem = 0; + total = sizeof(*gritem); + FIELD_SIZE(gr, gr_name, nsize); + FIELD_SIZE(gr, gr_passwd, psize); + if (gr->gr_mem) { + for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) + total += strlen(gr->gr_mem[nmem]) + 1; + nmem++; + total += sizeof(char *) * nmem; + } + if (name != NULL) + total += strlen(name) + 1; + + gritem = ecalloc(1, total); + + /* + * Copy in group contents and make strings relative to space + * at the end of the buffer. Note that gr_mem must come + * immediately after struct group to guarantee proper alignment. + */ + newgr = &gritem->gr; + memcpy(newgr, gr, sizeof(*gr)); + cp = (char *)(gritem + 1); + if (gr->gr_mem) { + newgr->gr_mem = (char **)cp; + cp += sizeof(char *) * nmem; + for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) { + len = strlen(gr->gr_mem[nmem]) + 1; + memcpy(cp, gr->gr_mem[nmem], len); + newgr->gr_mem[nmem] = cp; + cp += len; + } + newgr->gr_mem[nmem] = NULL; + } + FIELD_COPY(gr, newgr, gr_passwd, psize); + FIELD_COPY(gr, newgr, gr_name, nsize); + + /* Set key and datum. */ + if (name != NULL) { + memcpy(cp, name, strlen(name) + 1); + gritem->cache.k.name = cp; + } else { + gritem->cache.k.gid = gr->gr_gid; + } + gritem->cache.d.gr = newgr; + gritem->cache.refcnt = 1; + + debug_return_ptr(&gritem->cache); +} + +#ifdef HAVE_UTMPX_H +# define GROUPNAME_LEN (sizeof((struct utmpx *)0)->ut_user + 1) +#else +# ifdef HAVE_STRUCT_UTMP_UT_USER +# define GROUPNAME_LEN (sizeof((struct utmp *)0)->ut_user + 1) +# else +# define GROUPNAME_LEN (sizeof((struct utmp *)0)->ut_name + 1) +# endif +#endif /* HAVE_UTMPX_H */ + +/* + * Dynamically allocate space for a struct item plus the key and data + * elements. Fills in datum from the groups and gids arrays. + */ +static struct cache_item * +make_grlist_item(const char *user, GETGROUPS_T *gids, int ngids) +{ + char *cp; + size_t i, nsize, ngroups, total, len; + struct cache_item_grlist *grlitem; + struct group_list *grlist; + struct group *grp; + debug_decl(make_grlist_item, SUDO_DEBUG_NSS) + +#ifdef HAVE_SETAUTHDB + aix_setauthdb((char *) user); +#endif + + /* Allocate in one big chunk for easy freeing. */ + nsize = strlen(user) + 1; + total = sizeof(*grlitem) + nsize; + total += sizeof(char *) * ngids; + total += sizeof(gid_t *) * ngids; + total += GROUPNAME_LEN * ngids; + +again: + grlitem = ecalloc(1, total); + + /* + * Copy in group list and make pointers relative to space + * at the end of the buffer. Note that the groups array must come + * immediately after struct group to guarantee proper alignment. + */ + grlist = &grlitem->grlist; + cp = (char *)(grlitem + 1); + grlist->groups = (char **)cp; + cp += sizeof(char *) * ngids; + grlist->gids = (gid_t *)cp; + cp += sizeof(gid_t) * ngids; + + /* Set key and datum. */ + memcpy(cp, user, nsize); + grlitem->cache.k.name = cp; + grlitem->cache.d.grlist = grlist; + grlitem->cache.refcnt = 1; + cp += nsize; + + /* + * Store group IDs. + */ + for (i = 0; i < ngids; i++) + grlist->gids[i] = gids[i]; + grlist->ngids = ngids; + + /* + * Resolve and store group names by ID. + */ + ngroups = 0; + for (i = 0; i < ngids; i++) { + if ((grp = sudo_getgrgid(gids[i])) != NULL) { + len = strlen(grp->gr_name) + 1; + if (cp - (char *)grlitem + len > total) { + total += len + GROUPNAME_LEN; + efree(grlitem); + gr_delref(grp); + goto again; + } + memcpy(cp, grp->gr_name, len); + grlist->groups[ngroups++] = cp; + cp += len; + gr_delref(grp); + } + } + grlist->ngroups = ngroups; + +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif + + debug_return_ptr(&grlitem->cache); +} + +void +gr_addref(struct group *gr) +{ + debug_decl(gr_addref, SUDO_DEBUG_NSS) + ptr_to_item(gr)->refcnt++; + debug_return; +} + +static void +gr_delref_item(void *v) +{ + struct cache_item *item = v; + debug_decl(gr_delref_item, SUDO_DEBUG_NSS) + + if (--item->refcnt == 0) + efree(item); + + debug_return; +} + +void +gr_delref(struct group *gr) +{ + debug_decl(gr_delref, SUDO_DEBUG_NSS) + gr_delref_item(ptr_to_item(gr)); + debug_return; +} + +/* + * Get a group entry by gid and allocate space for it. + */ +struct group * +sudo_getgrgid(gid_t gid) +{ + struct cache_item key, *item; + struct rbnode *node; + debug_decl(sudo_getgrgid, SUDO_DEBUG_NSS) + + key.k.gid = gid; + if ((node = rbfind(grcache_bygid, &key)) != NULL) { + item = (struct cache_item *) node->data; + goto done; + } + /* + * Cache group db entry if it exists or a negative response if not. + */ + if ((key.d.gr = getgrgid(gid)) != NULL) { + item = make_gritem(key.d.gr, NULL); + if (rbinsert(grcache_bygid, item) != NULL) + errorx(1, _("unable to cache gid %u (%s), already exists"), + (unsigned int) gid, key.d.gr->gr_name); + } else { + item = ecalloc(1, sizeof(*item)); + item->refcnt = 1; + item->k.gid = gid; + /* item->d.gr = NULL; */ + if (rbinsert(grcache_bygid, item) != NULL) + errorx(1, _("unable to cache gid %u, already exists"), + (unsigned int) gid); + } +done: + item->refcnt++; + debug_return_ptr(item->d.gr); +} + +/* + * Get a group entry by name and allocate space for it. + */ +struct group * +sudo_getgrnam(const char *name) +{ + struct cache_item key, *item; + struct rbnode *node; + size_t len; + debug_decl(sudo_getgrnam, SUDO_DEBUG_NSS) + + key.k.name = (char *) name; + if ((node = rbfind(grcache_byname, &key)) != NULL) { + item = (struct cache_item *) node->data; + goto done; + } + /* + * Cache group db entry if it exists or a negative response if not. + */ + if ((key.d.gr = getgrnam(name)) != NULL) { + item = make_gritem(key.d.gr, name); + if (rbinsert(grcache_byname, item) != NULL) + errorx(1, _("unable to cache group %s, already exists"), name); + } else { + len = strlen(name) + 1; + item = ecalloc(1, sizeof(*item) + len); + item->refcnt = 1; + item->k.name = (char *) item + sizeof(*item); + memcpy(item->k.name, name, len); + /* item->d.gr = NULL; */ + if (rbinsert(grcache_byname, item) != NULL) + errorx(1, _("unable to cache group %s, already exists"), name); + } +done: + item->refcnt++; + debug_return_ptr(item->d.gr); +} + +/* + * Take a gid in string form "#123" and return a faked up group struct. + */ +struct group * +sudo_fakegrnam(const char *group) +{ + struct cache_item_gr *gritem; + struct group *gr; + struct rbnode *node; + size_t len, namelen; + int i; + debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS) + + namelen = strlen(group); + len = sizeof(*gritem) + namelen + 1; + + for (i = 0; i < 2; i++) { + gritem = ecalloc(1, len); + gr = &gritem->gr; + gr->gr_gid = (gid_t) atoi(group + 1); + gr->gr_name = (char *)(gritem + 1); + memcpy(gr->gr_name, group, namelen + 1); + + gritem->cache.refcnt = 1; + gritem->cache.d.gr = gr; + if (i == 0) { + /* Store by gid, overwriting cached version. */ + gritem->cache.k.gid = gr->gr_gid; + if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) { + gr_delref_item(node->data); + node->data = &gritem->cache; + } + } else { + /* Store by name, overwriting cached version. */ + gritem->cache.k.name = gr->gr_name; + if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) { + gr_delref_item(node->data); + node->data = &gritem->cache; + } + } + } + gritem->cache.refcnt++; + debug_return_ptr(gr); +} + +void +grlist_addref(struct group_list *grlist) +{ + debug_decl(gr_addref, SUDO_DEBUG_NSS) + ptr_to_item(grlist)->refcnt++; + debug_return; +} + +static void +grlist_delref_item(void *v) +{ + struct cache_item *item = v; + debug_decl(gr_delref_item, SUDO_DEBUG_NSS) + + if (--item->refcnt == 0) + efree(item); + + debug_return; +} + +void +grlist_delref(struct group_list *grlist) +{ + debug_decl(gr_delref, SUDO_DEBUG_NSS) + grlist_delref_item(ptr_to_item(grlist)); + debug_return; +} + +void +sudo_setgrent(void) +{ + debug_decl(sudo_setgrent, SUDO_DEBUG_NSS) + + setgrent(); + if (grcache_bygid == NULL) + grcache_bygid = rbcreate(cmp_grgid); + if (grcache_byname == NULL) + grcache_byname = rbcreate(cmp_grnam); + if (grlist_cache == NULL) + grlist_cache = rbcreate(cmp_grnam); + + debug_return; +} + +void +sudo_freegrcache(void) +{ + debug_decl(sudo_freegrcache, SUDO_DEBUG_NSS) + + if (grcache_bygid != NULL) { + rbdestroy(grcache_bygid, gr_delref_item); + grcache_bygid = NULL; + } + if (grcache_byname != NULL) { + rbdestroy(grcache_byname, gr_delref_item); + grcache_byname = NULL; + } + if (grlist_cache != NULL) { + rbdestroy(grlist_cache, grlist_delref_item); + grlist_cache = NULL; + } + + debug_return; +} + +void +sudo_endgrent(void) +{ + debug_decl(sudo_endgrent, SUDO_DEBUG_NSS) + + endgrent(); + sudo_freegrcache(); + + debug_return; +} + +struct group_list * +get_group_list(struct passwd *pw) +{ + struct cache_item key, *item; + struct rbnode *node; + size_t len; + GETGROUPS_T *gids; + int ngids; + debug_decl(get_group_list, SUDO_DEBUG_NSS) + + key.k.name = pw->pw_name; + if ((node = rbfind(grlist_cache, &key)) != NULL) { + item = (struct cache_item *) node->data; + goto done; + } + /* + * Cache group db entry if it exists or a negative response if not. + */ +#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) + ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2; + if (ngids < 0) +#endif + ngids = NGROUPS_MAX * 2; + gids = emalloc2(ngids, sizeof(GETGROUPS_T)); + if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { + efree(gids); + gids = emalloc2(ngids, sizeof(GETGROUPS_T)); + if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { + efree(gids); + debug_return_ptr(NULL); + } + } + if (ngids > 0) { + if ((item = make_grlist_item(pw->pw_name, gids, ngids)) == NULL) + errorx(1, "unable to parse group list for %s", pw->pw_name); + efree(gids); + if (rbinsert(grlist_cache, item) != NULL) + errorx(1, "unable to cache group list for %s, already exists", + pw->pw_name); + } else { + /* Should not happen. */ + len = strlen(pw->pw_name) + 1; + item = ecalloc(1, sizeof(*item) + len); + item->refcnt = 1; + item->k.name = (char *) item + sizeof(*item); + memcpy(item->k.name, pw->pw_name, len); + /* item->d.grlist = NULL; */ + if (rbinsert(grlist_cache, item) != NULL) + errorx(1, "unable to cache group list for %s, already exists", + pw->pw_name); + } +done: + item->refcnt++; + debug_return_ptr(item->d.grlist); +} + +void +set_group_list(const char *user, GETGROUPS_T *gids, int ngids) +{ + struct cache_item key, *item; + struct rbnode *node; + debug_decl(set_group_list, SUDO_DEBUG_NSS) + + /* + * Cache group db entry if it doesn't already exist + */ + key.k.name = (char *) user; + if ((node = rbfind(grlist_cache, &key)) == NULL) { + if ((item = make_grlist_item(user, gids, ngids)) == NULL) + errorx(1, "unable to parse group list for %s", user); + if (rbinsert(grlist_cache, item) != NULL) + errorx(1, "unable to cache group list for %s, already exists", + user); + } + debug_return; +} + +bool +user_in_group(struct passwd *pw, const char *group) +{ + struct group_list *grlist; + struct group *grp = NULL; + int i; + bool matched = false; + debug_decl(user_in_group, SUDO_DEBUG_NSS) + + if ((grlist = get_group_list(pw)) != NULL) { + /* + * If it could be a sudo-style group ID check gids first. + */ + if (group[0] == '#') { + gid_t gid = atoi(group + 1); + if (gid == pw->pw_gid) { + matched = true; + goto done; + } + for (i = 0; i < grlist->ngids; i++) { + if (gid == grlist->gids[i]) { + matched = true; + goto done; + } + } + } + + /* + * Next check the supplementary group vector. + * It usually includes the password db group too. + */ + for (i = 0; i < grlist->ngroups; i++) { + if (strcasecmp(group, grlist->groups[i]) == 0) { + matched = true; + goto done; + } + } + + /* Finally check against user's primary (passwd file) group. */ + if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) { + if (strcasecmp(group, grp->gr_name) == 0) { + matched = true; + goto done; + } + } +done: + if (grp != NULL) + gr_delref(grp); + grlist_delref(grlist); + } + debug_return_bool(matched); +} diff --git a/plugins/sudoers/redblack.c b/plugins/sudoers/redblack.c new file mode 100644 index 0000000..584f2c0 --- /dev/null +++ b/plugins/sudoers/redblack.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2004-2005, 2007, 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Adapted from the following code written by Emin Martinian: + * http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html + * + * Copyright (c) 2001 Emin Martinian + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that neither the name of Emin + * Martinian nor the names of any contributors are be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ + +#include "missing.h" +#include "alloc.h" +#include "sudo_debug.h" +#include "redblack.h" + +static void rbrepair(struct rbtree *, struct rbnode *); +static void rotate_left(struct rbtree *, struct rbnode *); +static void rotate_right(struct rbtree *, struct rbnode *); +static void _rbdestroy(struct rbtree *, struct rbnode *, void (*)(void *)); + +/* + * Red-Black tree, see http://en.wikipedia.org/wiki/Red-black_tree + * + * A red-black tree is a binary search tree where each node has a color + * attribute, the value of which is either red or black. Essentially, it + * is just a convenient way to express a 2-3-4 binary search tree where + * the color indicates whether the node is part of a 3-node or a 4-node. + * In addition to the ordinary requirements imposed on binary search + * trees, we make the following additional requirements of any valid + * red-black tree: + * 1) Every node is either red or black. + * 2) The root is black. + * 3) All leaves are black. + * 4) Both children of each red node are black. + * 5) The paths from each leaf up to the root each contain the same + * number of black nodes. + */ + +/* + * Create a red black tree struct using the specified compare routine. + * Allocates and returns the initialized (empty) tree. + */ +struct rbtree * +rbcreate(int (*compar)(const void *, const void*)) +{ + struct rbtree *tree; + debug_decl(rbcreate, SUDO_DEBUG_RBTREE) + + tree = (struct rbtree *) emalloc(sizeof(*tree)); + tree->compar = compar; + + /* + * We use a self-referencing sentinel node called nil to simplify the + * code by avoiding the need to check for NULL pointers. + */ + tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil; + tree->nil.color = black; + tree->nil.data = NULL; + + /* + * Similarly, the fake root node keeps us from having to worry + * about splitting the root. + */ + tree->root.left = tree->root.right = tree->root.parent = &tree->nil; + tree->root.color = black; + tree->root.data = NULL; + + debug_return_ptr(tree); +} + +/* + * Perform a left rotation starting at node. + */ +static void +rotate_left(struct rbtree *tree, struct rbnode *node) +{ + struct rbnode *child; + debug_decl(rotate_left, SUDO_DEBUG_RBTREE) + + child = node->right; + node->right = child->left; + + if (child->left != rbnil(tree)) + child->left->parent = node; + child->parent = node->parent; + + if (node == node->parent->left) + node->parent->left = child; + else + node->parent->right = child; + child->left = node; + node->parent = child; + + debug_return; +} + +/* + * Perform a right rotation starting at node. + */ +static void +rotate_right(struct rbtree *tree, struct rbnode *node) +{ + struct rbnode *child; + debug_decl(rotate_right, SUDO_DEBUG_RBTREE) + + child = node->left; + node->left = child->right; + + if (child->right != rbnil(tree)) + child->right->parent = node; + child->parent = node->parent; + + if (node == node->parent->left) + node->parent->left = child; + else + node->parent->right = child; + child->right = node; + node->parent = child; + + debug_return; +} + +/* + * Insert data pointer into a redblack tree. + * Returns a NULL pointer on success. If a node matching "data" + * already exists, a pointer to the existant node is returned. + */ +struct rbnode * +rbinsert(struct rbtree *tree, void *data) +{ + struct rbnode *node = rbfirst(tree); + struct rbnode *parent = rbroot(tree); + int res; + debug_decl(rbinsert, SUDO_DEBUG_RBTREE) + + /* Find correct insertion point. */ + while (node != rbnil(tree)) { + parent = node; + if ((res = tree->compar(data, node->data)) == 0) + debug_return_ptr(node); + node = res < 0 ? node->left : node->right; + } + + node = (struct rbnode *) emalloc(sizeof(*node)); + node->data = data; + node->left = node->right = rbnil(tree); + node->parent = parent; + if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0) + parent->left = node; + else + parent->right = node; + node->color = red; + + /* + * If the parent node is black we are all set, if it is red we have + * the following possible cases to deal with. We iterate through + * the rest of the tree to make sure none of the required properties + * is violated. + * + * 1) The uncle is red. We repaint both the parent and uncle black + * and repaint the grandparent node red. + * + * 2) The uncle is black and the new node is the right child of its + * parent, and the parent in turn is the left child of its parent. + * We do a left rotation to switch the roles of the parent and + * child, relying on further iterations to fixup the old parent. + * + * 3) The uncle is black and the new node is the left child of its + * parent, and the parent in turn is the left child of its parent. + * We switch the colors of the parent and grandparent and perform + * a right rotation around the grandparent. This makes the former + * parent the parent of the new node and the former grandparent. + * + * Note that because we use a sentinel for the root node we never + * need to worry about replacing the root. + */ + while (node->parent->color == red) { + struct rbnode *uncle; + if (node->parent == node->parent->parent->left) { + uncle = node->parent->parent->right; + if (uncle->color == red) { + node->parent->color = black; + uncle->color = black; + node->parent->parent->color = red; + node = node->parent->parent; + } else /* if (uncle->color == black) */ { + if (node == node->parent->right) { + node = node->parent; + rotate_left(tree, node); + } + node->parent->color = black; + node->parent->parent->color = red; + rotate_right(tree, node->parent->parent); + } + } else { /* if (node->parent == node->parent->parent->right) */ + uncle = node->parent->parent->left; + if (uncle->color == red) { + node->parent->color = black; + uncle->color = black; + node->parent->parent->color = red; + node = node->parent->parent; + } else /* if (uncle->color == black) */ { + if (node == node->parent->left) { + node = node->parent; + rotate_right(tree, node); + } + node->parent->color = black; + node->parent->parent->color = red; + rotate_left(tree, node->parent->parent); + } + } + } + rbfirst(tree)->color = black; /* first node is always black */ + debug_return_ptr(NULL); +} + +/* + * Look for a node matching key in tree. + * Returns a pointer to the node if found, else NULL. + */ +struct rbnode * +rbfind(struct rbtree *tree, void *key) +{ + struct rbnode *node = rbfirst(tree); + int res; + debug_decl(rbfind, SUDO_DEBUG_RBTREE) + + while (node != rbnil(tree)) { + if ((res = tree->compar(key, node->data)) == 0) + debug_return_ptr(node); + node = res < 0 ? node->left : node->right; + } + debug_return_ptr(NULL); +} + +/* + * Call func() for each node, passing it the node data and a cookie; + * If func() returns non-zero for a node, the traversal stops and the + * error value is returned. Returns 0 on successful traversal. + */ +int +rbapply_node(struct rbtree *tree, struct rbnode *node, + int (*func)(void *, void *), void *cookie, enum rbtraversal order) +{ + int error; + debug_decl(rbapply_node, SUDO_DEBUG_RBTREE) + + if (node != rbnil(tree)) { + if (order == preorder) + if ((error = func(node->data, cookie)) != 0) + debug_return_int(error); + if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0) + debug_return_int(error); + if (order == inorder) + if ((error = func(node->data, cookie)) != 0) + debug_return_int(error); + if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0) + debug_return_int(error); + if (order == postorder) + if ((error = func(node->data, cookie)) != 0) + debug_return_int(error); + } + debug_return_int(0); +} + +/* + * Returns the successor of node, or nil if there is none. + */ +static struct rbnode * +rbsuccessor(struct rbtree *tree, struct rbnode *node) +{ + struct rbnode *succ; + debug_decl(rbsuccessor, SUDO_DEBUG_RBTREE) + + if ((succ = node->right) != rbnil(tree)) { + while (succ->left != rbnil(tree)) + succ = succ->left; + } else { + /* No right child, move up until we find it or hit the root */ + for (succ = node->parent; node == succ->right; succ = succ->parent) + node = succ; + if (succ == rbroot(tree)) + succ = rbnil(tree); + } + debug_return_ptr(succ); +} + +/* + * Recursive portion of rbdestroy(). + */ +static void +_rbdestroy(struct rbtree *tree, struct rbnode *node, void (*destroy)(void *)) +{ + debug_decl(_rbdestroy, SUDO_DEBUG_RBTREE) + if (node != rbnil(tree)) { + _rbdestroy(tree, node->left, destroy); + _rbdestroy(tree, node->right, destroy); + if (destroy != NULL) + destroy(node->data); + efree(node); + } + debug_return; +} + +/* + * Destroy the specified tree, calling the destructor destroy + * for each node and then freeing the tree itself. + */ +void +rbdestroy(struct rbtree *tree, void (*destroy)(void *)) +{ + debug_decl(rbdestroy, SUDO_DEBUG_RBTREE) + _rbdestroy(tree, rbfirst(tree), destroy); + efree(tree); + debug_return; +} + +/* + * Delete node 'z' from the tree and return its data pointer. + */ +void *rbdelete(struct rbtree *tree, struct rbnode *z) +{ + struct rbnode *x, *y; + void *data = z->data; + debug_decl(rbdelete, SUDO_DEBUG_RBTREE) + + if (z->left == rbnil(tree) || z->right == rbnil(tree)) + y = z; + else + y = rbsuccessor(tree, z); + x = (y->left == rbnil(tree)) ? y->right : y->left; + + if ((x->parent = y->parent) == rbroot(tree)) { + rbfirst(tree) = x; + } else { + if (y == y->parent->left) + y->parent->left = x; + else + y->parent->right = x; + } + if (y->color == black) + rbrepair(tree, x); + if (y != z) { + y->left = z->left; + y->right = z->right; + y->parent = z->parent; + y->color = z->color; + z->left->parent = z->right->parent = y; + if (z == z->parent->left) + z->parent->left = y; + else + z->parent->right = y; + } + free(z); + + debug_return_ptr(data); +} + +/* + * Repair the tree after a node has been deleted by rotating and repainting + * colors to restore the 4 properties inherent in red-black trees. + */ +static void +rbrepair(struct rbtree *tree, struct rbnode *node) +{ + struct rbnode *sibling; + debug_decl(rbrepair, SUDO_DEBUG_RBTREE) + + while (node->color == black && node != rbroot(tree)) { + if (node == node->parent->left) { + sibling = node->parent->right; + if (sibling->color == red) { + sibling->color = black; + node->parent->color = red; + rotate_left(tree, node->parent); + sibling = node->parent->right; + } + if (sibling->right->color == black && sibling->left->color == black) { + sibling->color = red; + node = node->parent; + } else { + if (sibling->right->color == black) { + sibling->left->color = black; + sibling->color = red; + rotate_right(tree, sibling); + sibling = node->parent->right; + } + sibling->color = node->parent->color; + node->parent->color = black; + sibling->right->color = black; + rotate_left(tree, node->parent); + node = rbroot(tree); /* exit loop */ + } + } else { /* if (node == node->parent->right) */ + sibling = node->parent->left; + if (sibling->color == red) { + sibling->color = black; + node->parent->color = red; + rotate_right(tree, node->parent); + sibling = node->parent->left; + } + if (sibling->right->color == black && sibling->left->color == black) { + sibling->color = red; + node = node->parent; + } else { + if (sibling->left->color == black) { + sibling->right->color = black; + sibling->color = red; + rotate_left(tree, sibling); + sibling = node->parent->left; + } + sibling->color = node->parent->color; + node->parent->color = black; + sibling->left->color = black; + rotate_right(tree, node->parent); + node = rbroot(tree); /* exit loop */ + } + } + } + node->color = black; + + debug_return; +} diff --git a/plugins/sudoers/redblack.h b/plugins/sudoers/redblack.h new file mode 100644 index 0000000..eab5e8f --- /dev/null +++ b/plugins/sudoers/redblack.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2004, 2007, 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. + */ + +#ifndef _SUDO_REDBLACK_H +#define _SUDO_REDBLACK_H + +enum rbcolor { + red, + black +}; + +enum rbtraversal { + preorder, + inorder, + postorder +}; + +struct rbnode { + struct rbnode *left, *right, *parent; + void *data; + enum rbcolor color; +}; + +struct rbtree { + int (*compar)(const void *, const void *); + struct rbnode root; + struct rbnode nil; +}; + +#define rbapply(t, f, c, o) rbapply_node((t), (t)->root.left, (f), (c), (o)) +#define rbisempty(t) ((t)->root.left == &(t)->nil && (t)->root.right == &(t)->nil) +#define rbfirst(t) ((t)->root.left) +#define rbroot(t) (&(t)->root) +#define rbnil(t) (&(t)->nil) + +void *rbdelete(struct rbtree *, struct rbnode *); +int rbapply_node(struct rbtree *, struct rbnode *, + int (*)(void *, void *), void *, enum rbtraversal); +struct rbnode *rbfind(struct rbtree *, void *); +struct rbnode *rbinsert(struct rbtree *, void *); +struct rbtree *rbcreate(int (*)(const void *, const void *)); +void rbdestroy(struct rbtree *, void (*)(void *)); + +#endif /* _SUDO_REDBLACK_H */ diff --git a/plugins/sudoers/regress/iolog_path/check_iolog_path.c b/plugins/sudoers/regress/iolog_path/check_iolog_path.c new file mode 100644 index 0000000..f8079ad --- /dev/null +++ b/plugins/sudoers/regress/iolog_path/check_iolog_path.c @@ -0,0 +1,212 @@ +/* + * 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. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_SETLOCALE +# include +#endif +#include +#include +#include + +#define SUDO_ERROR_WRAP 0 + +#define _SUDO_MAIN +#include "sudoers.h" +#include "def_data.c" + +struct sudo_user sudo_user; +struct passwd *list_pw; +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +static char sessid[7]; + +static void +usage(void) +{ + fprintf(stderr, "usage: check_iolog_path datafile\n"); + exit(1); +} + +static int +do_check(char *dir_in, char *file_in, char *tdir_out, char *tfile_out) +{ + char *path, *slash; + char dir_out[4096], file_out[4096]; + struct tm *timeptr; + time_t now; + int error = 0; + + /* + * Expand any strftime(3) escapes + * XXX - want to pass timeptr to expand_iolog_path + */ + time(&now); + timeptr = localtime(&now); + strftime(dir_out, sizeof(dir_out), tdir_out, timeptr); + strftime(file_out, sizeof(file_out), tfile_out, timeptr); + + path = expand_iolog_path(NULL, dir_in, file_in, &slash); + *slash = '\0'; + if (strcmp(path, dir_out) != 0) { + warningx("%s: expected %s, got %s", dir_in, dir_out, path); + error = 1; + } + if (strcmp(slash + 1, file_out) != 0) { + warningx("%s: expected %s, got %s", file_in, file_out, slash + 1); + error = 1; + } + + return error; +} + +#define MAX_STATE 12 + +int +main(int argc, char *argv[]) +{ + struct passwd pw, rpw; + size_t len; + FILE *fp; + char line[2048]; + char *file_in = NULL, *file_out = NULL; + char *dir_in = NULL, *dir_out = NULL; + int state = 0; + int errors = 0; + int tests = 0; + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + setprogname(argc > 0 ? argv[0] : "check_iolog_path"); +#endif + + if (argc != 2) + usage(); + + fp = fopen(argv[1], "r"); + if (fp == NULL) + errorx(1, "unable to open %s", argv[1]); + + memset(&pw, 0, sizeof(pw)); + memset(&rpw, 0, sizeof(rpw)); + sudo_user.pw = &pw; + sudo_user._runas_pw = &rpw; + + /* + * Input consists of 12 lines: + * sequence number + * user name + * user gid + * runas user name + * runas gid + * hostname [short form] + * command + * dir [with escapes] + * file [with escapes] + * expanded dir + * expanded file + * empty line + */ + while (fgets(line, sizeof(line), fp) != NULL) { + len = strcspn(line, "\n"); + line[len] = '\0'; + + switch (state) { + case 0: + strlcpy(sessid, line, sizeof(sessid)); + break; + case 1: + if (user_name != NULL) + free(user_name); + user_name = strdup(line); + break; + case 2: + user_gid = atoi(line); + break; + case 3: + if (runas_pw->pw_name != NULL) + free(runas_pw->pw_name); + runas_pw->pw_name = strdup(line); + break; + case 4: + runas_pw->pw_gid = atoi(line); + break; + case 5: + user_shost = strdup(line); + break; + case 6: + user_base = strdup(line); + break; + case 7: + dir_in = strdup(line); + break; + case 8: + file_in = strdup(line); + break; + case 9: + dir_out = strdup(line); + break; + case 10: + file_out = strdup(line); + break; + case 11: + errors += do_check(dir_in, file_in, dir_out, file_out); + tests++; + break; + default: + errorx(1, "internal error, invalid state %d", state); + } + state = (state + 1) % MAX_STATE; + } + + if (tests != 0) { + printf("iolog_path: %d test%s run, %d errors, %d%% success rate\n", + tests, tests == 1 ? "" : "s", errors, + (tests - errors) * 100 / tests); + } + + exit(errors); +} + +void io_nextid(char *iolog_dir, char id[7]) +{ + memcpy(id, sessid, sizeof(sessid)); +} + +void +cleanup(int gotsig) +{ + return; +} diff --git a/plugins/sudoers/regress/iolog_path/data b/plugins/sudoers/regress/iolog_path/data new file mode 100644 index 0000000..dcc3942 --- /dev/null +++ b/plugins/sudoers/regress/iolog_path/data @@ -0,0 +1,96 @@ +000001 +nobody +1 +root +0 +somehost +id +/var/log/sudo-io +%%{bogus} +/var/log/sudo-io +%%{bogus} + +000001 +nobody +1 +root +0 +somehost +id +/var/log/sudo-io +%%{seq} +/var/log/sudo-io +%%{seq} + +000001 +nobody +1 +root +0 +somehost +id +/var/log/sudo-io +%{seq} +/var/log/sudo-io +00/00/01 + +000001 +nobody +1 +root +0 +somehost +id +/var/log/sudo-io/%{user} +%{seq} +/var/log/sudo-io/nobody +00/00/01 + +000001 +nobody +1 +root +0 +somehost +su +/var/log/sudo-io/%{user}/%{runas_user} +%{command}_%Y%m%s_%H%M +/var/log/sudo-io/nobody/root +su_%Y%m%s_%H%M + +000001 +nobody +1 +root +0 +somehost +su +/var/log/sudo-io/ +/%{user}/%{runas_user}/%{command}_%Y%m%s_%H%M +/var/log/sudo-io +nobody/root/su_%Y%m%s_%H%M + +000001 +nobody +1 +root +0 +somehost +su +/var/log/sudo-io/%d%m%Y +%{user}/%{runas_user}/%{command} +/var/log/sudo-io/%d%m%Y +nobody/root/su + +000001 +nobody +1 +root +0 +somehost +su +//////// +%{user}/%{runas_user}/%{command} +/ +nobody/root/su + diff --git a/plugins/sudoers/regress/logging/check_wrap.c b/plugins/sudoers/regress/logging/check_wrap.c new file mode 100644 index 0000000..2b9b8a2 --- /dev/null +++ b/plugins/sudoers/regress/logging/check_wrap.c @@ -0,0 +1,112 @@ +/* + * 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. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ + +#define SUDO_ERROR_WRAP 0 + +#include "missing.h" +#include "error.h" +#include "sudo_plugin.h" + +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +extern void writeln_wrap(FILE *fp, char *line, size_t len, size_t maxlen); + +static void +usage(void) +{ + fprintf(stderr, "usage: check_wrap inputfile\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + size_t len; + FILE *fp; + char *cp, *dash, *line, lines[2][2048]; + int which = 0; + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + setprogname(argc > 0 ? argv[0] : "check_wrap"); +#endif + + if (argc != 2) + usage(); + + fp = fopen(argv[1], "r"); + if (fp == NULL) + errorx(1, "unable to open %s", argv[1]); + + /* + * Each test record consists of a log entry on one line and a list of + * line lengths to test it with on the next. E.g. + * + * Jun 30 14:49:51 : millert : TTY=ttypn ; PWD=/usr/src/local/millert/hg/sudo/trunk/plugins/sudoers ; USER=root ; TSID=0004LD ; COMMAND=/usr/local/sbin/visudo + * 60-80,40 + */ + while ((line = fgets(lines[which], sizeof(lines[which]), fp)) != NULL) { + len = strcspn(line, "\n"); + line[len] = '\0'; + + /* If we read the 2nd line, parse list of line lengths and check. */ + if (which) { + for (cp = strtok(lines[1], ","); cp != NULL; cp = strtok(NULL, ",")) { + size_t maxlen; + /* May be either a number or a range. */ + len = maxlen = atoi(cp); + dash = strchr(cp, '-'); + if (dash) + maxlen = atoi(dash + 1); + while (len <= maxlen) { + printf("# word wrap at %d characters\n", (int)len); + writeln_wrap(stdout, lines[0], strlen(lines[0]), len); + len++; + } + } + } + which = !which; + } + + exit(0); +} + +void +cleanup(int gotsig) +{ + return; +} diff --git a/plugins/sudoers/regress/logging/check_wrap.in b/plugins/sudoers/regress/logging/check_wrap.in new file mode 100644 index 0000000..a2d1f08 --- /dev/null +++ b/plugins/sudoers/regress/logging/check_wrap.in @@ -0,0 +1,4 @@ +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +60-80,120,140 +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +60-80,120,140 diff --git a/plugins/sudoers/regress/logging/check_wrap.out.ok b/plugins/sudoers/regress/logging/check_wrap.out.ok new file mode 100644 index 0000000..4842443 --- /dev/null +++ b/plugins/sudoers/regress/logging/check_wrap.out.ok @@ -0,0 +1,175 @@ +# word wrap at 60 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 + ; PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 61 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 + ; PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 62 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 63 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 64 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 65 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 66 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 67 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 68 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 69 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 70 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 71 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool + list users +# word wrap at 72 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 73 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 74 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 75 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 76 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 77 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list + users +# word wrap at 78 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 79 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 80 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; + PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 120 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; + COMMAND=/opt/quest/bin/vastool list users +# word wrap at 140 characters +Jul 11 11:30:17 : tu2sp3-a : command not allowed ; TTY=pts/1 ; PWD=/home/tu2sp3-a ; USER=root ; COMMAND=/opt/quest/bin/vastool list users +# word wrap at 60 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 61 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 62 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 63 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 64 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 65 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 66 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 67 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 68 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 69 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; + TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 70 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT + ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 71 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT + ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 72 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 73 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 74 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 75 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 76 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 77 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 78 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 79 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; + PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 80 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build + ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm /root/.bash_profile +# word wrap at 120 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; + COMMAND=/bin/rm /root/.bash_profile +# word wrap at 140 characters +Jun 26 18:00:06 : millert : TTY=ttypm ; PWD=/usr/src/local/millert/hg/sudo/build ; USER=root ; TSID=0004KT ; COMMAND=/bin/rm + /root/.bash_profile diff --git a/plugins/sudoers/regress/parser/check_addr.c b/plugins/sudoers/regress/parser/check_addr.c new file mode 100644 index 0000000..a73de59 --- /dev/null +++ b/plugins/sudoers/regress/parser/check_addr.c @@ -0,0 +1,186 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include +#include +#include + +#include +#include +#include + +#define SUDO_ERROR_WRAP 0 + +#include "sudoers.h" +#include "parse.h" +#include "interfaces.h" + +static int check_addr_printf(int msg_type, const char *fmt, ...); + +/* for match_addr.c */ +struct interface *interfaces; +sudo_printf_t sudo_printf = check_addr_printf; + +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +static int +check_addr(char *input) +{ + int expected, matched; + size_t len; + char *cp; + + while (isspace((unsigned char)*input)) + input++; + + /* input: "addr[/mask] 1/0" */ + len = strcspn(input, " \t"); + cp = input + len; + while (isspace((unsigned char)*cp)) + cp++; + expected = atoi(cp); + input[len] = '\0'; + + matched = addr_matches(input); + if (matched != expected) { + warningx("%s %smatched: FAIL", input, matched ? "" : "not "); + return 1; + } + return 0; +} + +static void +usage(void) +{ + fprintf(stderr, "usage: check_addr datafile\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int ntests = 0, errors = 0; + char *cp, line[2048]; + size_t len; + FILE *fp; + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + setprogname(argc > 0 ? argv[0] : "check_addr"); +#endif + + if (argc != 2) + usage(); + + fp = fopen(argv[1], "r"); + if (fp == NULL) + errorx(1, "unable to open %s", argv[1]); + + /* + * Input is in the following format. There are two types of + * lines: interfaces, which sets the address and mask of the + * locally connected ethernet interfaces for the lines that + * follow and, address lines that include and address (with + * optional netmask) to match, followed by expected match status + * (1 or 0). E.g. + * + * interfaces: addr1/mask addr2/mask ... + * address: addr[/mask] 1/0 + * address: addr[/mask] 1/0 + * interfaces: addr3/mask addr4/mask ... + * address: addr[/mask] 1/0 + */ + + while (fgets(line, sizeof(line), fp) != NULL) { + len = strcspn(line, "\n"); + line[len] = '\0'; + + /* Ignore comments */ + if ((cp = strchr(line, '#')) != NULL) + *cp = '\0'; + + /* Skip blank lines. */ + if (line[0] == '\0') + continue; + + if (strncmp(line, "interfaces:", sizeof("interfaces:") - 1) == 0) { + set_interfaces(line + sizeof("interfaces:") - 1); + } else if (strncmp(line, "address:", sizeof("address:") - 1) == 0) { + errors += check_addr(line + sizeof("address:") - 1); + ntests++; + } else { + warningx("unexpected data line: %s\n", line); + continue; + } + } + + printf("check_addr: %d tests run, %d errors, %d%% success rate\n", + ntests, errors, (ntests - errors) * 100 / ntests); + + exit(errors); +} + +/* STUB */ +void +cleanup(int gotsig) +{ + return; +} + +static int +check_addr_printf(int msg_type, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + + switch (msg_type) { + case SUDO_CONV_INFO_MSG: + fp = stdout; + break; + case SUDO_CONV_ERROR_MSG: + fp = stderr; + break; + default: + errno = EINVAL; + return -1; + } + + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); + + return 0; +} diff --git a/plugins/sudoers/regress/parser/check_addr.in b/plugins/sudoers/regress/parser/check_addr.in new file mode 100644 index 0000000..a3c8612 --- /dev/null +++ b/plugins/sudoers/regress/parser/check_addr.in @@ -0,0 +1,13 @@ +# +interfaces: 10.5.54.73/255.255.240.0 +address: 10.5.48.0 1 +address: 10.5.54.0/20 1 +# +interfaces: 128.138.243.151/255.255.255.0 128.138.241.53/255.255.255.0 +address: 128.138.243.0 1 +address: 128.138.243.0/24 1 +address: 128.138.241.0 1 +address: 128.138.241.0/24 1 +address: 128.138.242.0/24 0 +address: 128.138.0.0 0 +address: 128.138.0.0/16 1 diff --git a/plugins/sudoers/regress/parser/check_fill.c b/plugins/sudoers/regress/parser/check_fill.c new file mode 100644 index 0000000..e0f3921 --- /dev/null +++ b/plugins/sudoers/regress/parser/check_fill.c @@ -0,0 +1,197 @@ +/* + * 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. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#include +#include + +#define SUDO_ERROR_WRAP 0 + +#include "list.h" +#include "parse.h" +#include "toke.h" +#include "sudo_plugin.h" +#include + +/* + * TODO: test realloc + */ + +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +YYSTYPE yylval; + +struct fill_test { + const char *input; + const char *output; + int len; + int addspace; +}; + +/* + * In "normal" fill, anything can be escaped and hex chars are expanded. + */ +static struct fill_test txt_data[] = { + { "Embedded\\x20Space", "Embedded Space", 0 }, + { "\\x20Leading", " Leading", 0 }, + { "Trailing\\x20", "Trailing ", 0 }, + { "Multiple\\x20\\x20Spaces", "Multiple Spaces", 0 }, + { "Hexparse\\x200Check", "Hexparse 0Check", 0 }, + { "Escaped\\\\Escape", "Escaped\\Escape", 0 }, + { "LongGroupName", "LongGrou", 8 } +}; + +/* + * The only escaped chars in a command should be [,:= \t#] + * The rest are done by glob() or fnmatch(). + */ +static struct fill_test cmd_data[] = { + { "foo\\,bar", "foo,bar", 0 }, + { "this\\:that", "this:that", 0 }, + { "foo\\=bar", "foo=bar", 0 }, + { "tab\\\tstop", "tab\tstop", 0 }, + { "not a \\#comment", "not a #comment", 0 } +}; + +/* + * No escaped characters in command line args. + * Arguments get appended. + */ +static struct fill_test args_data[] = { + { "/", "/", 0, 0 }, + { "-type", "/ -type", 0, 1 }, + { "f", "/ -type f", 0, 1 }, + { "-exec", "/ -type f -exec", 0, 1 }, + { "ls", "/ -type f -exec ls", 0, 1 }, + { "{}", "/ -type f -exec ls {}", 0, 1 } +}; + +static int +check_fill(const char *input, int len, int addspace, const char *expect, char **resultp) +{ + if (!fill(input, len)) + return -1; + *resultp = yylval.string; + return !strcmp(yylval.string, expect); +} + +static int +check_fill_cmnd(const char *input, int len, int addspace, const char *expect, char **resultp) +{ + if (!fill_cmnd(input, len)) + return -1; + *resultp = yylval.command.cmnd; + return !strcmp(yylval.command.cmnd, expect); +} + +static int +check_fill_args(const char *input, int len, int addspace, const char *expect, char **resultp) +{ + if (!fill_args(input, len, addspace)) + return -1; + *resultp = yylval.command.args; + return !strcmp(yylval.command.args, expect); +} + +static int +do_tests(int (*checker)(const char *, int, int, const char *, char **), + struct fill_test *data, size_t ntests) +{ + int i, len; + int errors = 0; + char *result; + + for (i = 0; i < ntests; i++) { + if (data[i].len == 0) + len = strlen(data[i].input); + else + len = data[i].len; + + switch ((*checker)(data[i].input, len, data[i].addspace, data[i].output, &result)) { + case 0: + /* no match */ + fprintf(stderr, "Failed parsing %.*s: expected [%s], got [%s]\n", + (int)data[i].len, data[i].input, data[i].output, result); + errors++; + break; + case 1: + /* match */ + break; + default: + /* error */ + fprintf(stderr, "Failed parsing %.*s: fill function failure\n", + (int)data[i].len, data[i].input); + errors++; + break; + } + } + + return errors; +} + +int +main(int argc, char *argv[]) +{ + int ntests, errors = 0; + + errors += do_tests(check_fill, txt_data, sizeof(txt_data) / sizeof(txt_data[0])); + errors += do_tests(check_fill_cmnd, cmd_data, sizeof(cmd_data) / sizeof(cmd_data[0])); + errors += do_tests(check_fill_args, args_data, sizeof(args_data) / sizeof(args_data[0])); + + ntests = sizeof(txt_data) / sizeof(txt_data[0]) + + sizeof(cmd_data) / sizeof(cmd_data[0]) + + sizeof(args_data) / sizeof(args_data[0]); + printf("check_fill: %d tests run, %d errors, %d%% success rate\n", + ntests, errors, (ntests - errors) * 100 / ntests); + + exit(errors); +} + +/* STUB */ +void +cleanup(int gotsig) +{ + return; +} + +/* STUB */ +void +yyerror(const char *s) +{ + return; +} diff --git a/plugins/sudoers/regress/sudoers/test1.in b/plugins/sudoers/regress/sudoers/test1.in new file mode 100644 index 0000000..872925c --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test1.in @@ -0,0 +1,8 @@ +# +# Verify that all command tags are parsed OK. +# See http://www.sudo.ws/bugs/show_bug.cgi?id=437 +# +user1 ALL = LOG_INPUT: LOG_OUTPUT: /usr/bin/su -:\ + ALL = NOLOG_INPUT: NOLOG_OUTPUT: /usr/bin/id +user2 ALL = NOPASSWD: NOEXEC: SETENV: /usr/bin/vi:\ + ALL = PASSWD: EXEC: NOSETENV: /usr/bin/echo diff --git a/plugins/sudoers/regress/sudoers/test1.out.ok b/plugins/sudoers/regress/sudoers/test1.out.ok new file mode 100644 index 0000000..44cb652 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test1.out.ok @@ -0,0 +1,6 @@ +Parses OK. + + + +user1 ALL = /usr/bin/su - : ALL = /usr/bin/id +user2 ALL = NOPASSWD: NOEXEC: /usr/bin/vi : ALL = PASSWD: EXEC: /usr/bin/echo diff --git a/plugins/sudoers/regress/sudoers/test1.toke.ok b/plugins/sudoers/regress/sudoers/test1.toke.ok new file mode 100644 index 0000000..3f3a7ad --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test1.toke.ok @@ -0,0 +1,6 @@ +# +# +# +# +WORD(5) ALL = LOG_INPUT LOG_OUTPUT COMMAND ARG : ALL = NOLOG_INPUT NOLOG_OUTPUT COMMAND +WORD(5) ALL = NOPASSWD NOEXEC SETENV COMMAND : ALL = PASSWD EXEC NOSETENV COMMAND diff --git a/plugins/sudoers/regress/sudoers/test2.in b/plugins/sudoers/regress/sudoers/test2.in new file mode 100644 index 0000000..cfdfaa3 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test2.in @@ -0,0 +1,60 @@ +# Check quoted user name in User_Alias +User_Alias UA1 = "foo" +User_Alias UA2 = "foo.bar" +User_Alias UA3 = "foo\"" +User_Alias UA4 = "foo:bar" +User_Alias UA5 = "foo:bar\"" + +# Check quoted group name in User_Alias +User_Alias UA6 = "%baz" +User_Alias UA7 = "%baz.biz" + +# Check quoted non-Unix group name in User_Alias +User_Alias UA8 = "%:C/non UNIX 0 c" +User_Alias UA9 = "%:C/non\'UNIX\'1 c" +User_Alias UA10 = "%:C/non\"UNIX\"0 c" +User_Alias UA11 = "%:C/non_UNIX_0 c" +User_Alias UA12 = "%:C/non\'UNIX_3 c" + +# Check quoted user name in Runas_Alias +Runas_Alias RA1 = "foo" +Runas_Alias RA2 = "foo\"" +Runas_Alias RA3 = "foo:bar" +Runas_Alias RA4 = "foo:bar\"" + +# Check quoted host name in Defaults +Defaults@"somehost" set_home +Defaults@"quoted\"" set_home + +# Check quoted user name in Defaults +Defaults:"you" set_home +Defaults:"us\"" set_home +Defaults:"%them" set_home +Defaults:"%: non UNIX 0 c" set_home +Defaults:"+net" set_home + +# Check quoted runas name in Defaults +Defaults>"someone" set_home +Defaults>"some one" set_home + +# Check quoted command in Defaults +# XXX - not currently supported +#Defaults!"/bin/ls -l" set_home +#Defaults!"/bin/ls -l \"foo\"" set_home + +# Check quoted user, runas and host name in Cmnd_Spec +"foo" "hosta" = ("root") ALL +"foo.bar" "hostb" = ("root") ALL +"foo\"" "hostc" = ("root") ALL +"foo:bar" "hostd" = ("root") ALL +"foo:bar\"" "hoste" = ("root") ALL + +# Check quoted group/netgroup name in Cmnd_Spec +"%baz" "hosta" = ("root") ALL +"%baz.biz" "hostb" = ("root") ALL +"%:C/non UNIX 0 c" "hostc" = ("root") ALL +"%:C/non\'UNIX\'1 c" "hostd" = ("root") ALL +"%:C/non\"UNIX\"0 c" "hoste" = ("root") ALL +"%:C/non_UNIX_0 c" "hostf" = ("root") ALL +"%:C/non\'UNIX_3 c" "hostg" = ("root") ALL +"+netgr" "hosth" = ("root") ALL diff --git a/plugins/sudoers/regress/sudoers/test2.out.ok b/plugins/sudoers/regress/sudoers/test2.out.ok new file mode 100644 index 0000000..8f55faf --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test2.out.ok @@ -0,0 +1,42 @@ +Parses OK. + +Defaults@somehost set_home +Defaults@quoted" set_home +Defaults:you set_home +Defaults:us" set_home +Defaults:%them set_home +Defaults:%: non UNIX 0 c set_home +Defaults:+net set_home +Defaults>someone set_home +Defaults>some one set_home + +Runas_Alias RA1 = foo +Runas_Alias RA2 = foo" +Runas_Alias RA3 = foo:bar +Runas_Alias RA4 = foo:bar" +User_Alias UA1 = foo +User_Alias UA10 = %:C/non"UNIX"0 c +User_Alias UA11 = %:C/non_UNIX_0 c +User_Alias UA12 = %:C/non\'UNIX_3 c +User_Alias UA2 = foo.bar +User_Alias UA3 = foo" +User_Alias UA4 = foo:bar +User_Alias UA5 = foo:bar" +User_Alias UA6 = %baz +User_Alias UA7 = %baz.biz +User_Alias UA8 = %:C/non UNIX 0 c +User_Alias UA9 = %:C/non\'UNIX\'1 c + +foo hosta = (root) ALL +foo.bar hostb = (root) ALL +foo" hostc = (root) ALL +foo:bar hostd = (root) ALL +foo:bar" hoste = (root) ALL +%baz hosta = (root) ALL +%baz.biz hostb = (root) ALL +%:C/non UNIX 0 c hostc = (root) ALL +%:C/non\'UNIX\'1 c hostd = (root) ALL +%:C/non"UNIX"0 c hoste = (root) ALL +%:C/non_UNIX_0 c hostf = (root) ALL +%:C/non\'UNIX_3 c hostg = (root) ALL ++netgr hosth = (root) ALL diff --git a/plugins/sudoers/regress/sudoers/test2.toke.ok b/plugins/sudoers/regress/sudoers/test2.toke.ok new file mode 100644 index 0000000..fcd7b73 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test2.toke.ok @@ -0,0 +1,60 @@ +# +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) + +# +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP + +# +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP +USERALIAS ALIAS = BEGINSTR STRBODY BACKSLASH STRBODY BACKSLASH STRBODY ENDSTR USERGROUP +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR USERGROUP +USERALIAS ALIAS = BEGINSTR STRBODY BACKSLASH STRBODY ENDSTR USERGROUP + +# +RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +RUNASALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) + +# +DEFAULTS_HOST BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_HOST BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR + +# +DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR + +# +DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR + +# +# +# +# + +# +BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR WORD(4) BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL + +# +BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY BACKSLASH STRBODY BACKSLASH STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY BACKSLASH STRBODY ENDSTR USERGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL +BEGINSTR STRBODY ENDSTR NETGROUP BEGINSTR STRBODY ENDSTR WORD(4) = ( BEGINSTR STRBODY ENDSTR WORD(4) ) ALL diff --git a/plugins/sudoers/regress/sudoers/test3.in b/plugins/sudoers/regress/sudoers/test3.in new file mode 100644 index 0000000..82fcd83 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test3.in @@ -0,0 +1,6 @@ +# Test whitespace in User_List as part of a per-user Defaults entry +User_Alias FOO = foo, bar +Defaults:FOO env_reset +Defaults:foo,bar env_reset +Defaults:foo,\ bar env_reset +Defaults:foo, bar env_reset diff --git a/plugins/sudoers/regress/sudoers/test3.out.ok b/plugins/sudoers/regress/sudoers/test3.out.ok new file mode 100644 index 0000000..af2f402 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test3.out.ok @@ -0,0 +1,9 @@ +Parses OK. + +Defaults:FOO env_reset +Defaults:foo,bar env_reset +Defaults:foo, bar env_reset +Defaults:foo,bar env_reset + +User_Alias FOO = foo, bar + diff --git a/plugins/sudoers/regress/sudoers/test3.toke.ok b/plugins/sudoers/regress/sudoers/test3.toke.ok new file mode 100644 index 0000000..49f2e51 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test3.toke.ok @@ -0,0 +1,6 @@ +# +USERALIAS ALIAS = WORD(5) , WORD(5) +DEFAULTS_USER ALIAS DEFVAR +DEFAULTS_USER WORD(5) , WORD(5) DEFVAR +DEFAULTS_USER WORD(5) , WORD(5) DEFVAR +DEFAULTS_USER WORD(5) , WORD(5) DEFVAR diff --git a/plugins/sudoers/regress/sudoers/test4.in b/plugins/sudoers/regress/sudoers/test4.in new file mode 100644 index 0000000..b8df454 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test4.in @@ -0,0 +1,7 @@ +# Test line continuation with anchored matches +User_Alias FOO = foo \ +: BAR = bar + +# This used to pass for sudo < 1.8.1 (though it should not have) +User_Alias FOO = foo \ +User_Alias BAR = bar diff --git a/plugins/sudoers/regress/sudoers/test4.out.ok b/plugins/sudoers/regress/sudoers/test4.out.ok new file mode 100644 index 0000000..1c0bc4b --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test4.out.ok @@ -0,0 +1,6 @@ +Parse error in sudoers near line 7. + + +User_Alias BAR = bar +User_Alias FOO = foo + diff --git a/plugins/sudoers/regress/sudoers/test4.toke.ok b/plugins/sudoers/regress/sudoers/test4.toke.ok new file mode 100644 index 0000000..a225792 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test4.toke.ok @@ -0,0 +1,5 @@ +# +USERALIAS ALIAS = WORD(5) : ALIAS = WORD(5) + +# +USERALIAS ALIAS = WORD(5) ERROR <*> ALIAS = WORD(5) diff --git a/plugins/sudoers/regress/sudoers/test5.in b/plugins/sudoers/regress/sudoers/test5.in new file mode 100644 index 0000000..354f589 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test5.in @@ -0,0 +1,3 @@ +# Test empty string in User_Alias and Command_Spec +User_Alias FOO = "" +"" ALL = ALL diff --git a/plugins/sudoers/regress/sudoers/test5.out.ok b/plugins/sudoers/regress/sudoers/test5.out.ok new file mode 100644 index 0000000..3f6e2f2 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test5.out.ok @@ -0,0 +1,4 @@ +Parse error in sudoers near line 2. + + + diff --git a/plugins/sudoers/regress/sudoers/test5.toke.ok b/plugins/sudoers/regress/sudoers/test5.toke.ok new file mode 100644 index 0000000..9376455 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test5.toke.ok @@ -0,0 +1,3 @@ +# +USERALIAS ALIAS = BEGINSTR ENDSTR ERROR <*> +BEGINSTR ENDSTR ERROR <*> ALL = ALL diff --git a/plugins/sudoers/regress/sudoers/test6.in b/plugins/sudoers/regress/sudoers/test6.in new file mode 100644 index 0000000..e804571 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test6.in @@ -0,0 +1,15 @@ +# Check that uids work in per-user and per-runas Defaults +Defaults:#123 set_home +Defaults>#123 set_home +Defaults:"#123" set_home +Defaults>"#123" set_home + +# Check that uids work in a Command_Spec +#0 ALL = ALL +#0 ALL = (#0 : #0) ALL +"#0" ALL = ALL +"#0" ALL = ("#0" : "#0") ALL + +# Check that gids work in a Command_Spec +%#0 ALL = ALL +"%#0" ALL = ALL diff --git a/plugins/sudoers/regress/sudoers/test6.out.ok b/plugins/sudoers/regress/sudoers/test6.out.ok new file mode 100644 index 0000000..275add6 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test6.out.ok @@ -0,0 +1,14 @@ +Parses OK. + +Defaults:#123 set_home +Defaults>#123 set_home +Defaults:#123 set_home +Defaults>#123 set_home + + +#0 ALL = ALL +#0 ALL = (#0 : #0) ALL +#0 ALL = ALL +#0 ALL = (#0 : #0) ALL +%#0 ALL = ALL +%#0 ALL = ALL diff --git a/plugins/sudoers/regress/sudoers/test6.toke.ok b/plugins/sudoers/regress/sudoers/test6.toke.ok new file mode 100644 index 0000000..a9c0522 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test6.toke.ok @@ -0,0 +1,15 @@ +# +DEFAULTS_USER WORD(5) DEFVAR +DEFAULTS_RUNAS WORD(5) DEFVAR +DEFAULTS_USER BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR +DEFAULTS_RUNAS BEGINSTR STRBODY ENDSTR WORD(4) DEFVAR + +# +WORD(5) ALL = ALL +WORD(5) ALL = ( WORD(5) : WORD(5) ) ALL +BEGINSTR STRBODY ENDSTR WORD(4) ALL = ALL +BEGINSTR STRBODY ENDSTR WORD(4) ALL = ( BEGINSTR STRBODY ENDSTR WORD(4) : BEGINSTR STRBODY ENDSTR WORD(4) ) ALL + +# +USERGROUP ALL = ALL +BEGINSTR STRBODY ENDSTR USERGROUP ALL = ALL diff --git a/plugins/sudoers/regress/sudoers/test7.in b/plugins/sudoers/regress/sudoers/test7.in new file mode 100644 index 0000000..7b241d0 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test7.in @@ -0,0 +1,7 @@ +# These should all be syntax errors +User_Alias FOO1 = "%" +User_Alias FOO2 = "%:" +User_Alias FOO3 = "+" +User_Alias FOO4 = % +User_Alias FOO5 = %: +User_Alias FOO6 = + diff --git a/plugins/sudoers/regress/sudoers/test7.out.ok b/plugins/sudoers/regress/sudoers/test7.out.ok new file mode 100644 index 0000000..3f6e2f2 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test7.out.ok @@ -0,0 +1,4 @@ +Parse error in sudoers near line 2. + + + diff --git a/plugins/sudoers/regress/sudoers/test7.toke.ok b/plugins/sudoers/regress/sudoers/test7.toke.ok new file mode 100644 index 0000000..a5bf018 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test7.toke.ok @@ -0,0 +1,7 @@ +# +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR ERROR <*> +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR ERROR <*> +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR ERROR <*> +USERALIAS ALIAS = ERROR <*> +USERALIAS ALIAS = ERROR <*> +USERALIAS ALIAS = ERROR <*> diff --git a/plugins/sudoers/regress/sudoers/test8.in b/plugins/sudoers/regress/sudoers/test8.in new file mode 100644 index 0000000..d25e834 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test8.in @@ -0,0 +1,8 @@ +# Test quoted strings +User_Alias UA1 = "xy" +User_Alias UA2 = "x\ +y" +User_Alias UA3 = x\"y + +# A newline in the middle of a string is an error +User_Alias UA4 = "x diff --git a/plugins/sudoers/regress/sudoers/test8.out.ok b/plugins/sudoers/regress/sudoers/test8.out.ok new file mode 100644 index 0000000..2f07300 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test8.out.ok @@ -0,0 +1,7 @@ +Parse error in sudoers near line 8. + + +User_Alias UA1 = xy +User_Alias UA2 = xy +User_Alias UA3 = x"y + diff --git a/plugins/sudoers/regress/sudoers/test8.toke.ok b/plugins/sudoers/regress/sudoers/test8.toke.ok new file mode 100644 index 0000000..0f7e2a9 --- /dev/null +++ b/plugins/sudoers/regress/sudoers/test8.toke.ok @@ -0,0 +1,7 @@ +# +USERALIAS ALIAS = BEGINSTR STRBODY ENDSTR WORD(4) +USERALIAS ALIAS = BEGINSTR STRBODY STRBODY ENDSTR WORD(4) +USERALIAS ALIAS = WORD(5) + +# +USERALIAS ALIAS = BEGINSTR STRBODY ERROR <*> ERROR \ No newline at end of file diff --git a/plugins/sudoers/regress/testsudoers/test1.out.ok b/plugins/sudoers/regress/testsudoers/test1.out.ok new file mode 100644 index 0000000..f980873 --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test1.out.ok @@ -0,0 +1,8 @@ +Parses OK. + +Entries for user root: + +ALL = ALL + host matched + +Command unmatched diff --git a/plugins/sudoers/regress/testsudoers/test1.sh b/plugins/sudoers/regress/testsudoers/test1.sh new file mode 100755 index 0000000..a6358b3 --- /dev/null +++ b/plugins/sudoers/regress/testsudoers/test1.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# Test for NULL dereference with "sudo -g group" when the sudoers rule +# has no runas user or group listed. +# This is RedHat bug Bug 667103. +# + +./testsudoers -g bin root id < + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#include + +#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 */ +#ifdef _AIX +# include +#endif +#include +#include +#include + +#include "sudoers.h" + +/* + * Prototypes + */ +#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) +static struct group_list *runas_setgroups(void); +#endif + +/* + * We keep track of the current permisstions and use a stack to restore + * the old permissions. A depth of 16 is overkill. + */ +struct perm_state { + uid_t ruid; + uid_t euid; +#if defined(HAVE_SETRESUID) || defined(ID_SAVED) + uid_t suid; +#endif + gid_t rgid; + gid_t egid; +#if defined(HAVE_SETRESUID) || defined(ID_SAVED) + gid_t sgid; +#endif + struct group_list *grlist; +}; + +#define PERM_STACK_MAX 16 +static struct perm_state perm_stack[PERM_STACK_MAX]; +static int perm_stack_depth = 0; + +#undef ID +#define ID(x) (state->x == ostate->x ? -1 : state->x) +#undef OID +#define OID(x) (ostate->x == state->x ? -1 : ostate->x) + +void +rewind_perms(void) +{ + debug_decl(rewind_perms, SUDO_DEBUG_PERMS) + + while (perm_stack_depth > 1) + restore_perms(); + grlist_delref(perm_stack[0].grlist); + + debug_return; +} + +#if defined(HAVE_SETRESUID) + +#define UID_CHANGED (state->ruid != ostate->ruid || state->euid != ostate->euid || state->suid != ostate->suid) +#define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid || state->sgid != ostate->sgid) + +/* + * Set real and effective and saved uids and gids based on perm. + * We always retain a saved uid of 0 unless we are headed for an exec(). + * We only flip the effective gid since it only changes for PERM_SUDOERS. + * This version of set_perms() works fine with the "stay_setuid" option. + */ +int +set_perms(int perm) +{ + struct perm_state *state, *ostate = NULL; + char errbuf[1024]; + int noexit; + debug_decl(set_perms, SUDO_DEBUG_PERMS) + + noexit = ISSET(perm, PERM_NOEXIT); + CLR(perm, PERM_MASK); + + if (perm_stack_depth == PERM_STACK_MAX) { + strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + + state = &perm_stack[perm_stack_depth]; + if (perm != PERM_INITIAL) { + if (perm_stack_depth == 0) { + strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + ostate = &perm_stack[perm_stack_depth - 1]; + } + + switch (perm) { + case PERM_INITIAL: + /* Stash initial state */ +#ifdef HAVE_GETRESUID + if (getresuid(&state->ruid, &state->euid, &state->suid)) { + strlcpy(errbuf, "PERM_INITIAL: getresuid", sizeof(errbuf)); + goto bad; + + } + if (getresgid(&state->rgid, &state->egid, &state->sgid)) { + strlcpy(errbuf, "PERM_INITIAL: getresgid", sizeof(errbuf)); + goto bad; + } +#else + state->ruid = getuid(); + state->euid = geteuid(); + state->suid = state->euid; /* in case we are setuid */ + + state->rgid = getgid(); + state->egid = getegid(); + state->sgid = state->egid; /* in case we are setgid */ +#endif + state->grlist = user_group_list; + grlist_addref(state->grlist); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: " + "ruid: %d, euid: %d, suid: %d, rgid: %d, egid: %d, sgid: %d", + __func__, (int)state->ruid, (int)state->euid, (int)state->suid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + break; + + case PERM_ROOT: + state->ruid = ROOT_UID; + state->euid = ROOT_UID; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_ROOT: setresuid(%d, %d, %d)", + ID(ruid), ID(euid), ID(suid)); + goto bad; + } + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->sgid = ostate->sgid; + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + break; + + case PERM_USER: + state->rgid = ostate->rgid; + state->egid = user_gid; + state->sgid = ostate->sgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) { + snprintf(errbuf, sizeof(errbuf), "PERM_USER: setresgid(%d, %d, %d)", + ID(rgid), ID(egid), ID(sgid)); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + state->euid = user_uid; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) { + snprintf(errbuf, sizeof(errbuf), "PERM_USER: setresuid(%d, %d, %d)", + ID(ruid), ID(euid), ID(suid)); + goto bad; + } + break; + + case PERM_FULL_USER: + /* headed for exec() */ + state->rgid = user_gid; + state->egid = user_gid; + state->sgid = user_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setresgid(%d, %d, %d)", + ID(rgid), ID(egid), ID(sgid)); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + state->euid = user_uid; + state->suid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setresuid(%d, %d, %d)", + ID(ruid), ID(euid), ID(suid)); + goto bad; + } + break; + + case PERM_RUNAS: + state->rgid = ostate->rgid; + state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; + state->sgid = ostate->sgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) { + strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf)); + goto bad; + } + state->grlist = runas_setgroups(); + state->ruid = ostate->ruid; + state->euid = runas_pw ? runas_pw->pw_uid : user_uid; + state->suid = ostate->suid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) { + strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf)); + goto bad; + } + break; + + case PERM_SUDOERS: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + + /* assumes euid == ROOT_UID, ruid == user */ + state->rgid = ostate->rgid; + state->egid = sudoers_gid; + state->sgid = ostate->sgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setresgid(ID(rgid), ID(egid), ID(sgid))) { + strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf)); + goto bad; + } + + state->ruid = ROOT_UID; + /* + * If sudoers_uid == ROOT_UID and sudoers_mode is group readable + * we use a non-zero uid in order to avoid NFS lossage. + * Using uid 1 is a bit bogus but should work on all OS's. + */ + if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) + state->euid = 1; + else + state->euid = sudoers_uid; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_SUDOERS: setresuid(%d, %d, %d)", + ID(ruid), ID(euid), ID(suid)); + goto bad; + } + break; + + case PERM_TIMESTAMP: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->sgid = ostate->sgid; + state->ruid = ROOT_UID; + state->euid = timestamp_uid; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setresuid(ID(ruid), ID(euid), ID(suid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_TIMESTAMP: setresuid(%d, %d, %d)", + ID(ruid), ID(euid), ID(suid)); + goto bad; + } + break; + } + + perm_stack_depth++; + debug_return_bool(1); +bad: + warningx("%s: %s", errbuf, + errno == EAGAIN ? _("too many processes") : strerror(errno)); + if (noexit) + debug_return_bool(0); + exit(1); +} + +void +restore_perms(void) +{ + struct perm_state *state, *ostate; + debug_decl(restore_perms, SUDO_DEBUG_PERMS) + + if (perm_stack_depth < 2) + debug_return; + + state = &perm_stack[perm_stack_depth - 1]; + ostate = &perm_stack[perm_stack_depth - 2]; + perm_stack_depth--; + + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d, %d] -> [%d, %d, %d]", + __func__, (int)state->ruid, (int)state->euid, (int)state->suid, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d, %d] -> [%d, %d, %d]", + __func__, (int)state->rgid, (int)state->egid, (int)state->sgid, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid); + + /* XXX - more cases here where euid != ruid */ + if (OID(euid) == ROOT_UID) { + if (setresuid(-1, ROOT_UID, -1)) { + warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]", + (int)state->ruid, (int)state->euid, (int)state->suid, + -1, ROOT_UID, -1); + goto bad; + } + } + if (setresuid(OID(ruid), OID(euid), OID(suid))) { + warning("setresuid() [%d, %d, %d] -> [%d, %d, %d]", + (int)state->ruid, (int)state->euid, (int)state->suid, + (int)OID(ruid), (int)OID(euid), (int)OID(suid)); + goto bad; + } + if (setresgid(OID(rgid), OID(egid), OID(sgid))) { + warning("setresgid() [%d, %d, %d] -> [%d, %d, %d]", + (int)state->rgid, (int)state->egid, (int)state->sgid, + (int)OID(rgid), (int)OID(egid), (int)OID(sgid)); + goto bad; + } + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) { + warning("setgroups()"); + goto bad; + } + } + grlist_delref(state->grlist); + debug_return; + +bad: + exit(1); +} + +#elif defined(_AIX) && defined(ID_SAVED) + +#define UID_CHANGED (state->ruid != ostate->ruid || state->euid != ostate->euid || state->suid != ostate->suid) +#define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid || state->sgid != ostate->sgid) + +/* + * Set real and effective and saved uids and gids based on perm. + * We always retain a saved uid of 0 unless we are headed for an exec(). + * We only flip the effective gid since it only changes for PERM_SUDOERS. + * This version of set_perms() works fine with the "stay_setuid" option. + */ +int +set_perms(int perm) +{ + struct perm_state *state, *ostate = NULL; + char errbuf[1024]; + int noexit; + debug_decl(set_perms, SUDO_DEBUG_PERMS) + + noexit = ISSET(perm, PERM_NOEXIT); + CLR(perm, PERM_MASK); + + if (perm_stack_depth == PERM_STACK_MAX) { + strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + + state = &perm_stack[perm_stack_depth]; + if (perm != PERM_INITIAL) { + if (perm_stack_depth == 0) { + strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + ostate = &perm_stack[perm_stack_depth - 1]; + } + + switch (perm) { + case PERM_INITIAL: + /* Stash initial state */ + state->ruid = getuidx(ID_REAL); + state->euid = getuidx(ID_EFFECTIVE); + state->suid = getuidx(ID_SAVED); + state->rgid = getgidx(ID_REAL); + state->egid = getgidx(ID_EFFECTIVE); + state->sgid = getgidx(ID_SAVED); + state->grlist = user_group_list; + grlist_addref(state->grlist); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: " + "ruid: %d, euid: %d, suid: %d, rgid: %d, egid: %d, sgid: %d", + __func__, (unsigned int)state->ruid, (unsigned int)state->euid, + (unsigned int)state->suid, (unsigned int)state->rgid, + (unsigned int)state->egid, (unsigned int)state->sgid); + break; + + case PERM_ROOT: + state->ruid = ROOT_UID; + state->euid = ROOT_UID; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_ROOT: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + ROOT_UID); + goto bad; + } + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->sgid = ostate->sgid; + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + break; + + case PERM_USER: + state->rgid = ostate->rgid; + state->egid = user_gid; + state->sgid = ostate->sgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setgidx(ID_EFFECTIVE, user_gid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: setgidx(ID_EFFECTIVE, %d)", user_gid); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + state->euid = user_uid; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (ostate->euid != ROOT_UID || ostate->suid != ROOT_UID) { + if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + ROOT_UID); + goto bad; + } + } + if (setuidx(ID_EFFECTIVE|ID_REAL, user_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: setuidx(ID_EFFECTIVE|ID_REAL, %d)", user_uid); + goto bad; + } + break; + + case PERM_FULL_USER: + /* headed for exec() */ + state->rgid = user_gid; + state->egid = user_gid; + state->sgid = user_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, user_gid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + user_gid); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + state->euid = user_uid; + state->suid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, user_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + user_uid); + goto bad; + } + break; + + case PERM_RUNAS: + state->rgid = ostate->rgid; + state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; + state->sgid = ostate->sgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setgidx(ID_EFFECTIVE, state->egid)) { + strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf)); + goto bad; + } + state->grlist = runas_setgroups(); + state->ruid = ostate->ruid; + state->euid = runas_pw ? runas_pw->pw_uid : user_uid; + state->suid = ostate->suid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED && setuidx(ID_EFFECTIVE, state->euid)) { + strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf)); + goto bad; + } + break; + + case PERM_SUDOERS: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + + /* assume euid == ROOT_UID, ruid == user */ + state->rgid = ostate->rgid; + state->egid = sudoers_gid; + state->sgid = ostate->sgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid, + (int)state->rgid, (int)state->egid, (int)state->sgid); + if (GID_CHANGED && setgidx(ID_EFFECTIVE, sudoers_gid)) { + strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf)); + goto bad; + } + + state->ruid = ROOT_UID; + /* + * If sudoers_uid == ROOT_UID and sudoers_mode is group readable + * we use a non-zero uid in order to avoid NFS lossage. + * Using uid 1 is a bit bogus but should work on all OS's. + */ + if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) + state->euid = 1; + else + state->euid = sudoers_uid; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED) { + if (ostate->ruid != ROOT_UID || ostate->suid != ROOT_UID) { + if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_SUDOERS: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + ROOT_UID); + goto bad; + } + } + if (setuidx(ID_EFFECTIVE, state->euid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_SUDOERS: setuidx(ID_EFFECTIVE, %d)", sudoers_uid); + goto bad; + } + } + break; + + case PERM_TIMESTAMP: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->sgid = ostate->sgid; + state->ruid = ROOT_UID; + state->euid = timestamp_uid; + state->suid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: " + "[%d, %d, %d] -> [%d, %d, %d]", __func__, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid, + (int)state->ruid, (int)state->euid, (int)state->suid); + if (UID_CHANGED) { + if (ostate->ruid != ROOT_UID || ostate->suid != ROOT_UID) { + if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_TIMESTAMP: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + ROOT_UID); + goto bad; + } + } + if (setuidx(ID_EFFECTIVE, timestamp_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_TIMESTAMP: setuidx(ID_EFFECTIVE, %d)", timestamp_uid); + goto bad; + } + } + break; + } + + perm_stack_depth++; + debug_return_bool(1); +bad: + warningx("%s: %s", errbuf, + errno == EAGAIN ? _("too many processes") : strerror(errno)); + if (noexit) + debug_return_bool(0); + exit(1); +} + +void +restore_perms(void) +{ + struct perm_state *state, *ostate; + debug_decl(restore_perms, SUDO_DEBUG_PERMS) + + if (perm_stack_depth < 2) + debug_return; + + state = &perm_stack[perm_stack_depth - 1]; + ostate = &perm_stack[perm_stack_depth - 2]; + perm_stack_depth--; + + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d, %d] -> [%d, %d, %d]", + __func__, (int)state->ruid, (int)state->euid, (int)state->suid, + (int)ostate->ruid, (int)ostate->euid, (int)ostate->suid); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d, %d] -> [%d, %d, %d]", + __func__, (int)state->rgid, (int)state->egid, (int)state->sgid, + (int)ostate->rgid, (int)ostate->egid, (int)ostate->sgid); + + if (OID(ruid) != -1 || OID(euid) != -1 || OID(suid) != -1) { + if (OID(euid) == ROOT_UID) { + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: setuidx(ID_EFFECTIVE, %d)", + __func__, ROOT_UID); + if (setuidx(ID_EFFECTIVE, ROOT_UID)) { + warning("setuidx(ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->ruid, (int)state->euid, (int)state->suid, + -1, ROOT_UID, -1); + goto bad; + } + } + if (OID(ruid) == OID(euid) && OID(euid) == OID(suid)) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + __func__, OID(ruid)); + if (setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, OID(ruid))) { + warning("setuidx(ID_EFFECTIVE|ID_REAL|ID_SAVED) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->ruid, (int)state->euid, (int)state->suid, + (int)OID(ruid), (int)OID(euid), (int)OID(suid)); + goto bad; + } + } else if (OID(ruid) == -1 && OID(suid) == -1) { + /* May have already changed euid to ROOT_UID above. */ + if (OID(euid) != ROOT_UID) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: setuidx(ID_EFFECTIVE, %d)", __func__, OID(euid)); + if (setuidx(ID_EFFECTIVE, OID(euid))) { + warning("setuidx(ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->ruid, (int)state->euid, (int)state->suid, + (int)OID(ruid), (int)OID(euid), (int)OID(suid)); + goto bad; + } + } + } else if (OID(suid) == -1) { + /* Cannot set the real uid alone. */ + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: setuidx(ID_REAL|ID_EFFECTIVE, %d)", __func__, OID(ruid)); + if (setuidx(ID_REAL|ID_EFFECTIVE, OID(ruid))) { + warning("setuidx(ID_REAL|ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->ruid, (int)state->euid, (int)state->suid, + (int)OID(ruid), (int)OID(euid), (int)OID(suid)); + goto bad; + } + /* Restore the effective euid if it doesn't match the ruid. */ + if (OID(euid) != OID(ruid)) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: setuidx(ID_EFFECTIVE, %d)", __func__, ostate->euid); + if (setuidx(ID_EFFECTIVE, ostate->euid)) { + warning("setuidx(ID_EFFECTIVE, %d)", ostate->euid); + goto bad; + } + } + } + } + if (OID(rgid) != -1 || OID(egid) != -1 || OID(sgid) != -1) { + if (OID(rgid) == OID(egid) && OID(egid) == OID(sgid)) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, %d)", + __func__, OID(rgid)); + if (setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED, OID(rgid))) { + warning("setgidx(ID_EFFECTIVE|ID_REAL|ID_SAVED) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->rgid, (int)state->egid, (int)state->sgid, + (int)OID(rgid), (int)OID(egid), (int)OID(sgid)); + goto bad; + } + } else if (OID(rgid) == -1 && OID(sgid) == -1) { + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: setgidx(ID_EFFECTIVE, %d)", + __func__, OID(egid)); + if (setgidx(ID_EFFECTIVE, OID(egid))) { + warning("setgidx(ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->rgid, (int)state->egid, (int)state->sgid, + (int)OID(rgid), (int)OID(egid), (int)OID(sgid)); + goto bad; + } + } else if (OID(sgid) == -1) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "%s: setgidx(ID_EFFECTIVE|ID_REAL, %d)", __func__, OID(rgid)); + if (setgidx(ID_REAL|ID_EFFECTIVE, OID(rgid))) { + warning("setgidx(ID_REAL|ID_EFFECTIVE) [%d, %d, %d] -> [%d, %d, %d]", + (int)state->rgid, (int)state->egid, (int)state->sgid, + (int)OID(rgid), (int)OID(egid), (int)OID(sgid)); + goto bad; + } + } + } + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) { + warning("setgroups()"); + goto bad; + } + } + grlist_delref(state->grlist); + debug_return; + +bad: + exit(1); +} + +#elif defined(HAVE_SETREUID) + +#define UID_CHANGED (state->ruid != ostate->ruid || state->euid != ostate->euid) +#define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid) + +/* + * Set real and effective and saved uids and gids based on perm. + * We always retain a saved uid of 0 unless we are headed for an exec(). + * We only flip the effective gid since it only changes for PERM_SUDOERS. + * This version of set_perms() works fine with the "stay_setuid" option. + */ +int +set_perms(int perm) +{ + struct perm_state *state, *ostate = NULL; + char errbuf[1024]; + int noexit; + debug_decl(set_perms, SUDO_DEBUG_PERMS) + + noexit = ISSET(perm, PERM_NOEXIT); + CLR(perm, PERM_MASK); + + if (perm_stack_depth == PERM_STACK_MAX) { + strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + + state = &perm_stack[perm_stack_depth]; + if (perm != PERM_INITIAL) { + if (perm_stack_depth == 0) { + strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + ostate = &perm_stack[perm_stack_depth - 1]; + } + + switch (perm) { + case PERM_INITIAL: + /* Stash initial state */ + state->ruid = getuid(); + state->euid = geteuid(); + state->rgid = getgid(); + state->egid = getegid(); + state->grlist = user_group_list; + grlist_addref(state->grlist); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: " + "ruid: %d, euid: %d, rgid: %d, egid: %d", __func__, + (int)state->ruid, (int)state->euid, + (int)state->rgid, (int)state->egid); + break; + + case PERM_ROOT: + state->ruid = ROOT_UID; + state->euid = ROOT_UID; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + /* + * setreuid(0, 0) may fail on some systems if euid is not already 0. + */ + if (ostate->euid != ROOT_UID) { + if (setreuid(-1, ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_ROOT: setreuid(-1, %d)", PERM_ROOT); + goto bad; + } + } + if (ostate->ruid != ROOT_UID) { + if (setreuid(ROOT_UID, -1)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_ROOT: setreuid(%d, -1)", ROOT_UID); + goto bad; + } + } + state->rgid = ostate->rgid; + state->egid = ostate->rgid; + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + break; + + case PERM_USER: + state->rgid = ostate->rgid; + state->egid = user_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setregid(ID(rgid), ID(egid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: setregid(%d, %d)", ID(rgid), ID(egid)); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = ROOT_UID; + state->euid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: setreuid(%d, %d)", ID(ruid), ID(euid)); + goto bad; + } + break; + + case PERM_FULL_USER: + /* headed for exec() */ + state->rgid = user_gid; + state->egid = user_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setregid(ID(rgid), ID(egid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setregid(%d, %d)", ID(rgid), ID(egid)); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + state->euid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setreuid(%d, %d)", ID(ruid), ID(euid)); + goto bad; + } + break; + + case PERM_RUNAS: + state->rgid = ostate->rgid; + state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setregid(ID(rgid), ID(egid))) { + strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf)); + goto bad; + } + state->grlist = runas_setgroups(); + state->ruid = ROOT_UID; + state->euid = runas_pw ? runas_pw->pw_uid : user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) { + strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf)); + goto bad; + } + break; + + case PERM_SUDOERS: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + + /* assume euid == ROOT_UID, ruid == user */ + state->rgid = ostate->rgid; + state->egid = sudoers_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setregid(ID(rgid), ID(egid))) { + strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf)); + goto bad; + } + + state->ruid = ROOT_UID; + /* + * If sudoers_uid == ROOT_UID and sudoers_mode is group readable + * we use a non-zero uid in order to avoid NFS lossage. + * Using uid 1 is a bit bogus but should work on all OS's. + */ + if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) + state->euid = 1; + else + state->euid = sudoers_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_SUDOERS: setreuid(%d, %d)", ID(ruid), ID(euid)); + goto bad; + } + break; + + case PERM_TIMESTAMP: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->ruid = ROOT_UID; + state->euid = timestamp_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (UID_CHANGED && setreuid(ID(ruid), ID(euid))) { + snprintf(errbuf, sizeof(errbuf), + "PERM_TIMESTAMP: setreuid(%d, %d)", ID(ruid), ID(euid)); + goto bad; + } + break; + } + + perm_stack_depth++; + debug_return_bool(1); +bad: + warningx("%s: %s", errbuf, + errno == EAGAIN ? _("too many processes") : strerror(errno)); + if (noexit) + debug_return_bool(0); + exit(1); +} + +void +restore_perms(void) +{ + struct perm_state *state, *ostate; + debug_decl(restore_perms, SUDO_DEBUG_PERMS) + + if (perm_stack_depth < 2) + debug_return; + + state = &perm_stack[perm_stack_depth - 1]; + ostate = &perm_stack[perm_stack_depth - 2]; + perm_stack_depth--; + + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d] -> [%d, %d]", + __func__, (int)state->ruid, (int)state->euid, + (int)ostate->ruid, (int)ostate->euid); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d] -> [%d, %d]", + __func__, (int)state->rgid, (int)state->egid, + (int)ostate->rgid, (int)ostate->egid); + + /* + * When changing euid to ROOT_UID, setreuid() may fail even if + * the ruid is ROOT_UID so call setuid() first. + */ + if (OID(euid) == ROOT_UID) { + /* setuid() may not set the saved ID unless the euid is ROOT_UID */ + if (ID(euid) != ROOT_UID) + (void)setreuid(-1, ROOT_UID); + if (setuid(ROOT_UID)) { + warning("setuid() [%d, %d] -> %d)", (int)state->ruid, + (int)state->euid, ROOT_UID); + goto bad; + } + } + if (setreuid(OID(ruid), OID(euid))) { + warning("setreuid() [%d, %d] -> [%d, %d]", (int)state->ruid, + (int)state->euid, (int)OID(ruid), (int)OID(euid)); + goto bad; + } + if (setregid(OID(rgid), OID(egid))) { + warning("setregid() [%d, %d] -> [%d, %d]", (int)state->rgid, + (int)state->egid, (int)OID(rgid), (int)OID(egid)); + goto bad; + } + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) { + warning("setgroups()"); + goto bad; + } + } + grlist_delref(state->grlist); + debug_return; + +bad: + exit(1); +} + +#elif defined(HAVE_SETEUID) + +#define GID_CHANGED (state->rgid != ostate->rgid || state->egid != ostate->egid) + +/* + * Set real and effective uids and gids based on perm. + * We always retain a real or effective uid of ROOT_UID unless + * we are headed for an exec(). + * This version of set_perms() works fine with the "stay_setuid" option. + */ +int +set_perms(int perm) +{ + struct perm_state *state, *ostate = NULL; + char errbuf[1024]; + int noexit; + debug_decl(set_perms, SUDO_DEBUG_PERMS) + + noexit = ISSET(perm, PERM_NOEXIT); + CLR(perm, PERM_MASK); + + if (perm_stack_depth == PERM_STACK_MAX) { + strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + + state = &perm_stack[perm_stack_depth]; + if (perm != PERM_INITIAL) { + if (perm_stack_depth == 0) { + strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + ostate = &perm_stack[perm_stack_depth - 1]; + } + + /* + * Since we only have setuid() and seteuid() and semantics + * for these calls differ on various systems, we set + * real and effective uids to ROOT_UID initially to be safe. + */ + if (perm != PERM_INITIAL) { + if (ostate->euid != ROOT_UID && seteuid(ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), "set_perms: seteuid(%d)", ROOT_UID); + goto bad; + } + if (ostate->ruid != ROOT_UID && setuid(ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), "set_perms: setuid(%d)", ROOT_UID); + goto bad; + } + } + + switch (perm) { + case PERM_INITIAL: + /* Stash initial state */ + state->ruid = getuid(); + state->euid = geteuid(); + state->rgid = getgid(); + state->egid = getegid(); + state->grlist = user_group_list; + grlist_addref(state->grlist); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: " + "ruid: %d, euid: %d, rgid: %d, egid: %d", __func__, + (int)state->ruid, (int)state->euid, + (int)state->rgid, (int)state->egid); + break; + + case PERM_ROOT: + /* We already set ruid/euid above. */ + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, ROOT_UID, ROOT_UID); + state->ruid = ROOT_UID; + state->euid = ROOT_UID; + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + break; + + case PERM_USER: + state->egid = user_gid; + state->rgid = ostate->rgid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setegid(user_gid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: setegid(%d)", user_gid); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = ROOT_UID; + state->euid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_USER: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (seteuid(user_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_USER: seteuid(%d)", user_uid); + goto bad; + } + break; + + case PERM_FULL_USER: + /* headed for exec() */ + state->rgid = user_gid; + state->egid = user_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setgid(user_gid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setgid(%d)", user_gid); + goto bad; + } + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + state->euid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_FULL_USER: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (setuid(user_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setuid(%d)", user_uid); + goto bad; + } + break; + + case PERM_RUNAS: + state->rgid = ostate->rgid; + state->egid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setegid(state->egid)) { + strlcpy(errbuf, _("unable to change to runas gid"), sizeof(errbuf)); + goto bad; + } + state->grlist = runas_setgroups(); + state->ruid = ostate->ruid; + state->euid = runas_pw ? runas_pw->pw_uid : user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_RUNAS: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (seteuid(state->euid)) { + strlcpy(errbuf, _("unable to change to runas uid"), sizeof(errbuf)); + goto bad; + } + break; + + case PERM_SUDOERS: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + + /* assume euid == ROOT_UID, ruid == user */ + state->rgid = ostate->rgid; + state->egid = sudoers_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: gid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->rgid, + (int)ostate->egid, (int)state->rgid, (int)state->egid); + if (GID_CHANGED && setegid(sudoers_gid)) { + strlcpy(errbuf, _("unable to change to sudoers gid"), sizeof(errbuf)); + goto bad; + } + + state->ruid = ROOT_UID; + /* + * If sudoers_uid == ROOT_UID and sudoers_mode is group readable + * we use a non-zero uid in order to avoid NFS lossage. + * Using uid 1 is a bit bogus but should work on all OS's. + */ + if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) + state->euid = 1; + else + state->euid = sudoers_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_SUDOERS: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (seteuid(state->euid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_SUDOERS: seteuid(%d)", state->euid); + goto bad; + } + break; + + case PERM_TIMESTAMP: + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + state->rgid = ostate->rgid; + state->egid = ostate->egid; + state->ruid = ROOT_UID; + state->euid = timestamp_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_TIMESTAMP: uid: " + "[%d, %d] -> [%d, %d]", __func__, (int)ostate->ruid, + (int)ostate->euid, (int)state->ruid, (int)state->euid); + if (seteuid(timestamp_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_TIMESTAMP: seteuid(%d)", timestamp_uid); + goto bad; + } + break; + } + + perm_stack_depth++; + debug_return_bool(1); +bad: + warningx("%s: %s", errbuf, + errno == EAGAIN ? _("too many processes") : strerror(errno)); + if (noexit) + debug_return_bool(0); + exit(1); +} + +void +restore_perms(void) +{ + struct perm_state *state, *ostate; + debug_decl(restore_perms, SUDO_DEBUG_PERMS) + + if (perm_stack_depth < 2) + debug_return; + + state = &perm_stack[perm_stack_depth - 1]; + ostate = &perm_stack[perm_stack_depth - 2]; + perm_stack_depth--; + + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d, %d] -> [%d, %d]", + __func__, (int)state->ruid, (int)state->euid, + (int)ostate->ruid, (int)ostate->euid); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d, %d] -> [%d, %d]", + __func__, (int)state->rgid, (int)state->egid, + (int)ostate->rgid, (int)ostate->egid); + + /* + * Since we only have setuid() and seteuid() and semantics + * for these calls differ on various systems, we set + * real and effective uids to ROOT_UID initially to be safe. + */ + if (seteuid(ROOT_UID)) { + warningx("seteuid() [%d] -> [%d]", (int)state->euid, ROOT_UID); + goto bad; + } + if (setuid(ROOT_UID)) { + warningx("setuid() [%d, %d] -> [%d, %d]", (int)state->ruid, ROOT_UID, + ROOT_UID, ROOT_UID); + goto bad; + } + + if (OID(egid) != -1 && setegid(ostate->egid)) { + warning("setegid(%d)", (int)ostate->egid); + goto bad; + } + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) { + warning("setgroups()"); + goto bad; + } + } + if (OID(euid) != -1 && seteuid(ostate->euid)) { + warning("seteuid(%d)", ostate->euid); + goto bad; + } + grlist_delref(state->grlist); + debug_return; + +bad: + exit(1); +} + +#else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */ + +/* + * Set uids and gids based on perm via setuid() and setgid(). + * NOTE: does not support the "stay_setuid" or timestampowner options. + * Also, sudoers_uid and sudoers_gid are not used. + */ +int +set_perms(int perm) +{ + struct perm_state *state, *ostate = NULL; + char errbuf[1024]; + int noexit; + debug_decl(set_perms, SUDO_DEBUG_PERMS) + + noexit = ISSET(perm, PERM_NOEXIT); + CLR(perm, PERM_MASK); + + if (perm_stack_depth == PERM_STACK_MAX) { + strlcpy(errbuf, _("perm stack overflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + + state = &perm_stack[perm_stack_depth]; + if (perm != PERM_INITIAL) { + if (perm_stack_depth == 0) { + strlcpy(errbuf, _("perm stack underflow"), sizeof(errbuf)); + errno = EINVAL; + goto bad; + } + ostate = &perm_stack[perm_stack_depth - 1]; + } + + switch (perm) { + case PERM_INITIAL: + /* Stash initial state */ + state->ruid = geteuid() == ROOT_UID ? ROOT_UID : getuid(); + state->rgid = getgid(); + state->grlist = user_group_list; + grlist_addref(state->grlist); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_INITIAL: " + "ruid: %d, rgid: %d", __func__, (int)state->ruid, (int)state->rgid); + break; + + case PERM_ROOT: + state->ruid = ROOT_UID; + state->rgid = ostate->rgid; + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: " + "[%d] -> [%d]", __func__, (int)ostate->ruid, (int)state->ruid); + if (setuid(ROOT_UID)) { + snprintf(errbuf, sizeof(errbuf), "PERM_ROOT: setuid(%d)", ROOT_UID); + goto bad; + } + break; + + case PERM_FULL_USER: + state->rgid = user_gid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: gid: " + "[%d] -> [%d]", __func__, (int)ostate->rgid, (int)state->rgid); + (void) setgid(user_gid); + state->grlist = user_group_list; + grlist_addref(state->grlist); + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(state->grlist->ngids, state->grlist->gids)) { + strlcpy(errbuf, "PERM_FULL_USER: setgroups", sizeof(errbuf)); + goto bad; + } + } + state->ruid = user_uid; + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: PERM_ROOT: uid: " + "[%d] -> [%d]", __func__, (int)ostate->ruid, (int)state->ruid); + if (setuid(user_uid)) { + snprintf(errbuf, sizeof(errbuf), + "PERM_FULL_USER: setuid(%d)", user_uid); + goto bad; + } + break; + + case PERM_USER: + case PERM_SUDOERS: + case PERM_RUNAS: + case PERM_TIMESTAMP: + /* Unsupported since we can't set euid. */ + state->ruid = ostate->ruid; + state->rgid = ostate->rgid; + state->grlist = ostate->grlist; + grlist_addref(state->grlist); + break; + } + + perm_stack_depth++; + debug_return_bool(1); +bad: + warningx("%s: %s", errbuf, + errno == EAGAIN ? _("too many processes") : strerror(errno)); + if (noexit) + debug_return_bool(0); + exit(1); +} + +void +restore_perms(void) +{ + struct perm_state *state, *ostate; + debug_decl(restore_perms, SUDO_DEBUG_PERMS) + + if (perm_stack_depth < 2) + debug_return; + + state = &perm_stack[perm_stack_depth - 1]; + ostate = &perm_stack[perm_stack_depth - 2]; + perm_stack_depth--; + + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: uid: [%d] -> [%d]", + __func__, (int)state->ruid, (int)ostate->ruid); + sudo_debug_printf(SUDO_DEBUG_INFO, "%s: gid: [%d] -> [%d]", + __func__, (int)state->rgid, (int)ostate->rgid); + + if (OID(rgid) != -1 && setgid(ostate->rgid)) { + warning("setgid(%d)", (int)ostate->rgid); + goto bad; + } + if (state->grlist != ostate->grlist) { + if (sudo_setgroups(ostate->grlist->ngids, ostate->grlist->gids)) { + warning("setgroups()"); + goto bad; + } + } + grlist_delref(state->grlist); + if (OID(ruid) != -1 && setuid(ostate->ruid)) { + warning("setuid(%d)", (int)ostate->ruid); + goto bad; + } + debug_return; + +bad: + exit(1); +} +#endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ + +#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) +static struct group_list * +runas_setgroups(void) +{ + struct passwd *pw; + struct group_list *grlist; + debug_decl(runas_setgroups, SUDO_DEBUG_PERMS) + + if (def_preserve_groups) { + grlist_addref(user_group_list); + debug_return_ptr(user_group_list); + } + + pw = runas_pw ? runas_pw : sudo_user.pw; +#ifdef HAVE_SETAUTHDB + aix_setauthdb(pw->pw_name); +#endif + grlist = get_group_list(pw); +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif + if (sudo_setgroups(grlist->ngids, grlist->gids) < 0) + log_fatal(USE_ERRNO|MSG_ONLY, _("unable to set runas group vector")); + debug_return_ptr(grlist); +} +#endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ diff --git a/plugins/sudoers/sudo_nss.c b/plugins/sudoers/sudo_nss.c new file mode 100644 index 0000000..d8ed0f5 --- /dev/null +++ b/plugins/sudoers/sudo_nss.c @@ -0,0 +1,305 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#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 */ +#include +#include +#include + +#include "sudoers.h" +#include "lbuf.h" + +extern struct sudo_nss sudo_nss_file; +#ifdef HAVE_LDAP +extern struct sudo_nss sudo_nss_ldap; +#endif + +#if defined(HAVE_LDAP) && defined(_PATH_NSSWITCH_CONF) +/* + * Read in /etc/nsswitch.conf + * Returns a tail queue of matches. + */ +struct sudo_nss_list * +sudo_read_nss(void) +{ + FILE *fp; + char *cp; + bool saw_files = false; + bool saw_ldap = false; + bool got_match = false; + static struct sudo_nss_list snl; + debug_decl(sudo_read_nss, SUDO_DEBUG_NSS) + + if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL) + goto nomatch; + + while ((cp = sudo_parseln(fp)) != NULL) { + /* Skip blank or comment lines */ + if (*cp == '\0') + continue; + + /* Look for a line starting with "sudoers:" */ + if (strncasecmp(cp, "sudoers:", 8) != 0) + continue; + + /* Parse line */ + for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) { + if (strcasecmp(cp, "files") == 0 && !saw_files) { + tq_append(&snl, &sudo_nss_file); + got_match = true; + } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) { + tq_append(&snl, &sudo_nss_ldap); + got_match = true; + } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) { + /* NOTFOUND affects the most recent entry */ + tq_last(&snl)->ret_if_notfound = true; + got_match = false; + } else + got_match = false; + } + /* Only parse the first "sudoers:" line */ + break; + } + fclose(fp); + +nomatch: + /* Default to files only if no matches */ + if (tq_empty(&snl)) + tq_append(&snl, &sudo_nss_file); + + debug_return_ptr(&snl); +} + +#else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */ + +# if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF) + +/* + * Read in /etc/netsvc.conf (like nsswitch.conf on AIX) + * Returns a tail queue of matches. + */ +struct sudo_nss_list * +sudo_read_nss(void) +{ + FILE *fp; + char *cp, *ep; + bool saw_files = false; + bool saw_ldap = false; + bool got_match = false; + static struct sudo_nss_list snl; + debug_decl(sudo_read_nss, SUDO_DEBUG_NSS) + + if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL) + goto nomatch; + + while ((cp = sudo_parseln(fp)) != NULL) { + /* Skip blank or comment lines */ + if (*cp == '\0') + continue; + + /* Look for a line starting with "sudoers = " */ + if (strncasecmp(cp, "sudoers", 7) != 0) + continue; + cp += 7; + while (isspace((unsigned char)*cp)) + cp++; + if (*cp++ != '=') + continue; + + /* Parse line */ + for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) { + /* Trim leading whitespace. */ + while (isspace((unsigned char)*cp)) + cp++; + + if (!saw_files && strncasecmp(cp, "files", 5) == 0 && + (isspace((unsigned char)cp[5]) || cp[5] == '\0')) { + tq_append(&snl, &sudo_nss_file); + got_match = true; + ep = &cp[5]; + } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 && + (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { + tq_append(&snl, &sudo_nss_ldap); + got_match = true; + ep = &cp[4]; + } else { + got_match = false; + } + + /* check for = auth qualifier */ + if (got_match && *ep) { + cp = ep; + while (isspace((unsigned char)*cp) || *cp == '=') + cp++; + if (strncasecmp(cp, "auth", 4) == 0 && + (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { + tq_last(&snl)->ret_if_found = true; + } + } + } + /* Only parse the first "sudoers" line */ + break; + } + fclose(fp); + +nomatch: + /* Default to files only if no matches */ + if (tq_empty(&snl)) + tq_append(&snl, &sudo_nss_file); + + debug_return_ptr(&snl); +} + +# else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */ + +/* + * Non-nsswitch.conf version with hard-coded order. + */ +struct sudo_nss_list * +sudo_read_nss(void) +{ + static struct sudo_nss_list snl; + debug_decl(sudo_read_nss, SUDO_DEBUG_NSS) + +# ifdef HAVE_LDAP + tq_append(&snl, &sudo_nss_ldap); +# endif + tq_append(&snl, &sudo_nss_file); + + debug_return_ptr(&snl); +} + +# endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */ + +#endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */ + +static int +output(const char *buf) +{ + struct sudo_conv_message msg; + struct sudo_conv_reply repl; + debug_decl(output, SUDO_DEBUG_NSS) + + /* Call conversation function */ + memset(&msg, 0, sizeof(msg)); + msg.msg_type = SUDO_CONV_INFO_MSG; + msg.msg = buf; + memset(&repl, 0, sizeof(repl)); + if (sudo_conv(1, &msg, &repl) == -1) + debug_return_int(0); + debug_return_int(strlen(buf)); +} + +/* + * Print out privileges for the specified user. + * We only get here if the user is allowed to run something on this host. + */ +void +display_privs(struct sudo_nss_list *snl, struct passwd *pw) +{ + struct sudo_nss *nss; + struct lbuf defs, privs; + int count, olen; + debug_decl(display_privs, SUDO_DEBUG_NSS) + + lbuf_init(&defs, output, 4, NULL, sudo_user.cols); + lbuf_init(&privs, output, 4, NULL, sudo_user.cols); + + /* Display defaults from all sources. */ + lbuf_append(&defs, _("Matching Defaults entries for %s on this host:\n"), + pw->pw_name); + count = 0; + tq_foreach_fwd(snl, nss) { + count += nss->display_defaults(nss, pw, &defs); + } + if (count) + lbuf_append(&defs, "\n\n"); + else + defs.len = 0; + + /* Display Runas and Cmnd-specific defaults from all sources. */ + olen = defs.len; + lbuf_append(&defs, _("Runas and Command-specific defaults for %s:\n"), + pw->pw_name); + count = 0; + tq_foreach_fwd(snl, nss) { + count += nss->display_bound_defaults(nss, pw, &defs); + } + if (count) + lbuf_append(&defs, "\n\n"); + else + defs.len = olen; + + /* Display privileges from all sources. */ + lbuf_append(&privs, + _("User %s may run the following commands on this host:\n"), + pw->pw_name); + count = 0; + tq_foreach_fwd(snl, nss) { + count += nss->display_privs(nss, pw, &privs); + } + if (count) { + lbuf_print(&defs); + lbuf_print(&privs); + } else { + printf(_("User %s is not allowed to run sudo on %s.\n"), pw->pw_name, + user_shost); + } + + lbuf_destroy(&defs); + lbuf_destroy(&privs); + + debug_return; +} + +/* + * Check user_cmnd against sudoers and print the matching entry if the + * command is allowed. + * Returns true if the command is allowed, else false. + */ +bool +display_cmnd(struct sudo_nss_list *snl, struct passwd *pw) +{ + struct sudo_nss *nss; + debug_decl(display_cmnd, SUDO_DEBUG_NSS) + + tq_foreach_fwd(snl, nss) { + if (nss->display_cmnd(nss, pw) == 0) + debug_return_bool(true); + } + debug_return_bool(false); +} diff --git a/plugins/sudoers/sudo_nss.h b/plugins/sudoers/sudo_nss.h new file mode 100644 index 0000000..dab885d --- /dev/null +++ b/plugins/sudoers/sudo_nss.h @@ -0,0 +1,44 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _SUDO_NSS_H +#define _SUDO_NSS_H + +struct lbuf; +struct passwd; + +struct sudo_nss { + struct sudo_nss *prev; + struct sudo_nss *next; + int (*open)(struct sudo_nss *nss); + int (*close)(struct sudo_nss *nss); + int (*parse)(struct sudo_nss *nss); + int (*setdefs)(struct sudo_nss *nss); + int (*lookup)(struct sudo_nss *nss, int, int); + int (*display_cmnd)(struct sudo_nss *nss, struct passwd *); + int (*display_defaults)(struct sudo_nss *nss, struct passwd *, struct lbuf *); + int (*display_bound_defaults)(struct sudo_nss *nss, struct passwd *, struct lbuf *); + int (*display_privs)(struct sudo_nss *nss, struct passwd *, struct lbuf *); + void *handle; + short ret_if_found; + short ret_if_notfound; +}; + +TQ_DECLARE(sudo_nss) + +struct sudo_nss_list *sudo_read_nss(void); + +#endif /* _SUDO_NSS_H */ diff --git a/plugins/sudoers/sudoers.c b/plugins/sudoers/sudoers.c new file mode 100644 index 0000000..9002712 --- /dev/null +++ b/plugins/sudoers/sudoers.c @@ -0,0 +1,1611 @@ +/* + * Copyright (c) 1993-1996, 1998-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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + * + * For a brief history of sudo, please see the HISTORY file included + * with this distribution. + */ + +#define _SUDO_MAIN + +#ifdef __TANDEM +# include +#endif + +#include + +#include +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SETLOCALE +# include +#endif +#include +#include +#ifdef HAVE_LOGIN_CAP_H +# include +# ifndef LOGIN_DEFROOTCLASS +# define LOGIN_DEFROOTCLASS "daemon" +# endif +# ifndef LOGIN_SETENV +# define LOGIN_SETENV 0 +# endif +#endif +#ifdef HAVE_SELINUX +# include +#endif +#include +#include +#ifndef HAVE_GETADDRINFO +# include "compat/getaddrinfo.h" +#endif + +#include "sudoers.h" +#include "interfaces.h" +#include "sudoers_version.h" +#include "auth/sudo_auth.h" +#include "secure_path.h" + +/* + * Prototypes + */ +static void init_vars(char * const *); +static int set_cmnd(void); +static void set_loginclass(struct passwd *); +static void set_runaspw(const char *); +static void set_runasgr(const char *); +static int cb_runas_default(const char *); +static int sudoers_policy_version(int verbose); +static int deserialize_info(char * const args[], char * const settings[], + char * const user_info[]); +static char *find_editor(int nfiles, char **files, char ***argv_out); +static void create_admin_success_flag(void); + +/* + * Globals + */ +struct sudo_user sudo_user; +struct passwd *list_pw; +struct interface *interfaces; +int long_list; +uid_t timestamp_uid; +extern int errorlineno; +extern bool parse_error; +extern char *errorfile; +#ifdef HAVE_BSD_AUTH_H +char *login_style; +#endif /* HAVE_BSD_AUTH_H */ +sudo_conv_t sudo_conv; +sudo_printf_t sudo_printf; +int sudo_mode; + +static int sudo_version; +static char *prev_user; +static char *runas_user; +static char *runas_group; +static struct sudo_nss_list *snl; +static const char *interfaces_string; +static sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp; + +/* XXX - must be extern for audit bits of sudo_auth.c */ +int NewArgc; +char **NewArgv; + +/* Declared here instead of plugin_error.c for static sudo builds. */ +sigjmp_buf error_jmp; + +static int +sudoers_policy_open(unsigned int version, sudo_conv_t conversation, + sudo_printf_t plugin_printf, char * const settings[], + char * const user_info[], char * const envp[], char * const args[]) +{ + volatile int sources = 0; + sigaction_t sa; + struct sudo_nss *nss; + debug_decl(sudoers_policy_open, SUDO_DEBUG_PLUGIN) + + sudo_version = version; + if (!sudo_conv) + sudo_conv = conversation; + if (!sudo_printf) + sudo_printf = plugin_printf; + + /* Plugin args are only specified for API version 1.2 and higher. */ + if (sudo_version < SUDO_API_MKVERSION(1, 2)) + args = NULL; + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + rewind_perms(); + debug_return_bool(-1); + } + + bindtextdomain("sudoers", LOCALEDIR); + + /* + * Signal setup: + * Ignore keyboard-generated signals so the user cannot interrupt + * us at some point and avoid the logging. + * Install handler to wait for children when they exit. + */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_IGN; + (void) sigaction(SIGINT, &sa, &saved_sa_int); + (void) sigaction(SIGQUIT, &sa, &saved_sa_quit); + (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp); + + sudo_setpwent(); + sudo_setgrent(); + + /* Initialize environment functions (including replacements). */ + env_init(envp); + + /* Setup defaults data structures. */ + init_defaults(); + + /* Parse args, settings and user_info */ + sudo_mode = deserialize_info(args, settings, user_info); + + init_vars(envp); /* XXX - move this later? */ + + /* Parse nsswitch.conf for sudoers order. */ + snl = sudo_read_nss(); + + /* LDAP or NSS may modify the euid so we need to be root for the open. */ + set_perms(PERM_INITIAL); + set_perms(PERM_ROOT); + + /* Open and parse sudoers, set global defaults */ + tq_foreach_fwd(snl, nss) { + if (nss->open(nss) == 0 && nss->parse(nss) == 0) { + sources++; + if (nss->setdefs(nss) != 0) + log_error(NO_STDERR, _("problem with defaults entries")); + } + } + if (sources == 0) { + warningx(_("no valid sudoers sources found, quitting")); + debug_return_bool(-1); + } + + /* XXX - collect post-sudoers parse settings into a function */ + + /* + * Initialize external group plugin, if any. + */ + if (def_group_plugin) { + if (group_plugin_load(def_group_plugin) != true) + def_group_plugin = NULL; + } + + /* + * Set runas passwd/group entries based on command line or sudoers. + * Note that if runas_group was specified without runas_user we + * defer setting runas_pw so the match routines know to ignore it. + */ + if (runas_group != NULL) { + set_runasgr(runas_group); + if (runas_user != NULL) + set_runaspw(runas_user); + } else + set_runaspw(runas_user ? runas_user : def_runas_default); + + if (!update_defaults(SETDEF_RUNAS)) + log_error(NO_STDERR, _("problem with defaults entries")); + + if (def_fqdn) + set_fqdn(); /* deferred until after sudoers is parsed */ + + /* Set login class if applicable. */ + set_loginclass(runas_pw ? runas_pw : sudo_user.pw); + + restore_perms(); + + debug_return_bool(true); +} + +static void +sudoers_policy_close(int exit_status, int error_code) +{ + debug_decl(sudoers_policy_close, SUDO_DEBUG_PLUGIN) + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + debug_return; + } + + /* We do not currently log the exit status. */ + if (error_code) + warningx(_("unable to execute %s: %s"), safe_cmnd, strerror(error_code)); + + /* Close the session we opened in sudoers_policy_init_session(). */ + if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT)) + (void)sudo_auth_end_session(runas_pw); + + /* Free remaining references to password and group entries. */ + pw_delref(sudo_user.pw); + pw_delref(runas_pw); + if (runas_gr != NULL) + gr_delref(runas_gr); + if (user_group_list != NULL) + grlist_delref(user_group_list); + + debug_return; +} + +/* + * The init_session function is called before executing the command + * and before uid/gid changes occur. + */ +static int +sudoers_policy_init_session(struct passwd *pwd, char **user_env[]) +{ + debug_decl(sudoers_policy_init, SUDO_DEBUG_PLUGIN) + + /* user_env is only specified for API version 1.2 and higher. */ + if (sudo_version < SUDO_API_MKVERSION(1, 2)) + user_env = NULL; + + if (sigsetjmp(error_jmp, 1)) { + /* called via error(), errorx() or log_fatal() */ + return -1; + } + + debug_return_bool(sudo_auth_begin_session(pwd, user_env)); +} + +static int +sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[], + char **command_infop[], char **argv_out[], char **user_env_out[]) +{ + static char *command_info[32]; /* XXX */ + char **edit_argv = NULL; + struct sudo_nss *nss; + int cmnd_status = -1, validated; + volatile int info_len = 0; + volatile int rval = true; + debug_decl(sudoers_policy_main, SUDO_DEBUG_PLUGIN) + + if (sigsetjmp(error_jmp, 1)) { + /* error recovery via error(), errorx() or log_fatal() */ + rval = -1; + goto done; + } + + /* Is root even allowed to run sudo? */ + if (user_uid == 0 && !def_root_sudo) { + warningx(_("sudoers specifies that root is not allowed to sudo")); + goto bad; + } + + /* Check for -C overriding def_closefrom. */ + if (user_closefrom >= 0 && user_closefrom != def_closefrom) { + if (!def_closefrom_override) { + warningx(_("you are not permitted to use the -C option")); + goto bad; + } + def_closefrom = user_closefrom; + } + + set_perms(PERM_INITIAL); + + /* Environment variables specified on the command line. */ + if (env_add != NULL && env_add[0] != NULL) + sudo_user.env_vars = env_add; + + /* + * Make a local copy of argc/argv, with special handling + * for pseudo-commands and the '-i' option. + */ + if (argc == 0) { + NewArgc = 1; + NewArgv = emalloc2(NewArgc + 1, sizeof(char *)); + NewArgv[0] = user_cmnd; + NewArgv[1] = NULL; + } else { + /* Must leave an extra slot before NewArgv for bash's --login */ + NewArgc = argc; + NewArgv = emalloc2(NewArgc + 2, sizeof(char *)); + memcpy(++NewArgv, argv, argc * sizeof(char *)); + NewArgv[NewArgc] = NULL; + if (ISSET(sudo_mode, MODE_LOGIN_SHELL) && runas_pw != NULL) + NewArgv[0] = estrdup(runas_pw->pw_shell); + } + + /* If given the -P option, set the "preserve_groups" flag. */ + if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) + def_preserve_groups = true; + + /* Find command in path */ + cmnd_status = set_cmnd(); + if (cmnd_status == -1) { + rval = -1; + goto done; + } + +#ifdef HAVE_SETLOCALE + if (!setlocale(LC_ALL, def_sudoers_locale)) { + warningx(_("unable to set locale to \"%s\", using \"C\""), + def_sudoers_locale); + setlocale(LC_ALL, "C"); + } +#endif + + /* + * Check sudoers sources. + */ + validated = FLAG_NO_USER | FLAG_NO_HOST; + tq_foreach_fwd(snl, nss) { + validated = nss->lookup(nss, validated, pwflag); + + if (ISSET(validated, VALIDATE_OK)) { + /* Handle "= auth" in netsvc.conf */ + if (nss->ret_if_found) + break; + } else { + /* Handle [NOTFOUND=return] */ + if (nss->ret_if_notfound) + break; + } + } + + if (safe_cmnd == NULL) + safe_cmnd = estrdup(user_cmnd); + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + + /* If only a group was specified, set runas_pw based on invoking user. */ + if (runas_pw == NULL) + set_runaspw(user_name); + + /* + * Look up the timestamp dir owner if one is specified. + */ + if (def_timestampowner) { + struct passwd *pw; + + if (*def_timestampowner == '#') + pw = sudo_getpwuid(atoi(def_timestampowner + 1)); + else + pw = sudo_getpwnam(def_timestampowner); + if (pw != NULL) { + timestamp_uid = pw->pw_uid; + pw_delref(pw); + } else { + log_error(0, _("timestamp owner (%s): No such user"), + def_timestampowner); + timestamp_uid = ROOT_UID; + } + } + + /* If no command line args and "shell_noargs" is not set, error out. */ + if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) { + rval = -2; /* usage error */ + goto done; + } + + /* Bail if a tty is required and we don't have one. */ + if (def_requiretty) { + int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY); + if (fd == -1) { + audit_failure(NewArgv, _("no tty")); + warningx(_("sorry, you must have a tty to run sudo")); + goto bad; + } else + (void) close(fd); + } + + /* + * We don't reset the environment for sudoedit or if the user + * specified the -E command line flag and they have setenv privs. + */ + if (ISSET(sudo_mode, MODE_EDIT) || + (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)) + def_env_reset = false; + + /* Build a new environment that avoids any nasty bits. */ + rebuild_env(); + + /* Require a password if sudoers says so. */ + rval = check_user(validated, sudo_mode); + if (rval != true) + goto done; + + /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ + /* XXX - causes confusion when root is not listed in sudoers */ + if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) { + if (user_uid == 0 && strcmp(prev_user, "root") != 0) { + struct passwd *pw; + + if ((pw = sudo_getpwnam(prev_user)) != NULL) { + if (sudo_user.pw != NULL) + pw_delref(sudo_user.pw); + sudo_user.pw = pw; + } + } + } + + /* If the user was not allowed to run the command we are done. */ + if (!ISSET(validated, VALIDATE_OK)) { + if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) { + audit_failure(NewArgv, _("No user or host")); + log_denial(validated, 1); + } else { + if (def_path_info) { + /* + * We'd like to not leak path info at all here, but that can + * *really* confuse the users. To really close the leak we'd + * have to say "not allowed to run foo" even when the problem + * is just "no foo in path" since the user can trivially set + * their path to just contain a single dir. + */ + log_denial(validated, + !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); + if (cmnd_status == NOT_FOUND) + warningx(_("%s: command not found"), user_cmnd); + else if (cmnd_status == NOT_FOUND_DOT) + warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); + } else { + /* Just tell the user they are not allowed to run foo. */ + log_denial(validated, 1); + } + audit_failure(NewArgv, _("validation failure")); + } + goto bad; + } + + /* Create Ubuntu-style dot file to indicate sudo was successful. */ + create_admin_success_flag(); + + /* Finally tell the user if the command did not exist. */ + if (cmnd_status == NOT_FOUND_DOT) { + audit_failure(NewArgv, _("command in current directory")); + warningx(_("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run."), user_cmnd, user_cmnd, user_cmnd); + goto bad; + } else if (cmnd_status == NOT_FOUND) { + audit_failure(NewArgv, _("%s: command not found"), user_cmnd); + warningx(_("%s: command not found"), user_cmnd); + goto bad; + } + + /* If user specified env vars make sure sudoers allows it. */ + if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) { + if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) { + warningx(_("sorry, you are not allowed to preserve the environment")); + goto bad; + } else + validate_env_vars(sudo_user.env_vars); + } + + if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) { + if (def_iolog_file && def_iolog_dir) { + command_info[info_len++] = expand_iolog_path("iolog_path=", + def_iolog_dir, def_iolog_file, &sudo_user.iolog_file); + sudo_user.iolog_file++; + } + if (def_log_input) { + command_info[info_len++] = estrdup("iolog_stdin=true"); + command_info[info_len++] = estrdup("iolog_ttyin=true"); + } + if (def_log_output) { + command_info[info_len++] = estrdup("iolog_stdout=true"); + command_info[info_len++] = estrdup("iolog_stderr=true"); + command_info[info_len++] = estrdup("iolog_ttyout=true"); + } + if (def_compress_io) + command_info[info_len++] = estrdup("iolog_compress=true"); + } + + log_allowed(validated); + if (ISSET(sudo_mode, MODE_CHECK)) + rval = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); + else if (ISSET(sudo_mode, MODE_LIST)) + display_privs(snl, list_pw ? list_pw : sudo_user.pw); /* XXX - return val */ + + /* Cleanup sudoers sources */ + tq_foreach_fwd(snl, nss) { + nss->close(nss); + } + if (def_group_plugin) + group_plugin_unload(); + + if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) { + /* rval already set appropriately */ + goto done; + } + + /* + * Set umask based on sudoers. + * If user's umask is more restrictive, OR in those bits too + * unless umask_override is set. + */ + if (def_umask != 0777) { + mode_t mask = def_umask; + if (!def_umask_override) { + mode_t omask = umask(mask); + mask |= omask; + umask(omask); + } + easprintf(&command_info[info_len++], "umask=0%o", (unsigned int)mask); + } + + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + char *p; + + /* Convert /bin/sh -> -sh so shell knows it is a login shell */ + if ((p = strrchr(NewArgv[0], '/')) == NULL) + p = NewArgv[0]; + *p = '-'; + NewArgv[0] = p; + + /* Set cwd to run user's homedir. */ + command_info[info_len++] = fmt_string("cwd", runas_pw->pw_dir); + + /* + * Newer versions of bash require the --login option to be used + * in conjunction with the -c option even if the shell name starts + * with a '-'. Unfortunately, bash 1.x uses -login, not --login + * so this will cause an error for that. + */ + if (NewArgc > 1 && strcmp(NewArgv[0], "-bash") == 0 && + strcmp(NewArgv[1], "-c") == 0) { + /* Use the extra slot before NewArgv so we can store --login. */ + NewArgv--; + NewArgc++; + NewArgv[0] = NewArgv[1]; + NewArgv[1] = "--login"; + } + +#if defined(_AIX) || (defined(__linux__) && !defined(HAVE_PAM)) + /* Insert system-wide environment variables. */ + read_env_file(_PATH_ENVIRONMENT, true); +#endif +#ifdef HAVE_LOGIN_CAP_H + /* Set environment based on login class. */ + if (login_class) { + login_cap_t *lc = login_getclass(login_class); + if (lc != NULL) { + setusercontext(lc, runas_pw, runas_pw->pw_uid, LOGIN_SETPATH|LOGIN_SETENV); + login_close(lc); + } + } +#endif /* HAVE_LOGIN_CAP_H */ + } + + /* Insert system-wide environment variables. */ + if (def_env_file) + read_env_file(def_env_file, false); + + /* Insert user-specified environment variables. */ + insert_env_vars(sudo_user.env_vars); + + /* Restore signal handlers before we exec. */ + (void) sigaction(SIGINT, &saved_sa_int, NULL); + (void) sigaction(SIGQUIT, &saved_sa_quit, NULL); + (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); + + if (ISSET(sudo_mode, MODE_EDIT)) { + char *editor = find_editor(NewArgc - 1, NewArgv + 1, &edit_argv); + if (editor == NULL) + goto bad; + command_info[info_len++] = fmt_string("command", editor); + command_info[info_len++] = estrdup("sudoedit=true"); + } else { + command_info[info_len++] = fmt_string("command", safe_cmnd); + } + if (def_stay_setuid) { + easprintf(&command_info[info_len++], "runas_uid=%u", + (unsigned int)user_uid); + easprintf(&command_info[info_len++], "runas_gid=%u", + (unsigned int)user_gid); + easprintf(&command_info[info_len++], "runas_euid=%u", + (unsigned int)runas_pw->pw_uid); + easprintf(&command_info[info_len++], "runas_egid=%u", + runas_gr ? (unsigned int)runas_gr->gr_gid : + (unsigned int)runas_pw->pw_gid); + } else { + easprintf(&command_info[info_len++], "runas_uid=%u", + (unsigned int)runas_pw->pw_uid); + easprintf(&command_info[info_len++], "runas_gid=%u", + runas_gr ? (unsigned int)runas_gr->gr_gid : + (unsigned int)runas_pw->pw_gid); + } + if (def_preserve_groups) { + command_info[info_len++] = "preserve_groups=true"; + } else { + int i, len; + gid_t egid; + size_t glsize; + char *cp, *gid_list; + struct group_list *grlist = get_group_list(runas_pw); + + /* We reserve an extra spot in the list for the effective gid. */ + glsize = sizeof("runas_groups=") - 1 + + ((grlist->ngids + 1) * (MAX_UID_T_LEN + 1)); + gid_list = emalloc(glsize); + memcpy(gid_list, "runas_groups=", sizeof("runas_groups=") - 1); + cp = gid_list + sizeof("runas_groups=") - 1; + + /* On BSD systems the effective gid is the first group in the list. */ + egid = runas_gr ? (unsigned int)runas_gr->gr_gid : + (unsigned int)runas_pw->pw_gid; + len = snprintf(cp, glsize - (cp - gid_list), "%u", egid); + if (len < 0 || len >= glsize - (cp - gid_list)) + errorx(1, _("internal error, runas_groups overflow")); + cp += len; + for (i = 0; i < grlist->ngids; i++) { + if (grlist->gids[i] != egid) { + len = snprintf(cp, glsize - (cp - gid_list), ",%u", + (unsigned int) grlist->gids[i]); + if (len < 0 || len >= glsize - (cp - gid_list)) + errorx(1, _("internal error, runas_groups overflow")); + cp += len; + } + } + command_info[info_len++] = gid_list; + grlist_delref(grlist); + } + if (def_closefrom >= 0) + easprintf(&command_info[info_len++], "closefrom=%d", def_closefrom); + if (def_noexec) + command_info[info_len++] = estrdup("noexec=true"); + if (def_set_utmp) + command_info[info_len++] = estrdup("set_utmp=true"); + if (def_use_pty) + command_info[info_len++] = estrdup("use_pty=true"); + if (def_utmp_runas) + command_info[info_len++] = fmt_string("utmp_user", runas_pw->pw_name); +#ifdef HAVE_LOGIN_CAP_H + if (def_use_loginclass) + command_info[info_len++] = fmt_string("login_class", login_class); +#endif /* HAVE_LOGIN_CAP_H */ +#ifdef HAVE_SELINUX + if (user_role != NULL) + command_info[info_len++] = fmt_string("selinux_role", user_role); + if (user_type != NULL) + command_info[info_len++] = fmt_string("selinux_type", user_type); +#endif /* HAVE_SELINUX */ + + /* Must audit before uid change. */ + audit_success(NewArgv); + + *command_infop = command_info; + + *argv_out = edit_argv ? edit_argv : NewArgv; + + /* Get private version of the environment and zero out stashed copy. */ + *user_env_out = env_get(); + env_init(NULL); + + goto done; + +bad: + rval = false; + +done: + rewind_perms(); + + /* Close the password and group files and free up memory. */ + sudo_endpwent(); + sudo_endgrent(); + + debug_return_bool(rval); +} + +static int +sudoers_policy_check(int argc, char * const argv[], char *env_add[], + char **command_infop[], char **argv_out[], char **user_env_out[]) +{ + debug_decl(sudoers_policy_check, SUDO_DEBUG_PLUGIN) + + if (!ISSET(sudo_mode, MODE_EDIT)) + SET(sudo_mode, MODE_RUN); + + debug_return_bool(sudoers_policy_main(argc, argv, 0, env_add, command_infop, + argv_out, user_env_out)); +} + +static int +sudoers_policy_validate(void) +{ + debug_decl(sudoers_policy_validate, SUDO_DEBUG_PLUGIN) + + user_cmnd = "validate"; + SET(sudo_mode, MODE_VALIDATE); + + debug_return_bool(sudoers_policy_main(0, NULL, I_VERIFYPW, NULL, NULL, NULL, NULL)); +} + +static void +sudoers_policy_invalidate(int remove) +{ + debug_decl(sudoers_policy_invalidate, SUDO_DEBUG_PLUGIN) + + user_cmnd = "kill"; + if (sigsetjmp(error_jmp, 1) == 0) { + remove_timestamp(remove); + plugin_cleanup(0); + } + + debug_return; +} + +static int +sudoers_policy_list(int argc, char * const argv[], int verbose, + const char *list_user) +{ + int rval; + debug_decl(sudoers_policy_list, SUDO_DEBUG_PLUGIN) + + user_cmnd = "list"; + if (argc) + SET(sudo_mode, MODE_CHECK); + else + SET(sudo_mode, MODE_LIST); + if (verbose) + long_list = 1; + if (list_user) { + list_pw = sudo_getpwnam(list_user); + if (list_pw == NULL) { + warningx(_("unknown user: %s"), list_user); + debug_return_bool(-1); + } + } + rval = sudoers_policy_main(argc, argv, I_LISTPW, NULL, NULL, NULL, NULL); + if (list_user) { + pw_delref(list_pw); + list_pw = NULL; + } + + debug_return_bool(rval); +} + +/* + * Initialize timezone, set umask, fill in ``sudo_user'' struct and + * load the ``interfaces'' array. + */ +static void +init_vars(char * const envp[]) +{ + char * const * ep; + debug_decl(init_vars, SUDO_DEBUG_PLUGIN) + +#ifdef HAVE_TZSET + (void) tzset(); /* set the timezone if applicable */ +#endif /* HAVE_TZSET */ + + for (ep = envp; *ep; ep++) { + /* XXX - don't fill in if empty string */ + switch (**ep) { + case 'K': + if (strncmp("KRB5CCNAME=", *ep, 11) == 0) + user_ccname = *ep + 11; + break; + case 'P': + if (strncmp("PATH=", *ep, 5) == 0) + user_path = *ep + 5; + break; + case 'S': + if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) + user_prompt = *ep + 12; + else if (strncmp("SUDO_USER=", *ep, 10) == 0) + prev_user = *ep + 10; + break; + } + } + + /* + * Get a local copy of the user's struct passwd with the shadow password + * if necessary. It is assumed that euid is 0 at this point so we + * can read the shadow passwd file if necessary. + */ + if ((sudo_user.pw = sudo_getpwuid(user_uid)) == NULL) { + /* + * It is not unusual for users to place "sudo -k" in a .logout + * file which can cause sudo to be run during reboot after the + * YP/NIS/NIS+/LDAP/etc daemon has died. + */ + if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) + errorx(1, _("unknown uid: %u"), (unsigned int) user_uid); + + /* Need to make a fake struct passwd for the call to log_fatal(). */ + sudo_user.pw = sudo_fakepwnamid(user_name, user_uid, user_gid); + log_fatal(0, _("unknown uid: %u"), (unsigned int) user_uid); + /* NOTREACHED */ + } + + /* + * Get group list. + */ + if (user_group_list == NULL) + user_group_list = get_group_list(sudo_user.pw); + + /* Set runas callback. */ + sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; + + /* It is now safe to use log_fatal() and set_perms() */ + debug_return; +} + +/* + * Fill in user_cmnd, user_args, user_base and user_stat variables + * and apply any command-specific defaults entries. + */ +static int +set_cmnd(void) +{ + int rval; + char *path = user_path; + debug_decl(set_cmnd, SUDO_DEBUG_PLUGIN) + + /* Resolve the path and return. */ + rval = FOUND; + user_stat = ecalloc(1, sizeof(struct stat)); + + /* Default value for cmnd, overridden below. */ + if (user_cmnd == NULL) + user_cmnd = NewArgv[0]; + + if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { + if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) { + if (def_secure_path && !user_is_exempt()) + path = def_secure_path; + set_perms(PERM_RUNAS); + rval = find_path(NewArgv[0], &user_cmnd, user_stat, path, + def_ignore_dot); + restore_perms(); + if (rval != FOUND) { + /* Failed as root, try as invoking user. */ + set_perms(PERM_USER); + rval = find_path(NewArgv[0], &user_cmnd, user_stat, path, + def_ignore_dot); + restore_perms(); + } + } + + /* set user_args */ + if (NewArgc > 1) { + char *to, *from, **av; + size_t size, n; + + /* Alloc and build up user_args. */ + for (size = 0, av = NewArgv + 1; *av; av++) + size += strlen(*av) + 1; + user_args = emalloc(size); + if (ISSET(sudo_mode, MODE_SHELL|MODE_LOGIN_SHELL)) { + /* + * When running a command via a shell, the sudo front-end + * escapes potential meta chars. We unescape non-spaces + * for sudoers matching and logging purposes. + */ + for (to = user_args, av = NewArgv + 1; (from = *av); av++) { + while (*from) { + if (from[0] == '\\' && !isspace((unsigned char)from[1])) + from++; + *to++ = *from++; + } + *to++ = ' '; + } + *--to = '\0'; + } else { + for (to = user_args, av = NewArgv + 1; *av; av++) { + n = strlcpy(to, *av, size - (to - user_args)); + if (n >= size - (to - user_args)) + errorx(1, _("internal error, set_cmnd() overflow")); + to += n; + *to++ = ' '; + } + *--to = '\0'; + } + } + } + if (strlen(user_cmnd) >= PATH_MAX) + errorx(1, _("%s: %s"), user_cmnd, strerror(ENAMETOOLONG)); + + if ((user_base = strrchr(user_cmnd, '/')) != NULL) + user_base++; + else + user_base = user_cmnd; + + if (!update_defaults(SETDEF_CMND)) + log_error(NO_STDERR, _("problem with defaults entries")); + + debug_return_int(rval); +} + +/* + * Open sudoers and sanity check mode/owner/type. + * Returns a handle to the sudoers file or NULL on error. + */ +FILE * +open_sudoers(const char *sudoers, bool doedit, bool *keepopen) +{ + struct stat sb; + FILE *fp = NULL; + debug_decl(open_sudoers, SUDO_DEBUG_PLUGIN) + + set_perms(PERM_SUDOERS); + + switch (sudo_secure_file(sudoers, sudoers_uid, sudoers_gid, &sb)) { + case SUDO_PATH_SECURE: + /* + * If we are expecting sudoers to be group readable but + * it is not, we must open the file as root, not uid 1. + */ + if (sudoers_uid == ROOT_UID && (sudoers_mode & S_IRGRP)) { + if ((sb.st_mode & S_IRGRP) == 0) { + restore_perms(); + set_perms(PERM_ROOT); + } + } + /* + * Open sudoers and make sure we can read it so we can present + * the user with a reasonable error message (unlike the lexer). + */ + if ((fp = fopen(sudoers, "r")) == NULL) { + log_error(USE_ERRNO, _("unable to open %s"), sudoers); + } else { + if (sb.st_size != 0 && fgetc(fp) == EOF) { + log_error(USE_ERRNO, _("unable to read %s"), + sudoers); + fclose(fp); + fp = NULL; + } else { + /* Rewind fp and set close on exec flag. */ + rewind(fp); + (void) fcntl(fileno(fp), F_SETFD, 1); + } + } + break; + case SUDO_PATH_MISSING: + log_error(USE_ERRNO, _("unable to stat %s"), sudoers); + break; + case SUDO_PATH_BAD_TYPE: + log_error(0, _("%s is not a regular file"), sudoers); + break; + case SUDO_PATH_WRONG_OWNER: + log_error(0, _("%s is owned by uid %u, should be %u"), + sudoers, (unsigned int) sb.st_uid, (unsigned int) sudoers_uid); + break; + case SUDO_PATH_WORLD_WRITABLE: + log_error(0, _("%s is world writable"), sudoers); + break; + case SUDO_PATH_GROUP_WRITABLE: + log_error(0, _("%s is owned by gid %u, should be %u"), + sudoers, (unsigned int) sb.st_gid, (unsigned int) sudoers_gid); + break; + default: + /* NOTREACHED */ + break; + } + + restore_perms(); /* change back to root */ + + debug_return_ptr(fp); +} + +#ifdef HAVE_LOGIN_CAP_H +static void +set_loginclass(struct passwd *pw) +{ + const int errflags = NO_MAIL|MSG_ONLY; + login_cap_t *lc; + debug_decl(set_loginclass, SUDO_DEBUG_PLUGIN) + + if (!def_use_loginclass) + debug_return; + + if (login_class && strcmp(login_class, "-") != 0) { + if (user_uid != 0 && + strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) + errorx(1, _("only root can use `-c %s'"), login_class); + } else { + login_class = pw->pw_class; + if (!login_class || !*login_class) + login_class = + (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; + } + + /* Make sure specified login class is valid. */ + lc = login_getclass(login_class); + if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) { + /* + * Don't make it a fatal error if the user didn't specify the login + * class themselves. We do this because if login.conf gets + * corrupted we want the admin to be able to use sudo to fix it. + */ + if (login_class) + log_fatal(errflags, _("unknown login class: %s"), login_class); + else + log_error(errflags, _("unknown login class: %s"), login_class); + def_use_loginclass = false; + } + login_close(lc); + debug_return; +} +#else +static void +set_loginclass(struct passwd *pw) +{ +} +#endif /* HAVE_LOGIN_CAP_H */ + +/* + * Look up the fully qualified domain name and set user_host and user_shost. + */ +void +set_fqdn(void) +{ + struct addrinfo *res0, hint; + char *p; + debug_decl(set_fqdn, SUDO_DEBUG_PLUGIN) + + zero_bytes(&hint, sizeof(hint)); + hint.ai_family = PF_UNSPEC; + hint.ai_flags = AI_CANONNAME; + if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { + log_error(MSG_ONLY, _("unable to resolve host %s"), user_host); + } else { + if (user_shost != user_host) + efree(user_shost); + efree(user_host); + user_host = estrdup(res0->ai_canonname); + freeaddrinfo(res0); + } + if ((p = strchr(user_host, '.')) != NULL) + user_shost = estrndup(user_host, (size_t)(p - user_host)); + else + user_shost = user_host; + debug_return; +} + +/* + * 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(const char *user) +{ + debug_decl(set_runaspw, SUDO_DEBUG_PLUGIN) + + if (runas_pw != NULL) + pw_delref(runas_pw); + if (*user == '#') { + if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) + runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); + } else { + if ((runas_pw = sudo_getpwnam(user)) == NULL) + log_fatal(NO_MAIL|MSG_ONLY, _("unknown user: %s"), user); + } + debug_return; +} + +/* + * Get group entry for the group we are going to run commands as + * and store it in runas_gr. + */ +static void +set_runasgr(const char *group) +{ + debug_decl(set_runasgr, SUDO_DEBUG_PLUGIN) + + if (runas_gr != NULL) + gr_delref(runas_gr); + if (*group == '#') { + if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) + runas_gr = sudo_fakegrnam(group); + } else { + if ((runas_gr = sudo_getgrnam(group)) == NULL) + log_fatal(NO_MAIL|MSG_ONLY, _("unknown group: %s"), group); + } + debug_return; +} + +/* + * Callback for runas_default sudoers setting. + */ +static int +cb_runas_default(const char *user) +{ + /* Only reset runaspw if user didn't specify one. */ + if (!runas_user && !runas_group) + set_runaspw(user); + return true; +} + +/* + * Cleanup hook for error()/errorx() + */ +void +plugin_cleanup(int gotsignal) +{ + struct sudo_nss *nss; + + if (!gotsignal) { + debug_decl(plugin_cleanup, SUDO_DEBUG_PLUGIN) + if (snl != NULL) { + tq_foreach_fwd(snl, nss) + nss->close(nss); + } + if (def_group_plugin) + group_plugin_unload(); + sudo_endpwent(); + sudo_endgrent(); + debug_return; + } +} + +static int +sudoers_policy_version(int verbose) +{ + debug_decl(sudoers_policy_version, SUDO_DEBUG_PLUGIN) + + if (sigsetjmp(error_jmp, 1)) { + /* error recovery via error(), errorx() or log_fatal() */ + debug_return_bool(-1); + } + + sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers policy plugin version %s\n"), + PACKAGE_VERSION); + sudo_printf(SUDO_CONV_INFO_MSG, _("Sudoers file grammar version %d\n"), + SUDOERS_GRAMMAR_VERSION); + + if (verbose) { + sudo_printf(SUDO_CONV_INFO_MSG, _("\nSudoers path: %s\n"), sudoers_file); +#ifdef HAVE_LDAP +# ifdef _PATH_NSSWITCH_CONF + sudo_printf(SUDO_CONV_INFO_MSG, _("nsswitch path: %s\n"), _PATH_NSSWITCH_CONF); +# endif + sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.conf path: %s\n"), _PATH_LDAP_CONF); + sudo_printf(SUDO_CONV_INFO_MSG, _("ldap.secret path: %s\n"), _PATH_LDAP_SECRET); +#endif + dump_auth_methods(); + dump_defaults(); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + if (interfaces_string != NULL) { + dump_interfaces(interfaces_string); + sudo_printf(SUDO_CONV_INFO_MSG, "\n"); + } + } + debug_return_bool(true); +} + +static int +deserialize_info(char * const args[], char * const settings[], char * const user_info[]) +{ + char * const *cur; + const char *p, *groups = NULL; + const char *debug_flags = NULL; + int flags = 0; + debug_decl(deserialize_info, SUDO_DEBUG_PLUGIN) + +#define MATCHES(s, v) (strncmp(s, v, sizeof(v) - 1) == 0) + + /* Parse sudo.conf plugin args. */ + if (args != NULL) { + for (cur = args; *cur != NULL; cur++) { + if (MATCHES(*cur, "sudoers_file=")) { + sudoers_file = *cur + sizeof("sudoers_file=") - 1; + continue; + } + if (MATCHES(*cur, "sudoers_uid=")) { + sudoers_uid = (uid_t) atoi(*cur + sizeof("sudoers_uid=") - 1); + continue; + } + if (MATCHES(*cur, "sudoers_gid=")) { + sudoers_gid = (gid_t) atoi(*cur + sizeof("sudoers_gid=") - 1); + continue; + } + if (MATCHES(*cur, "sudoers_mode=")) { + sudoers_mode = (mode_t) strtol(*cur + sizeof("sudoers_mode=") - 1, + NULL, 8); + continue; + } + } + } + + /* Parse command line settings. */ + user_closefrom = -1; + for (cur = settings; *cur != NULL; cur++) { + if (MATCHES(*cur, "closefrom=")) { + user_closefrom = atoi(*cur + sizeof("closefrom=") - 1); + continue; + } + if (MATCHES(*cur, "debug_flags=")) { + debug_flags = *cur + sizeof("debug_flags=") - 1; + continue; + } + if (MATCHES(*cur, "runas_user=")) { + runas_user = *cur + sizeof("runas_user=") - 1; + continue; + } + if (MATCHES(*cur, "runas_group=")) { + runas_group = *cur + sizeof("runas_group=") - 1; + continue; + } + if (MATCHES(*cur, "prompt=")) { + user_prompt = *cur + sizeof("prompt=") - 1; + def_passprompt_override = true; + continue; + } + if (MATCHES(*cur, "set_home=")) { + if (atobool(*cur + sizeof("set_home=") - 1) == true) + SET(flags, MODE_RESET_HOME); + continue; + } + if (MATCHES(*cur, "preserve_environment=")) { + if (atobool(*cur + sizeof("preserve_environment=") - 1) == true) + SET(flags, MODE_PRESERVE_ENV); + continue; + } + if (MATCHES(*cur, "run_shell=")) { + if (atobool(*cur + sizeof("run_shell=") - 1) == true) + SET(flags, MODE_SHELL); + continue; + } + if (MATCHES(*cur, "login_shell=")) { + if (atobool(*cur + sizeof("login_shell=") - 1) == true) { + SET(flags, MODE_LOGIN_SHELL); + def_env_reset = true; + } + continue; + } + if (MATCHES(*cur, "implied_shell=")) { + if (atobool(*cur + sizeof("implied_shell=") - 1) == true) + SET(flags, MODE_IMPLIED_SHELL); + continue; + } + if (MATCHES(*cur, "preserve_groups=")) { + if (atobool(*cur + sizeof("preserve_groups=") - 1) == true) + SET(flags, MODE_PRESERVE_GROUPS); + continue; + } + if (MATCHES(*cur, "ignore_ticket=")) { + if (atobool(*cur + sizeof("ignore_ticket=") - 1) == true) + SET(flags, MODE_IGNORE_TICKET); + continue; + } + if (MATCHES(*cur, "noninteractive=")) { + if (atobool(*cur + sizeof("noninteractive=") - 1) == true) + SET(flags, MODE_NONINTERACTIVE); + continue; + } + if (MATCHES(*cur, "sudoedit=")) { + if (atobool(*cur + sizeof("sudoedit=") - 1) == true) + SET(flags, MODE_EDIT); + continue; + } + if (MATCHES(*cur, "login_class=")) { + login_class = *cur + sizeof("login_class=") - 1; + def_use_loginclass = true; + continue; + } +#ifdef HAVE_SELINUX + if (MATCHES(*cur, "selinux_role=")) { + user_role = *cur + sizeof("selinux_role=") - 1; + continue; + } + if (MATCHES(*cur, "selinux_type=")) { + user_type = *cur + sizeof("selinux_type=") - 1; + continue; + } +#endif /* HAVE_SELINUX */ +#ifdef HAVE_BSD_AUTH_H + if (MATCHES(*cur, "bsdauth_type=")) { + login_style = *cur + sizeof("bsdauth_type=") - 1; + continue; + } +#endif /* HAVE_BSD_AUTH_H */ +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + if (MATCHES(*cur, "progname=")) { + setprogname(*cur + sizeof("progname=") - 1); + continue; + } +#endif + if (MATCHES(*cur, "network_addrs=")) { + interfaces_string = *cur + sizeof("network_addrs=") - 1; + set_interfaces(interfaces_string); + continue; + } + } + + for (cur = user_info; *cur != NULL; cur++) { + if (MATCHES(*cur, "user=")) { + user_name = estrdup(*cur + sizeof("user=") - 1); + continue; + } + if (MATCHES(*cur, "uid=")) { + user_uid = (uid_t) atoi(*cur + sizeof("uid=") - 1); + continue; + } + if (MATCHES(*cur, "gid=")) { + p = *cur + sizeof("gid=") - 1; + user_gid = (gid_t) atoi(p); + continue; + } + if (MATCHES(*cur, "groups=")) { + groups = *cur + sizeof("groups=") - 1; + continue; + } + if (MATCHES(*cur, "cwd=")) { + user_cwd = estrdup(*cur + sizeof("cwd=") - 1); + continue; + } + if (MATCHES(*cur, "tty=")) { + user_tty = user_ttypath = estrdup(*cur + sizeof("tty=") - 1); + if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + user_tty += sizeof(_PATH_DEV) - 1; + continue; + } + if (MATCHES(*cur, "host=")) { + user_host = user_shost = estrdup(*cur + sizeof("host=") - 1); + if ((p = strchr(user_host, '.'))) + user_shost = estrndup(user_host, (size_t)(p - user_host)); + continue; + } + if (MATCHES(*cur, "lines=")) { + sudo_user.lines = atoi(*cur + sizeof("lines=") - 1); + continue; + } + if (MATCHES(*cur, "cols=")) { + sudo_user.cols = atoi(*cur + sizeof("cols=") - 1); + continue; + } + } + if (user_cwd == NULL) + user_cwd = "unknown"; + if (user_tty == NULL) + user_tty = "unknown"; /* user_ttypath remains NULL */ + + if (groups != NULL && groups[0] != '\0') { + const char *cp; + GETGROUPS_T *gids; + int ngids; + + /* Count number of groups, including passwd gid. */ + ngids = 2; + for (cp = groups; *cp != '\0'; cp++) { + if (*cp == ',') + ngids++; + } + + /* The first gid in the list is the passwd group gid. */ + gids = emalloc2(ngids, sizeof(GETGROUPS_T)); + gids[0] = user_gid; + ngids = 1; + cp = groups; + for (;;) { + gids[ngids] = atoi(cp); + if (gids[0] != gids[ngids]) + ngids++; + cp = strchr(cp, ','); + if (cp == NULL) + break; + cp++; /* skip over comma */ + } + set_group_list(user_name, gids, ngids); + efree(gids); + } + + /* Setup debugging if indicated. */ + if (debug_flags != NULL) { + sudo_debug_init(NULL, debug_flags); + for (cur = settings; *cur != NULL; cur++) + sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s", *cur); + for (cur = user_info; *cur != NULL; cur++) + sudo_debug_printf(SUDO_DEBUG_INFO, "user_info: %s", *cur); + } + +#undef MATCHES + debug_return_int(flags); +} + +static char * +resolve_editor(char *editor, int nfiles, char **files, char ***argv_out) +{ + char *cp, **nargv, *editor_path = NULL; + int ac, i, nargc; + bool wasblank; + debug_decl(resolve_editor, SUDO_DEBUG_PLUGIN) + + editor = estrdup(editor); /* becomes part of argv_out */ + + /* + * Split editor into an argument vector; editor is reused (do not free). + * The EDITOR and VISUAL environment variables may contain command + * line args so look for those and alloc space for them too. + */ + nargc = 1; + for (wasblank = false, cp = editor; *cp != '\0'; cp++) { + if (isblank((unsigned char) *cp)) + wasblank = true; + else if (wasblank) { + wasblank = false; + nargc++; + } + } + /* If we can't find the editor in the user's PATH, give up. */ + cp = strtok(editor, " \t"); + if (cp == NULL || + find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) { + efree(editor); + debug_return_str(NULL); + } + nargv = (char **) emalloc2(nargc + 1 + nfiles + 1, sizeof(char *)); + for (ac = 0; cp != NULL && ac < nargc; ac++) { + nargv[ac] = cp; + cp = strtok(NULL, " \t"); + } + nargv[ac++] = "--"; + for (i = 0; i < nfiles; ) + nargv[ac++] = files[i++]; + nargv[ac] = NULL; + + *argv_out = nargv; + debug_return_str(editor_path); +} + +/* + * Determine which editor to use. We don't need to worry about restricting + * this to a "safe" editor since it runs with the uid of the invoking user, + * not the runas (privileged) user. + */ +static char * +find_editor(int nfiles, char **files, char ***argv_out) +{ + char *cp, *editor, *editor_path = NULL, **ev, *ev0[4]; + debug_decl(find_editor, SUDO_DEBUG_PLUGIN) + + /* + * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one. + */ + ev0[0] = "SUDO_EDITOR"; + ev0[1] = "VISUAL"; + ev0[2] = "EDITOR"; + ev0[3] = NULL; + for (ev = ev0; *ev != NULL; ev++) { + if ((editor = getenv(*ev)) != NULL && *editor != '\0') { + editor_path = resolve_editor(editor, nfiles, files, argv_out); + if (editor_path != NULL) + break; + } + } + if (editor_path == NULL) { + /* def_editor could be a path, split it up */ + editor = estrdup(def_editor); + cp = strtok(editor, ":"); + while (cp != NULL && editor_path == NULL) { + editor_path = resolve_editor(cp, nfiles, files, argv_out); + cp = strtok(NULL, ":"); + } + if (editor_path) + efree(editor); + } + if (!editor_path) { + audit_failure(NewArgv, _("%s: command not found"), editor); + warningx(_("%s: command not found"), editor); + } + debug_return_str(editor_path); +} + +#ifdef USE_ADMIN_FLAG +static void +create_admin_success_flag(void) +{ + struct stat statbuf; + char flagfile[PATH_MAX]; + int fd, n; + debug_decl(create_admin_success_flag, SUDO_DEBUG_PLUGIN) + + /* Check whether the user is in the admin group. */ + if (!user_in_group(sudo_user.pw, "admin")) + debug_return; + + /* Build path to flag file. */ + n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful", + user_dir); + if (n <= 0 || n >= sizeof(flagfile)) + debug_return; + + /* Create admin flag file if it doesn't already exist. */ + set_perms(PERM_USER); + if (stat(flagfile, &statbuf) != 0) { + fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644); + close(fd); + } + restore_perms(); + debug_return; +} +#else /* !USE_ADMIN_FLAG */ +static void +create_admin_success_flag(void) +{ + /* STUB */ +} +#endif /* USE_ADMIN_FLAG */ + +static void +sudoers_policy_register_hooks(int version, int (*register_hook)(struct sudo_hook *hook)) +{ + struct sudo_hook hook; + + memset(&hook, 0, sizeof(hook)); + hook.hook_version = SUDO_HOOK_VERSION; + + hook.hook_type = SUDO_HOOK_SETENV; + hook.hook_fn = sudoers_hook_setenv; + register_hook(&hook); + + hook.hook_type = SUDO_HOOK_UNSETENV; + hook.hook_fn = sudoers_hook_unsetenv; + register_hook(&hook); + + hook.hook_type = SUDO_HOOK_GETENV; + hook.hook_fn = sudoers_hook_getenv; + register_hook(&hook); + + hook.hook_type = SUDO_HOOK_PUTENV; + hook.hook_fn = sudoers_hook_putenv; + register_hook(&hook); +} + +struct policy_plugin sudoers_policy = { + SUDO_POLICY_PLUGIN, + SUDO_API_VERSION, + sudoers_policy_open, + sudoers_policy_close, + sudoers_policy_version, + sudoers_policy_check, + sudoers_policy_list, + sudoers_policy_validate, + sudoers_policy_invalidate, + sudoers_policy_init_session, + sudoers_policy_register_hooks +}; diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h new file mode 100644 index 0000000..7f753ef --- /dev/null +++ b/plugins/sudoers/sudoers.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1993-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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#ifndef _SUDO_SUDOERS_H +#define _SUDO_SUDOERS_H + +#include +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#include +#include "missing.h" +#include "error.h" +#include "alloc.h" +#include "list.h" +#include "fileops.h" +#include "defaults.h" +#include "logging.h" +#include "sudo_nss.h" +#include "sudo_plugin.h" +#include "sudo_debug.h" + +#define DEFAULT_TEXT_DOMAIN "sudoers" +#include "gettext.h" + +/* + * Password db and supplementary group IDs with associated group names. + */ +struct group_list { + char **groups; + GETGROUPS_T *gids; + int ngroups; + int ngids; +}; + +/* + * Info pertaining to the invoking user. + */ +struct sudo_user { + struct passwd *pw; + struct passwd *_runas_pw; + struct group *_runas_gr; + struct stat *cmnd_stat; + char *name; + char *path; + char *tty; + char *ttypath; + char *host; + char *shost; + char *prompt; + char *cmnd; + char *cmnd_args; + char *cmnd_base; + char *cmnd_safe; + char *class_name; + char *krb5_ccname; + struct group_list *group_list; + char * const * env_vars; +#ifdef HAVE_SELINUX + char *role; + char *type; +#endif + char *cwd; + char *iolog_file; + int closefrom; + int lines; + int cols; + uid_t uid; + uid_t gid; +}; + +/* + * Return values for sudoers_lookup(), also used as arguments for log_auth() + * Note: cannot use '0' as a value here. + */ +/* XXX - VALIDATE_SUCCESS and VALIDATE_FAILURE instead? */ +#define VALIDATE_ERROR 0x001 +#define VALIDATE_OK 0x002 +#define VALIDATE_NOT_OK 0x004 +#define FLAG_CHECK_USER 0x010 +#define FLAG_NO_USER 0x020 +#define FLAG_NO_HOST 0x040 +#define FLAG_NO_CHECK 0x080 + +/* + * find_path()/load_cmnd() return values + */ +#define FOUND 0 +#define NOT_FOUND 1 +#define NOT_FOUND_DOT 2 + +/* + * Various modes sudo can be in (based on arguments) in hex + */ +#define MODE_RUN 0x00000001 +#define MODE_EDIT 0x00000002 +#define MODE_VALIDATE 0x00000004 +#define MODE_INVALIDATE 0x00000008 +#define MODE_KILL 0x00000010 +#define MODE_VERSION 0x00000020 +#define MODE_HELP 0x00000040 +#define MODE_LIST 0x00000080 +#define MODE_CHECK 0x00000100 +#define MODE_LISTDEFS 0x00000200 +#define MODE_MASK 0x0000ffff + +/* Mode flags */ +#define MODE_BACKGROUND 0x00010000 /* XXX - unused */ +#define MODE_SHELL 0x00020000 +#define MODE_LOGIN_SHELL 0x00040000 +#define MODE_IMPLIED_SHELL 0x00080000 +#define MODE_RESET_HOME 0x00100000 +#define MODE_PRESERVE_GROUPS 0x00200000 +#define MODE_PRESERVE_ENV 0x00400000 +#define MODE_NONINTERACTIVE 0x00800000 +#define MODE_IGNORE_TICKET 0x01000000 + +/* + * Used with set_perms() + */ +#define PERM_INITIAL 0x00 +#define PERM_ROOT 0x01 +#define PERM_USER 0x02 +#define PERM_FULL_USER 0x03 +#define PERM_SUDOERS 0x04 +#define PERM_RUNAS 0x05 +#define PERM_TIMESTAMP 0x06 +#define PERM_NOEXIT 0x10 /* flag */ +#define PERM_MASK 0xf0 + +/* + * Shortcuts for sudo_user contents. + */ +#define user_name (sudo_user.name) +#define user_uid (sudo_user.uid) +#define user_gid (sudo_user.gid) +#define user_passwd (sudo_user.pw->pw_passwd) +#define user_uuid (sudo_user.uuid) +#define user_dir (sudo_user.pw->pw_dir) +#define user_group_list (sudo_user.group_list) +#define user_tty (sudo_user.tty) +#define user_ttypath (sudo_user.ttypath) +#define user_cwd (sudo_user.cwd) +#define user_cmnd (sudo_user.cmnd) +#define user_args (sudo_user.cmnd_args) +#define user_base (sudo_user.cmnd_base) +#define user_stat (sudo_user.cmnd_stat) +#define user_path (sudo_user.path) +#define user_prompt (sudo_user.prompt) +#define user_host (sudo_user.host) +#define user_shost (sudo_user.shost) +#define user_ccname (sudo_user.krb5_ccname) +#define safe_cmnd (sudo_user.cmnd_safe) +#define login_class (sudo_user.class_name) +#define runas_pw (sudo_user._runas_pw) +#define runas_gr (sudo_user._runas_gr) +#define user_role (sudo_user.role) +#define user_type (sudo_user.type) +#define user_closefrom (sudo_user.closefrom) + +#ifdef __TANDEM +# define ROOT_UID 65535 +#else +# define ROOT_UID 0 +#endif + +/* + * We used to use the system definition of PASS_MAX or _PASSWD_LEN, + * but that caused problems with various alternate authentication + * methods. So, we just define our own and assume that it is >= the + * system max. + */ +#define SUDO_PASS_MAX 256 + +struct lbuf; +struct passwd; +struct stat; +struct timeval; + +/* + * Function prototypes + */ +#define YY_DECL int yylex(void) + +/* goodpath.c */ +bool sudo_goodpath(const char *, struct stat *); + +/* findpath.c */ +int find_path(char *, char **, struct stat *, char *, int); + +/* check.c */ +int check_user(int, int); +void remove_timestamp(bool); +bool user_is_exempt(void); + +/* sudo_auth.c */ +int verify_user(struct passwd *pw, char *prompt); +int sudo_auth_begin_session(struct passwd *pw, char **user_env[]); +int sudo_auth_end_session(struct passwd *pw); +int sudo_auth_init(struct passwd *pw); +int sudo_auth_cleanup(struct passwd *pw); + +/* parse.c */ +int sudo_file_open(struct sudo_nss *); +int sudo_file_close(struct sudo_nss *); +int sudo_file_setdefs(struct sudo_nss *); +int sudo_file_lookup(struct sudo_nss *, int, int); +int sudo_file_parse(struct sudo_nss *); +int sudo_file_display_cmnd(struct sudo_nss *, struct passwd *); +int sudo_file_display_defaults(struct sudo_nss *, struct passwd *, struct lbuf *); +int sudo_file_display_bound_defaults(struct sudo_nss *, struct passwd *, struct lbuf *); +int sudo_file_display_privs(struct sudo_nss *, struct passwd *, struct lbuf *); + +/* set_perms.c */ +void rewind_perms(void); +int set_perms(int); +void restore_perms(void); +int pam_prep_user(struct passwd *); + +/* gram.y */ +int yyparse(void); + +/* toke.l */ +YY_DECL; +extern const char *sudoers_file; +extern mode_t sudoers_mode; +extern uid_t sudoers_uid; +extern gid_t sudoers_gid; + +/* defaults.c */ +void dump_defaults(void); +void dump_auth_methods(void); + +/* getspwuid.c */ +char *sudo_getepw(const struct passwd *); + +/* zero_bytes.c */ +void zero_bytes(volatile void *, size_t); + +/* sudo_nss.c */ +void display_privs(struct sudo_nss_list *, struct passwd *); +bool display_cmnd(struct sudo_nss_list *, struct passwd *); + +/* pwutil.c */ +void sudo_setgrent(void); +void sudo_endgrent(void); +void sudo_setpwent(void); +void sudo_endpwent(void); +void sudo_setspent(void); +void sudo_endspent(void); +struct group_list *get_group_list(struct passwd *pw); +void set_group_list(const char *, GETGROUPS_T *gids, int ngids); +struct passwd *sudo_getpwnam(const char *); +struct passwd *sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid); +struct passwd *sudo_fakepwnam(const char *, gid_t); +struct passwd *sudo_getpwuid(uid_t); +struct group *sudo_getgrnam(const char *); +struct group *sudo_fakegrnam(const char *); +struct group *sudo_getgrgid(gid_t); +void grlist_addref(struct group_list *); +void grlist_delref(struct group_list *); +void gr_addref(struct group *); +void gr_delref(struct group *); +void pw_addref(struct passwd *); +void pw_delref(struct passwd *); +bool user_in_group(struct passwd *, const char *); + +/* timestr.c */ +char *get_timestr(time_t, int); + +/* atobool.c */ +int atobool(const char *str); + +/* boottime.c */ +int get_boottime(struct timeval *); + +/* iolog.c */ +void io_nextid(char *iolog_dir, char sessid[7]); + +/* iolog_path.c */ +char *expand_iolog_path(const char *prefix, const char *dir, const char *file, + char **slashp); + +/* env.c */ +char **env_get(void); +void env_merge(char * const envp[], bool overwrite); +void env_init(char * const envp[]); +void init_envtables(void); +void insert_env_vars(char * const envp[]); +void read_env_file(const char *, int); +void rebuild_env(void); +void validate_env_vars(char * const envp[]); +int sudo_setenv(const char *var, const char *val, int overwrite); +int sudo_unsetenv(const char *var); +char *sudo_getenv(const char *name); +int sudoers_hook_getenv(const char *name, char **value, void *closure); +int sudoers_hook_putenv(char *string, void *closure); +int sudoers_hook_setenv(const char *name, const char *value, int overwrite, void *closure); +int sudoers_hook_unsetenv(const char *name, void *closure); + +/* fmt_string.c */ +char *fmt_string(const char *, const char *); + +/* sudoers.c */ +void plugin_cleanup(int); +void set_fqdn(void); +FILE *open_sudoers(const char *, bool, bool *); + +/* aix.c */ +void aix_restoreauthdb(void); +void aix_setauthdb(char *user); + +/* group_plugin.c */ +int group_plugin_load(char *plugin_info); +void group_plugin_unload(void); +int group_plugin_query(const char *user, const char *group, + const struct passwd *pwd); + +/* setgroups.c */ +int sudo_setgroups(int ngids, const GETGROUPS_T *gids); + +#ifndef _SUDO_MAIN +extern struct sudo_user sudo_user; +extern struct passwd *list_pw; +extern int long_list; +extern int sudo_mode; +extern uid_t timestamp_uid; +extern sudo_conv_t sudo_conv; +extern sudo_printf_t sudo_printf; +#endif + +#endif /* _SUDO_SUDOERS_H */ diff --git a/plugins/sudoers/sudoers.in b/plugins/sudoers/sudoers.in new file mode 100644 index 0000000..42e639e --- /dev/null +++ b/plugins/sudoers/sudoers.in @@ -0,0 +1,90 @@ +## sudoers file. +## +## This file MUST be edited with the 'visudo' command as root. +## Failure to use 'visudo' may result in syntax or file permission errors +## that prevent sudo from running. +## +## See the sudoers man page for the details on how to write a sudoers file. +## + +## +## Host alias specification +## +## Groups of machines. These may include host names (optionally with wildcards), +## IP addresses, network numbers or netgroups. +# Host_Alias WEBSERVERS = www1, www2, www3 + +## +## User alias specification +## +## Groups of users. These may consist of user names, uids, Unix groups, +## or netgroups. +# User_Alias ADMINS = millert, dowdy, mikef + +## +## Cmnd alias specification +## +## Groups of commands. Often used to group related commands together. +# Cmnd_Alias PROCESSES = /usr/bin/nice, /bin/kill, /usr/bin/renice, \ +# /usr/bin/pkill, /usr/bin/top + +## +## Defaults specification +## +## You may wish to keep some of the following environment variables +## when running commands via sudo. +## +## Locale settings +# Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET" +## +## Run X applications through sudo; HOME is used to find the +## .Xauthority file. Note that other programs use HOME to find +## configuration files and this may lead to privilege escalation! +# Defaults env_keep += "HOME" +## +## X11 resource path settings +# Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH" +## +## Desktop path settings +# Defaults env_keep += "QTDIR KDEDIR" +## +## Allow sudo-run commands to inherit the callers' ConsoleKit session +# Defaults env_keep += "XDG_SESSION_COOKIE" +## +## Uncomment to enable special input methods. Care should be taken as +## this may allow users to subvert the command being run via sudo. +# Defaults env_keep += "XMODIFIERS GTK_IM_MODULE QT_IM_MODULE QT_IM_SWITCHER" +## +## Uncomment to enable logging of a command's output, except for +## sudoreplay and reboot. Use sudoreplay to play back logged sessions. +# Defaults log_output +# Defaults!/usr/bin/sudoreplay !log_output +# Defaults!/usr/local/bin/sudoreplay !log_output +# Defaults!/sbin/reboot !log_output + +## +## Runas alias specification +## + +## +## User privilege specification +## +root ALL=(ALL) ALL + +## Uncomment to allow members of group wheel to execute any command +# %wheel ALL=(ALL) ALL + +## Same thing without a password +# %wheel ALL=(ALL) NOPASSWD: ALL + +## Uncomment to allow members of group sudo to execute any command +# %sudo ALL=(ALL) ALL + +## Uncomment to allow any user to run sudo if they know the password +## of the user they are running the command as (root by default). +# Defaults targetpw # Ask for the password of the target user +# ALL ALL=(ALL) ALL # WARNING: only use this together with 'Defaults targetpw' + +## Read drop-in files from @sysconfdir@/sudoers.d +## (the '#' here does not indicate a comment) +#includedir @sysconfdir@/sudoers.d diff --git a/plugins/sudoers/sudoers.sym b/plugins/sudoers/sudoers.sym new file mode 100644 index 0000000..7f74694 --- /dev/null +++ b/plugins/sudoers/sudoers.sym @@ -0,0 +1,2 @@ +sudoers_policy +sudoers_io diff --git a/plugins/sudoers/sudoers2ldif b/plugins/sudoers/sudoers2ldif new file mode 100755 index 0000000..442155e --- /dev/null +++ b/plugins/sudoers/sudoers2ldif @@ -0,0 +1,139 @@ +#!/usr/bin/env perl +use strict; + +# +# Converts a sudoers file to LDIF format in prepration for loading into +# the LDAP server. +# + +# BUGS: +# Does not yet handle multiple lines with : in them +# Does not yet remove quotation marks from options +# Does not yet escape + at the beginning of a dn +# Does not yet handle line wraps correctly +# Does not yet handle multiple roles with same name (needs tiebreaker) +# +# CAVEATS: +# Sudoers entries can have multiple RunAs entries that override former ones, +# with LDAP sudoRunAs{Group,User} applies to all commands in a sudoRole + +my %RA; +my %UA; +my %HA; +my %CA; +my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefined\n"; +my @options=(); + +my $did_defaults=0; +my $order = 0; + +# parse sudoers one line at a time +while (<>){ + + # remove comment + s/#.*//; + + # line continuation + $_.=<> while s/\\\s*$//s; + + # cleanup newline + chomp; + + # ignore blank lines + next if /^\s*$/; + + if (/^Defaults\s+/i) { + my $opt=$'; + $opt=~s/\s+$//; # remove trailing whitespace + push @options,$opt; + } elsif (/^(\S+)\s+(.+)=\s*(.*)/) { + + # Aliases or Definitions + my ($p1,$p2,$p3)=($1,$2,$3); + $p2=~s/\s+$//; # remove trailing whitespace + $p3=~s/\s+$//; # remove trailing whitespace + + if ($p1 eq "User_Alias") { + $UA{$p2}=$p3; + } elsif ($p1 eq "Runas_Alias") { + $RA{$p2}=$p3; + } elsif ($p1 eq "Host_Alias") { + $HA{$p2}=$p3; + } elsif ($p1 eq "Cmnd_Alias") { + $CA{$p2}=$p3; + } else { + if (!$did_defaults++){ + # do this once + print "dn: cn=defaults,$base\n"; + print "objectClass: top\n"; + print "objectClass: sudoRole\n"; + print "cn: defaults\n"; + print "description: Default sudoOption's go here\n"; + print "sudoOption: $_\n" foreach @options; + printf "sudoOrder: %d\n", ++$order; + print "\n"; + } + # Definition + my @users=split /\s*,\s*/,$p1; + my @hosts=split /\s*,\s*/,$p2; + my @cmds= split /\s*,\s*/,$p3; + @options=(); + print "dn: cn=$users[0],$base\n"; + print "objectClass: top\n"; + print "objectClass: sudoRole\n"; + print "cn: $users[0]\n"; + # will clobber options + print "sudoUser: $_\n" foreach expand(\%UA,@users); + print "sudoHost: $_\n" foreach expand(\%HA,@hosts); + foreach (@cmds) { + if (s/^\(([^\)]+)\)\s*//) { + my @runas = split(/:\s*/, $1); + if (defined($runas[0])) { + print "sudoRunAsUser: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[0])); + } + if (defined($runas[1])) { + print "sudoRunAsGroup: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[1])); + } + } + } + print "sudoCommand: $_\n" foreach expand(\%CA,@cmds); + print "sudoOption: $_\n" foreach @options; + printf "sudoOrder: %d\n", ++$order; + print "\n"; + } + + } else { + print "parse error: $_\n"; + } + +} + +# +# recursively expand hash elements +sub expand{ + my $ref=shift; + my @a=(); + + # preen the line a little + foreach (@_){ + # if NOPASSWD: directive found, mark entire entry as not requiring + s/NOPASSWD:\s*// && push @options,"!authenticate"; + s/PASSWD:\s*// && push @options,"authenticate"; + s/NOEXEC:\s*// && push @options,"noexec"; + s/EXEC:\s*// && push @options,"!noexec"; + s/SETENV:\s*// && push @options,"setenv"; + s/NOSETENV:\s*// && push @options,"!setenv"; + s/LOG_INPUT:\s*// && push @options,"log_input"; + s/NOLOG_INPUT:\s*// && push @options,"!log_input"; + s/LOG_OUTPUT:\s*// && push @options,"log_output"; + s/NOLOG_OUTPUT:\s*// && push @options,"!log_output"; + s/\w+://; # silently remove other directives + s/\s+$//; # right trim + } + + # do the expanding + push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_; + @a; +} + + diff --git a/plugins/sudoers/sudoers_version.h b/plugins/sudoers/sudoers_version.h new file mode 100644 index 0000000..346ace6 --- /dev/null +++ b/plugins/sudoers/sudoers_version.h @@ -0,0 +1,54 @@ +/* + * Major sudoers grammar changes are documented here. + * Note that minor changes such as added Defaults options are not listed here. + * This file placed in the public domain by Todd C. Miller on Apr 5, 2011. + * + * 1 sudo 1.1 + * 2 sudo 1.3, adds support specifying a directory instead of a command. + * 3 sudo 1.3.2, new parser, Aliases have to be upper case + * 4 sudo 1.3.2, adds User_Alias + * 5 sudo 1.3.4, netgroup support + * 6 sudo 1.3.5, support for escaping special chars + * 7 sudo 1.3.7, unix group support + * 8 sudo 1.4.1, wildcard support + * 9 sudo 1.4.2, double quote support in sudoers command line args + * 10 sudo 1.4.3, added NOPASSWD tag + * 11 sudo 1.4.3, added Runas_Spec + * 12 sudo 1.4.3, wildcards may be used in the pathname + * 13 sudo 1.4.3, command args of "" means no args allowed + * 14 sudo 1.4.4, '(' in command args no longer are a syntax error. + * 15 sudo 1.4.4, '!command' works in the presence of runas user or NOPASSWD. + * 16 sudo 1.4.4, all-caps user and host names are now handled properly. + * 17 sudo 1.5.0, usernames may now begin with a digit + * 18 sudo 1.5.3, adds Runas_Alias + * 19 sudo 1.5.7, %group may be used in a Runas_List + * 20 sudo 1.6.0, The runas user and NOPASSWD tags are now persistent across entries in a command list. A PASSWD tag has been added to reverse NOPASSWD + * 21 sudo 1.6.0, The '!' operator can be used in a Runas_Spec or an *_Alias + * 22 sudo 1.6.0, a list of hosts may be used in a Host_Spec + * 23 sudo 1.6.0, a list of users may be used in a User_Spec + * 24 sudo 1.6.0, It is now possible to escape "special" characters in usernames, hostnames, etc with a backslash. + * 25 sudo 1.6.0, Added Defaults run-time settings in sudoers. + * 26 sudo 1.6.0, relaxed the regexp for matching user, host, group names. + * 27 sudo 1.6.1, #uid is now allowed in a Runas_Alias. + * 28 sudo 1.6.2, Wildcards are now allowed in hostnames. + * 29 sudo 1.6.3p7, escaped special characters may be included in pathnames. + * 30 sudo 1.6.8, added NOEXEC and EXEC tags. + * 31 sudo 1.6.9, added SETENV and NOSETENV tags. + * 32 sudo 1.6.9p4, support for IPv6 address matching. + * 33 sudo 1.7.0, #include support. + * 34 sudo 1.7.0, Runas_Group support. + * 35 sudo 1.7.0, uid may now be used anywhere a username is valid. + * 36 sudo 1.7.2, #includedir support. + * 37 sudo 1.7.4, per-command Defaults support. + * 38 sudo 1.7.4, added LOG_INPUT/LOG_OUTPUT and NOLOG_INPUT/NOLOG_OUTPUT tags + * 39 sudo 1.7.6/1.8.1, White space is now permitted within a User_List in a per-user Defaults definition. + * 40 sudo 1.7.6/1.8.1, A group ID is now allowed in a User_List or Runas_List. + * 41 sudo 1.7.6/1.8.4, Support for relative paths in #include and #includedir +*/ + +#ifndef _SUDOERS_VERSION_H +#define _SUDOERS_VERSION_H + +#define SUDOERS_GRAMMAR_VERSION 41 + +#endif /* _SUDOERS_VERSION_H */ diff --git a/plugins/sudoers/sudoreplay.c b/plugins/sudoers/sudoreplay.c new file mode 100644 index 0000000..37c7e32 --- /dev/null +++ b/plugins/sudoers/sudoreplay.c @@ -0,0 +1,1100 @@ +/* + * Copyright (c) 2009-2012 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. + */ + +#include + +#include +#include +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#ifndef HAVE_STRUCT_TIMESPEC +# include "compat/timespec.h" +#endif +#include +#include +#include +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif +#ifdef HAVE_REGCOMP +# include +#endif +#ifdef HAVE_ZLIB_H +# include +#endif +#ifdef HAVE_SETLOCALE +# include +#endif +#include +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#include + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "gettext.h" +#include "sudo_plugin.h" +#include "sudo_conf.h" +#include "sudo_debug.h" + +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + +/* Must match the defines in iolog.c */ +#define IOFD_STDIN 0 +#define IOFD_STDOUT 1 +#define IOFD_STDERR 2 +#define IOFD_TTYIN 3 +#define IOFD_TTYOUT 4 +#define IOFD_TIMING 5 +#define IOFD_MAX 6 + +/* Bitmap of iofds to be replayed */ +unsigned int replay_filter = (1 << IOFD_STDOUT) | (1 << IOFD_STDERR) | + (1 << IOFD_TTYOUT); + +/* For getopt(3) */ +extern char *optarg; +extern int optind; + +union io_fd { + FILE *f; +#ifdef HAVE_ZLIB_H + gzFile g; +#endif + void *v; +}; + +/* + * Info present in the I/O log file + */ +struct log_info { + char *cwd; + char *user; + char *runas_user; + char *runas_group; + char *tty; + char *cmd; + time_t tstamp; + int rows; + int cols; +}; + +/* + * Handle expressions like: + * ( user millert or user root ) and tty console and command /bin/sh + */ +struct search_node { + struct search_node *next; +#define ST_EXPR 1 +#define ST_TTY 2 +#define ST_USER 3 +#define ST_PATTERN 4 +#define ST_RUNASUSER 5 +#define ST_RUNASGROUP 6 +#define ST_FROMDATE 7 +#define ST_TODATE 8 +#define ST_CWD 9 + char type; + char negated; + char or; + char pad; + union { +#ifdef HAVE_REGCOMP + regex_t cmdre; +#endif + time_t tstamp; + char *cwd; + char *tty; + char *user; + char *pattern; + char *runas_group; + char *runas_user; + struct search_node *expr; + void *ptr; + } u; +} *search_expr; + +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +#define STACK_NODE_SIZE 32 +static struct search_node *node_stack[32]; +static int stack_top; + +static const char *session_dir = _PATH_SUDO_IO_LOGDIR; + +static union io_fd io_fds[IOFD_MAX]; +static const char *io_fnames[IOFD_MAX] = { + "/stdin", + "/stdout", + "/stderr", + "/ttyin", + "/ttyout", + "/timing" +}; + +extern time_t get_date(char *); +extern char *get_timestr(time_t, int); +extern int term_raw(int, int); +extern int term_restore(int, int); +extern void get_ttysize(int *rowp, int *colp); +void cleanup(int); + +static int list_sessions(int, char **, const char *, const char *, const char *); +static int parse_expr(struct search_node **, char **); +static void check_input(int, double *); +static void delay(double); +static void help(void) __attribute__((__noreturn__)); +static void usage(int); +static int open_io_fd(char *pathbuf, int len, const char *suffix, union io_fd *fdp); +static int parse_timing(const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes); +static struct log_info *parse_logfile(char *logfile); +static void free_log_info(struct log_info *li); + +#ifdef HAVE_REGCOMP +# define REGEX_T regex_t +#else +# define REGEX_T char +#endif + +#define VALID_ID(s) (isalnum((unsigned char)(s)[0]) && \ + isalnum((unsigned char)(s)[1]) && isalnum((unsigned char)(s)[2]) && \ + isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \ + isalnum((unsigned char)(s)[5]) && (s)[6] == '\0') + +#define IS_IDLOG(s) ( \ + isalnum((unsigned char)(s)[0]) && isalnum((unsigned char)(s)[1]) && \ + (s)[2] == '/' && \ + isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \ + (s)[5] == '/' && \ + isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \ + (s)[8] == '/' && (s)[9] == 'l' && (s)[10] == 'o' && (s)[11] == 'g' && \ + (s)[12] == '\0') + +int +main(int argc, char *argv[]) +{ + int ch, idx, plen, nready, exitcode = 0, rows = 0, cols = 0; + bool interactive = false, listonly = false; + const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = "."; + char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; + double seconds, to_wait, speed = 1.0, max_wait = 0; + fd_set *fdsw; + sigaction_t sa; + size_t len, nbytes, nread, off; + ssize_t nwritten; + struct log_info *li; + debug_decl(main, SUDO_DEBUG_MAIN) + +#if defined(SUDO_DEVEL) && defined(__OpenBSD__) + { + extern char *malloc_options; + malloc_options = "AFGJPR"; + } +#endif + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + setprogname(argc > 0 ? argv[0] : "sudoreplay"); +#endif + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); + decimal = localeconv()->decimal_point; +#endif + bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have sudoreplay domain */ + textdomain("sudoers"); + + /* Read sudo.conf. */ + sudo_conf_read(); + + while ((ch = getopt(argc, argv, "d:f:hlm:s:V")) != -1) { + switch(ch) { + case 'd': + session_dir = optarg; + break; + case 'f': + /* Set the replay filter. */ + replay_filter = 0; + for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) { + if (strcmp(cp, "stdout") == 0) + SET(replay_filter, 1 << IOFD_STDOUT); + else if (strcmp(cp, "stderr") == 0) + SET(replay_filter, 1 << IOFD_STDERR); + else if (strcmp(cp, "ttyout") == 0) + SET(replay_filter, 1 << IOFD_TTYOUT); + else + errorx(1, _("invalid filter option: %s"), optarg); + } + break; + case 'h': + help(); + /* NOTREACHED */ + case 'l': + listonly = true; + break; + case 'm': + errno = 0; + max_wait = strtod(optarg, &ep); + if (*ep != '\0' || errno != 0) + errorx(1, _("invalid max wait: %s"), optarg); + break; + case 's': + errno = 0; + speed = strtod(optarg, &ep); + if (*ep != '\0' || errno != 0) + errorx(1, _("invalid speed factor: %s"), optarg); + break; + case 'V': + (void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION); + goto done; + default: + usage(1); + /* NOTREACHED */ + } + + } + argc -= optind; + argv += optind; + + if (listonly) { + exitcode = list_sessions(argc, argv, pattern, user, tty); + goto done; + } + + if (argc != 1) + usage(1); + + /* 6 digit ID in base 36, e.g. 01G712AB or free-form name */ + id = argv[0]; + if (VALID_ID(id)) { + plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing", + session_dir, id, &id[2], &id[4]); + if (plen <= 0 || plen >= sizeof(path)) + errorx(1, _("%s/%.2s/%.2s/%.2s/timing: %s"), session_dir, + id, &id[2], &id[4], strerror(ENAMETOOLONG)); + } else { + plen = snprintf(path, sizeof(path), "%s/%s/timing", + session_dir, id); + if (plen <= 0 || plen >= sizeof(path)) + errorx(1, _("%s/%s/timing: %s"), session_dir, + id, strerror(ENAMETOOLONG)); + } + plen -= 7; + + /* Open files for replay, applying replay filter for the -f flag. */ + for (idx = 0; idx < IOFD_MAX; idx++) { + if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) { + if (open_io_fd(path, plen, io_fnames[idx], &io_fds[idx]) == -1) + error(1, _("unable to open %s"), path); + } + } + + /* Parse log file. */ + path[plen] = '\0'; + strlcat(path, "/log", sizeof(path)); + if ((li = parse_logfile(path)) == NULL) + exit(1); + printf(_("Replaying sudo session: %s\n"), li->cmd); + + /* Make sure the terminal is large enough. */ + get_ttysize(&rows, &cols); + if (li->rows != 0 && li->cols != 0) { + if (li->rows > rows) { + printf(_("Warning: your terminal is too small to properly replay the log.\n")); + printf(_("Log geometry is %d x %d, your terminal's geometry is %d x %d."), li->rows, li->cols, rows, cols); + } + } + + /* Done with parsed log file. */ + free_log_info(li); + li = NULL; + + fflush(stdout); + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESETHAND; + sa.sa_handler = cleanup; + (void) sigaction(SIGINT, &sa, NULL); + (void) sigaction(SIGKILL, &sa, NULL); + (void) sigaction(SIGTERM, &sa, NULL); + (void) sigaction(SIGHUP, &sa, NULL); + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_IGN; + (void) sigaction(SIGTSTP, &sa, NULL); + (void) sigaction(SIGQUIT, &sa, NULL); + + /* XXX - read user input from /dev/tty and set STDOUT to raw if not a pipe */ + /* Set stdin to raw mode if it is a tty */ + interactive = isatty(STDIN_FILENO); + if (interactive) { + ch = fcntl(STDIN_FILENO, F_GETFL, 0); + if (ch != -1) + (void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK); + if (!term_raw(STDIN_FILENO, 1)) + error(1, _("unable to set tty to raw mode")); + } + fdsw = ecalloc(howmany(STDOUT_FILENO + 1, NFDBITS), sizeof(fd_mask)); + + /* + * Timing file consists of line of the format: "%f %d\n" + */ +#ifdef HAVE_ZLIB_H + while (gzgets(io_fds[IOFD_TIMING].g, buf, sizeof(buf)) != NULL) { +#else + while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) { +#endif + if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes)) + errorx(1, _("invalid timing file line: %s"), buf); + + if (interactive) + check_input(STDIN_FILENO, &speed); + + /* Adjust delay using speed factor and clamp to max_wait */ + to_wait = seconds / speed; + if (max_wait && to_wait > max_wait) + to_wait = max_wait; + delay(to_wait); + + /* Even if we are not relaying, we still have to delay. */ + if (io_fds[idx].v == NULL) + continue; + + /* All output is sent to stdout. */ + while (nbytes != 0) { + if (nbytes > sizeof(buf)) + len = sizeof(buf); + else + len = nbytes; +#ifdef HAVE_ZLIB_H + nread = gzread(io_fds[idx].g, buf, len); +#else + nread = fread(buf, 1, len, io_fds[idx].f); +#endif + nbytes -= nread; + off = 0; + do { + /* no stdio, must be unbuffered */ + nwritten = write(STDOUT_FILENO, buf + off, nread - off); + if (nwritten == -1) { + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + FD_SET(STDOUT_FILENO, fdsw); + do { + nready = select(STDOUT_FILENO + 1, NULL, fdsw, NULL, NULL); + } while (nready == -1 && errno == EINTR); + if (nready == 1) + continue; + } + error(1, _("writing to standard output")); + } + off += nwritten; + } while (nread > off); + } + } + term_restore(STDIN_FILENO, 1); +done: + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); + exit(exitcode); +} + +static void +delay(double secs) +{ + struct timespec ts, rts; + int rval; + + /* + * Typical max resolution is 1/HZ but we can't portably check that. + * If the interval is small enough, just ignore it. + */ + if (secs < 0.0001) + return; + + rts.tv_sec = secs; + rts.tv_nsec = (secs - (double) rts.tv_sec) * 1000000000.0; + do { + memcpy(&ts, &rts, sizeof(ts)); + rval = nanosleep(&ts, &rts); + } while (rval == -1 && errno == EINTR); + if (rval == -1) { + error2(1, _("nanosleep: tv_sec %ld, tv_nsec %ld"), + (long)ts.tv_sec, (long)ts.tv_nsec); + } +} + +static int +open_io_fd(char *path, int len, const char *suffix, union io_fd *fdp) +{ + path[len] = '\0'; + strlcat(path, suffix, PATH_MAX); + debug_decl(open_io_fd, SUDO_DEBUG_UTIL) + +#ifdef HAVE_ZLIB_H + fdp->g = gzopen(path, "r"); +#else + fdp->f = fopen(path, "r"); +#endif + debug_return_int(fdp->v ? 0 : -1); +} + +/* + * Build expression list from search args + */ +static int +parse_expr(struct search_node **headp, char *argv[]) +{ + struct search_node *sn, *newsn; + char or = 0, not = 0, type, **av; + debug_decl(parse_expr, SUDO_DEBUG_UTIL) + + sn = *headp; + for (av = argv; *av; av++) { + switch (av[0][0]) { + case 'a': /* and (ignore) */ + if (strncmp(*av, "and", strlen(*av)) != 0) + goto bad; + continue; + case 'o': /* or */ + if (strncmp(*av, "or", strlen(*av)) != 0) + goto bad; + or = 1; + continue; + case '!': /* negate */ + if (av[0][1] != '\0') + goto bad; + not = 1; + continue; + case 'c': /* command */ + if (av[0][1] == '\0') + errorx(1, _("ambiguous expression \"%s\""), *av); + if (strncmp(*av, "cwd", strlen(*av)) == 0) + type = ST_CWD; + else if (strncmp(*av, "command", strlen(*av)) == 0) + type = ST_PATTERN; + else + goto bad; + break; + case 'f': /* from date */ + if (strncmp(*av, "fromdate", strlen(*av)) != 0) + goto bad; + type = ST_FROMDATE; + break; + case 'g': /* runas group */ + if (strncmp(*av, "group", strlen(*av)) != 0) + goto bad; + type = ST_RUNASGROUP; + break; + case 'r': /* runas user */ + if (strncmp(*av, "runas", strlen(*av)) != 0) + goto bad; + type = ST_RUNASUSER; + break; + case 't': /* tty or to date */ + if (av[0][1] == '\0') + errorx(1, _("ambiguous expression \"%s\""), *av); + if (strncmp(*av, "todate", strlen(*av)) == 0) + type = ST_TODATE; + else if (strncmp(*av, "tty", strlen(*av)) == 0) + type = ST_TTY; + else + goto bad; + break; + case 'u': /* user */ + if (strncmp(*av, "user", strlen(*av)) != 0) + goto bad; + type = ST_USER; + break; + case '(': /* start sub-expression */ + if (av[0][1] != '\0') + goto bad; + if (stack_top + 1 == STACK_NODE_SIZE) { + errorx(1, _("too many parenthesized expressions, max %d"), + STACK_NODE_SIZE); + } + node_stack[stack_top++] = sn; + type = ST_EXPR; + break; + case ')': /* end sub-expression */ + if (av[0][1] != '\0') + goto bad; + /* pop */ + if (--stack_top < 0) + errorx(1, _("unmatched ')' in expression")); + if (node_stack[stack_top]) + sn->next = node_stack[stack_top]->next; + debug_return_int(av - argv + 1); + bad: + default: + errorx(1, _("unknown search term \"%s\""), *av); + /* NOTREACHED */ + } + + /* Allocate new search node */ + newsn = ecalloc(1, sizeof(*newsn)); + newsn->type = type; + newsn->or = or; + newsn->negated = not; + /* newsn->next = NULL; */ + if (type == ST_EXPR) { + av += parse_expr(&newsn->u.expr, av + 1); + } else { + if (*(++av) == NULL) + errorx(1, _("%s requires an argument"), av[-1]); +#ifdef HAVE_REGCOMP + if (type == ST_PATTERN) { + if (regcomp(&newsn->u.cmdre, *av, REG_EXTENDED|REG_NOSUB) != 0) + errorx(1, _("invalid regular expression: %s"), *av); + } else +#endif + if (type == ST_TODATE || type == ST_FROMDATE) { + newsn->u.tstamp = get_date(*av); + if (newsn->u.tstamp == -1) + errorx(1, _("could not parse date \"%s\""), *av); + } else { + newsn->u.ptr = *av; + } + } + not = or = 0; /* reset state */ + if (sn) + sn->next = newsn; + else + *headp = newsn; + sn = newsn; + } + if (stack_top) + errorx(1, _("unmatched '(' in expression")); + if (or) + errorx(1, _("illegal trailing \"or\"")); + if (not) + errorx(1, _("illegal trailing \"!\"")); + + debug_return_int(av - argv); +} + +static bool +match_expr(struct search_node *head, struct log_info *log) +{ + struct search_node *sn; + bool matched = true; + int rc; + debug_decl(match_expr, SUDO_DEBUG_UTIL) + + for (sn = head; sn; sn = sn->next) { + /* If we have no match, skip ahead to the next OR entry. */ + if (!matched && !sn->or) + continue; + + switch (sn->type) { + case ST_EXPR: + matched = match_expr(sn->u.expr, log); + break; + case ST_CWD: + matched = strcmp(sn->u.cwd, log->cwd) == 0; + break; + case ST_TTY: + matched = strcmp(sn->u.tty, log->tty) == 0; + break; + case ST_RUNASGROUP: + matched = strcmp(sn->u.runas_group, log->runas_group) == 0; + break; + case ST_RUNASUSER: + matched = strcmp(sn->u.runas_user, log->runas_user) == 0; + break; + case ST_USER: + matched = strcmp(sn->u.user, log->user) == 0; + break; + case ST_PATTERN: +#ifdef HAVE_REGCOMP + rc = regexec(&sn->u.cmdre, log->cmd, 0, NULL, 0); + if (rc && rc != REG_NOMATCH) { + char buf[BUFSIZ]; + regerror(rc, &sn->u.cmdre, buf, sizeof(buf)); + errorx(1, "%s", buf); + } + matched = rc == REG_NOMATCH ? 0 : 1; +#else + matched = strstr(log.cmd, sn->u.pattern) != NULL; +#endif + break; + case ST_FROMDATE: + matched = log->tstamp >= sn->u.tstamp; + break; + case ST_TODATE: + matched = log->tstamp <= sn->u.tstamp; + break; + } + if (sn->negated) + matched = !matched; + } + debug_return_bool(matched); +} + +static struct log_info * +parse_logfile(char *logfile) +{ + FILE *fp; + char *buf = NULL, *cp, *ep; + size_t bufsize = 0, cwdsize = 0, cmdsize = 0; + struct log_info *li = NULL; + debug_decl(list_session, SUDO_DEBUG_UTIL) + + fp = fopen(logfile, "r"); + if (fp == NULL) { + warning(_("unable to open %s"), logfile); + goto bad; + } + + /* + * ID file has three lines: + * 1) a log info line + * 2) cwd + * 3) command with args + */ + li = ecalloc(1, sizeof(*li)); + if (getline(&buf, &bufsize, fp) == -1 || + getline(&li->cwd, &cwdsize, fp) == -1 || + getline(&li->cmd, &cmdsize, fp) == -1) { + goto bad; + } + + /* Strip the newline from the cwd and command. */ + li->cwd[strcspn(li->cwd, "\n")] = '\0'; + li->cmd[strcspn(li->cmd, "\n")] = '\0'; + + /* + * Crack the log line (rows and cols not present in old versions). + * timestamp:user:runas_user:runas_group:tty:rows:cols + */ + buf[strcspn(buf, "\n")] = '\0'; + + /* timestamp */ + if ((ep = strchr(buf, ':')) == NULL) + goto bad; + if ((li->tstamp = atoi(buf)) == 0) + goto bad; + + /* user */ + cp = ep + 1; + if ((ep = strchr(cp, ':')) == NULL) + goto bad; + li->user = estrndup(cp, (size_t)(ep - cp)); + + /* runas user */ + cp = ep + 1; + if ((ep = strchr(cp, ':')) == NULL) + goto bad; + li->runas_user = estrndup(cp, (size_t)(ep - cp)); + + /* runas group */ + cp = ep + 1; + if ((ep = strchr(cp, ':')) == NULL) + goto bad; + if (cp != ep) + li->runas_group = estrndup(cp, (size_t)(ep - cp)); + + /* tty, followed by optional rows + columns */ + cp = ep + 1; + if ((ep = strchr(cp, ':')) == NULL) { + li->tty = estrdup(cp); + } else { + li->tty = estrndup(cp, (size_t)(ep - cp)); + cp = ep + 1; + li->rows = atoi(cp); + if ((ep = strchr(cp, ':')) != NULL) { + cp = ep + 1; + li->cols = atoi(cp); + } + } + fclose(fp); + efree(buf); + debug_return_ptr(li); + +bad: + fclose(fp); + efree(buf); + free_log_info(li); + debug_return_ptr(NULL); +} + +static void +free_log_info(struct log_info *li) +{ + if (li != NULL) { + efree(li->cwd); + efree(li->user); + efree(li->runas_user); + efree(li->runas_group); + efree(li->tty); + efree(li->cmd); + efree(li); + } +} + +static int +list_session(char *logfile, REGEX_T *re, const char *user, const char *tty) +{ + char idbuf[7], *idstr, *cp; + struct log_info *li; + int rval = -1; + debug_decl(list_session, SUDO_DEBUG_UTIL) + + if ((li = parse_logfile(logfile)) == NULL) + goto done; + + /* Match on search expression if there is one. */ + if (search_expr && !match_expr(search_expr, li)) + goto done; + + /* Convert from /var/log/sudo-sessions/00/00/01/log to 000001 */ + cp = logfile + strlen(session_dir) + 1; + if (IS_IDLOG(cp)) { + idbuf[0] = cp[0]; + idbuf[1] = cp[1]; + idbuf[2] = cp[3]; + idbuf[3] = cp[4]; + idbuf[4] = cp[6]; + idbuf[5] = cp[7]; + idbuf[6] = '\0'; + idstr = idbuf; + } else { + /* Not an id, just use the iolog_file portion. */ + cp[strlen(cp) - 4] = '\0'; + idstr = cp; + } + /* XXX - print rows + cols? */ + printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ", + get_timestr(li->tstamp, 1), li->user, li->tty, li->cwd, li->runas_user); + if (li->runas_group) + printf("GROUP=%s ; ", li->runas_group); + printf("TSID=%s ; COMMAND=%s\n", idstr, li->cmd); + + rval = 0; + +done: + free_log_info(li); + debug_return_int(rval); +} + +static int +session_compare(const void *v1, const void *v2) +{ + const char *s1 = *(const char **)v1; + const char *s2 = *(const char **)v2; + return strcmp(s1, s2); +} + +/* XXX - always returns 0, calls error() on failure */ +static int +find_sessions(const char *dir, REGEX_T *re, const char *user, const char *tty) +{ + DIR *d; + struct dirent *dp; + struct stat sb; + size_t sdlen, sessions_len = 0, sessions_size = 36*36; + int i, len; + char pathbuf[PATH_MAX], **sessions = NULL; + debug_decl(find_sessions, SUDO_DEBUG_UTIL) + + d = opendir(dir); + if (d == NULL) + error(1, _("unable to open %s"), dir); + + /* XXX - would be faster to chdir and use relative names */ + sdlen = strlcpy(pathbuf, dir, sizeof(pathbuf)); + if (sdlen + 1 >= sizeof(pathbuf)) { + errno = ENAMETOOLONG; + error(1, "%s/", dir); + } + pathbuf[sdlen++] = '/'; + pathbuf[sdlen] = '\0'; + + /* Store potential session dirs for sorting. */ + sessions = emalloc2(sessions_size, sizeof(char *)); + while ((dp = readdir(d)) != NULL) { + /* Skip "." and ".." */ + if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + continue; +#ifdef HAVE_STRUCT_DIRENT_D_TYPE + if (dp->d_type != DT_DIR) + continue; +#endif + + /* Add name to session list. */ + if (sessions_len + 1 > sessions_size) { + sessions_size <<= 1; + sessions = erealloc3(sessions, sessions_size, sizeof(char *)); + } + sessions[sessions_len++] = estrdup(dp->d_name); + } + closedir(d); + + /* Sort and list the sessions. */ + qsort(sessions, sessions_len, sizeof(char *), session_compare); + for (i = 0; i < sessions_len; i++) { + len = snprintf(&pathbuf[sdlen], sizeof(pathbuf) - sdlen, + "%s/log", sessions[i]); + if (len <= 0 || len >= sizeof(pathbuf) - sdlen) { + errno = ENAMETOOLONG; + error(1, "%s/%s/log", dir, sessions[i]); + } + efree(sessions[i]); + + /* Check for dir with a log file. */ + if (lstat(pathbuf, &sb) == 0 && S_ISREG(sb.st_mode)) { + list_session(pathbuf, re, user, tty); + } else { + /* Strip off "/log" and recurse if a dir. */ + pathbuf[sdlen + len - 4] = '\0'; +#ifndef HAVE_STRUCT_DIRENT_D_TYPE + if (lstat(pathbuf, &sb) == 0 && S_ISDIR(sb.st_mode)) +#endif + find_sessions(pathbuf, re, user, tty); + } + } + efree(sessions); + + debug_return_int(0); +} + +/* XXX - always returns 0, calls error() on failure */ +static int +list_sessions(int argc, char **argv, const char *pattern, const char *user, + const char *tty) +{ + REGEX_T rebuf, *re = NULL; + debug_decl(list_sessions, SUDO_DEBUG_UTIL) + + /* Parse search expression if present */ + parse_expr(&search_expr, argv); + +#ifdef HAVE_REGCOMP + /* optional regex */ + if (pattern) { + re = &rebuf; + if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0) + errorx(1, _("invalid regex: %s"), pattern); + } +#else + re = (char *) pattern; +#endif /* HAVE_REGCOMP */ + + debug_return_int(find_sessions(session_dir, re, user, tty)); +} + +/* + * Check input for ' ', '<', '>' + * pause, slow, fast + */ +static void +check_input(int ttyfd, double *speed) +{ + fd_set *fdsr; + int nready, paused = 0; + struct timeval tv; + char ch; + ssize_t n; + debug_decl(check_input, SUDO_DEBUG_UTIL) + + fdsr = ecalloc(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask)); + for (;;) { + FD_SET(ttyfd, fdsr); + tv.tv_sec = 0; + tv.tv_usec = 0; + + nready = select(ttyfd + 1, fdsr, NULL, NULL, paused ? NULL : &tv); + if (nready != 1) + break; + n = read(ttyfd, &ch, 1); + if (n == 1) { + if (paused) { + paused = 0; + continue; + } + switch (ch) { + case ' ': + paused = 1; + break; + case '<': + *speed /= 2; + break; + case '>': + *speed *= 2; + break; + } + } + } + free(fdsr); + debug_return; +} + +/* + * Parse a timing line, which is formatted as: + * index sleep_time num_bytes + * Where index is IOFD_*, sleep_time is the number of seconds to sleep + * before writing the data and num_bytes is the number of bytes to output. + * Returns 1 on success and 0 on failure. + */ +static int +parse_timing(buf, decimal, idx, seconds, nbytes) + const char *buf; + const char *decimal; + int *idx; + double *seconds; + size_t *nbytes; +{ + unsigned long ul; + long l; + double d, fract = 0; + char *cp, *ep; + debug_decl(parse_timing, SUDO_DEBUG_UTIL) + + /* Parse index */ + ul = strtoul(buf, &ep, 10); + if (ul > IOFD_MAX) + goto bad; + *idx = (int)ul; + for (cp = ep + 1; isspace((unsigned char) *cp); cp++) + continue; + + /* + * Parse number of seconds. Sudo logs timing data in the C locale + * but this may not match the current locale so we cannot use strtod(). + * Furthermore, sudo < 1.7.4 logged with the user's locale so we need + * to be able to parse those logs too. + */ + errno = 0; + l = strtol(cp, &ep, 10); + if ((errno == ERANGE && (l == LONG_MAX || l == LONG_MIN)) || + l < 0 || l > INT_MAX || + (*ep != '.' && strncmp(ep, decimal, strlen(decimal)) != 0)) { + goto bad; + } + *seconds = (double)l; + cp = ep + (*ep == '.' ? 1 : strlen(decimal)); + d = 10.0; + while (isdigit((unsigned char) *cp)) { + fract += (*cp - '0') / d; + d *= 10; + cp++; + } + *seconds += fract; + while (isspace((unsigned char) *cp)) + cp++; + + errno = 0; + ul = strtoul(cp, &ep, 10); + if (errno == ERANGE && ul == ULONG_MAX) + goto bad; + *nbytes = (size_t)ul; + + debug_return_int(1); +bad: + debug_return_int(0); +} + +static void +usage(int fatal) +{ + fprintf(fatal ? stderr : stdout, + _("usage: %s [-h] [-d directory] [-m max_wait] [-s speed_factor] ID\n"), + getprogname()); + fprintf(fatal ? stderr : stdout, + _("usage: %s [-h] [-d directory] -l [search expression]\n"), + getprogname()); + if (fatal) + exit(1); +} + +static void +help(void) +{ + (void) printf(_("%s - replay sudo session logs\n\n"), getprogname()); + usage(0); + (void) puts(_("\nOptions:\n" + " -d directory specify directory for session logs\n" + " -f filter specify which I/O type to display\n" + " -h display help message and exit\n" + " -l [expression] list available session IDs that match expression\n" + " -m max_wait max number of seconds to wait between events\n" + " -s speed_factor speed up or slow down output\n" + " -V display version information and exit")); + exit(0); +} + +/* + * Cleanup hook for error()/errorx() + */ +void +cleanup(int signo) +{ + term_restore(STDIN_FILENO, 0); + if (signo) + kill(getpid(), signo); +} diff --git a/plugins/sudoers/testsudoers.c b/plugins/sudoers/testsudoers.c new file mode 100644 index 0000000..d63ca92 --- /dev/null +++ b/plugins/sudoers/testsudoers.c @@ -0,0 +1,682 @@ +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#define _SUDO_MAIN + +#include + +#include +#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 */ +#ifdef HAVE_FNMATCH +# include +#else +# include "compat/fnmatch.h" +#endif /* HAVE_FNMATCH */ +#ifdef HAVE_NETGROUP_H +# include +#endif /* HAVE_NETGROUP_H */ +#include +#include +#include +#include +#include +#ifdef HAVE_SETLOCALE +# include +#endif + +#include "tsgetgrpw.h" +#include "sudoers.h" +#include "interfaces.h" +#include "parse.h" +#include "sudo_conf.h" +#include + +/* + * Function Prototypes + */ +int print_alias(void *, void *); +void dump_sudoers(void); +void print_defaults(void); +void print_privilege(struct privilege *); +void print_userspecs(void); +void usage(void) __attribute__((__noreturn__)); +void cleanup(int); +static void set_runaspw(const char *); +static void set_runasgr(const char *); +static int cb_runas_default(const char *); +static int testsudoers_printf(int msg_type, const char *fmt, ...); +static int testsudoers_print(const char *msg); + +extern void setgrfile(const char *); +extern void setgrent(void); +extern void endgrent(void); +extern struct group *getgrent(void); +extern struct group *getgrnam(const char *); +extern struct group *getgrgid(gid_t); +extern void setpwfile(const char *); +extern void setpwent(void); +extern void endpwent(void); +extern struct passwd *getpwent(void); +extern struct passwd *getpwnam(const char *); +extern struct passwd *getpwuid(uid_t); + +extern int (*trace_print)(const char *msg); + +/* + * Globals + */ +struct interface *interfaces; +struct sudo_user sudo_user; +struct passwd *list_pw; +static char *runas_group, *runas_user; +extern int errorlineno; +extern bool parse_error; +extern char *errorfile; +sudo_printf_t sudo_printf = testsudoers_printf; +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +/* For getopt(3) */ +extern char *optarg; +extern int optind; + +#if defined(SUDO_DEVEL) && defined(__OpenBSD__) +extern char *malloc_options; +#endif +#ifdef YYDEBUG +extern int yydebug; +#endif + +int +main(int argc, char *argv[]) +{ + struct cmndspec *cs; + struct privilege *priv; + struct userspec *us; + char *p, *grfile, *pwfile; + char hbuf[MAXHOSTNAMELEN + 1]; + int match, host_match, runas_match, cmnd_match; + int ch, dflag, exitcode = 0; + debug_decl(main, SUDO_DEBUG_MAIN) + +#if defined(SUDO_DEVEL) && defined(__OpenBSD__) + malloc_options = "AFGJPR"; +#endif +#ifdef YYDEBUG + yydebug = 1; +#endif + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + setprogname(argc > 0 ? argv[0] : "testsudoers"); +#endif + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have own domain */ + textdomain("sudoers"); + + /* Read sudo.conf. */ + sudo_conf_read(); + + dflag = 0; + grfile = pwfile = NULL; + while ((ch = getopt(argc, argv, "dg:G:h:p:tu:")) != -1) { + switch (ch) { + case 'd': + dflag = 1; + break; + case 'h': + user_host = optarg; + break; + case 'G': + grfile = optarg; + break; + case 'g': + runas_group = optarg; + break; + case 'p': + pwfile = optarg; + break; + case 't': + trace_print = testsudoers_print; + break; + case 'u': + runas_user = optarg; + break; + default: + usage(); + break; + } + } + argc -= optind; + argv += optind; + + /* Set group/passwd file and init the cache. */ + if (grfile) + setgrfile(grfile); + if (pwfile) + setpwfile(pwfile); + sudo_setpwent(); + sudo_setgrent(); + + if (argc < 2) { + if (!dflag) + usage(); + user_name = argc ? *argv++ : "root"; + user_cmnd = user_base = "true"; + argc = 0; + } else { + user_name = *argv++; + user_cmnd = *argv++; + if ((p = strrchr(user_cmnd, '/')) != NULL) + user_base = p + 1; + else + user_base = user_cmnd; + argc -= 2; + } + if ((sudo_user.pw = sudo_getpwnam(user_name)) == NULL) + errorx(1, _("unknown user: %s"), user_name); + + if (user_host == NULL) { + if (gethostname(hbuf, sizeof(hbuf)) != 0) + error(1, "gethostname"); + hbuf[sizeof(hbuf) - 1] = '\0'; + user_host = hbuf; + } + if ((p = strchr(user_host, '.'))) { + *p = '\0'; + user_shost = estrdup(user_host); + *p = '.'; + } else { + user_shost = user_host; + } + + /* Fill in user_args from argv. */ + if (argc > 0) { + char *to, **from; + size_t size, n; + + for (size = 0, from = argv; *from; from++) + size += strlen(*from) + 1; + + user_args = (char *) emalloc(size); + for (to = user_args, from = argv; *from; from++) { + n = strlcpy(to, *from, size - (to - user_args)); + if (n >= size - (to - user_args)) + errorx(1, _("internal error, init_vars() overflow")); + to += n; + *to++ = ' '; + } + *--to = '\0'; + } + + /* Initialize default values. */ + init_defaults(); + + /* Set runas callback. */ + sudo_defs_table[I_RUNAS_DEFAULT].callback = cb_runas_default; + + /* Load ip addr/mask for each interface. */ + if (get_net_ifs(&p) > 0) + set_interfaces(p); + + /* Allocate space for data structures in the parser. */ + init_parser("sudoers", 0); + + if (yyparse() != 0 || parse_error) { + parse_error = true; + if (errorlineno != -1) + (void) printf("Parse error in %s near line %d", + errorfile, errorlineno); + else + (void) printf("Parse error in %s", errorfile); + } else { + (void) fputs("Parses OK", stdout); + } + + if (!update_defaults(SETDEF_ALL)) + (void) fputs(" (problem with defaults entries)", stdout); + puts("."); + + if (def_group_plugin && group_plugin_load(def_group_plugin) != true) + def_group_plugin = NULL; + + /* + * Set runas passwd/group entries based on command line or sudoers. + * Note that if runas_group was specified without runas_user we + * defer setting runas_pw so the match routines know to ignore it. + */ + if (runas_group != NULL) { + set_runasgr(runas_group); + if (runas_user != NULL) + set_runaspw(runas_user); + } else + set_runaspw(runas_user ? runas_user : def_runas_default); + + if (dflag) { + (void) putchar('\n'); + dump_sudoers(); + if (argc < 2) { + exitcode = parse_error ? 1 : 0; + goto done; + } + } + + /* This loop must match the one in sudo_file_lookup() */ + printf("\nEntries for user %s:\n", user_name); + match = UNSPEC; + tq_foreach_rev(&userspecs, us) { + if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) + continue; + tq_foreach_rev(&us->privileges, priv) { + putchar('\n'); + print_privilege(priv); /* XXX */ + putchar('\n'); + host_match = hostlist_matches(&priv->hostlist); + if (host_match == ALLOW) { + puts("\thost matched"); + tq_foreach_rev(&priv->cmndlist, cs) { + runas_match = runaslist_matches(&cs->runasuserlist, + &cs->runasgrouplist); + if (runas_match == ALLOW) { + puts("\trunas matched"); + cmnd_match = cmnd_matches(cs->cmnd); + if (cmnd_match != UNSPEC) + match = cmnd_match; + printf("\tcmnd %s\n", match == ALLOW ? "allowed" : + match == DENY ? "denied" : "unmatched"); + } + } + } else + puts(_("\thost unmatched")); + } + } + puts(match == ALLOW ? _("\nCommand allowed") : + match == DENY ? _("\nCommand denied") : _("\nCommand unmatched")); + + /* + * Exit codes: + * 0 - parsed OK and command matched. + * 1 - parse error + * 2 - command not matched + * 3 - command denied + */ + exitcode = parse_error ? 1 : (match == ALLOW ? 0 : match + 3); +done: + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); + exit(exitcode); +} + +static void +set_runaspw(const char *user) +{ + debug_decl(main, SUDO_DEBUG_UTIL) + + if (runas_pw != NULL) + pw_delref(runas_pw); + if (*user == '#') { + if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) + runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); + } else { + if ((runas_pw = sudo_getpwnam(user)) == NULL) + errorx(1, _("unknown user: %s"), user); + } + + debug_return; +} + +static void +set_runasgr(const char *group) +{ + debug_decl(main, SUDO_DEBUG_UTIL) + + if (runas_gr != NULL) + gr_delref(runas_gr); + if (*group == '#') { + if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) + runas_gr = sudo_fakegrnam(group); + } else { + if ((runas_gr = sudo_getgrnam(group)) == NULL) + errorx(1, _("unknown group: %s"), group); + } + + debug_return; +} + +/* + * Callback for runas_default sudoers setting. + */ +static int +cb_runas_default(const char *user) +{ + /* Only reset runaspw if user didn't specify one. */ + if (!runas_user && !runas_group) + set_runaspw(user); + return true; +} + +void +sudo_setspent(void) +{ + return; +} + +void +sudo_endspent(void) +{ + return; +} + +void +set_fqdn(void) +{ + return; +} + +FILE * +open_sudoers(const char *path, bool doedit, bool *keepopen) +{ + debug_decl(open_sudoers, SUDO_DEBUG_UTIL) + + debug_return_ptr(fopen(path, "r")); +} + +void +init_envtables(void) +{ + return; +} + +int +set_perms(int perm) +{ + return 1; +} + +void +restore_perms(void) +{ +} + +void +cleanup(int gotsignal) +{ + if (!gotsignal) { + sudo_endpwent(); + sudo_endgrent(); + } +} + +void +print_member(struct member *m) +{ + struct sudo_command *c; + debug_decl(print_member, SUDO_DEBUG_UTIL) + + if (m->negated) + putchar('!'); + if (m->name == NULL) + fputs("ALL", stdout); + else if (m->type != COMMAND) + fputs(m->name, stdout); + else { + c = (struct sudo_command *) m->name; + printf("%s%s%s", c->cmnd, c->args ? " " : "", + c->args ? c->args : ""); + } + + debug_return; +} + +void +print_defaults(void) +{ + struct defaults *d; + struct member *m; + debug_decl(print_member, SUDO_DEBUG_UTIL) + + tq_foreach_fwd(&defaults, d) { + (void) fputs("Defaults", stdout); + switch (d->type) { + case DEFAULTS_HOST: + putchar('@'); + break; + case DEFAULTS_USER: + putchar(':'); + break; + case DEFAULTS_RUNAS: + putchar('>'); + break; + case DEFAULTS_CMND: + putchar('!'); + break; + } + tq_foreach_fwd(&d->binding, m) { + if (m != tq_first(&d->binding)) + putchar(','); + print_member(m); + } + printf("\t%s%s", d->op == false ? "!" : "", d->var); + if (d->val != NULL) { + printf("%c%s", d->op == true ? '=' : d->op, d->val); + } + putchar('\n'); + } + + debug_return; +} + +int +print_alias(void *v1, void *v2) +{ + struct alias *a = (struct alias *)v1; + struct member *m; + struct sudo_command *c; + debug_decl(print_alias, SUDO_DEBUG_UTIL) + + switch (a->type) { + case HOSTALIAS: + (void) printf("Host_Alias\t%s = ", a->name); + break; + case CMNDALIAS: + (void) printf("Cmnd_Alias\t%s = ", a->name); + break; + case USERALIAS: + (void) printf("User_Alias\t%s = ", a->name); + break; + case RUNASALIAS: + (void) printf("Runas_Alias\t%s = ", a->name); + break; + } + tq_foreach_fwd(&a->members, m) { + if (m != tq_first(&a->members)) + fputs(", ", stdout); + if (m->type == COMMAND) { + c = (struct sudo_command *) m->name; + printf("%s%s%s", c->cmnd, c->args ? " " : "", + c->args ? c->args : ""); + } else if (m->type == ALL) { + fputs("ALL", stdout); + } else { + fputs(m->name, stdout); + } + } + putchar('\n'); + debug_return_int(0); +} + +void +print_privilege(struct privilege *priv) +{ + struct cmndspec *cs; + struct member *m; + struct privilege *p; + struct cmndtag tags; + debug_decl(print_privilege, SUDO_DEBUG_UTIL) + + for (p = priv; p != NULL; p = p->next) { + if (p != priv) + fputs(" : ", stdout); + tq_foreach_fwd(&p->hostlist, m) { + if (m != tq_first(&p->hostlist)) + fputs(", ", stdout); + print_member(m); + } + fputs(" = ", stdout); + tags.nopasswd = tags.noexec = UNSPEC; + tq_foreach_fwd(&p->cmndlist, cs) { + if (cs != tq_first(&p->cmndlist)) + fputs(", ", stdout); + if (!tq_empty(&cs->runasuserlist) || !tq_empty(&cs->runasgrouplist)) { + fputs("(", stdout); + if (!tq_empty(&cs->runasuserlist)) { + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m != tq_first(&cs->runasuserlist)) + fputs(", ", stdout); + print_member(m); + } + } else if (tq_empty(&cs->runasgrouplist)) { + fputs(def_runas_default, stdout); + } else { + fputs(sudo_user.pw->pw_name, stdout); + } + if (!tq_empty(&cs->runasgrouplist)) { + fputs(" : ", stdout); + tq_foreach_fwd(&cs->runasgrouplist, m) { + if (m != tq_first(&cs->runasgrouplist)) + fputs(", ", stdout); + print_member(m); + } + } + fputs(") ", stdout); + } +#ifdef HAVE_SELINUX + if (cs->role) + printf("ROLE=%s ", cs->role); + if (cs->type) + printf("TYPE=%s ", cs->type); +#endif /* HAVE_SELINUX */ + if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd) + printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : ""); + if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec) + printf("%sEXEC: ", cs->tags.noexec ? "NO" : ""); + print_member(cs->cmnd); + memcpy(&tags, &cs->tags, sizeof(tags)); + } + } + debug_return; +} + +void +print_userspecs(void) +{ + struct member *m; + struct userspec *us; + debug_decl(print_userspecs, SUDO_DEBUG_UTIL) + + tq_foreach_fwd(&userspecs, us) { + tq_foreach_fwd(&us->users, m) { + if (m != tq_first(&us->users)) + fputs(", ", stdout); + print_member(m); + } + putchar('\t'); + print_privilege(us->privileges.first); /* XXX */ + putchar('\n'); + } + debug_return; +} + +static int +testsudoers_printf(int msg_type, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + debug_decl(testsudoers_printf, SUDO_DEBUG_UTIL) + + switch (msg_type) { + case SUDO_CONV_INFO_MSG: + fp = stdout; + break; + case SUDO_CONV_ERROR_MSG: + fp = stderr; + break; + default: + errno = EINVAL; + debug_return_int(-1); + } + + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); + + debug_return_int(0); +} + +void +dump_sudoers(void) +{ + debug_decl(dump_sudoers, SUDO_DEBUG_UTIL) + + print_defaults(); + + putchar('\n'); + alias_apply(print_alias, NULL); + + putchar('\n'); + print_userspecs(); + + debug_return; +} + +static int testsudoers_print(const char *msg) +{ + return fputs(msg, stderr); +} + +void +usage(void) +{ + (void) fprintf(stderr, "usage: %s [-dt] [-G grfile] [-g group] [-h host] [-p pwfile] [-u user] [args]\n", getprogname()); + exit(1); +} diff --git a/plugins/sudoers/timestr.c b/plugins/sudoers/timestr.c new file mode 100644 index 0000000..b2df41b --- /dev/null +++ b/plugins/sudoers/timestr.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1999, 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#include + +#include "missing.h" + +char *get_timestr(time_t, int); + +/* + * Return an ascii string with the current date + time + * Uses strftime() if available, else falls back to ctime(). + */ +char * +get_timestr(time_t tstamp, int log_year) +{ + char *s; +#ifdef HAVE_STRFTIME + static char buf[128]; + struct tm *timeptr; + + timeptr = localtime(&tstamp); + if (log_year) + s = "%h %e %T %Y"; + else + s = "%h %e %T"; + + /* strftime() does not guarantee to NUL-terminate so we must check. */ + buf[sizeof(buf) - 1] = '\0'; + if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0') + return buf; + +#endif /* HAVE_STRFTIME */ + + s = ctime(&tstamp) + 4; /* skip day of the week */ + if (log_year) + s[20] = '\0'; /* avoid the newline */ + else + s[15] = '\0'; /* don't care about year */ + + return s; +} diff --git a/plugins/sudoers/toke.c b/plugins/sudoers/toke.c new file mode 100644 index 0000000..40bc147 --- /dev/null +++ b/plugins/sudoers/toke.c @@ -0,0 +1,3736 @@ +#include +/* $OpenBSD: flex.skl,v 1.11 2010/08/04 18:24:50 millert Exp $ */ + +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /cvs/src/usr.bin/lex/flex.skl,v 1.11 2010/08/04 18:24:50 millert Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#ifdef __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + + +#define yywrap() 1 +#define YY_SKIP_YYWRAP +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 59 +#define YY_END_OF_BUFFER 60 +static yyconst short int yy_accept[607] = + { 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 60, 47, 55, 54, 53, 46, 58, 32, + 48, 49, 32, 50, 47, 47, 47, 47, 52, 51, + 58, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 58, 47, 47, 55, 58, 42, 42, 42, 42, + 42, 2, 58, 1, 47, 47, 17, 16, 17, 16, + 16, 58, 58, 58, 3, 9, 8, 9, 4, 9, + 5, 58, 13, 13, 13, 11, 12, 47, 0, 55, + 53, 0, 57, 0, 47, 34, 0, 32, 0, 33, + 0, 45, 45, 0, 47, 47, 0, 47, 47, 47, + + 47, 0, 37, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 47, 56, 47, 55, 0, 0, 0, + 0, 0, 0, 47, 47, 47, 47, 47, 2, 1, + 0, 1, 43, 43, 0, 47, 17, 17, 15, 14, + 15, 0, 0, 3, 9, 0, 6, 7, 9, 9, + 13, 0, 13, 13, 0, 10, 0, 0, 0, 34, + 34, 0, 0, 47, 47, 47, 47, 47, 0, 0, + 37, 37, 42, 39, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 47, 0, 0, 0, 0, 0, + 0, 47, 47, 47, 47, 47, 0, 47, 10, 0, + + 47, 47, 47, 47, 47, 47, 0, 38, 38, 38, + 0, 0, 37, 37, 37, 37, 37, 37, 37, 42, + 42, 42, 42, 42, 42, 42, 42, 40, 42, 41, + 47, 0, 0, 0, 0, 0, 0, 47, 47, 47, + 47, 47, 47, 47, 0, 0, 38, 38, 38, 0, + 37, 37, 0, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 0, 25, 42, 42, 42, 42, + 42, 42, 42, 42, 47, 0, 0, 0, 0, 47, + 47, 47, 47, 47, 47, 47, 47, 0, 38, 0, + 37, 37, 37, 0, 0, 0, 37, 37, 37, 37, + + 37, 37, 37, 37, 37, 37, 37, 37, 37, 42, + 42, 42, 42, 42, 42, 42, 42, 47, 0, 0, + 0, 47, 47, 47, 35, 35, 35, 0, 0, 37, + 37, 37, 37, 37, 37, 37, 0, 0, 0, 0, + 0, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 42, 42, 0, 24, 42, + 42, 42, 42, 0, 23, 0, 26, 47, 0, 0, + 0, 47, 47, 47, 47, 35, 35, 35, 35, 0, + 37, 0, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 0, 0, 0, 37, 37, 37, 37, + + 37, 37, 37, 37, 37, 37, 37, 37, 37, 42, + 42, 42, 42, 42, 42, 44, 0, 0, 0, 47, + 20, 43, 36, 36, 36, 36, 37, 0, 0, 0, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 0, 0, 0, 0, 0, 37, 37, + 37, 37, 37, 37, 37, 37, 42, 42, 42, 42, + 0, 22, 0, 27, 0, 20, 0, 0, 47, 0, + 47, 47, 47, 36, 36, 36, 36, 0, 0, 0, + 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + + 37, 37, 0, 30, 42, 42, 42, 0, 0, 0, + 18, 0, 21, 20, 0, 0, 0, 0, 0, 20, + 0, 47, 47, 47, 0, 0, 0, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 0, 28, 42, 42, 21, + 0, 0, 20, 47, 47, 47, 47, 47, 0, 0, + 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, + 37, 0, 31, 42, 0, 47, 47, 47, 37, 37, + 37, 37, 37, 37, 0, 29, 0, 0, 19, 47, + 47, 47, 47, 47, 37, 37, 37, 37, 37, 35, + + 35, 35, 35, 35, 35, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 7, 1, 1, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 22, 22, 23, 24, 1, 1, + 25, 26, 10, 27, 28, 29, 30, 31, 32, 29, + 33, 34, 35, 36, 36, 37, 36, 38, 39, 40, + 36, 41, 42, 43, 44, 45, 46, 47, 48, 36, + 10, 49, 10, 1, 50, 1, 51, 52, 53, 54, + + 55, 56, 57, 57, 58, 57, 57, 59, 60, 61, + 62, 57, 57, 63, 64, 65, 66, 57, 57, 57, + 57, 57, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[67] = + { 0, + 1, 2, 3, 4, 5, 6, 1, 7, 7, 1, + 1, 8, 1, 9, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 13, 7, 1, 11, 11, 11, + 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 14, 15, + 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15 + } ; + +static yyconst short int yy_base[671] = + { 0, + 0, 65, 67, 72, 99, 114, 162, 227, 292, 340, + 86, 125, 2840, 2790, 2836, 3665, 2833, 3665, 387, 70, + 3665, 3665, 2771, 3665, 136, 397, 133, 159, 2795, 3665, + 3665, 453, 2781, 33, 504, 2770, 2767, 2777, 2765, 2771, + 2754, 559, 170, 19, 165, 583, 38, 49, 2739, 68, + 2727, 81, 219, 2771, 305, 48, 0, 3665, 2761, 3665, + 0, 250, 639, 119, 0, 2709, 3665, 108, 3665, 112, + 3665, 140, 2699, 98, 121, 3665, 195, 2693, 661, 2739, + 2736, 2736, 3665, 227, 247, 300, 316, 152, 354, 2681, + 686, 373, 2670, 711, 352, 722, 2692, 2669, 375, 414, + + 302, 2656, 57, 763, 0, 2628, 2625, 2614, 505, 2602, + 2606, 2599, 2601, 202, 3665, 153, 546, 2572, 2565, 2549, + 2537, 2524, 200, 110, 244, 28, 111, 252, 171, 2578, + 422, 2577, 565, 2529, 818, 262, 0, 2573, 179, 3665, + 3665, 599, 269, 0, 2513, 453, 3665, 3665, 2512, 548, + 2490, 2533, 206, 253, 323, 2535, 2524, 2513, 607, 615, + 306, 722, 586, 831, 867, 903, 939, 2499, 2456, 980, + 333, 1022, 1063, 0, 2430, 2394, 2363, 2364, 2374, 2369, + 2327, 2330, 2329, 2328, 266, 2289, 2283, 2272, 2274, 2279, + 409, 334, 2279, 145, 335, 83, 672, 278, 2327, 2325, + + 627, 259, 1106, 1142, 741, 210, 2293, 2279, 683, 513, + 2275, 2271, 352, 747, 1178, 780, 788, 1220, 815, 2270, + 400, 325, 2261, 2258, 2248, 2246, 2242, 0, 2240, 0, + 489, 2223, 2213, 2198, 2211, 2198, 420, 407, 529, 490, + 491, 1263, 1299, 1335, 2235, 2234, 839, 2234, 2232, 2228, + 2226, 528, 848, 657, 856, 665, 1371, 0, 877, 1382, + 886, 894, 1424, 913, 570, 3665, 2208, 2197, 2201, 2178, + 2185, 2194, 2194, 2176, 558, 2169, 2152, 2150, 648, 626, + 530, 559, 923, 336, 1467, 1503, 964, 2171, 2140, 2139, + 2138, 1537, 551, 1000, 1041, 1082, 653, 694, 797, 1049, + + 923, 1580, 0, 1116, 1591, 1090, 1008, 1633, 1125, 2121, + 2082, 747, 686, 2064, 2071, 786, 926, 905, 2080, 2033, + 679, 634, 544, 915, 1675, 1710, 1745, 2052, 2043, 2033, + 1150, 1781, 1158, 1133, 1822, 1197, 1166, 2028, 1239, 1273, + 1207, 950, 951, 962, 991, 1247, 1073, 1865, 0, 1283, + 1876, 1307, 1315, 1918, 1323, 1987, 1968, 1188, 3665, 1967, + 1951, 1929, 1913, 1286, 3665, 1336, 3665, 707, 1897, 1889, + 786, 930, 764, 1298, 1358, 1041, 1960, 1995, 1400, 1927, + 1879, 1348, 708, 1406, 1348, 2031, 0, 559, 2042, 1441, + 1449, 2083, 1477, 1487, 1513, 1523, 1230, 1290, 1458, 1548, + + 1557, 1602, 2126, 0, 1613, 2137, 1650, 1565, 1660, 1806, + 1779, 1680, 1675, 1359, 1406, 1626, 1601, 1577, 897, 938, + 1695, 1589, 2180, 2216, 2252, 2288, 1611, 1686, 1720, 1731, + 1563, 1478, 1504, 1694, 1524, 2324, 0, 617, 2335, 1753, + 1761, 2376, 1769, 1798, 1550, 1808, 1841, 1851, 1335, 1358, + 1887, 714, 825, 2419, 0, 926, 1407, 1468, 1430, 1431, + 1547, 3665, 1616, 3665, 1381, 1731, 1045, 1512, 1575, 1908, + 1913, 1970, 1498, 2429, 2465, 1947, 1611, 1981, 1264, 2006, + 2016, 2061, 1198, 1181, 1732, 1782, 2067, 1842, 2501, 0, + 1181, 2512, 2100, 1904, 2553, 2110, 2155, 2164, 2189, 1769, + + 1142, 1232, 1634, 3665, 1699, 1095, 1077, 1025, 1046, 1306, + 3665, 384, 981, 2211, 2218, 2238, 2243, 2263, 2288, 2249, + 2307, 2596, 2632, 2668, 2304, 2354, 2395, 983, 894, 1902, + 1928, 2362, 1929, 2704, 0, 1428, 2715, 2403, 2437, 2445, + 867, 2454, 2474, 2483, 831, 1982, 3665, 1983, 782, 3665, + 1511, 2489, 2529, 2537, 1895, 2758, 2794, 2573, 2579, 650, + 2607, 2617, 2642, 629, 525, 1931, 447, 347, 2650, 0, + 1528, 2019, 3665, 2044, 1805, 2830, 2866, 2902, 2676, 2684, + 2692, 323, 0, 316, 2067, 3665, 166, 1845, 3665, 2733, + 1945, 2938, 2974, 2743, 3665, 2767, 2777, 2658, 3665, 2805, + + 2813, 2847, 63, 2855, 2881, 3665, 3023, 3039, 3055, 3071, + 3087, 3103, 3119, 3135, 3151, 3157, 3173, 3189, 2025, 3205, + 3221, 3237, 3253, 3269, 3285, 3301, 3307, 3314, 3330, 3346, + 3352, 3359, 3365, 3371, 3377, 3384, 3390, 3396, 3402, 3409, + 3417, 3423, 3429, 3435, 3442, 3450, 3456, 3462, 3469, 3477, + 3483, 3491, 3498, 3506, 3512, 3520, 3527, 3535, 3551, 3567, + 3583, 3589, 3597, 3604, 3610, 3618, 3624, 3632, 3648, 1295 + } ; + +static yyconst short int yy_def[671] = + { 0, + 606, 1, 1, 1, 607, 607, 608, 608, 609, 609, + 610, 610, 606, 611, 606, 606, 606, 606, 612, 613, + 606, 606, 614, 606, 615, 611, 26, 26, 616, 606, + 606, 606, 32, 32, 32, 35, 35, 35, 35, 35, + 35, 611, 26, 611, 606, 612, 32, 32, 35, 35, + 35, 606, 606, 606, 617, 611, 618, 606, 618, 606, + 618, 606, 612, 606, 619, 620, 606, 620, 606, 620, + 606, 621, 622, 622, 622, 606, 606, 611, 611, 606, + 606, 623, 606, 624, 606, 613, 606, 625, 613, 614, + 614, 615, 626, 611, 611, 26, 616, 96, 96, 96, + + 96, 627, 628, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 611, 606, 611, 606, 606, 606, 606, + 606, 606, 623, 611, 96, 611, 611, 611, 606, 606, + 606, 606, 617, 629, 611, 611, 618, 618, 606, 606, + 606, 624, 606, 619, 620, 620, 606, 606, 620, 620, + 622, 606, 622, 622, 606, 606, 623, 630, 606, 606, + 625, 625, 606, 611, 611, 611, 96, 167, 631, 606, + 632, 606, 104, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 611, 606, 606, 606, 606, 606, + 623, 611, 167, 611, 611, 611, 606, 611, 606, 630, + + 611, 611, 611, 611, 611, 611, 633, 634, 634, 209, + 635, 634, 636, 172, 606, 215, 215, 606, 215, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 611, 606, 606, 606, 606, 606, 623, 611, 611, 611, + 611, 611, 611, 611, 606, 637, 637, 247, 637, 638, + 639, 640, 606, 641, 218, 641, 641, 257, 641, 606, + 260, 260, 606, 260, 606, 606, 35, 35, 35, 35, + 35, 35, 35, 35, 611, 606, 606, 606, 623, 611, + 611, 611, 611, 611, 611, 611, 611, 642, 642, 643, + 644, 606, 606, 606, 606, 606, 645, 645, 646, 263, + + 646, 646, 302, 646, 606, 305, 305, 606, 305, 35, + 35, 35, 35, 35, 35, 35, 35, 611, 606, 606, + 623, 611, 611, 611, 611, 611, 611, 606, 647, 648, + 292, 606, 332, 332, 606, 332, 606, 606, 606, 606, + 606, 606, 649, 649, 650, 308, 650, 650, 348, 650, + 606, 351, 351, 606, 351, 35, 35, 606, 606, 35, + 35, 35, 35, 606, 606, 606, 606, 611, 606, 606, + 623, 611, 611, 611, 611, 611, 611, 611, 611, 606, + 651, 606, 652, 335, 652, 652, 386, 386, 606, 389, + 389, 606, 389, 606, 606, 606, 606, 653, 653, 654, + + 354, 654, 654, 403, 654, 606, 406, 406, 406, 35, + 35, 35, 35, 35, 35, 611, 606, 606, 623, 611, + 611, 611, 611, 611, 611, 611, 606, 606, 606, 606, + 655, 655, 656, 392, 656, 656, 436, 436, 606, 439, + 439, 606, 439, 606, 606, 606, 606, 606, 606, 657, + 657, 658, 658, 658, 454, 454, 35, 35, 35, 35, + 606, 606, 606, 606, 606, 606, 659, 623, 611, 660, + 661, 611, 611, 611, 611, 611, 611, 606, 606, 606, + 606, 606, 606, 662, 662, 663, 442, 663, 663, 489, + 489, 606, 492, 492, 606, 492, 606, 606, 606, 606, + + 664, 664, 606, 606, 35, 35, 35, 606, 659, 659, + 606, 623, 611, 660, 660, 660, 660, 606, 660, 661, + 661, 611, 611, 611, 606, 606, 606, 606, 665, 665, + 666, 495, 666, 666, 534, 534, 606, 537, 537, 537, + 606, 606, 606, 606, 606, 606, 606, 35, 35, 606, + 623, 606, 606, 611, 611, 611, 611, 611, 606, 606, + 606, 606, 606, 606, 667, 667, 668, 668, 668, 569, + 569, 606, 606, 35, 669, 611, 611, 611, 606, 606, + 606, 606, 670, 670, 606, 606, 669, 669, 606, 611, + 611, 611, 611, 611, 606, 606, 606, 606, 606, 611, + + 611, 611, 611, 611, 611, 0, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606 + } ; + +static yyconst short int yy_nxt[3732] = + { 0, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 14, + 23, 24, 14, 14, 25, 26, 27, 28, 26, 26, + 26, 26, 26, 29, 30, 31, 14, 32, 33, 33, + 33, 34, 35, 35, 35, 35, 36, 37, 35, 38, + 39, 40, 41, 35, 35, 35, 35, 35, 42, 14, + 43, 43, 43, 43, 43, 43, 14, 14, 14, 14, + 14, 14, 14, 44, 14, 14, 45, 79, 52, 105, + 46, 170, 53, 52, 105, 87, 79, 53, 54, 107, + 172, 55, 129, 54, 116, 105, 55, 74, 16, 75, + 76, 194, 130, 88, 47, 48, 79, 124, 49, 153, + + 15, 58, 59, 125, 60, 50, 111, 35, 51, 35, + 60, 79, 35, 136, 35, 15, 58, 59, 89, 60, + 143, 115, 60, 61, 154, 60, 74, 16, 75, 76, + 56, 79, 147, 127, 77, 56, 148, 60, 61, 93, + 93, 150, 115, 93, 93, 238, 152, 62, 99, 99, + 99, 99, 99, 99, 99, 99, 146, 87, 79, 79, + 146, 93, 62, 15, 16, 17, 117, 63, 589, 152, + 192, 195, 129, 77, 100, 100, 100, 100, 100, 101, + 143, 115, 130, 78, 94, 98, 98, 98, 98, 98, + 98, 98, 98, 79, 118, 119, 155, 156, 120, 151, + + 162, 79, 83, 143, 115, 121, 185, 153, 122, 238, + 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 15, 16, + 17, 131, 63, 97, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 79, 139, 115, 140, 152, 141, 154, 78, 79, 140, + 191, 141, 85, 85, 85, 85, 85, 85, 85, 85, + 143, 115, 201, 141, 141, 64, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 15, 16, 17, 67, 63, 141, 193, + + 79, 152, 68, 69, 70, 606, 196, 79, 134, 134, + 79, 606, 134, 134, 79, 198, 71, 168, 168, 168, + 168, 168, 168, 606, 155, 156, 79, 231, 159, 382, + 134, 160, 160, 160, 160, 160, 160, 160, 160, 241, + 72, 15, 16, 17, 67, 63, 532, 170, 89, 283, + 68, 69, 70, 135, 162, 86, 214, 86, 86, 267, + 606, 86, 86, 268, 71, 86, 170, 164, 165, 166, + 164, 164, 164, 164, 164, 214, 93, 93, 86, 86, + 93, 93, 79, 79, 79, 240, 83, 238, 72, 83, + 168, 168, 168, 168, 168, 168, 168, 168, 93, 84, + + 79, 265, 85, 85, 85, 85, 85, 85, 85, 85, + 95, 83, 96, 96, 96, 96, 96, 96, 96, 96, + 97, 94, 83, 266, 98, 98, 98, 98, 98, 168, + 168, 168, 168, 168, 168, 168, 168, 85, 85, 85, + 85, 85, 85, 85, 85, 79, 551, 98, 98, 98, + 98, 98, 98, 78, 145, 79, 280, 145, 145, 78, + 382, 237, 78, 78, 145, 78, 78, 78, 104, 104, + 104, 104, 104, 104, 104, 104, 97, 145, 279, 78, + 104, 104, 104, 104, 104, 105, 105, 105, 105, 106, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + + 105, 79, 105, 98, 98, 98, 98, 98, 98, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 105, + 105, 105, 105, 105, 105, 105, 105, 606, 249, 249, + 249, 105, 105, 105, 105, 105, 177, 79, 79, 79, + 105, 178, 170, 275, 179, 282, 180, 117, 532, 143, + 115, 214, 97, 238, 78, 78, 78, 78, 78, 78, + 114, 115, 78, 78, 78, 170, 78, 78, 134, 134, + 78, 265, 134, 134, 214, 118, 119, 79, 79, 120, + 431, 431, 78, 78, 78, 83, 121, 93, 323, 122, + 134, 93, 79, 266, 281, 84, 146, 93, 85, 85, + + 85, 85, 85, 85, 85, 85, 79, 79, 373, 93, + 93, 318, 324, 135, 606, 606, 606, 606, 606, 606, + 606, 606, 160, 160, 160, 160, 160, 160, 160, 160, + 160, 160, 160, 160, 160, 160, 160, 160, 484, 484, + 123, 83, 242, 243, 244, 242, 242, 242, 242, 242, + 83, 142, 487, 322, 606, 606, 606, 606, 606, 606, + 606, 606, 78, 559, 78, 78, 78, 170, 78, 78, + 253, 170, 78, 134, 79, 79, 255, 134, 606, 170, + 255, 83, 79, 134, 78, 78, 78, 90, 255, 90, + 90, 90, 372, 90, 90, 134, 134, 90, 247, 247, + + 248, 249, 249, 249, 249, 249, 211, 253, 170, 90, + 90, 90, 92, 321, 78, 78, 92, 255, 78, 78, + 360, 382, 92, 161, 361, 161, 161, 253, 170, 161, + 161, 384, 371, 161, 92, 92, 78, 167, 167, 167, + 167, 167, 167, 167, 167, 161, 161, 161, 358, 167, + 167, 167, 167, 167, 201, 79, 202, 202, 202, 202, + 202, 202, 219, 219, 219, 219, 219, 219, 219, 219, + 359, 416, 167, 167, 167, 167, 167, 167, 173, 173, + 173, 173, 173, 173, 173, 173, 97, 364, 83, 79, + 173, 173, 173, 173, 173, 257, 257, 257, 257, 257, + + 257, 257, 257, 258, 258, 258, 258, 258, 259, 365, + 253, 170, 79, 167, 167, 167, 167, 167, 167, 133, + 300, 78, 78, 133, 574, 78, 78, 421, 606, 133, + 256, 256, 256, 256, 256, 256, 256, 256, 606, 170, + 419, 133, 133, 78, 201, 170, 202, 202, 202, 202, + 202, 202, 202, 202, 289, 289, 289, 289, 289, 289, + 289, 289, 211, 294, 295, 296, 294, 294, 294, 294, + 294, 264, 264, 264, 264, 264, 264, 264, 264, 79, + 201, 170, 203, 203, 203, 203, 203, 203, 203, 203, + 253, 170, 298, 298, 298, 298, 298, 298, 467, 83, + + 255, 302, 302, 302, 302, 302, 302, 302, 302, 303, + 303, 303, 303, 303, 304, 79, 201, 487, 204, 204, + 204, 204, 204, 205, 202, 202, 606, 366, 301, 301, + 301, 301, 301, 301, 301, 301, 606, 170, 325, 326, + 327, 325, 325, 325, 325, 325, 300, 501, 501, 367, + 468, 79, 78, 79, 206, 206, 206, 206, 206, 206, + 206, 206, 368, 79, 170, 170, 206, 206, 206, 206, + 206, 79, 374, 255, 300, 253, 170, 283, 79, 284, + 284, 284, 284, 284, 284, 300, 79, 420, 469, 206, + 206, 206, 206, 206, 206, 208, 209, 210, 210, 210, + + 210, 210, 210, 211, 253, 170, 434, 212, 212, 212, + 212, 212, 79, 337, 346, 338, 338, 338, 338, 338, + 338, 338, 338, 349, 349, 349, 349, 349, 350, 79, + 212, 212, 212, 212, 212, 212, 170, 215, 216, 217, + 215, 215, 215, 215, 215, 218, 510, 511, 511, 219, + 219, 219, 219, 219, 337, 375, 339, 339, 339, 339, + 339, 339, 339, 339, 309, 309, 309, 309, 309, 309, + 309, 309, 219, 219, 219, 219, 219, 219, 220, 220, + 220, 220, 220, 220, 220, 220, 606, 170, 550, 79, + 220, 220, 220, 220, 220, 337, 346, 340, 340, 340, + + 340, 340, 341, 338, 338, 348, 348, 348, 348, 348, + 348, 348, 348, 206, 206, 206, 206, 206, 206, 201, + 549, 202, 202, 202, 202, 202, 202, 202, 202, 253, + 170, 344, 344, 344, 344, 344, 344, 548, 606, 300, + 347, 347, 347, 347, 347, 347, 347, 347, 387, 387, + 387, 387, 387, 388, 79, 201, 170, 202, 202, 202, + 202, 202, 202, 202, 202, 336, 336, 336, 336, 336, + 336, 336, 336, 386, 386, 386, 386, 386, 386, 386, + 386, 394, 395, 396, 394, 394, 394, 394, 394, 358, + 79, 253, 170, 254, 254, 254, 254, 254, 254, 254, + + 254, 255, 529, 529, 434, 256, 256, 256, 256, 256, + 606, 359, 385, 385, 385, 385, 385, 385, 385, 385, + 337, 384, 338, 338, 338, 338, 338, 338, 256, 256, + 256, 256, 256, 256, 170, 260, 261, 262, 260, 260, + 260, 260, 260, 263, 170, 253, 170, 264, 264, 264, + 264, 264, 337, 300, 338, 338, 338, 338, 338, 338, + 338, 338, 355, 355, 355, 355, 355, 355, 355, 355, + 264, 264, 264, 264, 264, 264, 283, 478, 284, 284, + 284, 284, 284, 284, 284, 284, 337, 364, 338, 338, + 338, 338, 338, 338, 338, 338, 253, 170, 399, 399, + + 399, 399, 399, 399, 170, 599, 346, 510, 511, 365, + 599, 79, 283, 346, 285, 285, 285, 285, 285, 285, + 285, 285, 403, 403, 403, 403, 403, 403, 403, 403, + 404, 404, 404, 404, 404, 405, 606, 366, 402, 402, + 402, 402, 402, 402, 402, 402, 79, 79, 283, 170, + 286, 286, 286, 286, 286, 287, 284, 284, 346, 367, + 461, 606, 422, 428, 429, 430, 428, 428, 428, 428, + 428, 384, 170, 423, 424, 425, 426, 423, 423, 423, + 423, 401, 462, 79, 253, 170, 298, 298, 298, 298, + 298, 298, 298, 298, 255, 253, 170, 299, 299, 299, + + 299, 299, 299, 299, 299, 300, 79, 463, 503, 301, + 301, 301, 301, 301, 375, 376, 376, 376, 376, 376, + 376, 393, 393, 393, 393, 393, 393, 393, 393, 464, + 504, 508, 301, 301, 301, 301, 301, 301, 170, 305, + 306, 307, 305, 305, 305, 305, 305, 308, 79, 565, + 565, 309, 309, 309, 309, 309, 436, 436, 436, 436, + 436, 436, 436, 436, 437, 437, 437, 437, 437, 438, + 507, 253, 170, 506, 309, 309, 309, 309, 309, 309, + 283, 346, 284, 284, 284, 284, 284, 284, 284, 284, + 606, 382, 435, 435, 435, 435, 435, 435, 435, 435, + + 444, 384, 445, 445, 445, 445, 445, 445, 445, 445, + 505, 472, 575, 83, 83, 79, 283, 382, 284, 284, + 284, 284, 284, 284, 284, 284, 444, 434, 446, 446, + 446, 446, 446, 446, 446, 446, 444, 606, 447, 447, + 447, 447, 447, 448, 445, 445, 79, 434, 461, 583, + 583, 79, 332, 333, 334, 332, 332, 332, 332, 332, + 335, 253, 170, 444, 336, 336, 336, 336, 336, 512, + 462, 401, 409, 409, 409, 409, 409, 409, 409, 409, + 455, 455, 455, 455, 455, 456, 384, 336, 336, 336, + 336, 336, 336, 253, 170, 344, 344, 344, 344, 344, + + 344, 344, 344, 300, 253, 170, 345, 345, 345, 345, + 345, 345, 345, 345, 346, 606, 170, 463, 347, 347, + 347, 347, 347, 79, 472, 401, 253, 170, 451, 451, + 451, 451, 451, 451, 331, 503, 401, 79, 513, 464, + 466, 347, 347, 347, 347, 347, 347, 170, 351, 352, + 353, 351, 351, 351, 351, 351, 354, 504, 465, 79, + 355, 355, 355, 355, 355, 454, 454, 454, 454, 454, + 454, 454, 454, 606, 79, 453, 453, 453, 453, 453, + 453, 453, 453, 355, 355, 355, 355, 355, 355, 375, + 376, 376, 376, 376, 376, 376, 376, 376, 470, 478, + + 546, 479, 479, 479, 479, 479, 479, 479, 479, 443, + 443, 443, 443, 443, 443, 443, 443, 460, 470, 459, + 470, 471, 547, 79, 375, 377, 377, 377, 377, 377, + 377, 377, 377, 478, 470, 480, 480, 480, 480, 480, + 480, 480, 480, 79, 478, 382, 481, 481, 481, 481, + 481, 482, 479, 479, 470, 434, 470, 470, 79, 375, + 378, 378, 378, 378, 378, 379, 376, 376, 489, 489, + 489, 489, 489, 489, 489, 489, 490, 490, 490, 490, + 490, 491, 606, 170, 488, 488, 488, 488, 488, 488, + 488, 488, 401, 79, 382, 382, 383, 383, 383, 383, + + 383, 383, 383, 383, 384, 487, 588, 589, 385, 385, + 385, 385, 385, 497, 498, 499, 497, 497, 497, 497, + 497, 444, 458, 445, 445, 445, 445, 445, 445, 445, + 445, 385, 385, 385, 385, 385, 385, 389, 390, 391, + 389, 389, 389, 389, 389, 392, 588, 589, 457, 393, + 393, 393, 393, 393, 444, 606, 445, 445, 445, 445, + 445, 445, 445, 445, 444, 487, 445, 445, 445, 445, + 445, 445, 393, 393, 393, 393, 393, 393, 253, 170, + 399, 399, 399, 399, 399, 399, 399, 399, 346, 253, + 170, 400, 400, 400, 400, 400, 400, 400, 400, 401, + + 253, 170, 331, 402, 402, 402, 402, 402, 554, 515, + 401, 516, 517, 518, 515, 382, 516, 517, 518, 535, + 535, 535, 535, 535, 536, 487, 402, 402, 402, 402, + 402, 402, 170, 406, 407, 408, 406, 406, 406, 406, + 406, 382, 606, 79, 382, 409, 409, 409, 409, 409, + 251, 532, 532, 418, 532, 417, 519, 415, 590, 414, + 472, 521, 473, 473, 473, 473, 473, 473, 409, 409, + 409, 409, 409, 409, 375, 376, 376, 376, 376, 376, + 376, 376, 376, 546, 572, 522, 523, 524, 522, 522, + 522, 522, 522, 79, 413, 79, 525, 526, 527, 525, + + 525, 525, 525, 525, 412, 547, 573, 411, 79, 375, + 376, 376, 376, 376, 376, 376, 376, 376, 79, 478, + 572, 479, 479, 479, 479, 479, 479, 479, 479, 478, + 410, 479, 479, 479, 479, 479, 479, 479, 479, 144, + 144, 337, 573, 79, 382, 585, 432, 432, 432, 432, + 432, 432, 432, 432, 384, 382, 331, 433, 433, 433, + 433, 433, 433, 433, 433, 434, 251, 586, 585, 435, + 435, 435, 435, 435, 478, 211, 479, 479, 479, 479, + 479, 479, 496, 496, 496, 496, 496, 496, 496, 496, + 586, 370, 435, 435, 435, 435, 435, 435, 439, 440, + + 441, 439, 439, 439, 439, 439, 442, 369, 363, 362, + 443, 443, 443, 443, 443, 534, 534, 534, 534, 534, + 534, 534, 534, 606, 357, 533, 533, 533, 533, 533, + 533, 533, 533, 443, 443, 443, 443, 443, 443, 253, + 170, 451, 451, 451, 451, 451, 451, 451, 451, 401, + 253, 170, 452, 452, 452, 452, 452, 452, 452, 452, + 356, 331, 251, 211, 453, 453, 453, 453, 453, 170, + 541, 541, 541, 541, 541, 541, 541, 541, 170, 542, + 542, 542, 542, 542, 542, 542, 542, 453, 453, 453, + 453, 453, 453, 472, 211, 473, 473, 473, 473, 473, + + 473, 473, 473, 170, 543, 543, 543, 543, 543, 544, + 541, 541, 606, 276, 606, 606, 606, 320, 319, 515, + 317, 516, 517, 518, 316, 315, 314, 313, 79, 472, + 312, 474, 474, 474, 474, 474, 474, 474, 474, 606, + 311, 516, 517, 518, 606, 310, 606, 606, 518, 292, + 606, 251, 606, 606, 606, 211, 288, 211, 103, 519, + 276, 278, 276, 277, 79, 472, 519, 475, 475, 475, + 475, 475, 476, 477, 477, 552, 276, 274, 553, 553, + 553, 553, 553, 553, 553, 553, 519, 273, 272, 271, + 270, 519, 269, 97, 211, 514, 514, 521, 251, 514, + + 79, 472, 211, 477, 477, 477, 473, 473, 473, 473, + 473, 514, 514, 514, 520, 520, 103, 559, 520, 560, + 560, 560, 560, 560, 560, 560, 560, 83, 199, 239, + 520, 520, 520, 236, 235, 234, 79, 382, 233, 485, + 485, 485, 485, 485, 485, 485, 485, 434, 382, 232, + 486, 486, 486, 486, 486, 486, 486, 486, 487, 230, + 229, 228, 488, 488, 488, 488, 488, 559, 227, 561, + 561, 561, 561, 561, 561, 561, 561, 540, 540, 540, + 540, 540, 540, 540, 540, 488, 488, 488, 488, 488, + 488, 492, 493, 494, 492, 492, 492, 492, 492, 495, + + 226, 225, 224, 496, 496, 496, 496, 496, 559, 223, + 562, 562, 562, 562, 562, 563, 560, 560, 569, 569, + 569, 569, 569, 569, 569, 569, 496, 496, 496, 496, + 496, 496, 253, 170, 502, 502, 502, 502, 502, 502, + 502, 502, 472, 222, 473, 473, 473, 473, 473, 473, + 473, 473, 570, 570, 570, 570, 570, 571, 606, 221, + 568, 568, 568, 568, 568, 568, 568, 568, 170, 541, + 541, 541, 541, 541, 541, 541, 541, 79, 472, 103, + 473, 473, 473, 473, 473, 473, 473, 473, 170, 541, + 541, 541, 541, 541, 541, 541, 541, 170, 541, 541, + + 541, 541, 541, 541, 553, 553, 553, 553, 553, 553, + 553, 553, 95, 79, 382, 83, 530, 530, 530, 530, + 530, 530, 530, 530, 487, 382, 83, 531, 531, 531, + 531, 531, 531, 531, 531, 532, 199, 151, 152, 533, + 533, 533, 533, 533, 553, 553, 553, 553, 553, 553, + 553, 553, 576, 577, 578, 576, 576, 576, 576, 576, + 146, 146, 533, 533, 533, 533, 533, 533, 537, 538, + 539, 537, 537, 537, 537, 537, 138, 197, 132, 132, + 540, 540, 540, 540, 540, 79, 554, 190, 555, 555, + 555, 555, 555, 555, 579, 580, 581, 579, 579, 579, + + 579, 579, 189, 540, 540, 540, 540, 540, 540, 554, + 188, 555, 555, 555, 555, 555, 555, 555, 555, 187, + 559, 79, 560, 560, 560, 560, 560, 560, 560, 560, + 559, 186, 560, 560, 560, 560, 560, 560, 560, 560, + 184, 183, 182, 181, 79, 554, 176, 556, 556, 556, + 556, 556, 556, 556, 556, 559, 175, 560, 560, 560, + 560, 560, 560, 382, 174, 584, 584, 584, 584, 584, + 584, 584, 584, 595, 595, 595, 595, 595, 595, 103, + 79, 554, 78, 557, 557, 557, 557, 557, 558, 555, + 555, 595, 595, 595, 595, 595, 595, 595, 595, 596, + + 596, 596, 596, 596, 596, 596, 596, 597, 597, 597, + 597, 597, 598, 595, 595, 103, 79, 382, 163, 566, + 566, 566, 566, 566, 566, 566, 566, 532, 382, 91, + 567, 567, 567, 567, 567, 567, 567, 567, 83, 81, + 80, 79, 568, 568, 568, 568, 568, 152, 600, 601, + 602, 600, 600, 600, 600, 600, 590, 146, 591, 591, + 591, 591, 591, 591, 138, 568, 568, 568, 568, 568, + 568, 554, 132, 555, 555, 555, 555, 555, 555, 555, + 555, 79, 595, 595, 595, 595, 595, 595, 595, 595, + 128, 79, 595, 595, 595, 595, 595, 595, 595, 595, + + 126, 113, 112, 111, 110, 109, 79, 554, 108, 555, + 555, 555, 555, 555, 555, 555, 555, 105, 103, 91, + 603, 603, 603, 603, 603, 603, 603, 603, 600, 600, + 600, 600, 600, 600, 600, 600, 81, 80, 79, 606, + 606, 606, 79, 590, 606, 591, 591, 591, 591, 591, + 591, 591, 591, 79, 606, 606, 606, 606, 606, 606, + 606, 79, 604, 604, 604, 604, 604, 605, 603, 603, + 603, 603, 603, 603, 603, 603, 603, 603, 79, 590, + 606, 592, 592, 592, 592, 592, 592, 592, 592, 606, + 606, 606, 606, 606, 606, 79, 603, 603, 603, 603, + + 603, 603, 606, 79, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 79, 590, 606, 593, 593, 593, + 593, 593, 594, 591, 591, 606, 606, 606, 606, 79, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 79, 590, 606, 591, 591, 591, 591, 591, 591, 591, + 591, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 79, 590, 606, 591, + 591, 591, 591, 591, 591, 591, 591, 606, 606, 606, + + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 79, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 78, 606, 606, + 606, 606, 606, 606, 606, 78, 78, 78, 606, 606, + + 78, 78, 78, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 86, + 606, 606, 606, 606, 86, 606, 606, 86, 86, 86, + 86, 606, 86, 86, 86, 90, 606, 606, 606, 606, + 606, 606, 606, 90, 90, 90, 606, 606, 90, 90, + 90, 92, 606, 606, 92, 92, 606, 92, 606, 92, + 92, 92, 606, 606, 92, 92, 92, 102, 102, 606, + 606, 606, 102, 133, 606, 606, 133, 133, 606, 133, + 606, 133, 133, 133, 606, 606, 133, 133, 133, 137, + 606, 606, 137, 137, 606, 137, 606, 137, 137, 137, + + 606, 137, 606, 137, 137, 145, 606, 606, 145, 606, + 606, 145, 606, 145, 145, 145, 145, 606, 145, 145, + 145, 149, 149, 149, 149, 149, 149, 149, 149, 149, + 149, 149, 149, 149, 149, 149, 149, 151, 151, 606, + 151, 606, 151, 151, 151, 151, 151, 151, 151, 151, + 151, 151, 151, 157, 157, 157, 157, 157, 157, 157, + 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, + 158, 606, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 158, 158, 158, 158, 161, 606, 606, 606, 606, + 161, 606, 606, 161, 161, 161, 606, 606, 161, 161, + + 161, 93, 606, 606, 93, 93, 606, 93, 606, 93, + 93, 93, 606, 606, 93, 93, 93, 169, 169, 606, + 606, 606, 169, 171, 171, 171, 606, 606, 606, 171, + 134, 606, 606, 134, 134, 606, 134, 606, 134, 134, + 134, 606, 606, 134, 134, 134, 200, 200, 200, 200, + 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, + 200, 200, 207, 207, 606, 606, 606, 207, 213, 213, + 213, 606, 606, 606, 213, 245, 245, 606, 606, 606, + 245, 246, 246, 606, 606, 606, 246, 250, 250, 606, + 606, 606, 250, 252, 252, 252, 606, 606, 606, 252, + + 288, 288, 606, 606, 606, 288, 290, 290, 606, 606, + 606, 290, 291, 291, 606, 606, 606, 291, 293, 293, + 293, 606, 606, 606, 293, 297, 297, 297, 297, 606, + 606, 606, 297, 328, 328, 606, 606, 606, 328, 329, + 329, 606, 606, 606, 329, 330, 330, 606, 606, 606, + 330, 342, 342, 342, 606, 606, 606, 342, 343, 343, + 343, 343, 606, 606, 606, 343, 380, 380, 606, 606, + 606, 380, 381, 381, 606, 606, 606, 381, 397, 397, + 397, 606, 606, 606, 397, 398, 398, 398, 398, 606, + 606, 606, 398, 427, 427, 606, 606, 606, 427, 431, + + 606, 431, 431, 606, 606, 606, 431, 449, 449, 449, + 606, 606, 606, 449, 450, 450, 450, 450, 606, 606, + 606, 450, 483, 483, 606, 606, 606, 483, 484, 606, + 484, 484, 606, 606, 606, 484, 500, 500, 500, 606, + 606, 606, 500, 501, 501, 501, 606, 606, 606, 606, + 501, 509, 509, 509, 509, 509, 509, 509, 509, 509, + 509, 509, 509, 509, 509, 509, 509, 514, 514, 606, + 514, 514, 514, 606, 606, 514, 514, 514, 606, 606, + 514, 514, 514, 520, 520, 606, 520, 520, 520, 606, + 606, 520, 520, 520, 606, 606, 520, 520, 520, 528, + + 528, 606, 606, 606, 528, 529, 606, 529, 529, 606, + 606, 606, 529, 545, 545, 606, 606, 606, 606, 545, + 564, 564, 606, 606, 606, 564, 565, 606, 565, 565, + 606, 606, 606, 565, 582, 582, 606, 606, 606, 582, + 583, 606, 583, 606, 606, 606, 606, 583, 587, 587, + 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, + 587, 587, 587, 587, 13, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606 + } ; + +static yyconst short int yy_chk[3732] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 44, 3, 34, + 2, 103, 3, 4, 47, 20, 126, 4, 3, 34, + 103, 3, 52, 4, 44, 48, 4, 11, 11, 11, + 11, 126, 52, 20, 2, 2, 56, 47, 2, 74, + + 5, 5, 5, 48, 5, 2, 50, 3, 2, 3, + 5, 603, 4, 56, 4, 6, 6, 6, 20, 6, + 64, 64, 5, 5, 75, 6, 12, 12, 12, 12, + 3, 196, 68, 50, 11, 4, 70, 6, 6, 25, + 25, 72, 72, 25, 25, 196, 74, 5, 27, 27, + 27, 27, 27, 27, 27, 27, 68, 88, 124, 127, + 70, 25, 6, 7, 7, 7, 45, 7, 587, 75, + 124, 127, 129, 12, 28, 28, 28, 28, 28, 28, + 139, 139, 129, 43, 25, 43, 43, 43, 43, 43, + 43, 43, 43, 194, 45, 45, 77, 77, 45, 77, + + 88, 116, 123, 114, 114, 45, 116, 153, 45, 194, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 53, 8, 206, 53, 53, 53, 53, 53, 53, + 53, 53, 84, 84, 84, 84, 84, 84, 84, 84, + 114, 62, 62, 62, 153, 62, 154, 125, 206, 62, + 123, 62, 85, 85, 85, 85, 85, 85, 85, 85, + 143, 143, 202, 62, 62, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 62, 125, + + 128, 154, 9, 9, 9, 86, 128, 202, 55, 55, + 136, 161, 55, 55, 185, 136, 9, 101, 101, 101, + 101, 101, 101, 86, 155, 155, 198, 185, 87, 584, + 55, 87, 87, 87, 87, 87, 87, 87, 87, 198, + 9, 10, 10, 10, 10, 10, 582, 171, 86, 284, + 10, 10, 10, 55, 161, 89, 171, 89, 89, 222, + 568, 89, 89, 222, 10, 89, 213, 95, 95, 95, + 95, 95, 95, 95, 95, 213, 92, 92, 89, 89, + 92, 92, 192, 195, 284, 195, 512, 192, 10, 19, + 99, 99, 99, 99, 99, 99, 99, 99, 92, 19, + + 95, 221, 19, 19, 19, 19, 19, 19, 19, 19, + 26, 191, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 92, 237, 221, 26, 26, 26, 26, 26, 100, + 100, 100, 100, 100, 100, 100, 100, 131, 131, 131, + 131, 131, 131, 131, 131, 26, 512, 26, 26, 26, + 26, 26, 26, 32, 146, 238, 238, 146, 146, 32, + 567, 191, 32, 32, 146, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 146, 237, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 210, 210, + 210, 35, 35, 35, 35, 35, 109, 231, 240, 241, + 35, 109, 252, 231, 109, 241, 109, 117, 565, 150, + 150, 252, 239, 240, 35, 35, 35, 35, 35, 35, + 42, 42, 42, 42, 42, 293, 42, 42, 133, 133, + 42, 265, 133, 133, 293, 117, 117, 239, 281, 117, + 388, 388, 42, 42, 42, 46, 117, 163, 281, 117, + 133, 163, 323, 265, 239, 46, 150, 163, 46, 46, + + 46, 46, 46, 46, 46, 46, 275, 282, 323, 163, + 163, 275, 282, 133, 142, 142, 142, 142, 142, 142, + 142, 142, 159, 159, 159, 159, 159, 159, 159, 159, + 160, 160, 160, 160, 160, 160, 160, 160, 438, 438, + 46, 63, 201, 201, 201, 201, 201, 201, 201, 201, + 279, 63, 564, 280, 63, 63, 63, 63, 63, 63, + 63, 63, 79, 560, 79, 79, 79, 297, 79, 79, + 254, 254, 79, 197, 280, 201, 297, 197, 256, 256, + 254, 321, 322, 197, 79, 79, 79, 91, 256, 91, + 91, 91, 322, 91, 91, 197, 197, 91, 209, 209, + + 209, 209, 209, 209, 209, 209, 209, 298, 298, 91, + 91, 91, 94, 279, 94, 94, 94, 298, 94, 94, + 313, 383, 94, 162, 313, 162, 162, 452, 452, 162, + 162, 383, 321, 162, 94, 94, 94, 96, 96, 96, + 96, 96, 96, 96, 96, 162, 162, 162, 312, 96, + 96, 96, 96, 96, 205, 368, 205, 205, 205, 205, + 205, 205, 214, 214, 214, 214, 214, 214, 214, 214, + 312, 368, 96, 96, 96, 96, 96, 96, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 316, 371, 205, + 104, 104, 104, 104, 104, 216, 216, 216, 216, 216, + + 216, 216, 216, 217, 217, 217, 217, 217, 217, 316, + 299, 299, 373, 104, 104, 104, 104, 104, 104, 135, + 299, 135, 135, 135, 549, 135, 135, 373, 219, 135, + 219, 219, 219, 219, 219, 219, 219, 219, 453, 453, + 371, 135, 135, 135, 164, 545, 164, 164, 164, 164, + 164, 164, 164, 164, 247, 247, 247, 247, 247, 247, + 247, 247, 247, 253, 253, 253, 253, 253, 253, 253, + 253, 255, 255, 255, 255, 255, 255, 255, 255, 164, + 165, 541, 165, 165, 165, 165, 165, 165, 165, 165, + 259, 259, 259, 259, 259, 259, 259, 259, 419, 419, + + 259, 261, 261, 261, 261, 261, 261, 261, 261, 262, + 262, 262, 262, 262, 262, 165, 166, 529, 166, 166, + 166, 166, 166, 166, 166, 166, 264, 317, 264, 264, + 264, 264, 264, 264, 264, 264, 301, 301, 283, 283, + 283, 283, 283, 283, 283, 283, 301, 456, 456, 317, + 419, 166, 167, 318, 167, 167, 167, 167, 167, 167, + 167, 167, 318, 324, 342, 343, 167, 167, 167, 167, + 167, 283, 324, 342, 343, 344, 344, 287, 372, 287, + 287, 287, 287, 287, 287, 344, 420, 372, 420, 167, + 167, 167, 167, 167, 167, 170, 170, 170, 170, 170, + + 170, 170, 170, 170, 345, 345, 528, 170, 170, 170, + 170, 170, 287, 294, 345, 294, 294, 294, 294, 294, + 294, 294, 294, 307, 307, 307, 307, 307, 307, 513, + 170, 170, 170, 170, 170, 170, 172, 172, 172, 172, + 172, 172, 172, 172, 172, 172, 467, 467, 509, 172, + 172, 172, 172, 172, 295, 376, 295, 295, 295, 295, + 295, 295, 295, 295, 300, 300, 300, 300, 300, 300, + 300, 300, 172, 172, 172, 172, 172, 172, 173, 173, + 173, 173, 173, 173, 173, 173, 347, 347, 508, 376, + 173, 173, 173, 173, 173, 296, 347, 296, 296, 296, + + 296, 296, 296, 296, 296, 306, 306, 306, 306, 306, + 306, 306, 306, 173, 173, 173, 173, 173, 173, 203, + 507, 203, 203, 203, 203, 203, 203, 203, 203, 304, + 304, 304, 304, 304, 304, 304, 304, 506, 309, 304, + 309, 309, 309, 309, 309, 309, 309, 309, 334, 334, + 334, 334, 334, 334, 203, 204, 501, 204, 204, 204, + 204, 204, 204, 204, 204, 331, 331, 331, 331, 331, + 331, 331, 331, 333, 333, 333, 333, 333, 333, 333, + 333, 337, 337, 337, 337, 337, 337, 337, 337, 358, + 204, 215, 215, 215, 215, 215, 215, 215, 215, 215, + + 215, 215, 491, 491, 484, 215, 215, 215, 215, 215, + 336, 358, 336, 336, 336, 336, 336, 336, 336, 336, + 341, 483, 341, 341, 341, 341, 341, 341, 215, 215, + 215, 215, 215, 215, 218, 218, 218, 218, 218, 218, + 218, 218, 218, 218, 397, 502, 502, 218, 218, 218, + 218, 218, 339, 397, 339, 339, 339, 339, 339, 339, + 339, 339, 346, 346, 346, 346, 346, 346, 346, 346, + 218, 218, 218, 218, 218, 218, 242, 479, 242, 242, + 242, 242, 242, 242, 242, 242, 340, 364, 340, 340, + 340, 340, 340, 340, 340, 340, 350, 350, 350, 350, + + 350, 350, 350, 350, 398, 670, 350, 510, 510, 364, + 670, 242, 243, 398, 243, 243, 243, 243, 243, 243, + 243, 243, 352, 352, 352, 352, 352, 352, 352, 352, + 353, 353, 353, 353, 353, 353, 355, 366, 355, 355, + 355, 355, 355, 355, 355, 355, 374, 243, 244, 449, + 244, 244, 244, 244, 244, 244, 244, 244, 449, 366, + 414, 385, 374, 382, 382, 382, 382, 382, 382, 382, + 382, 385, 450, 375, 375, 375, 375, 375, 375, 375, + 375, 450, 414, 244, 257, 257, 257, 257, 257, 257, + 257, 257, 257, 257, 257, 260, 260, 260, 260, 260, + + 260, 260, 260, 260, 260, 260, 375, 415, 457, 260, + 260, 260, 260, 260, 379, 379, 379, 379, 379, 379, + 379, 384, 384, 384, 384, 384, 384, 384, 384, 415, + 457, 465, 260, 260, 260, 260, 260, 260, 263, 263, + 263, 263, 263, 263, 263, 263, 263, 263, 379, 536, + 536, 263, 263, 263, 263, 263, 390, 390, 390, 390, + 390, 390, 390, 390, 391, 391, 391, 391, 391, 391, + 460, 399, 399, 459, 263, 263, 263, 263, 263, 263, + 285, 399, 285, 285, 285, 285, 285, 285, 285, 285, + 393, 432, 393, 393, 393, 393, 393, 393, 393, 393, + + 394, 432, 394, 394, 394, 394, 394, 394, 394, 394, + 458, 473, 551, 551, 468, 285, 286, 433, 286, 286, + 286, 286, 286, 286, 286, 286, 395, 433, 395, 395, + 395, 395, 395, 395, 395, 395, 396, 435, 396, 396, + 396, 396, 396, 396, 396, 396, 473, 435, 461, 571, + 571, 286, 292, 292, 292, 292, 292, 292, 292, 292, + 292, 400, 400, 445, 292, 292, 292, 292, 292, 468, + 461, 400, 401, 401, 401, 401, 401, 401, 401, 401, + 408, 408, 408, 408, 408, 408, 431, 292, 292, 292, + 292, 292, 292, 302, 302, 302, 302, 302, 302, 302, + + 302, 302, 302, 302, 305, 305, 305, 305, 305, 305, + 305, 305, 305, 305, 305, 402, 402, 463, 305, 305, + 305, 305, 305, 469, 477, 402, 405, 405, 405, 405, + 405, 405, 405, 405, 427, 503, 405, 422, 469, 463, + 418, 305, 305, 305, 305, 305, 305, 308, 308, 308, + 308, 308, 308, 308, 308, 308, 308, 503, 417, 477, + 308, 308, 308, 308, 308, 407, 407, 407, 407, 407, + 407, 407, 407, 409, 416, 409, 409, 409, 409, 409, + 409, 409, 409, 308, 308, 308, 308, 308, 308, 325, + 325, 325, 325, 325, 325, 325, 325, 325, 421, 428, + + 505, 428, 428, 428, 428, 428, 428, 428, 428, 434, + 434, 434, 434, 434, 434, 434, 434, 413, 421, 412, + 421, 421, 505, 325, 326, 326, 326, 326, 326, 326, + 326, 326, 326, 429, 466, 429, 429, 429, 429, 429, + 429, 429, 429, 421, 430, 485, 430, 430, 430, 430, + 430, 430, 430, 430, 466, 485, 466, 466, 326, 327, + 327, 327, 327, 327, 327, 327, 327, 327, 440, 440, + 440, 440, 440, 440, 440, 440, 441, 441, 441, 441, + 441, 441, 443, 500, 443, 443, 443, 443, 443, 443, + 443, 443, 500, 327, 332, 486, 332, 332, 332, 332, + + 332, 332, 332, 332, 332, 486, 575, 575, 332, 332, + 332, 332, 332, 444, 444, 444, 444, 444, 444, 444, + 444, 446, 411, 446, 446, 446, 446, 446, 446, 446, + 446, 332, 332, 332, 332, 332, 332, 335, 335, 335, + 335, 335, 335, 335, 335, 335, 588, 588, 410, 335, + 335, 335, 335, 335, 447, 488, 447, 447, 447, 447, + 447, 447, 447, 447, 448, 488, 448, 448, 448, 448, + 448, 448, 335, 335, 335, 335, 335, 335, 348, 348, + 348, 348, 348, 348, 348, 348, 348, 348, 348, 351, + 351, 351, 351, 351, 351, 351, 351, 351, 351, 351, + + 451, 451, 381, 351, 351, 351, 351, 351, 555, 470, + 451, 470, 470, 470, 471, 530, 471, 471, 471, 494, + 494, 494, 494, 494, 494, 530, 351, 351, 351, 351, + 351, 351, 354, 354, 354, 354, 354, 354, 354, 354, + 354, 531, 533, 555, 566, 354, 354, 354, 354, 354, + 380, 531, 533, 370, 566, 369, 470, 363, 591, 362, + 476, 471, 476, 476, 476, 476, 476, 476, 354, 354, + 354, 354, 354, 354, 377, 377, 377, 377, 377, 377, + 377, 377, 377, 546, 548, 472, 472, 472, 472, 472, + 472, 472, 472, 591, 361, 476, 478, 478, 478, 478, + + 478, 478, 478, 478, 360, 546, 548, 357, 377, 378, + 378, 378, 378, 378, 378, 378, 378, 378, 472, 480, + 572, 480, 480, 480, 480, 480, 480, 480, 480, 481, + 356, 481, 481, 481, 481, 481, 481, 481, 481, 619, + 619, 338, 572, 378, 386, 574, 386, 386, 386, 386, + 386, 386, 386, 386, 386, 389, 330, 389, 389, 389, + 389, 389, 389, 389, 389, 389, 329, 574, 585, 389, + 389, 389, 389, 389, 482, 328, 482, 482, 482, 482, + 482, 482, 487, 487, 487, 487, 487, 487, 487, 487, + 585, 320, 389, 389, 389, 389, 389, 389, 392, 392, + + 392, 392, 392, 392, 392, 392, 392, 319, 315, 314, + 392, 392, 392, 392, 392, 493, 493, 493, 493, 493, + 493, 493, 493, 496, 311, 496, 496, 496, 496, 496, + 496, 496, 496, 392, 392, 392, 392, 392, 392, 403, + 403, 403, 403, 403, 403, 403, 403, 403, 403, 403, + 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, + 310, 291, 290, 289, 406, 406, 406, 406, 406, 497, + 497, 497, 497, 497, 497, 497, 497, 497, 498, 498, + 498, 498, 498, 498, 498, 498, 498, 406, 406, 406, + 406, 406, 406, 423, 288, 423, 423, 423, 423, 423, + + 423, 423, 423, 499, 499, 499, 499, 499, 499, 499, + 499, 499, 514, 278, 514, 514, 514, 277, 276, 515, + 274, 515, 515, 515, 273, 272, 271, 270, 423, 424, + 269, 424, 424, 424, 424, 424, 424, 424, 424, 516, + 268, 516, 516, 516, 517, 267, 517, 517, 517, 251, + 520, 250, 520, 520, 520, 249, 248, 246, 245, 514, + 236, 235, 234, 233, 424, 425, 515, 425, 425, 425, + 425, 425, 425, 425, 425, 518, 232, 229, 518, 518, + 518, 518, 518, 518, 518, 518, 516, 227, 226, 225, + 224, 517, 223, 220, 212, 519, 519, 520, 211, 519, + + 425, 426, 208, 426, 426, 426, 426, 426, 426, 426, + 426, 519, 519, 519, 521, 521, 207, 525, 521, 525, + 525, 525, 525, 525, 525, 525, 525, 200, 199, 193, + 521, 521, 521, 190, 189, 188, 426, 436, 187, 436, + 436, 436, 436, 436, 436, 436, 436, 436, 439, 186, + 439, 439, 439, 439, 439, 439, 439, 439, 439, 184, + 183, 182, 439, 439, 439, 439, 439, 526, 181, 526, + 526, 526, 526, 526, 526, 526, 526, 532, 532, 532, + 532, 532, 532, 532, 532, 439, 439, 439, 439, 439, + 439, 442, 442, 442, 442, 442, 442, 442, 442, 442, + + 180, 179, 178, 442, 442, 442, 442, 442, 527, 177, + 527, 527, 527, 527, 527, 527, 527, 527, 538, 538, + 538, 538, 538, 538, 538, 538, 442, 442, 442, 442, + 442, 442, 454, 454, 454, 454, 454, 454, 454, 454, + 454, 454, 474, 176, 474, 474, 474, 474, 474, 474, + 474, 474, 539, 539, 539, 539, 539, 539, 540, 175, + 540, 540, 540, 540, 540, 540, 540, 540, 542, 542, + 542, 542, 542, 542, 542, 542, 542, 474, 475, 169, + 475, 475, 475, 475, 475, 475, 475, 475, 543, 543, + 543, 543, 543, 543, 543, 543, 543, 544, 544, 544, + + 544, 544, 544, 544, 552, 552, 552, 552, 552, 552, + 552, 552, 168, 475, 489, 158, 489, 489, 489, 489, + 489, 489, 489, 489, 489, 492, 157, 492, 492, 492, + 492, 492, 492, 492, 492, 492, 156, 152, 151, 492, + 492, 492, 492, 492, 553, 553, 553, 553, 553, 553, + 553, 553, 554, 554, 554, 554, 554, 554, 554, 554, + 149, 145, 492, 492, 492, 492, 492, 492, 495, 495, + 495, 495, 495, 495, 495, 495, 138, 134, 132, 130, + 495, 495, 495, 495, 495, 554, 558, 122, 558, 558, + 558, 558, 558, 558, 559, 559, 559, 559, 559, 559, + + 559, 559, 121, 495, 495, 495, 495, 495, 495, 522, + 120, 522, 522, 522, 522, 522, 522, 522, 522, 119, + 561, 558, 561, 561, 561, 561, 561, 561, 561, 561, + 562, 118, 562, 562, 562, 562, 562, 562, 562, 562, + 113, 112, 111, 110, 522, 523, 108, 523, 523, 523, + 523, 523, 523, 523, 523, 563, 107, 563, 563, 563, + 563, 563, 563, 569, 106, 569, 569, 569, 569, 569, + 569, 569, 569, 598, 598, 598, 598, 598, 598, 102, + 523, 524, 98, 524, 524, 524, 524, 524, 524, 524, + 524, 579, 579, 579, 579, 579, 579, 579, 579, 580, + + 580, 580, 580, 580, 580, 580, 580, 581, 581, 581, + 581, 581, 581, 581, 581, 97, 524, 534, 93, 534, + 534, 534, 534, 534, 534, 534, 534, 534, 537, 90, + 537, 537, 537, 537, 537, 537, 537, 537, 82, 81, + 80, 78, 537, 537, 537, 537, 537, 73, 590, 590, + 590, 590, 590, 590, 590, 590, 594, 66, 594, 594, + 594, 594, 594, 594, 59, 537, 537, 537, 537, 537, + 537, 556, 54, 556, 556, 556, 556, 556, 556, 556, + 556, 590, 596, 596, 596, 596, 596, 596, 596, 596, + 51, 594, 597, 597, 597, 597, 597, 597, 597, 597, + + 49, 41, 40, 39, 38, 37, 556, 557, 36, 557, + 557, 557, 557, 557, 557, 557, 557, 33, 29, 23, + 600, 600, 600, 600, 600, 600, 600, 600, 601, 601, + 601, 601, 601, 601, 601, 601, 17, 15, 14, 13, + 0, 0, 557, 576, 0, 576, 576, 576, 576, 576, + 576, 576, 576, 600, 0, 0, 0, 0, 0, 0, + 0, 601, 602, 602, 602, 602, 602, 602, 602, 602, + 604, 604, 604, 604, 604, 604, 604, 604, 576, 577, + 0, 577, 577, 577, 577, 577, 577, 577, 577, 0, + 0, 0, 0, 0, 0, 602, 605, 605, 605, 605, + + 605, 605, 0, 604, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 577, 578, 0, 578, 578, 578, + 578, 578, 578, 578, 578, 0, 0, 0, 0, 605, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 578, 592, 0, 592, 592, 592, 592, 592, 592, 592, + 592, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 592, 593, 0, 593, + 593, 593, 593, 593, 593, 593, 593, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 593, 607, 607, 607, 607, 607, 607, 607, + 607, 607, 607, 607, 607, 607, 607, 607, 607, 608, + 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, + 608, 608, 608, 608, 608, 609, 609, 609, 609, 609, + 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, + 609, 610, 610, 610, 610, 610, 610, 610, 610, 610, + 610, 610, 610, 610, 610, 610, 610, 611, 0, 0, + 0, 0, 0, 0, 0, 611, 611, 611, 0, 0, + + 611, 611, 611, 612, 612, 612, 612, 612, 612, 612, + 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, + 0, 0, 0, 0, 613, 0, 0, 613, 613, 613, + 613, 0, 613, 613, 613, 614, 0, 0, 0, 0, + 0, 0, 0, 614, 614, 614, 0, 0, 614, 614, + 614, 615, 0, 0, 615, 615, 0, 615, 0, 615, + 615, 615, 0, 0, 615, 615, 615, 616, 616, 0, + 0, 0, 616, 617, 0, 0, 617, 617, 0, 617, + 0, 617, 617, 617, 0, 0, 617, 617, 617, 618, + 0, 0, 618, 618, 0, 618, 0, 618, 618, 618, + + 0, 618, 0, 618, 618, 620, 0, 0, 620, 0, + 0, 620, 0, 620, 620, 620, 620, 0, 620, 620, + 620, 621, 621, 621, 621, 621, 621, 621, 621, 621, + 621, 621, 621, 621, 621, 621, 621, 622, 622, 0, + 622, 0, 622, 622, 622, 622, 622, 622, 622, 622, + 622, 622, 622, 623, 623, 623, 623, 623, 623, 623, + 623, 623, 623, 623, 623, 623, 623, 623, 623, 624, + 624, 0, 624, 624, 624, 624, 624, 624, 624, 624, + 624, 624, 624, 624, 624, 625, 0, 0, 0, 0, + 625, 0, 0, 625, 625, 625, 0, 0, 625, 625, + + 625, 626, 0, 0, 626, 626, 0, 626, 0, 626, + 626, 626, 0, 0, 626, 626, 626, 627, 627, 0, + 0, 0, 627, 628, 628, 628, 0, 0, 0, 628, + 629, 0, 0, 629, 629, 0, 629, 0, 629, 629, + 629, 0, 0, 629, 629, 629, 630, 630, 630, 630, + 630, 630, 630, 630, 630, 630, 630, 630, 630, 630, + 630, 630, 631, 631, 0, 0, 0, 631, 632, 632, + 632, 0, 0, 0, 632, 633, 633, 0, 0, 0, + 633, 634, 634, 0, 0, 0, 634, 635, 635, 0, + 0, 0, 635, 636, 636, 636, 0, 0, 0, 636, + + 637, 637, 0, 0, 0, 637, 638, 638, 0, 0, + 0, 638, 639, 639, 0, 0, 0, 639, 640, 640, + 640, 0, 0, 0, 640, 641, 641, 641, 641, 0, + 0, 0, 641, 642, 642, 0, 0, 0, 642, 643, + 643, 0, 0, 0, 643, 644, 644, 0, 0, 0, + 644, 645, 645, 645, 0, 0, 0, 645, 646, 646, + 646, 646, 0, 0, 0, 646, 647, 647, 0, 0, + 0, 647, 648, 648, 0, 0, 0, 648, 649, 649, + 649, 0, 0, 0, 649, 650, 650, 650, 650, 0, + 0, 0, 650, 651, 651, 0, 0, 0, 651, 652, + + 0, 652, 652, 0, 0, 0, 652, 653, 653, 653, + 0, 0, 0, 653, 654, 654, 654, 654, 0, 0, + 0, 654, 655, 655, 0, 0, 0, 655, 656, 0, + 656, 656, 0, 0, 0, 656, 657, 657, 657, 0, + 0, 0, 657, 658, 658, 658, 0, 0, 0, 0, + 658, 659, 659, 659, 659, 659, 659, 659, 659, 659, + 659, 659, 659, 659, 659, 659, 659, 660, 660, 0, + 660, 660, 660, 0, 0, 660, 660, 660, 0, 0, + 660, 660, 660, 661, 661, 0, 661, 661, 661, 0, + 0, 661, 661, 661, 0, 0, 661, 661, 661, 662, + + 662, 0, 0, 0, 662, 663, 0, 663, 663, 0, + 0, 0, 663, 664, 664, 0, 0, 0, 0, 664, + 665, 665, 0, 0, 0, 665, 666, 0, 666, 666, + 0, 0, 0, 666, 667, 667, 0, 0, 0, 667, + 668, 0, 668, 0, 0, 0, 0, 668, 669, 669, + 669, 669, 669, 669, 669, 669, 669, 669, 669, 669, + 669, 669, 669, 669, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606, 606, 606, 606, 606, 606, 606, 606, 606, 606, + 606 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "toke.l" +#define INITIAL 0 +#line 2 "toke.l" +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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 +#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 */ +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif +#include +#include +#include "sudoers.h" +#include "parse.h" +#include "toke.h" +#include +#include "lbuf.h" +#include "secure_path.h" + +extern YYSTYPE yylval; +extern bool parse_error; +extern bool sudoers_warnings; +int sudolineno; +int last_token; +char *sudoers; + +/* Default sudoers path, mode and owner (may be set via sudo.conf) */ +const char *sudoers_file = _PATH_SUDOERS; +mode_t sudoers_mode = SUDOERS_MODE; +uid_t sudoers_uid = SUDOERS_UID; +gid_t sudoers_gid = SUDOERS_GID; + +static bool continued, sawspace; +static int prev_state; + +static bool _push_include(char *, bool); +static bool pop_include(void); +static char *parse_include(char *); + +static int sudoers_trace_print(const char *msg); +int (*trace_print)(const char *msg) = sudoers_trace_print; + +#define LEXRETURN(n) do { \ + last_token = (n); \ + return (n); \ +} while (0) + +#define ECHO ignore_result(fwrite(yytext, yyleng, 1, yyout)) + +#define push_include(_p) (_push_include((_p), false)) +#define push_includedir(_p) (_push_include((_p), true)) +#define YY_NO_INPUT 1 +#define YY_NO_UNPUT 1 +#define GOTDEFS 1 + +#define GOTCMND 2 + +#define STARTDEFS 3 + +#define INDEFS 4 + +#define INSTR 5 + +#line 1525 "lex.yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if defined(YY_STACK_USED) && YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#ifdef __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + if ( yyleng > 0 ) \ + yy_current_buffer->yy_at_bol = \ + (yytext[yyleng - 1] == '\n'); \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 133 "toke.l" + +#line 1681 "lex.yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 607 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 3665 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 134 "toke.l" +{ + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + YY_BREAK +case 2: +YY_RULE_SETUP +#line 139 "toke.l" +BEGIN STARTDEFS; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 141 "toke.l" +{ + BEGIN INDEFS; + LEXTRACE("DEFVAR "); + if (!fill(yytext, yyleng)) + yyterminate(); + LEXRETURN(DEFVAR); + } + YY_BREAK + +case 4: +YY_RULE_SETUP +#line 150 "toke.l" +{ + BEGIN STARTDEFS; + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + YY_BREAK +case 5: +YY_RULE_SETUP +#line 156 "toke.l" +{ + LEXTRACE("= "); + LEXRETURN('='); + } /* return '=' */ + YY_BREAK +case 6: +YY_RULE_SETUP +#line 161 "toke.l" +{ + LEXTRACE("+= "); + LEXRETURN('+'); + } /* return '+' */ + YY_BREAK +case 7: +YY_RULE_SETUP +#line 166 "toke.l" +{ + LEXTRACE("-= "); + LEXRETURN('-'); + } /* return '-' */ + YY_BREAK +case 8: +YY_RULE_SETUP +#line 171 "toke.l" +{ + LEXTRACE("BEGINSTR "); + yylval.string = NULL; + prev_state = YY_START; + BEGIN INSTR; + } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 178 "toke.l" +{ + LEXTRACE("WORD(2) "); + if (!fill(yytext, yyleng)) + yyterminate(); + LEXRETURN(WORD); + } + YY_BREAK + + +case 10: +YY_RULE_SETUP +#line 187 "toke.l" +{ + /* Line continuation char followed by newline. */ + sudolineno++; + continued = true; + } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 193 "toke.l" +{ + LEXTRACE("ENDSTR "); + BEGIN prev_state; + + if (yylval.string == NULL) { + LEXTRACE("ERROR "); /* empty string */ + LEXRETURN(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 */ + LEXRETURN(ERROR); + } + LEXTRACE("USERGROUP "); + LEXRETURN(USERGROUP); + case '+': + if (yylval.string[1] == '\0') { + LEXTRACE("ERROR "); /* empty netgroup */ + LEXRETURN(ERROR); + } + LEXTRACE("NETGROUP "); + LEXRETURN(NETGROUP); + } + } + LEXTRACE("WORD(4) "); + LEXRETURN(WORD); + } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 225 "toke.l" +{ + LEXTRACE("BACKSLASH "); + if (!append(yytext, yyleng)) + yyterminate(); + } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 231 "toke.l" +{ + LEXTRACE("STRBODY "); + if (!append(yytext, yyleng)) + yyterminate(); + } + YY_BREAK + + +case 14: +YY_RULE_SETUP +#line 239 "toke.l" +{ + /* quoted fnmatch glob char, pass verbatim */ + LEXTRACE("QUOTEDCHAR "); + if (!fill_args(yytext, 2, sawspace)) + yyterminate(); + sawspace = false; + } + YY_BREAK +case 15: +YY_RULE_SETUP +#line 247 "toke.l" +{ + /* quoted sudoers special char, strip backslash */ + LEXTRACE("QUOTEDCHAR "); + if (!fill_args(yytext + 1, 1, sawspace)) + yyterminate(); + sawspace = false; + } + YY_BREAK +case 16: +YY_RULE_SETUP +#line 255 "toke.l" +{ + BEGIN INITIAL; + yyless(0); + LEXRETURN(COMMAND); + } /* end of command line args */ + YY_BREAK +case 17: +YY_RULE_SETUP +#line 261 "toke.l" +{ + LEXTRACE("ARG "); + if (!fill_args(yytext, yyleng, sawspace)) + yyterminate(); + sawspace = false; + } /* a command line arg */ + YY_BREAK + +case 18: +YY_RULE_SETUP +#line 269 "toke.l" +{ + char *path; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + if ((path = parse_include(yytext)) == NULL) + yyterminate(); + + LEXTRACE("INCLUDE\n"); + + /* Push current buffer and switch to include file */ + if (!push_include(path)) + yyterminate(); + } + YY_BREAK +case 19: +YY_RULE_SETUP +#line 287 "toke.l" +{ + char *path; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + if ((path = parse_include(yytext)) == NULL) + yyterminate(); + + LEXTRACE("INCLUDEDIR\n"); + + /* + * Push current buffer and switch to include file. + * We simply ignore empty directories. + */ + if (!push_includedir(path) && parse_error) + yyterminate(); + } + YY_BREAK +case 20: +YY_RULE_SETUP +#line 308 "toke.l" +{ + char deftype; + int n; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + for (n = 0; isblank((unsigned char)yytext[n]); n++) + continue; + n += sizeof("Defaults") - 1; + if ((deftype = yytext[n++]) != '\0') { + while (isblank((unsigned char)yytext[n])) + n++; + } + BEGIN GOTDEFS; + switch (deftype) { + case ':': + yyless(n); + LEXTRACE("DEFAULTS_USER "); + LEXRETURN(DEFAULTS_USER); + case '>': + yyless(n); + LEXTRACE("DEFAULTS_RUNAS "); + LEXRETURN(DEFAULTS_RUNAS); + case '@': + yyless(n); + LEXTRACE("DEFAULTS_HOST "); + LEXRETURN(DEFAULTS_HOST); + case '!': + yyless(n); + LEXTRACE("DEFAULTS_CMND "); + LEXRETURN(DEFAULTS_CMND); + default: + LEXTRACE("DEFAULTS "); + LEXRETURN(DEFAULTS); + } + } + YY_BREAK +case 21: +YY_RULE_SETUP +#line 348 "toke.l" +{ + int n; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + for (n = 0; isblank((unsigned char)yytext[n]); n++) + continue; + switch (yytext[n]) { + case 'H': + LEXTRACE("HOSTALIAS "); + LEXRETURN(HOSTALIAS); + case 'C': + LEXTRACE("CMNDALIAS "); + LEXRETURN(CMNDALIAS); + case 'U': + LEXTRACE("USERALIAS "); + LEXRETURN(USERALIAS); + case 'R': + LEXTRACE("RUNASALIAS "); + LEXRETURN(RUNASALIAS); + } + } + YY_BREAK +case 22: +YY_RULE_SETUP +#line 374 "toke.l" +{ + /* cmnd does not require passwd for this user */ + LEXTRACE("NOPASSWD "); + LEXRETURN(NOPASSWD); + } + YY_BREAK +case 23: +YY_RULE_SETUP +#line 380 "toke.l" +{ + /* cmnd requires passwd for this user */ + LEXTRACE("PASSWD "); + LEXRETURN(PASSWD); + } + YY_BREAK +case 24: +YY_RULE_SETUP +#line 386 "toke.l" +{ + LEXTRACE("NOEXEC "); + LEXRETURN(NOEXEC); + } + YY_BREAK +case 25: +YY_RULE_SETUP +#line 391 "toke.l" +{ + LEXTRACE("EXEC "); + LEXRETURN(EXEC); + } + YY_BREAK +case 26: +YY_RULE_SETUP +#line 396 "toke.l" +{ + LEXTRACE("SETENV "); + LEXRETURN(SETENV); + } + YY_BREAK +case 27: +YY_RULE_SETUP +#line 401 "toke.l" +{ + LEXTRACE("NOSETENV "); + LEXRETURN(NOSETENV); + } + YY_BREAK +case 28: +YY_RULE_SETUP +#line 406 "toke.l" +{ + LEXTRACE("LOG_OUTPUT "); + LEXRETURN(LOG_OUTPUT); + } + YY_BREAK +case 29: +YY_RULE_SETUP +#line 411 "toke.l" +{ + LEXTRACE("NOLOG_OUTPUT "); + LEXRETURN(NOLOG_OUTPUT); + } + YY_BREAK +case 30: +YY_RULE_SETUP +#line 416 "toke.l" +{ + LEXTRACE("LOG_INPUT "); + LEXRETURN(LOG_INPUT); + } + YY_BREAK +case 31: +YY_RULE_SETUP +#line 421 "toke.l" +{ + LEXTRACE("NOLOG_INPUT "); + LEXRETURN(NOLOG_INPUT); + } + YY_BREAK +case 32: +YY_RULE_SETUP +#line 426 "toke.l" +{ + /* empty group or netgroup */ + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + YY_BREAK +case 33: +YY_RULE_SETUP +#line 432 "toke.l" +{ + /* netgroup */ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NETGROUP "); + LEXRETURN(NETGROUP); + } + YY_BREAK +case 34: +YY_RULE_SETUP +#line 440 "toke.l" +{ + /* group */ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("USERGROUP "); + LEXRETURN(USERGROUP); + } + YY_BREAK +case 35: +YY_RULE_SETUP +#line 448 "toke.l" +{ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + YY_BREAK +case 36: +YY_RULE_SETUP +#line 455 "toke.l" +{ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + YY_BREAK +case 37: +YY_RULE_SETUP +#line 462 "toke.l" +{ + if (!ipv6_valid(yytext)) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + YY_BREAK +case 38: +YY_RULE_SETUP +#line 473 "toke.l" +{ + if (!ipv6_valid(yytext)) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + YY_BREAK +case 39: +YY_RULE_SETUP +#line 484 "toke.l" +{ + LEXTRACE("ALL "); + LEXRETURN(ALL); + + } + YY_BREAK +case 40: +YY_RULE_SETUP +#line 490 "toke.l" +{ +#ifdef HAVE_SELINUX + LEXTRACE("ROLE "); + LEXRETURN(ROLE); +#else + goto got_alias; +#endif + } + YY_BREAK +case 41: +YY_RULE_SETUP +#line 499 "toke.l" +{ +#ifdef HAVE_SELINUX + LEXTRACE("TYPE "); + LEXRETURN(TYPE); +#else + goto got_alias; +#endif + } + YY_BREAK +case 42: +YY_RULE_SETUP +#line 508 "toke.l" +{ +#ifndef HAVE_SELINUX + got_alias: +#endif + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("ALIAS "); + LEXRETURN(ALIAS); + } + YY_BREAK +case 43: +YY_RULE_SETUP +#line 518 "toke.l" +{ + /* no command args allowed for Defaults!/path */ + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + LEXTRACE("COMMAND "); + LEXRETURN(COMMAND); + } + YY_BREAK +case 44: +YY_RULE_SETUP +#line 526 "toke.l" +{ + BEGIN GOTCMND; + LEXTRACE("COMMAND "); + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + } /* sudo -e */ + YY_BREAK +case 45: +YY_RULE_SETUP +#line 533 "toke.l" +{ + /* directories can't have args... */ + if (yytext[yyleng - 1] == '/') { + LEXTRACE("COMMAND "); + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + LEXRETURN(COMMAND); + } else { + BEGIN GOTCMND; + LEXTRACE("COMMAND "); + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + } + } /* a pathname */ + YY_BREAK +case 46: +YY_RULE_SETUP +#line 548 "toke.l" +{ + LEXTRACE("BEGINSTR "); + yylval.string = NULL; + prev_state = YY_START; + BEGIN INSTR; + } + YY_BREAK +case 47: +YY_RULE_SETUP +#line 555 "toke.l" +{ + /* a word */ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("WORD(5) "); + LEXRETURN(WORD); + } + YY_BREAK +case 48: +YY_RULE_SETUP +#line 563 "toke.l" +{ + LEXTRACE("( "); + LEXRETURN('('); + } + YY_BREAK +case 49: +YY_RULE_SETUP +#line 568 "toke.l" +{ + LEXTRACE(") "); + LEXRETURN(')'); + } + YY_BREAK +case 50: +YY_RULE_SETUP +#line 573 "toke.l" +{ + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + YY_BREAK +case 51: +YY_RULE_SETUP +#line 578 "toke.l" +{ + LEXTRACE("= "); + LEXRETURN('='); + } /* return '=' */ + YY_BREAK +case 52: +YY_RULE_SETUP +#line 583 "toke.l" +{ + LEXTRACE(": "); + LEXRETURN(':'); + } /* return ':' */ + YY_BREAK +case 53: +YY_RULE_SETUP +#line 588 "toke.l" +{ + if (yyleng & 1) { + LEXTRACE("!"); + LEXRETURN('!'); /* return '!' */ + } + } + YY_BREAK +case 54: +YY_RULE_SETUP +#line 595 "toke.l" +{ + if (YY_START == INSTR) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); /* line break in string */ + } + BEGIN INITIAL; + sudolineno++; + continued = false; + LEXTRACE("\n"); + LEXRETURN(COMMENT); + } /* return newline */ + YY_BREAK +case 55: +YY_RULE_SETUP +#line 607 "toke.l" +{ /* throw away space/tabs */ + sawspace = true; /* but remember for fill_args */ + } + YY_BREAK +case 56: +YY_RULE_SETUP +#line 611 "toke.l" +{ + sawspace = true; /* remember for fill_args */ + sudolineno++; + continued = true; + } /* throw away EOL after \ */ + YY_BREAK +case 57: +YY_RULE_SETUP +#line 617 "toke.l" +{ + BEGIN INITIAL; + sudolineno++; + continued = false; + LEXTRACE("#\n"); + LEXRETURN(COMMENT); + } /* comment, not uid/gid */ + YY_BREAK +case 58: +YY_RULE_SETUP +#line 625 "toke.l" +{ + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } /* parse error */ + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(GOTDEFS): +case YY_STATE_EOF(GOTCMND): +case YY_STATE_EOF(STARTDEFS): +case YY_STATE_EOF(INDEFS): +case YY_STATE_EOF(INSTR): +#line 630 "toke.l" +{ + if (YY_START != INITIAL) { + BEGIN INITIAL; + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!pop_include()) + yyterminate(); + } + YY_BREAK +case 59: +YY_RULE_SETUP +#line 640 "toke.l" +ECHO; + YY_BREAK +#line 2457 "lex.yy.c" + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + yy_current_state += YY_AT_BOL(); + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 607 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 607 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 606); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + yy_current_buffer->yy_at_bol = (c == '\n'); + + return c; + } +#endif /* ifndef YY_NO_INPUT */ + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +#include +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if defined(YY_ALWAYS_INTERACTIVE) && YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if defined(YY_NEVER_INTERACTIVE) && YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + errno = oerrno; + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if defined(YY_MAIN) && YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 640 "toke.l" + +struct path_list { + char *path; + struct path_list *next; +}; + +struct include_stack { + YY_BUFFER_STATE bs; + char *path; + struct path_list *more; /* more files in case of includedir */ + int lineno; + bool keepopen; +}; + +static int +pl_compare(const void *v1, const void *v2) +{ + const struct path_list * const *p1 = v1; + const struct path_list * const *p2 = v2; + + return strcmp((*p1)->path, (*p2)->path); +} + +static char * +switch_dir(struct include_stack *stack, char *dirpath) +{ + DIR *dir; + int i, count = 0; + char *path = NULL; + struct dirent *dent; + struct stat sb; + struct path_list *pl, *first = NULL; + struct path_list **sorted = NULL; + debug_decl(switch_dir, SUDO_DEBUG_PARSER) + + if (!(dir = opendir(dirpath))) { + if (errno != ENOENT) { + char *errbuf; + if (asprintf(&errbuf, _("%s: %s"), dirpath, strerror(errno)) != -1) { + yyerror(errbuf); + free(errbuf); + } else { + yyerror(_("unable to allocate memory")); + } + } + goto done; + } + while ((dent = readdir(dir))) { + /* Ignore files that end in '~' or have a '.' in them. */ + if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~' + || strchr(dent->d_name, '.') != NULL) { + continue; + } + if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) { + closedir(dir); + goto bad; + } + if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) { + efree(path); + path = NULL; + continue; + } + pl = malloc(sizeof(*pl)); + if (pl == NULL) + goto bad; + pl->path = path; + pl->next = first; + first = pl; + count++; + } + closedir(dir); + + if (count == 0) + goto done; + + /* Sort the list as an array. */ + sorted = malloc(sizeof(*sorted) * count); + if (sorted == NULL) + goto bad; + pl = first; + for (i = 0; i < count; i++) { + sorted[i] = pl; + pl = pl->next; + } + qsort(sorted, count, sizeof(*sorted), pl_compare); + + /* Apply sorting to the list. */ + first = sorted[0]; + sorted[count - 1]->next = NULL; + for (i = 1; i < count; i++) + sorted[i - 1]->next = sorted[i]; + efree(sorted); + + /* Pull out the first element for parsing, leave the rest for later. */ + if (count) { + path = first->path; + pl = first->next; + efree(first); + stack->more = pl; + } else { + path = NULL; + } +done: + efree(dirpath); + debug_return_str(path); +bad: + while (first != NULL) { + pl = first; + first = pl->next; + free(pl->path); + free(pl); + } + efree(sorted); + efree(dirpath); + efree(path); + debug_return_str(NULL); +} + +#define MAX_SUDOERS_DEPTH 128 +#define SUDOERS_STACK_INCREMENT 16 + +static size_t istacksize, idepth; +static struct include_stack *istack; +static bool keepopen; + +void +init_lexer(void) +{ + struct path_list *pl; + debug_decl(init_lexer, SUDO_DEBUG_PARSER) + + while (idepth) { + idepth--; + while ((pl = istack[idepth].more) != NULL) { + istack[idepth].more = pl->next; + efree(pl->path); + efree(pl); + } + efree(istack[idepth].path); + if (idepth && !istack[idepth].keepopen) + fclose(istack[idepth].bs->yy_input_file); + yy_delete_buffer(istack[idepth].bs); + } + efree(istack); + istack = NULL; + istacksize = idepth = 0; + sudolineno = 1; + keepopen = false; + sawspace = false; + continued = false; + prev_state = INITIAL; + + debug_return; +} + +static bool +_push_include(char *path, bool isdir) +{ + struct path_list *pl; + FILE *fp; + debug_decl(_push_include, SUDO_DEBUG_PARSER) + + /* push current state onto stack */ + if (idepth >= istacksize) { + if (idepth > MAX_SUDOERS_DEPTH) { + yyerror(_("too many levels of includes")); + debug_return_bool(false); + } + istacksize += SUDOERS_STACK_INCREMENT; + istack = (struct include_stack *) realloc(istack, + sizeof(*istack) * istacksize); + if (istack == NULL) { + yyerror(_("unable to allocate memory")); + debug_return_bool(false); + } + } + if (isdir) { + struct stat sb; + switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) { + case SUDO_PATH_SECURE: + break; + case SUDO_PATH_MISSING: + debug_return_bool(false); + case SUDO_PATH_BAD_TYPE: + errno = ENOTDIR; + if (sudoers_warnings) { + warning("%s", path); + } + debug_return_bool(false); + case SUDO_PATH_WRONG_OWNER: + if (sudoers_warnings) { + warningx(_("%s is owned by uid %u, should be %u"), + path, (unsigned int) sb.st_uid, + (unsigned int) sudoers_uid); + } + debug_return_bool(false); + case SUDO_PATH_WORLD_WRITABLE: + if (sudoers_warnings) { + warningx(_("%s is world writable"), path); + } + debug_return_bool(false); + case SUDO_PATH_GROUP_WRITABLE: + if (sudoers_warnings) { + warningx(_("%s is owned by gid %u, should be %u"), + path, (unsigned int) sb.st_gid, + (unsigned int) sudoers_gid); + } + debug_return_bool(false); + default: + /* NOTREACHED */ + debug_return_bool(false); + } + if (!(path = switch_dir(&istack[idepth], path))) { + /* switch_dir() called yyerror() for us */ + debug_return_bool(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) + debug_return_bool(false); + path = pl->path; + istack[idepth].more = pl->next; + efree(pl); + } + } else { + if ((fp = open_sudoers(path, true, &keepopen)) == NULL) { + char *errbuf; + if (asprintf(&errbuf, _("%s: %s"), path, strerror(errno)) != -1) { + yyerror(errbuf); + free(errbuf); + } else { + yyerror(_("unable to allocate memory")); + } + debug_return_bool(false); + } + istack[idepth].more = NULL; + } + /* Push the old (current) file and open the new one. */ + istack[idepth].path = sudoers; /* push old path */ + istack[idepth].bs = YY_CURRENT_BUFFER; + istack[idepth].lineno = sudolineno; + istack[idepth].keepopen = keepopen; + idepth++; + sudolineno = 1; + sudoers = path; + yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); + + debug_return_bool(true); +} + +static bool +pop_include(void) +{ + struct path_list *pl; + FILE *fp; + debug_decl(pop_include, SUDO_DEBUG_PARSER) + + if (idepth == 0) + debug_return_bool(false); + + if (!keepopen) + fclose(YY_CURRENT_BUFFER->yy_input_file); + yy_delete_buffer(YY_CURRENT_BUFFER); + /* If we are in an include dir, move to the next file. */ + while ((pl = istack[idepth - 1].more) != NULL) { + fp = open_sudoers(pl->path, false, &keepopen); + if (fp != NULL) { + istack[idepth - 1].more = pl->next; + efree(sudoers); + sudoers = pl->path; + sudolineno = 1; + yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); + efree(pl); + break; + } + /* Unable to open path in include dir, go to next one. */ + istack[idepth - 1].more = pl->next; + efree(pl->path); + efree(pl); + } + /* If no path list, just pop the last dir on the stack. */ + if (pl == NULL) { + idepth--; + yy_switch_to_buffer(istack[idepth].bs); + efree(sudoers); + sudoers = istack[idepth].path; + sudolineno = istack[idepth].lineno; + keepopen = istack[idepth].keepopen; + } + debug_return_bool(true); +} + +static char * +parse_include(char *base) +{ + char *cp, *ep, *path, *pp; + int dirlen = 0, len = 0, subst = 0; + size_t shost_len = 0; + debug_decl(parse_include, SUDO_DEBUG_PARSER) + + /* Pull out path from #include line. */ + cp = base + sizeof("#include"); + if (*cp == 'i') + cp += 3; /* includedir */ + while (isblank((unsigned char) *cp)) + cp++; + ep = cp; + while (*ep != '\0' && !isspace((unsigned char) *ep)) { + if (ep[0] == '%' && ep[1] == 'h') { + shost_len = strlen(user_shost); + len += shost_len - 2; + subst = 1; + } + ep++; + } + + /* Relative paths are located in the same dir as the sudoers file. */ + if (*cp != '/') { + char *dirend = strrchr(sudoers, '/'); + if (dirend != NULL) + dirlen = (int)(dirend - sudoers) + 1; + } + + /* Make a copy of the fully-qualified path and return it. */ + len += (int)(ep - cp); + path = pp = malloc(len + dirlen + 1); + if (path == NULL) { + yyerror(_("unable to allocate memory")); + debug_return_str(NULL); + } + if (dirlen) { + memcpy(path, sudoers, dirlen); + pp += dirlen; + } + if (subst) { + /* substitute for %h */ + while (cp < ep) { + if (cp[0] == '%' && cp[1] == 'h') { + memcpy(pp, user_shost, shost_len); + pp += shost_len; + cp += 2; + continue; + } + *pp++ = *cp++; + } + *pp = '\0'; + } else { + memcpy(pp, cp, len); + pp[len] = '\0'; + } + + /* Push any excess characters (e.g. comment, newline) back to the lexer */ + if (*ep != '\0') + yyless((int)(ep - base)); + + debug_return_str(path); +} + +#ifdef TRACELEXER +static int +sudoers_trace_print(const char *msg) +{ + return fputs(msg, stderr); +} +#else +static int +sudoers_trace_print(const char *msg) +{ + static bool initialized; + static struct lbuf lbuf; + + if (!initialized) { + initialized = true; + lbuf_init(&lbuf, NULL, 0, NULL, 0); + } + + lbuf_append(&lbuf, "%s", msg); + /* XXX - assumes a final newline */ + if (strchr(msg, '\n') != NULL) + { + sudo_debug_printf2(NULL, NULL, 0, SUDO_DEBUG_PARSER|SUDO_DEBUG_DEBUG, + "%s:%d %s", sudoers, sudolineno, lbuf.buf); + lbuf.len = 0; + } + return 0; +} +#endif /* TRACELEXER */ diff --git a/plugins/sudoers/toke.h b/plugins/sudoers/toke.h new file mode 100644 index 0000000..efcb4f4 --- /dev/null +++ b/plugins/sudoers/toke.h @@ -0,0 +1,41 @@ +/* + * 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 + +bool append(const char *, int); +bool fill_args(const char *, int, int); +bool fill_cmnd(const char *, int); +bool fill_txt(const char *, int, int); +bool ipv6_valid(const char *s); +void yyerror(const char *); + +#ifndef FLEX_SCANNER +extern int (*trace_print)(const char *msg); +#endif + +#define fill(a, b) fill_txt(a, b, 0) + +/* realloc() to size + COMMANDARGINC to make room for command args */ +#define COMMANDARGINC 64 + +#define LEXTRACE(msg) do { \ + if (trace_print != NULL) \ + (*trace_print)(msg); \ +} while (0); + +#endif /* _SUDO_TOKE_H */ diff --git a/plugins/sudoers/toke.l b/plugins/sudoers/toke.l new file mode 100644 index 0000000..84e8de6 --- /dev/null +++ b/plugins/sudoers/toke.l @@ -0,0 +1,1027 @@ +%{ +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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 +#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 */ +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif +#include +#include +#include "sudoers.h" +#include "parse.h" +#include "toke.h" +#include +#include "lbuf.h" +#include "secure_path.h" + +extern YYSTYPE yylval; +extern bool parse_error; +extern bool sudoers_warnings; +int sudolineno; +int last_token; +char *sudoers; + +/* Default sudoers path, mode and owner (may be set via sudo.conf) */ +const char *sudoers_file = _PATH_SUDOERS; +mode_t sudoers_mode = SUDOERS_MODE; +uid_t sudoers_uid = SUDOERS_UID; +gid_t sudoers_gid = SUDOERS_GID; + +static bool continued, sawspace; +static int prev_state; + +static bool _push_include(char *, bool); +static bool pop_include(void); +static char *parse_include(char *); + +static int sudoers_trace_print(const char *msg); +int (*trace_print)(const char *msg) = sudoers_trace_print; + +#define LEXRETURN(n) do { \ + last_token = (n); \ + return (n); \ +} while (0) + +#define ECHO ignore_result(fwrite(yytext, yyleng, 1, yyout)) + +#define push_include(_p) (_push_include((_p), false)) +#define push_includedir(_p) (_push_include((_p), true)) +%} + +HEX16 [0-9A-Fa-f]{1,4} +OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]) +IPV4ADDR {OCTET}(\.{OCTET}){3} +IPV6ADDR ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR} + +HOSTNAME [[:alnum:]_-]+ +WORD ([^#>!=:,\(\) \t\n\\\"]|\\[^\n])+ +ID #-?[0-9]+ +PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ +ENVAR ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\\"]|\\[^\n])* +DEFVAR [a-z_]+ + +%option noinput +%option nounput +%option noyywrap + +%s GOTDEFS +%x GOTCMND +%x STARTDEFS +%x INDEFS +%x INSTR + +%% +[[:blank:]]*,[[:blank:]]* { + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + +[[:blank:]]+ BEGIN STARTDEFS; + +{DEFVAR} { + BEGIN INDEFS; + LEXTRACE("DEFVAR "); + if (!fill(yytext, yyleng)) + yyterminate(); + LEXRETURN(DEFVAR); + } + +{ + , { + BEGIN STARTDEFS; + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + + = { + LEXTRACE("= "); + LEXRETURN('='); + } /* return '=' */ + + \+= { + LEXTRACE("+= "); + LEXRETURN('+'); + } /* return '+' */ + + -= { + LEXTRACE("-= "); + LEXRETURN('-'); + } /* return '-' */ + + \" { + LEXTRACE("BEGINSTR "); + yylval.string = NULL; + prev_state = YY_START; + BEGIN INSTR; + } + + {ENVAR} { + LEXTRACE("WORD(2) "); + if (!fill(yytext, yyleng)) + yyterminate(); + LEXRETURN(WORD); + } +} + +{ + \\[[:blank:]]*\n[[:blank:]]* { + /* Line continuation char followed by newline. */ + sudolineno++; + continued = true; + } + + \" { + LEXTRACE("ENDSTR "); + BEGIN prev_state; + + if (yylval.string == NULL) { + LEXTRACE("ERROR "); /* empty string */ + LEXRETURN(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 */ + LEXRETURN(ERROR); + } + LEXTRACE("USERGROUP "); + LEXRETURN(USERGROUP); + case '+': + if (yylval.string[1] == '\0') { + LEXTRACE("ERROR "); /* empty netgroup */ + LEXRETURN(ERROR); + } + LEXTRACE("NETGROUP "); + LEXRETURN(NETGROUP); + } + } + LEXTRACE("WORD(4) "); + LEXRETURN(WORD); + } + + \\ { + LEXTRACE("BACKSLASH "); + if (!append(yytext, yyleng)) + yyterminate(); + } + + ([^\"\n\\]|\\\")+ { + LEXTRACE("STRBODY "); + if (!append(yytext, yyleng)) + yyterminate(); + } +} + +{ + \\[\*\?\[\]\!] { + /* quoted fnmatch glob char, pass verbatim */ + LEXTRACE("QUOTEDCHAR "); + if (!fill_args(yytext, 2, sawspace)) + yyterminate(); + sawspace = false; + } + + \\[:\\,= \t#] { + /* quoted sudoers special char, strip backslash */ + LEXTRACE("QUOTEDCHAR "); + if (!fill_args(yytext + 1, 1, sawspace)) + yyterminate(); + sawspace = false; + } + + [#:\,=\n] { + BEGIN INITIAL; + yyless(0); + LEXRETURN(COMMAND); + } /* end of command line args */ + + [^#\\:, \t\n]+ { + LEXTRACE("ARG "); + if (!fill_args(yytext, yyleng, sawspace)) + yyterminate(); + sawspace = false; + } /* a command line arg */ +} + +^#include[[:blank:]]+.*\n { + char *path; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + if ((path = parse_include(yytext)) == NULL) + yyterminate(); + + LEXTRACE("INCLUDE\n"); + + /* Push current buffer and switch to include file */ + if (!push_include(path)) + yyterminate(); + } + +^#includedir[[:blank:]]+.*\n { + char *path; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + if ((path = parse_include(yytext)) == NULL) + yyterminate(); + + LEXTRACE("INCLUDEDIR\n"); + + /* + * Push current buffer and switch to include file. + * We simply ignore empty directories. + */ + if (!push_includedir(path) && parse_error) + yyterminate(); + } + +^[[:blank:]]*Defaults([:@>\!][[:blank:]]*\!*\"?({ID}|{WORD}))? { + char deftype; + int n; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + for (n = 0; isblank((unsigned char)yytext[n]); n++) + continue; + n += sizeof("Defaults") - 1; + if ((deftype = yytext[n++]) != '\0') { + while (isblank((unsigned char)yytext[n])) + n++; + } + BEGIN GOTDEFS; + switch (deftype) { + case ':': + yyless(n); + LEXTRACE("DEFAULTS_USER "); + LEXRETURN(DEFAULTS_USER); + case '>': + yyless(n); + LEXTRACE("DEFAULTS_RUNAS "); + LEXRETURN(DEFAULTS_RUNAS); + case '@': + yyless(n); + LEXTRACE("DEFAULTS_HOST "); + LEXRETURN(DEFAULTS_HOST); + case '!': + yyless(n); + LEXTRACE("DEFAULTS_CMND "); + LEXRETURN(DEFAULTS_CMND); + default: + LEXTRACE("DEFAULTS "); + LEXRETURN(DEFAULTS); + } + } + +^[[:blank:]]*(Host|Cmnd|User|Runas)_Alias { + int n; + + if (continued) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + + for (n = 0; isblank((unsigned char)yytext[n]); n++) + continue; + switch (yytext[n]) { + case 'H': + LEXTRACE("HOSTALIAS "); + LEXRETURN(HOSTALIAS); + case 'C': + LEXTRACE("CMNDALIAS "); + LEXRETURN(CMNDALIAS); + case 'U': + LEXTRACE("USERALIAS "); + LEXRETURN(USERALIAS); + case 'R': + LEXTRACE("RUNASALIAS "); + LEXRETURN(RUNASALIAS); + } + } + +NOPASSWD[[:blank:]]*: { + /* cmnd does not require passwd for this user */ + LEXTRACE("NOPASSWD "); + LEXRETURN(NOPASSWD); + } + +PASSWD[[:blank:]]*: { + /* cmnd requires passwd for this user */ + LEXTRACE("PASSWD "); + LEXRETURN(PASSWD); + } + +NOEXEC[[:blank:]]*: { + LEXTRACE("NOEXEC "); + LEXRETURN(NOEXEC); + } + +EXEC[[:blank:]]*: { + LEXTRACE("EXEC "); + LEXRETURN(EXEC); + } + +SETENV[[:blank:]]*: { + LEXTRACE("SETENV "); + LEXRETURN(SETENV); + } + +NOSETENV[[:blank:]]*: { + LEXTRACE("NOSETENV "); + LEXRETURN(NOSETENV); + } + +LOG_OUTPUT[[:blank:]]*: { + LEXTRACE("LOG_OUTPUT "); + LEXRETURN(LOG_OUTPUT); + } + +NOLOG_OUTPUT[[:blank:]]*: { + LEXTRACE("NOLOG_OUTPUT "); + LEXRETURN(NOLOG_OUTPUT); + } + +LOG_INPUT[[:blank:]]*: { + LEXTRACE("LOG_INPUT "); + LEXRETURN(LOG_INPUT); + } + +NOLOG_INPUT[[:blank:]]*: { + LEXTRACE("NOLOG_INPUT "); + LEXRETURN(NOLOG_INPUT); + } + +(\+|\%|\%:) { + /* empty group or netgroup */ + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + +\+{WORD} { + /* netgroup */ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NETGROUP "); + LEXRETURN(NETGROUP); + } + +\%:?({WORD}|{ID}) { + /* group */ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("USERGROUP "); + LEXRETURN(USERGROUP); + } + +{IPV4ADDR}(\/{IPV4ADDR})? { + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + +{IPV4ADDR}\/([12]?[0-9]|3[0-2]) { + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + +{IPV6ADDR}(\/{IPV6ADDR})? { + if (!ipv6_valid(yytext)) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + +{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) { + if (!ipv6_valid(yytext)) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("NTWKADDR "); + LEXRETURN(NTWKADDR); + } + +ALL { + LEXTRACE("ALL "); + LEXRETURN(ALL); + + } + +ROLE { +#ifdef HAVE_SELINUX + LEXTRACE("ROLE "); + LEXRETURN(ROLE); +#else + goto got_alias; +#endif + } + +TYPE { +#ifdef HAVE_SELINUX + LEXTRACE("TYPE "); + LEXRETURN(TYPE); +#else + goto got_alias; +#endif + } + +[[:upper:]][[:upper:][:digit:]_]* { +#ifndef HAVE_SELINUX + got_alias: +#endif + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("ALIAS "); + LEXRETURN(ALIAS); + } + +({PATH}|sudoedit) { + /* no command args allowed for Defaults!/path */ + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + LEXTRACE("COMMAND "); + LEXRETURN(COMMAND); + } + +sudoedit { + BEGIN GOTCMND; + LEXTRACE("COMMAND "); + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + } /* sudo -e */ + +{PATH} { + /* directories can't have args... */ + if (yytext[yyleng - 1] == '/') { + LEXTRACE("COMMAND "); + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + LEXRETURN(COMMAND); + } else { + BEGIN GOTCMND; + LEXTRACE("COMMAND "); + if (!fill_cmnd(yytext, yyleng)) + yyterminate(); + } + } /* a pathname */ + +\" { + LEXTRACE("BEGINSTR "); + yylval.string = NULL; + prev_state = YY_START; + BEGIN INSTR; + } + +({ID}|{WORD}) { + /* a word */ + if (!fill(yytext, yyleng)) + yyterminate(); + LEXTRACE("WORD(5) "); + LEXRETURN(WORD); + } + +\( { + LEXTRACE("( "); + LEXRETURN('('); + } + +\) { + LEXTRACE(") "); + LEXRETURN(')'); + } + +, { + LEXTRACE(", "); + LEXRETURN(','); + } /* return ',' */ + += { + LEXTRACE("= "); + LEXRETURN('='); + } /* return '=' */ + +: { + LEXTRACE(": "); + LEXRETURN(':'); + } /* return ':' */ + +<*>!+ { + if (yyleng & 1) { + LEXTRACE("!"); + LEXRETURN('!'); /* return '!' */ + } + } + +<*>\n { + if (YY_START == INSTR) { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); /* line break in string */ + } + BEGIN INITIAL; + sudolineno++; + continued = false; + LEXTRACE("\n"); + LEXRETURN(COMMENT); + } /* return newline */ + +<*>[[:blank:]]+ { /* throw away space/tabs */ + sawspace = true; /* but remember for fill_args */ + } + +<*>\\[[:blank:]]*\n { + sawspace = true; /* remember for fill_args */ + sudolineno++; + continued = true; + } /* throw away EOL after \ */ + +#(-[^\n0-9].*|[^\n0-9-].*)?\n { + BEGIN INITIAL; + sudolineno++; + continued = false; + LEXTRACE("#\n"); + LEXRETURN(COMMENT); + } /* comment, not uid/gid */ + +<*>. { + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } /* parse error */ + +<*><> { + if (YY_START != INITIAL) { + BEGIN INITIAL; + LEXTRACE("ERROR "); + LEXRETURN(ERROR); + } + if (!pop_include()) + yyterminate(); + } + +%% +struct path_list { + char *path; + struct path_list *next; +}; + +struct include_stack { + YY_BUFFER_STATE bs; + char *path; + struct path_list *more; /* more files in case of includedir */ + int lineno; + bool keepopen; +}; + +static int +pl_compare(const void *v1, const void *v2) +{ + const struct path_list * const *p1 = v1; + const struct path_list * const *p2 = v2; + + return strcmp((*p1)->path, (*p2)->path); +} + +static char * +switch_dir(struct include_stack *stack, char *dirpath) +{ + DIR *dir; + int i, count = 0; + char *path = NULL; + struct dirent *dent; + struct stat sb; + struct path_list *pl, *first = NULL; + struct path_list **sorted = NULL; + debug_decl(switch_dir, SUDO_DEBUG_PARSER) + + if (!(dir = opendir(dirpath))) { + if (errno != ENOENT) { + char *errbuf; + if (asprintf(&errbuf, _("%s: %s"), dirpath, strerror(errno)) != -1) { + yyerror(errbuf); + free(errbuf); + } else { + yyerror(_("unable to allocate memory")); + } + } + goto done; + } + while ((dent = readdir(dir))) { + /* Ignore files that end in '~' or have a '.' in them. */ + if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~' + || strchr(dent->d_name, '.') != NULL) { + continue; + } + if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) { + closedir(dir); + goto bad; + } + if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) { + efree(path); + path = NULL; + continue; + } + pl = malloc(sizeof(*pl)); + if (pl == NULL) + goto bad; + pl->path = path; + pl->next = first; + first = pl; + count++; + } + closedir(dir); + + if (count == 0) + goto done; + + /* Sort the list as an array. */ + sorted = malloc(sizeof(*sorted) * count); + if (sorted == NULL) + goto bad; + pl = first; + for (i = 0; i < count; i++) { + sorted[i] = pl; + pl = pl->next; + } + qsort(sorted, count, sizeof(*sorted), pl_compare); + + /* Apply sorting to the list. */ + first = sorted[0]; + sorted[count - 1]->next = NULL; + for (i = 1; i < count; i++) + sorted[i - 1]->next = sorted[i]; + efree(sorted); + + /* Pull out the first element for parsing, leave the rest for later. */ + if (count) { + path = first->path; + pl = first->next; + efree(first); + stack->more = pl; + } else { + path = NULL; + } +done: + efree(dirpath); + debug_return_str(path); +bad: + while (first != NULL) { + pl = first; + first = pl->next; + free(pl->path); + free(pl); + } + efree(sorted); + efree(dirpath); + efree(path); + debug_return_str(NULL); +} + +#define MAX_SUDOERS_DEPTH 128 +#define SUDOERS_STACK_INCREMENT 16 + +static size_t istacksize, idepth; +static struct include_stack *istack; +static bool keepopen; + +void +init_lexer(void) +{ + struct path_list *pl; + debug_decl(init_lexer, SUDO_DEBUG_PARSER) + + while (idepth) { + idepth--; + while ((pl = istack[idepth].more) != NULL) { + istack[idepth].more = pl->next; + efree(pl->path); + efree(pl); + } + efree(istack[idepth].path); + if (idepth && !istack[idepth].keepopen) + fclose(istack[idepth].bs->yy_input_file); + yy_delete_buffer(istack[idepth].bs); + } + efree(istack); + istack = NULL; + istacksize = idepth = 0; + sudolineno = 1; + keepopen = false; + sawspace = false; + continued = false; + prev_state = INITIAL; + + debug_return; +} + +static bool +_push_include(char *path, bool isdir) +{ + struct path_list *pl; + FILE *fp; + debug_decl(_push_include, SUDO_DEBUG_PARSER) + + /* push current state onto stack */ + if (idepth >= istacksize) { + if (idepth > MAX_SUDOERS_DEPTH) { + yyerror(_("too many levels of includes")); + debug_return_bool(false); + } + istacksize += SUDOERS_STACK_INCREMENT; + istack = (struct include_stack *) realloc(istack, + sizeof(*istack) * istacksize); + if (istack == NULL) { + yyerror(_("unable to allocate memory")); + debug_return_bool(false); + } + } + if (isdir) { + struct stat sb; + switch (sudo_secure_dir(path, sudoers_uid, sudoers_gid, &sb)) { + case SUDO_PATH_SECURE: + break; + case SUDO_PATH_MISSING: + debug_return_bool(false); + case SUDO_PATH_BAD_TYPE: + errno = ENOTDIR; + if (sudoers_warnings) { + warning("%s", path); + } + debug_return_bool(false); + case SUDO_PATH_WRONG_OWNER: + if (sudoers_warnings) { + warningx(_("%s is owned by uid %u, should be %u"), + path, (unsigned int) sb.st_uid, + (unsigned int) sudoers_uid); + } + debug_return_bool(false); + case SUDO_PATH_WORLD_WRITABLE: + if (sudoers_warnings) { + warningx(_("%s is world writable"), path); + } + debug_return_bool(false); + case SUDO_PATH_GROUP_WRITABLE: + if (sudoers_warnings) { + warningx(_("%s is owned by gid %u, should be %u"), + path, (unsigned int) sb.st_gid, + (unsigned int) sudoers_gid); + } + debug_return_bool(false); + default: + /* NOTREACHED */ + debug_return_bool(false); + } + if (!(path = switch_dir(&istack[idepth], path))) { + /* switch_dir() called yyerror() for us */ + debug_return_bool(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) + debug_return_bool(false); + path = pl->path; + istack[idepth].more = pl->next; + efree(pl); + } + } else { + if ((fp = open_sudoers(path, true, &keepopen)) == NULL) { + char *errbuf; + if (asprintf(&errbuf, _("%s: %s"), path, strerror(errno)) != -1) { + yyerror(errbuf); + free(errbuf); + } else { + yyerror(_("unable to allocate memory")); + } + debug_return_bool(false); + } + istack[idepth].more = NULL; + } + /* Push the old (current) file and open the new one. */ + istack[idepth].path = sudoers; /* push old path */ + istack[idepth].bs = YY_CURRENT_BUFFER; + istack[idepth].lineno = sudolineno; + istack[idepth].keepopen = keepopen; + idepth++; + sudolineno = 1; + sudoers = path; + yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); + + debug_return_bool(true); +} + +static bool +pop_include(void) +{ + struct path_list *pl; + FILE *fp; + debug_decl(pop_include, SUDO_DEBUG_PARSER) + + if (idepth == 0) + debug_return_bool(false); + + if (!keepopen) + fclose(YY_CURRENT_BUFFER->yy_input_file); + yy_delete_buffer(YY_CURRENT_BUFFER); + /* If we are in an include dir, move to the next file. */ + while ((pl = istack[idepth - 1].more) != NULL) { + fp = open_sudoers(pl->path, false, &keepopen); + if (fp != NULL) { + istack[idepth - 1].more = pl->next; + efree(sudoers); + sudoers = pl->path; + sudolineno = 1; + yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); + efree(pl); + break; + } + /* Unable to open path in include dir, go to next one. */ + istack[idepth - 1].more = pl->next; + efree(pl->path); + efree(pl); + } + /* If no path list, just pop the last dir on the stack. */ + if (pl == NULL) { + idepth--; + yy_switch_to_buffer(istack[idepth].bs); + efree(sudoers); + sudoers = istack[idepth].path; + sudolineno = istack[idepth].lineno; + keepopen = istack[idepth].keepopen; + } + debug_return_bool(true); +} + +static char * +parse_include(char *base) +{ + char *cp, *ep, *path, *pp; + int dirlen = 0, len = 0, subst = 0; + size_t shost_len = 0; + debug_decl(parse_include, SUDO_DEBUG_PARSER) + + /* Pull out path from #include line. */ + cp = base + sizeof("#include"); + if (*cp == 'i') + cp += 3; /* includedir */ + while (isblank((unsigned char) *cp)) + cp++; + ep = cp; + while (*ep != '\0' && !isspace((unsigned char) *ep)) { + if (ep[0] == '%' && ep[1] == 'h') { + shost_len = strlen(user_shost); + len += shost_len - 2; + subst = 1; + } + ep++; + } + + /* Relative paths are located in the same dir as the sudoers file. */ + if (*cp != '/') { + char *dirend = strrchr(sudoers, '/'); + if (dirend != NULL) + dirlen = (int)(dirend - sudoers) + 1; + } + + /* Make a copy of the fully-qualified path and return it. */ + len += (int)(ep - cp); + path = pp = malloc(len + dirlen + 1); + if (path == NULL) { + yyerror(_("unable to allocate memory")); + debug_return_str(NULL); + } + if (dirlen) { + memcpy(path, sudoers, dirlen); + pp += dirlen; + } + if (subst) { + /* substitute for %h */ + while (cp < ep) { + if (cp[0] == '%' && cp[1] == 'h') { + memcpy(pp, user_shost, shost_len); + pp += shost_len; + cp += 2; + continue; + } + *pp++ = *cp++; + } + *pp = '\0'; + } else { + memcpy(pp, cp, len); + pp[len] = '\0'; + } + + /* Push any excess characters (e.g. comment, newline) back to the lexer */ + if (*ep != '\0') + yyless((int)(ep - base)); + + debug_return_str(path); +} + +#ifdef TRACELEXER +static int +sudoers_trace_print(const char *msg) +{ + return fputs(msg, stderr); +} +#else +static int +sudoers_trace_print(const char *msg) +{ + static bool initialized; + static struct lbuf lbuf; + + if (!initialized) { + initialized = true; + lbuf_init(&lbuf, NULL, 0, NULL, 0); + } + + lbuf_append(&lbuf, "%s", msg); + /* XXX - assumes a final newline */ + if (strchr(msg, '\n') != NULL) + { + sudo_debug_printf2(NULL, NULL, 0, SUDO_DEBUG_PARSER|SUDO_DEBUG_DEBUG, + "%s:%d %s", sudoers, sudolineno, lbuf.buf); + lbuf.len = 0; + } + return 0; +} +#endif /* TRACELEXER */ diff --git a/plugins/sudoers/toke_util.c b/plugins/sudoers/toke_util.c new file mode 100644 index 0000000..3302794 --- /dev/null +++ b/plugins/sudoers/toke_util.c @@ -0,0 +1,246 @@ +/* + * 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 "sudoers.h" +#include "parse.h" +#include "toke.h" +#include + +static int arg_len = 0; +static int arg_size = 0; + +static int +hexchar(const char *s) +{ + int i, result = 0; + debug_decl(hexchar, SUDO_DEBUG_PARSER) + + 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++; + } + } + debug_return_int(result); +} + +bool +fill_txt(const char *src, int len, int olen) +{ + char *dst; + debug_decl(fill_txt, SUDO_DEBUG_PARSER) + + dst = olen ? realloc(yylval.string, olen + len + 1) : malloc(len + 1); + if (dst == NULL) { + yyerror(_("unable to allocate memory")); + debug_return_bool(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'; + debug_return_bool(true); +} + +bool +append(const char *src, int len) +{ + int olen = 0; + debug_decl(append, SUDO_DEBUG_PARSER) + + if (yylval.string != NULL) + olen = strlen(yylval.string); + + debug_return_bool(fill_txt(src, len, olen)); +} + +#define SPECIAL(c) \ + ((c) == ',' || (c) == ':' || (c) == '=' || (c) == ' ' || (c) == '\t' || (c) == '#') + +bool +fill_cmnd(const char *src, int len) +{ + char *dst; + int i; + debug_decl(fill_cmnd, SUDO_DEBUG_PARSER) + + arg_len = arg_size = 0; + + dst = yylval.command.cmnd = (char *) malloc(len + 1); + if (yylval.command.cmnd == NULL) { + yyerror(_("unable to allocate memory")); + debug_return_bool(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; + debug_return_bool(true); +} + +bool +fill_args(const char *s, int len, int addspace) +{ + int new_len; + char *p; + debug_decl(fill_args, SUDO_DEBUG_PARSER) + + 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")); + debug_return_bool(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 */ + debug_return_bool(false); + } + arg_len = new_len; + debug_return_bool(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. + */ +bool +ipv6_valid(const char *s) +{ + int nmatch = 0; + debug_decl(ipv6_valid, SUDO_DEBUG_PARSER) + + for (; *s != '\0'; s++) { + if (s[0] == ':' && s[1] == ':') { + if (++nmatch > 1) + break; + } + if (s[0] == '/') + nmatch = 0; /* reset if we hit netmask */ + } + + debug_return_bool(nmatch <= 1); +} diff --git a/plugins/sudoers/tsgetgrpw.c b/plugins/sudoers/tsgetgrpw.c new file mode 100644 index 0000000..7b9ad79 --- /dev/null +++ b/plugins/sudoers/tsgetgrpw.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2005, 2008, 2010-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. + */ + +/* + * Trivial replacements for the libc get{gr,pw}{uid,nam}() routines + * for use by testsudoers in the sudo test harness. + * We need our own since many platforms don't provide set{pw,gr}file(). + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#include +#include + +#include "tsgetgrpw.h" +#include "sudoers.h" + +#ifndef LINE_MAX +# define LINE_MAX 2048 +#endif + +#undef GRMEM_MAX +#define GRMEM_MAX 200 + +static FILE *pwf; +static const char *pwfile = "/etc/passwd"; +static int pw_stayopen; + +static FILE *grf; +static const char *grfile = "/etc/group"; +static int gr_stayopen; + +void setgrfile(const char *); +void setgrent(void); +void endgrent(void); +struct group *getgrent(void); +struct group *getgrnam(const char *); +struct group *getgrgid(gid_t); + +void setpwfile(const char *); +void setpwent(void); +void endpwent(void); +struct passwd *getpwent(void); +struct passwd *getpwnam(const char *); +struct passwd *getpwuid(uid_t); + +void +setpwfile(const char *file) +{ + pwfile = file; + if (pwf != NULL) + endpwent(); +} + +void +setpwent(void) +{ + if (pwf == NULL) { + pwf = fopen(pwfile, "r"); + if (pwf != NULL) + fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC); + } else { + rewind(pwf); + } + pw_stayopen = 1; +} + +void +endpwent(void) +{ + if (pwf != NULL) { + fclose(pwf); + pwf = NULL; + } + pw_stayopen = 0; +} + +struct passwd * +getpwent(void) +{ + static struct passwd pw; + static char pwbuf[LINE_MAX]; + size_t len; + char *cp, *colon; + + if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL) + return NULL; + + zero_bytes(&pw, sizeof(pw)); + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + pw.pw_name = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + pw.pw_passwd = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + pw.pw_uid = atoi(cp); + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + pw.pw_gid = atoi(cp); + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + pw.pw_gecos = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + pw.pw_dir = cp; + pw.pw_shell = colon; + len = strlen(colon); + if (len > 0 && colon[len - 1] == '\n') + colon[len - 1] = '\0'; + return &pw; +} + +struct passwd * +getpwnam(const char *name) +{ + struct passwd *pw; + + if (pwf == NULL) { + if ((pwf = fopen(pwfile, "r")) == NULL) + return NULL; + fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC); + } else { + rewind(pwf); + } + while ((pw = getpwent()) != NULL) { + if (strcmp(pw->pw_name, name) == 0) + break; + } + if (!pw_stayopen) { + fclose(pwf); + pwf = NULL; + } + return pw; +} + +struct passwd * +getpwuid(uid_t uid) +{ + struct passwd *pw; + + if (pwf == NULL) { + if ((pwf = fopen(pwfile, "r")) == NULL) + return NULL; + fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC); + } else { + rewind(pwf); + } + while ((pw = getpwent()) != NULL) { + if (pw->pw_uid == uid) + break; + } + if (!pw_stayopen) { + fclose(pwf); + pwf = NULL; + } + return pw; +} + +void +setgrfile(const char *file) +{ + grfile = file; + if (grf != NULL) + endgrent(); +} + +void +setgrent(void) +{ + if (grf == NULL) { + grf = fopen(grfile, "r"); + if (grf != NULL) + fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); + } else { + rewind(grf); + } + gr_stayopen = 1; +} + +void +endgrent(void) +{ + if (grf != NULL) { + fclose(grf); + grf = NULL; + } + gr_stayopen = 0; +} + +struct group * +getgrent(void) +{ + static struct group gr; + static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1]; + size_t len; + char *cp, *colon; + int n; + + if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL) + return NULL; + + zero_bytes(&gr, sizeof(gr)); + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + gr.gr_name = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + gr.gr_passwd = cp; + if ((colon = strchr(cp = colon, ':')) == NULL) + return NULL; + *colon++ = '\0'; + gr.gr_gid = atoi(cp); + len = strlen(colon); + if (len > 0 && colon[len - 1] == '\n') + colon[len - 1] = '\0'; + if (*colon != '\0') { + gr.gr_mem = gr_mem; + cp = strtok(colon, ","); + for (n = 0; cp != NULL && n < GRMEM_MAX; n++) { + gr.gr_mem[n] = cp; + cp = strtok(NULL, ","); + } + gr.gr_mem[n++] = NULL; + } else + gr.gr_mem = NULL; + return &gr; +} + +struct group * +getgrnam(const char *name) +{ + struct group *gr; + + if (grf == NULL) { + if ((grf = fopen(grfile, "r")) == NULL) + return NULL; + fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); + } else { + rewind(grf); + } + while ((gr = getgrent()) != NULL) { + if (strcmp(gr->gr_name, name) == 0) + break; + } + if (!gr_stayopen) { + fclose(grf); + grf = NULL; + } + return gr; +} + +struct group * +getgrgid(gid_t gid) +{ + struct group *gr; + + if (grf == NULL) { + if ((grf = fopen(grfile, "r")) == NULL) + return NULL; + fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); + } else { + rewind(grf); + } + while ((gr = getgrent()) != NULL) { + if (gr->gr_gid == gid) + break; + } + if (!gr_stayopen) { + fclose(grf); + grf = NULL; + } + return gr; +} diff --git a/plugins/sudoers/tsgetgrpw.h b/plugins/sudoers/tsgetgrpw.h new file mode 100644 index 0000000..5c380c3 --- /dev/null +++ b/plugins/sudoers/tsgetgrpw.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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. + */ + +/* + * Trivial replacements for the libc get{gr,pw}{uid,nam}() routines + * for use by testsudoers in the sudo test harness. + * We need our own since many platforms don't provide set{pw,gr}file(). + */ + +#include + +/* + * Define away the system prototypes so we don't have any conflicts. + */ + +#define setgrfile sys_setgrfile +#define setgrent sys_setgrent +#define endgrent sys_endgrent +#define getgrent sys_getgrent +#define getgrnam sys_getgrnam +#define getgrgid sys_getgrgid + +#define setpwfile sys_setpwfile +#define setpwent sys_setpwent +#define endpwent sys_endpwent +#define getpwent sys_getpwent +#define getpwnam sys_getpwnam +#define getpwuid sys_getpwuid + +#include +#include + +#undef setgrfile +#undef setgrent +#undef endgrent +#undef getgrent +#undef getgrnam +#undef getgrgid + +void setgrfile(const char *); +void setgrent(void); +void endgrent(void); +struct group *getgrent(void); +struct group *getgrnam(const char *); +struct group *getgrgid(gid_t); + +#undef setpwfile +#undef setpwent +#undef endpwent +#undef getpwent +#undef getpwnam +#undef getpwuid + +void setpwfile(const char *); +void setpwent(void); +void endpwent(void); +struct passwd *getpwent(void); +struct passwd *getpwnam(const char *); +struct passwd *getpwuid(uid_t); diff --git a/plugins/sudoers/visudo.c b/plugins/sudoers/visudo.c new file mode 100644 index 0000000..8175b6e --- /dev/null +++ b/plugins/sudoers/visudo.c @@ -0,0 +1,1336 @@ +/* + * Copyright (c) 1996, 1998-2005, 2007-2012 + * 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. + */ + +/* + * Lock the sudoers file for safe editing (ala vipw) and check for parse errors. + */ + +#define _SUDO_MAIN + +#ifdef __TANDEM +# include +#endif + +#include + +#include +#include +#include +#include +#include +#ifndef __TANDEM +# include +#endif +#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 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +#endif +#ifdef HAVE_SETLOCALE +# include +#endif + +#include "sudoers.h" +#include "interfaces.h" +#include "parse.h" +#include "redblack.h" +#include "gettext.h" +#include "sudoers_version.h" +#include "sudo_conf.h" +#include + +struct sudoersfile { + struct sudoersfile *prev, *next; + char *path; + char *tpath; + int fd; + int modified; + int doedit; +}; +TQ_DECLARE(sudoersfile) + +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +/* + * Function prototypes + */ +static void quit(int); +static char *get_args(char *); +static char *get_editor(char **); +static void get_hostname(void); +static int whatnow(void); +static int check_aliases(bool, bool); +static bool check_syntax(char *, bool, bool, bool); +static bool edit_sudoers(struct sudoersfile *, char *, char *, int); +static bool install_sudoers(struct sudoersfile *, bool); +static int print_unused(void *, void *); +static void reparse_sudoers(char *, char *, bool, bool); +static int run_command(char *, char **); +static int visudo_printf(int msg_type, const char *fmt, ...); +static void setup_signals(void); +static void help(void) __attribute__((__noreturn__)); +static void usage(int); + +void cleanup(int); + +extern void yyerror(const char *); +extern void yyrestart(FILE *); + +/* + * External globals exported by the parser + */ +extern struct rbtree *aliases; +extern FILE *yyin; +extern char *sudoers, *errorfile; +extern int errorlineno; +extern bool parse_error; +/* For getopt(3) */ +extern char *optarg; +extern int optind; + +/* + * Globals + */ +struct interface *interfaces; +struct sudo_user sudo_user; +struct passwd *list_pw; +sudo_printf_t sudo_printf = visudo_printf; +static struct sudoersfile_list sudoerslist; +static struct rbtree *alias_freelist; +static bool checkonly; + +int +main(int argc, char *argv[]) +{ + struct sudoersfile *sp; + char *args, *editor, *sudoers_path; + int ch, exitcode = 0; + bool quiet, strict, oldperms; + debug_decl(main, SUDO_DEBUG_MAIN) + +#if defined(SUDO_DEVEL) && defined(__OpenBSD__) + { + extern char *malloc_options; + malloc_options = "AFGJPR"; + } +#endif + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + setprogname(argc > 0 ? argv[0] : "visudo"); +#endif + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + bindtextdomain("sudoers", LOCALEDIR); /* XXX - should have visudo domain */ + textdomain("sudoers"); + + if (argc < 1) + usage(1); + + /* Read sudo.conf. */ + sudo_conf_read(); + + /* + * Arg handling. + */ + checkonly = oldperms = quiet = strict = false; + sudoers_path = _PATH_SUDOERS; + while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) { + switch (ch) { + case 'V': + (void) printf(_("%s version %s\n"), getprogname(), PACKAGE_VERSION); + (void) printf(_("%s grammar version %d\n"), getprogname(), SUDOERS_GRAMMAR_VERSION); + goto done; + case 'c': + checkonly++; /* check mode */ + break; + case 'f': + sudoers_path = optarg; /* sudoers file path */ + oldperms = true; + break; + case 'h': + help(); + break; + case 's': + strict++; /* strict mode */ + break; + case 'q': + quiet++; /* quiet mode */ + break; + default: + usage(1); + } + } + /* There should be no other command line arguments. */ + if (argc - optind != 0) + usage(1); + + sudo_setpwent(); + sudo_setgrent(); + + /* Mock up a fake sudo_user struct. */ + user_cmnd = ""; + if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) + errorx(1, _("you do not exist in the %s database"), "passwd"); + get_hostname(); + + /* Setup defaults data structures. */ + init_defaults(); + + if (checkonly) { + exitcode = check_syntax(sudoers_path, quiet, strict, oldperms) ? 0 : 1; + goto done; + } + + /* + * Parse the existing sudoers file(s) in quiet mode to highlight any + * existing errors and to pull in editor and env_editor conf values. + */ + if ((yyin = open_sudoers(sudoers_path, true, NULL)) == NULL) { + error(1, "%s", sudoers_path); + } + init_parser(sudoers_path, 0); + yyparse(); + (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER); + + editor = get_editor(&args); + + /* Install signal handlers to clean up temp files if we are killed. */ + setup_signals(); + + /* Edit the sudoers file(s) */ + tq_foreach_fwd(&sudoerslist, sp) { + if (!sp->doedit) + continue; + if (sp != tq_first(&sudoerslist)) { + printf(_("press return to edit %s: "), sp->path); + while ((ch = getchar()) != EOF && ch != '\n') + continue; + } + edit_sudoers(sp, editor, args, -1); + } + + /* Check edited files for a parse error and re-edit any that fail. */ + reparse_sudoers(editor, args, strict, quiet); + + /* Install the sudoers temp files as needed. */ + tq_foreach_fwd(&sudoerslist, sp) { + (void) install_sudoers(sp, oldperms); + } + +done: + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); + exit(exitcode); +} + +/* + * List of editors that support the "+lineno" command line syntax. + * If an entry starts with '*' the tail end of the string is matched. + * No other wild cards are supported. + */ +static char *lineno_editors[] = { + "ex", + "nex", + "vi", + "nvi", + "vim", + "elvis", + "*macs", + "mg", + "vile", + "jove", + "pico", + "nano", + "ee", + "joe", + "zile", + NULL +}; + +/* + * Edit each sudoers file. + * Returns true on success, else false. + */ +static bool +edit_sudoers(struct sudoersfile *sp, char *editor, char *args, int lineno) +{ + int tfd; /* sudoers temp file descriptor */ + bool modified; /* was the file modified? */ + int ac; /* argument count */ + char **av; /* argument vector for run_command */ + char *cp; /* scratch char pointer */ + char buf[PATH_MAX*2]; /* buffer used for copying files */ + char linestr[64]; /* string version of lineno */ + struct timeval tv, tv1, tv2; /* time before and after edit */ + struct timeval orig_mtim; /* starting mtime of sudoers file */ + off_t orig_size; /* starting size of sudoers file */ + ssize_t nread; /* number of bytes read */ + struct stat sb; /* stat buffer */ + bool rval = false; /* return value */ + debug_decl(edit_sudoers, SUDO_DEBUG_UTIL) + + if (fstat(sp->fd, &sb) == -1) + error(1, _("unable to stat %s"), sp->path); + orig_size = sb.st_size; + mtim_get(&sb, &orig_mtim); + + /* Create the temp file if needed and set timestamp. */ + if (sp->tpath == NULL) { + easprintf(&sp->tpath, "%s.tmp", sp->path); + tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (tfd < 0) + error(1, "%s", sp->tpath); + + /* Copy sp->path -> sp->tpath and reset the mtime. */ + if (orig_size != 0) { + (void) lseek(sp->fd, (off_t)0, SEEK_SET); + while ((nread = read(sp->fd, buf, sizeof(buf))) > 0) + if (write(tfd, buf, nread) != nread) + error(1, _("write error")); + + /* Add missing newline at EOF if needed. */ + if (nread > 0 && buf[nread - 1] != '\n') { + buf[0] = '\n'; + if (write(tfd, buf, 1) != 1) + error(1, _("write error")); + } + } + (void) close(tfd); + } + (void) touch(-1, sp->tpath, &orig_mtim); + + /* Does the editor support +lineno? */ + if (lineno > 0) + { + char *editor_base = strrchr(editor, '/'); + if (editor_base != NULL) + editor_base++; + else + editor_base = editor; + if (*editor_base == 'r') + editor_base++; + + for (av = lineno_editors; (cp = *av) != NULL; av++) { + /* We only handle a leading '*' wildcard. */ + if (*cp == '*') { + size_t blen = strlen(editor_base); + size_t clen = strlen(++cp); + if (blen >= clen) { + if (strcmp(cp, editor_base + blen - clen) == 0) + break; + } + } else if (strcmp(cp, editor_base) == 0) + break; + } + /* Disable +lineno if editor doesn't support it. */ + if (cp == NULL) + lineno = -1; + } + + /* Find the length of the argument vector */ + ac = 3 + (lineno > 0); + if (args) { + bool wasblank; + + ac++; + for (wasblank = false, cp = args; *cp; cp++) { + if (isblank((unsigned char) *cp)) + wasblank = true; + else if (wasblank) { + wasblank = false; + ac++; + } + } + } + + /* Build up argument vector for the command */ + av = emalloc2(ac, sizeof(char *)); + if ((av[0] = strrchr(editor, '/')) != NULL) + av[0]++; + else + av[0] = editor; + ac = 1; + if (lineno > 0) { + (void) snprintf(linestr, sizeof(linestr), "+%d", lineno); + av[ac++] = linestr; + } + if (args) { + for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t"))) + av[ac++] = cp; + } + av[ac++] = sp->tpath; + av[ac++] = NULL; + + /* + * Do the edit: + * We cannot check the editor's exit value against 0 since + * XPG4 specifies that vi's exit value is a function of the + * number of errors during editing (?!?!). + */ + gettimeofday(&tv1, NULL); + if (run_command(editor, av) != -1) { + gettimeofday(&tv2, NULL); + /* + * Sanity checks. + */ + if (stat(sp->tpath, &sb) < 0) { + warningx(_("unable to stat temporary file (%s), %s unchanged"), + sp->tpath, sp->path); + goto done; + } + if (sb.st_size == 0 && orig_size != 0) { + warningx(_("zero length temporary file (%s), %s unchanged"), + sp->tpath, sp->path); + sp->modified = true; + goto done; + } + } else { + warningx(_("editor (%s) failed, %s unchanged"), editor, sp->path); + goto done; + } + + /* Set modified bit if use changed the file. */ + modified = true; + mtim_get(&sb, &tv); + if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) { + /* + * If mtime and size match but the user spent no measurable + * time in the editor we can't tell if the file was changed. + */ + timevalsub(&tv1, &tv2); + if (timevalisset(&tv2)) + modified = false; + } + + /* + * If modified in this edit session, mark as modified. + */ + if (modified) + sp->modified = modified; + else + warningx(_("%s unchanged"), sp->tpath); + + rval = true; +done: + debug_return_bool(rval); +} + +/* + * Parse sudoers after editing and re-edit any ones that caused a parse error. + */ +static void +reparse_sudoers(char *editor, char *args, bool strict, bool quiet) +{ + struct sudoersfile *sp, *last; + FILE *fp; + int ch; + debug_decl(reparse_sudoers, SUDO_DEBUG_UTIL) + + /* + * Parse the edited sudoers files and do sanity checking + */ + do { + sp = tq_first(&sudoerslist); + last = tq_last(&sudoerslist); + fp = fopen(sp->tpath, "r+"); + if (fp == NULL) + errorx(1, _("unable to re-open temporary file (%s), %s unchanged."), + sp->tpath, sp->path); + + /* Clean slate for each parse */ + init_defaults(); + init_parser(sp->path, quiet); + + /* Parse the sudoers temp file */ + yyrestart(fp); + if (yyparse() && !parse_error) { + warningx(_("unabled to parse temporary file (%s), unknown error"), + sp->tpath); + parse_error = true; + errorfile = sp->path; + } + fclose(yyin); + if (!parse_error) { + if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER) || + check_aliases(strict, quiet) != 0) { + parse_error = true; + errorfile = sp->path; + } + } + + /* + * Got an error, prompt the user for what to do now + */ + if (parse_error) { + switch (whatnow()) { + case 'Q' : parse_error = false; /* ignore parse error */ + break; + case 'x' : /* XXX - should return instead of exiting */ + cleanup(0); + sudo_debug_exit_int(__func__, __FILE__, + __LINE__, sudo_debug_subsys, 0); + exit(0); + break; + } + } + if (parse_error) { + /* Edit file with the parse error */ + tq_foreach_fwd(&sudoerslist, sp) { + if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { + edit_sudoers(sp, editor, args, errorlineno); + break; + } + } + if (sp == NULL) { + errorx(1, _("internal error, unable to find %s in list!"), + sudoers); + } + } + + /* If any new #include directives were added, edit them too. */ + for (sp = last->next; sp != NULL; sp = sp->next) { + printf(_("press return to edit %s: "), sp->path); + while ((ch = getchar()) != EOF && ch != '\n') + continue; + edit_sudoers(sp, editor, args, errorlineno); + } + } while (parse_error); + + debug_return; +} + +/* + * Set the owner and mode on a sudoers temp file and + * move it into place. Returns true on success, else false. + */ +static bool +install_sudoers(struct sudoersfile *sp, bool oldperms) +{ + struct stat sb; + bool rval = false; + debug_decl(install_sudoers, SUDO_DEBUG_UTIL) + + if (!sp->modified) { + /* + * No changes but fix owner/mode if needed. + */ + (void) unlink(sp->tpath); + if (!oldperms && fstat(sp->fd, &sb) != -1) { + if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) + ignore_result(chown(sp->path, SUDOERS_UID, SUDOERS_GID)); + if ((sb.st_mode & 0777) != SUDOERS_MODE) + ignore_result(chmod(sp->path, SUDOERS_MODE)); + } + rval = true; + goto done; + } + + /* + * Change mode and ownership of temp file so when + * we move it to sp->path things are kosher. + */ + if (oldperms) { + /* Use perms of the existing file. */ + if (fstat(sp->fd, &sb) == -1) + error(1, _("unable to stat %s"), sp->path); + if (chown(sp->tpath, sb.st_uid, sb.st_gid) != 0) { + warning(_("unable to set (uid, gid) of %s to (%u, %u)"), + sp->tpath, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid); + } + if (chmod(sp->tpath, sb.st_mode & 0777) != 0) { + warning(_("unable to change mode of %s to 0%o"), sp->tpath, + (unsigned int)(sb.st_mode & 0777)); + } + } else { + if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) { + warning(_("unable to set (uid, gid) of %s to (%u, %u)"), + sp->tpath, SUDOERS_UID, SUDOERS_GID); + goto done; + } + if (chmod(sp->tpath, SUDOERS_MODE) != 0) { + warning(_("unable to change mode of %s to 0%o"), sp->tpath, + SUDOERS_MODE); + goto done; + } + } + + /* + * Now that sp->tpath is sane (parses ok) it needs to be + * rename(2)'d to sp->path. If the rename(2) fails we try using + * mv(1) in case sp->tpath and sp->path are on different file systems. + */ + if (rename(sp->tpath, sp->path) == 0) { + efree(sp->tpath); + sp->tpath = NULL; + } else { + if (errno == EXDEV) { + char *av[4]; + warningx(_("%s and %s not on the same file system, using mv to rename"), + sp->tpath, sp->path); + + /* Build up argument vector for the command */ + if ((av[0] = strrchr(_PATH_MV, '/')) != NULL) + av[0]++; + else + av[0] = _PATH_MV; + av[1] = sp->tpath; + av[2] = sp->path; + av[3] = NULL; + + /* And run it... */ + if (run_command(_PATH_MV, av)) { + warningx(_("command failed: '%s %s %s', %s unchanged"), + _PATH_MV, sp->tpath, sp->path, sp->path); + (void) unlink(sp->tpath); + efree(sp->tpath); + sp->tpath = NULL; + goto done; + } + efree(sp->tpath); + sp->tpath = NULL; + } else { + warning(_("error renaming %s, %s unchanged"), sp->tpath, sp->path); + (void) unlink(sp->tpath); + goto done; + } + } + rval = true; +done: + debug_return_bool(rval); +} + +/* STUB */ +void +set_fqdn(void) +{ + return; +} + +/* STUB */ +void +init_envtables(void) +{ + return; +} + +/* STUB */ +bool +user_is_exempt(void) +{ + return false; +} + +/* STUB */ +void +sudo_setspent(void) +{ + return; +} + +/* STUB */ +void +sudo_endspent(void) +{ + return; +} + +/* STUB */ +int +group_plugin_query(const char *user, const char *group, const struct passwd *pw) +{ + return false; +} + +/* + * Assuming a parse error occurred, prompt the user for what they want + * to do now. Returns the first letter of their choice. + */ +static int +whatnow(void) +{ + int choice, c; + debug_decl(whatnow, SUDO_DEBUG_UTIL) + + for (;;) { + (void) fputs(_("What now? "), stdout); + choice = getchar(); + for (c = choice; c != '\n' && c != EOF;) + c = getchar(); + + switch (choice) { + case EOF: + choice = 'x'; + /* FALLTHROUGH */ + case 'e': + case 'x': + case 'Q': + debug_return_int(choice); + default: + (void) puts(_("Options are:\n" + " (e)dit sudoers file again\n" + " e(x)it without saving changes to sudoers file\n" + " (Q)uit and save changes to sudoers file (DANGER!)\n")); + } + } +} + +/* + * Install signal handlers for visudo. + */ +static void +setup_signals(void) +{ + sigaction_t sa; + debug_decl(setup_signals, SUDO_DEBUG_UTIL) + + /* + * Setup signal handlers to cleanup nicely. + */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = quit; + (void) sigaction(SIGTERM, &sa, NULL); + (void) sigaction(SIGHUP, &sa, NULL); + (void) sigaction(SIGINT, &sa, NULL); + (void) sigaction(SIGQUIT, &sa, NULL); + + debug_return; +} + +static int +run_command(char *path, char **argv) +{ + int status; + pid_t pid, rv; + debug_decl(run_command, SUDO_DEBUG_UTIL) + + switch (pid = sudo_debug_fork()) { + case -1: + error(1, _("unable to execute %s"), path); + break; /* NOTREACHED */ + case 0: + sudo_endpwent(); + sudo_endgrent(); + closefrom(STDERR_FILENO + 1); + execv(path, argv); + warning(_("unable to run %s"), path); + _exit(127); + break; /* NOTREACHED */ + } + + do { + rv = waitpid(pid, &status, 0); + } while (rv == -1 && errno == EINTR); + + if (rv != -1) + rv = WIFEXITED(status) ? WEXITSTATUS(status) : -1; + debug_return_int(rv); +} + +static bool +check_owner(const char *path, bool quiet) +{ + struct stat sb; + bool ok = true; + debug_decl(check_owner, SUDO_DEBUG_UTIL) + + if (stat(path, &sb) == 0) { + if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) { + ok = false; + if (!quiet) { + fprintf(stderr, + _("%s: wrong owner (uid, gid) should be (%u, %u)\n"), + path, SUDOERS_UID, SUDOERS_GID); + } + } + if ((sb.st_mode & 07777) != SUDOERS_MODE) { + ok = false; + if (!quiet) { + fprintf(stderr, _("%s: bad permissions, should be mode 0%o\n"), + path, SUDOERS_MODE); + } + } + } + debug_return_bool(ok); +} + +static bool +check_syntax(char *sudoers_path, bool quiet, bool strict, bool oldperms) +{ + bool ok = false; + debug_decl(check_syntax, SUDO_DEBUG_UTIL) + + 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); + goto done; + } + init_parser(sudoers_path, quiet); + if (yyparse() && !parse_error) { + if (!quiet) + warningx(_("failed to parse %s file, unknown error"), sudoers_path); + parse_error = true; + errorfile = sudoers_path; + } + if (!parse_error && check_aliases(strict, quiet) != 0) { + parse_error = true; + errorfile = sudoers_path; + } + ok = !parse_error; + + if (parse_error) { + if (!quiet) { + if (errorlineno != -1) + (void) printf(_("parse error in %s near line %d\n"), + errorfile, errorlineno); + else + (void) printf(_("parse error in %s\n"), errorfile); + } + } else { + struct sudoersfile *sp; + + /* Parsed OK, check mode and owner. */ + if (oldperms || check_owner(sudoers_path, quiet)) + (void) printf(_("%s: parsed OK\n"), sudoers_path); + else + ok = false; + tq_foreach_fwd(&sudoerslist, sp) { + if (oldperms || check_owner(sp->path, quiet)) + (void) printf(_("%s: parsed OK\n"), sp->path); + else + ok = false; + } + } + +done: + debug_return_bool(ok); +} + +/* + * Used to open (and lock) the initial sudoers file and to also open + * any subsequent files #included via a callback from the parser. + */ +FILE * +open_sudoers(const char *path, bool doedit, bool *keepopen) +{ + struct sudoersfile *entry; + FILE *fp; + int open_flags; + debug_decl(open_sudoers, SUDO_DEBUG_UTIL) + + if (checkonly) + open_flags = O_RDONLY; + else + open_flags = O_RDWR | O_CREAT; + + /* Check for existing entry */ + tq_foreach_fwd(&sudoerslist, entry) { + if (strcmp(path, entry->path) == 0) + break; + } + if (entry == NULL) { + entry = ecalloc(1, sizeof(*entry)); + entry->path = estrdup(path); + /* entry->modified = 0; */ + entry->prev = entry; + /* entry->next = NULL; */ + entry->fd = open(entry->path, open_flags, SUDOERS_MODE); + /* entry->tpath = NULL; */ + entry->doedit = doedit; + if (entry->fd == -1) { + warning("%s", entry->path); + efree(entry); + debug_return_ptr(NULL); + } + if (!checkonly && !lock_file(entry->fd, SUDO_TLOCK)) + errorx(1, _("%s busy, try again later"), entry->path); + if ((fp = fdopen(entry->fd, "r")) == NULL) + error(1, "%s", entry->path); + tq_append(&sudoerslist, entry); + } else { + /* Already exists, open .tmp version if there is one. */ + if (entry->tpath != NULL) { + if ((fp = fopen(entry->tpath, "r")) == NULL) + error(1, "%s", entry->tpath); + } else { + if ((fp = fdopen(entry->fd, "r")) == NULL) + error(1, "%s", entry->path); + rewind(fp); + } + } + if (keepopen != NULL) + *keepopen = true; + debug_return_ptr(fp); +} + +static char * +get_editor(char **args) +{ + char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs; + debug_decl(get_editor, SUDO_DEBUG_UTIL) + + /* + * Check VISUAL and EDITOR environment variables to see which editor + * the user wants to use (we may not end up using it though). + * If the path is not fully-qualified, make it so and check that + * the specified executable actually exists. + */ + UserEditorArgs = NULL; + if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0') + UserEditor = getenv("EDITOR"); + if (UserEditor && *UserEditor == '\0') + UserEditor = NULL; + else if (UserEditor) { + UserEditorArgs = get_args(UserEditor); + if (find_path(UserEditor, &Editor, NULL, getenv("PATH"), 0) == FOUND) { + UserEditor = Editor; + } else { + if (def_env_editor) { + /* If we are honoring $EDITOR this is a fatal error. */ + errorx(1, _("specified editor (%s) doesn't exist"), UserEditor); + } else { + /* Otherwise, just ignore $EDITOR. */ + UserEditor = NULL; + } + } + } + + /* + * See if we can use the user's choice of editors either because + * we allow any $EDITOR or because $EDITOR is in the allowable list. + */ + Editor = EditorArgs = EditorPath = NULL; + if (def_env_editor && UserEditor) { + Editor = UserEditor; + EditorArgs = UserEditorArgs; + } else if (UserEditor) { + struct stat editor_sb; + struct stat user_editor_sb; + char *base, *userbase; + + if (stat(UserEditor, &user_editor_sb) != 0) { + /* Should never happen since we already checked above. */ + error(1, _("unable to stat editor (%s)"), UserEditor); + } + EditorPath = estrdup(def_editor); + Editor = strtok(EditorPath, ":"); + do { + EditorArgs = get_args(Editor); + /* + * Both Editor and UserEditor should be fully qualified but + * check anyway... + */ + if ((base = strrchr(Editor, '/')) == NULL) + continue; + if ((userbase = strrchr(UserEditor, '/')) == NULL) { + Editor = NULL; + break; + } + base++, userbase++; + + /* + * We compare the basenames first and then use stat to match + * for sure. + */ + if (strcmp(base, userbase) == 0) { + if (stat(Editor, &editor_sb) == 0 && S_ISREG(editor_sb.st_mode) + && (editor_sb.st_mode & 0000111) && + editor_sb.st_dev == user_editor_sb.st_dev && + editor_sb.st_ino == user_editor_sb.st_ino) + break; + } + } while ((Editor = strtok(NULL, ":"))); + } + + /* + * Can't use $EDITOR, try each element of def_editor until we + * find one that exists, is regular, and is executable. + */ + if (Editor == NULL || *Editor == '\0') { + efree(EditorPath); + EditorPath = estrdup(def_editor); + Editor = strtok(EditorPath, ":"); + do { + EditorArgs = get_args(Editor); + if (sudo_goodpath(Editor, NULL)) + break; + } while ((Editor = strtok(NULL, ":"))); + + /* Bleah, none of the editors existed! */ + if (Editor == NULL || *Editor == '\0') + errorx(1, _("no editor found (editor path = %s)"), def_editor); + } + *args = EditorArgs; + debug_return_str(Editor); +} + +/* + * Split out any command line arguments and return them. + */ +static char * +get_args(char *cmnd) +{ + char *args; + debug_decl(get_args, SUDO_DEBUG_UTIL) + + args = cmnd; + while (*args && !isblank((unsigned char) *args)) + args++; + if (*args) { + *args++ = '\0'; + while (*args && isblank((unsigned char) *args)) + args++; + } + debug_return_str(*args ? args : NULL); +} + +/* + * Look up the hostname and set user_host and user_shost. + */ +static void +get_hostname(void) +{ + char *p, thost[MAXHOSTNAMELEN + 1]; + debug_decl(get_hostname, SUDO_DEBUG_UTIL) + + if (gethostname(thost, sizeof(thost)) != -1) { + thost[sizeof(thost) - 1] = '\0'; + user_host = estrdup(thost); + + if ((p = strchr(user_host, '.'))) { + *p = '\0'; + user_shost = estrdup(user_host); + *p = '.'; + } else { + user_shost = user_host; + } + } else { + user_host = user_shost = "localhost"; + } + debug_return; +} + +static bool +alias_remove_recursive(char *name, int type) +{ + struct member *m; + struct alias *a; + bool rval = true; + debug_decl(alias_remove_recursive, SUDO_DEBUG_ALIAS) + + if ((a = alias_find(name, type)) != NULL) { + tq_foreach_fwd(&a->members, m) { + if (m->type == ALIAS) { + if (!alias_remove_recursive(m->name, type)) + rval = false; + } + } + } + alias_seqno++; + a = alias_remove(name, type); + if (a) + rbinsert(alias_freelist, a); + debug_return_bool(rval); +} + +static int +check_alias(char *name, int type, int strict, int quiet) +{ + struct member *m; + struct alias *a; + int errors = 0; + debug_decl(check_alias, SUDO_DEBUG_ALIAS) + + if ((a = alias_find(name, type)) != NULL) { + /* check alias contents */ + tq_foreach_fwd(&a->members, m) { + if (m->type == ALIAS) + errors += check_alias(m->name, type, strict, quiet); + } + } else { + if (!quiet) { + char *fmt; + if (errno == ELOOP) { + fmt = strict ? + _("Error: cycle in %s_Alias `%s'") : + _("Warning: cycle in %s_Alias `%s'"); + } else { + fmt = strict ? + _("Error: %s_Alias `%s' referenced but not defined") : + _("Warning: %s_Alias `%s' referenced but not defined"); + } + warningx(fmt, + type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" : + type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : + "Unknown", name); + } + errors++; + } + + debug_return_int(errors); +} + +/* + * Iterate through the sudoers datastructures looking for undefined + * aliases or unused aliases. + */ +static int +check_aliases(bool strict, bool quiet) +{ + struct cmndspec *cs; + struct member *m, *binding; + struct privilege *priv; + struct userspec *us; + struct defaults *d; + int atype, errors = 0; + debug_decl(check_aliases, SUDO_DEBUG_ALIAS) + + alias_freelist = rbcreate(alias_compare); + + /* Forward check. */ + tq_foreach_fwd(&userspecs, us) { + tq_foreach_fwd(&us->users, m) { + if (m->type == ALIAS) { + alias_seqno++; + errors += check_alias(m->name, USERALIAS, strict, quiet); + } + } + tq_foreach_fwd(&us->privileges, priv) { + tq_foreach_fwd(&priv->hostlist, m) { + if (m->type == ALIAS) { + alias_seqno++; + errors += check_alias(m->name, HOSTALIAS, strict, quiet); + } + } + tq_foreach_fwd(&priv->cmndlist, cs) { + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m->type == ALIAS) { + alias_seqno++; + errors += check_alias(m->name, RUNASALIAS, strict, quiet); + } + } + if ((m = cs->cmnd)->type == ALIAS) { + alias_seqno++; + errors += check_alias(m->name, CMNDALIAS, strict, quiet); + } + } + } + } + + /* Reverse check (destructive) */ + tq_foreach_fwd(&userspecs, us) { + tq_foreach_fwd(&us->users, m) { + if (m->type == ALIAS) { + alias_seqno++; + if (!alias_remove_recursive(m->name, USERALIAS)) + errors++; + } + } + tq_foreach_fwd(&us->privileges, priv) { + tq_foreach_fwd(&priv->hostlist, m) { + if (m->type == ALIAS) { + alias_seqno++; + if (!alias_remove_recursive(m->name, HOSTALIAS)) + errors++; + } + } + tq_foreach_fwd(&priv->cmndlist, cs) { + tq_foreach_fwd(&cs->runasuserlist, m) { + if (m->type == ALIAS) { + alias_seqno++; + if (!alias_remove_recursive(m->name, RUNASALIAS)) + errors++; + } + } + if ((m = cs->cmnd)->type == ALIAS) { + alias_seqno++; + if (!alias_remove_recursive(m->name, CMNDALIAS)) + errors++; + } + } + } + } + tq_foreach_fwd(&defaults, d) { + switch (d->type) { + case DEFAULTS_HOST: + atype = HOSTALIAS; + break; + case DEFAULTS_USER: + atype = USERALIAS; + break; + case DEFAULTS_RUNAS: + atype = RUNASALIAS; + break; + case DEFAULTS_CMND: + atype = CMNDALIAS; + break; + default: + continue; /* not an alias */ + } + tq_foreach_fwd(&d->binding, binding) { + for (m = binding; m != NULL; m = m->next) { + if (m->type == ALIAS) { + alias_seqno++; + if (!alias_remove_recursive(m->name, atype)) + errors++; + } + } + } + } + rbdestroy(alias_freelist, alias_free); + + /* If all aliases were referenced we will have an empty tree. */ + if (!no_aliases() && !quiet) + alias_apply(print_unused, strict ? "Error" : "Warning"); + + debug_return_int(strict ? errors : 0); +} + +static int +print_unused(void *v1, void *v2) +{ + struct alias *a = (struct alias *)v1; + char *prefix = (char *)v2; + + warningx2(_("%s: unused %s_Alias %s"), prefix, + a->type == HOSTALIAS ? "Host" : a->type == CMNDALIAS ? "Cmnd" : + a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" : + "Unknown", a->name); + return 0; +} + +/* + * Unlink any sudoers temp files that remain. + */ +void +cleanup(int gotsignal) +{ + struct sudoersfile *sp; + + tq_foreach_fwd(&sudoerslist, sp) { + if (sp->tpath != NULL) + (void) unlink(sp->tpath); + } + if (!gotsignal) { + sudo_endpwent(); + sudo_endgrent(); + } +} + +/* + * Unlink sudoers temp files (if any) and exit. + */ +static void +quit(int signo) +{ + const char *signame, *myname; + + cleanup(signo); +#define emsg " exiting due to signal: " + myname = getprogname(); + signame = strsignal(signo); + ignore_result(write(STDERR_FILENO, myname, strlen(myname))); + ignore_result(write(STDERR_FILENO, emsg, sizeof(emsg) - 1)); + ignore_result(write(STDERR_FILENO, signame, strlen(signame))); + ignore_result(write(STDERR_FILENO, "\n", 1)); + _exit(signo); +} + +static void +usage(int fatal) +{ + (void) fprintf(fatal ? stderr : stdout, + "usage: %s [-chqsV] [-f sudoers]\n", getprogname()); + if (fatal) + exit(1); +} + +static void +help(void) +{ + (void) printf(_("%s - safely edit the sudoers file\n\n"), getprogname()); + usage(0); + (void) puts(_("\nOptions:\n" + " -c check-only mode\n" + " -f sudoers specify sudoers file location\n" + " -h display help message and exit\n" + " -q less verbose (quiet) syntax error messages\n" + " -s strict syntax checking\n" + " -V display version information and exit")); + exit(0); +} + +static int +visudo_printf(int msg_type, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + + switch (msg_type) { + case SUDO_CONV_INFO_MSG: + fp = stdout; + break; + case SUDO_CONV_ERROR_MSG: + fp = stderr; + break; + default: + errno = EINVAL; + return -1; + } + + va_start(ap, fmt); + vfprintf(fp, fmt, ap); + va_end(ap); + + return 0; +} diff --git a/plugins/system_group/Makefile.in b/plugins/system_group/Makefile.in new file mode 100644 index 0000000..0146c20 --- /dev/null +++ b/plugins/system_group/Makefile.in @@ -0,0 +1,127 @@ +# +# Copyright (c) 2011-2012 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ @LT_STATIC@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Libraries +LT_LIBS = $(LIBOBJDIR)libreplace.la +LIBS = $(LT_LIBS) + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(top_srcdir) @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# Flags to pass to the link stage +LDFLAGS = @LDFLAGS@ +LTLDFLAGS = @LTLDFLAGS@ + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localstatedir = @localstatedir@ +plugindir = @PLUGINDIR@ +soext = @SOEXT@ + +# OS dependent defines +DEFS = @OSDEFS@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +OBJS = system_group.lo + +LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/ + +VERSION = @PACKAGE_VERSION@ + +all: system_group.la + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file plugins/system_group/Makefile) + +.SUFFIXES: .o .c .h .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +system_group.la: $(OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(LTLDFLAGS) -o $@ $(OBJS) $(LIBS) -module -export-symbols $(srcdir)/system_group.sym -avoid-version -rpath $(plugindir) + +pre-install: + +install: install-plugin + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(plugindir) + +install-binaries: + +install-includes: + +install-doc: + +install-plugin: install-dirs system_group.la + $(INSTALL) -b~ -m 0755 .libs/system_group$(soext) $(DESTDIR)$(plugindir) + +uninstall: + -rm -f $(DESTDIR)$(plugindir)/system_group$(soext) + +check: + +clean: + -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +system_group.lo: $(srcdir)/system_group.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(top_srcdir)/compat/dlfcn.h \ + $(incdir)/sudo_plugin.h $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/system_group.c diff --git a/plugins/system_group/system_group.c b/plugins/system_group/system_group.c new file mode 100644 index 0000000..f4343f0 --- /dev/null +++ b/plugins/system_group/system_group.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2010, 2012 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. + */ + +#include + +#include +#include +#include + +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif /* STDC_HEADERS */ +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ +#ifdef HAVE_STRING_H +# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) +# include +# endif +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#ifdef HAVE_DLOPEN +# include +#else +# include "compat/dlfcn.h" +#endif +#include +#include +#include +#include +#include +#include + +#include "sudo_plugin.h" +#include "missing.h" + +#ifndef RTLD_DEFAULT +# define RTLD_DEFAULT NULL +#endif + +/* + * Sudoers group plugin that does group name-based lookups using the system + * group database functions, similar to how sudo behaved prior to 1.7.3. + * This can be used on systems where lookups by group ID are problematic. + */ + +static sudo_printf_t sudo_log; + +typedef struct group * (*sysgroup_getgrnam_t)(const char *); +typedef struct group * (*sysgroup_getgrgid_t)(gid_t); +typedef void (*sysgroup_gr_delref_t)(struct group *); + +static sysgroup_getgrnam_t sysgroup_getgrnam; +static sysgroup_getgrgid_t sysgroup_getgrgid; +static sysgroup_gr_delref_t sysgroup_gr_delref; +static bool need_setent; + +static int +sysgroup_init(int version, sudo_printf_t sudo_printf, char *const argv[]) +{ + void *handle; + + sudo_log = sudo_printf; + + if (GROUP_API_VERSION_GET_MAJOR(version) != GROUP_API_VERSION_MAJOR) { + sudo_log(SUDO_CONV_ERROR_MSG, + "sysgroup_group: incompatible major version %d, expected %d\n", + GROUP_API_VERSION_GET_MAJOR(version), + GROUP_API_VERSION_MAJOR); + return -1; + } + + /* Share group cache with sudo if possible. */ + handle = dlsym(RTLD_DEFAULT, "sudo_getgrnam"); + if (handle != NULL) { + sysgroup_getgrnam = (sysgroup_getgrnam_t)handle; + } else { + sysgroup_getgrnam = (sysgroup_getgrnam_t)getgrnam; + need_setent = true; + } + + handle = dlsym(RTLD_DEFAULT, "sudo_getgrgid"); + if (handle != NULL) { + sysgroup_getgrgid = (sysgroup_getgrgid_t)handle; + } else { + sysgroup_getgrgid = (sysgroup_getgrgid_t)getgrgid; + need_setent = true; + } + + handle = dlsym(RTLD_DEFAULT, "gr_delref"); + if (handle != NULL) + sysgroup_gr_delref = (sysgroup_gr_delref_t)handle; + + if (need_setent) + setgrent(); + + return true; +} + +static void +sysgroup_cleanup(void) +{ + if (need_setent) + endgrent(); +} + +/* + * Returns true if "user" is a member of "group", else false. + */ +static int +sysgroup_query(const char *user, const char *group, const struct passwd *pwd) +{ + char **member, *ep = '\0'; + struct group *grp; + + grp = sysgroup_getgrnam(group); + if (grp == NULL && group[0] == '#' && group[1] != '\0') { + long lval = strtol(group + 1, &ep, 10); + if (*ep == '\0') { + if ((lval != LONG_MAX && lval != LONG_MIN) || errno != ERANGE) + grp = sysgroup_getgrgid((gid_t)lval); + } + } + if (grp != NULL) { + for (member = grp->gr_mem; *member != NULL; member++) { + if (strcasecmp(user, *member) == 0) { + if (sysgroup_gr_delref) + sysgroup_gr_delref(grp); + return true; + } + } + if (sysgroup_gr_delref) + sysgroup_gr_delref(grp); + } + + return false; +} + +struct sudoers_group_plugin group_plugin = { + GROUP_API_VERSION, + sysgroup_init, + sysgroup_cleanup, + sysgroup_query +}; diff --git a/plugins/system_group/system_group.sym b/plugins/system_group/system_group.sym new file mode 100644 index 0000000..a859d6c --- /dev/null +++ b/plugins/system_group/system_group.sym @@ -0,0 +1 @@ +group_plugin diff --git a/pp b/pp index a997c0f..76b4d6e 100755 --- a/pp +++ b/pp @@ -1,7 +1,7 @@ #!/bin/sh -# (c) 2010 Quest Software, Inc. All rights reserved -pp_revision="283" - # Copyright 2010 Quest Software, Inc. All rights reserved. +# Copyright 2012 Quest Software, Inc. ALL RIGHTS RESERVED +pp_revision="355" + # Copyright 2012 Quest Software, Inc. ALL RIGHTS RESERVED. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -31,7 +31,7 @@ pp_revision="283" # Please see for more information pp_version="1.0.0.$pp_revision" -pp_copyright="Copyright 2010, Quest Software, Inc. All rights reserved." +pp_copyright="Copyright 2012, Quest Software, Inc. ALL RIGHTS RESERVED." pp_opt_debug=false pp_opt_destdir="$DESTDIR" @@ -438,7 +438,7 @@ pp_unique () { pp_mode_strip_altaccess () { case "$1" in - ??????????+) + ??????????[+.]) echo `echo "$1" | cut -b -10`;; *) echo "$1";; @@ -802,7 +802,7 @@ pp_frontend_init () { version= summary="no summary" description="No description" - copyright="Copyright 2010 Quest Software, Inc. All rights reserved." + copyright="Copyright 2012 Quest Software, Inc. ALL RIGHTS RESERVED." #-- if the user supplied extra arguments on the command line # then load them now. @@ -961,7 +961,7 @@ pp_frontend () { fi test $# -eq 0 || pp_warn "ignoring extra arguments: $line" continue;; - %pre|%post|%preun|%postup|%postun|%files|%depend|%check) + %pre|%post|%preun|%postup|%postun|%files|%depend|%check|%conflict) pp_debug "processing new component section $*" s="$1"; shift if test $# -eq 0 || pp_is_qualifier "$1"; then @@ -1056,7 +1056,7 @@ pp_frontend () { . $pp_wrkdir/tmp : > $pp_wrkdir/tmp ;; - %pre.*|%preun.*|%post.*|%postup.*|%postun.*|%depend.*|%check.*|%service.*|%fixup) + %pre.*|%preun.*|%post.*|%postup.*|%postun.*|%depend.*|%check.*|%conflict.*|%service.*|%fixup) pp_debug "leaving $section: substituting $pp_wrkdir/tmp" # cat $pp_wrkdir/tmp >&2 # debugging $pp_opt_debug && pp_substitute < $pp_wrkdir/tmp >&2 @@ -1092,6 +1092,10 @@ pp_frontend () { pp_debug "Adding explicit dependency $@ to $cpt" echo "$@" >> $pp_wrkdir/%depend.$cpt ;; + %conflict.*) + pp_debug "Adding explicit conflict $@ to $cpt" + echo "$@" >> $pp_wrkdir/%conflict.$cpt + ;; esac done exec <&- @@ -1554,6 +1558,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 @@ -1589,7 +1595,7 @@ pp_aix_detect_os () { pp_aix_version_fix () { typeset v - v=`echo $1 | tr -c -d '[0-9].\012'` + v=`echo $1 | sed 's/[-+]/./' | tr -c -d '[0-9].\012' | awk -F"." '{ printf "%d.%d.%d.%.4s\n", $1, $2, $3, $4 }' | sed 's/[.]*$//g'` if test x"$v" != x"$1"; then pp_warn "stripped version '$1' to '$v'" fi @@ -1688,8 +1694,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 @@ -1757,7 +1761,7 @@ pp_aix_add_service () { set -- $cmd cmd_cmd="$1"; shift - cmd_arg="$pp_aix_mkssys_cmd_args"; + cmd_arg="${pp_aix_mkssys_cmd_args:-$*}"; case "$stop_signal" in HUP) stop_signal=1;; @@ -1787,11 +1791,12 @@ pp_aix_add_service () { cat <<-. >> $pp_wrkdir/%post.$svc svc=$svc uid=0 -cmd_cmd=$daemon +cmd_cmd="$cmd_cmd" cmd_arg="$cmd_arg" stop_signal=$stop_signal force_signal=9 srcgroup="$pp_aix_mkssys_group" +instances_allowed=${pp_aix_mkssys_instances_allowed:--Q} lssrc -s \$svc > /dev/null 2>&1 if [ \$? -eq 0 ]; then @@ -1802,13 +1807,14 @@ if [ \$? -eq 0 ]; then rmsys -s \$svc > /dev/null 2>&1 fi -mkssys -s \$svc -u \$uid -p "\$cmd_cmd" \${cmd_arg:+-a "\$cmd_arg"} -S -n \$stop_signal -f 9 ${pp_aix_mkssys_args} \${srcgroup:+-G \$srcgroup} +mkssys -s \$svc -u \$uid -p "\$cmd_cmd" \${cmd_arg:+-a "\$cmd_arg"} -S -n \$stop_signal -f 9 ${pp_aix_mkssys_args} \${srcgroup:+-G \$srcgroup} \$instances_allowed . #-- add code to start the service on reboot ${pp_aix_init_services_after_install} && cat <<-. >> $pp_wrkdir/%post.$svc -mkitab "\$svc:2:once:/usr/bin/startsrc -s \$svc" > /dev/null 2>&1 +id=\`echo "\$svc" | cut -c1-14\` +mkitab "\$id:2:once:/usr/bin/startsrc -s \$svc" > /dev/null 2>&1 . ${pp_aix_start_services_after_install} && @@ -1824,7 +1830,7 @@ mv $pp_wrkdir/%post.$svc $pp_wrkdir/%post.run ${pp_aix_init_services_after_install} && pp_prepend $pp_wrkdir/%preun.$svc <<-. -rmitab $svc +rmitab `echo "$svc" | cut -c1-14` > /dev/null 2>&1 . pp_prepend $pp_wrkdir/%preun.$svc <<-. stopsrc -s $svc >/dev/null 2>&1 @@ -1891,6 +1897,7 @@ pp_backend_aix () { -o -s $pp_wrkdir/%pre.$cmp \ -o -s $pp_wrkdir/%post.$cmp \ -o -s $pp_wrkdir/%preun.$cmp \ + -o -s $pp_wrkdir/%postun.$cmp \ -o -s $pp_wrkdir/%check.$cmp then content=B @@ -1906,7 +1913,7 @@ pp_backend_aix () { bosboot=N; pp_contains_any "$pp_aix_bosboot" $cmp && bosboot=b echo $pp_aix_bff_name.$ex \ - ${pp_aix_version:-`pp_aix_version_fix "$version"`} \ + `[ $pp_aix_version ] && pp_aix_version_fix $pp_aix_version || pp_aix_version_fix "$version"` \ 1 $bosboot $content \ $pp_aix_lang "$summary $briefex" echo "[" @@ -1965,6 +1972,11 @@ pp_backend_aix () { < $pp_wrkdir/%preun.$cmp fi + if test -r $pp_wrkdir/%postun.$cmp; then + pp_aix_make_script $root_wrkdir/$pp_aix_bff_name.$ex.unpre_i \ + < $pp_wrkdir/%postun.$cmp + fi + # remove empty files for f in $user_wrkdir/$pp_aix_bff_name.$ex.* $root_wrkdir/$pp_aix_bff_name.$ex.*; do if test ! -s "$f"; then @@ -2043,7 +2055,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 () { @@ -2051,7 +2063,7 @@ pp_backend_aix_cleanup () { } pp_backend_aix_names () { - echo "$name.${pp_aix_version:-`pp_aix_version_fix "$version"`}.bff" + echo "$name.`[ $pp_aix_version ] && pp_aix_version_fix $pp_aix_version || pp_aix_version_fix "$version"`.bff" } pp_backend_aix_install_script () { @@ -2170,7 +2182,7 @@ pp_backend_aix_vas_platforms () { esac } pp_backend_aix_function () { - case $1 in + case "$1" in pp_mkgroup) cat <<'.';; /usr/sbin/lsgroup "$1" >/dev/null && return 0 @@ -2224,6 +2236,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,19 +2262,39 @@ 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 test x"$m" = x"-" && m=$dm case $t in - s) echo "$line $st $p";; - *) echo "$line -o $o -g $g -m $m $pp_destdir$p $p";; + s) + # swpackage will make unqualified links relative to the + # current working (source) directory, not the destination; + # we need to qualify them to prevent this. + case "$st" in + /*) echo "$line $st $p";; + *) echo "$line `dirname $p`/$st $p";; + esac + ;; + *) + echo "$line -o $o -g $g -m $m $pp_destdir$p $p" + ;; esac done @@ -2283,49 +2316,49 @@ pp_sd_service_group_script () { . cat <<-'.' >> $out - #-- starts services in order.. stops them all if any break - pp_start () { - undo= - for svc in $svcs; do - /sbin/init.d/$svc start - case $? in - 0|4) - undo="$svc $undo" - ;; - *) - if test -n "$undo"; then - for svc in $undo; do - /sbin/init.d/$svc stop - done - return 1 - fi - ;; - esac - done - return 0 - } + #-- starts services in order.. stops them all if any break + pp_start () { + undo= + for svc in \$svcs; do + /sbin/init.d/\$svc start + case \$? in + 0|4) + undo="\$svc \$undo" + ;; + *) + if test -n "\$undo"; then + for svc in \$undo; do + /sbin/init.d/\$svc stop + done + return 1 + fi + ;; + esac + done + return 0 + } - #-- stops services in reverse - pp_stop () { - reverse= - for svc in $svcs; do - reverse="$svc $reverse" - done - rc=0 - for svc in $reverse; do - /sbin/init.d/$svc stop || rc=$? - done - return $rc + #-- stops services in reverse + pp_stop () { + reverse= + for svc in \$svcs; do + reverse="\$svc \$reverse" + done + rc=0 + for svc in \$reverse; do + /sbin/init.d/\$svc stop || rc=\$? + done + return \$rc } - case $1 in - start_msg) echo "Starting $svcs";; - stop_msg) echo "Stopping $svcs";; + case \$1 in + start_msg) echo "Starting \$svcs";; + stop_msg) echo "Stopping \$svcs";; start) pp_start;; stop) pp_stop;; - *) echo "usage: $0 {start|stop|start_msg|stop_msg}" - exit 1;; - esac + *) echo "usage: \$0 {start|stop|start_msg|stop_msg}" + exit 1;; + esac . } @@ -2376,61 +2409,61 @@ pp_sd_service_script () { } pp_stop () { - if test ! -s "$pidfile"; then - echo "Unable to stop $svc (no pid file)" - return 1 + if test ! -s "\$pidfile"; then + echo "Unable to stop \$svc (no pid file)" + return 1 else - read pid < "$pidfile" - if kill -0 "$pid" 2>/dev/null; then - if kill -${stop_signal:-TERM} "$pid"; then - rm -f "$pidfile" - return 0 - else - echo "Unable to stop $svc" - return 1 - fi - else - rm -f "$pidfile" - return 0 - fi + read pid < "\$pidfile" + if kill -0 "\$pid" 2>/dev/null; then + if kill -${stop_signal:-TERM} "\$pid"; then + rm -f "\$pidfile" + return 0 + else + echo "Unable to stop \$svc" + return 1 + fi + else + rm -f "\$pidfile" + return 0 + fi fi } pp_running () { - if test ! -s "$pidfile"; then - return 1 + if test ! -s "\$pidfile"; then + return 1 else - read pid < "$pidfile" - kill -0 "$pid" 2>/dev/null + read pid < "\$pidfile" + kill -0 "\$pid" 2>/dev/null fi } - case $1 in - start_msg) echo "Starting the $svc service";; - stop_msg) echo "Stopping the $svc service";; + case \$1 in + start_msg) echo "Starting the \$svc service";; + stop_msg) echo "Stopping the \$svc service";; start) - if test -f "$config_file"; then - . $config_file - fi - if pp_disabled; then - exit 2 - elif pp_running; then - echo "$svc already running"; - exit 0 - elif pp_start; then - echo "$svc started"; - # rc(1M) says we should exit 4, but nobody expects it! - exit 0 - else - exit 1 - fi;; + if test -f "\$config_file"; then + . \$config_file + fi + if pp_disabled; then + exit 2 + elif pp_running; then + echo "\$svc already running"; + exit 0 + elif pp_start; then + echo "\$svc started"; + # rc(1M) says we should exit 4, but nobody expects it! + exit 0 + else + exit 1 + fi;; stop) if pp_stop; then - echo "$svc stopped"; - exit 0 - else - exit 1 - fi;; - *) echo "usage: $0 {start|stop|start_msg|stop_msg}" + echo "\$svc stopped"; + exit 0 + else + exit 1 + fi;; + *) echo "usage: \$0 {start|stop|start_msg|stop_msg}" exit 1;; esac . @@ -2439,11 +2472,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 +2525,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 @@ -2513,10 +2551,27 @@ pp_sd_control () { echo " $ctrl $script" } +pp_sd_depend () { + typeset _name _vers + while read _name _vers; do + case "$_name" in ""| "#"*) continue ;; esac + echo " prerequisites $_name ${_vers:+r>= $_vers}" + done +} + +pp_sd_conflict () { + typeset _name _vers + while read _name _vers; do + case "$_name" in ""| "#"*) continue ;; esac + echo " exrequisites $_name ${_vers:+r>= $_vers}" + done +} + 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 +2592,7 @@ pp_backend_sd () { copyright "$copyright" machine_type * os_name HP-UX - os_release ?.11.* + os_release $release os_version ? directory / is_locatable false @@ -2563,6 +2618,10 @@ pp_backend_sd () { title "${summary:-cpt}" revision $version . + test -s $pp_wrkdir/%depend.$cpt && + pp_sd_depend < $pp_wrkdir/%depend.$cpt >> $psf + test -s $pp_wrkdir/%conflict.$cpt && + pp_sd_conflict < $pp_wrkdir/%conflict.$cpt >> $psf #-- make sure services are shut down during uninstall if test $cpt = run -a -n "$pp_services"; then @@ -2618,10 +2677,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 @@ -2719,7 +2783,7 @@ pp_backend_sd_init_svc_vars () { : } pp_backend_sd_function () { - case $1 in + case "$1" in pp_mkgroup) cat <<'.';; /usr/sbin/groupmod "$1" 2>/dev/null || /usr/sbin/groupadd "$1" @@ -2753,7 +2817,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= @@ -2887,6 +2953,16 @@ pp_solaris_depend () { done } +pp_solaris_conflict () { + typeset _name _vers + while read _name _vers; do + if test -n "$_name"; then + echo "I $_name $_name" + test -n "$_vers" && echo " $_vers" + fi + done +} + pp_solaris_space() { echo "$2:$3:$1" >> $pp_wrkdir/space.cumulative } @@ -2903,14 +2979,14 @@ pp_solaris_proto () { typeset abi while read t m o g f p st; do - if test x"$o" = x"-"; then - o="root" - fi - if test x"$g" = x"-"; then - g="bin" - fi + # Use Solaris default mode, owner and group if all unspecified + if test x"$m$o$g" = x"---"; then + m="?"; o="?"; g="?" + fi + test x"$o" = x"-" && o="root" case "$t" in - f) test x"$m" = x"-" && m=444 + f) test x"$g" = x"-" && g="bin" + test x"$m" = x"-" && m=444 case "$f" in *v*) echo "v $1 $p=$pp_destdir$p $m $o $g";; *) echo "f $1 $p=$pp_destdir$p $m $o $g";; @@ -2929,12 +3005,15 @@ pp_solaris_proto () { fi fi ;; - d) test x"$m" = x"-" && m=555 + d) test x"$g" = x"-" && g="sys" + test x"$m" = x"-" && m=555 echo "d $1 $p $m $o $g" ;; - s) test x"$m" = x"-" && m=777 - test x"$m" = x"777" || + s) test x"$g" = x"-" && g="bin" + test x"$m" = x"-" && m=777 + if test x"$m" != x"777" -a x"$m" != x"?"; then pp_warn "$p: invalid mode $m for symlink, should be 777 or -" + fi echo "s $1 $p=$st $m $o $g" ;; esac @@ -2982,8 +3061,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 @@ -2993,6 +3076,7 @@ pp_backend_solaris () { #-- scripts to run before and after install : > $pp_wrkdir/postinstall : > $pp_wrkdir/preremove + : > $pp_wrkdir/postremove for _cmp in $pp_components; do #-- add the preinstall scripts in definition order if test -s $pp_wrkdir/%pre.$_cmp; then @@ -3009,15 +3093,22 @@ pp_backend_solaris () { pp_solaris_procedure $_cmp preremove < $pp_wrkdir/%preun.$_cmp | pp_prepend $pp_wrkdir/preremove fi + #-- add the postremove scripts in definition order + if test -s $pp_wrkdir/%postun.$_cmp; then + pp_solaris_procedure $_cmp postremove < $pp_wrkdir/%postun.$_cmp \ + >> $pp_wrkdir/postremove + fi #-- Add the check script in definition order if test -s $pp_wrkdir/%check.$_cmp; then pp_solaris_procedure $_cmp checkinstall \ < $pp_wrkdir/%check.$_cmp \ >> $pp_wrkdir/checkinstall fi - #-- All dependencies are merged together for Solaris pkgs + #-- All dependencies and conflicts are merged together for Solaris pkgs test -s $pp_wrkdir/%depend.$_cmp && - pp_solaris_depend < $pp_wrkdir/%depend.$_cmp > $pp_wrkdir/depend + pp_solaris_depend < $pp_wrkdir/%depend.$_cmp >> $pp_wrkdir/depend + test -s $pp_wrkdir/%conflict.$_cmp && + pp_solaris_conflict < $pp_wrkdir/%conflict.$_cmp >> $pp_wrkdir/depend done @@ -3028,11 +3119,12 @@ 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 + pp_solaris_remove_service $_svc | pp_prepend $pp_wrkdir/postremove + unset pp_svc_xml_file done test -n "$pp_service_groups" && @@ -3110,8 +3202,8 @@ 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; } + 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} \ @@ -3264,7 +3356,7 @@ pp_backend_solaris_vas_platforms () { esac } pp_backend_solaris_function() { - case $1 in + case "$1" in pp_mkgroup) cat<<'.';; /usr/sbin/groupmod "$1" 2>/dev/null && return 0 /usr/sbin/groupadd "$1" @@ -3284,12 +3376,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 +3399,118 @@ 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"} + pp_solaris_mansect=${pp_solaris_mansect:-1} + 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:-$svc} + + 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 + pp_solaris_add_parent_dirs "$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 + + + + + + + + + + + + + + + + . } @@ -3352,8 +3522,9 @@ pp_solaris_make_service_group () { file="/etc/init.d/$group" out="$pp_destdir$file" - #-- return if the script is supplued already + #-- return if the script is supplied already pp_add_file_if_missing "$file" run 755 || return 0 + pp_solaris_add_parent_dirs "$file" echo "#! /sbin/sh" > $out echo "# polypkg service group script for these services:" >> $out @@ -3411,22 +3582,59 @@ 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 + pp_solaris_add_parent_dirs "$file" 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" >&2 + fi + ;; + stop) + echo "stopping $svc" + /usr/sbin/svcadm disable -ts $_smf_category/$svc + RESULT=0 + ;; + 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" >&2 + fi + ;; + *) + echo "Usage: $file {start|stop|restart|status}" >&2 + RESULT=1 + esac + exit $RESULT +fi +_EOF + fi + #-- construct a start command that builds a pid file as needed # and forks the daemon _cmd="$cmd"; @@ -3465,8 +3673,8 @@ pp_solaris_make_service () { # returns true if $svc is running pp_running () { - test -r "$pidfile" && - read pid junk < "$pidfile" && + test -s "$pidfile" || return 1 + read pid junk < "$pidfile" 2>/dev/null test ${pid:-0} -gt 1 && kill -0 "$pid" 2>/dev/null } @@ -3528,13 +3736,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 +3772,54 @@ 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_solaris_add_parent_dirs () { + typeset dir + dir=${1%/*} + while test -n "$dir"; do + if awk "\$6 == \"$dir/\" {exit 1}" < $pp_wrkdir/%files.run; then + echo "d - - - - $dir/" >> $pp_wrkdir/%files.run + fi + dir=${dir%/*} + done } pp_platforms="$pp_platforms deb" @@ -3666,11 +3907,37 @@ 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_conflict () { + local _name _vers _conflicts + + _conflicts="Conflicts:" + while read _name _vers; do + case "$_name" in ""| "#"*) continue ;; esac + _conflicts="$_conflicts $_name" + test -n "$_vers" && _conflicts="$_conflicts $_name (>= $vers)" + _conflicts="${_conflicts}," + done + echo "${_conflicts%,}" +} + 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} @@ -3682,6 +3949,9 @@ pp_deb_make_control() { sed -ne '/^[ ]*$/!s/^[ ]*/Depends: /p' \ < $pp_wrkdir/%depend."$1" fi + if test -s $pp_wrkdir/%conflict."$1"; then + pp_deb_conflict < $pp_wrkdir/%conflict."$1" + fi } pp_deb_make_md5sums() { @@ -3791,6 +4061,11 @@ pp_deb_make_DEBIAN() { "$pp_wrkdir/%preun.$cmp" "Pre-uninstall script for $cmp_full_name"\ || exit $? + # Create postrm + pp_deb_make_package_maintainer_script "$data/DEBIAN/postrm" \ + "$pp_wrkdir/%postun.$cmp" "Post-uninstall script for $cmp_full_name"\ + || exit $? + umask $old_umask } @@ -3800,6 +4075,12 @@ pp_deb_make_data() { cmp=$1 data=$pp_wrkdir/`pp_deb_cmp_full_name $cmp` cat $pp_wrkdir/%files.${cmp} | while read t m o g f p st; do + if test x"$m" = x"-"; then + case "$t" in + d) m=755;; + f) m=644;; + esac + fi test x"$o" = x"-" && o=root test x"$g" = x"-" && g=root case "$t" in @@ -3897,7 +4178,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 @@ -4072,17 +4353,11 @@ pp_backend_deb_vas_platforms () { *) pp_die "unknown architecture ${pp_deb_arch_std}";; esac } -pp_backend_deb_init_svc_vars () { - # Default multi-user runlevel on Debian is 2; 3-5 are also multi-user - pp_deb_default_start_runlevels="2 3 4 5" - pp_deb_default_svc_description="No description" -} - pp_backend_deb_init_svc_vars () { reload_signal= - start_runlevels=${pp_deb_default_start_runlevels} # == lsb default-start - stop_runlevels="0 1 6" # == lsb default-stop + start_runlevels=${pp_deb_default_start_runlevels-"2 3 4 5"} # == lsb default-start + stop_runlevels=${pp_deb_default_stop_runlevels-"0 1 6"} # == lsb default-stop svc_description="${pp_deb_default_svc_description}" # == lsb short descr svc_process= @@ -4113,9 +4388,10 @@ pp_deb_service_make_init_script () { #_process=${svc_process:-"$1"} --? WTF #-- construct a start command that builds a pid file if needed + #-- the command name in /proc/[pid]/stat is limited to 15 characters _cmd="$cmd"; _cmd_path=`echo $cmd | cut -d" " -f1` - _cmd_name=`basename $_cmd_path` + _cmd_name=`basename $_cmd_path | cut -c1-15` _cmd_args=`echo $cmd | cut -d" " -f2-` test x"$_cmd_path" != x"$_cmd_args" || _cmd_args= @@ -4128,7 +4404,7 @@ pp_deb_service_make_init_script () { # Required-Stop: ${lsb_required_stop} # Default-Start: ${start_runlevels} # Default-Stop: ${stop_runlevels} - # Short-Description: ${svc_description} + # Short-Description: ${svc_description:-no description} ### END INIT INFO # Generated by PolyPackage ${pp_version} # ${copyright} @@ -4326,7 +4602,7 @@ esac chmod 755 $out } pp_backend_deb_function() { - case $1 in + case "$1" in pp_mkgroup) cat<<'.';; /usr/sbin/groupmod "$1" 2>/dev/null && return 0 /usr/sbin/groupadd "$1" @@ -4677,7 +4953,7 @@ cat <<-'.' >> $out return $rc } - case $1 in + case "$1" in start_msg) echo "Starting $svcs";; stop_msg) echo "Stopping $svcs";; start) pp_start;; @@ -4743,7 +5019,7 @@ pp_kit_service_script () { kill -0 "$pid" 2>/dev/null fi } - case $1 in + case "$1" in start_msg) echo "Starting the $svc service";; stop_msg) echo "Stopping the $svc service";; start) @@ -5096,28 +5372,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 +5407,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; } @@ -5139,6 +5425,7 @@ pp_rpm_detect_distro () { pp_rpm_distro=`awk ' /^Red Hat Enterprise Linux/ { print "rhel" $7; exit; } /^CentOS release/ { print "centos" $3; exit; } + /^CentOS Linux release/ { print "centos" $4; exit; } /^Red Hat Linux release/ { print "rh" $5; exit; } ' /etc/redhat-release` elif test -f /etc/SuSE-release; then @@ -5150,6 +5437,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` @@ -5212,6 +5503,8 @@ pp_rpm_writefiles () { farch=x86_64;; *": ELF 32-bit MSB "*", PowerPC"*) farch=ppc;; + *": ELF 64-bit MSB "*", 64-bit PowerPC"*) + farch=ppc64;; *": ELF 64-bit LSB "*", IA-64"*) farch=ia64;; *": ELF 32-bit MSB "*", IBM S/390"*) @@ -5221,10 +5514,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 @@ -5246,12 +5563,21 @@ pp_rpm_subname () { } pp_rpm_depend () { + local _name _vers while read _name _vers; do case "$_name" in ""| "#"*) continue ;; esac echo "Requires: $_name ${_vers:+>= $_vers}" done } +pp_rpm_conflict () { + local _name _vers + while read _name _vers; do + case "$_name" in ""| "#"*) continue ;; esac + echo "Conflicts: $_name ${_vers:+>= $_vers}" + done +} + pp_rpm_override_requires () { local orig_find_requires @@ -5317,6 +5643,9 @@ pp_backend_rpm () { elif test -s $pp_wrkdir/%depend.run; then pp_rpm_depend < $pp_wrkdir/%depend.run >> $specfile fi + if test -s $pp_wrkdir/%conflict.run; then + pp_rpm_conflict < $pp_wrkdir/%conflict.run >> $specfile + fi pp_rpm_override_requires >> $specfile @@ -5356,6 +5685,9 @@ pp_backend_rpm () { elif test -s $pp_wrkdir/%depend.$cmp; then pp_rpm_depend < $pp_wrkdir/%depend.$cmp >> $specfile fi + if test -s $pp_wrkdir/%conflict.$cmp; then + pp_rpm_conflict < $pp_wrkdir/%conflict.$cmp >> $specfile + fi eval '_pkg="$pp_rpm_'$cmp'_provides"' eval pp_rpm_label Provides $_pkg @@ -5442,6 +5774,13 @@ pp_backend_rpm () { cat $pp_wrkdir/%preun.$cmp echo : # causes script to exit true fi + + if test -s $pp_wrkdir/%postun.$cmp; then + echo "" + echo "%postun $_subname" + cat $pp_wrkdir/%postun.$cmp + echo : # causes script to exit true + fi done >>$specfile #-- create a suitable work area for rpmbuild @@ -5675,11 +6014,6 @@ pp_backend_rpm_vas_platforms () { esac } -pp_backend_rpm_init_svc_vars () { - pp_rpm_default_start_runlevels="2 3 4 5" - pp_rpm_default_svc_description="No description" -} - pp_rpm_service_install_common () { cat <<-'.' @@ -5786,8 +6120,8 @@ pp_rpm_service_remove () { pp_backend_rpm_init_svc_vars () { reload_signal= - start_runlevels=${pp_rpm_default_start_runlevels} # == lsb default-start - stop_runlevels="0 1 6" # == lsb default-stop + start_runlevels=${pp_rpm_default_start_runlevels-"2 3 4 5"} # == lsb default-start + stop_runlevels=${pp_rpm_default_stop_runlevels-"0 1 6"} # == lsb default-stop svc_description="${pp_rpm_default_svc_description}" # == lsb short descr svc_process= @@ -6084,7 +6418,7 @@ pp_rpm_service_make_init_script () { chmod 755 $out } pp_backend_rpm_function () { - case $1 in + case "$1" in pp_mkgroup) cat<<'.';; /usr/sbin/groupadd -f -r "$1" . @@ -6195,7 +6529,7 @@ pp_backend_rpm_function () { Examples found in /System/Library/LaunchDaemons/ See manual page launchd.plist(5) for details: - { Label: "com.quest.vintela.foo", # required + { Label: "com.quest.rc.foo", # required Program: "/sbin/program", ProgramArguments: [ "/sbin/program", "arg1", "arg2" ], # required RunAtLoad: true, @@ -6241,9 +6575,13 @@ pp_backend_macos_init () { pp_macos_bundle_vendor= pp_macos_bundle_version= pp_macos_bundle_info_string= - pp_macos_prog_packagemaker=/Developer/usr/bin/packagemaker - pp_macos_pkg_domain=anywhere - pp_macos_pkg_extra_flags= + pp_macos_pkg_type=bundle + pp_macos_pkg_license= + pp_macos_pkg_readme= + pp_macos_pkg_welcome= + pp_macos_sudo=sudo + # OS X puts the library version *before* the .dylib extension + pp_shlib_suffix='*.dylib' } pp_macos_plist () { @@ -6282,65 +6620,132 @@ pp_macos_plist () { pp_macos_rewrite_cpio () { typeset script script=$pp_wrkdir/cpio-rewrite.pl - # rely on the fact that OS X comes with perl. It is a little easier to - # re-write a binary stream with perl than it is with posix :) - # - # A CPIO header block has octal fields at the following offset/lengths: - # 0 6 magic - # 6 6 dev - # 12 6 ino - # 18 6 mode - # 24 6 uid - # 30 6 gid - # 36 6 nlink - # 42 6 rdev - # 48 11 mtime - # 59 6 namesize - # 65 11 filesize - # 76 -- cat <<-'.' >$script + #!/usr/bin/perl + # + # Filter a cpio file, applying the user/group/mode specified in %files + # + # A CPIO header block has octal fields at the following offset/lengths: + # 0 6 magic + # 6 6 dev + # 12 6 ino + # 18 6 mode + # 24 6 uid + # 30 6 gid + # 36 6 nlink + # 42 6 rdev + # 48 11 mtime + # 59 6 namesize (including NUL terminator) + # 65 11 filesize + # 76 -- + # + use strict; + use warnings; + no strict 'subs'; + + # set %uid, %gid, %mode based on %files + my (%uid, %gid, %mode, %users, %groups); + my %type_map = ( d => 0040000, f => 0100000, s => 0120000 ); while () { - my ($type,$mode,$uid,$gid,$flags,$name) = - m/^(.) (\d+) (\S+) (\S+) (\S+) (.*)/; - $uid = 0 if $uid eq "-"; - $gid = 0 if $gid eq "-"; - if ($uid ne "=" and $uid =~ m/\D/) { - my @pw = getpwnam($uid) or die "bad username '$uid'"; - $uid = $pw[2]; - } - if ($gid ne "=" and $gid =~ m/\D/) { - my @gr = getgrnam($gid) or die "bad group '$gid'"; - $gid = $gr[2]; - } - $name = ".".$name."\0"; - $ok{$name} = 1; - $uid{$name} = sprintf("%06o",int($uid)) unless $uid eq "="; - $gid{$name} = sprintf("%06o",int($gid)) unless $gid eq "="; - $mode{$name} = sprintf("%06o",oct($mode)) unless $mode eq "="; + my ($type,$mode,$uid,$gid,$flags,$name) = + m/^(.) (\S+) (\S+) (\S+) (\S+) (\S+)/; + $mode = $type eq "f" ? "0644" : "0755" if $mode eq "-"; + $uid = 0 if $uid eq "-"; + $gid = 0 if $gid eq "-"; + if ($uid ne "=" and $uid =~ m/\D/) { + unless (exists $users{$uid}) { + my @pw = getpwnam($uid) or die "bad username '$uid'"; + $users{$uid} = $pw[2]; + } + $uid = $users{$uid}; + } + if ($gid ne "=" and $gid =~ m/\D/) { + unless (exists $groups{$gid}) { + my @gr = getgrnam($gid) or die "bad group'$gid'"; + $groups{$gid} = $gr[2]; + } + $gid = $groups{$gid}; + } + $name =~ s:/$:: if $type eq "d"; + $name = ".".$name."\0"; + $uid{$name} = sprintf("%06o",int($uid)) unless $uid eq "="; + $gid{$name} = sprintf("%06o",int($gid)) unless $gid eq "="; + $mode{$name} = sprintf("%06o",oct($mode)|$type_map{$type}) unless $mode eq "="; } - $ok{"TRAILER!!!\0"} = 1; - while (!eof STDIN) { - read STDIN, $header, 76; - die "bad magic" unless $header =~ m/^070707/; - $namesize = oct(substr($header,59,6)); - $filesize = oct(substr($header,65,11)); - read STDIN, $name, $namesize; - # convert uid and gid to 0 - substr($header, 24, 6) = $uid{$name} if defined($uid{$name}); - substr($header, 30, 6) = $gid{$name} if defined($gid{$name}); - substr($header, 18, 6) = $mode{$name} if defined($mode{$name}); - print ($header, $name) if $ok{$name}; - # copy-through the file data - while ($filesize > 0) { - my $seg = 8192; - $seg = $filesize if $filesize < $seg; - undef $data; - read STDIN, $data, $seg; - print $data if $ok{$name}; - $filesize -= $seg; - } + undef %users; + undef %groups; + # parse the cpio file + my $hdrlen = 76; + while (read(STDIN, my $header, $hdrlen)) { + my ($name, $namesize, $filesize); + my $filepad = 0; + if ($header =~ m/^07070[12]/) { + # SVR4 ASCII format, convert to ODC + if ($hdrlen == 76) { + # Read in rest of header and update header len for SVR4 + read(STDIN, $header, 110 - 76, 76); + $hdrlen = 110; + } + my $ino = hex(substr($header, 6, 8)) & 0x3ffff; + my $mode = hex(substr($header, 14, 8)) & 0x3ffff; + my $uid = hex(substr($header, 22, 8)) & 0x3ffff; + my $gid = hex(substr($header, 30, 8)) & 0x3ffff; + my $nlink = hex(substr($header, 38, 8)) & 0x3ffff; + my $mtime = hex(substr($header, 46, 8)) & 0xffffffff; + $filesize = hex(substr($header, 54, 8)) & 0xffffffff; + my $dev_maj = hex(substr($header, 62, 8)); + my $dev_min = hex(substr($header, 70, 8)); + my $dev = &makedev($dev_maj, $dev_min) & 0x3ffff; + my $rdev_maj = hex(substr($header, 78, 8)); + my $rdev_min = hex(substr($header, 86, 8)); + my $rdev = &makedev($rdev_maj, $rdev_min) & 0x3ffff; + $namesize = hex(substr($header, 94, 8)) & 0x3ffff; + read(STDIN, $name, $namesize); + # Header + name is padded to a multiple of 4 bytes + my $namepad = (($hdrlen + $namesize + 3) & 0xfffffffc) - ($hdrlen + $namesize); + read(STDIN, my $padding, $namepad) if ($namepad); + # File data is padded to be a multiple of 4 bytes + $filepad = (($filesize + 3) & 0xfffffffc) - $filesize; + + my $new_header = sprintf("070707%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o", $dev, $ino, $mode, $uid, $gid, $nlink, $rdev, $mtime, $namesize, $filesize); + $header = $new_header; + } elsif ($header =~ m/^070707/) { + # POSIX Portable ASCII Format + $namesize = oct(substr($header, 59, 6)); + $filesize = oct(substr($header, 65, 11)); + read(STDIN, $name, $namesize); + } else { + die "bad magic"; + } + # update uid, gid and mode (already in octal) + substr($header, 24, 6) = $uid{$name} if exists $uid{$name}; + substr($header, 30, 6) = $gid{$name} if exists $gid{$name}; + substr($header, 18, 6) = $mode{$name} if exists $mode{$name}; + print($header, $name); + # check for trailer at EOF + last if $filesize == 0 && $name =~ /^TRAILER!!!\0/; + # copy-through the file data + while ($filesize > 0) { + my $seg = 8192; + $seg = $filesize if $filesize < $seg; + read(STDIN, my $data, $seg); + print $data; + $filesize -= $seg; + } + # If file data is padded, skip it + read(STDIN, my $padding, $filepad) if ($filepad); + } + # pass through any padding at the end (blocksize-dependent) + for (;;) { + my $numread = read(STDIN, my $data, 8192); + last unless $numread; + print $data; } exit(0); + + sub makedev { + (((($_[0] & 0xff)) << 24) | ($_[1] & 0xffffff)); + } __DATA__ . # Append to the script the %files data @@ -6356,7 +6761,7 @@ pp_macos_files_bom () { ?) m="000$m";; ??) m="00$m";; ???) m="0$m";; - ?????*) pp_fatal "pp_macos_writebom: mode '$m' too long";; + ?????*) pp_error "pp_macos_writebom: mode '$m' too long";; esac # convert owner,group into owner/group in octal @@ -6366,19 +6771,25 @@ pp_macos_files_bom () { case $t in f) + test x"$m" = x"000-" && m=0644 echo ".$p 10$m $owner ` /usr/bin/cksum < "${pp_destdir}$p" | - awk '{print $2 " " $1}'`";; + awk '{print $2 " " $1}'`" + ;; d) - echo ".${p%/} 4$m $owner";; + test x"$m" = x"000-" && m=0755 + echo ".${p%/} 4$m $owner" + ;; s) + test x"$m" = x"000-" && m=0755 rl=`/usr/bin/readlink "${pp_destdir}$p"` #test x"$rl" = x"$st" || # pp_error "symlink mismatch $rl != $st" echo ".$p 12$m $owner ` /usr/bin/readlink -n "${pp_destdir}$p" | /usr/bin/cksum | - awk '{print $2 " " $1}'` $st";; + awk '{print $2 " " $1}'` $st" + ;; esac done } @@ -6392,8 +6803,11 @@ pp_macos_bom_fix_parents () { print "$d\t40755\t0/0\n"; } } - m/^\S+/; - &chk(&dirname($&));' + m/^(\S+)\s+(\d+)/; + if (oct($2) & 040000) { + $seen{$1}++; # directory + } + &chk(&dirname($1));' } pp_macos_files_size () { @@ -6434,28 +6848,38 @@ pp_macos_mkbom () { pp_warn "mkbom workaround: copying source files to staging area" bomstage=$pp_wrkdir/bom_stage + $pp_macos_sudo /bin/mkdir "$bomstage" 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 () { - typeset pkgdir Contents Resources lprojdir + : ${pp_macos_bundle_id:=$pp_macos_default_bundle_id_prefix$name} + case "$pp_macos_pkg_type" in + bundle) pp_backend_macos_bundle;; + flat) pp_backend_macos_flat;; + *) pp_error "unsupported package type $pp_macos_pkg_type";; + esac +} + +pp_backend_macos_bundle () { + typeset pkgdir Contents Resources lprojdir svc typeset Info_plist Description_plist - typeset bundle_vendor bundle_version size + typeset bundle_vendor bundle_version size cmp filelists mac_version=`sw_vers -productVersion` bundle_vendor=${pp_macos_bundle_vendor:-$vendor} @@ -6463,9 +6887,6 @@ pp_backend_macos () { if test -z "$pp_macos_bundle_version"; then bundle_version=`echo "$version.0.0.0" | sed -n -e 's/[^0-9.]//g' \ -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/p'` - #if test x"$bundle_version" != x"$version"; then - # pp_warn "converted version from '$version' to '$bundle_version'" - #fi else bundle_version="$pp_macos_bundle_version" fi @@ -6477,7 +6898,7 @@ pp_backend_macos () { Resources=$Contents/Resources lprojdir=$Resources/en.lproj mkdir $pkgdir $Contents $Resources $lprojdir || - pp_fatal "Can't make package temporary directories" + pp_error "Can't make package temporary directories" echo "major: 1" > $Resources/package_version echo "minor: 0" >> $Resources/package_version @@ -6485,12 +6906,56 @@ pp_backend_macos () { case $mac_version in "10.6"*) xattr -w "com.apple.TextEncoding" "macintosh;0" "$Resources/package_version" - xattr -w "com.apple.TextEncoding" "macintosh;0" "$Resources/PkgInfo" + xattr -w "com.apple.TextEncoding" "macintosh;0" "$Contents/PkgInfo" ;; esac + # Copy welcome file/dir for display at package install time. + if test -n "$pp_macos_pkg_welcome"; then + typeset sfx + sfx=`echo "$pp_macos_pkg_welcome"|sed 's/^.*\.\([^\.]*\)$/\1/'` + case "$sfx" in + rtf|html|rtfd|txt) ;; + *) sfx=txt;; + esac + cp -R ${pp_macos_pkg_welcome} $Resources/Welcome.$sfx + fi + + # Copy readme file/dir for display at package install time. + if test -n "$pp_macos_pkg_readme"; then + typeset sfx + sfx=`echo "$pp_macos_pkg_readme"|sed 's/^.*\.\([^\.]*\)$/\1/'` + case "$sfx" in + rtf|html|rtfd|txt) ;; + *) sfx=txt;; + esac + cp -R ${pp_macos_pkg_readme} $Resources/ReadMe.$sfx + fi + + # Copy license file/dir for display at package install time. + if test -n "$pp_macos_pkg_license"; then + typeset sfx + sfx=`echo "$pp_macos_pkg_license"|sed 's/^.*\.\([^\.]*\)$/\1/'` + case "$sfx" in + rtf|html|rtfd|txt) ;; + *) sfx=txt;; + esac + cp -R ${pp_macos_pkg_license} $Resources/License.$sfx + fi + + # Add services (may modify %files) + for svc in $pp_services .; do + test . = "$svc" && continue + pp_macos_add_service $svc + done + + # Find file lists (%files.* includes ignore files) + for cmp in $pp_components; do + test -f $pp_wrkdir/%files.$cmp && filelists="$filelists${filelists:+ }$pp_wrkdir/%files.$cmp" + done + # compute the installed size - size=`cat $pp_wrkdir/%files.* | pp_macos_files_size` + size=`cat $filelists | pp_macos_files_size` #-- Create Info.plist Info_plist=$Contents/Info.plist @@ -6499,7 +6964,7 @@ pp_backend_macos () { key CFBundleGetInfoString string \ "${pp_macos_bundle_info_string:-$version $bundle_vendor}" \ key CFBundleIdentifier string \ - "${pp_macos_bundle_id:-$pp_macos_default_bundle_id_prefix$name}" \ + "${pp_macos_bundle_id}" \ key CFBundleName string "$name" \ key CFBundleShortVersionString string "$bundle_version" \ key IFMajorVersion integer 1 \ @@ -6531,8 +6996,8 @@ pp_backend_macos () { key IFPkgDescriptionVersion string "$version" \ \} end-plist > $Description_plist - # write Resources/files - cat $pp_wrkdir/%files.* | awk '{print $6}' > $Resources/files + # write Resources/files + awk '{print $6}' $filelists > $Resources/files # write package size file printf \ @@ -6541,7 +7006,7 @@ InstalledSize $size CompressedSize 0 " > $Resources/$name.sizes - # write Resources/postinstall + # write Resources/preinstall for cmp in $pp_components; do if test -s $pp_wrkdir/%pre.$cmp; then if test ! -s $Resources/preinstall; then @@ -6565,7 +7030,7 @@ CompressedSize 0 fi done - # write Resources/postupgrade) + # write Resources/postupgrade for cmp in $pp_components; do if test -s $pp_wrkdir/%postup.$cmp; then if test ! -s $Resources/postupgrade; then @@ -6577,7 +7042,7 @@ CompressedSize 0 fi done - # write Resources/preremove) + # write Resources/preremove for cmp in $pp_components; do if test -s $pp_wrkdir/%preun.$cmp; then if test ! -s $Resources/preremove; then @@ -6589,7 +7054,7 @@ CompressedSize 0 fi done - # write Resources/postremove) + # write Resources/postremove for cmp in $pp_components; do if test -s $pp_wrkdir/%postun.$cmp; then if test ! -s $Resources/postremove; then @@ -6607,20 +7072,199 @@ CompressedSize 0 echo "requires=$pp_macos_requires" >> $Resources/uninstall fi + . $pp_wrkdir/%fixup + # Create the bill-of-materials (Archive.bom) - cat $pp_wrkdir/%files.* | pp_macos_files_bom | sort | + cat $filelists | pp_macos_files_bom | sort | pp_macos_bom_fix_parents > $pp_wrkdir/tmp.bomls pp_macos_mkbom $pp_wrkdir/tmp.bomls $Contents/Archive.bom # Create the cpio archive (Archive.pax.gz) - # On 10.5, we used "-f -" to write explicitly to stdout ( cd $pp_destdir && - cat $pp_wrkdir/%files.* | awk '{ print "." $6 }' | sed '/\/$/d' | sort | /bin/pax -w -f - | gzip -9 -c > $Contents/Archive.pax.gz + awk '{ print "." $6 }' $filelists | sed 's:/$::' | sort | /usr/bin/cpio -o | pp_macos_rewrite_cpio $filelists | gzip -9f -c > $Contents/Archive.pax.gz + ) + + test -d $pp_wrkdir/bom_stage && $pp_macos_sudo rm -rf $pp_wrkdir/bom_stage + + rm -f ${name}-${version}.dmg + hdiutil create -fs HFS+ -srcfolder $pkgdir -volname $name ${name}-${version}.dmg +} + +pp_backend_macos_flat () { + typeset pkgdir bundledir Resources lprojdir svc + typeset Info_plist Description_plist + typeset bundle_vendor bundle_version size numfiles cmp filelists + + mac_version=`sw_vers -productVersion` + bundle_vendor=${pp_macos_bundle_vendor:-$vendor} + + if test -z "$pp_macos_bundle_version"; then + bundle_version=`echo "$version.0.0.0" | sed -n -e 's/[^0-9.]//g' \ + -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/p'` + else + bundle_version="$pp_macos_bundle_version" + fi + source_version=`echo $version | sed 's/.*\.//'` + + # build the flat package layout + pkgdir=$pp_wrkdir/pkg + bundledir=$pp_wrkdir/pkg/$name.pkg + Resources=$pkgdir/Resources + lprojdir=$Resources/en.lproj + mkdir $pkgdir $bundledir $Resources $lprojdir || + pp_error "Can't make package temporary directories" + + # Add services (may modify %files) + for svc in $pp_services .; do + test . = "$svc" && continue + pp_macos_add_service $svc + done + + # Find file lists (%files.* includes ignore files) + for cmp in $pp_components; do + test -f $pp_wrkdir/%files.$cmp && filelists="$filelists${filelists:+ }$pp_wrkdir/%files.$cmp" + done + + # compute the installed size and number of files/dirs + size=`cat $filelists | pp_macos_files_size` + numfiles=`cat $filelists | wc -l` + numfiles="${numfiles##* }" + + # Write Distribution file + cat <<-. >$pkgdir/Distribution + + + $name $version + + +. + if test -n "$pp_macos_pkg_welcome"; then + cp -R "${pp_macos_pkg_welcome}" $Resources + echo " " >>$pkgdir/Distribution + fi + if test -n "$pp_macos_pkg_readme"; then + cp -R "${pp_macos_pkg_readme}" $Resources + echo " " >>$pkgdir/Distribution + fi + if test -n "$pp_macos_pkg_license"; then + cp -R "${pp_macos_pkg_license}" $Resources + echo " " >>$pkgdir/Distribution + fi + cat <<-. >>$pkgdir/Distribution + + + + + + + #$name.pkg + +. + + # write scripts archive + # XXX - missing preupgrade, preflight, postflight + mkdir $pp_wrkdir/scripts + for cmp in $pp_components; do + if test -s $pp_wrkdir/%pre.$cmp; then + if test ! -s $pp_wrkdir/scripts/preinstall; then + echo "#!/bin/sh" > $pp_wrkdir/scripts/preinstall + chmod +x $pp_wrkdir/scripts/preinstall + fi + cat $pp_wrkdir/%pre.$cmp >> $pp_wrkdir/scripts/preinstall + echo : >> $pp_wrkdir/scripts/preinstall + fi + if test -s $pp_wrkdir/%post.$cmp; then + if test ! -s $pp_wrkdir/scripts/postinstall; then + echo "#!/bin/sh" > $pp_wrkdir/scripts/postinstall + chmod +x $pp_wrkdir/scripts/postinstall + fi + cat $pp_wrkdir/%post.$cmp >> $pp_wrkdir/scripts/postinstall + echo : >> $pp_wrkdir/scripts/postinstall + fi + if test -s $pp_wrkdir/%postup.$cmp; then + if test ! -s $pp_wrkdir/scripts/postupgrade; then + echo "#!/bin/sh" > $pp_wrkdir/scripts/postupgrade + chmod +x $pp_wrkdir/scripts/postupgrade + fi + cat $pp_wrkdir/%postup.$cmp >> $pp_wrkdir/scripts/postupgrade + echo : >> $pp_wrkdir/scripts/postupgrade + fi + # XXX - not supported + if test -s $pp_wrkdir/%preun.$cmp; then + if test ! -s $pp_wrkdir/scripts/preremove; then + echo "#!/bin/sh" > $pp_wrkdir/scripts/preremove + chmod +x $pp_wrkdir/scripts/preremove + fi + cat $pp_wrkdir/%preun.$cmp >> $pp_wrkdir/scripts/preremove + echo : >> $pp_wrkdir/scripts/preremove + fi + # XXX - not supported + if test -s $pp_wrkdir/%postun.$cmp; then + if test ! -s $pp_wrkdir/scripts/postremove; then + echo "#!/bin/sh" > $pp_wrkdir/scripts/postremove + chmod +x $pp_wrkdir/scripts/postremove + fi + cat $pp_wrkdir/%postun.$cmp >> $pp_wrkdir/scripts/postremove + echo : >> $pp_wrkdir/scripts/postremove + fi + done + if test "`echo $pp_wrkdir/scripts/*`" != "$pp_wrkdir/scripts/*"; then + # write scripts archive, scripts are mode 0755 uid/gid 0/0 + # resetting the owner and mode is not strictly required + ( + cd $pp_wrkdir/scripts || pp_error "Can't cd to $pp_wrkdir/scripts" + rm -f $pp_wrkdir/tmp.files.scripts + for s in *; do + echo "f 0755 0 0 - ./$s" >>$pp_wrkdir/tmp.files.scripts + done + find . -type f | /usr/bin/cpio -o | pp_macos_rewrite_cpio $pp_wrkdir/tmp.files.scripts | gzip -9f -c > $bundledir/Scripts + ) + fi + + # Write PackageInfo file + cat <<-. >$bundledir/PackageInfo + + + +. + if test -s $bundledir/Scripts; then + echo " " >>$bundledir/PackageInfo + for s in preflight postflight preinstall postinstall preupgrade postupgrade; do + if test -s "$pp_wrkdir/scripts/$s"; then + echo " <$s file=\"$s\"/>" >>$bundledir/PackageInfo + fi + done + echo " " >>$bundledir/PackageInfo + fi + cat <<-. >>$bundledir/PackageInfo + +. + + . $pp_wrkdir/%fixup + + # Create the bill-of-materials (Bom) + cat $filelists | pp_macos_files_bom | sort | + pp_macos_bom_fix_parents > $pp_wrkdir/tmp.bomls + pp_macos_mkbom $pp_wrkdir/tmp.bomls $bundledir/Bom + + # Create the cpio payload + ( + cd $pp_destdir || pp_error "Can't cd to $pp_destdir" + awk '{ print "." $6 }' $filelists | sed 's:/$::' | sort | /usr/bin/cpio -o | pp_macos_rewrite_cpio $filelists | gzip -9f -c > $bundledir/Payload ) - rm -rf $pp_wrkdir/bom_stage + test -d $pp_wrkdir/bom_stage && $pp_macos_sudo rm -rf $pp_wrkdir/bom_stage + + # Create the flat package with xar (like pkgutil --flatten does) + # Note that --distribution is only supported by Mac OS X 10.6 and above + xar_flags="--compression=bzip2 --no-compress Scripts --no-compress Payload" + case $mac_version in + "10.5"*) ;; + *) xar_flags="$xar_flags --distribution";; + esac + (cd $pkgdir && /usr/bin/xar $xar_flags -cf "../$name-$version.pkg" *) } pp_backend_macos_cleanup () { @@ -6628,7 +7272,11 @@ pp_backend_macos_cleanup () { } pp_backend_macos_names () { - echo ${name}.pkg + case "$pp_macos_pkg_type" in + bundle) echo ${name}.pkg;; + flat) echo ${name}-${version}.pkg;; + *) pp_error "unsupported package type $pp_macos_pkg_type";; + esac } pp_backend_macos_install_script () { @@ -6692,7 +7340,106 @@ pp_backend_macos_install_script () { } pp_backend_macos_init_svc_vars () { - : + pp_macos_start_services_after_install=false + pp_macos_service_name= + pp_macos_default_service_id_prefix="com.quest.rc." + pp_macos_service_id= + pp_macos_service_user= + pp_macos_service_group= + pp_macos_service_initgroups= + pp_macos_service_umask= + pp_macos_service_cwd= + pp_macos_service_nice= + pp_macos_svc_plist_file= +} + +pp_macos_launchd_plist () { + typeset svc svc_id + + svc="$1" + svc_id="$2" + + set -- $cmd + + if [ -n "$pp_macos_svc_plist_file" ]; then + echo "## Launchd plist file already defined at $pp_macos_svc_plist_file" + return + fi + + echo "## Generating the launchd plist file for $svc" + pp_macos_svc_plist_file="$pp_wrkdir/$svc.plist" + cat <<-. > $pp_macos_svc_plist_file + + + + + Label + $svc_id + ProgramArguments + +. + while test $# != 0; do + printf " $1\n" >> $pp_macos_svc_plist_file + shift + done + cat <<-. >> $pp_macos_svc_plist_file + + KeepAlive + +. + if test -n "$pp_macos_service_user"; then + printf " UserName\n" >> $pp_macos_svc_plist_file + printf " $pp_macos_service_user\n" >> $pp_macos_svc_plist_file + fi + if test -n "$pp_macos_service_group"; then + printf " GroupName\n" >> $pp_macos_svc_plist_file + printf " $pp_macos_service_group\n" >> $pp_macos_svc_plist_file + fi + if test -n "$pp_macos_service_initgroups"; then + printf " InitGroups\n" >> $pp_macos_svc_plist_file + printf " $pp_macos_service_initgroups\n" >> $pp_macos_svc_plist_file + fi + if test -n "$pp_macos_service_umask"; then + printf " Umask\n" >> $pp_macos_svc_plist_file + printf " $pp_macos_service_umask\n" >> $pp_macos_svc_plist_file + fi + if test -n "$pp_macos_service_cwd"; then + printf " WorkingDirectory\n" >> $pp_macos_svc_plist_file + printf " $pp_macos_service_cwd\n" >> $pp_macos_svc_plist_file + fi + if test -n "$pp_macos_service_nice"; then + printf " Nice\n" >> $pp_macos_svc_plist_file + printf " $pp_macos_service_nice\n" >> $pp_macos_svc_plist_file + fi + cat <<-. >> $pp_macos_svc_plist_file + + +. +} + +pp_macos_add_service () { + typeset svc svc_id plist_file plist_dir + + pp_load_service_vars "$1" + svc=${pp_macos_service_name:-$1} + svc_id=${pp_macos_service_id:-$pp_macos_default_service_id_prefix$svc} + + #-- create a plist file for svc + pp_macos_launchd_plist "$svc" "$svc_id" + + #-- copy the plist file into place and add to %files + plist_dir="/Library/LaunchDaemons" + plist_file="$plist_dir/$svc_id.plist" + mkdir -p "$pp_destdir/$plist_dir" + cp "$pp_macos_svc_plist_file" "$pp_destdir/$plist_file" + pp_add_file_if_missing "$plist_file" + + #-- add code to start the service on install + ${pp_macos_start_services_after_install} && <<-. >> $pp_wrkdir/%post.$svc + # start service '$svc' automatically after install + launchctl load "$plist_file" +. } pp_backend_macos_probe () { @@ -6710,7 +7457,7 @@ pp_backend_macos_vas_platforms () { echo "osx" # XXX non-really sure what they do.. it should be "macos" } pp_backend_macos_function () { - case $1 in + case "$1" in _pp_macos_search_unused) cat<<'.';; # Find an unused value in the given path # args: path attribute minid [maxid] diff --git a/pwutil.c b/pwutil.c deleted file mode 100644 index 35524f3..0000000 --- a/pwutil.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - */ - -#include - -#include -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#ifdef HAVE_SETAUTHDB -# include -#endif /* HAVE_SETAUTHDB */ -#include -#include - -#include "sudo.h" -#include "redblack.h" - -/* - * The passwd and group caches. - */ -static struct rbtree *pwcache_byuid, *pwcache_byname; -static struct rbtree *grcache_bygid, *grcache_byname; - -static int cmp_pwuid __P((const void *, const void *)); -static int cmp_pwnam __P((const void *, const void *)); -static int cmp_grgid __P((const void *, const void *)); -static int cmp_grnam __P((const void *, const void *)); - -/* - * Compare by uid. - */ -static int -cmp_pwuid(v1, v2) - const void *v1; - const void *v2; -{ - const struct passwd *pw1 = (const struct passwd *) v1; - const struct passwd *pw2 = (const struct passwd *) v2; - return(pw1->pw_uid - pw2->pw_uid); -} - -/* - * Compare by user name. - */ -static int -cmp_pwnam(v1, v2) - const void *v1; - const void *v2; -{ - const struct passwd *pw1 = (const struct passwd *) v1; - const struct passwd *pw2 = (const struct passwd *) v2; - return(strcasecmp(pw1->pw_name, pw2->pw_name)); -} - -#define FIELD_SIZE(src, name, size) \ -do { \ - if (src->name) { \ - size = strlen(src->name) + 1; \ - total += size; \ - } \ -} while (0) - -#define FIELD_COPY(src, dst, name, size) \ -do { \ - if (src->name) { \ - memcpy(cp, src->name, size); \ - dst->name = cp; \ - cp += size; \ - } \ -} while (0) - -/* - * Dynamically allocate space for a struct password and the constituent parts - * that we care about. Fills in pw_passwd from shadow file. - */ -static struct passwd * -sudo_pwdup(pw) - const struct passwd *pw; -{ - char *cp; - const char *pw_shell; - size_t nsize, psize, csize, gsize, dsize, ssize, total; - struct passwd *newpw; - - /* If shell field is empty, expand to _PATH_BSHELL. */ - pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0') - ? _PATH_BSHELL : pw->pw_shell; - - /* Allocate in one big chunk for easy freeing. */ - nsize = psize = csize = gsize = dsize = ssize = 0; - total = sizeof(struct passwd); - FIELD_SIZE(pw, pw_name, nsize); - FIELD_SIZE(pw, pw_passwd, psize); -#ifdef HAVE_LOGIN_CAP_H - FIELD_SIZE(pw, pw_class, csize); -#endif - FIELD_SIZE(pw, pw_gecos, gsize); - FIELD_SIZE(pw, pw_dir, dsize); - /* Treat shell specially since we expand "" -> _PATH_BSHELL */ - ssize = strlen(pw_shell) + 1; - total += ssize; - - if ((cp = malloc(total)) == NULL) - return(NULL); - newpw = (struct passwd *) cp; - - /* - * Copy in passwd contents and make strings relative to space - * at the end of the buffer. - */ - memcpy(newpw, pw, sizeof(struct passwd)); - cp += sizeof(struct passwd); - FIELD_COPY(pw, newpw, pw_name, nsize); - FIELD_COPY(pw, newpw, pw_passwd, psize); -#ifdef HAVE_LOGIN_CAP_H - FIELD_COPY(pw, newpw, pw_class, csize); -#endif - FIELD_COPY(pw, newpw, pw_gecos, gsize); - FIELD_COPY(pw, newpw, pw_dir, dsize); - /* Treat shell specially since we expand "" -> _PATH_BSHELL */ - memcpy(cp, pw_shell, ssize); - newpw->pw_shell = cp; - - return(newpw); -} - -/* - * Get a password entry by uid and allocate space for it. - * Fills in pw_passwd from shadow file if necessary. - */ -struct passwd * -sudo_getpwuid(uid) - uid_t uid; -{ - struct passwd key, *pw; - struct rbnode *node; - char *cp; - - key.pw_uid = uid; - if ((node = rbfind(pwcache_byuid, &key)) != NULL) { - pw = (struct passwd *) node->data; - goto done; - } - /* - * Cache passwd db entry if it exists or a negative response if not. - */ -#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); - } 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); - } -#ifdef HAVE_SETAUTHDB - aix_restoreauthdb(); -#endif -done: - return(pw->pw_name != NULL ? pw : NULL); -} - -/* - * Get a password entry by name and allocate space for it. - * Fills in pw_passwd from shadow file if necessary. - */ -struct passwd * -sudo_getpwnam(name) - const char *name; -{ - struct passwd key, *pw; - struct rbnode *node; - size_t len; - char *cp; - - key.pw_name = (char *) name; - if ((node = rbfind(pwcache_byname, &key)) != NULL) { - pw = (struct passwd *) node->data; - goto done; - } - /* - * Cache passwd db entry if it exists or a negative response if not. - */ -#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) - 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) - 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); -} - -/* - * Take a uid in string form "#123" and return a faked up passwd struct. - */ -struct passwd * -sudo_fakepwnam(user, gid) - const char *user; - gid_t gid; -{ - struct passwd *pw; - struct rbnode *node; - size_t len; - - len = strlen(user); - pw = emalloc(sizeof(struct passwd) + len + 1 /* pw_name */ + - sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ + - sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL)); - zero_bytes(pw, sizeof(struct passwd)); - pw->pw_uid = (uid_t) atoi(user + 1); - pw->pw_gid = gid; - pw->pw_name = (char *)pw + sizeof(struct passwd); - memcpy(pw->pw_name, user, len + 1); - pw->pw_passwd = pw->pw_name + len + 1; - memcpy(pw->pw_passwd, "*", 2); - pw->pw_gecos = pw->pw_passwd + 2; - pw->pw_gecos[0] = '\0'; - pw->pw_dir = pw->pw_gecos + 1; - memcpy(pw->pw_dir, "/", 2); - pw->pw_shell = pw->pw_dir + 2; - memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL)); - - /* Store by uid and by name, overwriting cached version. */ - if ((node = rbinsert(pwcache_byuid, pw)) != NULL) { - efree(node->data); - node->data = (void *) pw; - } - if ((node = rbinsert(pwcache_byname, pw)) != NULL) { - efree(node->data); - node->data = (void *) pw; - } - return(pw); -} - -/* - * Take a gid in string form "#123" and return a faked up group struct. - */ -struct group * -sudo_fakegrnam(group) - const char *group; -{ - struct group *gr; - struct rbnode *node; - size_t len; - - len = strlen(group); - gr = emalloc(sizeof(struct group) + len + 1); - zero_bytes(gr, sizeof(struct group)); - gr->gr_gid = (gid_t) atoi(group + 1); - gr->gr_name = (char *)gr + sizeof(struct group); - strlcpy(gr->gr_name, group, len + 1); - - /* Store by gid and by name, overwriting cached version. */ - if ((node = rbinsert(grcache_bygid, gr)) != NULL) { - efree(node->data); - node->data = (void *) gr; - } - if ((node = rbinsert(grcache_byname, gr)) != NULL) { - efree(node->data); - node->data = (void *) gr; - } - return(gr); -} - -void -sudo_setpwent() -{ - setpwent(); - sudo_setspent(); - if (pwcache_byuid == NULL) - pwcache_byuid = rbcreate(cmp_pwuid); - if (pwcache_byname == NULL) - pwcache_byname = rbcreate(cmp_pwnam); -} - -#ifdef PURIFY -static void pw_free __P((void *)); - -void -sudo_freepwcache() -{ - if (pwcache_byuid != NULL) { - rbdestroy(pwcache_byuid, pw_free); - pwcache_byuid = NULL; - } - if (pwcache_byname != NULL) { - rbdestroy(pwcache_byname, NULL); - pwcache_byname = NULL; - } -} - -static void -pw_free(v) - void *v; -{ - struct passwd *pw = (struct passwd *) v; - - if (pw->pw_passwd != NULL) { - zero_bytes(pw->pw_passwd, strlen(pw->pw_passwd)); - efree(pw->pw_passwd); - } - efree(pw); -} -#endif /* PURIFY */ - -void -sudo_endpwent() -{ - endpwent(); - sudo_endspent(); -#ifdef PURIFY - sudo_freepwcache(); -#endif -} - -/* - * Compare by gid. - */ -static int -cmp_grgid(v1, v2) - const void *v1; - const void *v2; -{ - const struct group *grp1 = (const struct group *) v1; - const struct group *grp2 = (const struct group *) v2; - return(grp1->gr_gid - grp2->gr_gid); -} - -/* - * Compare by group name. - */ -static int -cmp_grnam(v1, v2) - const void *v1; - const void *v2; -{ - const struct group *grp1 = (const struct group *) v1; - const struct group *grp2 = (const struct group *) v2; - return(strcasecmp(grp1->gr_name, grp2->gr_name)); -} - -struct group * -sudo_grdup(gr) - const struct group *gr; -{ - char *cp; - size_t nsize, psize, nmem, total, len; - struct group *newgr; - - /* Allocate in one big chunk for easy freeing. */ - nsize = psize = nmem = 0; - total = sizeof(struct group); - FIELD_SIZE(gr, gr_name, nsize); - FIELD_SIZE(gr, gr_passwd, psize); - if (gr->gr_mem) { - for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) - total += strlen(gr->gr_mem[nmem]) + 1; - nmem++; - total += sizeof(char *) * nmem; - } - if ((cp = malloc(total)) == NULL) - return(NULL); - newgr = (struct group *)cp; - - /* - * Copy in group contents and make strings relative to space - * at the end of the buffer. Note that gr_mem must come - * immediately after struct group to guarantee proper alignment. - */ - (void)memcpy(newgr, gr, sizeof(struct group)); - cp += sizeof(struct group); - if (gr->gr_mem) { - newgr->gr_mem = (char **)cp; - cp += sizeof(char *) * nmem; - for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) { - len = strlen(gr->gr_mem[nmem]) + 1; - memcpy(cp, gr->gr_mem[nmem], len); - newgr->gr_mem[nmem] = cp; - cp += len; - } - newgr->gr_mem[nmem] = NULL; - } - FIELD_COPY(gr, newgr, gr_passwd, psize); - FIELD_COPY(gr, newgr, gr_name, nsize); - - return(newgr); -} - -/* - * Get a group entry by gid and allocate space for it. - */ -struct group * -sudo_getgrgid(gid) - gid_t gid; -{ - struct group key, *gr; - struct rbnode *node; - - key.gr_gid = gid; - if ((node = rbfind(grcache_bygid, &key)) != NULL) { - gr = (struct group *) node->data; - 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); - } 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"); - } -done: - return(gr->gr_name != NULL ? gr : NULL); -} - -/* - * Get a group entry by name and allocate space for it. - */ -struct group * -sudo_getgrnam(name) - const char *name; -{ - struct group key, *gr; - struct rbnode *node; - size_t len; - char *cp; - - key.gr_name = (char *) name; - if ((node = rbfind(grcache_byname, &key)) != NULL) { - gr = (struct group *) node->data; - 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) - 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) - errorx(1, "unable to cache group %s, already exists", name); - } -done: - return(gr->gr_gid != (gid_t) -1 ? gr : NULL); -} - -void -sudo_setgrent() -{ - setgrent(); - if (grcache_bygid == NULL) - grcache_bygid = rbcreate(cmp_grgid); - if (grcache_byname == NULL) - grcache_byname = rbcreate(cmp_grnam); -} - -#ifdef PURIFY -void -sudo_freegrcache() -{ - if (grcache_bygid != NULL) { - rbdestroy(grcache_bygid, free); - grcache_bygid = NULL; - } - if (grcache_byname != NULL) { - rbdestroy(grcache_byname, NULL); - grcache_byname = NULL; - } -} -#endif /* PURIFY */ - -void -sudo_endgrent() -{ - endgrent(); -#ifdef PURIFY - sudo_freegrcache(); -#endif -} - -int -user_in_group(pw, group) - struct passwd *pw; - const char *group; -{ -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - uuid_t gu, uu; - int ismember; -#else - char **gr_mem; - int i; -#endif - struct group *grp; - -#ifdef HAVE_SETAUTHDB - aix_setauthdb(pw->pw_name); -#endif - grp = sudo_getgrnam(group); -#ifdef HAVE_SETAUTHDB - aix_restoreauthdb(); -#endif - if (grp == NULL) - return(FALSE); - - /* check against user's primary (passwd file) gid */ - if (grp->gr_gid == pw->pw_gid) - return(TRUE); - -#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); - } 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); - } -#else /* HAVE_MBR_CHECK_MEMBERSHIP */ -# ifdef HAVE_GETGROUPS - /* - * If we are matching the invoking or list user and that user has a - * supplementary group vector, check it. - */ - if (user_ngroups >= 0 && - strcmp(pw->pw_name, list_pw ? list_pw->pw_name : user_name) == 0) { - for (i = 0; i < user_ngroups; i++) { - if (grp->gr_gid == user_groups[i]) - return(TRUE); - } - } 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); - } - } - } -#endif /* HAVE_MBR_CHECK_MEMBERSHIP */ - - return(FALSE); -} diff --git a/redblack.c b/redblack.c deleted file mode 100644 index 95ac095..0000000 --- a/redblack.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007,2009 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. - */ - -/* - * Adapted from the following code written by Emin Martinian: - * http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html - * - * Copyright (c) 2001 Emin Martinian - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that neither the name of Emin - * Martinian nor the names of any contributors are be used to endorse or - * promote products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include - -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ - -#include "sudo.h" -#include "redblack.h" - -static void rbrepair __P((struct rbtree *, struct rbnode *)); -static void rotate_left __P((struct rbtree *, struct rbnode *)); -static void rotate_right __P((struct rbtree *, struct rbnode *)); -static void _rbdestroy __P((struct rbtree *, struct rbnode *, - void (*)(void *))); - -/* - * Red-Black tree, see http://en.wikipedia.org/wiki/Red-black_tree - * - * A red-black tree is a binary search tree where each node has a color - * attribute, the value of which is either red or black. Essentially, it - * is just a convenient way to express a 2-3-4 binary search tree where - * the color indicates whether the node is part of a 3-node or a 4-node. - * In addition to the ordinary requirements imposed on binary search - * trees, we make the following additional requirements of any valid - * red-black tree: - * 1) Every node is either red or black. - * 2) The root is black. - * 3) All leaves are black. - * 4) Both children of each red node are black. - * 5) The paths from each leaf up to the root each contain the same - * number of black nodes. - */ - -/* - * Create a red black tree struct using the specified compare routine. - * Allocates and returns the initialized (empty) tree. - */ -struct rbtree * -rbcreate(compar) - int (*compar)__P((const void *, const void*)); -{ - struct rbtree *tree; - - tree = (struct rbtree *) emalloc(sizeof(*tree)); - tree->compar = compar; - - /* - * We use a self-referencing sentinel node called nil to simplify the - * code by avoiding the need to check for NULL pointers. - */ - tree->nil.left = tree->nil.right = tree->nil.parent = &tree->nil; - tree->nil.color = black; - tree->nil.data = NULL; - - /* - * Similarly, the fake root node keeps us from having to worry - * about splitting the root. - */ - tree->root.left = tree->root.right = tree->root.parent = &tree->nil; - tree->root.color = black; - tree->root.data = NULL; - - return(tree); -} - -/* - * Perform a left rotation starting at node. - */ -static void -rotate_left(tree, node) - struct rbtree *tree; - struct rbnode *node; -{ - struct rbnode *child; - - child = node->right; - node->right = child->left; - - if (child->left != rbnil(tree)) - child->left->parent = node; - child->parent = node->parent; - - if (node == node->parent->left) - node->parent->left = child; - else - node->parent->right = child; - child->left = node; - node->parent = child; -} - -/* - * Perform a right rotation starting at node. - */ -static void -rotate_right(tree, node) - struct rbtree *tree; - struct rbnode *node; -{ - struct rbnode *child; - - child = node->left; - node->left = child->right; - - if (child->right != rbnil(tree)) - child->right->parent = node; - child->parent = node->parent; - - if (node == node->parent->left) - node->parent->left = child; - else - node->parent->right = child; - child->right = node; - node->parent = child; -} - -/* - * Insert data pointer into a redblack tree. - * Returns a NULL pointer on success. If a node matching "data" - * already exists, a pointer to the existant node is returned. - */ -struct rbnode * -rbinsert(tree, data) - struct rbtree *tree; - void *data; -{ - struct rbnode *node = rbfirst(tree); - struct rbnode *parent = rbroot(tree); - int res; - - /* Find correct insertion point. */ - while (node != rbnil(tree)) { - parent = node; - if ((res = tree->compar(data, node->data)) == 0) - return(node); - node = res < 0 ? node->left : node->right; - } - - node = (struct rbnode *) emalloc(sizeof(*node)); - node->data = data; - node->left = node->right = rbnil(tree); - node->parent = parent; - if (parent == rbroot(tree) || tree->compar(data, parent->data) < 0) - parent->left = node; - else - parent->right = node; - node->color = red; - - /* - * If the parent node is black we are all set, if it is red we have - * the following possible cases to deal with. We iterate through - * the rest of the tree to make sure none of the required properties - * is violated. - * - * 1) The uncle is red. We repaint both the parent and uncle black - * and repaint the grandparent node red. - * - * 2) The uncle is black and the new node is the right child of its - * parent, and the parent in turn is the left child of its parent. - * We do a left rotation to switch the roles of the parent and - * child, relying on further iterations to fixup the old parent. - * - * 3) The uncle is black and the new node is the left child of its - * parent, and the parent in turn is the left child of its parent. - * We switch the colors of the parent and grandparent and perform - * a right rotation around the grandparent. This makes the former - * parent the parent of the new node and the former grandparent. - * - * Note that because we use a sentinel for the root node we never - * need to worry about replacing the root. - */ - while (node->parent->color == red) { - struct rbnode *uncle; - if (node->parent == node->parent->parent->left) { - uncle = node->parent->parent->right; - if (uncle->color == red) { - node->parent->color = black; - uncle->color = black; - node->parent->parent->color = red; - node = node->parent->parent; - } else /* if (uncle->color == black) */ { - if (node == node->parent->right) { - node = node->parent; - rotate_left(tree, node); - } - node->parent->color = black; - node->parent->parent->color = red; - rotate_right(tree, node->parent->parent); - } - } else { /* if (node->parent == node->parent->parent->right) */ - uncle = node->parent->parent->left; - if (uncle->color == red) { - node->parent->color = black; - uncle->color = black; - node->parent->parent->color = red; - node = node->parent->parent; - } else /* if (uncle->color == black) */ { - if (node == node->parent->left) { - node = node->parent; - rotate_right(tree, node); - } - node->parent->color = black; - node->parent->parent->color = red; - rotate_left(tree, node->parent->parent); - } - } - } - rbfirst(tree)->color = black; /* first node is always black */ - return(NULL); -} - -/* - * Look for a node matching key in tree. - * Returns a pointer to the node if found, else NULL. - */ -struct rbnode * -rbfind(tree, key) - struct rbtree *tree; - void *key; -{ - struct rbnode *node = rbfirst(tree); - int res; - - while (node != rbnil(tree)) { - if ((res = tree->compar(key, node->data)) == 0) - return(node); - node = res < 0 ? node->left : node->right; - } - return(NULL); -} - -/* - * Call func() for each node, passing it the node data and a cookie; - * If func() returns non-zero for a node, the traversal stops and the - * error value is returned. Returns 0 on successful traversal. - */ -int -rbapply_node(tree, node, func, cookie, order) - struct rbtree *tree; - struct rbnode *node; - int (*func)__P((void *, void *)); - void *cookie; - enum rbtraversal order; -{ - int error; - - if (node != rbnil(tree)) { - if (order == preorder) - if ((error = func(node->data, cookie)) != 0) - return(error); - if ((error = rbapply_node(tree, node->left, func, cookie, order)) != 0) - return(error); - if (order == inorder) - if ((error = func(node->data, cookie)) != 0) - return(error); - if ((error = rbapply_node(tree, node->right, func, cookie, order)) != 0) - return(error); - if (order == postorder) - if ((error = func(node->data, cookie)) != 0) - return(error); - } - return (0); -} - -/* - * Returns the successor of node, or nil if there is none. - */ -static struct rbnode * -rbsuccessor(tree, node) - struct rbtree *tree; - struct rbnode *node; -{ - struct rbnode *succ; - - if ((succ = node->right) != rbnil(tree)) { - while (succ->left != rbnil(tree)) - succ = succ->left; - } else { - /* No right child, move up until we find it or hit the root */ - for (succ = node->parent; node == succ->right; succ = succ->parent) - node = succ; - if (succ == rbroot(tree)) - succ = rbnil(tree); - } - return(succ); -} - -/* - * Recursive portion of rbdestroy(). - */ -static void -_rbdestroy(tree, node, destroy) - struct rbtree *tree; - struct rbnode *node; - void (*destroy)__P((void *)); -{ - if (node != rbnil(tree)) { - _rbdestroy(tree, node->left, destroy); - _rbdestroy(tree, node->right, destroy); - if (destroy != NULL) - destroy(node->data); - efree(node); - } -} - -/* - * Destroy the specified tree, calling the destructor destroy - * for each node and then freeing the tree itself. - */ -void -rbdestroy(tree, destroy) - struct rbtree *tree; - void (*destroy)__P((void *)); -{ - _rbdestroy(tree, rbfirst(tree), destroy); - efree(tree); -} - -/* - * Delete node 'z' from the tree and return its data pointer. - */ -void *rbdelete(tree, z) - struct rbtree *tree; - struct rbnode *z; -{ - struct rbnode *x, *y; - void *data = z->data; - - if (z->left == rbnil(tree) || z->right == rbnil(tree)) - y = z; - else - y = rbsuccessor(tree, z); - x = (y->left == rbnil(tree)) ? y->right : y->left; - - if ((x->parent = y->parent) == rbroot(tree)) { - rbfirst(tree) = x; - } else { - if (y == y->parent->left) - y->parent->left = x; - else - y->parent->right = x; - } - if (y->color == black) - rbrepair(tree, x); - if (y != z) { - y->left = z->left; - y->right = z->right; - y->parent = z->parent; - y->color = z->color; - z->left->parent = z->right->parent = y; - if (z == z->parent->left) - z->parent->left = y; - else - z->parent->right = y; - } - free(z); - - return (data); -} - -/* - * Repair the tree after a node has been deleted by rotating and repainting - * colors to restore the 4 properties inherent in red-black trees. - */ -static void -rbrepair(tree, node) - struct rbtree *tree; - struct rbnode *node; -{ - struct rbnode *sibling; - - while (node->color == black && node != rbroot(tree)) { - if (node == node->parent->left) { - sibling = node->parent->right; - if (sibling->color == red) { - sibling->color = black; - node->parent->color = red; - rotate_left(tree, node->parent); - sibling = node->parent->right; - } - if (sibling->right->color == black && sibling->left->color == black) { - sibling->color = red; - node = node->parent; - } else { - if (sibling->right->color == black) { - sibling->left->color = black; - sibling->color = red; - rotate_right(tree, sibling); - sibling = node->parent->right; - } - sibling->color = node->parent->color; - node->parent->color = black; - sibling->right->color = black; - rotate_left(tree, node->parent); - node = rbroot(tree); /* exit loop */ - } - } else { /* if (node == node->parent->right) */ - sibling = node->parent->left; - if (sibling->color == red) { - sibling->color = black; - node->parent->color = red; - rotate_right(tree, node->parent); - sibling = node->parent->left; - } - if (sibling->right->color == black && sibling->left->color == black) { - sibling->color = red; - node = node->parent; - } else { - if (sibling->left->color == black) { - sibling->right->color = black; - sibling->color = red; - rotate_left(tree, sibling); - sibling = node->parent->left; - } - sibling->color = node->parent->color; - node->parent->color = black; - sibling->left->color = black; - rotate_right(tree, node->parent); - node = rbroot(tree); /* exit loop */ - } - } - } - node->color = black; -} diff --git a/redblack.h b/redblack.h deleted file mode 100644 index b1938ca..0000000 --- a/redblack.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2004, 2007 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_REDBLACK_H -#define _SUDO_REDBLACK_H - -enum rbcolor { - red, - black -}; - -enum rbtraversal { - preorder, - inorder, - postorder -}; - -struct rbnode { - struct rbnode *left, *right, *parent; - void *data; - enum rbcolor color; -}; - -struct rbtree { - int (*compar) __P((const void *, const void *)); - struct rbnode root; - struct rbnode nil; -}; - -#define rbapply(t, f, c, o) rbapply_node((t), (t)->root.left, (f), (c), (o)) -#define rbisempty(t) ((t)->root.left == &(t)->nil && (t)->root.right == &(t)->nil) -#define rbfirst(t) ((t)->root.left) -#define rbroot(t) (&(t)->root) -#define rbnil(t) (&(t)->nil) - -void *rbdelete __P((struct rbtree *, struct rbnode *)); -int rbapply_node __P((struct rbtree *, struct rbnode *, - int (*)(void *, void *), void *, - enum rbtraversal)); -struct rbnode *rbfind __P((struct rbtree *, void *)); -struct rbnode *rbinsert __P((struct rbtree *, void *)); -struct rbtree *rbcreate __P((int (*)(const void *, const void *))); -void rbdestroy __P((struct rbtree *, void (*)(void *))); - -#endif /* _SUDO_REDBLACK_H */ diff --git a/sample.pam b/sample.pam deleted file mode 100644 index d56e712..0000000 --- a/sample.pam +++ /dev/null @@ -1,30 +0,0 @@ -#%PAM-1.0 -# Sample /etc/pam.d/sudo file for RedHat 9 / Fedora Core. -# For other Linux distributions you may want to -# use /etc/pam.d/sshd or /etc/pam.d/su as a guide. -# -# There are two basic ways to configure PAM, either via pam_stack -# or by explicitly specifying the various methods to use. -# -# Here we use pam_stack -auth required pam_stack.so service=system-auth -account required pam_stack.so service=system-auth -password required pam_stack.so service=system-auth -session required pam_stack.so service=system-auth -# -# Alternately, you can specify the authentication method directly. -# Here we use pam_unix for normal password authentication. -#auth required pam_env.so -#auth sufficient pam_unix.so -#account required pam_unix.so -#password required pam_cracklib.so retry=3 type= -#password required pam_unix.so nullok use_authtok md5 shadow -#session required pam_limits.so -#session required pam_unix.so -# -# Another option is to use SMB for authentication. -#auth required pam_env.so -#auth sufficient pam_smb_auth.so -#account required pam_smb_auth.so -#password required pam_smb_auth.so -#session required pam_limits.so diff --git a/sample.sudoers b/sample.sudoers deleted file mode 100644 index 0ef1579..0000000 --- a/sample.sudoers +++ /dev/null @@ -1,131 +0,0 @@ -# -# Sample /etc/sudoers file. -# -# This file MUST be edited with the 'visudo' command as root. -# -# See the sudoers man page for the details on how to write a sudoers file. - -## -# Override built-in defaults -## -Defaults syslog=auth -Defaults>root !set_logname -Defaults:FULLTIMERS !lecture -Defaults:millert !authenticate -Defaults@SERVERS log_year, logfile=/var/log/sudo.log -Defaults!PAGERS noexec - -## -# User alias specification -## -User_Alias FULLTIMERS = millert, mikef, dowdy -User_Alias PARTTIMERS = bostley, jwfox, crawl -User_Alias WEBMASTERS = will, wendy, wim - -## -# Runas alias specification -## -Runas_Alias OP = root, operator -Runas_Alias DB = oracle, sybase - -## -# Host alias specification -## -Host_Alias SPARC = bigtime, eclipse, moet, anchor:\ - SGI = grolsch, dandelion, black:\ - ALPHA = widget, thalamus, foobar:\ - HPPA = boa, nag, python -Host_Alias CUNETS = 128.138.0.0/255.255.0.0 -Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 -Host_Alias SERVERS = master, mail, www, ns -Host_Alias CDROM = orion, perseus, hercules - -## -# Cmnd alias specification -## -Cmnd_Alias DUMPS = /usr/sbin/dump, /usr/sbin/rdump, /usr/sbin/restore, \ - /usr/sbin/rrestore, /usr/bin/mt -Cmnd_Alias KILL = /usr/bin/kill -Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm -Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown -Cmnd_Alias HALT = /usr/sbin/halt -Cmnd_Alias REBOOT = /usr/sbin/reboot -Cmnd_Alias SHELLS = /sbin/sh, /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \ - /usr/local/bin/tcsh, /usr/bin/rsh, \ - /usr/local/bin/zsh -Cmnd_Alias SU = /usr/bin/su -Cmnd_Alias VIPW = /usr/sbin/vipw, /usr/bin/passwd, /usr/bin/chsh, \ - /usr/bin/chfn -Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less - -## -# User specification -## - -# root and users in group wheel can run anything on any machine as any user -root ALL = (ALL) ALL -%wheel ALL = (ALL) ALL - -# full time sysadmins can run anything on any machine without a password -FULLTIMERS ALL = NOPASSWD: ALL - -# part time sysadmins may run anything but need a password -PARTTIMERS ALL = ALL - -# jack may run anything on machines in CSNETS -jack CSNETS = ALL - -# lisa may run any command on any host in CUNETS (a class B network) -lisa CUNETS = ALL - -# operator may run maintenance commands and anything in /usr/oper/bin/ -operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\ - sudoedit /etc/printcap, /usr/oper/bin/ - -# joe may su only to operator -joe ALL = /usr/bin/su operator - -# pete may change passwords for anyone but root on the hp snakes -pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root - -# bob may run anything on the sparc and sgi machines as any user -# listed in the Runas_Alias "OP" (ie: root and operator) -bob SPARC = (OP) ALL : SGI = (OP) ALL - -# jim may run anything on machines in the biglab netgroup -jim +biglab = ALL - -# users in the secretaries netgroup need to help manage the printers -# as well as add and remove users -+secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser - -# fred can run commands as oracle or sybase without a password -fred ALL = (DB) NOPASSWD: ALL - -# on the alphas, john may su to anyone but root and flags are not allowed -john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* - -# jen can run anything on all machines except the ones -# in the "SERVERS" Host_Alias -jen ALL, !SERVERS = ALL - -# jill can run any commands in the directory /usr/bin/, except for -# those in the SU and SHELLS aliases. -jill SERVERS = /usr/bin/, !SU, !SHELLS - -# steve can run any command in the directory /usr/local/op_commands/ -# as user operator. -steve CSNETS = (operator) /usr/local/op_commands/ - -# matt needs to be able to kill things on his workstation when -# they get hung. -matt valkyrie = KILL - -# users in the WEBMASTERS User_Alias (will, wendy, and wim) -# may run any command as user www (which owns the web pages) -# or simply su to www. -WEBMASTERS www = (www) ALL, (root) /usr/bin/su www - -# anyone can mount/unmount a cd-rom on the machines in the CDROM alias -ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ - /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM diff --git a/sample.syslog.conf b/sample.syslog.conf deleted file mode 100644 index 686cd19..0000000 --- a/sample.syslog.conf +++ /dev/null @@ -1,26 +0,0 @@ -# This is a sample syslog.conf fragment for use with Sudo. -# -# By default, sudo logs to "authpriv" if your system supports it, else it -# uses "auth". The facility can be set via the --with-logfac configure -# option or in the sudoers file. -# To see what syslog facility a sudo binary uses, run `sudo -V' as *root*. -# -# NOTES: -# The whitespace in the following line is made up of -# characters, *not* spaces. You cannot just cut and paste! -# -# If you edit syslog.conf you need to send syslogd a HUP signal. -# Ie: kill -HUP process_id -# -# Syslogd will not create new log files for you, you must first -# create the file before syslogd will log to it. Eg. -# 'touch /var/log/sudo' - -# This logs successful and failed sudo attempts to the file /var/log/auth -# If your system has the authpriv syslog facility, use authpriv.debug -auth.debug /var/log/auth - -# To log to a remote machine, use something like the following, -# where "loghost" is the name of the remote machine. -# If your system has the authpriv syslog facility, use authpriv.debug -auth.debug @loghost diff --git a/schema.ActiveDirectory b/schema.ActiveDirectory deleted file mode 100644 index 4b87e05..0000000 --- a/schema.ActiveDirectory +++ /dev/null @@ -1,195 +0,0 @@ -# -# Active Directory Schema for sudo configuration (sudoers) -# -# To extend your Active Directory schema, run one of the following command -# on your Windows DC (default port - Active Directory): -# -# ldifde -i -f schema.ActiveDirectory -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext -# -# or on your Windows DC if using another port (with Active Directory LightWeight Directory Services / ADAM-Active Directory Application Mode) -# Port 50000 by example (or any other port specified when defining the ADLDS/ADAM instance -# -# ldifde -i -f schema.ActiveDirectory -t 50000 -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext -# -# or -# -# ldifde -i -f schema.ActiveDirectory -s server:port -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext -# -# Can add username domain and password -# -# -b username domain password -# -# Can create Log file in current or any directory -# -# -j . -# - -dn: CN=sudoUser,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoUser -distinguishedName: CN=sudoUser,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.1 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoUser -adminDescription: User(s) who may run sudo -oMSyntax: 22 -searchFlags: 1 -lDAPDisplayName: sudoUser -name: sudoUser -schemaIDGUID:: JrGcaKpnoU+0s+HgeFjAbg== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: CN=sudoHost,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoHost -distinguishedName: CN=sudoHost,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.2 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoHost -adminDescription: Host(s) who may run sudo -oMSyntax: 22 -lDAPDisplayName: sudoHost -name: sudoHost -schemaIDGUID:: d0TTjg+Y6U28g/Y+ns2k4w== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoCommand -distinguishedName: CN=sudoCommand,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.3 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoCommand -adminDescription: Command(s) to be executed by sudo -oMSyntax: 22 -lDAPDisplayName: sudoCommand -name: sudoCommand -schemaIDGUID:: D6QR4P5UyUen3RGYJCHCPg== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoRunAs -distinguishedName: CN=sudoRunAs,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.4 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoRunAs -adminDescription: User(s) impersonated by sudo (deprecated) -oMSyntax: 22 -lDAPDisplayName: sudoRunAs -name: sudoRunAs -schemaIDGUID:: CP98mCQTyUKKxGrQeM80hQ== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: CN=sudoOption,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoOption -distinguishedName: CN=sudoOption,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.5 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoOption -adminDescription: Option(s) followed by sudo -oMSyntax: 22 -lDAPDisplayName: sudoOption -name: sudoOption -schemaIDGUID:: ojaPzBBlAEmsvrHxQctLnA== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoRunAsUser -distinguishedName: CN=sudoRunAsUser,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.6 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoRunAsUser -adminDescription: User(s) impersonated by sudo -oMSyntax: 22 -lDAPDisplayName: sudoRunAsUser -name: sudoRunAsUser -schemaIDGUID:: 9C52yPYd3RG3jMR2VtiVkw== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: attributeSchema -cn: sudoRunAsGroup -distinguishedName: CN=sudoRunAsGroup,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -attributeID: 1.3.6.1.4.1.15953.9.1.7 -attributeSyntax: 2.5.5.5 -isSingleValued: FALSE -showInAdvancedViewOnly: TRUE -adminDisplayName: sudoRunAsGroup -adminDescription: Groups(s) impersonated by sudo -oMSyntax: 22 -lDAPDisplayName: sudoRunAsGroup -name: sudoRunAsGroup -schemaIDGUID:: xJhSt/Yd3RGJPTB1VtiVkw== -objectCategory: CN=Attribute-Schema,CN=Schema,CN=Configuration,DC=X - -dn: -changetype: modify -add: schemaUpdateNow -schemaUpdateNow: 1 -- - -dn: CN=sudoRole,CN=Schema,CN=Configuration,DC=X -changetype: add -objectClass: top -objectClass: classSchema -cn: sudoRole -distinguishedName: CN=sudoRole,CN=Schema,CN=Configuration,DC=X -instanceType: 4 -possSuperiors: container -possSuperiors: top -subClassOf: top -governsID: 1.3.6.1.4.1.15953.9.2.1 -mayContain: sudoCommand -mayContain: sudoHost -mayContain: sudoOption -mayContain: sudoRunAs -mayContain: sudoRunAsUser -mayContain: sudoRunAsGroup -mayContain: sudoUser -rDNAttID: cn -showInAdvancedViewOnly: FALSE -adminDisplayName: sudoRole -adminDescription: Sudoer Entries -objectClassCategory: 1 -lDAPDisplayName: sudoRole -name: sudoRole -schemaIDGUID:: SQn432lnZ0+ukbdh3+gN3w== -systemOnly: FALSE -objectCategory: CN=Class-Schema,CN=Schema,CN=Configuration,DC=X -defaultObjectCategory: CN=sudoRole,CN=Schema,CN=Configuration,DC=X diff --git a/schema.OpenLDAP b/schema.OpenLDAP deleted file mode 100644 index df3fc0f..0000000 --- a/schema.OpenLDAP +++ /dev/null @@ -1,55 +0,0 @@ -# -# OpenLDAP schema file for Sudo -# Save as /etc/openldap/schema/sudo.schema -# - -attributetype ( 1.3.6.1.4.1.15953.9.1.1 - NAME 'sudoUser' - DESC 'User(s) who may run sudo' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -attributetype ( 1.3.6.1.4.1.15953.9.1.2 - NAME 'sudoHost' - DESC 'Host(s) who may run sudo' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -attributetype ( 1.3.6.1.4.1.15953.9.1.3 - NAME 'sudoCommand' - DESC 'Command(s) to be executed by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -attributetype ( 1.3.6.1.4.1.15953.9.1.4 - NAME 'sudoRunAs' - DESC 'User(s) impersonated by sudo (deprecated)' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -attributetype ( 1.3.6.1.4.1.15953.9.1.5 - NAME 'sudoOption' - DESC 'Options(s) followed by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -attributetype ( 1.3.6.1.4.1.15953.9.1.6 - NAME 'sudoRunAsUser' - DESC 'User(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -attributetype ( 1.3.6.1.4.1.15953.9.1.7 - NAME 'sudoRunAsGroup' - DESC 'Group(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - -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 ) - ) diff --git a/schema.iPlanet b/schema.iPlanet deleted file mode 100644 index 3718fd7..0000000 --- a/schema.iPlanet +++ /dev/null @@ -1,9 +0,0 @@ -dn: cn=schema -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -attributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) -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' ) diff --git a/selinux.c b/selinux.c deleted file mode 100644 index 2c03e6c..0000000 --- a/selinux.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2009-2010 Todd C. Miller - * Copyright (c) 2008 Dan Walsh - * - * Borrowed heavily from newrole source code - * Authors: - * Anthony Colatrella - * Tim Fraser - * Steve Grubb - * Darrel Goeddel - * Michael Thompson - * Dan Walsh - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_LINUX_AUDIT -#include -#endif - -#include /* for SECCLASS_CHR_FILE */ -#include /* for is_selinux_enabled() */ -#include /* for context-mangling functions */ -#include -#include - -#include "sudo.h" -#include "linux_audit.h" - -static struct selinux_state { - security_context_t old_context; - security_context_t new_context; - security_context_t tty_context; - security_context_t new_tty_context; - const char *ttyn; - int ttyfd; - int enforcing; -} se_state; - -/* - * This function attempts to revert the relabeling done to the tty. - * fd - referencing the opened ttyn - * ttyn - name of tty to restore - * - * Returns zero on success, non-zero otherwise - */ -int -selinux_restore_tty(void) -{ - int retval = 0; - security_context_t chk_tty_context = NULL; - - if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL) - goto skip_relabel; - - /* Verify that the tty still has the context set by sudo. */ - if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) { - warning("unable to fgetfilecon %s", se_state.ttyn); - goto skip_relabel; - } - - if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) { - warningx("%s changed labels.", se_state.ttyn); - goto skip_relabel; - } - - if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0) - warning("unable to restore context for %s", se_state.ttyn); - -skip_relabel: - if (se_state.ttyfd != -1) { - close(se_state.ttyfd); - se_state.ttyfd = -1; - } - if (chk_tty_context != NULL) { - freecon(chk_tty_context); - chk_tty_context = NULL; - } - return retval; -} - -/* - * This function attempts to relabel the tty. If this function fails, then - * the contexts are free'd and -1 is returned. On success, 0 is returned - * and tty_context and new_tty_context are set. - * - * This function will not fail if it can not relabel the tty when selinux is - * in permissive mode. - */ -static int -relabel_tty(const char *ttyn, int ptyfd) -{ - security_context_t tty_con = NULL; - security_context_t new_tty_con = NULL; - int fd; - - se_state.ttyfd = ptyfd; - - /* It is perfectly legal to have no tty. */ - if (ptyfd == -1 && ttyn == NULL) - return 0; - - /* If sudo is not allocating a pty for the command, open current tty. */ - if (ptyfd == -1) { - se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); - if (se_state.ttyfd == -1) { - warning("unable to open %s, not relabeling tty", ttyn); - if (se_state.enforcing) - goto bad; - } - (void)fcntl(se_state.ttyfd, F_SETFL, - fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK); - } - - if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) { - warning("unable to get current tty context, not relabeling tty"); - if (se_state.enforcing) - goto bad; - } - - if (tty_con && (security_compute_relabel(se_state.new_context, tty_con, - SECCLASS_CHR_FILE, &new_tty_con) < 0)) { - warning("unable to get new tty context, not relabeling tty"); - if (se_state.enforcing) - goto bad; - } - - if (new_tty_con != NULL) { - if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) { - warning("unable to set new tty context"); - if (se_state.enforcing) - goto bad; - } - } - - if (ptyfd != -1) { - /* Reopen pty that was relabeled, std{in,out,err} are reset later. */ - se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0); - if (se_state.ttyfd == -1) { - warning("cannot open %s", ttyn); - if (se_state.enforcing) - goto bad; - } - if (dup2(se_state.ttyfd, ptyfd) == -1) { - warning("dup2"); - goto bad; - } - } else { - /* Re-open tty to get new label and reset std{in,out,err} */ - close(se_state.ttyfd); - se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); - if (se_state.ttyfd == -1) { - warning("unable to open %s", ttyn); - goto bad; - } - (void)fcntl(se_state.ttyfd, F_SETFL, - fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK); - for (fd = STDIN_FILENO; fd <= STDERR_FILENO; fd++) { - if (isatty(fd) && dup2(se_state.ttyfd, fd) == -1) { - warning("dup2"); - goto bad; - } - } - } - /* Retain se_state.ttyfd so we can restore label when command finishes. */ - (void)fcntl(se_state.ttyfd, F_SETFD, FD_CLOEXEC); - - se_state.ttyn = ttyn; - se_state.tty_context = tty_con; - se_state.new_tty_context = new_tty_con; - return 0; - -bad: - if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) { - close(se_state.ttyfd); - se_state.ttyfd = -1; - } - freecon(tty_con); - return -1; -} - -/* - * Returns a new security context based on the old context and the - * specified role and type. - */ -security_context_t -get_exec_context(security_context_t old_context, const char *role, const char *type) -{ - security_context_t new_context = NULL; - context_t context = NULL; - char *typebuf = NULL; - - /* We must have a role, the type is optional (we can use the default). */ - if (!role) { - warningx("you must specify a role for type %s", type); - errno = EINVAL; - return NULL; - } - if (!type) { - if (get_default_type(role, &typebuf)) { - warningx("unable to get default type for role %s", role); - errno = EINVAL; - return NULL; - } - type = typebuf; - } - - /* - * Expand old_context into a context_t so that we extract and modify - * its components easily. - */ - context = context_new(old_context); - - /* - * Replace the role and type in "context" with the role and - * type we will be running the command as. - */ - if (context_role_set(context, role)) { - warning("failed to set new role %s", role); - goto bad; - } - if (context_type_set(context, type)) { - warning("failed to set new type %s", type); - goto bad; - } - - /* - * Convert "context" back into a string and verify it. - */ - new_context = estrdup(context_str(context)); - if (security_check_context(new_context) < 0) { - warningx("%s is not a valid context", new_context); - errno = EINVAL; - goto bad; - } - -#ifdef DEBUG - warningx("Your new context is %s", new_context); -#endif - - context_free(context); - return new_context; - -bad: - free(typebuf); - context_free(context); - freecon(new_context); - return NULL; -} - -/* - * Set the exec and tty contexts in preparation for fork/exec. - * Must run as root, before the uid change. - * If ptyfd is not -1, it indicates we are running - * in a pty and do not need to reset std{in,out,err}. - * Returns 0 on success and -1 on failure. - */ -int -selinux_setup(const char *role, const char *type, const char *ttyn, - int ptyfd) -{ - int rval = -1; - - /* Store the caller's SID in old_context. */ - if (getprevcon(&se_state.old_context)) { - warning("failed to get old_context"); - goto done; - } - - se_state.enforcing = security_getenforce(); - if (se_state.enforcing < 0) { - warning("unable to determine enforcing mode."); - goto done; - } - -#ifdef DEBUG - warningx("your old context was %s", se_state.old_context); -#endif - se_state.new_context = get_exec_context(se_state.old_context, role, type); - if (!se_state.new_context) - goto done; - - if (relabel_tty(ttyn, ptyfd) < 0) { - warning("unable to setup tty context for %s", se_state.new_context); - goto done; - } - -#ifdef DEBUG - if (se_state.ttyfd != -1) { - warningx("your old tty context is %s", se_state.tty_context); - warningx("your new tty context is %s", se_state.new_tty_context); - } -#endif - -#ifdef HAVE_LINUX_AUDIT - linux_audit_role_change(se_state.old_context, se_state.new_context, - se_state.ttyn); -#endif - - rval = 0; - -done: - return rval; -} - -void -selinux_execve(const char *path, char *argv[], char *envp[]) -{ - if (setexeccon(se_state.new_context)) { - warning("unable to set exec context to %s", se_state.new_context); - if (se_state.enforcing) - return; - } - -#ifdef HAVE_SETKEYCREATECON - if (setkeycreatecon(se_state.new_context)) { - warning("unable to set key creation context to %s", se_state.new_context); - if (se_state.enforcing) - return; - } -#endif /* HAVE_SETKEYCREATECON */ - - /* We use the "spare" slot in argv to store sesh. */ - --argv; - argv[0] = *argv[1] == '-' ? "-sesh" : "sesh"; - argv[1] = (char *)path; - - execve(_PATH_SUDO_SESH, argv, envp); -} diff --git a/sesh.c b/sesh.c deleted file mode 100644 index 3195e25..0000000 --- a/sesh.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2008 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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "compat.h" - -int -main (int argc, char **argv) -{ - char *cp, *cmnd; - - if (argc < 2) - errx(EXIT_FAILURE, "requires at least one argument"); - - /* Shift argv and make a copy of the command to execute. */ - argv++; - argc--; - cmnd = strdup(argv[0]); - if (cmnd == NULL) - err(EXIT_FAILURE, NULL); - - /* If invoked as a login shell, modify argv[0] accordingly. */ - if (argv[0][0] == '-') { - if ((cp = strrchr(argv[0], '/')) == NULL) - cp = argv[0]; - *cp = '-'; - } - execv(cmnd, argv); - warn("unable to execute %s", argv[0]); - _exit(EXIT_FAILURE); -} diff --git a/set_perms.c b/set_perms.c deleted file mode 100644 index 81e2e76..0000000 --- a/set_perms.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright (c) 1994-1996,1998-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. - */ - -#include - -#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 */ -#include -#include -#include -#ifdef HAVE_LOGIN_CAP_H -# include -#endif - -#include "sudo.h" - -#ifdef __TANDEM -# define ROOT_UID 65535 -#else -# define ROOT_UID 0 -#endif - -/* - * Prototypes - */ -static void runas_setup __P((void)); -static void runas_setgroups __P((void)); -static void restore_groups __P((void)); - -static int current_perm = -1; - -#ifdef HAVE_SETRESUID -/* - * Set real and effective and saved uids and gids based on perm. - * We always retain a saved uid of 0 unless we are headed for an exec(). - * We only flip the effective gid since it only changes for PERM_SUDOERS. - * This version of set_perms() works fine with the "stay_setuid" option. - */ -int -set_perms(perm) - int perm; -{ - const char *errstr; - int noexit; - - noexit = ISSET(perm, PERM_NOEXIT); - CLR(perm, PERM_MASK); - - if (perm == current_perm) - return(1); - - switch (perm) { - case PERM_ROOT: - if (setresuid(ROOT_UID, ROOT_UID, ROOT_UID)) { - errstr = "setresuid(ROOT_UID, ROOT_UID, ROOT_UID)"; - goto bad; - } - (void) setresgid(-1, user_gid, -1); - if (current_perm == PERM_RUNAS) - restore_groups(); - break; - - case PERM_USER: - (void) setresgid(-1, user_gid, -1); - if (setresuid(user_uid, user_uid, ROOT_UID)) { - errstr = "setresuid(user_uid, user_uid, ROOT_UID)"; - goto bad; - } - break; - - case PERM_FULL_USER: - /* headed for exec() */ - (void) setgid(user_gid); - if (setresuid(user_uid, user_uid, user_uid)) { - errstr = "setresuid(user_uid, user_uid, user_uid)"; - goto bad; - } - break; - - case PERM_RUNAS: - runas_setgroups(); - (void) setresgid(-1, runas_gr ? - runas_gr->gr_gid : runas_pw->pw_gid, -1); - if (setresuid(-1, runas_pw ? runas_pw->pw_uid : - user_uid, -1)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_FULL_RUNAS: - /* headed for exec(), assume euid == ROOT_UID */ - runas_setup(); - if (setresuid(def_stay_setuid ? - user_uid : runas_pw->pw_uid, - runas_pw->pw_uid, runas_pw->pw_uid)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_SUDOERS: - /* assume euid == ROOT_UID, ruid == user */ - if (setresgid(-1, SUDOERS_GID, -1)) - error(1, "unable to change to sudoers gid"); - - /* - * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE - * is group readable we use a non-zero - * uid in order to avoid NFS lossage. - * Using uid 1 is a bit bogus but should - * work on all OS's. - */ - if (SUDOERS_UID == ROOT_UID) { - if ((SUDOERS_MODE & 040) && setresuid(ROOT_UID, 1, ROOT_UID)) { - errstr = "setresuid(ROOT_UID, 1, ROOT_UID)"; - goto bad; - } - } else { - if (setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)) { - errstr = "setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID)"; - goto bad; - } - } - break; - case PERM_TIMESTAMP: - if (setresuid(ROOT_UID, timestamp_uid, ROOT_UID)) { - errstr = "setresuid(ROOT_UID, timestamp_uid, ROOT_UID)"; - goto bad; - } - break; - } - - current_perm = perm; - return(1); -bad: - warningx("%s: %s", errstr, - errno == EAGAIN ? "too many processes" : strerror(errno)); - if (noexit) - return(0); - exit(1); -} - -#else -# ifdef HAVE_SETREUID - -/* - * Set real and effective uids and gids based on perm. - * We always retain a real or effective uid of ROOT_UID unless - * we are headed for an exec(). - * This version of set_perms() works fine with the "stay_setuid" option. - */ -int -set_perms(perm) - int perm; -{ - const char *errstr; - int noexit; - - noexit = ISSET(perm, PERM_NOEXIT); - CLR(perm, PERM_MASK); - - if (perm == current_perm) - return(1); - - switch (perm) { - case PERM_ROOT: - if (setreuid(-1, ROOT_UID)) { - errstr = "setreuid(-1, ROOT_UID)"; - goto bad; - } - if (setuid(ROOT_UID)) { - errstr = "setuid(ROOT_UID)"; - goto bad; - } - (void) setregid(-1, user_gid); - if (current_perm == PERM_RUNAS) - restore_groups(); - break; - - case PERM_USER: - (void) setregid(-1, user_gid); - if (setreuid(ROOT_UID, user_uid)) { - errstr = "setreuid(ROOT_UID, user_uid)"; - goto bad; - } - break; - - case PERM_FULL_USER: - /* headed for exec() */ - (void) setgid(user_gid); - if (setreuid(user_uid, user_uid)) { - errstr = "setreuid(user_uid, user_uid)"; - goto bad; - } - break; - - case PERM_RUNAS: - runas_setgroups(); - (void) setregid(-1, runas_gr ? - runas_gr->gr_gid : runas_pw->pw_gid); - if (setreuid(-1, - runas_pw ? runas_pw->pw_uid : user_uid)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_FULL_RUNAS: - /* headed for exec(), assume euid == ROOT_UID */ - runas_setup(); - if (setreuid(def_stay_setuid ? user_uid : - runas_pw->pw_uid, runas_pw->pw_uid)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_SUDOERS: - /* assume euid == ROOT_UID, ruid == user */ - if (setregid(-1, SUDOERS_GID)) - error(1, "unable to change to sudoers gid"); - - /* - * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE - * is group readable we use a non-zero - * uid in order to avoid NFS lossage. - * Using uid 1 is a bit bogus but should - * work on all OS's. - */ - if (SUDOERS_UID == ROOT_UID) { - if ((SUDOERS_MODE & 040) && setreuid(ROOT_UID, 1)) { - errstr = "setreuid(ROOT_UID, 1)"; - goto bad; - } - } else { - if (setreuid(ROOT_UID, SUDOERS_UID)) { - errstr = "setreuid(ROOT_UID, SUDOERS_UID)"; - goto bad; - } - } - break; - case PERM_TIMESTAMP: - if (setreuid(ROOT_UID, timestamp_uid)) { - errstr = "setreuid(ROOT_UID, timestamp_uid)"; - goto bad; - } - break; - } - - current_perm = perm; - return(1); -bad: - warningx("%s: %s", errstr, - errno == EAGAIN ? "too many processes" : strerror(errno)); - if (noexit) - return(0); - exit(1); -} - -# else /* !HAVE_SETRESUID && !HAVE_SETREUID */ -# ifdef HAVE_SETEUID - -/* - * Set real and effective uids and gids based on perm. - * NOTE: does not support the "stay_setuid" option. - */ -int -set_perms(perm) - int perm; -{ - const char *errstr; - int noexit; - - noexit = ISSET(perm, PERM_NOEXIT); - CLR(perm, PERM_MASK); - - if (perm == current_perm) - return(1); - - /* - * Since we only have setuid() and seteuid() and semantics - * for these calls differ on various systems, we set - * real and effective uids to ROOT_UID initially to be safe. - */ - if (seteuid(ROOT_UID)) { - errstr = "seteuid(ROOT_UID)"; - goto bad; - } - if (setuid(ROOT_UID)) { - errstr = "setuid(ROOT_UID)"; - goto bad; - } - - switch (perm) { - case PERM_ROOT: - /* uid set above */ - (void) setegid(user_gid); - if (current_perm == PERM_RUNAS) - restore_groups(); - break; - - case PERM_USER: - (void) setegid(user_gid); - if (seteuid(user_uid)) { - errstr = "seteuid(user_uid)"; - goto bad; - } - break; - - case PERM_FULL_USER: - /* headed for exec() */ - (void) setgid(user_gid); - if (setuid(user_uid)) { - errstr = "setuid(user_uid)"; - goto bad; - } - break; - - case PERM_RUNAS: - runas_setgroups(); - (void) setegid(runas_gr ? - runas_gr->gr_gid : runas_pw->pw_gid); - if (seteuid(runas_pw ? runas_pw->pw_uid : user_uid)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_FULL_RUNAS: - /* headed for exec() */ - runas_setup(); - if (setuid(runas_pw->pw_uid)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_SUDOERS: - if (setegid(SUDOERS_GID)) - error(1, "unable to change to sudoers gid"); - - /* - * If SUDOERS_UID == ROOT_UID and SUDOERS_MODE - * is group readable we use a non-zero - * uid in order to avoid NFS lossage. - * Using uid 1 is a bit bogus but should - * work on all OS's. - */ - if (SUDOERS_UID == ROOT_UID) { - if ((SUDOERS_MODE & 040) && seteuid(1)) { - errstr = "seteuid(1)"; - goto bad; - } - } else { - if (seteuid(SUDOERS_UID)) { - errstr = "seteuid(SUDOERS_UID)"; - goto bad; - } - } - break; - case PERM_TIMESTAMP: - if (seteuid(timestamp_uid)) { - errstr = "seteuid(timestamp_uid)"; - goto bad; - } - break; - } - - current_perm = perm; - return(1); -bad: - warningx("%s: %s", errstr, - errno == EAGAIN ? "too many processes" : strerror(errno)); - if (noexit) - return(0); - exit(1); -} - -# else /* !HAVE_SETRESUID && !HAVE_SETREUID && !HAVE_SETEUID */ - -/* - * Set uids and gids based on perm via setuid() and setgid(). - * NOTE: does not support the "stay_setuid" or timestampowner options. - * Also, SUDOERS_UID and SUDOERS_GID are not used. - */ -int -set_perms(perm) - int perm; -{ - const char *errstr; - int noexit; - - noexit = ISSET(perm, PERM_NOEXIT); - CLR(perm, PERM_MASK); - - if (perm == current_perm) - return(1); - - switch (perm) { - case PERM_ROOT: - if (setuid(ROOT_UID)) { - errstr = "setuid(ROOT_UID)"; - goto bad; - } - if (current_perm == PERM_RUNAS) - restore_groups(); - break; - - case PERM_FULL_USER: - (void) setgid(user_gid); - if (setuid(user_uid)) { - errstr = "setuid(user_uid)"; - goto bad; - } - break; - - case PERM_FULL_RUNAS: - runas_setup(); - if (setuid(runas_pw->pw_uid)) { - errstr = "unable to change to runas uid"; - goto bad; - } - break; - - case PERM_USER: - case PERM_SUDOERS: - case PERM_RUNAS: - case PERM_TIMESTAMP: - /* Unsupported since we can't set euid. */ - break; - } - - current_perm = perm; - return(1); -bad: - warningx("%s: %s", errstr, - errno == EAGAIN ? "too many processes" : strerror(errno)); - if (noexit) - return(0); - exit(1); -} -# endif /* HAVE_SETEUID */ -# endif /* HAVE_SETREUID */ -#endif /* HAVE_SETRESUID */ - -#ifdef HAVE_INITGROUPS -static void -runas_setgroups() -{ - static int ngroups = -1; -# ifdef HAVE_GETGROUPS - static GETGROUPS_T *groups; -# endif - static struct passwd *pw; - struct passwd *opw = pw; - - if (def_preserve_groups) - return; - - /* - * Use stashed copy of runas groups if available, else initgroups and stash. - */ - pw = runas_pw ? runas_pw : sudo_user.pw; - if (pw != opw) { -# ifdef HAVE_SETAUTHDB - aix_setauthdb(pw->pw_name); -# endif - if (initgroups(pw->pw_name, pw->pw_gid) < 0) - log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector"); -# ifdef HAVE_GETGROUPS - if (groups) { - efree(groups); - groups = NULL; - } - if ((ngroups = getgroups(0, NULL)) > 0) { - groups = emalloc2(ngroups, sizeof(GETGROUPS_T)); - if (getgroups(ngroups, groups) < 0) - log_error(USE_ERRNO|MSG_ONLY, "can't get runas group vector"); - } -# ifdef HAVE_SETAUTHDB - aix_restoreauthdb(); -# endif - } else { - if (setgroups(ngroups, groups) < 0) - log_error(USE_ERRNO|MSG_ONLY, "can't set runas group vector"); -# endif /* HAVE_GETGROUPS */ - } -} - -static void -restore_groups() -{ - if (user_ngroups >= 0 && setgroups(user_ngroups, user_groups) < 0) - log_error(USE_ERRNO|MSG_ONLY, "can't reset user group vector"); -} - -#else - -static void -runas_setgroups() -{ - /* STUB */ -} - -static void -restore_groups() -{ - /* STUB */ -} - -#endif /* HAVE_INITGROUPS */ - -static void -runas_setup() -{ - gid_t gid; -#ifdef HAVE_LOGIN_CAP_H - int flags; - extern login_cap_t *lc; -#endif - - if (runas_pw->pw_name != NULL) { - gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid; -#ifdef HAVE_GETUSERATTR - aix_prep_user(runas_pw->pw_name, user_ttypath); -#endif -#ifdef HAVE_PAM - pam_begin_session(runas_pw); -#endif /* HAVE_PAM */ - -#ifdef HAVE_LOGIN_CAP_H - if (def_use_loginclass) { - /* - * We only use setusercontext() to set the nice value and rlimits. - */ - flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; - if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) { - if (runas_pw->pw_uid != ROOT_UID) - error(1, "unable to set user context"); - else - warning("unable to set user context"); - } - } -#endif /* HAVE_LOGIN_CAP_H */ - /* - * Initialize group vector - */ - runas_setgroups(); -#ifdef HAVE_SETEUID - if (setegid(gid)) - warning("cannot set egid to runas gid"); -#endif - if (setgid(gid)) - warning("cannot set gid to runas gid"); - } -} diff --git a/setsid.c b/setsid.c deleted file mode 100644 index d8bba8b..0000000 --- a/setsid.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#include - -#include -#include -#include - -#include -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ - -#include -#include - -pid_t -setsid() -{ - int fd; - -#ifdef SETPGRP_VOID - if (setpgrp() == -1) -#else - if (setpgrp(0, 0) == -1) -#endif - return -1; -# ifdef TIOCNOTTY - if ((fd = open(_PATH_TTY, O_RDWR, 0644)) != -1) { - (void) ioctl(fd, TIOCNOTTY, NULL); - close(fd); - } -# endif - return getpid(); -} diff --git a/sigaction.c b/sigaction.c deleted file mode 100644 index e34d471..0000000 --- a/sigaction.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2001-2005 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. - */ - -#include -#include - -#include - -int -sigaction(signo, sa, osa) - int signo; - const sigaction_t *sa; - sigaction_t *osa; -{ - sigaction_t nsa; - int error; - - /* We must reverse SV_INTERRUPT since it is the opposite of SA_RESTART */ - if (sa) { - nsa = *sa; - nsa.sa_flags ^= SV_INTERRUPT; - sa = &nsa; - } - - error = sigvec(signo, sa, osa); - if (!error && osa) - osa->sa_flags ^= SV_INTERRUPT; /* flip SV_INTERRUPT as above */ - - return(error); -} - -int -sigemptyset(set) - sigset_t *set; -{ - - *set = 0; - return(0); -} - -int -sigfillset(set) - sigset_t *set; -{ - - *set = ~0;; - return(0); -} - -int -sigaddset(set, signo) - sigset_t *set; - int signo; -{ - - if (signo <= 0 || signo >= NSIG) { - errno = EINVAL; - return(-1); - } - - SET(*set, sigmask(signo)); - return(0); -} - -int -sigdelset(set, signo) - sigset_t *set; - int signo; -{ - - if (signo <= 0 || signo >= NSIG) { - errno = EINVAL; - return(-1); - } - - CLR(*set, sigmask(signo)); - return(0); -} - -int -sigismember(set, signo) - sigset_t *set; - int signo; -{ - - return(ISSET(*set, sigmask(signo))); -} - -int -sigprocmask(how, set, oset) - int how; - const sigset_t *set; - sigset_t *oset; -{ - int mask; - - /* If 'set' is NULL the user just wants the current signal mask. */ - if (set == 0) - mask = sigblock(0); - else - switch (how) { - case SIG_BLOCK: - mask = sigblock(*set); - break; - case SIG_UNBLOCK: - mask = sigsetmask(~*set); - break; - case SIG_SETMASK: - mask = sigsetmask(*set); - break; - default: - return(-1); - } - - if (mask == -1) - return(-1); - if (oset) - *oset = mask; - return(0); -} diff --git a/siglist.in b/siglist.in deleted file mode 100644 index f149eb5..0000000 --- a/siglist.in +++ /dev/null @@ -1,56 +0,0 @@ -# -# List of signals used to build sys_siglist (see mksiglist.c) -# Adapted from pdksh; public domain -# -# Note that if a system has multiple defines for the same signal -# (eg, SIGABRT vs SIGIOT, SIGCHLD vs SIGCLD), only the first one -# will be seen, so the order in this list is important. -# - HUP Hangup - INT Interrupt - QUIT Quit - ILL Illegal instruction - TRAP Trace trap -# before IOT (ABRT is posix and ABRT is sometimes the same as IOT) - ABRT Abort - IOT IOT instruction - EMT EMT trap - FPE Floating point exception - KILL Killed -# before BUS (Older Linux doesn't really have a BUS, but defines it to UNUSED) - UNUSED Unused - BUS Bus error - SEGV Memory fault - SYS Bad system call - PIPE Broken pipe - ALRM Alarm clock - TERM Terminated - STKFLT Stack fault -# before POLL (POLL is sometimes the same as IO) - IO I/O possible - XCPU CPU time limit exceeded - XFSZ File size limit exceeded - VTALRM Virtual timer expired - PROF Profiling timer expired - WINCH Window size change - LOST File lock lost - USR1 User defined signal 1 - USR2 User defined signal 2 - PWR Power-fail/Restart - POLL Pollable event occurred - STOP Stopped (signal) - TSTP Stopped - CONT Continued -# before CLD (CHLD is posix and CHLD is sometimes the same as CLD) - CHLD Child exited - CLD Child exited - TTIN Stopped (tty input) - TTOU Stopped (tty output) - INFO Information request - URG Urgent I/O condition -# Solaris (svr4?) signals - WAITING No runnable LWPs - LWP Inter-LWP signal - FREEZE Checkpoint freeze - THAW Checkpoint thaw - CANCEL Thread cancellation diff --git a/snprintf.c b/snprintf.c deleted file mode 100644 index 4123a9d..0000000 --- a/snprintf.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright (c) 1999-2005, 2008, 2010 - * Todd C. Miller - * Copyright (c) 1990, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Chris Torek. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * From: @(#)vfprintf.c 8.1 (Berkeley) 6/4/93 - */ - -/* - * v?snprintf/v?asprintf based on 4.4BSD stdio. - * NOTE: does not support floating point. - */ - -#include - -#include -#include - -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_STRING_H -# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) -# include -# endif -# include -#endif /* HAVE_STRING_H */ -#ifdef HAVE_STRINGS_H -# include -#endif /* HAVE_STRINGS_H */ -#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) -# include -#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ -#include - -#ifdef __STDC__ -# include -#else -# include -#endif - -#include - -static int xxxprintf __P((char **, size_t, int, const char *, va_list)); - -/* - * Some systems may not have these defined in - */ -#ifndef ULONG_MAX -# define ULONG_MAX ((unsigned long)-1) -#endif -#ifndef LONG_MAX -# define LONG_MAX (ULONG_MAX / 2) -#endif -#ifdef HAVE_LONG_LONG_INT -# ifndef ULLONG_MAX -# ifdef UQUAD_MAX -# define ULLONG_MAX UQUAD_MAX -# else -# define ULLONG_MAX ((unsigned long long)-1) -# endif -# endif -# ifndef LLONG_MAX -# ifdef QUAD_MAX -# define LLONG_MAX QUAD_MAX -# else -# define LLONG_MAX (ULLONG_MAX / 2) -# endif -# endif -#endif /* HAVE_LONG_LONG_INT */ - -/* - * Macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned int)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -/* - * Flags used during conversion. - */ -#define ALT 0x001 /* alternate form */ -#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double; unimplemented */ -#define LONGINT 0x010 /* long integer */ -#define QUADINT 0x020 /* quad integer */ -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ - -#define BUF 68 - -#ifndef HAVE_MEMCHR -void * -memchr(s, c, n) - const void *s; - unsigned char c; - size_t n; -{ - if (n != 0) { - const unsigned char *p = s; - - do { - if (*p++ == c) - return ((void *)(p - 1)); - } while (--n != 0); - } - return (NULL); -} -#endif /* !HAVE_MEMCHR */ - -/* - * Convert an unsigned long to ASCII for printf purposes, returning - * a pointer to the first character of the string representation. - * Octal numbers can be forced to have a leading zero; hex numbers - * use the given digits. - */ -static char * -__ultoa(val, endp, base, octzero, xdigs) - unsigned long val; - char *endp; - int base, octzero; - char *xdigs; -{ - char *cp = endp; - long sval; - - /* - * Handle the three cases separately, in the hope of getting - * better/faster code. - */ - switch (base) { - case 10: - if (val < 10) { /* many numbers are 1 digit */ - *--cp = to_char(val); - return (cp); - } - /* - * On many machines, unsigned arithmetic is harder than - * signed arithmetic, so we do at most one unsigned mod and - * divide; this is sufficient to reduce the range of - * the incoming value to where signed arithmetic works. - */ - if (val > LONG_MAX) { - *--cp = to_char(val % 10); - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[val & 15]; - val >>= 4; - } while (val); - break; - - default: /* oops */ - abort(); - } - return (cp); -} - -/* Identical to __ultoa, but for quads. */ -#ifdef HAVE_LONG_LONG_INT -# if SIZEOF_LONG_INT == 8 -# define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x)) -# else -static char * -__uqtoa(val, endp, base, octzero, xdigs) - unsigned long long val; - char *endp; - int base, octzero; - char *xdigs; -{ - char *cp = endp; - long long sval; - - /* quick test for small values; __ultoa is typically much faster */ - /* (perhaps instead we should run until small, then call __ultoa?) */ - if (val <= (unsigned long long)ULONG_MAX) - return (__ultoa((unsigned long)val, endp, base, octzero, xdigs)); - switch (base) { - case 10: - if (val < 10) { - *--cp = to_char(val % 10); - return (cp); - } - if (val > LLONG_MAX) { - *--cp = to_char(val % 10); - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[val & 15]; - val >>= 4; - } while (val); - break; - - default: /* oops */ - abort(); - } - return (cp); -} -# endif /* !SIZEOF_LONG_INT */ -#endif /* HAVE_LONG_LONG_INT */ - -/* - * Actual printf innards. - */ -static int -xxxprintf(strp, strsize, alloc, fmt0, ap) - char **strp; - size_t strsize; - int alloc; - const char *fmt0; - va_list ap; -{ - char *fmt; /* format string */ - int ch; /* character from fmt */ - int n; /* handy integer (short term usage) */ - char *cp; /* handy char pointer (short term usage) */ - int flags; /* flags as above */ - int ret; /* return value accumulator */ - int width; /* width from format (%8d), or 0 */ - int prec; /* precision from format (%.3d), or -1 */ - char sign; /* sign prefix (' ', '+', '-', or \0) */ - unsigned long ulval; /* integer arguments %[diouxX] */ -#ifdef HAVE_LONG_LONG_INT - unsigned long long uqval; /* %q (quad) integers */ -#endif - int base; /* base for [diouxX] conversion */ - int dprec; /* a copy of prec if [diouxX], 0 otherwise */ - int fieldsz; /* field size expanded by sign, etc */ - int realsz; /* field size expanded by dprec */ - int size; /* size of converted field or string */ - char *xdigs; /* digits for [xX] conversion */ - char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */ - char ox[2]; /* space for 0x hex-prefix */ - char *str; /* pointer to string to fill */ - char *estr; /* pointer to last char in str */ - - /* - * Choose PADSIZE to trade efficiency vs. size. If larger printf - * fields occur frequently, increase PADSIZE and make the initialisers - * below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static char blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static char zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - - /* Print chars to "str", (allocate as needed if alloc is set). */ -#define PRINT(ptr, len) do { \ - const char *p = ptr; \ - const char *endp = ptr + len; \ - while (p < endp && (str < estr || alloc)) { \ - if (alloc && str >= estr) { \ - char *t; \ - strsize = (strsize << 1) + 1; \ - if (!(t = (char *)realloc(*strp, strsize))) { \ - free(str); \ - *strp = NULL; \ - ret = -1; \ - goto done; \ - } \ - str = t + (str - *strp); \ - estr = t + strsize - 1; \ - *strp = t; \ - } \ - *str++ = *p++; \ - } \ -} while (0) - - /* BEWARE, PAD uses `n'. */ -#define PAD(howmany, with) do { \ - if ((n = (howmany)) > 0) { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ -} while (0) - - /* - * To extend shorts properly, we need both signed and unsigned - * argument extraction methods. - */ -#define SARG() \ - (flags&LONGINT ? va_arg(ap, long) : \ - flags&SHORTINT ? (long)(short)va_arg(ap, int) : \ - (long)va_arg(ap, int)) -#define UARG() \ - (flags&LONGINT ? va_arg(ap, unsigned long) : \ - flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \ - (unsigned long)va_arg(ap, unsigned int)) - - fmt = (char *)fmt0; - ret = 0; - - if (alloc) { - strsize = 128; - *strp = str = (char *)malloc(strsize); - if (str == NULL) { - ret = -1; - goto done; - } - estr = str + 127; - } else { - str = *strp; - if (strsize) - estr = str + strsize - 1; - else - estr = NULL; - } - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) - /* void */; - if ((n = fmt - cp) != 0) { - PRINT(cp, n); - ret += n; - } - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - dprec = 0; - width = 0; - prec = -1; - sign = '\0'; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - /* - * ``If the space and + flags both appear, the space - * flag will be ignored.'' - * -- ANSI X3J11 - */ - if (!sign) - sign = ' '; - goto rflag; - case '#': - flags |= ALT; - goto rflag; - case '*': - /* - * ``A negative field width argument is taken as a - * - flag followed by a positive field width.'' - * -- ANSI X3J11 - * They don't exclude field widths read from args. - */ - if ((width = va_arg(ap, int)) >= 0) - goto rflag; - width = -width; - /* FALLTHROUGH */ - case '-': - flags |= LADJUST; - goto rflag; - case '+': - sign = '+'; - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - n = va_arg(ap, int); - prec = n < 0 ? -1 : n; - goto rflag; - } - n = 0; - while (is_digit(ch)) { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } - prec = n < 0 ? -1 : n; - goto reswitch; - case '0': - /* - * ``Note that 0 is taken as a flag, not as the - * beginning of a field width.'' - * -- ANSI X3J11 - */ - flags |= ZEROPAD; - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - width = n; - goto reswitch; - case 'h': - flags |= SHORTINT; - goto rflag; - case 'l': - flags |= LONGINT; - goto rflag; -#ifdef HAVE_LONG_LONG_INT - case 'q': - flags |= QUADINT; - goto rflag; -#endif /* HAVE_LONG_LONG_INT */ - case 'c': - *(cp = buf) = va_arg(ap, int); - size = 1; - sign = '\0'; - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': -#ifdef HAVE_LONG_LONG_INT - if (flags & QUADINT) { - uqval = va_arg(ap, long long); - if ((long long)uqval < 0) { - uqval = -uqval; - sign = '-'; - } - } - else -#endif /* HAVE_LONG_LONG_INT */ - { - ulval = SARG(); - if ((long)ulval < 0) { - ulval = -ulval; - sign = '-'; - } - } - base = 10; - goto number; - case 'n': -#ifdef HAVE_LONG_LONG_INT - if (flags & QUADINT) - *va_arg(ap, long long *) = ret; - else -#endif /* HAVE_LONG_LONG_INT */ - if (flags & LONGINT) - *va_arg(ap, long *) = ret; - else if (flags & SHORTINT) - *va_arg(ap, short *) = ret; - else - *va_arg(ap, int *) = ret; - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': -#ifdef HAVE_LONG_LONG_INT - if (flags & QUADINT) - uqval = va_arg(ap, unsigned long long); - else -#endif /* HAVE_LONG_LONG_INT */ - ulval = UARG(); - base = 8; - goto nosign; - case 'p': - /* - * ``The argument shall be a pointer to void. The - * value of the pointer is converted to a sequence - * of printable characters, in an implementation- - * defined manner.'' - * -- ANSI X3J11 - */ - ulval = (unsigned long)va_arg(ap, void *); - base = 16; - xdigs = "0123456789abcdef"; - flags = (flags & ~QUADINT) | HEXPREFIX; - ch = 'x'; - goto nosign; - case 's': - if ((cp = va_arg(ap, char *)) == NULL) - cp = "(null)"; - if (prec >= 0) { - /* - * can't use strlen; can only look for the - * NUL in the first `prec' characters, and - * strlen() will go further. - */ - char *p = memchr(cp, 0, prec); - - if (p != NULL) { - size = p - cp; - if (size > prec) - size = prec; - } else - size = prec; - } else - size = strlen(cp); - sign = '\0'; - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': -#ifdef HAVE_LONG_LONG_INT - if (flags & QUADINT) - uqval = va_arg(ap, unsigned long long); - else -#endif /* HAVE_LONG_LONG_INT */ - ulval = UARG(); - base = 10; - goto nosign; - case 'X': - xdigs = "0123456789ABCDEF"; - goto hex; - case 'x': - xdigs = "0123456789abcdef"; -hex: -#ifdef HAVE_LONG_LONG_INT - if (flags & QUADINT) - uqval = va_arg(ap, unsigned long long); - else -#endif /* HAVE_LONG_LONG_INT */ - ulval = UARG(); - base = 16; - /* leading 0x/X only if non-zero */ - if (flags & ALT && -#ifdef HAVE_LONG_LONG_INT - (flags & QUADINT ? uqval != 0 : ulval != 0)) -#else - ulval != 0) -#endif /* HAVE_LONG_LONG_INT */ - flags |= HEXPREFIX; - - /* unsigned conversions */ -nosign: sign = '\0'; - /* - * ``... diouXx conversions ... if a precision is - * specified, the 0 flag will be ignored.'' - * -- ANSI X3J11 - */ -number: if ((dprec = prec) >= 0) - flags &= ~ZEROPAD; - - /* - * ``The result of converting a zero value with an - * explicit precision of zero is no characters.'' - * -- ANSI X3J11 - */ - cp = buf + BUF; -#ifdef HAVE_LONG_LONG_INT - if (flags & QUADINT) { - if (uqval != 0 || prec != 0) - cp = __uqtoa(uqval, cp, base, - flags & ALT, xdigs); - } - else -#endif /* HAVE_LONG_LONG_INT */ - { - if (ulval != 0 || prec != 0) - cp = __ultoa(ulval, cp, base, - flags & ALT, xdigs); - } - size = buf + BUF - cp; - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - /* pretend it was %c with argument ch */ - cp = buf; - *cp = ch; - size = 1; - sign = '\0'; - break; - } - - /* - * All reasonable formats wind up here. At this point, `cp' - * points to a string which (if not flags&LADJUST) should be - * padded out to `width' places. If flags&ZEROPAD, it should - * first be prefixed by any sign or other prefix; otherwise, - * it should be blank padded before the prefix is emitted. - * After any left-hand padding and prefixing, emit zeroes - * required by a decimal [diouxX] precision, then print the - * string proper, then emit zeroes required by any leftover - * floating precision; finally, if LADJUST, pad with blanks. - * - * Compute actual size, so we know how much to pad. - * fieldsz excludes decimal prec; realsz includes it. - */ - fieldsz = size; - if (sign) - fieldsz++; - else if (flags & HEXPREFIX) - fieldsz += 2; - realsz = dprec > fieldsz ? dprec : fieldsz; - - /* right-adjusting blank padding */ - if ((flags & (LADJUST|ZEROPAD)) == 0) - PAD(width - realsz, blanks); - - /* prefix */ - if (sign) { - PRINT(&sign, 1); - } else if (flags & HEXPREFIX) { - ox[0] = '0'; - ox[1] = ch; - PRINT(ox, 2); - } - - /* right-adjusting zero padding */ - if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) - PAD(width - realsz, zeroes); - - /* leading zeroes from decimal precision */ - PAD(dprec - fieldsz, zeroes); - - /* the string or number proper */ - PRINT(cp, size); - - /* left-adjusting padding (always blank) */ - if (flags & LADJUST) - PAD(width - realsz, blanks); - - /* finally, adjust ret */ - ret += width > realsz ? width : realsz; - } -done: - if (strsize) - *str = '\0'; - return (ret); - /* NOTREACHED */ -} - -#ifndef HAVE_VSNPRINTF -int -vsnprintf(str, n, fmt, ap) - char *str; - size_t n; - const char *fmt; - va_list ap; -{ - - return (xxxprintf(&str, n, 0, fmt, ap)); -} -#endif /* HAVE_VSNPRINTF */ - -#ifndef HAVE_SNPRINTF -int -#ifdef __STDC__ -snprintf(char *str, size_t n, char const *fmt, ...) -#else -snprintf(str, n, fmt, va_alist) - char *str; - size_t n; - char const *fmt; - va_dcl -#endif -{ - int ret; - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - ret = xxxprintf(&str, n, 0, fmt, ap); - va_end(ap); - return (ret); -} -#endif /* HAVE_SNPRINTF */ - -#ifndef HAVE_VASPRINTF -int -vasprintf(str, fmt, ap) - char **str; - const char *fmt; - va_list ap; -{ - - return (xxxprintf(str, 0, 1, fmt, ap)); -} -#endif /* HAVE_VASPRINTF */ - -#ifndef HAVE_ASPRINTF -int -#ifdef __STDC__ -asprintf(char **str, char const *fmt, ...) -#else -asprintf(str, fmt, va_alist) - char **str; - char const *fmt; - va_dcl -#endif -{ - int ret; - va_list ap; - -#ifdef __STDC__ - va_start(ap, fmt); -#else - va_start(ap); -#endif - ret = xxxprintf(str, 0, 1, fmt, ap); - va_end(ap); - return (ret); -} -#endif /* HAVE_ASPRINTF */ diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..601b57f --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,278 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +devdir = @devdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +incdir = $(top_srcdir)/include + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ @LT_STATIC@ + +# Our install program supports extra flags... +INSTALL = $(SHELL) $(top_srcdir)/install-sh -c + +# Libraries +LT_LIBS = $(top_builddir)/common/libcommon.la $(LIBOBJDIR)libreplace.la +LIBS = @LIBS@ @SUDO_LIBS@ @GETGROUPS_LIB@ @NET_LIBS@ @LIBINTL@ $(LT_LIBS) + +# C preprocessor flags +CPPFLAGS = -I$(incdir) -I$(top_builddir) -I$(srcdir) -I$(top_srcdir) -I. @CPPFLAGS@ + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# Flags to pass to the link stage +LDFLAGS = @LDFLAGS@ +LTLDFLAGS = @LTLDFLAGS@ + +# Where to install things... +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +sysconfdir = @sysconfdir@ +libexecdir = @libexecdir@ +datarootdir = @datarootdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +noexecfile = @NOEXECFILE@ +noexecdir = @NOEXECDIR@ + +# User and group ids the installed files should be "owned" by +install_uid = 0 +install_gid = 0 + +# OS dependent defines +DEFS = @OSDEFS@ -DLOCALEDIR=\"$(localedir)\" + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +PROGS = @PROGS@ + +OBJS = conversation.o env_hooks.o error.o exec.o exec_common.o exec_pty.o \ + get_pty.o hooks.o net_ifs.o load_plugins.o parse_args.o sudo.o \ + sudo_edit.o tgetpass.o ttyname.o utmp.o @SUDO_OBJS@ + +LIBOBJDIR = $(top_builddir)/@ac_config_libobj_dir@/ + +VERSION = @PACKAGE_VERSION@ + +all: $(PROGS) + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file src/Makefile) + +.SUFFIXES: .c .h .lo .o + +.c.o: + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +sudo: $(OBJS) $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LIBS) + +libsudo_noexec.la: sudo_noexec.lo + $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(LTLDFLAGS) -o $@ sudo_noexec.lo -avoid-version -rpath $(noexecdir) + +sesh: sesh.o error.o exec_common.o @LIBINTL@ $(LT_LIBS) + $(LIBTOOL) --mode=link $(CC) -o $@ sesh.o error.o exec_common.o $(LDFLAGS) @LIBINTL@ $(LIBS) + +pre-install: + +install: install-binaries @INSTALL_NOEXEC@ + +install-dirs: + $(SHELL) $(top_srcdir)/mkinstalldirs $(DESTDIR)$(bindir) \ + $(DESTDIR)$(noexecdir) + +install-binaries: install-dirs $(PROGS) + $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 04111 sudo $(DESTDIR)$(bindir)/sudo + rm -f $(DESTDIR)$(bindir)/sudoedit + ln $(DESTDIR)$(bindir)/sudo $(DESTDIR)$(bindir)/sudoedit + if [ -f sesh ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -M 0111 sesh $(DESTDIR)$(libexecdir)/sesh; fi + +install-doc: + +install-includes: + +# We install sudo_noexec by hand so we can avoid a "lib" prefix +# and a version number. Since we use LD_PRELOAD, neither is needed. +install-noexec: install-dirs libsudo_noexec.la + if [ -f .libs/lib$(noexecfile) ]; then $(INSTALL) -b~ -O $(install_uid) -G $(install_gid) -m 0755 .libs/lib$(noexecfile) $(DESTDIR)$(noexecdir)/$(noexecfile); fi + +install-plugin: + +uninstall: + -rm -f $(DESTDIR)$(bindir)/sudo $(DESTDIR)$(bindir)/sudoedit \ + $(DESTDIR)$(libexecdir)/sesh \ + $(DESTDIR)$(noexecdir)/$(noexecfile) \ + +check: + +clean: + -$(LIBTOOL) --mode=clean rm -f $(PROGS) *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs sudo_usage.h + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +conversation.o: $(srcdir)/conversation.c $(top_builddir)/config.h \ + $(srcdir)/sudo.h $(top_builddir)/pathnames.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/fileops.h \ + $(incdir)/list.h $(incdir)/sudo_conf.h $(incdir)/list.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h $(srcdir)/sudo_plugin_int.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/conversation.c +env_hooks.o: $(srcdir)/env_hooks.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/dlfcn.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/env_hooks.c +error.o: $(srcdir)/error.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/error.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/error.c +exec.o: $(srcdir)/exec.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/sudo_exec.h $(incdir)/sudo_plugin.h \ + $(srcdir)/sudo_plugin_int.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/exec.c +exec_common.o: $(srcdir)/exec_common.c $(top_builddir)/config.h \ + $(srcdir)/sudo.h $(top_builddir)/pathnames.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/fileops.h \ + $(incdir)/list.h $(incdir)/sudo_conf.h $(incdir)/list.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h $(srcdir)/sudo_exec.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/exec_common.c +exec_pty.o: $(srcdir)/exec_pty.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/sudo_exec.h $(incdir)/sudo_plugin.h \ + $(srcdir)/sudo_plugin_int.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/exec_pty.c +get_pty.o: $(srcdir)/get_pty.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/get_pty.c +hooks.o: $(srcdir)/hooks.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h $(srcdir)/sudo_plugin_int.h \ + $(incdir)/sudo_debug.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/hooks.c +load_plugins.o: $(srcdir)/load_plugins.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/dlfcn.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h $(srcdir)/sudo_plugin_int.h \ + $(incdir)/sudo_conf.h $(incdir)/list.h $(incdir)/sudo_debug.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/load_plugins.c +net_ifs.o: $(srcdir)/net_ifs.c $(top_builddir)/config.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/sudo_debug.h \ + $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/net_ifs.c +parse_args.o: $(srcdir)/parse_args.c $(top_builddir)/config.h ./sudo_usage.h \ + $(srcdir)/sudo.h $(top_builddir)/pathnames.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h \ + $(incdir)/alloc.h $(incdir)/error.h $(incdir)/fileops.h \ + $(incdir)/list.h $(incdir)/sudo_conf.h $(incdir)/list.h \ + $(incdir)/sudo_debug.h $(incdir)/gettext.h $(incdir)/lbuf.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/parse_args.c +preload.o: $(srcdir)/preload.c $(top_builddir)/config.h $(incdir)/sudo_plugin.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/preload.c +selinux.o: $(srcdir)/selinux.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/sudo_exec.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/selinux.c +sesh.o: $(srcdir)/sesh.c $(top_builddir)/config.h \ + $(top_srcdir)/compat/stdbool.h $(incdir)/missing.h $(incdir)/alloc.h \ + $(incdir)/error.h $(incdir)/gettext.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(srcdir)/sudo_exec.h \ + $(incdir)/sudo_plugin.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sesh.c +sudo.o: $(srcdir)/sudo.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(incdir)/sudo_plugin.h $(srcdir)/sudo_plugin_int.h ./sudo_usage.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo.c +sudo_edit.o: $(srcdir)/sudo_edit.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_edit.c +sudo_noexec.lo: $(srcdir)/sudo_noexec.c $(top_builddir)/config.h \ + $(incdir)/missing.h + $(LIBTOOL) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/sudo_noexec.c +tgetpass.o: $(srcdir)/tgetpass.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/tgetpass.c +ttyname.o: $(srcdir)/ttyname.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/ttyname.c +utmp.o: $(srcdir)/utmp.c $(top_builddir)/config.h $(srcdir)/sudo.h \ + $(top_builddir)/pathnames.h $(top_srcdir)/compat/stdbool.h \ + $(incdir)/missing.h $(incdir)/alloc.h $(incdir)/error.h \ + $(incdir)/fileops.h $(incdir)/list.h $(incdir)/sudo_conf.h \ + $(incdir)/list.h $(incdir)/sudo_debug.h $(incdir)/gettext.h \ + $(srcdir)/sudo_exec.h + $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/utmp.c diff --git a/src/conversation.c b/src/conversation.c new file mode 100644 index 0000000..737335e --- /dev/null +++ b/src/conversation.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1999-2005, 2007-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. + */ + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include + +#include "sudo.h" +#include "sudo_plugin.h" +#include "sudo_plugin_int.h" + +extern int tgetpass_flags; /* XXX */ + +#if defined(HAVE_DLOPEN) || defined(HAVE_SHL_LOAD) +sudo_conv_t sudo_conv; /* NULL in sudo front-end */ +#endif + +/* + * Sudo conversation function. + */ +int +sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[]) +{ + struct sudo_conv_reply *repl; + const struct sudo_conv_message *msg; + char *pass; + int n, flags = tgetpass_flags; + + for (n = 0; n < num_msgs; n++) { + msg = &msgs[n]; + repl = &replies[n]; + switch (msg->msg_type & 0xff) { + case SUDO_CONV_PROMPT_ECHO_ON: + case SUDO_CONV_PROMPT_MASK: + if (msg->msg_type == SUDO_CONV_PROMPT_ECHO_ON) + SET(flags, TGP_ECHO); + else + SET(flags, TGP_MASK); + /* FALLTHROUGH */ + case SUDO_CONV_PROMPT_ECHO_OFF: + if (ISSET(msg->msg_type, SUDO_CONV_PROMPT_ECHO_OK)) + SET(flags, TGP_NOECHO_TRY); + /* Read the password unless interrupted. */ + pass = tgetpass(msg->msg, msg->timeout, flags); + if (pass == NULL) + goto err; + repl->reply = estrdup(pass); + zero_bytes(pass, strlen(pass)); + break; + case SUDO_CONV_INFO_MSG: + if (msg->msg) + (void) fputs(msg->msg, stdout); + break; + case SUDO_CONV_ERROR_MSG: + if (msg->msg) + (void) fputs(msg->msg, stderr); + break; + case SUDO_CONV_DEBUG_MSG: + if (msg->msg) + sudo_debug_write(msg->msg, strlen(msg->msg), 0); + break; + default: + goto err; + } + } + + return 0; + +err: + /* Zero and free allocated memory and return an error. */ + do { + repl = &replies[n]; + if (repl->reply != NULL) { + zero_bytes(repl->reply, strlen(repl->reply)); + free(repl->reply); + repl->reply = NULL; + } + } while (n--); + + return -1; +} + +int +_sudo_printf(int msg_type, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + int len; + + switch (msg_type) { + case SUDO_CONV_INFO_MSG: + fp = stdout; + break; + case SUDO_CONV_ERROR_MSG: + fp = stderr; + break; + default: + errno = EINVAL; + return -1; + } + + va_start(ap, fmt); + len = vfprintf(fp, fmt, ap); + va_end(ap); + + return len; +} diff --git a/src/env_hooks.c b/src/env_hooks.c new file mode 100644 index 0000000..1e1db8c --- /dev/null +++ b/src/env_hooks.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2010, 2012 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. + */ + +#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 */ +#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS) +# include +#endif /* HAVE_MALLOC_H && !STDC_HEADERS */ +#include +#ifdef HAVE_DLOPEN +# include +#else +# include "compat/dlfcn.h" +#endif + +#include "sudo.h" +#include "sudo_plugin.h" + +extern char **environ; /* global environment pointer */ +static char **priv_environ; /* private environment pointer */ + +static char * +rpl_getenv(const char *name) +{ + char **ep, *val = NULL; + size_t namelen = 0; + + /* For BSD compatibility, treat '=' in name like end of string. */ + while (name[namelen] != '\0' && name[namelen] != '=') + namelen++; + for (ep = environ; *ep != NULL; ep++) { + if (strncmp(*ep, name, namelen) == 0 && (*ep)[namelen] == '=') { + val = *ep + namelen + 1; + break; + } + } + return val; +} + +typedef char * (*sudo_fn_getenv_t)(const char *); + +char * +getenv_unhooked(const char *name) +{ +#if defined(HAVE_DLOPEN) && defined(RTLD_NEXT) + sudo_fn_getenv_t fn; + + fn = (sudo_fn_getenv_t)dlsym(RTLD_NEXT, "getenv"); + if (fn != NULL) + return fn(name); +#endif /* HAVE_DLOPEN && RTLD_NEXT */ + return rpl_getenv(name); +} + +char * +getenv(const char *name) +{ + char *val = NULL; + + switch (process_hooks_getenv(name, &val)) { + case SUDO_HOOK_RET_STOP: + return val; + case SUDO_HOOK_RET_ERROR: + return NULL; + default: + return getenv_unhooked(name); + } +} + +static int +rpl_putenv(PUTENV_CONST char *string) +{ + char **ep; + size_t len; + bool found = false; + + /* Look for existing entry. */ + len = (strchr(string, '=') - string) + 1; + for (ep = environ; *ep != NULL; ep++) { + if (strncmp(string, *ep, len) == 0) { + *ep = (char *)string; + found = true; + break; + } + } + /* Prune out duplicate variables. */ + if (found) { + while (*ep != NULL) { + if (strncmp(string, *ep, len) == 0) { + char **cur = ep; + while ((*cur = *(cur + 1)) != NULL) + cur++; + } else { + ep++; + } + } + } + + /* Append at the end if not already found. */ + if (!found) { + size_t env_len = (size_t)(ep - environ); + char **envp = erealloc3(priv_environ, env_len + 2, sizeof(char *)); + if (environ != priv_environ) + memcpy(envp, environ, env_len * sizeof(char *)); + envp[env_len++] = (char *)string; + envp[env_len] = NULL; + priv_environ = environ = envp; + } + return 0; +} + +typedef int (*sudo_fn_putenv_t)(PUTENV_CONST char *); + +static int +putenv_unhooked(PUTENV_CONST char *string) +{ +#if defined(HAVE_DLOPEN) && defined(RTLD_NEXT) + sudo_fn_putenv_t fn; + + fn = (sudo_fn_putenv_t)dlsym(RTLD_NEXT, "putenv"); + if (fn != NULL) + return fn(string); +#endif /* HAVE_DLOPEN && RTLD_NEXT */ + return rpl_putenv(string); +} + +int +putenv(PUTENV_CONST char *string) +{ + switch (process_hooks_putenv((char *)string)) { + case SUDO_HOOK_RET_STOP: + return 0; + case SUDO_HOOK_RET_ERROR: + return -1; + default: + return putenv_unhooked(string); + } +} + +static int +rpl_setenv(const char *var, const char *val, int overwrite) +{ + char *envstr, *dst; + const char *src; + size_t esize; + + if (!var || *var == '\0') { + errno = EINVAL; + return -1; + } + + /* + * POSIX says a var name with '=' is an error but BSD + * just ignores the '=' and anything after it. + */ + for (src = var; *src != '\0' && *src != '='; src++) + ; + esize = (size_t)(src - var) + 2; + if (val) { + esize += strlen(val); /* glibc treats a NULL val as "" */ + } + + /* Allocate and fill in envstr. */ + if ((envstr = malloc(esize)) == NULL) + return -1; + for (src = var, dst = envstr; *src != '\0' && *src != '=';) + *dst++ = *src++; + *dst++ = '='; + if (val) { + for (src = val; *src != '\0';) + *dst++ = *src++; + } + *dst = '\0'; + + if (!overwrite && getenv(var) != NULL) { + free(envstr); + return 0; + } + return rpl_putenv(envstr); +} + +typedef int (*sudo_fn_setenv_t)(const char *, const char *, int); + +static int +setenv_unhooked(const char *var, const char *val, int overwrite) +{ +#if defined(HAVE_SETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT) + sudo_fn_setenv_t fn; + + fn = (sudo_fn_setenv_t)dlsym(RTLD_NEXT, "setenv"); + if (fn != NULL) + return fn(var, val, overwrite); +#endif /* HAVE_SETENV && HAVE_DLOPEN && RTLD_NEXT */ + return rpl_setenv(var, val, overwrite); +} + +int +setenv(const char *var, const char *val, int overwrite) +{ + switch (process_hooks_setenv(var, val, overwrite)) { + case SUDO_HOOK_RET_STOP: + return 0; + case SUDO_HOOK_RET_ERROR: + return -1; + default: + return setenv_unhooked(var, val, overwrite); + } +} + +static int +rpl_unsetenv(const char *var) +{ + char **ep = environ; + size_t len; + + if (var == NULL || *var == '\0' || strchr(var, '=') != NULL) { + errno = EINVAL; + return -1; + } + + len = strlen(var); + while (*ep != NULL) { + if (strncmp(var, *ep, len) == 0 && (*ep)[len] == '=') { + /* Found it; shift remainder + NULL over by one. */ + char **cur = ep; + while ((*cur = *(cur + 1)) != NULL) + cur++; + /* Keep going, could be multiple instances of the var. */ + } else { + ep++; + } + } + return 0; +} + +#ifdef UNSETENV_VOID +typedef void (*sudo_fn_unsetenv_t)(const char *); +#else +typedef int (*sudo_fn_unsetenv_t)(const char *); +#endif + +static int +unsetenv_unhooked(const char *var) +{ + int rval = 0; +#if defined(HAVE_UNSETENV) && defined(HAVE_DLOPEN) && defined(RTLD_NEXT) + sudo_fn_unsetenv_t fn; + + fn = (sudo_fn_unsetenv_t)dlsym(RTLD_NEXT, "unsetenv"); + if (fn != NULL) { +# ifdef UNSETENV_VOID + fn(var); +# else + rval = fn(var); +# endif + } else +#endif /* HAVE_UNSETENV && HAVE_DLOPEN && RTLD_NEXT */ + { + rval = rpl_unsetenv(var); + } + return rval; +} + +#ifdef UNSETENV_VOID +void +#else +int +#endif +unsetenv(const char *var) +{ + int rval; + + switch (process_hooks_unsetenv(var)) { + case SUDO_HOOK_RET_STOP: + rval = 0; + break; + case SUDO_HOOK_RET_ERROR: + rval = -1; + break; + default: + rval = unsetenv_unhooked(var); + break; + } +#ifndef UNSETENV_VOID + return rval; +#endif +} diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..56108c1 --- /dev/null +++ b/src/error.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2004-2005, 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. + */ + +#include + +#include + +#include +#include +#include +#include + +#include "missing.h" +#include "error.h" + +#define DEFAULT_TEXT_DOMAIN "sudo" +#include "gettext.h" + +static void _warning(int, const char *, va_list); + void cleanup(int); + +void +error2(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _warning(1, fmt, ap); + va_end(ap); + cleanup(0); + exit(eval); +} + +void +errorx2(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _warning(0, fmt, ap); + va_end(ap); + cleanup(0); + exit(eval); +} + +void +warning2(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _warning(1, fmt, ap); + va_end(ap); +} + +void +warningx2(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + _warning(0, fmt, ap); + va_end(ap); +} + +static void +_warning(int use_errno, const char *fmt, va_list ap) +{ + int serrno = errno; + + fputs(getprogname(), stderr); + if (fmt != NULL) { + fputs(_(": "), stderr); + vfprintf(stderr, fmt, ap); + } + if (use_errno) { + fputs(_(": "), stderr); + fputs(strerror(serrno), stderr); + } + putc('\n', stderr); +} diff --git a/src/exec.c b/src/exec.c new file mode 100644 index 0000000..fd5cb26 --- /dev/null +++ b/src/exec.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2009-2012 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. + */ + +#include + +#include +#include +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +# include +#endif /* HAVE_SYS_SELECT_H */ +#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 TIME_WITH_SYS_TIME +# include +#endif +#ifdef HAVE_SETLOCALE +# include +#endif +#include +#include +#include +#include + +#include "sudo.h" +#include "sudo_exec.h" +#include "sudo_plugin.h" +#include "sudo_plugin_int.h" + +/* Shared with exec_pty.c for use with handler(). */ +int signal_pipe[2]; + +/* We keep a tailq of signals to forward to child. */ +struct sigforward { + struct sigforward *prev, *next; + int signo; +}; +TQ_DECLARE(sigforward) +static struct sigforward_list sigfwd_list; + +static int handle_signals(int sv[2], pid_t child, int log_io, + struct command_status *cstat); +static void forward_signals(int fd); +static void schedule_signal(int signo); +#ifdef SA_SIGINFO +static void handler_nofwd(int s, siginfo_t *info, void *context); +#endif + +/* + * Fork and execute a command, returns the child's pid. + * Sends errno back on sv[1] if execve() fails. + */ +static int fork_cmnd(struct command_details *details, int sv[2]) +{ + struct command_status cstat; + sigaction_t sa; + pid_t child; + debug_decl(fork_cmnd, SUDO_DEBUG_EXEC) + + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */ + sa.sa_handler = handler; + sigaction(SIGCONT, &sa, NULL); + + /* + * The policy plugin's session init must be run before we fork + * or certain pam modules won't be able to track their state. + */ + if (policy_init_session(details) != true) + errorx(1, _("policy plugin failed session initialization")); + + child = sudo_debug_fork(); + switch (child) { + case -1: + error(1, _("unable to fork")); + break; + case 0: + /* child */ + close(sv[0]); + close(signal_pipe[0]); + close(signal_pipe[1]); + fcntl(sv[1], F_SETFD, FD_CLOEXEC); + restore_signals(); + if (exec_setup(details, NULL, -1) == true) { + /* headed for execve() */ + sudo_debug_execve(SUDO_DEBUG_INFO, details->command, + details->argv, details->envp); + if (details->closefrom >= 0) { + int maxfd = details->closefrom; + dup2(sv[1], maxfd); + (void)fcntl(maxfd, F_SETFD, FD_CLOEXEC); + sv[1] = maxfd++; + if (sudo_debug_fd_set(maxfd) != -1) + maxfd++; + closefrom(maxfd); + } +#ifdef HAVE_SELINUX + if (ISSET(details->flags, CD_RBAC_ENABLED)) { + selinux_execve(details->command, details->argv, details->envp, + ISSET(details->flags, CD_NOEXEC)); + } else +#endif + { + sudo_execve(details->command, details->argv, details->envp, + ISSET(details->flags, CD_NOEXEC)); + } + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s", + details->command, strerror(errno)); + } + cstat.type = CMD_ERRNO; + cstat.val = errno; + send(sv[1], &cstat, sizeof(cstat), 0); + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1); + _exit(1); + } + debug_return_int(child); +} + +static struct signal_state { + int signo; + sigaction_t sa; +} saved_signals[] = { + { SIGALRM }, + { SIGCHLD }, + { SIGCONT }, + { SIGHUP }, + { SIGINT }, + { SIGPIPE }, + { SIGQUIT }, + { SIGTERM }, + { SIGTSTP }, + { SIGTTIN }, + { SIGTTOU }, + { SIGUSR1 }, + { SIGUSR2 }, + { -1 } +}; + +/* + * Save signal handler state so it can be restored before exec. + */ +void +save_signals(void) +{ + struct signal_state *ss; + debug_decl(save_signals, SUDO_DEBUG_EXEC) + + for (ss = saved_signals; ss->signo != -1; ss++) + sigaction(ss->signo, NULL, &ss->sa); + + debug_return; +} + +/* + * Restore signal handlers to initial state. + */ +void +restore_signals(void) +{ + struct signal_state *ss; + debug_decl(restore_signals, SUDO_DEBUG_EXEC) + + for (ss = saved_signals; ss->signo != -1; ss++) + sigaction(ss->signo, &ss->sa, NULL); + + debug_return; +} + +/* + * Execute a command, potentially in a pty with I/O loggging. + * This is a little bit tricky due to how POSIX job control works and + * we fact that we have two different controlling terminals to deal with. + */ +int +sudo_execute(struct command_details *details, struct command_status *cstat) +{ + int maxfd, n, nready, sv[2]; + const char *utmp_user = NULL; + bool log_io = false; + fd_set *fdsr, *fdsw; + sigaction_t sa; + pid_t child; + debug_decl(sudo_execute, SUDO_DEBUG_EXEC) + + /* If running in background mode, fork and exit. */ + if (ISSET(details->flags, CD_BACKGROUND)) { + switch (sudo_debug_fork()) { + case -1: + cstat->type = CMD_ERRNO; + cstat->val = errno; + debug_return_int(-1); + case 0: + /* child continues without controlling terminal */ + (void)setpgid(0, 0); + break; + default: + /* parent exits (but does not flush buffers) */ + sudo_debug_exit_int(__func__, __FILE__, __LINE__, + sudo_debug_subsys, 0); + _exit(0); + } + } + + /* + * If we have an I/O plugin or the policy plugin has requested one, we + * need to allocate a pty. It is OK to set log_io in the pty-only case + * as the io plugin tailqueue will be empty and no I/O logging will occur. + */ + if (!tq_empty(&io_plugins) || ISSET(details->flags, CD_USE_PTY)) { + log_io = true; + if (ISSET(details->flags, CD_SET_UTMP)) + utmp_user = details->utmp_user ? details->utmp_user : user_details.username; + sudo_debug_printf(SUDO_DEBUG_INFO, "allocate pty for I/O logging"); + pty_setup(details->euid, user_details.tty, utmp_user); + } + + /* + * We communicate with the child over a bi-directional pair of sockets. + * Parent sends signal info to child and child sends back wait status. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sv) == -1) + error(1, _("unable to create sockets")); + + /* + * We use a pipe to atomically handle signal notification within + * the select() loop. + */ + if (pipe_nonblock(signal_pipe) != 0) + error(1, _("unable to create pipe")); + + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + + /* + * Signals to forward to the child process (excluding SIGALRM and SIGCHLD). + * Note: HP-UX select() will not be interrupted if SA_RESTART set. + */ + sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */ + sa.sa_handler = handler; + sigaction(SIGALRM, &sa, NULL); + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + /* + * When not running the command in a pty, we do not want to + * forward signals generated by the kernel that the child will + * already have received either by virtue of being in the + * controlling tty's process group (SIGINT, SIGQUIT) or because + * the session is terminating (SIGHUP). + */ +#ifdef SA_SIGINFO + if (!log_io) { + sa.sa_flags |= SA_SIGINFO; + sa.sa_sigaction = handler_nofwd; + } +#endif + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + + /* Max fd we will be selecting on. */ + maxfd = MAX(sv[0], signal_pipe[0]); + + /* + * Child will run the command in the pty, parent will pass data + * to and from pty. Adjusts maxfd as needed. + */ + if (log_io) + child = fork_pty(details, sv, &maxfd); + else + child = fork_cmnd(details, sv); + close(sv[1]); + + /* Set command timeout if specified. */ + if (ISSET(details->flags, CD_SET_TIMEOUT)) + alarm(details->timeout); + +#ifdef HAVE_SETLOCALE + /* + * I/O logging must be in the C locale for floating point numbers + * to be logged consistently. + */ + setlocale(LC_ALL, "C"); +#endif + + /* + * In the event loop we pass input from user tty to master + * and pass output from master to stdout and IO plugin. + */ + fdsr = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); + fdsw = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); + for (;;) { + memset(fdsw, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask)); + memset(fdsr, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask)); + + FD_SET(signal_pipe[0], fdsr); + FD_SET(sv[0], fdsr); + if (!tq_empty(&sigfwd_list)) + FD_SET(sv[0], fdsw); + if (log_io) + fd_set_iobs(fdsr, fdsw); /* XXX - better name */ + nready = select(maxfd + 1, fdsr, fdsw, NULL, NULL); + sudo_debug_printf(SUDO_DEBUG_DEBUG, "select returns %d", nready); + if (nready == -1) { + if (errno == EINTR || errno == ENOMEM) + continue; + if (errno == EBADF || errno == EIO) { + /* One of the ttys must have gone away. */ + goto do_tty_io; + } + warning(_("select failed")); + sudo_debug_printf(SUDO_DEBUG_ERROR, + "select failure, terminating child"); + schedule_signal(SIGKILL); + forward_signals(sv[0]); + break; + } + if (FD_ISSET(sv[0], fdsw)) { + forward_signals(sv[0]); + } + if (FD_ISSET(signal_pipe[0], fdsr)) { + n = handle_signals(sv, child, log_io, cstat); + if (n == 0) { + /* Child has exited, cstat is set, we are done. */ + break; + } + 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 != sizeof(*cstat)) { + if (n == -1) { + if (errno == EINTR) + continue; + /* + * If not logging I/O we may receive ECONNRESET when + * the command is executed and sv is closed. + * It is safe to ignore this. + */ + if (log_io && errno != EAGAIN) { + cstat->type = CMD_ERRNO; + cstat->val = errno; + break; + } + sudo_debug_printf(SUDO_DEBUG_ERROR, + "failed to read child status: %s", strerror(errno)); + } else { + /* Short read or EOF. */ + sudo_debug_printf(SUDO_DEBUG_ERROR, + "failed to read child status: %s", + n ? "short read" : "EOF"); + /* XXX - should set cstat */ + break; + } + } + if (cstat->type == CMD_WSTATUS) { + if (WIFSTOPPED(cstat->val)) { + /* Suspend parent and tell child how to resume on return. */ + sudo_debug_printf(SUDO_DEBUG_INFO, + "child stopped, suspending parent"); + n = suspend_parent(WSTOPSIG(cstat->val)); + schedule_signal(n); + continue; + } else { + /* Child exited or was killed, either way we are done. */ + sudo_debug_printf(SUDO_DEBUG_INFO, "child exited or was killed"); + break; + } + } else if (cstat->type == CMD_ERRNO) { + /* Child was unable to execute command or broken pipe. */ + sudo_debug_printf(SUDO_DEBUG_INFO, "errno from child: %s", + strerror(cstat->val)); + break; + } + } +do_tty_io: + if (perform_io(fdsr, fdsw, cstat) != 0) { + /* I/O error, kill child if still alive and finish. */ + sudo_debug_printf(SUDO_DEBUG_ERROR, "I/O error, terminating child"); + schedule_signal(SIGKILL); + forward_signals(sv[0]); + break; + } + } + + if (log_io) { + /* Flush any remaining output and free pty-related memory. */ + pty_close(cstat); + } + +#ifdef HAVE_SELINUX + if (ISSET(details->flags, CD_RBAC_ENABLED)) { + /* This is probably not needed in log_io mode. */ + if (selinux_restore_tty() != 0) + warningx(_("unable to restore tty label")); + } +#endif + + efree(fdsr); + efree(fdsw); + while (!tq_empty(&sigfwd_list)) { + struct sigforward *sigfwd = tq_first(&sigfwd_list); + tq_remove(&sigfwd_list, sigfwd); + efree(sigfwd); + } + + debug_return_int(cstat->type == CMD_ERRNO ? -1 : 0); +} + +/* + * Read signals on fd written to by handler(). + * Returns -1 on error, 0 on child exit, else 1. + */ +static int +handle_signals(int sv[2], pid_t child, int log_io, struct command_status *cstat) +{ + unsigned char signo; + ssize_t nread; + int status; + pid_t pid; + debug_decl(handle_signals, SUDO_DEBUG_EXEC) + + for (;;) { + /* read signal pipe */ + nread = read(signal_pipe[0], &signo, sizeof(signo)); + if (nread <= 0) { + /* It should not be possible to get EOF but just in case. */ + if (nread == 0) + errno = ECONNRESET; + /* Restart if interrupted by signal so the pipe doesn't fill. */ + if (errno == EINTR) + continue; + /* If pipe is empty, we are done. */ + if (errno == EAGAIN) + break; + sudo_debug_printf(SUDO_DEBUG_ERROR, "error reading signal pipe %s", + strerror(errno)); + cstat->type = CMD_ERRNO; + cstat->val = errno; + debug_return_int(-1); + } + sudo_debug_printf(SUDO_DEBUG_DIAG, "received signal %d", signo); + if (signo == SIGCHLD) { + /* + * If logging I/O, child is the intermediate process, + * otherwise it is the command itself. + */ + do { + pid = waitpid(child, &status, WUNTRACED|WNOHANG); + } while (pid == -1 && errno == EINTR); + if (pid == child) { + if (log_io) { + /* + * On BSD we get ECONNRESET on sv[0] if monitor dies + * and select() will return with sv[0] readable. + * On Linux that doesn't appear to happen so if the + * monitor dies, shut down the socketpair to force a + * select() notification. + */ + (void) shutdown(sv[0], SHUT_WR); + } else { + if (WIFSTOPPED(status)) { + /* + * Save the controlling terminal's process group + * so we can restore it after we resume. + */ + pid_t saved_pgrp = (pid_t)-1; + int fd = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0); + if (fd != -1) + saved_pgrp = tcgetpgrp(fd); + if (kill(getpid(), WSTOPSIG(status)) != 0) { + warning("kill(%d, %d)", (int)getpid(), + WSTOPSIG(status)); + } + if (fd != -1) { + if (saved_pgrp != (pid_t)-1) + (void)tcsetpgrp(fd, saved_pgrp); + close(fd); + } + } else { + /* Child has exited, we are done. */ + cstat->type = CMD_WSTATUS; + cstat->val = status; + debug_return_int(0); + } + } + } + } else { + if (log_io) { + /* Schedule signo to be forwared to the child. */ + schedule_signal(signo); + } else { + /* Nothing listening on sv[0], send directly. */ + if (signo == SIGALRM) + terminate_child(child, false); + else if (kill(child, signo) != 0) + warning("kill(%d, %d)", (int)child, signo); + } + } + } + debug_return_int(1); +} + +/* + * Forward signals in sigfwd_list to child listening on fd. + */ +static void +forward_signals(int sock) +{ + struct sigforward *sigfwd; + struct command_status cstat; + ssize_t nsent; + debug_decl(forward_signals, SUDO_DEBUG_EXEC) + + while (!tq_empty(&sigfwd_list)) { + sigfwd = tq_first(&sigfwd_list); + sudo_debug_printf(SUDO_DEBUG_INFO, + "sending signal %d to child over backchannel", sigfwd->signo); + cstat.type = CMD_SIGNO; + cstat.val = sigfwd->signo; + do { + nsent = send(sock, &cstat, sizeof(cstat), 0); + } while (nsent == -1 && errno == EINTR); + tq_remove(&sigfwd_list, sigfwd); + efree(sigfwd); + if (nsent != sizeof(cstat)) { + if (errno == EPIPE) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "broken pipe writing to child over backchannel"); + /* 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); + } + /* XXX - child (monitor) is dead, we should exit too? */ + } + break; + } + } + debug_return; +} + +/* + * Schedule a signal to be forwared. + */ +static void +schedule_signal(int signo) +{ + struct sigforward *sigfwd; + debug_decl(schedule_signal, SUDO_DEBUG_EXEC) + + sudo_debug_printf(SUDO_DEBUG_DIAG, "forwarding signal %d to child", signo); + + sigfwd = ecalloc(1, sizeof(*sigfwd)); + sigfwd->prev = sigfwd; + /* sigfwd->next = NULL; */ + sigfwd->signo = signo; + tq_append(&sigfwd_list, sigfwd); + + debug_return; +} + +/* + * Generic handler for signals passed from parent -> child. + * The other end of signal_pipe is checked in the main event loop. + */ +void +handler(int s) +{ + unsigned char signo = (unsigned char)s; + + /* + * The pipe is non-blocking, if we overflow the kernel's pipe + * buffer we drop the signal. This is not a problem in practice. + */ + ignore_result(write(signal_pipe[1], &signo, sizeof(signo))); +} + +#ifdef SA_SIGINFO +/* + * Generic handler for signals passed from parent -> child. + * The other end of signal_pipe is checked in the main event loop. + * This version is for the non-pty case and does not forward + * signals that are generated by the kernel. + */ +static void +handler_nofwd(int s, siginfo_t *info, void *context) +{ + unsigned char signo = (unsigned char)s; + + /* Only forward user-generated signals. */ + if (info == NULL || info->si_code <= 0) { + /* + * The pipe is non-blocking, if we overflow the kernel's pipe + * buffer we drop the signal. This is not a problem in practice. + */ + ignore_result(write(signal_pipe[1], &signo, sizeof(signo))); + } +} +#endif /* SA_SIGINFO */ + +/* + * Open a pipe and make both ends non-blocking. + * Returns 0 on success and -1 on error. + */ +int +pipe_nonblock(int fds[2]) +{ + int flags, rval; + debug_decl(pipe_nonblock, SUDO_DEBUG_EXEC) + + 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]); + } + } + + debug_return_int(rval); +} diff --git a/src/exec_common.c b/src/exec_common.c new file mode 100644 index 0000000..a4cd540 --- /dev/null +++ b/src/exec_common.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2009-2012 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. + */ + +#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 */ +#ifdef HAVE_PRIV_SET +# include +#endif +#include + +#include "sudo.h" +#include "sudo_exec.h" + +/* + * Disable execution of child processes in the command we are about + * to run. On systems with privilege sets, we can remove the exec + * privilege. On other systems we use LD_PRELOAD and the like. + */ +static char * const * +disable_execute(char *const envp[]) +{ +#ifdef _PATH_SUDO_NOEXEC + char *preload, **nenvp = NULL; + int env_len, env_size; + int preload_idx = -1; +# ifdef RTLD_PRELOAD_ENABLE_VAR + bool enabled = false; +# endif +#endif /* _PATH_SUDO_NOEXEC */ + debug_decl(disable_execute, SUDO_DEBUG_UTIL) + +#ifdef HAVE_PRIV_SET + /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */ + if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0) + debug_return_ptr(envp); + warning(_("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT")); +#endif /* HAVE_PRIV_SET */ + +#ifdef _PATH_SUDO_NOEXEC + /* + * Preload a noexec file. For a list of LD_PRELOAD-alikes, see + * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html + * XXX - need to support 32-bit and 64-bit variants + */ + + /* Count entries in envp, looking for LD_PRELOAD as we go. */ + for (env_len = 0; envp[env_len] != NULL; env_len++) { + if (strncmp(envp[env_len], RTLD_PRELOAD_VAR "=", sizeof(RTLD_PRELOAD_VAR)) == 0) { + preload_idx = env_len; + continue; + } +#ifdef RTLD_PRELOAD_ENABLE_VAR + if (strncmp(envp[env_len], RTLD_PRELOAD_ENABLE_VAR "=", sizeof(RTLD_PRELOAD_ENABLE_VAR)) == 0) { + enabled = true; + continue; + } +#endif + } + + /* Make a new copy of envp as needed. */ + env_size = env_len + 1 + (preload_idx == -1); +#ifdef RTLD_PRELOAD_ENABLE_VAR + if (!enabled) + env_size++; +#endif + nenvp = emalloc2(env_size, sizeof(*envp)); + memcpy(nenvp, envp, env_len * sizeof(*envp)); + nenvp[env_len] = NULL; + + /* Prepend our LD_PRELOAD to existing value or add new entry at the end. */ + if (preload_idx == -1) { +# ifdef RTLD_PRELOAD_DEFAULT + easprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, sudo_conf_noexec_path(), RTLD_PRELOAD_DELIM, RTLD_PRELOAD_DEFAULT); +# else + preload = fmt_string(RTLD_PRELOAD_VAR, sudo_conf_noexec_path()); +# endif + if (preload == NULL) + errorx(1, _("unable to allocate memory")); + nenvp[env_len++] = preload; + nenvp[env_len] = NULL; + } else { + easprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, sudo_conf_noexec_path(), RTLD_PRELOAD_DELIM, nenvp[preload_idx]); + nenvp[preload_idx] = preload; + } +# ifdef RTLD_PRELOAD_ENABLE_VAR + if (!enabled) { + nenvp[env_len++] = RTLD_PRELOAD_ENABLE_VAR "="; + nenvp[env_len] = NULL; + } +# endif + + /* Install new env pointer. */ + envp = nenvp; +#endif /* _PATH_SUDO_NOEXEC */ + + debug_return_ptr(envp); +} + +/* + * Like execve(2) but falls back to running through /bin/sh + * ala execvp(3) if we get ENOEXEC. + */ +int +sudo_execve(const char *path, char *const argv[], char *const envp[], int noexec) +{ + /* Modify the environment as needed to disable further execve(). */ + if (noexec) + envp = disable_execute(envp); + + execve(path, argv, envp); + if (errno == ENOEXEC) { + int argc; + char **nargv; + + for (argc = 0; argv[argc] != NULL; argc++) + continue; + nargv = emalloc2(argc + 2, sizeof(char *)); + nargv[0] = "sh"; + nargv[1] = (char *)path; + memcpy(nargv + 2, argv + 1, argc * sizeof(char *)); + execve(_PATH_BSHELL, nargv, envp); + efree(nargv); + } + return -1; +} diff --git a/src/exec_pty.c b/src/exec_pty.c new file mode 100644 index 0000000..f34df2b --- /dev/null +++ b/src/exec_pty.c @@ -0,0 +1,1287 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#ifdef HAVE_SYS_SYSMACROS_H +# include +#endif +#include +#include +#include +#include +#ifdef HAVE_SYS_SELECT_H +# include +#endif /* HAVE_SYS_SELECT_H */ +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#include +#include +#include +#include + +#include "sudo.h" +#include "sudo_exec.h" +#include "sudo_plugin.h" +#include "sudo_plugin_int.h" + +#define SFD_STDIN 0 +#define SFD_STDOUT 1 +#define SFD_STDERR 2 +#define SFD_MASTER 3 +#define SFD_SLAVE 4 +#define SFD_USERTTY 5 + +#define TERM_COOKED 0 +#define TERM_RAW 1 + +/* Compatibility with older tty systems. */ +#if !defined(TIOCGWINSZ) && defined(TIOCGSIZE) +# define TIOCGWINSZ TIOCGSIZE +# define TIOCSWINSZ TIOCSSIZE +# define winsize ttysize +#endif + +struct io_buffer { + struct io_buffer *next; + int len; /* buffer length (how much produced) */ + int off; /* write position (how much already consumed) */ + int rfd; /* reader (producer) */ + int wfd; /* writer (consumer) */ + bool (*action)(const char *buf, unsigned int len); + char buf[16 * 1024]; +}; + +static char slavename[PATH_MAX]; +static bool foreground, pipeline, tty_initialized; +static int io_fds[6] = { -1, -1, -1, -1, -1, -1}; +static int ttymode = TERM_COOKED; +static pid_t ppgrp, child, child_pgrp; +static sigset_t ttyblock; +static struct io_buffer *iobufs; + +static void flush_output(void); +static int exec_monitor(struct command_details *details, int backchannel); +static void exec_pty(struct command_details *detail, int *errfd); +static void sigwinch(int s); +static void sync_ttysize(int src, int dst); +static void deliver_signal(pid_t pid, int signo, bool from_parent); +static int safe_close(int fd); +static void check_foreground(void); + +/* + * Cleanup hook for error()/errorx() + */ +void +cleanup(int gotsignal) +{ + debug_decl(cleanup, SUDO_DEBUG_EXEC); + + if (!tq_empty(&io_plugins) && io_fds[SFD_USERTTY] != -1) { + check_foreground(); + if (foreground) + term_restore(io_fds[SFD_USERTTY], 0); + } +#ifdef HAVE_SELINUX + selinux_restore_tty(); +#endif + utmp_logout(slavename, 0); /* XXX - only if CD_SET_UTMP */ + + debug_return; +} + +/* + * Allocate a pty if /dev/tty is a tty. + * Fills in io_fds[SFD_USERTTY], io_fds[SFD_MASTER], io_fds[SFD_SLAVE] + * and slavename globals. + */ +void +pty_setup(uid_t uid, const char *tty, const char *utmp_user) +{ + debug_decl(pty_setup, SUDO_DEBUG_EXEC); + + io_fds[SFD_USERTTY] = open(_PATH_TTY, O_RDWR|O_NOCTTY, 0); + if (io_fds[SFD_USERTTY] != -1) { + if (!get_pty(&io_fds[SFD_MASTER], &io_fds[SFD_SLAVE], + slavename, sizeof(slavename), uid)) + error(1, _("unable to allocate pty")); + /* Add entry to utmp/utmpx? */ + if (utmp_user != NULL) + utmp_login(tty, slavename, io_fds[SFD_SLAVE], utmp_user); + } + + debug_return; +} + +/* Call I/O plugin tty input log method. */ +static bool +log_ttyin(const char *buf, unsigned int n) +{ + struct plugin_container *plugin; + sigset_t omask; + bool rval = true; + debug_decl(log_ttyin, SUDO_DEBUG_EXEC); + + sigprocmask(SIG_BLOCK, &ttyblock, &omask); + tq_foreach_fwd(&io_plugins, plugin) { + if (plugin->u.io->log_ttyin) { + if (!plugin->u.io->log_ttyin(buf, n)) { + rval = false; + break; + } + } + } + sigprocmask(SIG_SETMASK, &omask, NULL); + + debug_return_bool(rval); +} + +/* Call I/O plugin stdin log method. */ +static bool +log_stdin(const char *buf, unsigned int n) +{ + struct plugin_container *plugin; + sigset_t omask; + bool rval = true; + debug_decl(log_stdin, SUDO_DEBUG_EXEC); + + sigprocmask(SIG_BLOCK, &ttyblock, &omask); + tq_foreach_fwd(&io_plugins, plugin) { + if (plugin->u.io->log_stdin) { + if (!plugin->u.io->log_stdin(buf, n)) { + rval = false; + break; + } + } + } + sigprocmask(SIG_SETMASK, &omask, NULL); + + debug_return_bool(rval); +} + +/* Call I/O plugin tty output log method. */ +static bool +log_ttyout(const char *buf, unsigned int n) +{ + struct plugin_container *plugin; + sigset_t omask; + bool rval = true; + debug_decl(log_ttyout, SUDO_DEBUG_EXEC); + + sigprocmask(SIG_BLOCK, &ttyblock, &omask); + tq_foreach_fwd(&io_plugins, plugin) { + if (plugin->u.io->log_ttyout) { + if (!plugin->u.io->log_ttyout(buf, n)) { + rval = false; + break; + } + } + } + sigprocmask(SIG_SETMASK, &omask, NULL); + + debug_return_bool(rval); +} + +/* Call I/O plugin stdout log method. */ +static bool +log_stdout(const char *buf, unsigned int n) +{ + struct plugin_container *plugin; + sigset_t omask; + bool rval = true; + debug_decl(log_stdout, SUDO_DEBUG_EXEC); + + sigprocmask(SIG_BLOCK, &ttyblock, &omask); + tq_foreach_fwd(&io_plugins, plugin) { + if (plugin->u.io->log_stdout) { + if (!plugin->u.io->log_stdout(buf, n)) { + rval = false; + break; + } + } + } + sigprocmask(SIG_SETMASK, &omask, NULL); + + debug_return_bool(rval); +} + +/* Call I/O plugin stderr log method. */ +static bool +log_stderr(const char *buf, unsigned int n) +{ + struct plugin_container *plugin; + sigset_t omask; + bool rval = true; + debug_decl(log_stderr, SUDO_DEBUG_EXEC); + + sigprocmask(SIG_BLOCK, &ttyblock, &omask); + tq_foreach_fwd(&io_plugins, plugin) { + if (plugin->u.io->log_stderr) { + if (!plugin->u.io->log_stderr(buf, n)) { + rval = false; + break; + } + } + } + sigprocmask(SIG_SETMASK, &omask, NULL); + + debug_return_bool(rval); +} + +/* + * Check whether we are running in the foregroup. + * Updates the foreground global and does lazy init of the + * the pty slave as needed. + */ +static void +check_foreground(void) +{ + debug_decl(check_foreground, SUDO_DEBUG_EXEC); + + if (io_fds[SFD_USERTTY] != -1) { + foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp; + if (foreground && !tty_initialized) { + if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) { + tty_initialized = true; + sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]); + } + } + } + + debug_return; +} + +/* + * Suspend sudo if the underlying command is suspended. + * Returns SIGCONT_FG if the child should be resume in the + * foreground or SIGCONT_BG if it is a background process. + */ +int +suspend_parent(int signo) +{ + sigaction_t sa, osa; + int n, oldmode = ttymode, rval = 0; + debug_decl(suspend_parent, SUDO_DEBUG_EXEC); + + switch (signo) { + case SIGTTOU: + case SIGTTIN: + /* + * If we are the foreground process, just resume the child. + * Otherwise, re-send the signal with the handler disabled. + */ + if (!foreground) + check_foreground(); + if (foreground) { + if (ttymode != TERM_RAW) { + do { + n = term_raw(io_fds[SFD_USERTTY], 0); + } while (!n && errno == EINTR); + ttymode = TERM_RAW; + } + rval = SIGCONT_FG; /* resume child in foreground */ + break; + } + ttymode = TERM_RAW; + /* FALLTHROUGH */ + case SIGSTOP: + case SIGTSTP: + /* Flush any remaining output before suspending. */ + flush_output(); + + /* Restore original tty mode before suspending. */ + if (oldmode != TERM_COOKED) { + do { + n = term_restore(io_fds[SFD_USERTTY], 0); + } while (!n && errno == EINTR); + } + + /* Suspend self and continue child when we resume. */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */ + sa.sa_handler = SIG_DFL; + sigaction(signo, &sa, &osa); + sudo_debug_printf(SUDO_DEBUG_INFO, "kill parent %d", signo); + if (killpg(ppgrp, signo) != 0) + warning("killpg(%d, %d)", (int)ppgrp, signo); + + /* Check foreground/background status on resume. */ + check_foreground(); + + /* + * Only modify term if we are foreground process and either + * the old tty mode was not cooked or child got SIGTT{IN,OU} + */ + sudo_debug_printf(SUDO_DEBUG_INFO, "parent is in %s, ttymode %d -> %d", + foreground ? "foreground" : "background", oldmode, ttymode); + + if (ttymode != TERM_COOKED) { + if (foreground) { + /* Set raw mode. */ + do { + n = term_raw(io_fds[SFD_USERTTY], 0); + } while (!n && errno == EINTR); + } else { + /* Background process, no access to tty. */ + ttymode = TERM_COOKED; + } + } + + sigaction(signo, &osa, NULL); + rval = ttymode == TERM_RAW ? SIGCONT_FG : SIGCONT_BG; + break; + } + + debug_return_int(rval); +} + +/* + * Kill child with increasing urgency. + */ +void +terminate_child(pid_t pid, bool use_pgrp) +{ + debug_decl(terminate_child, SUDO_DEBUG_EXEC); + + /* + * Note that SIGCHLD will interrupt the sleep() + */ + if (use_pgrp) { + sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGHUP", (int)pid); + killpg(pid, SIGHUP); + sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGTERM", (int)pid); + killpg(pid, SIGTERM); + sleep(2); + sudo_debug_printf(SUDO_DEBUG_INFO, "killpg %d SIGKILL", (int)pid); + killpg(pid, SIGKILL); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGHUP", (int)pid); + kill(pid, SIGHUP); + sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGTERM", (int)pid); + kill(pid, SIGTERM); + sleep(2); + sudo_debug_printf(SUDO_DEBUG_INFO, "kill %d SIGKILL", (int)pid); + kill(pid, SIGKILL); + } + + debug_return; +} + +static struct io_buffer * +io_buf_new(int rfd, int wfd, bool (*action)(const char *, unsigned int), + struct io_buffer *head) +{ + struct io_buffer *iob; + debug_decl(io_buf_new, SUDO_DEBUG_EXEC); + + iob = ecalloc(1, sizeof(*iob)); + iob->rfd = rfd; + iob->wfd = wfd; + iob->action = action; + iob->next = head; + + debug_return_ptr(iob); +} + +/* + * Read/write iobufs depending on fdsr and fdsw. + * Returns the number of errors. + */ +int +perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat) +{ + struct io_buffer *iob; + int n, errors = 0; + debug_decl(perform_io, SUDO_DEBUG_EXEC); + + for (iob = iobufs; iob; iob = iob->next) { + if (iob->rfd != -1 && FD_ISSET(iob->rfd, fdsr)) { + do { + n = read(iob->rfd, iob->buf + iob->len, + sizeof(iob->buf) - iob->len); + } while (n == -1 && errno == EINTR); + switch (n) { + case -1: + if (errno != EAGAIN) { + /* treat read error as fatal and close the fd */ + sudo_debug_printf(SUDO_DEBUG_ERROR, + "error reading fd %d: %s", iob->rfd, + strerror(errno)); + safe_close(iob->rfd); + iob->rfd = -1; + } + break; + case 0: + /* got EOF or pty has gone away */ + sudo_debug_printf(SUDO_DEBUG_INFO, + "read EOF from fd %d", iob->rfd); + safe_close(iob->rfd); + iob->rfd = -1; + break; + default: + sudo_debug_printf(SUDO_DEBUG_INFO, + "read %d bytes from fd %d", n, iob->rfd); + if (!iob->action(iob->buf + iob->len, n)) + terminate_child(child, true); + iob->len += n; + break; + } + } + if (iob->wfd != -1 && FD_ISSET(iob->wfd, fdsw)) { + do { + n = write(iob->wfd, iob->buf + iob->off, + iob->len - iob->off); + } while (n == -1 && errno == EINTR); + if (n == -1) { + if (errno == EPIPE || errno == ENXIO || errno == EIO || errno == EBADF) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "unable to write %d bytes to fd %d", + iob->len - iob->off, iob->wfd); + /* other end of pipe closed or pty revoked */ + if (iob->rfd != -1) { + safe_close(iob->rfd); + iob->rfd = -1; + } + safe_close(iob->wfd); + iob->wfd = -1; + continue; + } + if (errno != EAGAIN) { + errors++; + sudo_debug_printf(SUDO_DEBUG_ERROR, + "error writing fd %d: %s", iob->wfd, strerror(errno)); + } + } else { + sudo_debug_printf(SUDO_DEBUG_INFO, + "wrote %d bytes to fd %d", n, iob->wfd); + iob->off += n; + } + } + } + if (errors && cstat != NULL) { + cstat->type = CMD_ERRNO; + cstat->val = errno; + } + debug_return_int(errors); +} + +/* + * Fork a monitor process which runs the actual command as its own child + * process with std{in,out,err} hooked up to the pty or pipes as appropriate. + * Returns the child pid. + */ +int +fork_pty(struct command_details *details, int sv[], int *maxfd) +{ + struct command_status cstat; + struct io_buffer *iob; + int io_pipe[3][2], n; + sigaction_t sa; + debug_decl(fork_pty, SUDO_DEBUG_EXEC); + + ppgrp = getpgrp(); /* parent's pgrp, so child can signal us */ + + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + + if (io_fds[SFD_USERTTY] != -1) { + sa.sa_flags = SA_RESTART; + sa.sa_handler = sigwinch; + sigaction(SIGWINCH, &sa, NULL); + } + + /* So we can block tty-generated signals */ + sigemptyset(&ttyblock); + sigaddset(&ttyblock, SIGINT); + sigaddset(&ttyblock, SIGQUIT); + sigaddset(&ttyblock, SIGTSTP); + sigaddset(&ttyblock, SIGTTIN); + sigaddset(&ttyblock, SIGTTOU); + + /* + * Setup stdin/stdout/stderr for child, to be duped after forking. + * In background mode there is no stdin. + */ + if (!ISSET(details->flags, CD_BACKGROUND)) + io_fds[SFD_STDIN] = io_fds[SFD_SLAVE]; + io_fds[SFD_STDOUT] = io_fds[SFD_SLAVE]; + io_fds[SFD_STDERR] = io_fds[SFD_SLAVE]; + + if (io_fds[SFD_USERTTY] != -1) { + /* Read from /dev/tty, write to pty master */ + if (!ISSET(details->flags, CD_BACKGROUND)) { + iobufs = io_buf_new(io_fds[SFD_USERTTY], io_fds[SFD_MASTER], + log_ttyin, iobufs); + } + + /* Read from pty master, write to /dev/tty */ + iobufs = io_buf_new(io_fds[SFD_MASTER], io_fds[SFD_USERTTY], + log_ttyout, iobufs); + + /* Are we the foreground process? */ + foreground = tcgetpgrp(io_fds[SFD_USERTTY]) == ppgrp; + } + + /* + * If either stdin, stdout or stderr is not a tty we use a pipe + * to interpose ourselves instead of duping the pty fd. + */ + memset(io_pipe, 0, sizeof(io_pipe)); + if (io_fds[SFD_STDIN] == -1 || !isatty(STDIN_FILENO)) { + sudo_debug_printf(SUDO_DEBUG_INFO, "stdin not a tty, creating a pipe"); + pipeline = true; + if (pipe(io_pipe[STDIN_FILENO]) != 0) + error(1, _("unable to create pipe")); + iobufs = io_buf_new(STDIN_FILENO, io_pipe[STDIN_FILENO][1], + log_stdin, iobufs); + io_fds[SFD_STDIN] = io_pipe[STDIN_FILENO][0]; + } + if (io_fds[SFD_STDOUT] == -1 || !isatty(STDOUT_FILENO)) { + sudo_debug_printf(SUDO_DEBUG_INFO, "stdout not a tty, creating a pipe"); + pipeline = true; + if (pipe(io_pipe[STDOUT_FILENO]) != 0) + error(1, _("unable to create pipe")); + iobufs = io_buf_new(io_pipe[STDOUT_FILENO][0], STDOUT_FILENO, + log_stdout, iobufs); + io_fds[SFD_STDOUT] = io_pipe[STDOUT_FILENO][1]; + } + if (io_fds[SFD_STDERR] == -1 || !isatty(STDERR_FILENO)) { + sudo_debug_printf(SUDO_DEBUG_INFO, "stderr not a tty, creating a pipe"); + if (pipe(io_pipe[STDERR_FILENO]) != 0) + error(1, _("unable to create pipe")); + iobufs = io_buf_new(io_pipe[STDERR_FILENO][0], STDERR_FILENO, + log_stderr, iobufs); + io_fds[SFD_STDERR] = io_pipe[STDERR_FILENO][1]; + } + + /* Job control signals to relay from parent to child. */ + sa.sa_flags = SA_INTERRUPT; /* do not restart syscalls */ + sa.sa_handler = handler; + sigaction(SIGTSTP, &sa, NULL); + + /* We don't want to receive SIGTTIN/SIGTTOU, getting EIO is preferable. */ + sa.sa_handler = SIG_IGN; + sigaction(SIGTTIN, &sa, NULL); + sigaction(SIGTTOU, &sa, NULL); + + if (foreground) { + /* Copy terminal attrs from user tty -> pty slave. */ + if (term_copy(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE])) { + tty_initialized = true; + sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]); + } + + /* Start out in raw mode if we are not part of a pipeline. */ + if (!pipeline) { + ttymode = TERM_RAW; + do { + n = term_raw(io_fds[SFD_USERTTY], 0); + } while (!n && errno == EINTR); + if (!n) + error(1, _("unable to set terminal to raw mode")); + } + } + + /* + * The policy plugin's session init must be run before we fork + * or certain pam modules won't be able to track their state. + */ + if (policy_init_session(details) != true) + errorx(1, _("policy plugin failed session initialization")); + + child = sudo_debug_fork(); + switch (child) { + case -1: + error(1, _("unable to fork")); + break; + case 0: + /* child */ + close(sv[0]); + close(signal_pipe[0]); + close(signal_pipe[1]); + fcntl(sv[1], F_SETFD, FD_CLOEXEC); + if (exec_setup(details, slavename, io_fds[SFD_SLAVE]) == true) { + /* Close the other end of the stdin/stdout/stderr pipes and exec. */ + if (io_pipe[STDIN_FILENO][1]) + close(io_pipe[STDIN_FILENO][1]); + if (io_pipe[STDOUT_FILENO][0]) + close(io_pipe[STDOUT_FILENO][0]); + if (io_pipe[STDERR_FILENO][0]) + close(io_pipe[STDERR_FILENO][0]); + exec_monitor(details, sv[1]); + } + cstat.type = CMD_ERRNO; + cstat.val = errno; + send(sv[1], &cstat, sizeof(cstat), 0); + _exit(1); + } + + /* Close the other end of the stdin/stdout/stderr pipes. */ + if (io_pipe[STDIN_FILENO][0]) + close(io_pipe[STDIN_FILENO][0]); + if (io_pipe[STDOUT_FILENO][1]) + close(io_pipe[STDOUT_FILENO][1]); + if (io_pipe[STDERR_FILENO][1]) + close(io_pipe[STDERR_FILENO][1]); + + for (iob = iobufs; iob; iob = iob->next) { + /* Determine maxfd */ + if (iob->rfd > *maxfd) + *maxfd = iob->rfd; + if (iob->wfd > *maxfd) + *maxfd = iob->wfd; + + /* Set non-blocking mode. */ + n = fcntl(iob->rfd, F_GETFL, 0); + if (n != -1 && !ISSET(n, O_NONBLOCK)) + (void) fcntl(iob->rfd, F_SETFL, n | O_NONBLOCK); + n = fcntl(iob->wfd, F_GETFL, 0); + if (n != -1 && !ISSET(n, O_NONBLOCK)) + (void) fcntl(iob->wfd, F_SETFL, n | O_NONBLOCK); + } + + debug_return_int(child); +} + +void +pty_close(struct command_status *cstat) +{ + int n; + debug_decl(pty_close, SUDO_DEBUG_EXEC); + + /* Flush any remaining output (the plugin already got it) */ + if (io_fds[SFD_USERTTY] != -1) { + n = fcntl(io_fds[SFD_USERTTY], F_GETFL, 0); + if (n != -1 && ISSET(n, O_NONBLOCK)) { + CLR(n, O_NONBLOCK); + (void) fcntl(io_fds[SFD_USERTTY], F_SETFL, n); + } + } + flush_output(); + + if (io_fds[SFD_USERTTY] != -1) { + check_foreground(); + if (foreground) { + do { + n = term_restore(io_fds[SFD_USERTTY], 0); + } while (!n && errno == EINTR); + } + } + + /* If child was signalled, write the reason to stdout like the shell. */ + if (cstat->type == CMD_WSTATUS && WIFSIGNALED(cstat->val)) { + int signo = WTERMSIG(cstat->val); + if (signo && signo != SIGINT && signo != SIGPIPE) { + const char *reason = strsignal(signo); + n = io_fds[SFD_USERTTY] != -1 ? + io_fds[SFD_USERTTY] : STDOUT_FILENO; + if (write(n, reason, strlen(reason)) != -1) { + if (WCOREDUMP(cstat->val)) { + ignore_result(write(n, " (core dumped)", 14)); + } + ignore_result(write(n, "\n", 1)); + } + } + } + utmp_logout(slavename, cstat->type == CMD_WSTATUS ? cstat->val : 0); /* XXX - only if CD_SET_UTMP */ + debug_return; +} + +/* + * Fill in fdsr and fdsw based on the io buffers list. + * Called prior to select(). + */ +void +fd_set_iobs(fd_set *fdsr, fd_set *fdsw) +{ + struct io_buffer *iob; + debug_decl(fd_set_iobs, SUDO_DEBUG_EXEC); + + for (iob = iobufs; iob; iob = iob->next) { + if (iob->rfd == -1 && iob->wfd == -1) + continue; + if (iob->off == iob->len) { + iob->off = iob->len = 0; + /* Forward the EOF from reader to writer. */ + if (iob->rfd == -1) { + safe_close(iob->wfd); + iob->wfd = -1; + } + } + /* Don't read/write /dev/tty if we are not in the foreground. */ + if (iob->rfd != -1 && + (ttymode == TERM_RAW || iob->rfd != io_fds[SFD_USERTTY])) { + if (iob->len != sizeof(iob->buf)) + FD_SET(iob->rfd, fdsr); + } + if (iob->wfd != -1 && + (foreground || iob->wfd != io_fds[SFD_USERTTY])) { + if (iob->len > iob->off) + FD_SET(iob->wfd, fdsw); + } + } + debug_return; +} + +static void +deliver_signal(pid_t pid, int signo, bool from_parent) +{ + int status; + debug_decl(deliver_signal, SUDO_DEBUG_EXEC); + + /* Handle signal from parent. */ + sudo_debug_printf(SUDO_DEBUG_INFO, "received signal %d%s", signo, + from_parent ? " from parent" : ""); + switch (signo) { + case SIGALRM: + terminate_child(pid, true); + break; + case SIGCONT_FG: + /* Continue in foreground, grant it controlling tty. */ + do { + status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp); + } while (status == -1 && errno == EINTR); + killpg(pid, SIGCONT); + break; + case SIGCONT_BG: + /* Continue in background, I take controlling tty. */ + do { + status = tcsetpgrp(io_fds[SFD_SLAVE], getpid()); + } while (status == -1 && errno == EINTR); + killpg(pid, SIGCONT); + break; + case SIGKILL: + _exit(1); /* XXX */ + /* NOTREACHED */ + default: + /* Relay signal to child. */ + killpg(pid, signo); + break; + } + debug_return; +} + +/* + * Send status to parent over socketpair. + * Return value is the same as send(2). + */ +static int +send_status(int fd, struct command_status *cstat) +{ + int n = -1; + debug_decl(send_status, SUDO_DEBUG_EXEC); + + if (cstat->type != CMD_INVALID) { + sudo_debug_printf(SUDO_DEBUG_INFO, + "sending status message to parent: [%d, %d]", + cstat->type, cstat->val); + do { + n = send(fd, cstat, sizeof(*cstat), 0); + } while (n == -1 && errno == EINTR); + if (n != sizeof(*cstat)) { + sudo_debug_printf(SUDO_DEBUG_ERROR, + "unable to send status to parent: %s", strerror(errno)); + } + cstat->type = CMD_INVALID; /* prevent re-sending */ + } + debug_return_int(n); +} + +/* + * Wait for child status after receiving SIGCHLD. + * If the child was stopped, the status is send back to the parent. + * Otherwise, cstat is filled in but not sent. + * Returns true if child is still alive, else false. + */ +static bool +handle_sigchld(int backchannel, struct command_status *cstat) +{ + bool alive = true; + int status; + pid_t pid; + debug_decl(handle_sigchld, SUDO_DEBUG_EXEC); + + /* read child status */ + do { + pid = waitpid(child, &status, WUNTRACED|WNOHANG); + } while (pid == -1 && errno == EINTR); + if (pid == child) { + if (cstat->type != CMD_ERRNO) { + cstat->type = CMD_WSTATUS; + cstat->val = status; + if (WIFSTOPPED(status)) { + sudo_debug_printf(SUDO_DEBUG_INFO, "command stopped, signal %d", + WSTOPSIG(status)); + do { + child_pgrp = tcgetpgrp(io_fds[SFD_SLAVE]); + } while (child_pgrp == -1 && errno == EINTR); + if (send_status(backchannel, cstat) == -1) + return alive; /* XXX */ + } else if (WIFSIGNALED(status)) { + sudo_debug_printf(SUDO_DEBUG_INFO, "command killed, signal %d", + WTERMSIG(status)); + } else { + sudo_debug_printf(SUDO_DEBUG_INFO, "command exited: %d", + WEXITSTATUS(status)); + } + } + if (!WIFSTOPPED(status)) + alive = false; + } + debug_return_bool(alive); +} + +/* + * Monitor process that creates a new session with the controlling tty, + * resets signal handlers and forks a child to call exec_pty(). + * Waits for status changes from the command and relays them to the + * parent and relays signals from the parent to the command. + * Returns an error if fork(2) fails, else calls _exit(2). + */ +static int +exec_monitor(struct command_details *details, int backchannel) +{ + struct command_status cstat; + struct timeval tv; + fd_set *fdsr; + sigaction_t sa; + int errpipe[2], maxfd, n, status; + bool alive = true; + unsigned char signo; + debug_decl(exec_monitor, SUDO_DEBUG_EXEC); + + /* Close unused fds. */ + if (io_fds[SFD_MASTER] != -1) + close(io_fds[SFD_MASTER]); + if (io_fds[SFD_USERTTY] != -1) + close(io_fds[SFD_USERTTY]); + + /* + * We use a pipe to atomically handle signal notification within + * the select() loop. + */ + if (pipe_nonblock(signal_pipe) != 0) + error(1, _("unable to create pipe")); + + /* Reset SIGWINCH and SIGALRM. */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = SIG_DFL; + sigaction(SIGWINCH, &sa, NULL); + sigaction(SIGALRM, &sa, NULL); + + /* Ignore any SIGTTIN or SIGTTOU we get. */ + sa.sa_handler = SIG_IGN; + sigaction(SIGTTIN, &sa, NULL); + sigaction(SIGTTOU, &sa, NULL); + + /* Note: HP-UX select() will not be interrupted if SA_RESTART set */ + sa.sa_flags = SA_INTERRUPT; + sa.sa_handler = handler; + sigaction(SIGCHLD, &sa, NULL); + + /* Catch common signals so we can cleanup properly. */ + sa.sa_flags = SA_RESTART; + sa.sa_handler = handler; + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGTSTP, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); + sigaction(SIGUSR2, &sa, NULL); + + /* + * Start a new session with the parent as the session leader + * and the slave pty as the controlling terminal. + * This allows us to be notified when the child has been suspended. + */ + if (setsid() == -1) { + warning("setsid"); + goto bad; + } + if (io_fds[SFD_SLAVE] != -1) { +#ifdef TIOCSCTTY + if (ioctl(io_fds[SFD_SLAVE], TIOCSCTTY, NULL) != 0) + error(1, _("unable to set controlling tty")); +#else + /* Set controlling tty by reopening slave. */ + if ((n = open(slavename, O_RDWR)) >= 0) + close(n); +#endif + } + + /* + * If stdin/stdout is not a tty, start command in the background + * since it might be part of a pipeline that reads from /dev/tty. + * In this case, we rely on the command receiving SIGTTOU or SIGTTIN + * when it needs access to the controlling tty. + */ + if (pipeline) + foreground = false; + + /* Start command and wait for it to stop or exit */ + if (pipe(errpipe) == -1) + error(1, _("unable to create pipe")); + child = sudo_debug_fork(); + if (child == -1) { + warning(_("unable to fork")); + goto bad; + } + if (child == 0) { + /* We pass errno back to our parent via pipe on exec failure. */ + close(backchannel); + close(signal_pipe[0]); + close(signal_pipe[1]); + close(errpipe[0]); + fcntl(errpipe[1], F_SETFD, FD_CLOEXEC); + restore_signals(); + + /* setup tty and exec command */ + exec_pty(details, &errpipe[1]); + cstat.type = CMD_ERRNO; + cstat.val = errno; + ignore_result(write(errpipe[1], &cstat, sizeof(cstat))); + _exit(1); + } + close(errpipe[1]); + + /* If any of stdin/stdout/stderr are pipes, close them in parent. */ + if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDIN]); + if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDOUT]); + if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDERR]); + + /* + * Put child in its own process group. If we are starting the command + * in the foreground, assign its pgrp to the tty. + */ + child_pgrp = child; + setpgid(child, child_pgrp); + if (foreground) { + do { + status = tcsetpgrp(io_fds[SFD_SLAVE], child_pgrp); + } while (status == -1 && errno == EINTR); + } + + /* Wait for errno on pipe, signal on backchannel or for SIGCHLD */ + maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel); + fdsr = ecalloc(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); + memset(&cstat, 0, sizeof(cstat)); + tv.tv_sec = 0; + tv.tv_usec = 0; + for (;;) { + /* Check for signal on backchannel or errno on errpipe. */ + FD_SET(backchannel, fdsr); + FD_SET(signal_pipe[0], fdsr); + if (errpipe[0] != -1) + FD_SET(errpipe[0], fdsr); + maxfd = MAX(MAX(errpipe[0], signal_pipe[0]), backchannel); + + /* If command exited we just poll, there may be data on errpipe. */ + n = select(maxfd + 1, fdsr, NULL, NULL, alive ? NULL : &tv); + if (n <= 0) { + if (n == 0) + goto done; + if (errno == EINTR || errno == ENOMEM) + continue; + warning("monitor: %s", _("select failed")); + break; + } + + 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) { + if (!handle_sigchld(backchannel, &cstat)) + alive = false; + } else { + deliver_signal(child, signo, false); + } + continue; + } + if (errpipe[0] != -1 && FD_ISSET(errpipe[0], fdsr)) { + /* read errno or EOF from command pipe */ + n = read(errpipe[0], &cstat, sizeof(cstat)); + if (n == -1) { + if (errno == EINTR) + continue; + warning(_("error reading from pipe")); + goto done; + } + /* Got errno or EOF, either way we are done with errpipe. */ + FD_CLR(errpipe[0], fdsr); + close(errpipe[0]); + errpipe[0] = -1; + } + if (FD_ISSET(backchannel, fdsr)) { + struct command_status cstmp; + + /* read command from backchannel, should be a signal */ + n = recv(backchannel, &cstmp, sizeof(cstmp), 0); + if (n == -1) { + if (errno == EINTR) + continue; + warning(_("error reading from socketpair")); + goto done; + } + if (cstmp.type != CMD_SIGNO) { + warningx(_("unexpected reply type on backchannel: %d"), + cstmp.type); + continue; + } + deliver_signal(child, cstmp.val, true); + } + } + +done: + if (alive) { + /* XXX An error occurred, should send an error back. */ + kill(child, SIGKILL); + } else { + /* Send parent status. */ + send_status(backchannel, &cstat); + } + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 1); + _exit(1); + +bad: + debug_return_int(errno); +} + +/* + * Flush any output buffered in iobufs or readable from the fds. + * Does not read from /dev/tty. + */ +static void +flush_output(void) +{ + struct io_buffer *iob; + struct timeval tv; + fd_set *fdsr, *fdsw; + int nready, nwriters, maxfd = -1; + debug_decl(flush_output, SUDO_DEBUG_EXEC); + + /* Determine maxfd */ + for (iob = iobufs; iob; iob = iob->next) { + if (iob->rfd > maxfd) + maxfd = iob->rfd; + if (iob->wfd > maxfd) + maxfd = iob->wfd; + } + if (maxfd == -1) + debug_return; + + fdsr = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); + fdsw = emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask)); + for (;;) { + memset(fdsw, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask)); + memset(fdsr, 0, howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask)); + + nwriters = 0; + for (iob = iobufs; iob; iob = iob->next) { + /* Don't read from /dev/tty while flushing. */ + if (io_fds[SFD_USERTTY] != -1 && iob->rfd == io_fds[SFD_USERTTY]) + continue; + if (iob->rfd == -1 && iob->wfd == -1) + continue; + if (iob->off == iob->len) { + iob->off = iob->len = 0; + /* Forward the EOF from reader to writer. */ + if (iob->rfd == -1) { + safe_close(iob->wfd); + iob->wfd = -1; + } + } + if (iob->rfd != -1) { + if (iob->len != sizeof(iob->buf)) + FD_SET(iob->rfd, fdsr); + } + if (iob->wfd != -1) { + if (iob->len > iob->off) { + nwriters++; + FD_SET(iob->wfd, fdsw); + } + } + } + + /* Don't sleep in select if there are no buffers that need writing. */ + tv.tv_sec = 0; + tv.tv_usec = 0; + nready = select(maxfd + 1, fdsr, fdsw, NULL, nwriters ? NULL : &tv); + if (nready <= 0) { + if (nready == 0) + break; /* all I/O flushed */ + if (errno == EINTR || errno == ENOMEM) + continue; + warning(_("select failed")); + } + if (perform_io(fdsr, fdsw, NULL) != 0 || nready == -1) + break; + } + efree(fdsr); + efree(fdsw); + debug_return; +} + +/* + * Sets up std{in,out,err} and executes the actual command. + * Returns only if execve() fails. + */ +static void +exec_pty(struct command_details *details, int *errfd) +{ + pid_t self = getpid(); + debug_decl(exec_pty, SUDO_DEBUG_EXEC); + + /* Set child process group here too to avoid a race. */ + setpgid(0, self); + + /* Wire up standard fds, note that stdout/stderr may be pipes. */ + if (dup2(io_fds[SFD_STDIN], STDIN_FILENO) == -1 || + dup2(io_fds[SFD_STDOUT], STDOUT_FILENO) == -1 || + dup2(io_fds[SFD_STDERR], STDERR_FILENO) == -1) + error(1, "dup2"); + + /* Wait for parent to grant us the tty if we are foreground. */ + if (foreground) { + while (tcgetpgrp(io_fds[SFD_SLAVE]) != self) + ; /* spin */ + } + + /* We have guaranteed that the slave fd is > 2 */ + if (io_fds[SFD_SLAVE] != -1) + close(io_fds[SFD_SLAVE]); + if (io_fds[SFD_STDIN] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDIN]); + if (io_fds[SFD_STDOUT] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDOUT]); + if (io_fds[SFD_STDERR] != io_fds[SFD_SLAVE]) + close(io_fds[SFD_STDERR]); + + sudo_debug_execve(SUDO_DEBUG_INFO, details->command, + details->argv, details->envp); + + if (details->closefrom >= 0) { + int maxfd = details->closefrom; + dup2(*errfd, maxfd); + (void)fcntl(maxfd, F_SETFD, FD_CLOEXEC); + *errfd = maxfd++; + if (sudo_debug_fd_set(maxfd) != -1) + maxfd++; + closefrom(maxfd); + } +#ifdef HAVE_SELINUX + if (ISSET(details->flags, CD_RBAC_ENABLED)) { + selinux_execve(details->command, details->argv, details->envp, + ISSET(details->flags, CD_NOEXEC)); + } else +#endif + { + sudo_execve(details->command, details->argv, details->envp, + ISSET(details->flags, CD_NOEXEC)); + } + sudo_debug_printf(SUDO_DEBUG_ERROR, "unable to exec %s: %s", + details->command, strerror(errno)); + debug_return; +} + +/* + * Propagates tty size change signals to pty being used by the command. + */ +static void +sync_ttysize(int src, int dst) +{ +#ifdef TIOCGWINSZ + struct winsize wsize; + pid_t pgrp; + debug_decl(sync_ttysize, SUDO_DEBUG_EXEC); + + if (ioctl(src, TIOCGWINSZ, &wsize) == 0) { + ioctl(dst, TIOCSWINSZ, &wsize); + if ((pgrp = tcgetpgrp(dst)) != -1) + killpg(pgrp, SIGWINCH); + } + + debug_return; +#endif +} + +/* + * Handler for SIGWINCH in parent. + */ +static void +sigwinch(int s) +{ + int serrno = errno; + + sync_ttysize(io_fds[SFD_USERTTY], io_fds[SFD_SLAVE]); + errno = serrno; +} + +/* + * Only close the fd if it is not /dev/tty or std{in,out,err}. + * Return value is the same as send(2). + */ +static int +safe_close(int fd) +{ + debug_decl(safe_close, SUDO_DEBUG_EXEC); + + /* Avoid closing /dev/tty or std{in,out,err}. */ + if (fd < 3 || fd == io_fds[SFD_USERTTY]) { + errno = EINVAL; + debug_return_int(-1); + } + debug_return_int(close(fd)); +} diff --git a/src/get_pty.c b/src/get_pty.c new file mode 100644 index 0000000..21449cb --- /dev/null +++ b/src/get_pty.c @@ -0,0 +1,199 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#ifdef HAVE_SYS_STROPTS_H +#include +#endif /* HAVE_SYS_STROPTS_H */ +#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 */ +#include +#include +#include +#include + +#if defined(HAVE_LIBUTIL_H) +# include +#elif defined(HAVE_UTIL_H) +# include +#endif +#ifdef HAVE_PTY_H +# include +#endif + +#include "sudo.h" + +#if defined(HAVE_OPENPTY) +int +get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid) +{ + struct group *gr; + gid_t ttygid = -1; + int rval = 0; + debug_decl(get_pty, SUDO_DEBUG_PTY) + + if ((gr = getgrnam("tty")) != NULL) + ttygid = gr->gr_gid; + + if (openpty(master, slave, name, NULL, NULL) == 0) { + if (chown(name, ttyuid, ttygid) == 0) + rval = 1; + } + + debug_return_bool(rval); +} + +#elif defined(HAVE__GETPTY) +int +get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid) +{ + char *line; + int rval = 0; + debug_decl(get_pty, SUDO_DEBUG_PTY) + + /* IRIX-style dynamic ptys (may fork) */ + line = _getpty(master, O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP, 0); + if (line != NULL) { + *slave = open(line, O_RDWR|O_NOCTTY, 0); + if (*slave != -1) { + (void) chown(line, ttyuid, -1); + strlcpy(name, line, namesz); + rval = 1; + } else { + close(*master); + *master = -1; + } + } + debug_return_bool(rval); +} +#elif defined(HAVE_GRANTPT) +# ifndef HAVE_POSIX_OPENPT +static int +posix_openpt(int oflag) +{ + int fd; + +# ifdef _AIX + fd = open("/dev/ptc", oflag); +# else + fd = open("/dev/ptmx", oflag); +# endif + return fd; +} +# endif /* HAVE_POSIX_OPENPT */ + +int +get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid) +{ + char *line; + int rval = 0; + debug_decl(get_pty, SUDO_DEBUG_PTY) + + *master = posix_openpt(O_RDWR|O_NOCTTY); + if (*master != -1) { + (void) grantpt(*master); /* may fork */ + if (unlockpt(*master) != 0) { + close(*master); + goto done; + } + line = ptsname(*master); + if (line == NULL) { + close(*master); + goto done; + } + *slave = open(line, O_RDWR|O_NOCTTY, 0); + if (*slave == -1) { + close(*master); + goto done; + } +# if defined(I_PUSH) && !defined(_AIX) + ioctl(*slave, I_PUSH, "ptem"); /* pseudo tty emulation module */ + ioctl(*slave, I_PUSH, "ldterm"); /* line discipline module */ +# endif + (void) chown(line, ttyuid, -1); + strlcpy(name, line, namesz); + rval = 1; + } +done: + debug_return_bool(rval); +} + +#else /* Old-style BSD ptys */ + +static char line[] = "/dev/ptyXX"; + +int +get_pty(int *master, int *slave, char *name, size_t namesz, uid_t ttyuid) +{ + char *bank, *cp; + struct group *gr; + gid_t ttygid = -1; + int rval = 0; + debug_decl(get_pty, SUDO_DEBUG_PTY) + + if ((gr = getgrnam("tty")) != NULL) + ttygid = gr->gr_gid; + + for (bank = "pqrs"; *bank != '\0'; bank++) { + line[sizeof("/dev/ptyX") - 2] = *bank; + for (cp = "0123456789abcdef"; *cp != '\0'; cp++) { + line[sizeof("/dev/ptyXX") - 2] = *cp; + *master = open(line, O_RDWR|O_NOCTTY, 0); + if (*master == -1) { + if (errno == ENOENT) + goto done; /* out of ptys */ + continue; /* already in use */ + } + line[sizeof("/dev/p") - 2] = 't'; + (void) chown(line, ttyuid, ttygid); + (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +# ifdef HAVE_REVOKE + (void) revoke(line); +# endif + *slave = open(line, O_RDWR|O_NOCTTY, 0); + if (*slave != -1) { + strlcpy(name, line, namesz); + rval = 1; /* success */ + goto done; + } + (void) close(*master); + } + } +done: + debug_return(rval); +} +#endif /* HAVE_OPENPTY */ diff --git a/src/hooks.c b/src/hooks.c new file mode 100644 index 0000000..b2daaa9 --- /dev/null +++ b/src/hooks.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2012 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. + */ + +#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 */ + +#include "sudo.h" +#include "sudo_plugin.h" +#include "sudo_plugin_int.h" +#include "sudo_debug.h" + +/* Singly linked hook list. */ +struct sudo_hook_list { + struct sudo_hook_list *next; + union { + sudo_hook_fn_t generic_fn; + sudo_hook_fn_setenv_t setenv_fn; + sudo_hook_fn_unsetenv_t unsetenv_fn; + sudo_hook_fn_getenv_t getenv_fn; + sudo_hook_fn_putenv_t putenv_fn; + } u; + void *closure; +}; + +/* Each hook type gets own hook list. */ +static struct sudo_hook_list *sudo_hook_setenv_list; +static struct sudo_hook_list *sudo_hook_unsetenv_list; +static struct sudo_hook_list *sudo_hook_getenv_list; +static struct sudo_hook_list *sudo_hook_putenv_list; + +int +process_hooks_setenv(const char *name, const char *value, int overwrite) +{ + struct sudo_hook_list *hook; + int rc = SUDO_HOOK_RET_NEXT; + debug_decl(process_hooks_setenv, SUDO_DEBUG_HOOKS) + + /* First process the hooks. */ + for (hook = sudo_hook_setenv_list; hook != NULL; hook = hook->next) { + rc = hook->u.setenv_fn(name, value, overwrite, hook->closure); + switch (rc) { + case SUDO_HOOK_RET_NEXT: + break; + case SUDO_HOOK_RET_ERROR: + case SUDO_HOOK_RET_STOP: + goto done; + default: + warningx("invalid setenv hook return value: %d", rc); + break; + } + } +done: + debug_return_int(rc); +} + +int +process_hooks_putenv(char *string) +{ + struct sudo_hook_list *hook; + int rc = SUDO_HOOK_RET_NEXT; + debug_decl(process_hooks_putenv, SUDO_DEBUG_HOOKS) + + /* First process the hooks. */ + for (hook = sudo_hook_putenv_list; hook != NULL; hook = hook->next) { + rc = hook->u.putenv_fn(string, hook->closure); + switch (rc) { + case SUDO_HOOK_RET_NEXT: + break; + case SUDO_HOOK_RET_ERROR: + case SUDO_HOOK_RET_STOP: + goto done; + default: + warningx("invalid putenv hook return value: %d", rc); + break; + } + } +done: + debug_return_int(rc); +} + +int +process_hooks_getenv(const char *name, char **value) +{ + struct sudo_hook_list *hook; + char *val = NULL; + int rc = SUDO_HOOK_RET_NEXT; + debug_decl(process_hooks_getenv, SUDO_DEBUG_HOOKS) + + /* First process the hooks. */ + for (hook = sudo_hook_getenv_list; hook != NULL; hook = hook->next) { + rc = hook->u.getenv_fn(name, &val, hook->closure); + switch (rc) { + case SUDO_HOOK_RET_NEXT: + break; + case SUDO_HOOK_RET_ERROR: + case SUDO_HOOK_RET_STOP: + goto done; + default: + warningx("invalid getenv hook return value: %d", rc); + break; + } + } +done: + if (val != NULL) + *value = val; + debug_return_int(rc); +} + +int +process_hooks_unsetenv(const char *name) +{ + struct sudo_hook_list *hook; + int rc = SUDO_HOOK_RET_NEXT; + debug_decl(process_hooks_unsetenv, SUDO_DEBUG_HOOKS) + + /* First process the hooks. */ + for (hook = sudo_hook_unsetenv_list; hook != NULL; hook = hook->next) { + rc = hook->u.unsetenv_fn(name, hook->closure); + switch (rc) { + case SUDO_HOOK_RET_NEXT: + break; + case SUDO_HOOK_RET_ERROR: + case SUDO_HOOK_RET_STOP: + goto done; + default: + warningx("invalid unsetenv hook return value: %d", rc); + break; + } + } +done: + debug_return_int(rc); +} + +/* Hook registration internals. */ +static void +register_hook_internal(struct sudo_hook_list **head, + int (*hook_fn)(), void *closure) +{ + struct sudo_hook_list *hook; + debug_decl(register_hook_internal, SUDO_DEBUG_HOOKS) + + hook = ecalloc(1, sizeof(*hook)); + hook->u.generic_fn = hook_fn; + hook->closure = closure; + hook->next = *head; + *head = hook; + + debug_return; +} + +/* Register the specified hook. */ +int +register_hook(struct sudo_hook *hook) +{ + int rval = 0; + debug_decl(register_hook, SUDO_DEBUG_HOOKS) + + if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) { + /* Major versions must match. */ + rval = -1; + } else { + switch (hook->hook_type) { + case SUDO_HOOK_GETENV: + register_hook_internal(&sudo_hook_getenv_list, hook->hook_fn, + hook->closure); + break; + case SUDO_HOOK_PUTENV: + register_hook_internal(&sudo_hook_putenv_list, hook->hook_fn, + hook->closure); + break; + case SUDO_HOOK_SETENV: + register_hook_internal(&sudo_hook_setenv_list, hook->hook_fn, + hook->closure); + break; + case SUDO_HOOK_UNSETENV: + register_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn, + hook->closure); + break; + default: + /* XXX - use define for unknown value */ + rval = 1; + break; + } + } + + debug_return_int(rval); +} + +/* Hook deregistration internals. */ +static void +deregister_hook_internal(struct sudo_hook_list **head, + int (*hook_fn)(), void *closure) +{ + struct sudo_hook_list *hook, *prev = NULL; + debug_decl(deregister_hook_internal, SUDO_DEBUG_HOOKS) + + for (hook = *head, prev = NULL; hook != NULL; prev = hook, hook = hook->next) { + if (hook->u.generic_fn == hook_fn && hook->closure == closure) { + /* Remove from list and free. */ + if (prev == NULL) + *head = hook->next; + else + prev->next = hook->next; + efree(hook); + break; + } + } + + debug_return; +} + +/* Deregister the specified hook. */ +int +deregister_hook(struct sudo_hook *hook) +{ + int rval = 0; + debug_decl(deregister_hook, SUDO_DEBUG_HOOKS) + + if (SUDO_HOOK_VERSION_GET_MAJOR(hook->hook_version) != SUDO_HOOK_VERSION_MAJOR) { + /* Major versions must match. */ + rval = -1; + } else { + switch (hook->hook_type) { + case SUDO_HOOK_GETENV: + deregister_hook_internal(&sudo_hook_getenv_list, hook->hook_fn, + hook->closure); + break; + case SUDO_HOOK_PUTENV: + deregister_hook_internal(&sudo_hook_putenv_list, hook->hook_fn, + hook->closure); + break; + case SUDO_HOOK_SETENV: + deregister_hook_internal(&sudo_hook_setenv_list, hook->hook_fn, + hook->closure); + break; + case SUDO_HOOK_UNSETENV: + deregister_hook_internal(&sudo_hook_unsetenv_list, hook->hook_fn, + hook->closure); + break; + default: + /* XXX - use define for unknown value */ + rval = 1; + break; + } + } + + debug_return_int(rval); +} diff --git a/src/load_plugins.c b/src/load_plugins.c new file mode 100644 index 0000000..767f8ee --- /dev/null +++ b/src/load_plugins.c @@ -0,0 +1,172 @@ +/* + * 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 + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#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 */ +#ifdef HAVE_DLOPEN +# include +#else +# include "compat/dlfcn.h" +#endif +#include + +#include "sudo.h" +#include "sudo_plugin.h" +#include "sudo_plugin_int.h" +#include "sudo_conf.h" +#include "sudo_debug.h" + +#ifndef RTLD_GLOBAL +# define RTLD_GLOBAL 0 +#endif + +/* + * Load the plugins listed in sudo.conf. + */ +bool +sudo_load_plugins(struct plugin_container *policy_plugin, + struct plugin_container_list *io_plugins) +{ + struct plugin_info_list *plugins; + struct generic_plugin *plugin; + struct plugin_container *container; + struct plugin_info *info; + struct stat sb; + void *handle; + char path[PATH_MAX]; + bool rval = false; + debug_decl(sudo_load_plugins, SUDO_DEBUG_PLUGIN) + + /* Walk plugin list. */ + plugins = sudo_conf_plugins(); + tq_foreach_fwd(plugins, info) { + if (info->path[0] == '/') { + if (strlcpy(path, info->path, sizeof(path)) >= sizeof(path)) { + warningx(_("%s: %s"), info->path, strerror(ENAMETOOLONG)); + goto done; + } + } else { + if (snprintf(path, sizeof(path), "%s%s", _PATH_SUDO_PLUGIN_DIR, + info->path) >= sizeof(path)) { + warningx(_("%s%s: %s"), _PATH_SUDO_PLUGIN_DIR, info->path, + strerror(ENAMETOOLONG)); + goto done; + } + } + if (stat(path, &sb) != 0) { + warning("%s", path); + goto done; + } + if (sb.st_uid != ROOT_UID) { + warningx(_("%s must be owned by uid %d"), path, ROOT_UID); + goto done; + } + if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) { + warningx(_("%s must be only be writable by owner"), path); + goto done; + } + + /* Open plugin and map in symbol */ + handle = dlopen(path, RTLD_LAZY|RTLD_GLOBAL); + if (!handle) { + warningx(_("unable to dlopen %s: %s"), path, dlerror()); + goto done; + } + plugin = dlsym(handle, info->symbol_name); + if (!plugin) { + warningx(_("%s: unable to find symbol %s"), path, + info->symbol_name); + goto done; + } + + if (plugin->type != SUDO_POLICY_PLUGIN && plugin->type != SUDO_IO_PLUGIN) { + warningx(_("%s: unknown policy type %d"), path, plugin->type); + goto done; + } + if (SUDO_API_VERSION_GET_MAJOR(plugin->version) != SUDO_API_VERSION_MAJOR) { + warningx(_("%s: incompatible policy major version %d, expected %d"), + path, SUDO_API_VERSION_GET_MAJOR(plugin->version), + SUDO_API_VERSION_MAJOR); + goto done; + } + if (plugin->type == SUDO_POLICY_PLUGIN) { + if (policy_plugin->handle) { + warningx(_("%s: only a single policy plugin may be loaded"), + _PATH_SUDO_CONF); + goto done; + } + policy_plugin->handle = handle; + policy_plugin->name = info->symbol_name; + policy_plugin->options = info->options; + policy_plugin->u.generic = plugin; + } else if (plugin->type == SUDO_IO_PLUGIN) { + container = ecalloc(1, sizeof(*container)); + container->prev = container; + /* container->next = NULL; */ + container->handle = handle; + container->name = info->symbol_name; + container->options = info->options; + container->u.generic = plugin; + tq_append(io_plugins, container); + } + } + if (policy_plugin->handle == NULL) { + warningx(_("%s: at least one policy plugin must be specified"), + _PATH_SUDO_CONF); + goto done; + } + if (policy_plugin->u.policy->check_policy == NULL) { + warningx(_("policy plugin %s does not include a check_policy method"), + policy_plugin->name); + goto done; + } + + /* Install hooks (XXX - later). */ + if (policy_plugin->u.policy->version >= SUDO_API_MKVERSION(1, 2)) { + if (policy_plugin->u.policy->register_hooks != NULL) + policy_plugin->u.policy->register_hooks(SUDO_HOOK_VERSION, register_hook); + tq_foreach_fwd(io_plugins, container) { + if (container->u.io->register_hooks != NULL) + container->u.io->register_hooks(SUDO_HOOK_VERSION, register_hook); + } + } + + rval = true; + +done: + debug_return_bool(rval); +} diff --git a/src/net_ifs.c b/src/net_ifs.c new file mode 100644 index 0000000..fa8b676 --- /dev/null +++ b/src/net_ifs.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 1996, 1998-2005, 2007-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. + */ + +/* + * Suppress a warning w/ gcc on Digital UN*X. + * The system headers should really do this.... + */ +#if defined(__osf__) && !defined(__cplusplus) +struct mbuf; +struct rtentry; +#endif + +#include + +#include +#include +#include +#include +#include +#if defined(HAVE_SYS_SOCKIO_H) && !defined(SIOCGIFCONF) +# include +#endif +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#ifdef _ISC +# include +# include +# include +# define STRSET(cmd, param, len) {strioctl.ic_cmd=(cmd);\ + strioctl.ic_dp=(param);\ + strioctl.ic_timout=0;\ + strioctl.ic_len=(len);} +#endif /* _ISC */ +#ifdef _MIPS +# include +#endif /* _MIPS */ +#include +#include +#include +#ifdef HAVE_GETIFADDRS +# include +#endif + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "sudo_debug.h" + +#define DEFAULT_TEXT_DOMAIN "sudo" +#include "gettext.h" + +/* Minix apparently lacks IFF_LOOPBACK */ +#ifndef IFF_LOOPBACK +# define IFF_LOOPBACK 0 +#endif + +#ifndef INET6_ADDRSTRLEN +# define INET6_ADDRSTRLEN 46 +#endif + +#ifdef HAVE_GETIFADDRS + +/* + * Fill in the interfaces string with the machine's ip addresses and netmasks + * and return the number of interfaces found. + */ +int +get_net_ifs(char **addrinfo) +{ + struct ifaddrs *ifa, *ifaddrs; + struct sockaddr_in *sin; +#ifdef HAVE_STRUCT_IN6_ADDR + struct sockaddr_in6 *sin6; + char addrbuf[INET6_ADDRSTRLEN]; +#endif + int ailen, i, len, num_interfaces = 0; + char *cp; + debug_decl(get_net_ifs, SUDO_DEBUG_NETIF) + + if (getifaddrs(&ifaddrs)) + debug_return_int(0); + + /* Allocate space for the interfaces info string. */ + for (ifa = ifaddrs; ifa != NULL; ifa = ifa -> ifa_next) { + /* Skip interfaces marked "down" and "loopback". */ + if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL || + !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK)) + continue; + + switch (ifa->ifa_addr->sa_family) { + case AF_INET: +#ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: +#endif + num_interfaces++; + break; + } + } + if (num_interfaces == 0) + debug_return_int(0); + ailen = num_interfaces * 2 * INET6_ADDRSTRLEN; + *addrinfo = cp = emalloc(ailen); + + /* Store the IP addr/netmask pairs. */ + for (ifa = ifaddrs, i = 0; ifa != NULL; ifa = ifa -> ifa_next) { + /* Skip interfaces marked "down" and "loopback". */ + if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL || + !ISSET(ifa->ifa_flags, IFF_UP) || ISSET(ifa->ifa_flags, IFF_LOOPBACK)) + continue; + + switch (ifa->ifa_addr->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *)ifa->ifa_addr; + len = snprintf(cp, ailen - (*addrinfo - cp), + "%s%s/", cp == *addrinfo ? "" : " ", + inet_ntoa(sin->sin_addr)); + if (len <= 0 || len >= ailen - (*addrinfo - cp)) { + warningx(_("load_interfaces: overflow detected")); + goto done; + } + cp += len; + + sin = (struct sockaddr_in *)ifa->ifa_netmask; + len = snprintf(cp, ailen - (*addrinfo - cp), + "%s", inet_ntoa(sin->sin_addr)); + if (len <= 0 || len >= ailen - (*addrinfo - cp)) { + warningx(_("load_interfaces: overflow detected")); + goto done; + } + cp += len; + break; +#ifdef HAVE_STRUCT_IN6_ADDR + case AF_INET6: + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf)); + len = snprintf(cp, ailen - (*addrinfo - cp), + "%s%s/", cp == *addrinfo ? "" : " ", addrbuf); + if (len <= 0 || len >= ailen - (*addrinfo - cp)) { + warningx(_("load_interfaces: overflow detected")); + goto done; + } + cp += len; + + sin6 = (struct sockaddr_in6 *)ifa->ifa_netmask; + inet_ntop(AF_INET6, &sin6->sin6_addr, addrbuf, sizeof(addrbuf)); + len = snprintf(cp, ailen - (*addrinfo - cp), "%s", addrbuf); + if (len <= 0 || len >= ailen - (*addrinfo - cp)) { + warningx(_("load_interfaces: overflow detected")); + goto done; + } + cp += len; + break; +#endif /* HAVE_STRUCT_IN6_ADDR */ + } + } + +done: +#ifdef HAVE_FREEIFADDRS + freeifaddrs(ifaddrs); +#else + efree(ifaddrs); +#endif + debug_return_int(num_interfaces); +} + +#elif defined(SIOCGIFCONF) && !defined(STUB_LOAD_INTERFACES) + +/* + * Allocate and fill in the interfaces global variable with the + * machine's ip addresses and netmasks. + */ +int +get_net_ifs(char **addrinfo) +{ + struct ifconf *ifconf; + struct ifreq *ifr, ifr_tmp; + struct sockaddr_in *sin; + int ailen, i, len, n, sock, num_interfaces = 0; + size_t buflen = sizeof(struct ifconf) + BUFSIZ; + char *cp, *previfname = "", *ifconf_buf = NULL; +#ifdef _ISC + struct strioctl strioctl; +#endif /* _ISC */ + debug_decl(get_net_ifs, SUDO_DEBUG_NETIF) + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + error(1, _("unable to open socket")); + + /* + * Get interface configuration or return. + */ + for (;;) { + ifconf_buf = emalloc(buflen); + ifconf = (struct ifconf *) ifconf_buf; + ifconf->ifc_len = buflen - sizeof(struct ifconf); + ifconf->ifc_buf = (caddr_t) (ifconf_buf + sizeof(struct ifconf)); + +#ifdef _ISC + STRSET(SIOCGIFCONF, (caddr_t) ifconf, buflen); + if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) +#else + /* Note that some kernels return EINVAL if the buffer is too small */ + if (ioctl(sock, SIOCGIFCONF, (caddr_t) ifconf) < 0 && errno != EINVAL) +#endif /* _ISC */ + goto done; + + /* Break out of loop if we have a big enough buffer. */ + if (ifconf->ifc_len + sizeof(struct ifreq) < buflen) + break; + buflen += BUFSIZ; + efree(ifconf_buf); + } + + /* Allocate space for the maximum number of interfaces that could exist. */ + if ((n = ifconf->ifc_len / sizeof(struct ifreq)) == 0) + debug_return_int(0); + ailen = n * 2 * INET6_ADDRSTRLEN; + *addrinfo = cp = emalloc(ailen); + + /* For each interface, store the ip address and netmask. */ + for (i = 0; i < ifconf->ifc_len; ) { + /* Get a pointer to the current interface. */ + ifr = (struct ifreq *) &ifconf->ifc_buf[i]; + + /* Set i to the subscript of the next interface. */ + i += sizeof(struct ifreq); +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr)) + i += ifr->ifr_addr.sa_len - sizeof(struct sockaddr); +#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + + /* Skip duplicates and interfaces with NULL addresses. */ + sin = (struct sockaddr_in *) &ifr->ifr_addr; + if (sin->sin_addr.s_addr == 0 || + strncmp(previfname, ifr->ifr_name, sizeof(ifr->ifr_name) - 1) == 0) + continue; + + if (ifr->ifr_addr.sa_family != AF_INET) + continue; + +#ifdef SIOCGIFFLAGS + memset(&ifr_tmp, 0, sizeof(ifr_tmp)); + strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); + if (ioctl(sock, SIOCGIFFLAGS, (caddr_t) &ifr_tmp) < 0) +#endif + ifr_tmp = *ifr; + + /* Skip interfaces marked "down" and "loopback". */ + if (!ISSET(ifr_tmp.ifr_flags, IFF_UP) || + ISSET(ifr_tmp.ifr_flags, IFF_LOOPBACK)) + continue; + + sin = (struct sockaddr_in *) &ifr->ifr_addr; + len = snprintf(cp, ailen - (*addrinfo - cp), + "%s%s/", cp == *addrinfo ? "" : " ", + inet_ntoa(sin->sin_addr)); + if (len <= 0 || len >= ailen - (*addrinfo - cp)) { + warningx(_("load_interfaces: overflow detected")); + goto done; + } + cp += len; + + /* Stash the name of the interface we saved. */ + previfname = ifr->ifr_name; + + /* Get the netmask. */ + memset(&ifr_tmp, 0, sizeof(ifr_tmp)); + strncpy(ifr_tmp.ifr_name, ifr->ifr_name, sizeof(ifr_tmp.ifr_name) - 1); +#ifdef _ISC + STRSET(SIOCGIFNETMASK, (caddr_t) &ifr_tmp, sizeof(ifr_tmp)); + if (ioctl(sock, I_STR, (caddr_t) &strioctl) < 0) { +#else + if (ioctl(sock, SIOCGIFNETMASK, (caddr_t) &ifr_tmp) < 0) { +#endif /* _ISC */ + sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr; + sin->sin_addr.s_addr = htonl(IN_CLASSC_NET); + } + sin = (struct sockaddr_in *) &ifr_tmp.ifr_addr; + len = snprintf(cp, ailen - (*addrinfo - cp), + "%s", inet_ntoa(sin->sin_addr)); + if (len <= 0 || len >= ailen - (*addrinfo - cp)) { + warningx(_("load_interfaces: overflow detected")); + goto done; + } + cp += len; + num_interfaces++; + } + +done: + efree(ifconf_buf); + (void) close(sock); + + debug_return_int(num_interfaces); +} + +#else /* !SIOCGIFCONF || STUB_LOAD_INTERFACES */ + +/* + * Stub function for those without SIOCGIFCONF or getifaddrs() + */ +int +get_net_ifs(char **addrinfo) +{ + debug_decl(get_net_ifs, SUDO_DEBUG_NETIF) + debug_return_int(0); +} + +#endif /* SIOCGIFCONF && !STUB_LOAD_INTERFACES */ diff --git a/src/parse_args.c b/src/parse_args.c new file mode 100644 index 0000000..bcdfd86 --- /dev/null +++ b/src/parse_args.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 1993-1996, 1998-2012 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. + */ + +#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 */ +#include +#include +#include + +#include +#include "sudo.h" +#include "lbuf.h" + +/* For getopt(3) */ +extern char *optarg; +extern int optind; + +int tgetpass_flags; + +/* + * Local functions. + */ +static void help(void) __attribute__((__noreturn__)); +static void usage_excl(int); + +/* + * Mapping of command line flags to name/value settings. + */ +static struct sudo_settings { + const char *name; + const char *value; +} sudo_settings[] = { +#define ARG_BSDAUTH_TYPE 0 + { "bsdauth_type" }, +#define ARG_LOGIN_CLASS 1 + { "login_class" }, +#define ARG_DEBUG_FLAGS 2 + { "debug_flags" }, +#define ARG_PRESERVE_ENVIRONMENT 3 + { "preserve_environment" }, +#define ARG_RUNAS_GROUP 4 + { "runas_group" }, +#define ARG_SET_HOME 5 + { "set_home" }, +#define ARG_USER_SHELL 6 + { "run_shell" }, +#define ARG_LOGIN_SHELL 7 + { "login_shell" }, +#define ARG_IGNORE_TICKET 8 + { "ignore_ticket" }, +#define ARG_PROMPT 9 + { "prompt" }, +#define ARG_SELINUX_ROLE 10 + { "selinux_role" }, +#define ARG_SELINUX_TYPE 11 + { "selinux_type" }, +#define ARG_RUNAS_USER 12 + { "runas_user" }, +#define ARG_PROGNAME 13 + { "progname" }, +#define ARG_IMPLIED_SHELL 14 + { "implied_shell" }, +#define ARG_PRESERVE_GROUPS 15 + { "preserve_groups" }, +#define ARG_NONINTERACTIVE 16 + { "noninteractive" }, +#define ARG_SUDOEDIT 17 + { "sudoedit" }, +#define ARG_CLOSEFROM 18 + { "closefrom" }, +#define ARG_NET_ADDRS 19 + { "network_addrs" }, +#define NUM_SETTINGS 20 + { NULL } +}; + +/* + * Command line argument parsing. + * Sets nargc and nargv which corresponds to the argc/argv we'll use + * for the command to be run (if we are running one). + */ +int +parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp, + char ***env_addp) +{ + int mode = 0; /* what mode is sudo to be run in? */ + int flags = 0; /* mode flags */ + int valid_flags, ch; + int i, j; + char *cp, **env_add, **settings; + const char *debug_flags; + int nenv = 0; + int env_size = 32; + debug_decl(parse_args, SUDO_DEBUG_ARGS) + + env_add = emalloc2(env_size, sizeof(char *)); + + /* Pass progname to plugin so it can call setprogname() */ + sudo_settings[ARG_PROGNAME].value = getprogname(); + + /* First, check to see if we were invoked as "sudoedit". */ + if (strcmp(getprogname(), "sudoedit") == 0) { + mode = MODE_EDIT; + sudo_settings[ARG_SUDOEDIT].value = "true"; + } + + /* Load local IP addresses and masks. */ + if (get_net_ifs(&cp) > 0) + sudo_settings[ARG_NET_ADDRS].value = cp; + + /* Set debug file and flags from sudo.conf. */ + debug_flags = sudo_conf_debug_flags(); + if (debug_flags != NULL) + sudo_settings[ARG_DEBUG_FLAGS].value = debug_flags; + + /* Returns true if the last option string was "--" */ +#define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \ + argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0') + + /* Returns true if next option is an environment variable */ +#define is_envar (optind < argc && argv[optind][0] != '/' && \ + strchr(argv[optind], '=') != NULL) + + /* Flags allowed when running a command */ + valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME| + MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL; + /* XXX - should fill in settings at the end to avoid dupes */ + for (;;) { + /* + * We disable arg permutation for GNU getopt(). + * Some trickiness is required to allow environment variables + * to be interspersed with command line options. + */ + if ((ch = getopt(argc, argv, "+Aa:bC:c:D:Eeg:HhiKklnPp:r:Sst:U:u:Vv")) != -1) { + switch (ch) { + case 'A': + SET(tgetpass_flags, TGP_ASKPASS); + break; +#ifdef HAVE_BSD_AUTH_H + case 'a': + sudo_settings[ARG_BSDAUTH_TYPE].value = optarg; + break; +#endif + case 'b': + SET(flags, MODE_BACKGROUND); + break; + case 'C': + if (atoi(optarg) < 3) { + warningx(_("the argument to -C must be a number greater than or equal to 3")); + usage(1); + } + sudo_settings[ARG_CLOSEFROM].value = optarg; + break; +#ifdef HAVE_LOGIN_CAP_H + case 'c': + sudo_settings[ARG_LOGIN_CLASS].value = optarg; + break; +#endif + case 'D': + /* Ignored for backwards compatibility. */ + break; + case 'E': + sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true"; + break; + case 'e': + if (mode && mode != MODE_EDIT) + usage_excl(1); + mode = MODE_EDIT; + sudo_settings[ARG_SUDOEDIT].value = "true"; + valid_flags = MODE_NONINTERACTIVE; + break; + case 'g': + runas_group = optarg; + sudo_settings[ARG_RUNAS_GROUP].value = optarg; + break; + case 'H': + sudo_settings[ARG_SET_HOME].value = "true"; + break; + case 'h': + if (mode && mode != MODE_HELP) { + if (strcmp(getprogname(), "sudoedit") != 0) + usage_excl(1); + } + mode = MODE_HELP; + valid_flags = 0; + break; + case 'i': + sudo_settings[ARG_LOGIN_SHELL].value = "true"; + SET(flags, MODE_LOGIN_SHELL); + break; + case 'k': + sudo_settings[ARG_IGNORE_TICKET].value = "true"; + break; + case 'K': + sudo_settings[ARG_IGNORE_TICKET].value = "true"; + if (mode && mode != MODE_KILL) + usage_excl(1); + mode = MODE_KILL; + valid_flags = 0; + break; + case 'l': + if (mode) { + if (mode == MODE_LIST) + SET(flags, MODE_LONG_LIST); + else + usage_excl(1); + } + mode = MODE_LIST; + valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST; + break; + case 'n': + SET(flags, MODE_NONINTERACTIVE); + sudo_settings[ARG_NONINTERACTIVE].value = "true"; + break; + case 'P': + sudo_settings[ARG_PRESERVE_GROUPS].value = "true"; + break; + case 'p': + sudo_settings[ARG_PROMPT].value = optarg; + break; +#ifdef HAVE_SELINUX + case 'r': + sudo_settings[ARG_SELINUX_ROLE].value = optarg; + break; + case 't': + sudo_settings[ARG_SELINUX_TYPE].value = optarg; + break; +#endif + case 'S': + SET(tgetpass_flags, TGP_STDIN); + break; + case 's': + sudo_settings[ARG_USER_SHELL].value = "true"; + SET(flags, MODE_SHELL); + break; + case 'U': + if ((getpwnam(optarg)) == NULL) + errorx(1, _("unknown user: %s"), optarg); + list_user = optarg; + break; + case 'u': + runas_user = optarg; + sudo_settings[ARG_RUNAS_USER].value = optarg; + break; + case 'v': + if (mode && mode != MODE_VALIDATE) + usage_excl(1); + mode = MODE_VALIDATE; + valid_flags = MODE_NONINTERACTIVE; + break; + case 'V': + if (mode && mode != MODE_VERSION) + usage_excl(1); + mode = MODE_VERSION; + valid_flags = 0; + break; + default: + usage(1); + } + } else if (!got_end_of_args && is_envar) { + if (nenv == env_size - 2) { + env_size *= 2; + env_add = erealloc3(env_add, env_size, sizeof(char *)); + } + env_add[nenv++] = argv[optind]; + + /* Crank optind and resume getopt. */ + optind++; + } else { + /* Not an option or an environment variable -- we're done. */ + break; + } + } + env_add[nenv] = NULL; + + argc -= optind; + argv += optind; + + if (!mode) { + /* Defer -k mode setting until we know whether it is a flag or not */ + if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) { + if (argc == 0 && !(flags & (MODE_SHELL|MODE_LOGIN_SHELL))) { + mode = MODE_INVALIDATE; /* -k by itself */ + sudo_settings[ARG_IGNORE_TICKET].value = NULL; + valid_flags = 0; + } + } + if (!mode) + mode = MODE_RUN; /* running a command */ + } + + if (argc > 0 && mode == MODE_LIST) + mode = MODE_CHECK; + + if (ISSET(flags, MODE_LOGIN_SHELL)) { + if (ISSET(flags, MODE_SHELL)) { + warningx(_("you may not specify both the `-i' and `-s' options")); + usage(1); + } + if (ISSET(flags, MODE_PRESERVE_ENV)) { + warningx(_("you may not specify both the `-i' and `-E' options")); + usage(1); + } + SET(flags, MODE_SHELL); + } + if ((flags & valid_flags) != flags) + usage(1); + if (mode == MODE_EDIT && + (ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) { + if (ISSET(mode, MODE_PRESERVE_ENV)) + warningx(_("the `-E' option is not valid in edit mode")); + if (env_add[0] != NULL) + warningx(_("you may not specify environment variables in edit mode")); + usage(1); + } + if ((runas_user != NULL || runas_group != NULL) && + !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) { + usage(1); + } + if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) { + warningx(_("the `-U' option may only be used with the `-l' option")); + usage(1); + } + if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) { + warningx(_("the `-A' and `-S' options may not be used together")); + usage(1); + } + if ((argc == 0 && mode == MODE_EDIT) || + (argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK))) + usage(1); + if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) { + SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL)); + sudo_settings[ARG_IMPLIED_SHELL].value = "true"; + } + + if (mode == MODE_HELP) + help(); + + /* + * For shell mode we need to rewrite argv + */ + if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) { + char **av; + int ac; + + if (argc == 0) { + /* just the shell */ + ac = argc + 1; + av = emalloc2(ac + 1, sizeof(char *)); + memcpy(av + 1, argv, argc * sizeof(char *)); + } else { + /* shell -c "command" */ + char *cmnd, *src, *dst; + size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) + + strlen(argv[argc - 1]) + 1; + + cmnd = dst = emalloc2(cmnd_size, 2); + for (av = argv; *av != NULL; av++) { + for (src = *av; *src != '\0'; src++) { + /* quote potential meta characters */ + if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-') + *dst++ = '\\'; + *dst++ = *src; + } + *dst++ = ' '; + } + if (cmnd != dst) + dst--; /* replace last space with a NUL */ + *dst = '\0'; + + ac = 3; + av = emalloc2(ac + 1, sizeof(char *)); + av[1] = "-c"; + av[2] = cmnd; + } + av[0] = (char *)user_details.shell; /* plugin may override shell */ + av[ac] = NULL; + + argv = av; + argc = ac; + } + + /* + * Format setting_pairs into settings array. + */ + settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *)); + for (i = 0, j = 0; i < NUM_SETTINGS; i++) { + if (sudo_settings[i].value) { + sudo_debug_printf(SUDO_DEBUG_INFO, "settings: %s=%s", + sudo_settings[i].name, sudo_settings[i].value); + settings[j] = fmt_string(sudo_settings[i].name, + sudo_settings[i].value); + if (settings[j] == NULL) + errorx(1, _("unable to allocate memory")); + j++; + } + } + settings[j] = NULL; + + if (mode == MODE_EDIT) { +#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) + /* Must have the command in argv[0]. */ + argc++; + argv--; + argv[0] = "sudoedit"; +#else + errorx(1, _("sudoedit is not supported on this platform")); +#endif + } + + *settingsp = settings; + *env_addp = env_add; + *nargc = argc; + *nargv = argv; + debug_return_int(mode | flags); +} + +static int +usage_err(const char *buf) +{ + return fputs(buf, stderr); +} + +static int +usage_out(const char *buf) +{ + return fputs(buf, stdout); +} + +/* + * Give usage message and exit. + * The actual usage strings are in sudo_usage.h for configure substitution. + */ +void +usage(int fatal) +{ + struct lbuf lbuf; + char *uvec[6]; + int i, ulen; + + /* + * Use usage vectors appropriate to the progname. + */ + if (strcmp(getprogname(), "sudoedit") == 0) { + uvec[0] = SUDO_USAGE5 + 3; + uvec[1] = NULL; + } else { + uvec[0] = SUDO_USAGE1; + uvec[1] = SUDO_USAGE2; + uvec[2] = SUDO_USAGE3; + uvec[3] = SUDO_USAGE4; + uvec[4] = SUDO_USAGE5; + uvec[5] = NULL; + } + + /* + * Print usage and wrap lines as needed, depending on the + * tty width. + */ + ulen = (int)strlen(getprogname()) + 8; + lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL, + user_details.ts_cols); + for (i = 0; uvec[i] != NULL; i++) { + lbuf_append(&lbuf, "usage: %s%s", getprogname(), uvec[i]); + lbuf_print(&lbuf); + } + lbuf_destroy(&lbuf); + if (fatal) + exit(1); +} + +/* + * Tell which options are mutually exclusive and exit. + */ +static void +usage_excl(int fatal) +{ + debug_decl(usage_excl, SUDO_DEBUG_ARGS) + + warningx(_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified")); + usage(fatal); +} + +static void +help(void) +{ + struct lbuf lbuf; + int indent = 16; + const char *pname = getprogname(); + debug_decl(help, SUDO_DEBUG_ARGS) + + lbuf_init(&lbuf, usage_out, indent, NULL, user_details.ts_cols); + if (strcmp(pname, "sudoedit") == 0) + lbuf_append(&lbuf, _("%s - edit files as another user\n\n"), pname); + else + lbuf_append(&lbuf, _("%s - execute a command as another user\n\n"), pname); + lbuf_print(&lbuf); + + usage(0); + + lbuf_append(&lbuf, _("\nOptions:\n")); +#ifdef HAVE_BSD_AUTH_H + lbuf_append(&lbuf, " -A %s", + _("use helper program for password prompting\n")); +#endif + lbuf_append(&lbuf, " -a type %s", + _("use specified BSD authentication type\n")); + lbuf_append(&lbuf, " -b %s", + _("run command in the background\n")); + lbuf_append(&lbuf, " -C fd %s", + _("close all file descriptors >= fd\n")); +#ifdef HAVE_LOGIN_CAP_H + lbuf_append(&lbuf, " -c class %s", + _("run command with specified login class\n")); +#endif + lbuf_append(&lbuf, " -E %s", + _("preserve user environment when executing command\n")); + lbuf_append(&lbuf, " -e %s", + _("edit files instead of running a command\n")); + lbuf_append(&lbuf, " -g group %s", + _("execute command as the specified group\n")); + lbuf_append(&lbuf, " -H %s", + _("set HOME variable to target user's home dir.\n")); + lbuf_append(&lbuf, " -h %s", + _("display help message and exit\n")); + lbuf_append(&lbuf, " -i [command] %s", + _("run a login shell as target user\n")); + lbuf_append(&lbuf, " -K %s", + _("remove timestamp file completely\n")); + lbuf_append(&lbuf, " -k %s", + _("invalidate timestamp file\n")); + lbuf_append(&lbuf, " -l[l] command %s", + _("list user's available commands\n")); + lbuf_append(&lbuf, " -n %s", + _("non-interactive mode, will not prompt user\n")); + lbuf_append(&lbuf, " -P %s", + _("preserve group vector instead of setting to target's\n")); + lbuf_append(&lbuf, " -p prompt %s", + _("use specified password prompt\n")); +#ifdef HAVE_SELINUX + lbuf_append(&lbuf, " -r role %s", + _("create SELinux security context with specified role\n")); +#endif + lbuf_append(&lbuf, " -S %s", + _("read password from standard input\n")); + lbuf_append(&lbuf, + " -s [command] %s", _("run a shell as target user\n")); +#ifdef HAVE_SELINUX + lbuf_append(&lbuf, " -t type %s", + _("create SELinux security context with specified role\n")); +#endif + lbuf_append(&lbuf, " -U user %s", + _("when listing, list specified user's privileges\n")); + lbuf_append(&lbuf, " -u user %s", + _("run command (or edit file) as specified user\n")); + lbuf_append(&lbuf, " -V %s", + _("display version information and exit\n")); + lbuf_append(&lbuf, " -v %s", + _("update user's timestamp without running a command\n")); + lbuf_append(&lbuf, " -- %s", + _("stop processing command line arguments\n")); + lbuf_print(&lbuf); + lbuf_destroy(&lbuf); + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, 0); + exit(0); +} diff --git a/src/po/README b/src/po/README new file mode 100644 index 0000000..ff9b845 --- /dev/null +++ b/src/po/README @@ -0,0 +1,14 @@ +NLS Translations for sudo are coordinated through the Translation +Project, at http://translationproject.org/ + +If you would like to contribute a translation for sudo, please join +a translation team at the Translation Project instead of contributing +a po file directly. This will avoid duplicated work if there is +already a translation in progress. If you would like to become a +member of a translation team, please follow the instructions at +http://translationproject.org/html/translators.html + +The messages in sudo are split into two domains: sudo and sudoers. +The former is used by the sudo front-end and utility functions. +The latter is used by the sudoers policy and I/O logging plug-ins +as well as the sudoers-specific commands visudo and sudoreplay. diff --git a/src/po/da.mo b/src/po/da.mo new file mode 100644 index 0000000..c03e6cd Binary files /dev/null and b/src/po/da.mo differ diff --git a/src/po/da.po b/src/po/da.po new file mode 100644 index 0000000..281ee2a --- /dev/null +++ b/src/po/da.po @@ -0,0 +1,788 @@ +# Danish translation of sudo. +# This file is put in the public domain. +# Joe Hansen , 2011, 2012. +# +# audit -> overvågning +# overflow -> overløb +# +# projekt bruger konsekvent små bogstaver, og så i starten af sætninger, så +# dette er også valgt på dansk uanset at der er : som efterfølgende normalt +# ville have stort begyndelsesbogstav på dansk. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5-b4\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-03-28 14:06-0400\n" +"PO-Revision-Date: 2012-04-08 23:06+0100\n" +"Last-Translator: Joe Hansen \n" +"Language-Team: Danish \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:105 src/exec_pty.c:616 src/exec_pty.c:948 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "kunne ikke forgrene" + +#: src/exec.c:252 +#, c-format +msgid "unable to create sockets" +msgstr "kunne ikke oprette sokler" + +#: src/exec.c:259 src/exec_pty.c:567 src/exec_pty.c:576 src/exec_pty.c:584 +#: src/exec_pty.c:883 src/exec_pty.c:945 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "kunne ikke oprette datakanal (pipe)" + +#: src/exec.c:340 src/exec_pty.c:1011 src/exec_pty.c:1146 +#, c-format +msgid "select failed" +msgstr "select fejlede" + +#: src/exec.c:425 +#, c-format +msgid "unable to restore tty label" +msgstr "kunne ikke gendanne tty-etiket" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "kan ikke fjerne PRIV_PROC_EXEC fra PRIV_LIMIT" + +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:447 src/sudo.c:467 +#: src/sudo.c:474 src/sudo.c:485 src/sudo.c:871 common/alloc.c:85 +#: common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 common/alloc.c:168 +#: common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#, c-format +msgid "unable to allocate memory" +msgstr "kunne ikke allokere hukommelse" + +#: src/exec_pty.c:140 +#, c-format +msgid "unable to allocate pty" +msgstr "kunne ikke allokere pty" + +#: src/exec_pty.c:609 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "kunne ikke angive terminal til tilstanden rå (raw)" + +#: src/exec_pty.c:926 +#, c-format +msgid "unable to set controlling tty" +msgstr "kunne ikke angive kontrollerende tty" + +#: src/exec_pty.c:1019 +#, c-format +msgid "error reading from signal pipe" +msgstr "fejl under læsning fra signaldatakanal" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from pipe" +msgstr "fejl ved læsning fra datakanal" + +#: src/exec_pty.c:1054 +#, c-format +msgid "error reading from socketpair" +msgstr "fejl ved læsning fra socketpair" + +#: src/exec_pty.c:1058 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "uventet svartype på bagkanal (backchannel): %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s skal være ejet af uid %d" + +# engelsk fejl be dobbelt? +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s må kun være skrivbar for ejeren" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "kunne ikke dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: kunne ikke finde symbol %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: ukendt politiktype %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: inkompatibel politik hovedversion %d, forventede %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: kun et udvidelsesmodul for én politik må være indlæst" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: mindst et udvidelsesmodul for politik skal være angivet" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "politikudvidelsesmodulet %s inkluderer ikke en metode for check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: overløb detekteret" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "kunne ikke åbne sokkel" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "argumentet for -C skal være et tal større end eller lig 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "ukendt bruger: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "du kan ikke samtidig angive tilvalgene »-i« og »-s«" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "du kan ikke samtidig angive tilvalgende »-i« og »-E«" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "tilvalget »-E« er ikke gyldigt i redigeringstilstand" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "du må ikke angive miljøvariabler i redigeringstilstand" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "tilvalget »-U« må kun bruges med tilvalget »-l«" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "tilvalgene »-A« og »-S« må ikke bruges sammen" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit er ikke understøttet på denne platform" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Kun et af tilvalgene -e, -h, -i, -K, -l, -s, -v eller -V må angives" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - rediger filer som en anden bruger\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - udfør en kommando som en anden bruger\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Tilvalg:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "brug hjælpeprogram for indhentelse af adgangskode\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "brug angivet BSD-godkendelsestype\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "kør kommando i baggrunden\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "luk alle filbeskrivelser >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "kør kommando med angivet logindklasse\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "bevar brugermiljø når kommando udføres\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "rediger filer i stedet for at køre en kommando\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "udfør kommando som den angivne gruppe\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "angiv HOME-variabel til målbrugers hjemmemappe.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "vis hjælpetekst og afslut\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "kør en logindskal som målbruger\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "fjern tidsstempelfil fuldstændig\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "ugyldiggør tidsstempelfil\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "vis brugers tilgængelige kommandoer\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "ikkeinteraktiv tilstand, vil ikke spørge bruger\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "bevar gruppevektor i stedet for at sætte til målets\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "brug angivet logind for adgangskode\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "opret SELinux-sikkerhedskontekt med angivet rolle\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "læs adgangskode fra standardinddata\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "kør en skal som målbruger\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "når der listes, så list angivne brugers privilegier\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "kør kommando (eller rediger fil) som angivet bruger\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "vis versionsinformation og afslut\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "opdater brugers tidsstempel uden at køre en kommando\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "stop behandling af parametre for kommandolinjen\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "kunne ikke åbne overvågningssystem" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "kunne ikke sende overvågningsbesked" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "kunne ikke fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s ændrede etiketter" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "kan ikke gendanne kontekst for %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "kan ikke åbne %s, giver ikke ny etiket til tty" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "kan ikke indhente aktuel tty-kontekst, giver ikke ny etiket til tty" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "kan ikke indhente ny tty-kontekst, giver ikke nyt etiket til tty" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "kan ikke angive ny tty-kontekst" + +#: src/selinux.c:196 src/selinux.c:209 src/sudo.c:333 common/sudo_conf.c:328 +#, c-format +msgid "unable to open %s" +msgstr "kan ikke åbne %s" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "du skal angive en rolle for type %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "kan ikke indhente standardtype for rolle %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "kunne ikke angive ny rolle %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "kunne ikke angive ny type %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s er ikke en gyldig kontekst" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "kunne ikke indhente gammel_kontekst (old_context)" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "kunne ikke bestemme tilstanden gennemtving (enforcing)." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "kunne ikke opsætte tty-kontekst for %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "kunne ikke angive kørselskontekt til %s" + +# engelsk: mangler vist lidt info her tast eller nøgle. mon ikke det er nøgle +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "kunne ikke angive nøgleoprettelseskontekst til %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "kræver mindst et argument" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "kan ikke køre %s" + +#: src/sudo.c:213 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo version %s\n" + +#: src/sudo.c:215 +#, c-format +msgid "Configure options: %s\n" +msgstr "Konfigurationsindstillinger: %s\n" + +#: src/sudo.c:220 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "fatal fejl, kan ikke indlæse udvidelsesmoduler" + +#: src/sudo.c:228 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "kan ikke initialisere udvidelsesmodul for politik" + +#: src/sudo.c:283 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "fejl under initialisering af I/O-udvidelsesmodulet %s" + +#: src/sudo.c:308 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "uventet sudo-tilstand 0x%x" + +#: src/sudo.c:402 +#, c-format +msgid "unable to get group vector" +msgstr "kan ikke indhente gruppevektor" + +#: src/sudo.c:443 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "ukendt uid %u: hvem er du?" + +#: src/sudo.c:735 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s skal være ejet af uid %d og have setuid bit angivet" + +#: src/sudo.c:738 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "effektiv uid er ikke %d, er %s på et filsystem med indstillingen »nosuid« angivet eller et NFS-filsytsem uden administratorprivilegier (root)?" + +#: src/sudo.c:744 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "effektiv uid er ikke %d, er sudo installeret setuid root?" + +#: src/sudo.c:813 +#, c-format +msgid "resource control limit has been reached" +msgstr "grænse for ressourcekontrol er nået" + +#: src/sudo.c:816 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "bruger »%s« er ikke medlem af projektet »%s«" + +#: src/sudo.c:820 +#, c-format +msgid "the invoking task is final" +msgstr "start af opgave er færdig" + +#: src/sudo.c:823 +#, c-format +msgid "could not join project \"%s\"" +msgstr "kunne ikke slutte til projekt »%s«" + +#: src/sudo.c:828 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "ingen ressourcekø som accepterer standardbindinger findes for projekt »%s«" + +#: src/sudo.c:832 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "angivet ressourcekø findes ikke for projekt »%s«" + +#: src/sudo.c:836 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "kunne ikke binde til standardressourcekø for projekt »%s«" + +#: src/sudo.c:842 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject fejlede for projekt »%s«" + +#: src/sudo.c:844 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "advarsel, ressourcekontroltildeling fejlede for projekt »%s«" + +#: src/sudo.c:909 +#, c-format +msgid "unknown login class %s" +msgstr "ukendt logindklasse %s" + +#: src/sudo.c:923 src/sudo.c:926 +#, c-format +msgid "unable to set user context" +msgstr "kan ikke angive brugerkontekst" + +#: src/sudo.c:938 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "kunne ikke angive supplerende gruppe-id'er" + +#: src/sudo.c:945 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "kan ikke angive effektiv gid til runas gid %u" + +#: src/sudo.c:951 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "kunne ikke angive gid til runas gid %u" + +#: src/sudo.c:958 +#, c-format +msgid "unable to set process priority" +msgstr "kunne ikke angive procesprioritet" + +#: src/sudo.c:966 +#, c-format +msgid "unable to change root to %s" +msgstr "kunne ikke ændre administrator (root) til %s" + +#: src/sudo.c:973 src/sudo.c:979 src/sudo.c:985 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "kunne ikke ændre til runas uid (%u, %u)" + +#: src/sudo.c:999 +#, c-format +msgid "unable to change directory to %s" +msgstr "kunne ikke ændre mappe til %s" + +#: src/sudo.c:1072 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "uventet underbetingelse for terminering: %d" + +#: src/sudo.c:1133 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "politikudvidelsesmodul %s understøter ikke listning af privilegier" + +#: src/sudo.c:1145 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "politikudvidelsesmodul %s understøtter ikke tilvalget -v" + +#: src/sudo.c:1157 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "politikudvidelsesmodul %s understøtter ikke tilvalget -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "kunne ikke ændre uid til root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "fejl i udvidelsesmodul: mangler filliste for sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: ikke en regulær fil" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: kort skrivning" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s tilbage uændrede" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s uændrede" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "kan ikke skrive til %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "indhold fra redigeringssession tilbage i %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "kan ikke læse midlertidig fil" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "ingen tty til stede og intet askpass-program angivet" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "intet askpass-program angivet, forsøg at angive SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "kan ikke angive gid til %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "kan ikke angive uid til %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "kan ikke køre %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "kan ikke gemme til stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "kan ikke dup2 stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "kan ikke gendanne stdin" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "kan ikke åbne userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "kan ikke skifte til register »%s« for %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "kan ikke gendanne register" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "intern fejl, forsøgte at emalloc(0)" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "intern fejl, forsøgte at emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "intern fejl, emalloc2()-overløb" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "intern fejl, forsøgte at ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "intern fejl, ecalloc()-overløb" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "intern fejl, forsøgte at erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "intern fejl, forsøgte at erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "intern fejl, erealloc3()-overløb" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "kan ikke køre stat %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s er ikke en regulær fil" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s er ejet af uid %u, burde være %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s er skrivbar for alle" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s er skrivbar for gruppe" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "ukendt signal" + +#~ msgid "must be setuid root" +#~ msgstr "skal være setuid root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "argumentet for -D skal være mellem 1 og 9; begge tal inkluderet" diff --git a/src/po/de.mo b/src/po/de.mo new file mode 100644 index 0000000..423279a Binary files /dev/null and b/src/po/de.mo differ diff --git a/src/po/de.po b/src/po/de.po new file mode 100644 index 0000000..686b3c5 --- /dev/null +++ b/src/po/de.po @@ -0,0 +1,786 @@ +# German translation for sudo. +# This file is distributed under the same license as the sudo package. +# Mario Blättermann , 2012. +# Jakob Kramer , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 14:32+0200\n" +"Last-Translator: Jakob Kramer \n" +"Language-Team: German \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Language: German\n" +"X-Poedit-Country: GERMANY\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "Nutzerdatenbank konnte nicht geöffnet werden" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "Es konnte nicht zur Registrierungsdatenbank »%s« von %s gewechselt werden" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "Registrierungsdatenbank konnte nicht wiederhergestellt werden" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "Interner Fehler: Es wurde versucht, emalloc(0) auszuführen" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "Speicher konnte nicht zugewiesen werden" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "Interner Fehler: Es wurde versucht, emalloc2(0) auszuführen" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "Interner Fehler: Überlauf bei emalloc2()" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "Interner Fehler: Es wurde versucht, ecalloc(0) auszuführen" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "Interner Fehler: Überlauf bei ecalloc()" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "Interner Fehler: Es wurde versucht, erealloc(0) auszuführen" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "Interner Fehler: Es wurde versucht, erealloc3(0) auszuführen" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "Interner Fehler, Überlauf bei erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "stat konnte nicht auf %s angewandt werden" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s ist keine reguläre Datei" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s gehört Benutzer mit UID %u, sollte allerdings %u gehören" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s kann von allen verändert werden" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s kann von der Gruppe verändert werden" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "%s konnte nicht geöffnet werden" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Unbekanntes Signal" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "Regelwerks-Plugin konnte Sitzung nicht initialisieren" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "Es konnte nicht geforkt werden" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "Sockets konnten nicht hergestellt werden" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "Weiterleitung konnte nicht erstellt werden" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "»select« schlug fehl" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "TTY-Kennzeichnung konnte nicht wiederhergestellt werden" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "PRIV_PROC_EXEC konnte nicht von PRIV_LIMIT entfernt werden" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "PTY konnte nicht vergeben werden" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "Terminal konnte nicht in den Rohmodus gesetzt werden" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "Kontrollierendes TTY konnte nicht gesetzt werden" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "Fehler beim Lesen der Signal-Pipe" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "Fehler beim Lesen der Pipe" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "Fehler beim Lesen des Socket-Paars" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "Unerwarteter Antworttyp auf Rückmeldungskanal: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s muss Benutzer mit UID %d gehören" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s darf nur vom Besitzer beschreibbar sein" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "dlopen konnte nicht auf %s ausgeführt werden: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: Symbol %s konnte nicht gefunden werden" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: Unbekannter Regelwerktyp %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: Inkompatible Hauptversion %d des Regelwerks, %d erwartet" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: Nur ein einziges Regelwerks-Plugin kann geladen werden" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: Mindestens ein Regelwerks-Plugin muss festgelegt werden" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "Das Regelwerks-Plugin %s enthält keine check_policy-Methode" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: Überlauf entdeckt" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "Socket konnte nicht geöffnet werden" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "Das Argument für -C muss eine Zahl größergleich 3 sein" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "Unbekannter Benutzer: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "Die Optionen »-i« und »-s« können nicht gemeinsam benutzt werden" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "Die Optionen »-i« und »-E« können nicht gemeinsam benutzt werden" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "Die Option »-E« ist im Bearbeiten-Modus ungültig" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "Im Bearbeiten-Modus können keine Umgebungsvariablen gesetzt werden" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "Die »-U«-Option kann nur zusammen mit »-l« benutzt werden" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "Die Optionen »-A« und »-S« können nicht gemeinsam benutzt werden" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit ist auf dieser Plattform nicht verfügbar" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Nur eine der Optionen -e, -h, -i, -K, -l, -s, -v oder -V darf angegeben werden" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - Dateien als anderer Benutzer verändern\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - Einen Befehl als anderer Benutzer ausführen\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Optionen:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "Hilfsprogramm zum Eingeben des Passworts verwenden\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "Angegebenen BSD-Legitimierungstypen verwenden\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "Befehl im Hintergrund ausführen\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "Alle Dateideskriptoren >= fd schließen\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "Befehl unter angegebener Login-Klasse ausführen\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "Benutzerumgebung beim Starten des Befehls beibehalten\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "Dateien bearbeiten statt einen Befehl ausführen\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "Befehl unter angegebener Gruppe ausführen\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "HOME-Variable als Home-Ordner des Zielnutzers setzen.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "Hilfe ausgeben und beenden\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "Eine Anmeldeshell als Zielnutzer starten\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "Zeitstempeldateien komplett entfernen\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "Zeitstempeldatei ungültig machen\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "Für den Benutzer verfügbare Befehle auflisten\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "Nicht-interaktiver Modus, der Benutzer wird zu nichts aufgefordert werden\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "Gruppen-Vektor beibehalten, statt zu dem des Zielnutzers zu setzen\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "Angegebenen Passwort-Prompt benutzen\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "SELinux-Sicherheitskontext mit angegebener Funktion erstellen\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "Passwort von der Standardeingabe lesen\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "Eine Shell als Zielnutzer ausführen\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "Wenn aufgelistet wird, Berechtigungen des angegebenen Benutzers auflisten\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "Befehl oder Datei als angegebener Benutzer ausführen bzw. ändern\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "Versionsinformation anzeigen und beenden\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "Den Zeitstempel des Benutzers erneuern, ohne einen Befehl auszuführen\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "Aufhören, die Befehlszeilenargumente zu verarbeiten\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "Das Audit-System konnte nicht geöffnet werden" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "Die Audit-Nachricht konnte nicht verschickt werden" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "»fgetfilecon« konnte nicht auf %s angewendet werden" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s änderte die Kennzeichnung" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "Der Kontext für %s konnte nicht wiederhergestellt werden" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "%s konnte nicht geöffnet werden, TTY wird nicht neu gekennzeichnet" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "" +"Aktueller TTY-Kontext konnte nicht festgestellt werden, TTY wird nicht neu\n" +"gekennzeichnet." + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "" +"Neuer TTY-Kontext konnte nicht festgestellt werden, TTY wird nicht neu\n" +"gekennzeichnet." + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "Neuer TTY-Kontext konnte nicht festgestellt werden" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "Für den Typen %s muss eine Funktion angegeben werden" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "Standardtyp für Funktion %s konnte nicht ermittelt werden" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "Neue Funktion %s konnte nicht festgelegt werden" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "Neuer Typ %s konnte nicht festgelegt werden" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s ist kein gültiger Kontext" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "»old_context« konnte nicht wiedergeholt werden" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "" + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "TTY-Kontext konnte für %s nicht aufgesetzt werden" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "Ausführungskontext konnte nicht auf »%s« gesetzt werden" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "Benötigt mindestens ein Argument" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "%s konnte nicht ausgeführt werden" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo-Version %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Optionen für »configure«: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "Schwerwiegender Fehler, Plugins konnten nicht geladen werden" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "Regelwerks-Plugin konnte nicht initialisiert werden" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "E/A-Plugin %s konnte nicht initialisiert werden" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "Unerwarteter Sudo-Modus 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "Unbekannte UID %u: Wer sind Sie?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s muss dem Benutzer mit UID %d gehören und das »setuid«-Bit gesetzt haben" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "Effektive UID ist nicht %d. Liegt %s auf einem Dateisystem mit gesetzter »nosuid«-Option oder auf einem NFS-Dateisystem ohne Root-Rechte?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "Effektive UID ist nicht %d. Wurde sudo mit »setuid root« installiert?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "Benutzer »%s« ist kein Mitglied des Projekts »%s«" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "Projekt »%s« konnte nicht beigetreten werden" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "Den angegebenen Ressourcen-Pool gibt es für das Projekt »%s« nicht" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "Es konnte nicht zum Standard-Ressourcen-Pool für Projekt »%s« verbunden werden." + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "»setproject« schlug für Projekt »%s« fehl" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "Unbekannte Anmeldungsklasse %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "Nutzerkontext konnte nicht gesetzt werden" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "Zusätzliche Gruppenkennungen konnten nicht gesetzt werden" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "Effektive GID konnte nicht zu »runas«-GID %u gesetzt werden" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "GID konnte nicht zu »runas«-GID %u gesetzt werden" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "Prozesspriorität konnte nicht gesetzt werden" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "Wurzelordner konnte nicht zu %s geändert werden" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "Es konnte nicht zu »runas«-GID gewechselt werden (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "In Ordner »%s« konnte nicht gewechselt werden" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "Unerwartete Abbruchsbedingung eines Unterprozesses: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "Regelwerks-Plugin %s unterstützt das Auflisten von Privilegien nicht" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "Regelwerks-Plugin %s unterstützt die Option -v nicht" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "Regelwerks-Plugin %s unterstützt die Optionen -k und -K nicht" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "UID konnte nicht zu Root (%u) geändert werden" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "Plugin-Fehler: Fehlende Dateiliste für sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: Keine reguläre Datei" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: Zu kurzer Schreibvorgang" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s blieb unverändert" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s unverändert" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "%s konnte nicht beschrieben werden" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "Bearbeitungssitzung wurden in %s gelassen" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "Temporäre Datei konnte nicht gelesen werden" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "Kein TTY vorhanden und kein »askpass«-Programm angegeben" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "Kein »askpass«-Programm angegeben, es wird versucht, SUDO_ASKPASS zu setzen" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "GID konnte nicht als %u festgelegt werden" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "UID konnte nicht als %u festgelegt werden" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "%s konnte nicht ausgeführt werden" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "Standardeingabe konnte nicht gespeichert werden" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "dup2 konnte nicht auf die Standardeingabe angewandt werden" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "Standardeingabe konnte nicht wiederhergestellt werden" diff --git a/src/po/eo.mo b/src/po/eo.mo new file mode 100644 index 0000000..06ca5d1 Binary files /dev/null and b/src/po/eo.mo differ diff --git a/src/po/eo.po b/src/po/eo.po new file mode 100644 index 0000000..6e48cf7 --- /dev/null +++ b/src/po/eo.po @@ -0,0 +1,782 @@ +# Esperanto translations for sudo package. +# This file is put in the public domain. +# Keith Bowes , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 18:56-0400\n" +"Last-Translator: Keith Bowes \n" +"Language-Team: Esperanto \n" +"Language: eo\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "ne eblas malfermi la uzanto-datumbazon" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "ne eblas ŝanĝiĝi al registrejo \"%s\" por %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "ne eblas restarigi registrejon" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "ena eraro, provis je emalloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "ne eblas generi memoron" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "ena eraro, provis je emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "ena eraro, emalloc2() superfluo" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "ena eraro, provis je ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "ena eraro, ecalloc() superfluo" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "ena eraro, provis je erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "ena eraro, provis je erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "ena eraro, erealloc3() superfluo" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "ne eblas trovi je %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s estas ne regula dosiero" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s estas estrata de uid %u, devas esti %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s estas skribebla de ĉiuj" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s estas skribebla de la tuta grupo" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "ne eblas malfermi %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Nekonata signalo" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "konduta kromprogramo fiaskis dum seanca komenciĝo" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "ne eblas forki" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "ne eblas krei konektingojn" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "ne eblas krei tubon" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "elekto malsukcesis" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "ne eblis reatingi tty-etikedon" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "ne eblas forigi PRIV_PROC_EXEC-on de PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "ne eblis generi pty-on" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "ne eblas elekti nudan reĝimon ĉe la terminalo" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "ne eblas elekti la regan tty-on" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "eraro dum legi la signalan tubon" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "eraro dum legi el tubo" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "eraro dum legi la konektingan paron" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "neatendita respondotipo ĉe la postkanalo: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s devas esti estrita de uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s estas skribebla nur de estro" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "malebla: dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: ne eblas trovi simbolon %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: nekonata konduta tipo %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: malkongrua konduto, ĉefa eldono %d, atendita %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: nur unu konduta kromprogramo eblas ŝargiĝi" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: almenaŭ unu konduku devas esti specifita" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "konduta kromprogramo %s ne inkluzivas la metodon check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: superfluo malkovrita" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "ne eblas malfermi konektingon" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "la parametro de -C devas esti nombron almenaŭ 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "nekonata uzanto: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "vi ne rajtas specifi kaj '-i' kaj '-s'" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "vi ne rajtas specifi kaj '-i' kaj '-E'" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "la parametro '-E' ne validas en redakta reĝimo" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "vi ne rajtas specifi medivariablojn en redakta reĝimo" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "la parametro '-U' ne validas kun '-l'" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "'-A' kaj '-S' ne eblas uziĝi kune" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit ne estas havebla en ĉi tiu platformon" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Vi rajtas specifi nur unu el -e, -h, -i, -K, -l, -s, -v aŭ -V" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - redakti dosierojn kiel alia uzanto\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - plenumigi komandon kiel alia uzanto\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Parametroj:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "uzi helpoprogrogramon por pasvortilo\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "uzi specifitan BSD-konstatan tipon\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "plenumigi komandon fone\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "fermi ĉiujn dosierpriskribilojn >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "plenumigi komandon per specifitan ensalutan klason\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "konservi uzanto-medivariablojn dum plenumigi komandon\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "redakti dosierojn anstataŭ plenumigi komandon\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "plenumigi komandon kiel la specifitan grupon\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "valorizi medivariablon HOME je la hejma dosierujo de la cela uzanto.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "elmontri helpan mesaĝon kaj eliri\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "plenumigi ensalutan ŝelon kiel celan uzanton\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "tute forigi tempo-indikilan dosieron\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "eksvalidigi tempo-indikilan dosieron\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "listigi disponeblajn komandojn de uzanto\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "neinteraga reĝimo, ne demandos uzanton\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "konservi grupan vektoron anstataŭ elekti celan vektoron\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "uzi specifitan pasvortilon\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "krei SELinux-sekurecan kuntekstan kun specifita rolo\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "legi pasvorton el norma enigo\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "plenumigi ŝelon kiel cela uzanto\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "dum listigo, listigi privilegiojn de specifita uzanto\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "plenumigi komandon (aŭ redakti dosieron) kiel specifita uzanto\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "elmontri eldonan informon kaj eliri\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "ĝisdatigi la tempo-indikilon de la uzanto, sed ne plenumigi komandon\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "ĉesigi procedi komandliniajn parametrojn\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "ne eblas malfermi aŭdan sistemon" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "ne eblas sendi aŭdan mesaĝon" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "ne eblas voki fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s ŝanĝis etikedojn" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "ne eblas restarigi kuntekston por %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "ne eblas malfermi %s, ne remarkanta tty-on" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "ne eblas akiri aktualan tty-kuntekston, ne remarkanta" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "ne eblas akiri novan tty-kuntekston, ne remarkanta" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "ne eblas elekti novan tty-kuntekston" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "vi devas specifi rolon por tipon %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "ne eblas akiri aŭtomatan tipon por rolo %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "malsukcesis elekti novan rolon %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "malsukcesis elekti novan tipon %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s ne estas valida kunteksto" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "malsukcesis je old_context" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "ne povas determini eldevigan reĝimon." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "ne eblas agordi tty-kuntekston por %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "ne eblas elekti exec-kuntekston al %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "ne eblas elekti ŝlosilkrean kuntekston al %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "postulas almenaŭ unu parametron" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "ne eblas plenumigi: %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo: eldono %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Muntaj parametroj: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "ĉesiga eraro: ne eblas ŝargi kromprogramojn" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "ne eblas komenci konduktan kromprogramon" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "eraro dum komenci eneligan kromprogramon %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "neatendita sudo-reĝimon 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "ne eblas elekti grupan vektoron" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "nekonata uid %u: kiu vi estas?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s devas esti estrita de uid %d kaj la setuid-bito devas esti elektita" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "efektiva uid ne estas %d; ĉu %s estas en dosiersistemo kun la elekto 'nosuid' aŭ reta dosiersistemo sen ĉefuzanto-privilegioj?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "efektiva uid ne estas %d; ĉu sudo estas instalita kiel setuid-radiko?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "rimedo-rega limigo estis atingita" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "uzanto \"%s\" ne estas ano de projekto \"%s\"" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "la voka tasko estas nenuligebla" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "ne eblis aliĝi al projekto \"%s\"" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "neniu rimedujo akceptanta aŭtomatajn bindaĵojn ekzistas por projekto \"%s\"" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "specifita rimedujo ne ekzistas por projekto \"%s\"" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "ne eblis bindi al aprioran rimedujo por projekto \"%s\"" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject malsukcesis por projekto \"%s\"" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "averto, rimedo-rega asigno malsukcesis por projekto \"%s\"" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "nekonata ensaluta klaso %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "ne eblas elekti uzanto-kuntekston" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "ne eblas elekti suplementajn grupajn identigilojn" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "ne eblas elekti efikan gid-on al plenumigkiela gid %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "ne eblas elekti gid-on kiel plenumigkielan gid-on %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "ne eblas elekti procezan prioritaton" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "ne eblas ŝanĝi ĉefuzanton al %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "ne eblas ŝanĝi al plenumigkiela uid (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "ne eblas ŝanĝi dosierujon al %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "neatendita ido ekzekutiĝis laŭ la kondiĉo: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "konduta kromprogramo %s ne komprenas listigon de privilegioj" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "konduta kromprogramo %s ne komprenas la parametron -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "konduta kromprogramo %s ne komprenas la parametrojn -k kaj -K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "ne eblas ŝanĝi uid-on al ĉefuzanto (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "kromprograma eraro: malhavas dosieran liston por sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: ne regula dosiero" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: mallonga skribado" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s restas ne modifita" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s ne ŝanĝita" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "ne eblas skribi al %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "enhavo de redakta seanco restas en %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "ne eblas legi provizoran dosieron" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "neniu tty ĉeestas kaj neniu pasvorto-programo specifita" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "neniu pasvorto-programo specifita, provi valorizi SUDO_ASKPASS-on" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "ne eblas elekti gid-on al %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "ne eblas elekti uid-on al %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "ne eblas plenumigi: %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "ne eblas konservi enigon" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "ne eblas kopii al enigo" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "ne eblas restarigi enigon" + +#~ msgid "must be setuid root" +#~ msgstr "devas esti ĉefuzanto setuid" diff --git a/src/po/es.mo b/src/po/es.mo new file mode 100644 index 0000000..53ad62a Binary files /dev/null and b/src/po/es.mo differ diff --git a/src/po/es.po b/src/po/es.po new file mode 100644 index 0000000..49e04ae --- /dev/null +++ b/src/po/es.po @@ -0,0 +1,783 @@ +# traducción al español de sudo. +# This file is distributed under the same license as the sudo package. +# +# Abel Sendon , 2012. +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5-b4\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-03-28 14:06-0400\n" +"PO-Revision-Date: 2012-04-10 16:19-0300\n" +"Last-Translator: Abel Sendon \n" +"Language-Team: Spanish \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Poedit-Language: Spanish\n" +"X-Poedit-Country: ARGENTINA\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:105 src/exec_pty.c:616 src/exec_pty.c:948 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "no se puede bifurcar" + +#: src/exec.c:252 +#, c-format +msgid "unable to create sockets" +msgstr "no se puede crear sockets" + +#: src/exec.c:259 src/exec_pty.c:567 src/exec_pty.c:576 src/exec_pty.c:584 +#: src/exec_pty.c:883 src/exec_pty.c:945 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "no se puede crear tubería" + +#: src/exec.c:340 src/exec_pty.c:1011 src/exec_pty.c:1146 +#, c-format +msgid "select failed" +msgstr "selección fallida" + +#: src/exec.c:425 +#, c-format +msgid "unable to restore tty label" +msgstr "no se puede restaurar la etiqueta tty" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "no se puede remover PRIV_PROC_EXEC desde PRIV_LIMIT" + +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:447 src/sudo.c:467 +#: src/sudo.c:474 src/sudo.c:485 src/sudo.c:871 common/alloc.c:85 +#: common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 common/alloc.c:168 +#: common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#, c-format +msgid "unable to allocate memory" +msgstr "no se puede de asignar memoria" + +#: src/exec_pty.c:140 +#, c-format +msgid "unable to allocate pty" +msgstr "no se puede asignar pty" + +#: src/exec_pty.c:609 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "no se puede establecer la terminal en modo directo" + +#: src/exec_pty.c:926 +#, c-format +msgid "unable to set controlling tty" +msgstr "no se puede establecer el controlador tty" + +#: src/exec_pty.c:1019 +#, c-format +msgid "error reading from signal pipe" +msgstr "error al leer desde la tubería de la señal" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from pipe" +msgstr "error al leer de la tubería" + +#: src/exec_pty.c:1054 +#, c-format +msgid "error reading from socketpair" +msgstr "error leyendo de socketpair" + +#: src/exec_pty.c:1058 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "tipo de respuesta inesperada en canales alternos %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s debe ser propiedad del uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s sólo tener permisos de escritura por el propietario" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "no se puede dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: no se puede de encontrar el símbolo %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: tipo de política desconocida %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: incompatible la versión principal de la política %d, se esperaba %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: se puede cargar sólo una política de plugin" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: debe ser especificada al menos una política de plugin" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "la política del plugin %s no incluye un método check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: desbordamiento detectado" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "no se puede de abrir socket" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "el argumento -C debe ser un número mayor o igual a 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "usuario desconocido: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "no se deben especificar las opciones '-i' y '-s' simultáneamente" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "no se deben especificar las opciones '-i' y '-E' simultáneamente" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "la opción '-E' no es válida en el modo edición" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "no se debe especificar variables de entorno en el modo edición" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "la opción '-U' sólo se puede usar con la opcion '-l'" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "las opciones '-A' y '-S' no se pueden utilizar conjuntamente" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit no está soportado en ésta plataforma" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "puede ser especificada sólo una de las opciones -e, -h, -i, -K, -l, -s, -v o -V" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - edita archivos como otro usuario\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - ejecuta un comando como otro usuario\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Opciones:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "utilizar el programa de ayuda para la solicitud de contraseña\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "utiliza tipo de autentificación especificado en BSD\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "ejecuta un comando en segundo plano\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "cierra todos los descriptores de archivo >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "ejecuta un comando con la clase especificada de inicio de sesión\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "preserva entorno del usuario cuando está ejecutando un comando\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "edita archivos en vez de ejecutar un comando\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "ejecuta un comando como el grupo especificado\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "asigna la variable HOME al directorio de inicio del usuario\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "muestra este mensaje de ayuda y sale\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "ejecuta un intérprete de comandos como un determinado usuario\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "remueve un archivo de marca completamente\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "archivo de marca inválido\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "lista los comandos del usuario disponibles\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "modo no-interactivo, no se pedirá usuario\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "preserva el vector de grupos en vez de establecer de objetivo\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "usa la contraseña especificada\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "crea el contexto de seguridad SELinux con la regla especificada\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "lee la contraseña desde la entrada estandar\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "ejecuta un intérprete de comandos como un determinado usuario\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "cuando está listando, lista los privilegios del usuario especificado\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "ejecuta un comando (o edita un archivo) como un usuario específico\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "muestra la información de la versión y sale\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "actualiza la marca del usuario sin ejecutar un comando\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "detiene el proceso de argumentos de la línea de comandos\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "no se puede de abrir el sistema de auditoría" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "no se puede enviar mensaje de auditoría" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "no se puede fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s etiquetas cambiadas" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "no se puede restaurar el contexto para %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "no se puede abrir %s, no volver a etiquetar tty" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "no se puede obtener el actual contexto tty, no volver a etiquetar tty" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "no se puede obtener el nuevo contexto tty, no volver a etiquetar tty" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "no se puede establecer nuevo contexto tty" + +#: src/selinux.c:196 src/selinux.c:209 src/sudo.c:333 common/sudo_conf.c:328 +#, c-format +msgid "unable to open %s" +msgstr "no se pudo abrir %s" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "se debe especificar una regla por tipo %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "no se puede obtener el tipo de regla predeterminada %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "falló al establecer nueva regla %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "falló al establecer nuevo tipo %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s no es un contexto válido" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "falló al obtener old_context" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "no se puede determinar el método de forzado" + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "no se puede establecer el contexto tty para %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "no se puede establecer el contexto de ejecución a %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "no se puede establecer la clave de creación de contexto a %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "requiere al menos un argumento" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "no se puede ejecutar %s" + +#: src/sudo.c:213 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo versión %s\n" + +#: src/sudo.c:215 +#, c-format +msgid "Configure options: %s\n" +msgstr "Opciones de configuración: %s\n" + +#: src/sudo.c:220 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "error fatal, no se puede cargar los plugins" + +#: src/sudo.c:228 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "no se puede inicializar la política de plugin" + +#: src/sudo.c:283 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "error al inicializar los plugins de E/S %s" + +#: src/sudo.c:308 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "inesperado modo sudo 0x%x" + +#: src/sudo.c:402 +#, c-format +msgid "unable to get group vector" +msgstr "no se puede obtener el vector de grupo" + +#: src/sudo.c:443 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "uid desconocido %u: quién es usted?" + +#: src/sudo.c:735 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s debe ser propiedad del uid %d y tener el bit setuid establecido" + +#: src/sudo.c:738 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "el uid no es %d, es %s en un sistema de archivos con la opción 'nosuid' establecida o un sistema de archivos NFS sin privilegios de root?" + +#: src/sudo.c:744 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "el uid efectivo no es %d, sudo está instalado con setuid root?" + +#: src/sudo.c:813 +#, c-format +msgid "resource control limit has been reached" +msgstr "el límite de control de recursos ha sido alcanzado" + +#: src/sudo.c:816 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "el usuario \"%s\" no es miembro del proyecto \"%s\"" + +#: src/sudo.c:820 +#, c-format +msgid "the invoking task is final" +msgstr "la tarea que invoca es definitiva" + +#: src/sudo.c:823 +#, c-format +msgid "could not join project \"%s\"" +msgstr "no podría unirse al proyecto \"%s\"" + +#: src/sudo.c:828 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "no hay fondo de recursos aceptando las asignaciones existentes para el proyecto \"%s\"" + +#: src/sudo.c:832 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "el fondo de recursos especificado no existe para el proyecto \"%s\"" + +#: src/sudo.c:836 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "no se podría enlazar al fondo de recursos predeterminado para el proyecto \"%s\" " + +#: src/sudo.c:842 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "configuración del proyecto fallida \"%s\" " + +#: src/sudo.c:844 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "aviso, el control de asignación de recursos falló para el proyecto \"%s\"" + +#: src/sudo.c:909 +#, c-format +msgid "unknown login class %s" +msgstr "clase de inicio de sesión desconocida %s" + +#: src/sudo.c:923 src/sudo.c:926 +#, c-format +msgid "unable to set user context" +msgstr "no se puede establecer el contexto del usuario" + +#: src/sudo.c:938 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "no se puede establecer el grupo suplementario de IDs" + +#: src/sudo.c:945 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "no se puede establecer el gid efectivo para ejecutar como gid %u" + +#: src/sudo.c:951 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "no se puede establecer el gid para ejecutar como gid %u" + +#: src/sudo.c:958 +#, c-format +msgid "unable to set process priority" +msgstr "no se puede establecer la prioridad de proceso" + +#: src/sudo.c:966 +#, c-format +msgid "unable to change root to %s" +msgstr "no se puede cambiar de root a %s" + +#: src/sudo.c:973 src/sudo.c:979 src/sudo.c:985 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "no se puede cambiar a runas uid (%u, %u)" + +#: src/sudo.c:999 +#, c-format +msgid "unable to change directory to %s" +msgstr "no se puede cambiar al directorio %s" + +#: src/sudo.c:1072 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "inesperada terminación de condición hija: %d" + +#: src/sudo.c:1133 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "la política del plugin %s no soporta listado de privilegios" + +#: src/sudo.c:1145 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "la política del plugin %s no soporta la opción -v" + +#: src/sudo.c:1157 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "la política del plugin %s no soporta las opciones -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "no se puede cambiar uid a root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "error de plugin: falta la lista de archivos para sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: no es un archivo regular" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: escritura corta" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s sin modificar" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s sin cambios" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "no se puede escribir en %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "los contenidos de edición de sesión se dejan en %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "no se puede leer el archivo temporal" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "sin tty presente y no hay programa askpass especificado" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "no hay programa askpass especificado, intente establecer SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "no se puede establecer el gid a %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "no se puede establecer el uid a %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "no se puede ejecutar %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "no se puede guardar stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "no se puede hacer dup2 stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "no se puede restaurar stdin" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "no se puede abrir userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "no se puede cambiar al registro \"%s\" para %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "no se puede restaurar el registro" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "error interno: trató emalloc(0)" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "error interno: trató emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "error interno: desbordamiento en emalloc2()" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "error interno: trató ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "error interno: desbordamiento en ealloc()" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "error interno: trató erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "error interno: trató erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "error interno: desbordamiento de erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "no se puede stat en %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s no es un archivo regular" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s es adueñado por uid %u, sería %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s es escribible por todos" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s es escribible por el grupo" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Señal desconocida" + +#~ msgid "must be setuid root" +#~ msgstr "debe ser setuid root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "el argumento -D debe estar entre 1 y 9 inclusive" diff --git a/src/po/eu.mo b/src/po/eu.mo new file mode 100644 index 0000000..ea726d4 Binary files /dev/null and b/src/po/eu.mo differ diff --git a/src/po/eu.po b/src/po/eu.po new file mode 100644 index 0000000..5702274 --- /dev/null +++ b/src/po/eu.po @@ -0,0 +1,741 @@ +# Basque translation of sudo. +# Copyright (C) 2011 Free Software Foundation, Inc. +# This file is distributed under the same license as the sudo package. +# Mikel Olasagasti Uranga , 2011. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.2rc2\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2011-06-04 18:27-0400\n" +"PO-Revision-Date: 2011-06-06 18:28+0100\n" +"Last-Translator: Mikel Olasagasti Uranga \n" +"Language-Team: Basque \n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ":" + +#: src/exec.c:125 src/exec_pty.c:573 src/exec_pty.c:880 src/tgetpass.c:224 +#, c-format +msgid "unable to fork" +msgstr "ezin da fork egin" + +#: src/exec.c:246 +#, c-format +msgid "unable to create sockets" +msgstr "ezin da socketik sortu" + +#: src/exec.c:253 src/exec_pty.c:526 src/exec_pty.c:534 src/exec_pty.c:541 +#: src/exec_pty.c:826 src/exec_pty.c:877 src/tgetpass.c:221 +#, c-format +msgid "unable to create pipe" +msgstr "ezin da pipe bat sortu" + +#: src/exec.c:319 src/exec_pty.c:944 src/exec_pty.c:1077 +#, c-format +msgid "select failed" +msgstr "select-ek huts egin du" + +#: src/exec.c:387 +#, c-format +msgid "unable to restore tty label" +msgstr "" + +#: src/exec_pty.c:136 +#, c-format +msgid "unable to allocate pty" +msgstr "" + +#: src/exec_pty.c:566 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "" + +#: src/exec_pty.c:858 +#, c-format +msgid "unable to set controlling tty" +msgstr "" + +#: src/exec_pty.c:952 +#, c-format +msgid "error reading from signal pipe" +msgstr "errorea seinale hoditik irakurtzean" + +#: src/exec_pty.c:971 +#, c-format +msgid "error reading from pipe" +msgstr "errorea hoditik irakurtzean" + +#: src/exec_pty.c:987 +#, c-format +msgid "error reading from socketpair" +msgstr "errorea socketpair-etik irakurtzean" + +#: src/exec_pty.c:991 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "espero ez zen erantzun moeta backchannel-ean: %d" + +#: src/load_plugins.c:154 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:160 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:170 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s-(r)en jabeak %d uid-a behar du" + +#: src/load_plugins.c:174 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s jabeak bakarrik idazteko moduan behar du" + +#: src/load_plugins.c:181 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "ezin da %s-(r)engan dlopen egin: %s" + +#: src/load_plugins.c:186 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: ezin da %s sinboloa aurkitu" + +#: src/load_plugins.c:192 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: %d arau moeta ezezaguna" + +#: src/load_plugins.c:196 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "" + +#: src/load_plugins.c:203 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "" + +#: src/load_plugins.c:221 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "" + +#: src/load_plugins.c:226 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "" + +#: src/net_ifs.c:155 src/net_ifs.c:164 src/net_ifs.c:176 src/net_ifs.c:185 +#: src/net_ifs.c:295 src/net_ifs.c:319 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: overflow-a atzeman da" + +#: src/net_ifs.c:224 +#, c-format +msgid "unable to open socket" +msgstr "ezin da socket-a ireki" + +#: src/parse_args.c:180 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "-C argumentuak 3 edo zenbaki altuagoa behar du" + +#: src/parse_args.c:192 +#, c-format +msgid "the argument to -D must be between 1 and 9 inclusive" +msgstr "-D argumentua 1 eta 9 bitartean behar du, biak barne" + +#: src/parse_args.c:273 +#, c-format +msgid "unknown user: %s" +msgstr "erabiltzaile ezezaguna: %s" + +#: src/parse_args.c:332 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "ez zenituzke `-i' eta `-s' aukerak batera erabili behar" + +#: src/parse_args.c:336 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "ez zenitzuke `-i' eta `-E' aukerak batera erabili behar" + +#: src/parse_args.c:346 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "`-E' aukera ez da onartzen edizio moduan" + +#: src/parse_args.c:348 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "ez zenuke ingurune aldagairik zehaztu beharko edizio moduan" + +#: src/parse_args.c:356 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "`-U' aukera `-l' aukerarekin erabili beharko zenuke soilik" + +#: src/parse_args.c:360 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "`-A' eta `-S' aukerak ez lirateke batera erabili beharko" + +#: src/parse_args.c:418 src/sudo.c:398 src/sudo.c:418 src/sudo.c:426 +#: src/sudo.c:436 common/alloc.c:85 common/alloc.c:105 common/alloc.c:123 +#: common/alloc.c:145 common/alloc.c:203 common/alloc.c:217 +#, c-format +msgid "unable to allocate memory" +msgstr "ezin da memoria esleitu" + +#: src/parse_args.c:431 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit-ek ez du euskarririk plataforma hontan" + +#: src/parse_args.c:502 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Soilik -e, -h, -i, -K, -l, -s, -v edo -V aukeretako bat definitu beharko litzateke" + +#: src/parse_args.c:515 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - editatu fitxategia beste erabiltzaile bat bezala\n" +"\n" + +#: src/parse_args.c:517 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - exekutatu komandu bat beste erabiltzaile bat bezala\n" +"\n" + +#: src/parse_args.c:522 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Aukerak:\n" + +#: src/parse_args.c:525 +msgid "use helper program for password prompting\n" +msgstr "" + +#: src/parse_args.c:528 +msgid "use specified BSD authentication type\n" +msgstr "" + +#: src/parse_args.c:530 +msgid "run command in the background\n" +msgstr "" + +#: src/parse_args.c:532 +msgid "close all file descriptors >= fd\n" +msgstr "" + +#: src/parse_args.c:535 +msgid "run command with specified login class\n" +msgstr "" + +#: src/parse_args.c:538 +msgid "preserve user environment when executing command\n" +msgstr "" + +#: src/parse_args.c:540 +msgid "edit files instead of running a command\n" +msgstr "" + +#: src/parse_args.c:542 +msgid "execute command as the specified group\n" +msgstr "" + +#: src/parse_args.c:544 +msgid "set HOME variable to target user's home dir.\n" +msgstr "" + +#: src/parse_args.c:546 +msgid "display help message and exit\n" +msgstr "laguntza mezua erakutsi eta irten\n" + +#: src/parse_args.c:548 +msgid "run a login shell as target user\n" +msgstr "abiarazi login shell bat helburua den erabiltzaile moduan\n" + +#: src/parse_args.c:550 +msgid "remove timestamp file completely\n" +msgstr "ezabatu guztiz data-zigilu fitxategia\n" + +#: src/parse_args.c:552 +msgid "invalidate timestamp file\n" +msgstr "baliogabetu data-zigilu fitxategia\n" + +#: src/parse_args.c:554 +msgid "list user's available commands\n" +msgstr "zerrendatu erabiltzaileak eskuragarri dituen komandoak\n" + +#: src/parse_args.c:556 +msgid "non-interactive mode, will not prompt user\n" +msgstr "" + +#: src/parse_args.c:558 +msgid "preserve group vector instead of setting to target's\n" +msgstr "" + +#: src/parse_args.c:560 +msgid "use specified password prompt\n" +msgstr "" + +#: src/parse_args.c:563 src/parse_args.c:571 +msgid "create SELinux security context with specified role\n" +msgstr "" + +#: src/parse_args.c:566 +msgid "read password from standard input\n" +msgstr "" + +#: src/parse_args.c:568 +msgid "run a shell as target user\n" +msgstr "" + +#: src/parse_args.c:574 +msgid "when listing, list specified user's privileges\n" +msgstr "" + +#: src/parse_args.c:576 +msgid "run command (or edit file) as specified user\n" +msgstr "" + +#: src/parse_args.c:578 +msgid "display version information and exit\n" +msgstr "" + +#: src/parse_args.c:580 +msgid "update user's timestamp without running a command\n" +msgstr "" + +#: src/parse_args.c:582 +msgid "stop processing command line arguments\n" +msgstr "" + +#: src/selinux.c:75 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: src/selinux.c:112 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "ezin da %s-(r)engan fgetfilecon egin" + +#: src/selinux.c:117 +#, c-format +msgid "%s changed labels" +msgstr "" + +#: src/selinux.c:122 +#, c-format +msgid "unable to restore context for %s" +msgstr "" + +#: src/selinux.c:161 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "" + +#: src/selinux.c:170 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "" + +#: src/selinux.c:177 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "" + +#: src/selinux.c:184 +#, c-format +msgid "unable to set new tty context" +msgstr "" + +#: src/selinux.c:194 src/selinux.c:207 src/sudo.c:330 +#, c-format +msgid "unable to open %s" +msgstr "" + +#: src/selinux.c:249 +#, c-format +msgid "you must specify a role for type %s" +msgstr "" + +#: src/selinux.c:255 +#, c-format +msgid "unable to get default type for role %s" +msgstr "" + +#: src/selinux.c:273 +#, c-format +msgid "failed to set new role %s" +msgstr "" + +#: src/selinux.c:277 +#, c-format +msgid "failed to set new type %s" +msgstr "" + +#: src/selinux.c:286 +#, c-format +msgid "%s is not a valid context" +msgstr "" + +#: src/selinux.c:320 +#, c-format +msgid "failed to get old_context" +msgstr "" + +#: src/selinux.c:326 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "" + +#: src/selinux.c:338 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "" + +#: src/selinux.c:367 +#, c-format +msgid "unable to set exec context to %s" +msgstr "" + +#: src/selinux.c:374 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "" + +#: src/sesh.c:48 +msgid "requires at least one argument" +msgstr "gutxienez argumentu bat behar du" + +#: src/sesh.c:64 +#, c-format +msgid "unable to execute %s" +msgstr "ezin da %s exekutatu" + +#: src/sudo.c:192 +#, c-format +msgid "must be setuid root" +msgstr "root setuid-a behar du" + +#: src/sudo.c:210 +#, c-format +msgid "Sudo version %s\n" +msgstr "%s sudo bertsioa\n" + +#: src/sudo.c:212 +#, c-format +msgid "Configure options: %s\n" +msgstr "Konfigurazio aukerak: %s\n" + +#: src/sudo.c:217 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "errore larria, ezin dira gehigarriak gehitu" + +#: src/sudo.c:225 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "" + +#: src/sudo.c:280 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "errorea %s I/O plugina abiaraztean" + +#: src/sudo.c:307 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "" + +#: src/sudo.c:356 +#, c-format +msgid "unable to get group vector" +msgstr "" + +#: src/sudo.c:394 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "" + +#: src/sudo.c:734 +#, c-format +msgid "resource control limit has been reached" +msgstr "" + +#: src/sudo.c:737 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "" + +#: src/sudo.c:741 +#, c-format +msgid "the invoking task is final" +msgstr "" + +#: src/sudo.c:744 +#, c-format +msgid "could not join project \"%s\"" +msgstr "ezin izan da \"%s\" proiektura batu" + +#: src/sudo.c:749 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "" + +#: src/sudo.c:753 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "" + +#: src/sudo.c:757 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "" + +#: src/sudo.c:763 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject-ek huts egin du \"%s\" proiektuarentzat" + +#: src/sudo.c:765 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "" + +#: src/sudo.c:791 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "" + +#: src/sudo.c:895 +#, c-format +msgid "unknown login class %s" +msgstr "" + +#: src/sudo.c:902 src/sudo.c:905 +#, c-format +msgid "unable to set user context" +msgstr "" + +#: src/sudo.c:916 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "" + +#: src/sudo.c:921 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "" + +#: src/sudo.c:929 src/sudo.c:935 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "" + +#: src/sudo.c:943 +#, c-format +msgid "unable to set process priority" +msgstr "" + +#: src/sudo.c:951 +#, c-format +msgid "unable to change root to %s" +msgstr "" + +#: src/sudo.c:961 src/sudo.c:967 src/sudo.c:973 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "" + +#: src/sudo.c:987 +#, c-format +msgid "unable to change directory to %s" +msgstr "" + +#: src/sudo.c:1078 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "" + +#: src/sudo.c:1118 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "" + +#: src/sudo.c:1129 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "" + +#: src/sudo_edit.c:108 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "ezin da uid-a root-era aldatu (%u)" + +#: src/sudo_edit.c:140 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "" + +#: src/sudo_edit.c:172 src/sudo_edit.c:280 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: ez da fitxategi normala" + +#: src/sudo_edit.c:206 src/sudo_edit.c:316 +#, c-format +msgid "%s: short write" +msgstr "" + +#: src/sudo_edit.c:281 +#, c-format +msgid "%s left unmodified" +msgstr "" + +#: src/sudo_edit.c:294 +#, c-format +msgid "%s unchanged" +msgstr "%s aldatugabea" + +#: src/sudo_edit.c:306 src/sudo_edit.c:327 +#, c-format +msgid "unable to write to %s" +msgstr "ezin da %s-(e)ra idatzi" + +#: src/sudo_edit.c:307 src/sudo_edit.c:325 src/sudo_edit.c:328 +#, c-format +msgid "contents of edit session left in %s" +msgstr "" + +#: src/sudo_edit.c:324 +#, c-format +msgid "unable to read temporary file" +msgstr "ezin da aldi baterako fitxategia irakurri" + +#: src/tgetpass.c:95 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "ez dago tty-rik eta askpass aplikazioa zehaztu gabe" + +#: src/tgetpass.c:104 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "ez da askpass aplikaziorik zehaztu, saiatu SUDO_ASKPASS ezartzen" + +#: src/tgetpass.c:234 +#, c-format +msgid "unable to set gid to %u" +msgstr "ezin da %u gid-a ezarri" + +#: src/tgetpass.c:238 +#, c-format +msgid "unable to set uid to %u" +msgstr "ezin da %u uid-a ezarri" + +#: src/tgetpass.c:243 +#, c-format +msgid "unable to run %s" +msgstr "ezin da %s exekutatu" + +#: src/utmp.c:263 +#, c-format +msgid "unable to save stdin" +msgstr "ezin da stdin-era gorde" + +#: src/utmp.c:265 +#, c-format +msgid "unable to dup2 stdin" +msgstr "ezin da stdin-era dup2 egin" + +#: src/utmp.c:268 +#, c-format +msgid "unable to restore stdin" +msgstr "ezin da stdin-era leheneratu" + +#: common/aix.c:144 +#, c-format +msgid "unable to open userdb" +msgstr "ezin da userdb-a ireki" + +#: common/aix.c:147 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "ezin da \"%s\" erregistrora aldatu %s-(r)entzat" + +#: common/aix.c:161 +#, c-format +msgid "unable to restore registry" +msgstr "ezin da erregistroa leheneratu" + +#: common/alloc.c:82 +#, c-format +msgid "internal error, tried to emalloc(0)" +msgstr "barne errorea, emalloc(0) egiteko saiakera egon da" + +#: common/alloc.c:99 +#, c-format +msgid "internal error, tried to emalloc2(0)" +msgstr "barne errorea, emalloc2(0) egiteko saiakera egon da" + +#: common/alloc.c:101 +#, c-format +msgid "internal error, emalloc2() overflow" +msgstr "barne errorea, emalloc2() overflow-a" + +#: common/alloc.c:119 +#, c-format +msgid "internal error, tried to erealloc(0)" +msgstr "barne errorea, erealloc(0) egiteko saiakera egon da" + +#: common/alloc.c:138 +#, c-format +msgid "internal error, tried to erealloc3(0)" +msgstr "barne errorea, erealloc3(0) egiteko saiakera egon da" + +#: common/alloc.c:140 +#, c-format +msgid "internal error, erealloc3() overflow" +msgstr "barne errorea, erealloc3(0) overflow-a" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Seinale ezezaguna" diff --git a/src/po/fi.mo b/src/po/fi.mo new file mode 100644 index 0000000..7dcfa22 Binary files /dev/null and b/src/po/fi.mo differ diff --git a/src/po/fi.po b/src/po/fi.po new file mode 100644 index 0000000..56da933 --- /dev/null +++ b/src/po/fi.po @@ -0,0 +1,796 @@ +# Finnish messages for sudo. +# This file is put in the public domain. +# Copyright © 2011, 2012 Free Software Foundation, Inc. +# This file is distributed under the same license as the sudo package. +# Jorma Karvonen , 2011-2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 11:02+0200\n" +"Last-Translator: Jorma Karvonen \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "ei kyetä avaamaan userdb-käyttäjätietokantaa" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "ei kyetä vaihtamaan registeriä ”%s” käyttäjälle %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "ei kyetä palauttamaan rekisteriä" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "sisäinen virhe, yritettiin suorittaa emalloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "ei kyetä varaamaan muistia" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "sisäinen virhe, yritettiin suorittaa emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "sisäinen virhe, emalloc2() -ylivuoto" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "sisäinen virhe, yritettiin suorittaa ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "sisäinen virhe, ecalloc() -ylivuoto" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "sisäinen virhe, yritettiin suorittaa erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "sisäinen virhe, yritettiin suorittaa erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "sisäinen virhe, erealloc3() -ylivuoto" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "ei kyetä suorittamaan käskyä stat %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s ei ole tavallinen tiedosto" + +# ensimmäinen parametri on path +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "polun %s omistaja on %u, pitäisi olla %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s on yleiskirjoitettava" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s on ryhmäkirjoitettava" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "ei kyetä avaamaan kohdetta %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Tuntematon signaali" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "Menettelytapalisäosa epäonnistui istunnon alustamisessa" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "ei kyetä kutsumaan fork-kutsua" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "ei kyetä luomaan pistokkeita" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "ei kyetä luomaan putkea" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "select-funktio epäonnistui" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "ei kyetä palauttamaan tty-nimiötä" + +# Solaris privileges, remove PRIV_PROC_EXEC post-execve. +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "ei kyetä poistamaan PRIV_PROC_EXEC kohteesta PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "ei kyetä varaamaan pty:tä" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "ei kyetä asettamaan päätettä raakatilaan" + +# Istunnolla voi olla ohjaava tty. Istunnon yksi prosessiryhmä voi olla edustaprosessiryhmä ja toimia siten ohjaavana tty:nä, joka vastaanottaa tty-syötteen ja -signaalit. +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "ei kyetä asettamaan ohjaavaa tty:tä" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "virhe luettaessa signaaliputkesta" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "virhe luettaessa putkesta" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "virhe luettaessa pistokeparista" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "odottamaton vastaustyyppi paluukanavalla: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +# ensimmäinen parametri on path +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "polun %s omistajan on oltava uid %d" + +# parametri on path +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "polun %s on oltava vain omistajan kirjoitettava" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "lisäosan avaaminen epäonnistui funktiolla dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: ei kyetä löytämään symbolia %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: tuntematon menettelytapatyyppi %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: yhteensopimaton menettelytavan major-versio %d, odotettiin %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: vain yksi menettelytapalisäosa voidaan ladata" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: vähintään yksi menettelytapalisäosa on määriteltävä" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "menettelytapalisäosa %s ei sisällä check_policy-metodia" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: ylivuoto havaittu" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "ei kyetä avaamaan pistoketta" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "valitsimen -C argumentin on oltava vähintään 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "tuntematon käyttäjä: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "et voi määritellä sekä valitsinta ”-i” että valitsinta ”-s”" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "et voi määritellä sekä valitsinta ”-i” että valitsinta ”-E”" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "valitsin ”-E” ei ole kelvollinen muokkaustilassa" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "ei voi määritellä ympäristömuuttujia muokkaustilassa" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "valitsinta ”-U” voidaan käyttää vain valitsimen ”-l” kanssa" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "valitsimia ”-A” ja ”-S” ei voi käyttää yhdessä" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit ei ole tuettu tällä alustalla" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Vain yksi valitsimista -e, -h, -i, -K, -l, -s, -v tai -V voidaan määritellä" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - muokkaa tiedostoja toisena käyttäjänä\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - suorita komentoja toisena käyttäjänä\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Valitsimet:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "käytä apuohjelmaa salasanakyselyyn\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "käytä määriteltyä BSD-todennustyyppiä\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "suorita komento taustalla\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "sulje kaikki tiedostokuvaajat >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "suorita komento määritellyllä kirjautumisluokalla\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "säilytä käyttäjäympäristö komentoa suoritettaessa\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "muokkaa tiedostoja komennon suorittamisen sijasta\n" + +# tämä viittaa runas_group-määritelyyn +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "suorita komento määriteltynä ryhmänä\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "aseta HOME-muuttuja osoittamaan kohdekäyttäjän kotihakemistoon.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "näytä opasteviesti ja poistu\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "suorita kirjautumiskomentoikkuna kohdekäyttäjänä\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "poista aikaleimatiedosto kokonaan\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "mitätöi aikaleimatiedosto\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "luettele käyttäjän käytettävissä olevat komennot\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "ei-interaktiivinen tila, ei kysy käyttäjältä\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "säilytä ryhmävektori kohteen vektorin asettamisen sijasta\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "käytä määriteltyä salasanakehotetta\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "luo SELinux-turva-asiayhteys määritellyllä roolilla\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "lue salasana vakiosyötteestä\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "suorita komentotulkki kohdekäyttäjänä\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "luetteloitaessa luettele määritellyn käyttäjän käyttöoikeudet\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "suorita komento (tai muokkaa tiedostoa) määriteltynä käyttäjänä\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "näytä versiotiedot ja poistu\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "päivitä käyttäjän aikaleima suorittamatta komentoa\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "lopeta komentoriviargumenttien käsittely\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "ei kyetä avaamaan audit-järjestelmää" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "ei kyetä lähettämään audit-viestiä" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "ei kyetä kutsumaan funktiota fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s muutti nimiöitä" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "ei kyetä palauttamaan asiayhteyttä kohteelle %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "ei kyetä avaamaan kohdetta %s, ei nimiöidä uudelleen tty:tä" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "ei kyetä hakemaan nykyistä tty-asiayhteyttä, ei nimiöidä uudelleen tty:tä" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "ei kyetä hakemaan uutta tty-asiayhteyttä, ei nimiöidä uudelleen tty:tä" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "ei kyetä asettamaan uutta tty-asiayhteyttä" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "tyypille %s on määriteltävä rooli" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "roolille %s ei kyetä hakemaan oletustyyppiä" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "uuden roolin %s asettaminen epäonnistui" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "uuden tyypin %s asettaminen epäonnistui" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s ei ole kelvollinen asiayhteys" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "kohteen old_context hakeminen epäonnistui" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "ei kyetä määrittelemään vahvistustilaa." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "ei kyetä asettamaan tty-asiayhteydeksi %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "ei kyetä asettamaan suoritusasiayhteydeksi %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "ei kyetä asettamaan avaimenluontiasiayhteydeksi %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "vaatii vähintään yhden argumentin" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "ei kyetä suorittamaan kohdetta %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo-versio %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Asetusvalitsimet: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "kohtalokas virhe, ei kyetä lataamaan lisäosia" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "ei kyetä alustamaan menettelytapalisäosaa" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "virhe alustettaessa siirräntälisäosaa %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "odottamaton sudo-tila 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "ei kyetä hakemaan ryhmävektoria" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "tuntematon uid-käyttäjätunniste %u: kuka olet?" + +# ensimmäinen parametri on path +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "polun %s omistajan on oltava uid %d ja setuid-bitin on oltava asetettu" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "todellinen käyttäjätunniste ei ole %d, onko %s asetettu tiedostojärjestelmässä, jossa on ’nosuid’-valitsin vai onko tämä NFS-tiedostojärjestelmä ilman root-käyttäjäoikeuksia?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "todellinen käyttäjätunniste ei ole %d, onko sudo asennettu setuid root -käyttöoikeuksilla?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "resurssivalvontaraja saavutettu" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "käyttäjä ”%s” ei ole hankkeen ”%s” jäsen" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "kutsuttu tehtävä on final-tyyppinen" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "ei voitu liittyä hankkeeseen ”%s”" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "hankkeelle ”%s” ei ole oletusyhteydet hyväksyvää resurssivarantoa" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "hankkeelle ”%s” ei ole määriteltyä resurssivarantoa" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "hankkeelle ”%s” ei voitu sitoa oletusresurssivarantoa" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject hankkeelle ”%s” epäonnistui" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "varoitus, hankkeen ”%s” resurssiohjausosoitus epäonnistui" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "tuntematon kirjautumisluokka %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "ei kyetä asettamaan käyttäjäasiayhteyttä" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "ei kyetä asettamaan lisäryhmätunnisteita" + +# tämän ymmärrän niin, että käyttäjärjestelmäydin luo tiedoston ja antaa tälle tavallaan tilapäisen effective gid-tunnisteen, joka vaihdetaan suorittamisen yhteydessä prosessin omistajan suoritettavaksi ryhmätunnisteeksi. +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "ei kyetä asettamaan voimassaolevaa gid-ryhmätunnistetta suoritettavaksi gid-ryhmätunnisteeksi %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "ei kyetä asettamaan gid-ryhmätunnistetta suoritettavaksi gid-ryhmätunnisteeksi %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "ei kyetä asettamaan prosessiprioriteettia" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "ei kyetä vaihtamaan root-käyttäjää käyttäjäksi %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "ei kyetä vaihtamaan suoritettavaksi uid-käyttäjätunnisteeksi (%u, %u)" + +# parametrina on CWD- eli Change Working Directory- komennolla palautettava hakemisto +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "ei kyetä vaihtamaan hakemistoksi %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "lapsiprosessin odottamaton päättymisehto: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "menettelytapalisäosa %s ei tue luettelointikäyttöoikeuksia" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "menettelytapalisäosa %s ei tue valitsinta -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "menettelytapalisäosa %s ei tue valitsimia -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "ei kyetä vaihtamaan uid-käyttäjätunnistetta root-tunnisteeksi (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "lisäosavirhe: puuttuu sudoedit-tiedostoluettelo" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: ei ole tavallinen tiedosto" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: lyhyt kirjoitus" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s jätetty muokkaamattomaksi" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s muuttamaton" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "ei kyetä kirjoittamaan kohteeseen %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "muokkausistunnon sisältö jätetty kohteessa %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "ei kyetä lukemaan tilapäistä tiedostoa" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "ei tty:tä käytettävissä eikä salasanan kyselyohjelmaa määriteltynä" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "salasanan kyselyohjelma ei ole määritelty, yritä asettaa SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "ei kyetä asettamaan gid-ryhmätunnisteeksi %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "ei kyetä asettamaan uid-käyttäjätunnisteeksi %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "ei kyetä suorittamaan salasanakyselyä %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "ei kyetä tallentamaan vakiosyötettä" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "ei kyetä kutsumaan funktiota dup2 vakiosyötteellä" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "ei kyetä palauttamaan vakiosyötettä" + +#~ msgid "must be setuid root" +#~ msgstr "on oltava setuid root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "valitsimen -D argumentin on oltava alueella 1 - 9" diff --git a/src/po/gl.mo b/src/po/gl.mo new file mode 100644 index 0000000..96245d8 Binary files /dev/null and b/src/po/gl.mo differ diff --git a/src/po/gl.po b/src/po/gl.po new file mode 100644 index 0000000..ae2a8c3 --- /dev/null +++ b/src/po/gl.po @@ -0,0 +1,730 @@ +# Galician translations for sudo package. +# This file is put in the public domain. +# Fran Dieguez , 2012. +# Francisco Diéguez , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.4b1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-01-06 15:10-0500\n" +"PO-Revision-Date: 2012-02-07 22:35+0100\n" +"Last-Translator: Francisco Diéguez \n" +"Language-Team: Galician \n" +"Language: gl_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:133 src/exec_pty.c:604 src/exec_pty.c:936 src/tgetpass.c:227 +#, c-format +msgid "unable to fork" +msgstr "non se pode bifurcar" + +#: src/exec.c:299 +#, c-format +msgid "unable to create sockets" +msgstr "non foi posíbel crear sockets" + +#: src/exec.c:306 src/exec_pty.c:557 src/exec_pty.c:565 src/exec_pty.c:572 +#: src/exec_pty.c:871 src/exec_pty.c:933 src/tgetpass.c:224 +#, c-format +msgid "unable to create pipe" +msgstr "non foi psosíbel crear tubería" + +#: src/exec.c:373 src/exec_pty.c:1000 src/exec_pty.c:1135 +#, c-format +msgid "select failed" +msgstr "selección fallada" + +#: src/exec.c:458 +#, c-format +msgid "unable to restore tty label" +msgstr "non foi posíbel restaurar a etiqueta tty" + +#: src/exec_pty.c:140 +#, c-format +msgid "unable to allocate pty" +msgstr "non foi posíbel asignar pty" + +#: src/exec_pty.c:597 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "non foi posíbel estabelcer a terminal en modo directo" + +#: src/exec_pty.c:914 +#, c-format +msgid "unable to set controlling tty" +msgstr "non foi posíebl estabelecer o controlador tty" + +#: src/exec_pty.c:1008 +#, c-format +msgid "error reading from signal pipe" +msgstr "produciuse un erro ao ler desde a tubería do sinal" + +#: src/exec_pty.c:1027 +#, c-format +msgid "error reading from pipe" +msgstr "produciuse un erro ao ler da tubería" + +#: src/exec_pty.c:1043 +#, c-format +msgid "error reading from socketpair" +msgstr "produciuse un erro ao ler de socketpair" + +#: src/exec_pty.c:1047 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "tipo de resposta inesperada en canles alternos %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s debe ser propiedade do uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s só debe ter permisos de escritura polo propietario" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "non foi posíbel dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: non é posíbel atopar o símbolo %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: tipo de política descoñecida %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: versión maiór %d da política incompatíbel, agardábase %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: só se pode cargar unha política de engadido" + +#: src/load_plugins.c:146 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: debe ser especificada cando menos unha política de engadido" + +#: src/load_plugins.c:151 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "a política do engadido %s non inclúe un método check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: desbordamento detectado" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "non foi posíbel abrir o socket" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "o agumento -C debe ser un número maior ou igual a 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "usuario descoñecido: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "non se deben especificar as opcións «-i» e «-s» simultáneamente" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "non se deben especificar as opcións «-i» e «-E» simultáneamente" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "a opción «-E» non é válida no modo edición" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "non se deben especificar variábeis de contorno no modo edición" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "a opción «-U» só se pode usar coa opción «-l»" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "as opcións «-A» e «-S» non se poden empregar conxuntamente" + +#: src/parse_args.c:432 src/sudo.c:482 src/sudo.c:502 src/sudo.c:509 +#: src/sudo.c:519 common/alloc.c:85 common/alloc.c:105 common/alloc.c:123 +#: common/alloc.c:145 common/alloc.c:203 common/alloc.c:217 +#, c-format +msgid "unable to allocate memory" +msgstr "non foi posíbel asignar memoria" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit non se admite nesta plataforma" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Só pode especificar unha das opcións -e, -h, -i, -K, -l, -s, -v ou -V" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - edita ficheiros como outro usuario\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - executa unha orde como outro usuario\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Opcións:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "usar o programa de axuda para a solicitude de contrasinal\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "usar tipo de autenticación especificado en BSD\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "executa unha orde en segundo plano\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "pecha todos os descriptores de ficheiro >= td\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "executa unha orde coa clase especificada de inicio de sesión\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "preserva o contorno de usuario ao executar unha orde\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "edita ficheiros no lugar de executar unha orde\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "executa unha orde como o grupo especificado\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "asigna a variábel HOME ao cartafol de inicio do usuario\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "mostra esta mensaxe de axuda e sae\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "executa un intérprete de ordes como un determinado usuario\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "remove un ficheiro de marca completamente\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "ficheiro de marca non válido\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "lista de ordes do usuario dispoñíbeis\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "modo non interactivo, non se preguntará ao usuario\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "preserva o vector de grupos no lugar de estabelecelo ao obxectivo\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "usa o contrasinal especificado\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "crea un contexto de seguranza SELinux coa regra especificada\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "lee o contrasinal desde a entrada estándar\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "executa un intérprete de ordes como un determinado usuario\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "cando está na lista, mostra os privilexios do usuario especificado\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "executa unha orde (ou edita un ficheiro) como un usuario específico\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "mostra a información da versión e sae\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "actualiza a marca do usuario sen executar unha orde\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "deten o proceso de argumentos da liña de ordes\n" + +#: src/selinux.c:76 +#, c-format +msgid "unable to open audit system" +msgstr "non foi posíbel abrir o sistema de auditoría" + +#: src/selinux.c:84 +#, c-format +msgid "unable to send audit message" +msgstr "non foi posíbel enviar a mensaxe de auditoría" + +#: src/selinux.c:112 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "non foi posíbel executar fgetfilecon %s" + +#: src/selinux.c:117 +#, c-format +msgid "%s changed labels" +msgstr "%s etiquetas cambiadas" + +#: src/selinux.c:122 +#, c-format +msgid "unable to restore context for %s" +msgstr "non foi posíbel restaurar o contexto para %s" + +#: src/selinux.c:162 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "non foi posíbel abrir %s, non volver a etiquetar tty" + +#: src/selinux.c:171 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "non se pode obter o contexto actual de tty, non volver a etiquetar tty" + +#: src/selinux.c:178 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "non foi posíbel obter o novo contexto tty, non volver a etiquetar tty" + +#: src/selinux.c:185 +#, c-format +msgid "unable to set new tty context" +msgstr "non foi posíbel estabelecer o novo contexto tty" + +#: src/selinux.c:195 src/selinux.c:208 src/sudo.c:335 +#, c-format +msgid "unable to open %s" +msgstr "non foi posíbel abrir %s" + +#: src/selinux.c:251 +#, c-format +msgid "you must specify a role for type %s" +msgstr "débese especificar unha regra por tipo %s" + +#: src/selinux.c:257 +#, c-format +msgid "unable to get default type for role %s" +msgstr "non foi posíbel obter o tipo de regra predeterminada %s" + +#: src/selinux.c:275 +#, c-format +msgid "failed to set new role %s" +msgstr "produciouse un fallo ao estabelecer a nova regra %s" + +#: src/selinux.c:279 +#, c-format +msgid "failed to set new type %s" +msgstr "produciuse un fallo ao estabelecer o novo tipo %s" + +#: src/selinux.c:288 +#, c-format +msgid "%s is not a valid context" +msgstr "%s non é un contexto válido" + +#: src/selinux.c:323 +#, c-format +msgid "failed to get old_context" +msgstr "produciuse un fallo ao obter old_context" + +#: src/selinux.c:329 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "non foi posíbel determinar o método de forzado" + +#: src/selinux.c:341 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "non foi posíbel estabelecer o contexto tty para %s" + +#: src/selinux.c:371 +#, c-format +msgid "unable to set exec context to %s" +msgstr "non foi posíbel o contexto de execución a %s" + +#: src/selinux.c:378 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "non foi posíbel estabelecer a chave de creación de contexto a %s" + +#: src/sesh.c:48 +msgid "requires at least one argument" +msgstr "require cando menos un argumento" + +#: src/sesh.c:64 +#, c-format +msgid "unable to execute %s" +msgstr "non se pode executar %s" + +#: src/sudo.c:198 +#, c-format +msgid "must be setuid root" +msgstr "debe ser setuid root" + +#: src/sudo.c:219 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo versión %s\n" + +#: src/sudo.c:221 +#, c-format +msgid "Configure options: %s\n" +msgstr "Opcións de configuración: %s\n" + +#: src/sudo.c:226 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "erro fatal, non foi posíbel cargar os engadidos" + +#: src/sudo.c:234 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "non foi posíbel inicializar a normativa do engadido" + +#: src/sudo.c:289 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "erro ao inicializar os engadidos de E/S %s" + +#: src/sudo.c:310 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "modo sudo 0x%x non agardado" + +#: src/sudo.c:404 +#, c-format +msgid "unable to get group vector" +msgstr "non é posíbel obter o vector de grupo" + +#: src/sudo.c:478 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "uid descoñecido %u: quen é vostede?" + +#: src/sudo.c:818 +#, c-format +msgid "resource control limit has been reached" +msgstr "o límite de control de recursos foi alcanzado" + +#: src/sudo.c:821 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "o usuario «%s» non é membro do grupo «%s»" + +#: src/sudo.c:825 +#, c-format +msgid "the invoking task is final" +msgstr "a tarefa que invoca é definitiva" + +#: src/sudo.c:828 +#, c-format +msgid "could not join project \"%s\"" +msgstr "non podería unirse ao proxecto «%s»" + +#: src/sudo.c:833 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "non hai fondo de recursos aceptando as asignacións existentes par ao proxecto «%s»" + +#: src/sudo.c:837 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "o fondo de recursos especificado non existe para o proxecto «%s»" + +#: src/sudo.c:841 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "non se podería ligar ao fondo de recursos predeterminado para o proxecto «%s»" + +#: src/sudo.c:847 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "configuración do proxecto fallada «%s»" + +#: src/sudo.c:849 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "aviso, o control de asignación de recuros fallou para o proxecto «%s»" + +#: src/sudo.c:879 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "non foi posíbel eliminar PRIV_PROC_EXEC desde PRIV_LIMIT" + +#: src/sudo.c:988 +#, c-format +msgid "unknown login class %s" +msgstr "clase de inicio de sesión descoñecida %s" + +#: src/sudo.c:1004 src/sudo.c:1007 +#, c-format +msgid "unable to set user context" +msgstr "non foi posíbel estabelecer o contexto do usuario" + +#: src/sudo.c:1022 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "non foi posíbel estabelcer o gid efectivo para executar como gid %u" + +#: src/sudo.c:1028 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "non foi posíbel estabelcer o gid para executar como gid %u" + +#: src/sudo.c:1036 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "non foi posíbel estabelecer o grupo suplementario de IDs" + +#: src/sudo.c:1044 +#, c-format +msgid "unable to set process priority" +msgstr "non foi posíbel estabelecer a prioridade de proceso" + +#: src/sudo.c:1052 +#, c-format +msgid "unable to change root to %s" +msgstr "non foi posíbel cambiar de root a %s" + +#: src/sudo.c:1062 src/sudo.c:1068 src/sudo.c:1074 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "non foi posíbel cambiar as runas uid (%u, %u)" + +#: src/sudo.c:1088 +#, c-format +msgid "unable to change directory to %s" +msgstr "non foi posíbel cambiar ao cartafol %s" + +#: src/sudo.c:1158 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "terminación de condición filla non agardada: %d" + +#: src/sudo.c:1204 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "a política do engadido %s non admite o listado de privilexios" + +#: src/sudo.c:1216 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "a política do engadido %s non admite a opción -v" + +#: src/sudo.c:1228 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "a normativa do engadido %s non admite as opcións -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "non foi posíbel cambiar uid a root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "erro do engadido: falta a lista de ficheiros para sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: non é un ficheiro regular" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: escritura curta" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s sen modificar" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s sen cambios" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "non foi posíbel escribir en %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "os contidos de edición de sesión déixanse en %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "non é posíbel ler o ficheiro temporal" + +#: src/tgetpass.c:96 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "sen tty presente e non se especificou un programa askpass" + +#: src/tgetpass.c:105 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "non hai programa askpass especificado, tente estabelecer SUDO_ASKPASS" + +#: src/tgetpass.c:237 +#, c-format +msgid "unable to set gid to %u" +msgstr "non foi posíbel estabelecer o gid a %u" + +#: src/tgetpass.c:241 +#, c-format +msgid "unable to set uid to %u" +msgstr "non foi posíbel estabelecer o uid a %u" + +#: src/tgetpass.c:246 +#, c-format +msgid "unable to run %s" +msgstr "non foi posíbel executar %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "non foi posíbel gardar stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "non foi posíbel facer dup2 stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "non foi posíbel restaurar stdin" + +#: common/aix.c:144 +#, c-format +msgid "unable to open userdb" +msgstr "non foi posíbel abrir userdb" + +#: common/aix.c:147 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "non foi posíbel cambiar ao rexistro «%s» para %s" + +#: common/aix.c:161 +#, c-format +msgid "unable to restore registry" +msgstr "non foi posíbel restaurar o rexistro" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "erro interno: tentou emalloc(0)" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "erro interno: tentou emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "erro interno: desbordamento en emalloc2(0)" + +#: common/alloc.c:119 +msgid "internal error, tried to erealloc(0)" +msgstr "erro interno: tentou erealloc(0)" + +#: common/alloc.c:138 +msgid "internal error, tried to erealloc3(0)" +msgstr "erro interno: tentou erealloc3(0)" + +#: common/alloc.c:140 +msgid "internal error, erealloc3() overflow" +msgstr "erro interno: desbordamento de erealloc3(0)" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Sinal descoñecido" diff --git a/src/po/hr.mo b/src/po/hr.mo new file mode 100644 index 0000000..b3558b4 Binary files /dev/null and b/src/po/hr.mo differ diff --git a/src/po/hr.po b/src/po/hr.po new file mode 100644 index 0000000..bf3817d --- /dev/null +++ b/src/po/hr.po @@ -0,0 +1,774 @@ +# Translation of sudo to Croatian. +# This file is put in the public domain. +# Tomislav Krznar , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-03-28 14:06-0400\n" +"PO-Revision-Date: 2012-04-17 22:01+0200\n" +"Last-Translator: Tomislav Krznar \n" +"Language-Team: Croatian \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:105 src/exec_pty.c:616 src/exec_pty.c:948 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "ne mogu razdvojiti" + +#: src/exec.c:252 +#, c-format +msgid "unable to create sockets" +msgstr "ne mogu napraviti utičnice" + +#: src/exec.c:259 src/exec_pty.c:567 src/exec_pty.c:576 src/exec_pty.c:584 +#: src/exec_pty.c:883 src/exec_pty.c:945 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "ne mogu napraviti cjevovod" + +#: src/exec.c:340 src/exec_pty.c:1011 src/exec_pty.c:1146 +#, c-format +msgid "select failed" +msgstr "odabir nije uspio" + +#: src/exec.c:425 +#, c-format +msgid "unable to restore tty label" +msgstr "ne mogu vratiti tty oznaku" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "ne mogu ukloniti PRIV_PROC_EXEC iz PRIV_LIMIT" + +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:447 src/sudo.c:467 +#: src/sudo.c:474 src/sudo.c:485 src/sudo.c:871 common/alloc.c:85 +#: common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 common/alloc.c:168 +#: common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#, c-format +msgid "unable to allocate memory" +msgstr "ne mogu alocirati memoriju" + +#: src/exec_pty.c:140 +#, c-format +msgid "unable to allocate pty" +msgstr "ne mogu alocirati pty" + +#: src/exec_pty.c:609 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "ne mogu postaviti terminal u sirovi način" + +#: src/exec_pty.c:926 +#, c-format +msgid "unable to set controlling tty" +msgstr "ne mogu postaviti kontrolni tty" + +#: src/exec_pty.c:1019 +#, c-format +msgid "error reading from signal pipe" +msgstr "greška čitanja iz cjevovoda signala" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from pipe" +msgstr "greška čitanja iz cjevovoda" + +#: src/exec_pty.c:1054 +#, c-format +msgid "error reading from socketpair" +msgstr "greška čitanja iz para utičnica" + +#: src/exec_pty.c:1058 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "neočekivana vrsta odgovora na povratnom kanalu: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "vlasnik %s mora biti uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "samo vlasnik smije imati dozvole za pisanje %s" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "ne mogu izvršiti dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: ne mogu pronaći simbol %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: nepoznata vrsta police %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: nekompatibilna glavna inačica police %d, očekujem %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: može se učitati samo jedan priključak police" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: mora biti naveden barem jedan priključak police" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "priključak police %s ne uključuje metodu check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: otkriven preljev" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "ne mogu otvoriti utičnicu" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "argument za -C mora biti broj veći ili jednak 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "nepoznat korisnik: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "ne možete navesti opcije „-i” i „-s” zajedno" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "ne možete navesti opcije „-i” i „-E” zajedno" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "opcija „-E” nije ispravna u načinu uređivanja" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "ne možete navesti varijable okoline u načinu uređivanja" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "opciju „-U” možete koristiti samo uz opciju „-l”" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "ne možete koristiti opcije „-A” i „-S” zajedno" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit nije podržan na ovoj platformi" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Smijete navesti samo jednu od opcija -e, -h, -i, -K, -l, -s, -v i -V " + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - uredi datoteke kao drugi korisnik\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - izvrši naredbu kao drugi korisnik\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Opcije:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "koristi pomoćni program za traženje lozinke\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "koristi navedenu vrstu BSD autentifikacije\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "pokreni naredbu u pozadini\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "zatvori sve opisnike datoteka >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "pokreni naredbu s navedenim razredom prijave\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "očuvaj korisničku okolinu pri izvršavanju naredbe\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "uredi datoteke umjesto pokretanja naredbe\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "izvrši naredbu kao navedena grupa\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "postavi HOME varijablu na početni direktorij odredišnog korisnika.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "prikaži ovu pomoć i izađi\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "pokreni ljusku prijave kao odredišni korisnik\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "potpuno ukloni datoteku vremenskih oznaka\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "učini datoteku vremenskih oznaka nevažećom\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "ispiši dostupne korisničke naredbe\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "neinteraktivni način, neće ispitivati korisnika\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "očuvaj grupni vektor umjesto postavljanja na odredišni\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "koristi navedeno traženje lozinke\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "stvori SELinux sigurnosni kontekst s navedenom ulogom\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "čitaj lozinku sa standardnog ulaza\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "pokreni ljusku kao odredišni korisnik\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "pri ispisu, ispiši navedene korisničke ovlasti\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "pokreni naredbu (ili uredi datoteku) kao navedeni korisnik\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "prikaži informacije o inačici i izađi\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "ažuriraj korisničku vremensku oznaku bez pokretanja naredbe\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "zaustavi obradu argumenata naredbenog retka\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "ne mogu otvoriti sustav revizije" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "ne mogu poslati poruku revizije" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "ne mogu izvršiti fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s je promijenio oznake" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "ne mogu vratiti kontekst za %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "ne mogu otvoriti %s, ne mijenjam oznaku tty" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "ne mogu dohvatiti trenutni tty kontekst, ne mijenjam oznaku tty" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "ne mogu dohvatiti novi tty kontekst, ne mijenjam oznaku tty" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "ne mogu postaviti novi tty kontekst" + +#: src/selinux.c:196 src/selinux.c:209 src/sudo.c:333 common/sudo_conf.c:328 +#, c-format +msgid "unable to open %s" +msgstr "ne mogu otvoriti %s" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "morate navesti ulogu za vrstu %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "ne mogu dohvatiti zadanu vrstu za ulogu %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "nisam uspio postaviti novu ulogu %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "nisam uspio postaviti novu vrstu %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s nije ispravan kontekst" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "nisam uspio dohvatiti stari kontekst (old_context)" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "ne mogu odrediti način provedbe." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "ne mogu postaviti tty kontekst za %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "ne mogu postaviti izvršni kontekst u %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "ne mogu postaviti kontekst stvaranja ključa u %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "zahtijeva barem jedan argument" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "ne mogu izvršiti %s" + +#: src/sudo.c:213 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo inačica %s\n" + +#: src/sudo.c:215 +#, c-format +msgid "Configure options: %s\n" +msgstr "Konfiguracijske opcije: %s\n" + +#: src/sudo.c:220 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "fatalna greška, ne mogu učitati priključke" + +#: src/sudo.c:228 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "ne mogu inicijalizirati priključak police" + +#: src/sudo.c:283 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "greška inicijalizacije U/I priključka %s" + +#: src/sudo.c:308 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "neočekivani sudo mod 0x%x" + +#: src/sudo.c:402 +#, c-format +msgid "unable to get group vector" +msgstr "ne mogu dohvatiti grupni vektor" + +#: src/sudo.c:443 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "nepoznat uid %u: tko ste vi?" + +#: src/sudo.c:735 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "vlasnik %s mora biti uid %d i mora imati postavljen setuid bit" + +#: src/sudo.c:738 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "efektivni uid nije %d, je li %s na datotečnom sustavu s postavljenom opcijom „nosuid” ili NFS datotečnom sustavu bez administratorskih ovlasti?" + +#: src/sudo.c:744 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "efektivni uid nije %d, je li sudo instaliran uz setuid root?" + +#: src/sudo.c:813 +#, c-format +msgid "resource control limit has been reached" +msgstr "dosegnuta je granica upravljanja resursima" + +#: src/sudo.c:816 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "korisnik „%s” nije član projekta „%s”" + +#: src/sudo.c:820 +#, c-format +msgid "the invoking task is final" +msgstr "pozivanje zadatka je konačno" + +#: src/sudo.c:823 +#, c-format +msgid "could not join project \"%s\"" +msgstr "ne mogu pridružiti projektu „%s”" + +#: src/sudo.c:828 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "ne postoji skladište resursa koje prihvaća zadane poveznice za projekt „%s”" + +#: src/sudo.c:832 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "ne postoji navedeno skladište resursa za projekt „%s”" + +#: src/sudo.c:836 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "ne mogu povezati na zadano skladište resursa za projekt „%s”" + +#: src/sudo.c:842 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject nije uspio za projekt „%s”" + +#: src/sudo.c:844 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "upozorenje, zadatak upravljanja resursima nije uspio za projekt „%s”" + +#: src/sudo.c:909 +#, c-format +msgid "unknown login class %s" +msgstr "nepoznat razred prijave %s" + +#: src/sudo.c:923 src/sudo.c:926 +#, c-format +msgid "unable to set user context" +msgstr "ne mogu postaviti korisnički kontekst" + +#: src/sudo.c:938 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "ne mogu postaviti dopunske grupne identifikatore" + +#: src/sudo.c:945 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "ne mogu postaviti efektivni gid u runas gid %u" + +#: src/sudo.c:951 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "ne mogu postaviti gid u runas (pokreni kao) gid %u" + +#: src/sudo.c:958 +#, c-format +msgid "unable to set process priority" +msgstr "ne mogu postaviti prioritet procesa" + +#: src/sudo.c:966 +#, c-format +msgid "unable to change root to %s" +msgstr "ne mogu promijeniti korijen u %s" + +#: src/sudo.c:973 src/sudo.c:979 src/sudo.c:985 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "ne mogu promijeniti u runas (pokreni kao) uid (%u, %u)" + +#: src/sudo.c:999 +#, c-format +msgid "unable to change directory to %s" +msgstr "ne mogu promijeniti direktorij u %s" + +#: src/sudo.c:1072 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "neočekivani uvjet završavanja djeteta: %d" + +#: src/sudo.c:1133 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "priključak police %s ne podržava ispis ovlasti" + +#: src/sudo.c:1145 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "priključak police %s ne podržava opciju -v" + +#: src/sudo.c:1157 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "priključak police %s ne podržava opcije -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "ne mogu promijeniti uid u root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "greška priključka: nedostaje popis datoteka za sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: nije obična datoteka" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: kratko pisanje" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s nepromijenjen" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s nepromijenjen" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "ne mogu pisati u %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "sadržaj uređivanja ostavljen u %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "ne mogu čitati privremenu datoteku" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "nije prisutan tty i nije naveden program za traženje lozinke" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "nije naveden program za traženje lozinke, pokušajte postaviti SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "ne mogu postaviti gid u %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "ne mogu postaviti uid u %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "ne mogu pokrenuti %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "ne mogu spremiti stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "ne mogu izvršiti dup2 stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "ne mogu vratiti stdin" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "ne mogu otvoriti korisničku bazu podataka" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "ne mogu promijeniti u registar „%s” za %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "ne mogu vratiti registar" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "interna greška, pokušao sam emalloc(0)" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "interna greška, pokušao sam emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "interna greška, emalloc2() preljev" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "interna greška, pokušao sam ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "interna greška, ecalloc() preljev" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "interna greška, pokušao sam erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "interna greška, pokušao sam erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "interna greška, erealloc3() preljev" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "ne mogu izvršiti stat %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s nije obična datoteka" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "vlasnik %s je uid %u, treba biti %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s ima dozvole za pisanje svih korisnika" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s ima dozvole za pisanje svih grupa" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Nepoznat signal" diff --git a/src/po/it.mo b/src/po/it.mo new file mode 100644 index 0000000..b2a7582 Binary files /dev/null and b/src/po/it.mo differ diff --git a/src/po/it.po b/src/po/it.po new file mode 100644 index 0000000..01cfdf9 --- /dev/null +++ b/src/po/it.po @@ -0,0 +1,782 @@ +# Italian translations for sudo package +# Copyright (c) 2011, 2012 The Free Software Foundation +# This file is distributed under the same license as the sudo package. +# Milo Casagrande , 2011, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo-1.8.5-b4\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-03-28 14:06-0400\n" +"PO-Revision-Date: 2012-04-05 13:56+0200\n" +"Last-Translator: Milo Casagrande \n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8-bit\n" +"Plural-Forms: nplurals=2; plural=(n!=1);\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:105 src/exec_pty.c:616 src/exec_pty.c:948 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "impossibile eseguire fork" + +#: src/exec.c:252 +#, c-format +msgid "unable to create sockets" +msgstr "impossibile creare socket" + +#: src/exec.c:259 src/exec_pty.c:567 src/exec_pty.c:576 src/exec_pty.c:584 +#: src/exec_pty.c:883 src/exec_pty.c:945 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "impossibile creare una pipe" + +#: src/exec.c:340 src/exec_pty.c:1011 src/exec_pty.c:1146 +#, c-format +msgid "select failed" +msgstr "select non riuscita" + +#: src/exec.c:425 +#, c-format +msgid "unable to restore tty label" +msgstr "impossibile ripristinare l'etichetta tty" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "impossibile rimuovere PRIV_PROC_EXEC da PRIV_LIMIT" + +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:447 src/sudo.c:467 +#: src/sudo.c:474 src/sudo.c:485 src/sudo.c:871 common/alloc.c:85 +#: common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 common/alloc.c:168 +#: common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#, c-format +msgid "unable to allocate memory" +msgstr "impossibile allocare la memoria" + +#: src/exec_pty.c:140 +#, c-format +msgid "unable to allocate pty" +msgstr "impossibile allocare pty" + +#: src/exec_pty.c:609 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "impossibile impostare il terminale in modalità raw" + +#: src/exec_pty.c:926 +#, c-format +msgid "unable to set controlling tty" +msgstr "impossibile impostare il tty di controllo" + +#: src/exec_pty.c:1019 +#, c-format +msgid "error reading from signal pipe" +msgstr "errore nel leggere dalla pipe di segnale" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from pipe" +msgstr "errore nel leggere dalla pipe" + +#: src/exec_pty.c:1054 +#, c-format +msgid "error reading from socketpair" +msgstr "errore nel leggere dal socketpair" + +#: src/exec_pty.c:1058 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "tipologia di risposta inattesa sul backchannel: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s deve essere di proprietà dello uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s deve essere scrivibile solo dal proprietario" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "impossibile eseguire dlopen su %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: impossibile trovare il simbolo %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: politica di tipo %d sconosciuta" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: numero principale di versione %d non compatibile, atteso %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: solo un plugin di politica può essere caricato" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: almeno un plugin di politica deve essere specificato" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "il plugin di politica %s non include un metodo check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: rilevato overflow" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "impossibile aprire socket" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "l'argomento di -C deve essere un numero maggiore o uguale a 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "utente sconosciuto: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "non è possibile specificare entrambe le opzioni \"-i\" e \"-s\"" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "non è possibile specificare entrambe le opzioni \"-i\" ed \"-E\"" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "l'opzione \"-E\" non è valida in modalità di modifica" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "non è possibile specificare variabili d'ambiente in modalità di modifica" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "l'opzione \"-U\" può essere usata solo con l'opzione \"-l\"" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "non è possibile usare assieme le opzioni \"-A\" e \"-S\"" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit non è supportato su questa piattaforma" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Solo una delle opzioni -e, -h, -i, -K, -l, -s, -v o -V può essere specificata" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - modifica file come un altro utente\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - esegue un comando come un altro utente\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Opzioni:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "Utilizza un programma d'aiuto per richiedere la password\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "Utilizza la tipologia di autenticazione BSD specificata\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "Esegue il comando in background\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "Chiude tutti i descrittori di file >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "Esegue il comando con la classe di accesso specificata\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "Mantiene l'ambiente dell'utente quando viene eseguito il comando\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "Modifica i file invece di eseguire un comando\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "Esegue il comando come il gruppo specificato\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "Imposta la variabile HOME alla directory dell'utente finale\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "Visualizza il messaggio di aiuto ed esce\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "Esegue una shell di login come l'utente finale\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "Rimuove completamente il file temporale\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "Invalida il file temporale\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "Elenca i comandi utente disponibili\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "Modalità non interattiva, non richiede nulla all'utente\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "Mantiene il vettore di gruppo invece di impostarlo a quello dell'obiettivo\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "Utilizza la richiesta della password specificata\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "Crea il contesto di sicurezza SELinux con il ruolo specificato\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "Legge la password dallo standard input\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "Esegue una shell come l'utente finale\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "Durante l'elencazione, visualizza i privilegi dell'utente specificato\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "Esegue un comando (o modifica un file) come l'utente specificato\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "Visualizza le informazioni sulla versione ed esce\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "Aggiorna il timestamp dell'utente senza eseguire un comando\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "Ferma l'elaborazione degli argomenti a riga di comando\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "impossibile aprire il sistema di audit" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "impossibile inviare il messaggio di audit" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "impossibile eseguire fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s ha modificato le etichette" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "impossibile ripristinare il contesto per %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "impossibile aprire %s, tty non viene etichettato nuovamente" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "impossibile ottenere il contesto tty attuale, tty non viene etichettato nuovamente" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "impossibile ottenere il nuovo contesto tty, tty non viene etichettato nuovamente" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "impossibile impostare il nuovo contesto tty" + +#: src/selinux.c:196 src/selinux.c:209 src/sudo.c:333 common/sudo_conf.c:328 +#, c-format +msgid "unable to open %s" +msgstr "impossibile aprire %s" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "è necessario specificare un ruolo per la tipologia %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "impossibile ottenere la tipologia predefinita per il ruolo %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "impossibile impostare il nuovo ruolo %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "impossibile impostare la nuova tipologia %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s non è un contesto valido" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "recupero del vecchio contesto non riuscito" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "impossibile determinare la modalità di rispetto." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "impossibile impostare il contesto tty per %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "impossibile impostare il contesto exec a %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "impossibile impostare il contesto di creazione della chiave a %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "richiede almeno un argomento" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "impossibile eseguire %s" + +#: src/sudo.c:213 +#, c-format +msgid "Sudo version %s\n" +msgstr "Versione di sudo: %s\n" + +#: src/sudo.c:215 +#, c-format +msgid "Configure options: %s\n" +msgstr "Opzioni di configurazione: %s\n" + +#: src/sudo.c:220 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "errore irreversibile, impossibile caricare i plugin" + +#: src/sudo.c:228 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "impossibile inizializzare il plugin delle politiche" + +#: src/sudo.c:283 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "errore nell'inizializzare il plugin di I/O %s" + +#: src/sudo.c:308 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "modalità 0x%x di sudo non attesa" + +#: src/sudo.c:402 +#, c-format +msgid "unable to get group vector" +msgstr "impossibile ottenere il vettore di gruppo" + +# (ndt) mah... andrebbe resa meglio... +#: src/sudo.c:443 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "uid %u sconosciuto: identificarsi." + +#: src/sudo.c:735 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s deve essere di proprietà dello uid %d e avere il bit setuid impostato" + +#: src/sudo.c:738 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "lo uid effettivo non è %d. %s si trova su un file system con l'opzione \"nosuid\" impostata o su un file system NFS senza privilegi di root?" + +#: src/sudo.c:744 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "lo uid effettivo non è %d. Il programma sudo è installato con setuid root?" + +#: src/sudo.c:813 +#, c-format +msgid "resource control limit has been reached" +msgstr "raggiunto il limite di controllo delle risorse" + +#: src/sudo.c:816 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "l'utente \"%s\" non fa parte del progetto \"%s\"" + +#: src/sudo.c:820 +#, c-format +msgid "the invoking task is final" +msgstr "il task chiamante è definitivo" + +#: src/sudo.c:823 +#, c-format +msgid "could not join project \"%s\"" +msgstr "impossibile unirsi al progetto \"%s\"" + +#: src/sudo.c:828 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "non esiste alcun pool di risorse per il progetto \"%s\" che accetti binding predefiniti" + +#: src/sudo.c:832 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "il pool di risorse specificato non esiste per il progetto \"%s\"" + +#: src/sudo.c:836 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "impossibile unirsi al pool di risorse predefinito per il progetto \"%s\"" + +#: src/sudo.c:842 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject per il progetto \"%s\" non riuscita" + +#: src/sudo.c:844 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "attenzione, assegnazione della risorsa di controllo per il progetto \"%s\" non riuscita" + +#: src/sudo.c:909 +#, c-format +msgid "unknown login class %s" +msgstr "classe di accesso %s sconosciuta" + +#: src/sudo.c:923 src/sudo.c:926 +#, c-format +msgid "unable to set user context" +msgstr "impossibile impostare il contesto utente" + +#: src/sudo.c:938 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "impossibile impostare ID di gruppo supplementari" + +#: src/sudo.c:945 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "impossibile impostare il gid effettivo per eseguire come %u" + +#: src/sudo.c:951 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "impossibile impostare il gid per eseguire come gid %u" + +#: src/sudo.c:958 +#, c-format +msgid "unable to set process priority" +msgstr "impossibile impostare la priorità del processo" + +#: src/sudo.c:966 +#, c-format +msgid "unable to change root to %s" +msgstr "impossibile modificare root a %s" + +#: src/sudo.c:973 src/sudo.c:979 src/sudo.c:985 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "impossibile passare a un diverso uid (%u, %u)" + +#: src/sudo.c:999 +#, c-format +msgid "unable to change directory to %s" +msgstr "impossibile passare alla directory %s" + +#: src/sudo.c:1072 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "condizione di uscita del figlio inattesa: %d" + +#: src/sudo.c:1133 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "il plugin di politica %s non supporta l'elencazione dei privilegi" + +#: src/sudo.c:1145 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "il plugin di politica %s non supporta l'opzione -v" + +#: src/sudo.c:1157 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "il plguind di politica %s non supporta le opzioni -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "impossibile modificare lo uid a root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "errore di plugin: elenco file mancante per sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: non è un file regolare" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: scrittura breve" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s lasciato non modificato" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s non modificato" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "impossibile scrivere su %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "contenuto della sessione di modifica tralasciato in %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "impossibile leggere il file temporaneo" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "nessun tty presente e nessun programma di richiesta password specificato" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "nessun programma di richiesta password specificato, impostare SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "impossibile impostare lo gid a %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "impossibile impostare lo uid a %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "impossibile eseguire %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "impossibile salvare lo stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "impossibile eseguire dup2 sullo stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "impossibile ripristinare lo stdin" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "impossibile aprire lo userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "impossibile passare al registro \"%s\" per %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "impossibile ripristinare il registro" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "errore interno, tentativo di chiamare emalloc(0)" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "errore interno, tentativo di chiamare emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "errore interno, overflow di emalloc2()" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "errore interno, tentativo di chiamare ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "errore interno, overflow di ecalloc()" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "errore interno, tentativo di chiamare erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "errore interno, tentativo di chiamare erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "errore interno, overflow di erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "impossibile eseguire stat su %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s non è un file regolare" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s è di proprietà dello uid %u, dovrebbe essere di %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s è scrivibile da tutti" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s è scrivibile dal gruppo" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Segnale sconosciuto" + +#~ msgid "must be setuid root" +#~ msgstr "è necessario essere setuid root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "l'argomento di -D deve essere tra 1 e 9 compresi" diff --git a/src/po/ja.mo b/src/po/ja.mo new file mode 100644 index 0000000..badeb3e Binary files /dev/null and b/src/po/ja.mo differ diff --git a/src/po/ja.po b/src/po/ja.po new file mode 100644 index 0000000..99ae3ca --- /dev/null +++ b/src/po/ja.po @@ -0,0 +1,786 @@ +# Japanese messages for sudo +# This file is put in the public domain. +# Yasuaki Taniguchi , 2011. +# Takeshi Hamasaki , 2012 +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-30 16:14+0900\n" +"Last-Translator: Takeshi Hamasaki \n" +"Language-Team: Japanese \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "ユーザーデータベースを開くことができません" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "%s 用のレジストリー \"%s\" へ切り替えることができません" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "レジストリーを復元できません" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "内部エラー、emalloc(0) を試みました" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "メモリ割り当てを行えませんでした" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "内部エラー、 emalloc2(0) を試みました" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "内部エラー、 emalloc2() がオーバーフローしました" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "内部エラー、ecalloc(0) を試みました" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "内部エラー、 ecalloc() がオーバーフローしました" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "内部エラー、 erealloc(0) を試みました" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "内部エラー、 erealloc3(0) を試みました" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "内部エラー、 erealloc3() がオーバーフローしました" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "%s の状態取得 (stat) ができません" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s は通常ファイルではありません" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s はユーザーID %u によって所有されています。これは %u であるべきです" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s は誰でも書き込み可能です" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s はグループのメンバーによる書き込みが可能です" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "%s を開けません" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "不明なシグナルです" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "ポリシープラグインがセッションの初期化に失敗しました" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "fork できません" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "ソケットを作成できません" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "パイプを作成できません" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "select に失敗しました" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "tty ラベルを復旧できません" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "PRIV_LIMIT から PRIV_PROC_EXEC を取り除くことができません" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "pty を割り当てられません" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "端末を raw モードに設定できません" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "tty の制御設定ができません" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "シグナルパイプからの読み込み中にエラーが発生しました" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "パイプからの読み込み中にエラーが発生しました" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "ソケットペアからの読み込み中にエラーが発生しました" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "バックチャンネルに関する予期しないリプレイタイプです: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s の所有者は uid %d でなければいけません" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s は所有者のみ書き込み可能で無ければいけません" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "dlopen %s を行うことができません: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: シンボル %s を見つけることができません" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: 不明なポリシータイプ %d です" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: 互換性の無いポリシーメジャーバージョン %d です。予期されるのは %d です" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: 一つのポリシープラグインのみロードされているようです" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: 最低でも一つ以上のポリシープラグインを指定しなければいけません" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "ポリシープラグイン %s には check_policy メソッドが含まれていません" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: オーバーフローが検出されました" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "ソケットを開くことができません" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "-C の引数は 3 以上の数値でなければいけません" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "不明なユーザーです: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "`-i' と `-s' オプションを同時に指定することはできません" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "`-i' と `-E' オプションを同時に指定することはできません" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "`-E' オプションは編集モードでは無効です" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "編集モードでは環境変数を指定できません" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "`-U' オプションは `-l' オプションのみと同時に指定できます" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "`-A' と `-S' オプションは同時に指定することはできません" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit はこのプラットフォームではサポートされていません" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "-e, -h, -i, -K, -l, -s, -v または -V のうち一つのみ指定できます" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - 別のユーザーとしてファイルを編集します\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - 別のユーザーとしてコマンドを実行します\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"オプション:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "パスワード要求のために補助プログラムを使用する\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "指定した BSD 認証タイプを使用する\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "コマンドをバックグラウンドで実行する\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "fd 以上のすべてのファイル記述子を閉じる\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "指定したログインクラスでコマンドを実行する\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "コマンドを実行する時にユーザーの環境変数を保護する\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "コマンドを実行する代わりにファイルを編集する\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "指定したグループでコマンドを実行する\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "HOME 変数を変更先となるユーザーのホームディレクトリに設定する\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "ヘルプメッセージを表示して終了する\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "変更先のユーザーとしてログインシェルを実行する\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "タイムスタンプファイルを完全に削除する\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "タイムスタンプファイルを無効にする\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "ユーザーが使用可能なコマンドを一覧表示する\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "非対話モードで実行し、ユーザーに入力を求めない\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "グループベクトルを保護する (変更先のユーザーのものに設定しない)\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "指定したパスワードプロンプトを使用する\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "指定した役割で SELinux セキュリティーコンテキストを作成する\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "標準入力からパスワードを読み込む\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "変更先のユーザーとしてシェルを実行する\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "一覧表示する時に、指定したユーザーの権限を一覧表示する\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "指定したユーザーでコマンドを実行する (またはファイルを編集する)\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "バージョン情報を表示して終了する\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "コマンドを実行せずにユーザーのタイムスタンプを更新する\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "コマンドライン引数の処理を終了する\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "監査システムを開くことができません" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "監査メッセージを送ることができません" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "fgetfilecon %s を行うことができません" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s はラベルを変更しました" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "%s 用のコンテキストを復元することができません" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "%s を開くことができません。tty の再ラベル付けを行いません" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "現在の tty コンテキストを取得できません。 tty の再ラベル付けを行いません" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "新しい tty コンテキストを取得できません。 tty の再ラベル付けを行いません" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "新しい tty コンテキストを設定できません" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "タイプ %s 用の役割を指定しなければいけません" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "役割 %s 用のデフォルトのタイプを取得できません" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "新しい役割 %s の設定に失敗しました" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "新しいタイプ %s の設定に失敗しました" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s は有効なコンテキストではありません" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "古いコンテキスト (old_context) の取得に失敗しました" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "強制モードを決定することができません。" + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "%s 用の tty コンテキストをセットアップできません" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "実行コンテキストを %s に設定できません" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "キー作成コンテキストを %s へ設定できません" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "最低でも一つ以上おの引数が必要です" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "%s を実行できません" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo バージョン %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "configure オプション: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "致命的エラー、プラグインをロードできません" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "ポリシープラグインを初期化できません" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "I/O プラグイン %s を初期化中にエラーが発生しました" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "予期しない sudo のモード 0x%x です" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "グループベクトルを取得できません" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "不明なユーザーID %u です: 誰ですか?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s は所有者が uid %d である必要があり、かつ setuid が設定されている必要があります" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "実効 uid が %d ではありません、%s は 'nosuid' が設定されたファイルシステムにあるか、root 権限のないNFSファイルシステムにあるのでは?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "実効 uid が %d ではありません、sudo は setuid root を設定してインストールされていますか?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "資源制御の制限の最大値に達しました" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "ユーザー \"%s\" はプロジェクト \"%s\" のメンバーではありません" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "起動しているタスクは最後 (final) です" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "プロジェクト \"%s\" に参加できません" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "プロジェクト \"%s\" 用にはデフォルト割り当てとして受け付けられる資源プールがありません" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "プロジェクト \"%s\" 用として指定した資源プールは存在しません" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "プロジェクト \"%s\" 用にデフォルト資源プールを割り当てられませんでした" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "プロジェクト\"%s\" への setproject に失敗しました" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "警告、プロジェクト \"%s\" への資源制御割り当てに失敗しました" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "不明なログインクラス %s です" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "ユーザーコンテキストを設定できません" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "追加のグループIDを設定できません" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "実行時のグループID (gid) %u を実効グループIDに設定できません" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "実行時のグループID (gid) %u をグループIDに設定できません" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "プロセス優先度を設定できません" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "root を %s へ変更できません" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "実行時のユーザーID (uid) (%u, %u) へ変更できません" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "ディレクトリーを %s に変更できません" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "予期しない子プロセスの終了コードです: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "ポリシープラグイン %s は権限の一覧表示をサポートしていません" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "ポリシープラグイン %s は -v オプションをサポートしません" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "ポリシープラグイン %s は -k/-K オプションをサポートしません" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "ユーザーID (uid) を root (%u) に変更できません" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "プラグインエラー: sudoedit 用のファイル一覧がありません" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: 通常ファイルではありません" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: 短い書き込みです" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s を修正しないままにします" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s を変更しません" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "%s へ書き込むことができません" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "編集セッションの内容が %s 内に残っています" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "一時ファイルを読み込むことができません" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "端末 (tty) が存在せず、パスワードを尋ねる (askpass) プログラムが指定されていません" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "パスワードを尋ねる (askpass) プログラムが指定されていません。 SUDO_ASKPASS の設定を試みます" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "グループIDを %u に設定できません" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "ユーザーIDを %u に設定できません" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "%s を実行できません" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "標準入力を保存できません" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "標準入力へ dup2 を実行できません" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "標準入力を復元できません" + +#~ msgid "must be setuid root" +#~ msgstr "setuid root されていなければいけません" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "-D の引数は 1 から 9 の間でなければいけません" diff --git a/src/po/pl.mo b/src/po/pl.mo new file mode 100644 index 0000000..4e986e3 Binary files /dev/null and b/src/po/pl.mo differ diff --git a/src/po/pl.po b/src/po/pl.po new file mode 100644 index 0000000..a239e44 --- /dev/null +++ b/src/po/pl.po @@ -0,0 +1,778 @@ +# Polish translation for sudo. +# This file is put in the public domain. +# Jakub Bogusz , 2011-2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-05-06 21:33+0200\n" +"Last-Translator: Jakub Bogusz \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "nie udało się otworzyć userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "nie udało się przełączyć na rejestr \"%s\" dla %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "nie udało się odtworzyć rejestru" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "błąd wewnętrzny, próbowano wykonać emalloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "nie udało się przydzielić pamięci" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "błąd wewnętrzny, próbowano wykonać emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "błąd wewnętrzny, przepełnienie emalloc2()" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "błąd wewnętrzny, próbowano wykonać ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "błąd wewnętrzny, przepełnienie ecalloc()" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "błąd wewnętrzny, próbowano wykonać erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "błąd wewnętrzny, próbowano wykonać erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "błąd wewnętrzny, przepełnienie erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "nie udało się wykonać stat na %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s nie jest zwykłym plikiem" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "właścicielem %s jest uid %u, powinien być %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s jest zapisywalny dla świata" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s jest zapisywalny dla grupy" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "nie udało się otworzyć %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Nieznany sygnał" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "nie udało się zainicjować sesji przez wtyczkę polityki" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "nie udało się wykonać fork" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "nie udało się utworzyć gniazd" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "nie udało się utworzyć potoku" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "wywołanie select nie powiodło się" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "nie udało się przywrócić etykiety tty" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "nie udało się usunąć PRIV_PROC_EXEC z PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "nie udało się przydzielić pty" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "nie udało się przestawić terminala w tryb surowy" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "nie udało się ustawić sterującego tty" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "błąd odczytu z potoku sygnałowego" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "błąd odczytu z potoku" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "błąd odczytu z pary gniazd" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "nieoczekiwany typ odpowiedzi z kanału zwrotnego: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "właścicielem %s musi być uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "prawo zapisu do %s może mieć tylko właściciel" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "nie udało się wykonać dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: nie udało się odnaleźć symbolu %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: nieznany typ polityki %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: niezgodna główna wersja polityki %d, oczekiwano %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: może być wczytana tylko jedna wtyczka polityki" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: musi być wczytana przynajmniej jedna wtyczka polityki" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "wtyczka polityki %s nie zawiera metody check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: wykryto przepełnienie" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "nie udało się otworzyć gniazda" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "argument opcji -C musi być większy lub równy 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "nieznany użytkownik: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "nie można podać jednocześnie opcji `-i' oraz `-s'" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "nie można podać jednocześnie opcji `-i' oraz `-E'" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "opcja `-E' nie jest poprawna w trybie edycji" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "w trybie edycji nie można przekazywać zmiennych środowiskowych" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "opcji `-U' można używać tylko wraz z opcją `-l'" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "opcji `-A' oraz `-S' nie można używać jednocześnie" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit nie jest obsługiwane na tej platformie" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Można podać tylko jedną z opcji -e, -h, -i, -K, -l, -s, -v lub -V" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - modyfikowanie plików jako inny użytkownik\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - wykonywanie poleceń jako inny użytkownik\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Opcje:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "użycie programu pomocniczego do pytań o hasło\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "użycie podanego rodzaju uwierzytelnienia BSD\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "uruchomienie polecenia w tle\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "zamknięcie wszystkich deskryptorów >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "uruchomienie polecenia z podaną klasą logowania\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "zachowanie środowiska użytkownika przy uruchamianiu polecenia\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "modyfikowanie plików zamiast uruchomienia polecenia\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "wywołanie polecenia jako określona grupa\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "ustawienie zmiennej HOME na katalog domowy użytkownika docelowego.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "wyświetlenie opisu i zakończenie\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "uruchomienie powłoki logowania jako docelowy użytkownik\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "całkowite usunięcie pliku znacznika czasu\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "unieważnienie pliku znacznika czasu\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "wypisanie poleceń dostępnych dla użytkownika\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "tryb nieinteraktywny, użytkownik nie będzie pytany\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "zachowanie wektora grup zamiast ustawiania docelowych\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "użycie podanego pytania o hasło\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "utworzenie kontekstu bezpieczeństwa SELinuksa z podaną rolą\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "odczyt hasła ze standardowego wejścia\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "uruchomienie powłoki jako użytkownik docelowy\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "przy wypisywaniu podanie uprawnień danego użytkownika\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "uruchomienie polecenia (lub modyfikowanie pliku) jako podany użytkownik\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "wyświetlenie informacji o wersji i zakończenie\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "uaktualnienie znacznika czasu użytkownika bez uruchamiania polecenia\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "zakończenie przetwarzania argumentów linii poleceń\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "nie udało się otworzyć systemu audytu" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "nie udało się wysłać komunikatu audytowego" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "nie udało się wykonać fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "zmienionych etykiet: %s" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "nie udało się przywrócić kontekstu %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "nie udało się otworzyć %s, bez zmiany etykiety tty" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "nie udało się uzyskać bieżącego kontekstu tty, bez zmiany etykiety tty" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "nie udało się uzyskać nowego kontekstu tty, bez zmiany etykiety tty" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "nie udało się ustawić nowego kontekstu tty" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "trzeba podać rolę dla typu %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "nie udało się uzyskać domyślnego typu dla roli %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "nie udało się ustawić nowej roli %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "nie udało się ustawić nowego typu %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s nie jest poprawnym kontekstem" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "nie udało się uzyskać starego kontekstu" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "nie udało się określić trybu wymuszenia." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "nie udało się ustawić kontekstu tty dla %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "nie udało się ustawić kontekstu wykonywania na %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "nie udało się ustawić kontekstu tworzenia klucza na %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "wymagany jest przynajmniej jeden argument" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "nie udało się wykonać %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo wersja %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Opcje konfiguracji: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "błąd krytyczny, nie udało się załadować wtyczek" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "nie udało się zainicjować wtyczki polityki" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "błąd inicjalizacji wtyczki we/wy %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "nieoczekiwany tryb sudo 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "nie udało się uzyskać wektora grup" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "nieznany uid %u: kim jesteś?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s musi mieć uid %d jako właściciela oraz ustawiony bit setuid" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "efektywny uid nie wynosi %d, czy %s jest na systemie plików z opcją 'nosuid' albo systemie plików NFS bez uprawnień roota?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "efektywny uid nie wynosi %d, czy sudo jest zainstalowane z setuid root?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "osiągnięto limit kontroli zasobów" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "użytkownik \"%s\" nie jest członkiem projektu \"%s\"" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "zadanie uruchamiające jest ostatnim" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "nie udało się dołączyć do projektu \"%s\"" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "nie istnieje pula zasobów akceptująca domyślne przypisania dla projektu \"%s\"" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "podana pula zasobów nie istnieje w projekcie \"%s\"" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "nie można przypisać do domyślnej puli zasobów w projekcie \"%s\"" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject dla projektu \"%s\" nie powiodło się" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "uwaga: przypisanie kontroli zasobów dla projektu \"%s\" nie powiodło się" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "nieznana klasa logowania %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "nie udało się ustawić kontekstu użytkownika" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "nie udało się ustawić ID dodatkowych grup" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "nie udało się ustawić efektywnego gid-a w celu działania jako gid %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "nie udało się ustawić gid-a w celu działania jako gid %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "nie udało się ustawić priorytetu procesu" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "nie udało się zmienić katalogu głównego na %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "nie udało się zmienić uid-ów, aby działać jako (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "nie udało się zmienić katalogu na %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "nieoczekiwane zakończenie procesu potomnego: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "wtyczka polityki %s nie obsługuje wypisywania uprawnień" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "wtyczka polityki %s nie obsługuje opcji -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "wtyczka polityki %s nie obsługuje opcji -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "nie udało się zmienić uid-a na roota (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "błąd wtyczki: brak listy plików dla sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: nie jest zwykłym plikiem" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: skrócony zapis" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "pozostawiono bez zmian: %s" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "nie zmieniono: %s" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "nie udało się zapisać do %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "zawartość sesji edycji pozostawiono w %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "nie udało się odczytać pliku tymczasowego" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "brak tty i nie podano programu pytającego o hasło" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "nie podano programu pytającego o hasło, proszę spróbować ustawić SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "nie udało się ustawić gid-a na %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "nie udało się ustawić uid-a na %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "nie udało się uruchomić %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "nie udało się zapisać standardowego wejścia" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "nie udało się wykonać dup2 na standardowym wejściu" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "nie udało się przywrócić standardowego wejścia" diff --git a/src/po/ru.mo b/src/po/ru.mo new file mode 100644 index 0000000..7997582 Binary files /dev/null and b/src/po/ru.mo differ diff --git a/src/po/ru.po b/src/po/ru.po new file mode 100644 index 0000000..cc64fec --- /dev/null +++ b/src/po/ru.po @@ -0,0 +1,788 @@ +# Transation of sudo messages to Russian. +# This file is put in the public domain. +# This file is distributed under the same license as the sudo package. +# +# Pavel Maryanov , 2011. +# Yuri Kozlov , 2011, 2012. +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-30 08:23+0400\n" +"Last-Translator: Yuri Kozlov \n" +"Language-Team: Russian \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.2\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "не удаётся открыть userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "не удаётся переключиться на реестр «%s» для %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "не удаётся восстановить реестр" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "внутренняя ошибка, попытка выполнить emalloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "не удаётся выделить память" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "внутренняя ошибка, попытка выполнить emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "внутренняя ошибка, переполнение emalloc2()" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "внутренняя ошибка, попытка выполнить ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "внутренняя ошибка, переполнение ecalloc()" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "внутренняя ошибка, попытка выполнить erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "внутренняя ошибка, попытка выполнить erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "внутренняя ошибка, переполнение erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "не удалось выполнить вызов stat %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s не является обычным файлом" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s принадлежит пользователю с uid %u, а должен принадлежать пользователю с uid %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "доступ на запись в %s разрешена всем" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "доступ на запись в %s разрешена группе" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "не удаётся открыть %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Неизвестный сигнал" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "модулю политик не удалось инициализировать сеанс" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "не удаётся создать дочерний процесс" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "не удаётся создать сокеты" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "не удаётся создать канал" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "ошибка select" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "не удаётся создать восстановить метку tty" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "не удаётся удалить PRIV_PROC_EXEC из PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "не удаётся выделить pty" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "не удаётся перевести терминал в «сырой» режим" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "не удаётся установить управляющий tty" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "ошибка чтения из сигнального канала" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "ошибка чтения из канала" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "ошибка чтения из пары сокетов" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "неожиданный тип ответа в резервном канале: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s должен принадлежать пользователю с uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s должен быть доступен на запись только владельцу" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "не удаётся выполнить dlopen для %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: не удаётся найти символ %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: неизвестный тип политики %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: несовместимая основная версия политики %d, ожидалась %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: может быть загружен только один модуль политики" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: необходимо указать не менее одного модуля политики" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "модуль политики %s не содержит метод check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: обнаружено переполнение" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "не удаётся открыть сокет" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "аргумент для -C должен быть числом, которое больше или равно 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "неизвестный пользователь: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "параметры «-i» и «-s» являются взаимоисключающими" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "параметры «-i» и «-E» являются взаимоисключающими" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "параметр «-E» не действует в режиме редактирования" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "переменные окружения нельзя определять в режиме редактирования" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "параметр «-U» можно использовать только с параметром «-l»" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "параметры «-A» и «-S» являются взаимоисключающими" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit не поддерживается на этой платформе" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Можно указать только параметры -e, -h, -i, -K, -l, -s, -v или -V" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s — редактирование файлов от имени другого пользователя\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s — выполнение команд от имени другого пользователя\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Параметры:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "использовать вспомогательную программу для ввода пароля\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "использовать указанный тип проверки подлинности BSD\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "выполнить команду в фоновом режиме\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "закрыть все дескрипторы файлов >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "выполнить команду с указанным классом входа в систему\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "сохранить пользовательскую среду при выполнении команды\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "редактировать файлы вместо выполнения команды\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "выполнить команду от имени указанной группы\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "установить для переменной HOME домашний каталог указанного пользователя\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "показать справку и выйти\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "запустить оболочку входа в систему от имени указанного пользователя\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "полностью удалить файл timestamp\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "объявить недействительным файл timestamp\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "вывести список команд, доступных пользователю\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "автономный режим без не вывода запросов пользователю\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "сохранить вектор группы вместо установки целевой группы\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "использовать указанный запрос пароля\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "создать контекст безопасности SELinux с указанной ролью\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "читать пароль из стандартного ввода\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "запустить оболочку от имени указанного пользователя\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "при выводе списка показать привилегии пользователя\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "выполнить команду (или редактировать файл) от имени указанного пользователя\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "показать сведения о версии и выйти\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "обновить временную метку пользователя без выполнения команды\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "прекратить обработку аргументов командной строки\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "не удаётся открыть систему аудита" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "не удаётся отправить сообщение аудита" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "не удаётся выполнить fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "изменено меток: %s" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "не удаётся восстановить контекст для %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "не удаётся открыть %s, tty без возможности переименования" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "не удаётся получить контекст текущего tty, tty без возможности переименования" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "не удаётся получить контекст tty, tty без возможности переименования" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "не удаётся установить новый контекст tty" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "необходимо указать роль для типа %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "не удаётся получить тип по умолчанию для роли %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "не удалось установить новую роль %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "не удалось установить новый тип %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s не является допустимым контекстом" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "не удалось получить old_context" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "не удаётся определить принудительный режим" + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "не удаётся настроить контекст tty для %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "не удаётся установить для контекста exec значение %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "не удаётся установить для контекста создания ключа значение %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "укажите не менее одного аргумента" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "не удаётся выполнить %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo версия %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Параметры настройки: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "фатальная ошибка, не удалось загрузить модули" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "не удаётся инициализировать модуль политики" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "ошибка инициализации модуля ввода-вывода %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "неожиданный режим sudo: 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "не удаётся получить вектор группы" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "неизвестный uid %u: кто вы?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s должен принадлежать пользователю с uid %d и иметь бит setuid" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "эффективный uid не равен %d, возможно, %s находится в файловой системе, смонтированной с битом «nosuid» или в файловой системе NFS без прав суперпользователя?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "эффективный uid не равен %d, программа sudo установлена с битом setuid и принадлежит root?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "достигнут лимит управления ресурсами" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "пользователь «%s» не является членом проекта «%s»" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "вызывающе задание — последнее" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "не удалось присоединиться к проекту «%s»" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "для проекта «%s» не существует пула ресурсов, принимающих привязки по умолчанию" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "у проекта «%s» нет указанного пула ресурсов" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "не удаётся подключиться к пулу ресурсов по умолчанию проекта «%s»" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject завершилась с ошибкой для проекта «%s»" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "предупреждение: назначение контроля за ресурсами завершилось с ошибкой для проекта «%s»" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "неизвестный класс входа %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "не удаётся назначить контекст пользователя" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "не удаётся назначить дополнительные идентификаторы групп" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "не удаётся назначить эффективный gid на runas gid %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "не удаётся назначить gid на runas gid %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "не удаётся назначить приоритет процесса" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "не удаётся изменить root на %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "не удаётся изменить на runas uid (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "не удаётся сменить каталог на %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "неожиданное условие завершения потомка: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "модуль политики %s не поддерживает списка прав" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "модуль политики %s не поддерживает параметр -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "модуль политики %s не поддерживает параметры -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "Не удалось изменить uid на root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "ошибка модуля: отсутствует список файлов для sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: не обычный файл" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: неполная запись" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s осталось неизменным" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s не изменено" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "не удаётся записать в %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "содержимое сеанса редактирования сохранено в %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "не удаётся прочесть временный файл" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "нет tty и не указана программа askpass" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "не указана программа askpass, попробуйте задать значение в SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "не удаётся назначить gid равным %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "не удаётся назначить uid равным %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "не удаётся выполнить %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "не удаётся сохранить стандартный ввод" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "не удаётся выполнить dup2 для стандартного ввода" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "не удаётся восстановить стандартный ввод" + +#~ msgid "must be setuid root" +#~ msgstr "требуется setuid пользователя root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "аргумент для -D должен быть в диапазоне от 1 до 9 включительно" diff --git a/src/po/sr.mo b/src/po/sr.mo new file mode 100644 index 0000000..63c0598 Binary files /dev/null and b/src/po/sr.mo differ diff --git a/src/po/sr.po b/src/po/sr.po new file mode 100644 index 0000000..c2a1fa1 --- /dev/null +++ b/src/po/sr.po @@ -0,0 +1,784 @@ +# Language sudo-1 translations for sudo package. +# This file is put in the public domain. +# Мирослав Николић , 2011, 2012. +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-05-02 10:11+0200\n" +"Last-Translator: Мирослав Николић \n" +"Language-Team: Serbian \n" +"Language: sr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "не могу да отворим корисничку базу података" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "не могу да се пребацим на регистар „%s“ за %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "не могу да повратим регистар" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "унутрашња грешка, покушах да обавим „emalloc(0)“" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "не могу да доделим меморију" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "унутрашња грешка, покушах да обавим „emalloc2(0)“" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "унутрашња грешка, прекорачење функције „emalloc2()“" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "унутрашња грешка, покушах „ecalloc(0)“" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "унутрашња грешка, прекорачење функције „ecalloc()“" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "унутрашња грешка, покушах да обавим „erealloc(0)“" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "унутрашња грешка, покушах да обавим „erealloc3(0)“" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "унутрашња грешка, прекорачење функције „erealloc3()“" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "не могу да добијем податке о „%s“" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "„%s“ није обична датотека" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s је у власништву уиб-а %u, а треба бити %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s је светски уписив" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s је групно уписив" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "не могу да отворим %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Непознати сигнал" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "није успело покретање сесије прикључка политике" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "не могу да поделим" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "не могу да направим утичнице" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "не могу да направим спојку" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "избор није успео" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "не могу да повратим tty натпис" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "не могу да уклоним PRIV_PROC_EXEC из PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "не могу да доделим pty" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "не могу да подесим терминал у сирови режим" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "не могу да подесим контролисање tty" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "грешка у читању из спојке сигнала" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "грешка у читању из спојке" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "грешка у читању из пара прикључка" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "неочекивана врста одговора на повратном каналу: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s мора бити у власништву уида %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s мора бити уписив само од стране власника" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "не могу да дл-отворим %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: не могу да пронађем симбол %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: непозната врста сигурности %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: несагласно главно издање сигурности %d, очекивано је %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: само прикључак самосталне сигурности може бити учитан" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: барем један прикључак сигурности мора бити наведен" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "прикључак сигурности %s не садржи метод провере_сигурности" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "учитај_сучеља: откривено је прекорачење" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "не могу да отворим утичницу" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "аргумент уз -C мора бити број већи или једнак 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "непознат корисник: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "не можете да наведете обе опције „-i“ и „-s“" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "не можете да наведете обе опције „-i“ и „-E“" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "опција „-E“ није исправна у режиму уређивања" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "не можете да одредите променљиве окружења у режиму уређивања" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "опција „-U“ може бити коришћена само са опцијом „-l“" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "опције „-A“ и „-S“ не могу бити коришћене заједно" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "„sudoedit“ није подржано на овој платформи" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Само једна од опција -e, -h, -i, -K, -l, -s, -v или -V може бити наведена" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s — уредите датотеке као други корисник\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s — извршите наредбу као други корисник\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Опције:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "користите програм испомоћи за упит лозинке\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "користи наведену врсту БСД потврде идентитета\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "покреће наредбу у позадини\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "затвара све описнике датотеке >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "покреће наредбу са наведеном класом пријаве\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "чува корисничко окружење приликом извршавања наредбе\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "уређује датотеке уместо да изврши наредбу\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "извршава наредбу као наведену групу\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "подешава променљиву ЛИЧНО у циљну корисничку личну фасциклу.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "приказује поруку помоћи и излази\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "покреће љуску пријаве као крајњи корисник\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "потпуно уклања датотеку записа датума и времена\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "чини неисправном датотеку датума и времена\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "наводи наредбе доступне кориснику\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "немеђудејствени режим, неће питати корисника\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "чува вектор групе уместо да подеси на циљеве\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "користи наведени упит лозинке\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "ствара СЕЛинукс сигурносни контекст са наведеном улогом\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "чита лозинку са стандардног улаза\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "покреће љуску као крајњи корисник\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "када прави списак, исписује наведене привилегије корисника\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "покреће наредбу (или уређује датотеку) као наведени корисник\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "приказује податке о издању и излази\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "освежава кориснички запис датума и времена без покретања наредбе\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "зауставља обрађивање аргумената линије наредби\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "не могу да отворим аудит систем" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "не могу да пошаљем аудит поруку" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "не могу да добавим контекст отворене датотеке %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s измењена натписа" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "не могу да повратим контекст за %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "не могу да отворим %s, није тту за поновно натписивање" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "не могу да добавим текући тту контекст, није тту за поновно натписивање" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "не могу да добавим нови тту контекст, није тту за поновно натписивање" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "не могу да подесим нови тту контекст" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "морате да наведете улогу за врсту %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "не могу да добавим основну врсту за улогу %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "нисам успео да подесим нову улогу %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "нисам успео да подесим нову врсту %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s није исправан контекст" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "нисам успео да добавим стари_контекст" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "не могу да одредим режим присиљавања." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "не могу да подесим тту контекст за %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "не могу да подесим извршни контекст за %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "не могу да подесим контекст стварања кључа за %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "захтева барем један аргумент" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "не могу да извршим %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Судо издање %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Опције подешавања: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "кобна грешка, не могу да учитам прикључке" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "не могу да започнем прикључак сигурности" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "грешка приликом покретања У/И прикључка %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "неочекивани судо режим 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "не могу да добавим вектор групе" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "непознати уид %u: ко сте ви?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s мора бити власништвo уида %d и треба да има подешен бит „setuid“" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "стварни уид није %d, већ %s на систему датотека са подешеном опцијом „nosuid“ или је НФС систем датотека без администраторских привилегија?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "стварни уид није %d, већ сетуид администратор инсталиран судоом?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "ограничење контроле ресурса је достигнуто" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "корисник „%s“ није члан пројекта „%s“" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "задатак призивања је завршни" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "не могу да приступим пројекту „%s“" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "не постоји депо извора који прихвата основне пречице за пројекат „%s“" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "наведени депо извора не постоји за пројекат „%s“" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "не могу да се повежем са основним депоом извора за пројекат „%s“" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "подешавање пројекта није успело за пројекат „%s“" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "упозорење, није успело додељивање контроле ресурса за пројекат „%s“" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "непозната класа пријаве %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "не могу да подесим кориснички контекст" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "не могу да подесим додатне ИБ-ове групе" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "не могу да подесим ефективан гид да се покрене_као гид %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "не могу да подесим гид да се покрене као гид %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "не могу да подесим приоритет процеса" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "не могу да променим администратора на %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "не могу да се пребацим у покрени_као уид (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "не могу да променим директоријум у %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "неочекивани услов завршетка потпроцеса: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "прикључак сигурности %s не подржава привилегије исписивања" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "прикључак сигурности %s не подржава опцију -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "прикључак сигурности %s не подржава опције -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "не могу да променим уид у администратора (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "грешка прикључка: недостаје датотеа списка за уређивање судоа" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: није обична датотека" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: кратак упис" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s је остао неизмењен" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s је непромењен" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "не могу да упишем у %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "садржај сесије уређивања је остао у %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "не могу да прочитам привремену датотеку" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "тту не постоји и није наведен програм за пропуштање" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "није наведен програм за пропуштање, покушајте да подесите SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "не могу да подесим гид у %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "не могу да подесим уид у %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "не могу да покренем %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "не могу да сачувам стандардни улаз" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "не могу да дуп2 стандардни улаз" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "не могу да повратим стандардни улаз" + +#~ msgid "must be setuid root" +#~ msgstr "морате бити сетуид администратор" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "аргумент уз -D мора бити између 1 и 9 укључујући" diff --git a/src/po/sudo.pot b/src/po/sudo.pot new file mode 100644 index 0000000..b0c960e --- /dev/null +++ b/src/po/sudo.pot @@ -0,0 +1,776 @@ +# SOME DESCRIPTIVE TITLE. +# This file is put in the public domain. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr "" + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "" + +#: src/parse_args.c:518 +#, c-format +msgid "" +"Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "" + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "" + +#: src/sudo.c:763 +#, c-format +msgid "" +"effective uid is not %d, is %s on a file system with the 'nosuid' option set " +"or an NFS file system without root privileges?" +msgstr "" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "" diff --git a/src/po/sv.mo b/src/po/sv.mo new file mode 100644 index 0000000..e34914a Binary files /dev/null and b/src/po/sv.mo differ diff --git a/src/po/sv.po b/src/po/sv.po new file mode 100644 index 0000000..ff729ef --- /dev/null +++ b/src/po/sv.po @@ -0,0 +1,757 @@ +# Swedish translation for sudo. +# Copyright (C) 2012 Free Software Foundation, Inc. +# This file is put in the public domain. +# Daniel Nylander , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5-b1\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-03-14 14:20-0400\n" +"PO-Revision-Date: 2012-03-19 12:10+0100\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:105 src/exec_pty.c:616 src/exec_pty.c:948 src/tgetpass.c:227 +#, c-format +msgid "unable to fork" +msgstr "kunde inte grena process" + +#: src/exec.c:252 +#, c-format +msgid "unable to create sockets" +msgstr "kunde inte skapa uttag" + +#: src/exec.c:259 src/exec_pty.c:567 src/exec_pty.c:576 src/exec_pty.c:584 +#: src/exec_pty.c:883 src/exec_pty.c:945 src/tgetpass.c:224 +#, c-format +msgid "unable to create pipe" +msgstr "kunde inte skapa rör" + +#: src/exec.c:340 src/exec_pty.c:1012 src/exec_pty.c:1147 +#, c-format +msgid "select failed" +msgstr "" + +#: src/exec.c:425 +#, c-format +msgid "unable to restore tty label" +msgstr "" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "" + +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:451 src/sudo.c:471 +#: src/sudo.c:478 src/sudo.c:489 src/sudo.c:848 common/alloc.c:85 +#: common/alloc.c:105 common/alloc.c:123 common/alloc.c:145 common/alloc.c:203 +#: common/alloc.c:217 +#, c-format +msgid "unable to allocate memory" +msgstr "kunde inte allokera minne" + +#: src/exec_pty.c:140 +#, c-format +msgid "unable to allocate pty" +msgstr "kunde inte allokera pty" + +#: src/exec_pty.c:609 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "" + +#: src/exec_pty.c:926 +#, c-format +msgid "unable to set controlling tty" +msgstr "" + +#: src/exec_pty.c:1020 +#, c-format +msgid "error reading from signal pipe" +msgstr "fel vid läsning från signalrör" + +#: src/exec_pty.c:1039 +#, c-format +msgid "error reading from pipe" +msgstr "fel vid läsning från rör" + +#: src/exec_pty.c:1055 +#, c-format +msgid "error reading from socketpair" +msgstr "" + +#: src/exec_pty.c:1059 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s måste ägas av uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s får endast vara skrivbar av ägaren" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "kunde inte köra dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: kunde inte hitta symbolen %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: okänd policytyp %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: minst en policyinsticksmodul måste anges" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: stackspill upptäcktes" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "kunde inte öppna uttag" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "argumentet till -C måste vara ett tal större än eller lika med 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "okänd användare: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "du får inte ange flaggorna \"-i\" och \"-s\" samtidigt" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "du får inte ange flaggorna \"-i\" och \"-E\" samtidigt" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "flaggan \"-E\" är inte giltig i redigeringsläget" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "du får inte ange miljövariabler i redigeringsläget" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "the `-U' option may only be used with the `-l' option" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "flaggorna \"-A\" och \"-S\" får inte användas tillsammans" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit stöds inte på denna plattform" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Endast en av flaggorna -e, -h, -i, -K, -l, -s, -v eller -V får anges" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - redigera filer som en annan användare\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - kör ett kommando som en annan användare\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Flaggor:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "använd hjälpprogram för att fråga efter lösenord\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "använd angiven BSD-autentiseringstyp\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "kör kommando i bakgrunden\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "kör kommando med angiven inloggningsklass\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "bevara användarens miljö när kommandot körs\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "redigera filer istället för att köra ett kommando\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "kör kommando som angiven grupp\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "ställ in HOME-variabeln till målanvändarens hemkatalog.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "visa hjälpmeddelande och avsluta\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "kör ett inloggningsskal som målanvändaren\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "ta bort tidsstämpelfilen helt\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "lista användarens tillgängliga kommandon\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "använd angiven lösenordsprompt\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "skapa SELinux-säkerhetskontext med angiven roll\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "läs lösenord från standard in\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "kör ett skal som målanvändaren\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "kör kommando (eller redigera fil) som angiven användare\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "visa versionsinformation och avsluta\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "uppdatera användarens tidsstämpel utan att köra ett kommando\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "" + +#: src/selinux.c:76 +#, c-format +msgid "unable to open audit system" +msgstr "" + +#: src/selinux.c:84 +#, c-format +msgid "unable to send audit message" +msgstr "" + +#: src/selinux.c:112 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "" + +#: src/selinux.c:117 +#, c-format +msgid "%s changed labels" +msgstr "" + +#: src/selinux.c:122 +#, c-format +msgid "unable to restore context for %s" +msgstr "" + +#: src/selinux.c:162 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "" + +#: src/selinux.c:171 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "" + +#: src/selinux.c:178 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "" + +#: src/selinux.c:185 +#, c-format +msgid "unable to set new tty context" +msgstr "" + +#: src/selinux.c:195 src/selinux.c:208 src/sudo.c:337 common/sudo_conf.c:328 +#, c-format +msgid "unable to open %s" +msgstr "kunde inte öppna %s" + +#: src/selinux.c:251 +#, c-format +msgid "you must specify a role for type %s" +msgstr "du måste ange en roll för typen %s" + +#: src/selinux.c:257 +#, c-format +msgid "unable to get default type for role %s" +msgstr "kunde inte få tag på standardtyp för rollen %s" + +#: src/selinux.c:275 +#, c-format +msgid "failed to set new role %s" +msgstr "misslyckades med att ställa in nya rollen %s" + +#: src/selinux.c:279 +#, c-format +msgid "failed to set new type %s" +msgstr "misslyckades med att ställa in nya typen %s" + +#: src/selinux.c:288 +#, c-format +msgid "%s is not a valid context" +msgstr "%s är inte en giltig kontext" + +#: src/selinux.c:323 +#, c-format +msgid "failed to get old_context" +msgstr "misslyckades med att få tag på old_context" + +#: src/selinux.c:329 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "" + +#: src/selinux.c:341 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "" + +#: src/selinux.c:372 +#, c-format +msgid "unable to set exec context to %s" +msgstr "kunde inte ställa in körkontext till %s" + +#: src/selinux.c:379 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "kräver minst ett argument" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "kunde inte köra %s" + +#: src/sudo.c:191 +#, c-format +msgid "must be setuid root" +msgstr "måste vara setuid root" + +#: src/sudo.c:214 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo version %s\n" + +#: src/sudo.c:216 +#, c-format +msgid "Configure options: %s\n" +msgstr "Konfigurationsflaggor: %s\n" + +#: src/sudo.c:221 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "ödesdigert fel, kunde inte läsa in insticksmoduler" + +#: src/sudo.c:229 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "" + +#: src/sudo.c:284 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "" + +#: src/sudo.c:312 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "" + +#: src/sudo.c:406 +#, c-format +msgid "unable to get group vector" +msgstr "" + +#: src/sudo.c:447 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "okänt uid %u: vem är du?" + +#: src/sudo.c:790 +#, c-format +msgid "resource control limit has been reached" +msgstr "" + +#: src/sudo.c:793 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "användaren \"%s\" är inte medlem av projektet \"%s\"" + +#: src/sudo.c:797 +#, c-format +msgid "the invoking task is final" +msgstr "" + +#: src/sudo.c:800 +#, c-format +msgid "could not join project \"%s\"" +msgstr "kunde inte gå med i projektet \"%s\"" + +#: src/sudo.c:805 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "" + +#: src/sudo.c:809 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "angiven resurspool finns inte för projektet \"%s\"" + +#: src/sudo.c:813 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "" + +#: src/sudo.c:819 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "setproject misslyckades för projektet \"%s\"" + +#: src/sudo.c:821 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "" + +#: src/sudo.c:892 +#, c-format +msgid "unknown login class %s" +msgstr "okänd inloggningsklass %s" + +#: src/sudo.c:906 src/sudo.c:909 +#, c-format +msgid "unable to set user context" +msgstr "kunde inte ställa in användarens kontext" + +#: src/sudo.c:924 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "" + +#: src/sudo.c:931 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "kunde inte ställa in effektiv gid till runas gid %u" + +#: src/sudo.c:937 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "kunde inte ställa in gid för runas gid %u" + +#: src/sudo.c:944 +#, c-format +msgid "unable to set process priority" +msgstr "kunde inte ställa in processprioritet" + +#: src/sudo.c:952 +#, c-format +msgid "unable to change root to %s" +msgstr "kunde inte ändra rot till %s" + +#: src/sudo.c:959 src/sudo.c:965 src/sudo.c:971 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "kunde inte ändra till runas uid (%u, %u)" + +#: src/sudo.c:985 +#, c-format +msgid "unable to change directory to %s" +msgstr "kunde inte ändra katalog till %s" + +#: src/sudo.c:1058 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "" + +#: src/sudo.c:1119 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "" + +#: src/sudo.c:1131 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "" + +#: src/sudo.c:1143 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "kunde inte ändra uid till root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: inte en vanlig fil" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: kort skrivning" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s lämnad oförändrad" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s oförändrad" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "kunde inte skriva till %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "innehåll av redigeringssession finns kvar i %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "kunde inte läsa temporärfilen" + +#: src/tgetpass.c:96 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "ingen tty finns tillgänglig och inget askpass-program angivet" + +#: src/tgetpass.c:105 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "inget askpass-program angivet, prova att ställ in SUDO_ASKPASS" + +#: src/tgetpass.c:237 +#, c-format +msgid "unable to set gid to %u" +msgstr "kunde inte ställa in gid till %u" + +#: src/tgetpass.c:241 +#, c-format +msgid "unable to set uid to %u" +msgstr "kunde inte ställa in uid till %u" + +#: src/tgetpass.c:246 +#, c-format +msgid "unable to run %s" +msgstr "kunde inte köra %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "kunde inte spara standard in" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "kunde inte öppna användardatabasen" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "kunde inte växla till registret \"%s\" för %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "kunde inte återställa registret" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "internt fel, försökte med emalloc(0)" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "internt fel, försökte med emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "internt fel, stackspill i emalloc2()" + +#: common/alloc.c:119 +msgid "internal error, tried to erealloc(0)" +msgstr "internt fel, försökte med erealloc(0)" + +#: common/alloc.c:138 +msgid "internal error, tried to erealloc3(0)" +msgstr "internt fel, försökte med erealloc3(0)" + +#: common/alloc.c:140 +msgid "internal error, erealloc3() overflow" +msgstr "internt fel, stackspill i erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "kunde inte ta status på %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s är inte en vanlig fil" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s ägs av uid %u, ska vara %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s är skrivbar för alla" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s är skrivbar för gruppen" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Okänd signal" diff --git a/src/po/uk.mo b/src/po/uk.mo new file mode 100644 index 0000000..89518f4 Binary files /dev/null and b/src/po/uk.mo differ diff --git a/src/po/uk.po b/src/po/uk.po new file mode 100644 index 0000000..9c8cbc0 --- /dev/null +++ b/src/po/uk.po @@ -0,0 +1,786 @@ +# Ukrainian translation for sudo. +# This file is put in the public domain. +# +# Yuri Chornoivan , 2011, 2012. +msgid "" +msgstr "" +"Project-Id-Version: sudo 1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 12:02+0300\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 1.5\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "не вдалося відкрити userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "не вдалося перемкнутися на регістр «%s» для %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "не вдалося відновити регістр" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "внутрішня помилка, спроба виконання emalloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "не вдалося отримати потрібний об’єм пам’яті" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "внутрішня помилка, спроба виконання emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "внутрішня помилка, переповнення emalloc2()" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "внутрішня помилка, спроба виконання ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "внутрішня помилка, переповнення ecalloc()" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "внутрішня помилка, спроба виконання erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "внутрішня помилка, спроба виконання erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "внутрішня помилка, переповнення erealloc3()" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "не вдалося виконати stat для %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s не є звичайним файлом" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s належить uid %u, має належати %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "Запис до «%s» можливий для довільного користувача" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "Запис до «%s» може здійснювати будь-який користувач з групи" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "не вдалося відкрити %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Невідомий сигнал" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "не вдалося виконати ініціалізацію сеансу через додаток правил" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "не вдалося створити відгалуження" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "не вдалося створити сокети" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "не вдалося створити канал" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "спроба виконати select зазнала невдачі" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "не вдалося відновити позначку tty" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "не вдалося вилучити PRIV_PROC_EXEC з PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "не вдалося розмістити pty" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "не вдалося перевести термінал у режим без обробки" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "не вдалося встановити tty для керування" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "помилка під час спроби читання з каналу сигналів" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "помилка під час спроби читання з каналу" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "помилка під час спроби читання з пари сокетів" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "неочікуваний тип відповіді на зворотному каналі: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s має належати користувачеві з uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s має бути доступним до запису лише для власника" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "не вдалося виконати dlopen для %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: не вдалося знайти символ %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: невідомий тип правил %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: несумісна основна версія правил %d, мало бути — %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: можна завантажувати лише єдиний додаток правил" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: мало бути вказано принаймні один додаток правил" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "до додатка правил %s не включено метод check_policy" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: виявлено переповнення" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "не вдалося відкрити сокет" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "аргументом параметра -C mмає бути число не менше за 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "невідомий користувач: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "не можна одночасно вказувати параметри «-i» і «-s»" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "не можна одночасно вказувати параметри «-i» і «-E»" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "не можна використовувати «-E» у режимі редагування" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "не можна вказувати змінні середовища у режимі редагування" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "параметр «-U» можна використовувати лише разом з параметром «-l»" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "параметри «-A» і «-S» не можна використовувати одночасно" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "підтримки sudoedit для цієї платформи не передбачено" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Можна використовувати лише такі параметри: -e, -h, -i, -K, -l, -s, -v та -V" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s — редагувати файли від імені іншого користувача\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s — виконати команду від імені іншого користувача\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Параметри:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "використовувати допоміжну програму для запитів щодо пароля\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "використовувати вказаний тип розпізнавання BSD\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "виконати команду у фоновому режимі\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "закрити всі дескриптори файлів >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "виконати команду з вказаним класом доступу\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "зберегти середовище користувача на час виконання команди\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "редагувати файли замість виконання команди\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "виконати команду від імені вказаної групи користувачів\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "встановити для змінної HOME значення домашнього каталогу вказаного користувача.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "показати довідкове повідомлення і завершити роботу\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "запустити оболонку для входу до системи від імені вказаного користувача\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "повністю вилучити файл часового штампу\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "позбавити чинності файл часового штампу\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "показати список доступних користувачеві команд\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "неінтерактивний режим, не просити користувача відповідати на питання\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "зберегти вектор групи, не встановлювати вектор вказаного користувача\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "використовувати вказаний інструмент отримання паролів\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "створити контекст захисту SELinux з вказаною роллю\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "прочитати пароль зі стандартного джерела вхідних даних\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "запустити командну оболонку від імені вказаного користувача\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "у списку показати права доступу вказаного користувача\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "виконати команду (або редагувати файл) від імені вказаного користувача\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "показати дані щодо версії і завершити роботу\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "оновити штамп часу користувача без виконання команди\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "зупинити обробку аргументів командного рядка\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "не вдалося відкрити систему аудита" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "не вдалося надіслати повідомлення аудита" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "не вдалося виконати fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s змінено позначки" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "не вдалося відновити контекст %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "не вдалося відкрити %s, не змінюємо позначки tty" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "не вдалося отримати поточний контекст tty, не змінюємо позначки tty" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "не вдалося отримати новий контекст tty, не змінюємо позначки tty" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "не вдалося встановити новий контекст tty" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "вам слід вказати роль для типу %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "не вдалося отримати типовий тип для ролі %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "не вдалося встановити нову роль %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "не вдалося встановити новий тип %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s не є коректним контекстом" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "не вдалося отримати old_context" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "не вдалося визначити режим примушення." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "не вдалося налаштувати контекст tty для %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "не вдалося встановити контекст виконання у значення %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "не вдалося встановити контекст ключа створення у значення %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "потребує принаймні одного аргументу" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "не вдалося виконати %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Версія sudo %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Параметри налаштування: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "критична помилка, не вдалося завантажити додатки" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "не вдалося ініціалізувати додаток правил" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "помилка під час спроби ініціалізації додатка введення/виведення даних %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "неочікуваний режим sudo 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "не вдалося отримати вектор групи" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "невідомий uid %u: хто ви такий?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s має належати користувачеві з uid %d, крім того, має бути встановлено біт setuid" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "поточним uid не є %d. Можливо %s зберігається у файловій системі зі встановленим параметром «nosuid» або у файловій системі NFS без прав доступу root?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "поточним uid не є %d, sudo встановлено з ідентифікатором користувача root?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "перевищено обмеження керування ресурсами" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "користувач «%s» не є учасником проекту «%s»" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "викликане завдання є завершальним" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "не вдалося приєднатися до проекту «%s»" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "для проекту «%s» не існує сховища ресурсів, яке приймає типові прив’язки" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "у проекті «%s» не існує вказаного сховища ресурсів" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "не вдалося виконати прив’язку до типового сховища ресурсів проекту «%s»" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "помилка під час виконання setproject для проекту «%s»" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "попередження, помилка призначення керування ресурсами проекту «%s»" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "невідомий клас входу %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "не вдалося встановити контекст користувача" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "не вдалося встановити ідентифікатори додаткових груп" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "не вдалося встановити ефективний ідентифікатор групи для ідентифікатора групи запуску %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "не вдалося встановити ідентифікатор групи для ідентифікатора групи запуску %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "не вдалося встановити пріоритет процесу" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "не вдалося змінити root на %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "не вдалося змінити uid користувача, від імені якого відбувається виконання (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "не вдалося змінити каталог на %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "неочікувана умова переривання дочірнього процесу: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "у додатку правил %s не передбачено підтримки побудови списку прав доступу" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "у додатку правил %s не передбачено підтримки параметра -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "у додатку правил %s не передбачено підтримки параметрів -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "не вдалося змінити значення uid на значення root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "помилка додатка: не вистачає списку файлів для sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: не є звичайним файлом" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: короткий запис" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s залишено без змін" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s не змінено" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "не вдалося виконати запис до %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "дані сеансу редагування залишилися у %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "не вдалося виконати читання з файла тимчасових даних" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "не виявлено tty і не вказано програми askpass" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "не вказано програми askpass, спробуйте встановити значення змінної SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "не вдалося встановити gid у значення %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "не вдалося встановити uid у значення %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "не вдалося виконати %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "не вдалося зберегти stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "не вдалося виконати dup2 для stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "не вдалося відновити stdin" + +#~ msgid "must be setuid root" +#~ msgstr "має виконуватися з setuid root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "аргументом параметра -D має бути число з діапазону від 1 до 9, включно" diff --git a/src/po/vi.mo b/src/po/vi.mo new file mode 100644 index 0000000..af73915 Binary files /dev/null and b/src/po/vi.mo differ diff --git a/src/po/vi.po b/src/po/vi.po new file mode 100644 index 0000000..fbbf493 --- /dev/null +++ b/src/po/vi.po @@ -0,0 +1,787 @@ +# Vietnamese translation for sudo. +# Copyright © 2012 Free Software Foundation, Inc. +# This file is distributed under the same license as the sudo package. +# Trần Ngọc Quân , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo-1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-30 07:00+0700\n" +"Last-Translator: Trần Ngọc Quân \n" +"Language-Team: Vietnamese \n" +"Language: vi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=1;\n" +"X-Generator: LocFactoryEditor 1.8\n" +"X-Poedit-Language: Vietnamese\n" +"X-Poedit-Country: VIET NAM\n" +"X-Poedit-SourceCharset: utf-8\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "không thể mở userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "không thể chuyển đến sổ đăng ký \"%s\" cho %s" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "không thể phục hồi sổ đăng ký" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "lỗi nội bộ, dùng thử erealloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "không thể cấp phát vùng nhớ" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "lỗi nội bộ, dùng thử erealloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "lỗi nội bộ, erealloc2() bị tràn" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "lỗi nội bộ, đã dùng thử ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "lỗi nội bộ, ecalloc() bị tràn" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "lỗi nội bộ, dùng thử erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "lỗi nội bộ, dùng thử erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "lỗi nội bộ, erealloc3() bị tràn" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "không thể lấy trạng thái về %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s không phải tập tin thường" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s được sở hữu bởi uid %u, nên là %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s ai ghi cũng được" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s là nhóm có thể ghi" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "không mở được %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "Không hiểu tín hiệu" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ": " + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "phần bổ xung chính sách gặp lỗi khi khởi tạo phiên" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "không thể tạo tiến trình con" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "không thể tạo sockets" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "không tạo được đường ống pipe" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "lựa chọn gặp lỗi" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "không thể phục hồi nhãn cho tty" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "không thể xóa bỏ PRIV_PROC_EXEC từ PRIV_LIMIT" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "không thể phân bổ pty" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "không thể đặt thiết bị cuối sang chế độ raw" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "không thể đặt điều khiển cho tty" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "lỗi khi đọc từ đường ống dẫn tín hiệu" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "gặp lỗi khi đọc từ một đường ống dẫn lệnh" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "gặp lỗi khi đọc từ socketpair" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "kiểu trả về không như mong đợi từ backchannel: %d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s: %s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s: %s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s phải được sở hữu bởi uid %d" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s phải là những thứ chỉ có thể ghi bởi chủ sở hữu" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "không thể dlopen %s: %s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s: không thể tìm thấy liên kết tượng trưng (symbol) %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s: không hiểu kiểu chính sách %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s: chính sách không tương thích với phiên bản %d, mong chờ %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s: chỉ có một phần bổ xung chính sách được tải lên thôi" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s: phải xác định ít nhất một phần bổ xung chính sách" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "phần bổ xung chính sách %s không bao gồm phương thức kiểm tra chính sách" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces: bị tràn" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "không mở được socket" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "đối số cho -C phải là một số lớn hơn hoặc bằng 3" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "không hiểu người dùng: %s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "bạn không thể chỉ định cả hai tùy chọn `-i' và `-s'" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "bạn không thể chỉ định cả hai tùy chọn `-i' và `-E'" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "tùy chọn `-E' không hợp lệ trong chế độ chỉnh sửa" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "bạn có lẽ không được chỉ định biến môi trường trong chế độ soạn thảo" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "tùy chọn `-U' chỉ sử dụng cùng với tùy chọn `-l'" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "tùy chọn `-A' và `-S' không thể dùng cùng một lúc với nhau" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "sudoedit không được hỗ trợ trên nền tảng này" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "Chỉ có một trong số các tùy chọn -e, -h, -i, -K, -l, -s, -v hay -V được chỉ định" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - sửa chữa các tập tin trên danh nghĩa người dùng khác\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - thực hiện câu lệnh với người dùng khác\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"Tùy chọn:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "sử dụng chương trình trợ giúp cho hỏi đáp mật khẩu\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "sử dụng kiểu xác thực BSD được chỉ ra\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "chạy lệnh ở chế độ nền\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "đóng tất cả các mô tả của tập tin >= fd\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "chạy lệnh với một lớp đăng nhập được chỉ ra\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "ngăn ngừa môi trường người dùng khi thi hành lệnh\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "chỉnh sửa các tập tin thay vì chạy lệnh\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "thực hiện câu lệnh như là nhóm được chỉ định\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "đặt biến HOME cho thư mục home của người dùng đích.\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "hiển thị trợ giúp này rồi thoát\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "chạy shell đăng nhập như là người dùng đích\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "gỡ bỏ timestamp tập tin\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "làm mất hiệu lực timestamp của tập tin\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "danh sách các câu lệnh người dùng có thể sử dụng\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "chế độ không tương tác, không hỏi tên tài khoản người dùng\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "ngăn ngừa véc tơ nhóm thay vì các cài đặt cho đích\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "sử dụng nhắc nhập mật khẩu.\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "tạo ngữ cảnh an ninh SELinux với vai trò đã được chỉ định\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "đọc mật khẩu từ đầu vào tiêu chuẩn\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "chạy shell như là người dùng đích\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "khi liệt kê, liệt kê các đặc quyền của người dùng\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "chạy lệnh (hay sửa chữa tập tin) trên tư cách của người dùng đã chỉ định\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "hiển thị thông tin phiên bản rồi thoát\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "cập nhật dấu thời gian (timestamp) của người dùng mà không chạy một lệnh\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "dừng việc xử lý đối số dòng lệnh\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "không thể mở hệ thống audit" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "không thể gửi thông tin audit" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "không thể fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s nhãn đã thay đổi" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "Không thể phục hồi ngữ cảnh cho %s" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "không thể mở %s, không phải là tty liên quan" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "không thể lấy ngữ cảnh tty hiện hành, không phải là tty có liên quan" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "không thể lấy ngữ cảnh tty mới, không phải là tty có liên quan" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "không thể đặt ngữ cảnh tty mới" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "bạn phải chỉ định một kiểu vai trò cho %s" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "không thể lấy kiểu mặc định cho vai trò %s" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "lỗi khi đặt đặt vai trò mới %s" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "lỗi khi đặt kiểu mới %s" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s không phải là một ngữ cảnh hợp lệ" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "lỗi lấy ngữ cảnh cũ" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "không thể xác định rõ chế độ ép buộc." + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "không thể cài đặt ngữ cảnh tty mới cho %s" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "không thể đặt ngữ cảnh bảo thực thi thành %s" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "không thể đặt ngữ cảnh tạo khóa thành %s" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "cần thiết ít nhất một đối số" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "không thể thực thi %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Phiên bản sudo %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "Cấu hình các tùy chọn: %s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "lỗi nghiêm trọng, không thể tải plugins" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "không thể khởi tạo phần bổ xung chính sách" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "Gặp lỗi khi nạp phần bổ sung I/O %s" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "không mong đợi chế độ sudo 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "không thể lấy véc tơ nhóm" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "không hiểu uid %u: bạn là ai?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s phải được sở hữu bởi uid %d và bít setuid phải được đặt" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "uid hữu hiệu thì không là %d, %s trên hệ thống tập tin với tuỳ chọn 'nosuid' được đặt, hay một hệ thống tập tin NFS không có đặc quyền của root có phải vậy không?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "uid hữu hiệu thì không là %d, chương trình sudo có được cài với setuid root không?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "giới hạn điều khiển tài nguyên đã tới hạn" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "người dùng \"%s\" không phải là thành viên của dự án \"%s\"" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "tác vụ được gọi đã kết thúc" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "không thể gia nhập dự án \"%s\"" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "không kho tài nguyên chung nào được thừa nhận ràng buộc đã tồn tại sẵn cho dự án \"%s\"" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "nguồn tài nguyên chung được chỉ ra chưa tồn tại cho dự án \"%s\"" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "không thể buộc phần tài nguyên chung mặc định cho dự án \"%s\"" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "đặt dự án cho dự án \"%s\" gặp lỗi" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "cảnh báo, nguồn điều khiển gán gặp lỗi cho dự án \"%s\"" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "không rõ lớp đăng nhập %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "không thể đặt ngữ cảnh người dùng" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "không thể đặt nhóm phụ IDs" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "không thể đặt hiệu ứng gid chạy như là gid %u" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "không thể thay đổi gid thành runas gid %u" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "không thể đặt ưu tiên cho quá trình" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "không thể chuyển đổi thư mục gốc thành %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "không thể thay đổi thành runas uid (%u, %u)" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "không thể thay đổi thư mục thành %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "biểu thức điều kiện con kết thúc không như mong đợi: %d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "phần bổ xung chính sách %s không hỗ trợ liệt kê đặc quyền" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "phần bổ xung chính sách %s không hỗ trợ tùy chọn -v" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "phần bổ xung chính sách %s không hỗ trợ tùy chọn -k/-K" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "không thể thay đổi uid thành root (%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "lỗi phần bổ xung: thiếu danh sách tập tin cho sudoedit" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s: không phải là tập tin thường" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s: ghi ngắn" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s còn lại chưa thay đổi" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s không thay đổi" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "không thể ghi vào %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "nội dung của phiên chỉnh sửa chỉ còn %s" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "Không đọc tập tin tạm thời" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "không có tty hiện diện và không có chương trình hỏi mật khẩu nào được chỉ ra" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "không có chương trình hỏi mật khẩu nào được chỉ ra, hãy thử cài đặt SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "không thể đặt gid thành %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "không thể đặt uid thành %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "không thể chạy %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "không thể ghi lại stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "không thể dup2 stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "không thể phục hồi stdin" + +#~ msgid "must be setuid root" +#~ msgstr "phải được đặt setuid của root" diff --git a/src/po/zh_CN.mo b/src/po/zh_CN.mo new file mode 100644 index 0000000..ab0e22e Binary files /dev/null and b/src/po/zh_CN.mo differ diff --git a/src/po/zh_CN.po b/src/po/zh_CN.po new file mode 100644 index 0000000..a5a5862 --- /dev/null +++ b/src/po/zh_CN.po @@ -0,0 +1,785 @@ +# Chinese simplified translation for sudo. +# sudo 的简体中文翻译。 +# This file is put in the public domain. +# Wylmer Wang , 2011, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: sudo-1.8.5rc3\n" +"Report-Msgid-Bugs-To: http://www.sudo.ws/bugs\n" +"POT-Creation-Date: 2012-04-24 13:41-0400\n" +"PO-Revision-Date: 2012-04-29 17:01+0800\n" +"Last-Translator: Wylmer Wang \n" +"Language-Team: Chinese (simplified) \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: common/aix.c:149 +#, c-format +msgid "unable to open userdb" +msgstr "无法打开 userdb" + +#: common/aix.c:152 +#, c-format +msgid "unable to switch to registry \"%s\" for %s" +msgstr "无法为 %2$s 切换到注册表“%1$s”" + +#: common/aix.c:169 +#, c-format +msgid "unable to restore registry" +msgstr "无法恢复注册表" + +#: common/alloc.c:82 +msgid "internal error, tried to emalloc(0)" +msgstr "内部错误,试图 emalloc(0)" + +#: common/alloc.c:85 common/alloc.c:105 common/alloc.c:127 common/alloc.c:146 +#: common/alloc.c:168 common/alloc.c:192 common/alloc.c:256 common/alloc.c:270 +#: src/exec_common.c:111 src/parse_args.c:432 src/sudo.c:456 src/sudo.c:482 +#: src/sudo.c:489 src/sudo.c:500 src/sudo.c:737 +#, c-format +msgid "unable to allocate memory" +msgstr "无法分配内存" + +#: common/alloc.c:99 +msgid "internal error, tried to emalloc2(0)" +msgstr "内部错误,试图 emalloc2(0)" + +#: common/alloc.c:101 +msgid "internal error, emalloc2() overflow" +msgstr "内部错误,emalloc2() 溢出" + +#: common/alloc.c:120 +msgid "internal error, tried to ecalloc(0)" +msgstr "内部错误,试图 ecalloc(0)" + +#: common/alloc.c:123 +msgid "internal error, ecalloc() overflow" +msgstr "内部错误,ecalloc() 溢出" + +#: common/alloc.c:142 +msgid "internal error, tried to erealloc(0)" +msgstr "内部错误,试图 erealloc(0)" + +#: common/alloc.c:161 common/alloc.c:185 +msgid "internal error, tried to erealloc3(0)" +msgstr "内部错误,试图 erealloc3(0)" + +#: common/alloc.c:163 common/alloc.c:187 +msgid "internal error, erealloc3() overflow" +msgstr "内部错误,erealloc3() 错误" + +#: common/sudo_conf.c:306 +#, c-format +msgid "unable to stat %s" +msgstr "无法 stat %s" + +#: common/sudo_conf.c:309 +#, c-format +msgid "%s is not a regular file" +msgstr "%s 不是常规文件" + +#: common/sudo_conf.c:312 +#, c-format +msgid "%s is owned by uid %u, should be %u" +msgstr "%s 属于用户 ID %u,应为 %u" + +#: common/sudo_conf.c:316 +#, c-format +msgid "%s is world writable" +msgstr "%s 可被任何人写" + +#: common/sudo_conf.c:319 +#, c-format +msgid "%s is group writable" +msgstr "%s 可被用户组写" + +#: common/sudo_conf.c:328 src/selinux.c:196 src/selinux.c:209 src/sudo.c:331 +#, c-format +msgid "unable to open %s" +msgstr "打不开 %s" + +#: compat/strsignal.c:47 +msgid "Unknown signal" +msgstr "未知信号" + +#: src/error.c:82 src/error.c:86 +msgid ": " +msgstr ":" + +#: src/exec.c:107 src/exec_pty.c:628 +#, c-format +msgid "policy plugin failed session initialization" +msgstr "策略插件会话初始化失败" + +#: src/exec.c:112 src/exec_pty.c:633 src/exec_pty.c:967 src/tgetpass.c:221 +#, c-format +msgid "unable to fork" +msgstr "无法执行 fork" + +#: src/exec.c:259 +#, c-format +msgid "unable to create sockets" +msgstr "无法创建套接字" + +#: src/exec.c:266 src/exec_pty.c:572 src/exec_pty.c:581 src/exec_pty.c:589 +#: src/exec_pty.c:902 src/exec_pty.c:964 src/tgetpass.c:218 +#, c-format +msgid "unable to create pipe" +msgstr "无法创建管道" + +#: src/exec.c:351 src/exec_pty.c:1029 src/exec_pty.c:1167 +#, c-format +msgid "select failed" +msgstr "select 失败" + +#: src/exec.c:441 +#, c-format +msgid "unable to restore tty label" +msgstr "无法恢复终端标签" + +#: src/exec_common.c:69 +#, c-format +msgid "unable to remove PRIV_PROC_EXEC from PRIV_LIMIT" +msgstr "无法从 PRIV_LIMIT 中移除 PRIV_PROC_EXEC" + +#: src/exec_pty.c:144 +#, c-format +msgid "unable to allocate pty" +msgstr "无法分配伪终端" + +#: src/exec_pty.c:619 +#, c-format +msgid "unable to set terminal to raw mode" +msgstr "无法将终端设为原始模式" + +#: src/exec_pty.c:945 +#, c-format +msgid "unable to set controlling tty" +msgstr "无法设置控制终端" + +#: src/exec_pty.c:1038 +#, c-format +msgid "error reading from signal pipe" +msgstr "从单管道读取出错" + +#: src/exec_pty.c:1059 +#, c-format +msgid "error reading from pipe" +msgstr "从管道读取出错" + +#: src/exec_pty.c:1075 +#, c-format +msgid "error reading from socketpair" +msgstr "从套接字对读取出错" + +#: src/exec_pty.c:1079 +#, c-format +msgid "unexpected reply type on backchannel: %d" +msgstr "联络通道的回应类型异常:%d" + +#: src/load_plugins.c:79 +#, c-format +msgid "%s: %s" +msgstr "%s:%s" + +#: src/load_plugins.c:85 +#, c-format +msgid "%s%s: %s" +msgstr "%s%s:%s" + +#: src/load_plugins.c:95 +#, c-format +msgid "%s must be owned by uid %d" +msgstr "%s 必须属于用户 ID %d(的用户)" + +#: src/load_plugins.c:99 +#, c-format +msgid "%s must be only be writable by owner" +msgstr "%s 必须只对其所有者可写" + +#: src/load_plugins.c:106 +#, c-format +msgid "unable to dlopen %s: %s" +msgstr "无法 dlopen %s:%s" + +#: src/load_plugins.c:111 +#, c-format +msgid "%s: unable to find symbol %s" +msgstr "%s:找不到符号 %s" + +#: src/load_plugins.c:117 +#, c-format +msgid "%s: unknown policy type %d" +msgstr "%s:未知的策略类型 %d" + +#: src/load_plugins.c:121 +#, c-format +msgid "%s: incompatible policy major version %d, expected %d" +msgstr "%s:不兼容的策略主版本号 %d,应为 %d" + +#: src/load_plugins.c:128 +#, c-format +msgid "%s: only a single policy plugin may be loaded" +msgstr "%s:只能加载一个策略插件" + +#: src/load_plugins.c:148 +#, c-format +msgid "%s: at least one policy plugin must be specified" +msgstr "%s:至少要指定一个策略插件" + +#: src/load_plugins.c:153 +#, c-format +msgid "policy plugin %s does not include a check_policy method" +msgstr "策略插件 %s 不包含 check_policy 方法" + +#: src/net_ifs.c:157 src/net_ifs.c:166 src/net_ifs.c:178 src/net_ifs.c:187 +#: src/net_ifs.c:298 src/net_ifs.c:322 +#, c-format +msgid "load_interfaces: overflow detected" +msgstr "load_interfaces:检测到溢出" + +#: src/net_ifs.c:227 +#, c-format +msgid "unable to open socket" +msgstr "无法打开套接字" + +#: src/parse_args.c:187 +#, c-format +msgid "the argument to -C must be a number greater than or equal to 3" +msgstr "-C 选项的参数必须是一个大于等于 3 的数字" + +#: src/parse_args.c:276 +#, c-format +msgid "unknown user: %s" +msgstr "未知用户:%s" + +#: src/parse_args.c:335 +#, c-format +msgid "you may not specify both the `-i' and `-s' options" +msgstr "您不能同时指定“-i”和“-s”选项" + +#: src/parse_args.c:339 +#, c-format +msgid "you may not specify both the `-i' and `-E' options" +msgstr "您不能同时指定“-i”和“-E”选项" + +#: src/parse_args.c:349 +#, c-format +msgid "the `-E' option is not valid in edit mode" +msgstr "“-E”选项在编辑模式中无效" + +#: src/parse_args.c:351 +#, c-format +msgid "you may not specify environment variables in edit mode" +msgstr "在编辑模式中您不能指定环境变量" + +#: src/parse_args.c:359 +#, c-format +msgid "the `-U' option may only be used with the `-l' option" +msgstr "“-U”选项只能与“-l”选项一起使用" + +#: src/parse_args.c:363 +#, c-format +msgid "the `-A' and `-S' options may not be used together" +msgstr "“-A”和“-S”选项不可同时使用" + +#: src/parse_args.c:445 +#, c-format +msgid "sudoedit is not supported on this platform" +msgstr "此平台不支持 sudoedit" + +#: src/parse_args.c:518 +#, c-format +msgid "Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified" +msgstr "只能指定 -e、-h、-i、-K、-l、-s、-v 或 -V 选项中的一个" + +#: src/parse_args.c:532 +#, c-format +msgid "" +"%s - edit files as another user\n" +"\n" +msgstr "" +"%s - 以其他用户身份编辑文件\n" +"\n" + +#: src/parse_args.c:534 +#, c-format +msgid "" +"%s - execute a command as another user\n" +"\n" +msgstr "" +"%s - 以其他用户身份执行一条命令\n" +"\n" + +#: src/parse_args.c:539 +#, c-format +msgid "" +"\n" +"Options:\n" +msgstr "" +"\n" +"选项:\n" + +#: src/parse_args.c:542 +msgid "use helper program for password prompting\n" +msgstr "使用助手程序进行密码提示\n" + +#: src/parse_args.c:545 +msgid "use specified BSD authentication type\n" +msgstr "使用指定的 BSD 认证类型\n" + +#: src/parse_args.c:547 +msgid "run command in the background\n" +msgstr "在后台运行命令\n" + +#: src/parse_args.c:549 +msgid "close all file descriptors >= fd\n" +msgstr "关闭所有 >= fd 的文件描述符\n" + +#: src/parse_args.c:552 +msgid "run command with specified login class\n" +msgstr "以指定的登录类别运行命令\n" + +#: src/parse_args.c:555 +msgid "preserve user environment when executing command\n" +msgstr "在执行命令时保留用户环境\n" + +#: src/parse_args.c:557 +msgid "edit files instead of running a command\n" +msgstr "编辑文件而非执行命令\n" + +#: src/parse_args.c:559 +msgid "execute command as the specified group\n" +msgstr "以指定的用户组执行命令\n" + +#: src/parse_args.c:561 +msgid "set HOME variable to target user's home dir.\n" +msgstr "将 HOME 变量设为目标用户的主目录。\n" + +#: src/parse_args.c:563 +msgid "display help message and exit\n" +msgstr "显示帮助消息并退出\n" + +#: src/parse_args.c:565 +msgid "run a login shell as target user\n" +msgstr "以目标用户身份运行一个登录 shell\n" + +#: src/parse_args.c:567 +msgid "remove timestamp file completely\n" +msgstr "完全移除时间戳文件\n" + +#: src/parse_args.c:569 +msgid "invalidate timestamp file\n" +msgstr "无效的时间戳文件\n" + +#: src/parse_args.c:571 +msgid "list user's available commands\n" +msgstr "列出用户能执行的命令\n" + +#: src/parse_args.c:573 +msgid "non-interactive mode, will not prompt user\n" +msgstr "非交互模式,将不提示用户\n" + +#: src/parse_args.c:575 +msgid "preserve group vector instead of setting to target's\n" +msgstr "保留组向量,而非设置为目标的组向量\n" + +#: src/parse_args.c:577 +msgid "use specified password prompt\n" +msgstr "使用指定的密码提示\n" + +#: src/parse_args.c:580 src/parse_args.c:588 +msgid "create SELinux security context with specified role\n" +msgstr "以指定的角色创建 SELinux 安全环境\n" + +#: src/parse_args.c:583 +msgid "read password from standard input\n" +msgstr "从标准输入读取密码\n" + +#: src/parse_args.c:585 +msgid "run a shell as target user\n" +msgstr "以目标用户身份运行 shell\n" + +#: src/parse_args.c:591 +msgid "when listing, list specified user's privileges\n" +msgstr "在列表时,列出指定用户的权限\n" + +#: src/parse_args.c:593 +msgid "run command (or edit file) as specified user\n" +msgstr "以指定用户身份运行命令(或编辑文件)\n" + +#: src/parse_args.c:595 +msgid "display version information and exit\n" +msgstr "显示版本信息并退出\n" + +#: src/parse_args.c:597 +msgid "update user's timestamp without running a command\n" +msgstr "更新用户的时间戳而不执行命令\n" + +#: src/parse_args.c:599 +msgid "stop processing command line arguments\n" +msgstr "停止处理命令行参数\n" + +#: src/selinux.c:77 +#, c-format +msgid "unable to open audit system" +msgstr "无法打开审查系统" + +#: src/selinux.c:85 +#, c-format +msgid "unable to send audit message" +msgstr "无法发送审查消息" + +#: src/selinux.c:113 +#, c-format +msgid "unable to fgetfilecon %s" +msgstr "无法 fgetfilecon %s" + +#: src/selinux.c:118 +#, c-format +msgid "%s changed labels" +msgstr "%s 修改了标签" + +#: src/selinux.c:123 +#, c-format +msgid "unable to restore context for %s" +msgstr "无法恢复 %s 的环境" + +#: src/selinux.c:163 +#, c-format +msgid "unable to open %s, not relabeling tty" +msgstr "无法打开 %s,将不重新标记终端" + +#: src/selinux.c:172 +#, c-format +msgid "unable to get current tty context, not relabeling tty" +msgstr "无法获取当前终端的环境,将不重新标记终端" + +#: src/selinux.c:179 +#, c-format +msgid "unable to get new tty context, not relabeling tty" +msgstr "无法获取新终端的环境,将不重新标记终端" + +#: src/selinux.c:186 +#, c-format +msgid "unable to set new tty context" +msgstr "无法设置新终端的环境" + +#: src/selinux.c:252 +#, c-format +msgid "you must specify a role for type %s" +msgstr "您必须为 %s 类型指定一个角色" + +#: src/selinux.c:258 +#, c-format +msgid "unable to get default type for role %s" +msgstr "无法获取 %s 角色的默认类型" + +#: src/selinux.c:276 +#, c-format +msgid "failed to set new role %s" +msgstr "设置新角色 %s 失败" + +#: src/selinux.c:280 +#, c-format +msgid "failed to set new type %s" +msgstr "设置新类型 %s 失败" + +#: src/selinux.c:289 +#, c-format +msgid "%s is not a valid context" +msgstr "%s 不是有效的环境" + +#: src/selinux.c:324 +#, c-format +msgid "failed to get old_context" +msgstr "无法获取 old_context" + +#: src/selinux.c:330 +#, c-format +msgid "unable to determine enforcing mode." +msgstr "无法确定强制模式。" + +#: src/selinux.c:342 +#, c-format +msgid "unable to setup tty context for %s" +msgstr "无法设置 %s 的终端环境" + +#: src/selinux.c:373 +#, c-format +msgid "unable to set exec context to %s" +msgstr "无法向 %s 设置 exec 环境" + +#: src/selinux.c:380 +#, c-format +msgid "unable to set key creation context to %s" +msgstr "无法向 %s 设置键创建环境" + +#: src/sesh.c:70 +#, c-format +msgid "requires at least one argument" +msgstr "要求至少有一个参数" + +#: src/sesh.c:91 +#, c-format +msgid "unable to execute %s" +msgstr "无法执行 %s" + +#: src/sudo.c:211 +#, c-format +msgid "Sudo version %s\n" +msgstr "Sudo 版本 %s\n" + +#: src/sudo.c:213 +#, c-format +msgid "Configure options: %s\n" +msgstr "当前选项:%s\n" + +#: src/sudo.c:218 +#, c-format +msgid "fatal error, unable to load plugins" +msgstr "致命错误,无法加载插件" + +#: src/sudo.c:226 +#, c-format +msgid "unable to initialize policy plugin" +msgstr "无法初始化策略插件" + +#: src/sudo.c:281 +#, c-format +msgid "error initializing I/O plugin %s" +msgstr "初始化 I/O 插件 %s 出错" + +#: src/sudo.c:306 +#, c-format +msgid "unexpected sudo mode 0x%x" +msgstr "异常的 sudo 模式 0x%x" + +#: src/sudo.c:400 +#, c-format +msgid "unable to get group vector" +msgstr "无法获取组向量" + +#: src/sudo.c:452 +#, c-format +msgid "unknown uid %u: who are you?" +msgstr "未知的用户 ID %u:您是?" + +#: src/sudo.c:760 +#, c-format +msgid "%s must be owned by uid %d and have the setuid bit set" +msgstr "%s 必须属于用户 ID %d(的用户)并且设置 setuid 位" + +#: src/sudo.c:763 +#, c-format +msgid "effective uid is not %d, is %s on a file system with the 'nosuid' option set or an NFS file system without root privileges?" +msgstr "有效用户 ID 不是 %d,%s 位于一个设置了“nosuid”选项的文件系统或没有 root 权限的 NFS 文件系统中吗?" + +#: src/sudo.c:769 +#, c-format +msgid "effective uid is not %d, is sudo installed setuid root?" +msgstr "有效用户 ID 不是 %d,sudo 属于 root 并设置了 setuid 位吗?" + +#: src/sudo.c:838 +#, c-format +msgid "resource control limit has been reached" +msgstr "达到了资源控制限制" + +#: src/sudo.c:841 +#, c-format +msgid "user \"%s\" is not a member of project \"%s\"" +msgstr "用户“%s”不是项目“%s”的成员" + +#: src/sudo.c:845 +#, c-format +msgid "the invoking task is final" +msgstr "调用的任务是最终的(final)" + +#: src/sudo.c:848 +#, c-format +msgid "could not join project \"%s\"" +msgstr "无法加入项目“%s”" + +#: src/sudo.c:853 +#, c-format +msgid "no resource pool accepting default bindings exists for project \"%s\"" +msgstr "不存在对应于项目“%s”的、接受默认绑定的资源池" + +#: src/sudo.c:857 +#, c-format +msgid "specified resource pool does not exist for project \"%s\"" +msgstr "指定的对应于项目“%s”的资源池不存在" + +#: src/sudo.c:861 +#, c-format +msgid "could not bind to default resource pool for project \"%s\"" +msgstr "无法为项目“%s”绑定到默认的资源池" + +#: src/sudo.c:867 +#, c-format +msgid "setproject failed for project \"%s\"" +msgstr "对项目“%s”执行 setproject 失败" + +#: src/sudo.c:869 +#, c-format +msgid "warning, resource control assignment failed for project \"%s\"" +msgstr "警告,对项目“%s”的资源控制分配失败" + +#: src/sudo.c:917 +#, c-format +msgid "unknown login class %s" +msgstr "未知的登录类别 %s" + +#: src/sudo.c:931 src/sudo.c:934 +#, c-format +msgid "unable to set user context" +msgstr "无法设置用户环境" + +#: src/sudo.c:946 +#, c-format +msgid "unable to set supplementary group IDs" +msgstr "无法设置补充组 ID" + +#: src/sudo.c:953 +#, c-format +msgid "unable to set effective gid to runas gid %u" +msgstr "无法设置有效组 ID 来以组 ID %u 运行" + +#: src/sudo.c:959 +#, c-format +msgid "unable to set gid to runas gid %u" +msgstr "无法设置组 ID 来以组 ID %u 运行" + +#: src/sudo.c:966 +#, c-format +msgid "unable to set process priority" +msgstr "无法设置进程优先级" + +#: src/sudo.c:974 +#, c-format +msgid "unable to change root to %s" +msgstr "无法从 root 切换到 %s" + +#: src/sudo.c:981 src/sudo.c:987 src/sudo.c:993 +#, c-format +msgid "unable to change to runas uid (%u, %u)" +msgstr "无法切换到以用户 ID(%u,%u)运行" + +#: src/sudo.c:1007 +#, c-format +msgid "unable to change directory to %s" +msgstr "无法将目录切换到 %s" + +#: src/sudo.c:1079 +#, c-format +msgid "unexpected child termination condition: %d" +msgstr "异常的子进程终止条件:%d" + +#: src/sudo.c:1140 +#, c-format +msgid "policy plugin %s does not support listing privileges" +msgstr "策略插件 %s 不支持列出权限" + +#: src/sudo.c:1152 +#, c-format +msgid "policy plugin %s does not support the -v option" +msgstr "策略插件 %s不支持 -v 选项" + +#: src/sudo.c:1164 +#, c-format +msgid "policy plugin %s does not support the -k/-K options" +msgstr "策略插件 %s 不支持 -k/-K 选项" + +#: src/sudo_edit.c:111 +#, c-format +msgid "unable to change uid to root (%u)" +msgstr "无法将用户 ID 切换到 root(%u)" + +#: src/sudo_edit.c:143 +#, c-format +msgid "plugin error: missing file list for sudoedit" +msgstr "插件错误:缺少 sudoedit 的文件列表" + +#: src/sudo_edit.c:171 src/sudo_edit.c:271 +#, c-format +msgid "%s: not a regular file" +msgstr "%s:不是常规文件" + +#: src/sudo_edit.c:205 src/sudo_edit.c:307 +#, c-format +msgid "%s: short write" +msgstr "%s:截短写入" + +#: src/sudo_edit.c:272 +#, c-format +msgid "%s left unmodified" +msgstr "%s 并未修改" + +#: src/sudo_edit.c:285 +#, c-format +msgid "%s unchanged" +msgstr "%s 已更改" + +#: src/sudo_edit.c:297 src/sudo_edit.c:318 +#, c-format +msgid "unable to write to %s" +msgstr "无法写入 %s" + +#: src/sudo_edit.c:298 src/sudo_edit.c:316 src/sudo_edit.c:319 +#, c-format +msgid "contents of edit session left in %s" +msgstr "编辑会话的内容留在了 %s 中" + +#: src/sudo_edit.c:315 +#, c-format +msgid "unable to read temporary file" +msgstr "无法读取临时文件" + +#: src/tgetpass.c:90 +#, c-format +msgid "no tty present and no askpass program specified" +msgstr "没有终端存在,且未指定 askpass 程序" + +#: src/tgetpass.c:99 +#, c-format +msgid "no askpass program specified, try setting SUDO_ASKPASS" +msgstr "没有指定 askpass 程序,尝试设置 SUDO_ASKPASS" + +#: src/tgetpass.c:231 +#, c-format +msgid "unable to set gid to %u" +msgstr "无法将组 ID 设为 %u" + +#: src/tgetpass.c:235 +#, c-format +msgid "unable to set uid to %u" +msgstr "无法将用户 ID 设为 %u" + +#: src/tgetpass.c:240 +#, c-format +msgid "unable to run %s" +msgstr "无法执行 %s" + +#: src/utmp.c:278 +#, c-format +msgid "unable to save stdin" +msgstr "无法保存 stdin" + +#: src/utmp.c:280 +#, c-format +msgid "unable to dup2 stdin" +msgstr "无法 dup2 stdin" + +#: src/utmp.c:283 +#, c-format +msgid "unable to restore stdin" +msgstr "无法恢复 stdin" + +#~ msgid "must be setuid root" +#~ msgstr "必须为 setuid root" + +#~ msgid "the argument to -D must be between 1 and 9 inclusive" +#~ msgstr "-D 选项的参数必须介于 1 到 9(含 1 和 9)" diff --git a/src/preload.c b/src/preload.c new file mode 100644 index 0000000..cb0bdde --- /dev/null +++ b/src/preload.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 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. + */ + +#include + +#include "sudo_plugin.h" + +extern struct policy_plugin sudoers_policy; +extern struct io_plugin sudoers_io; + +struct sudo_preload_table { + const char *name; + void *address; +} sudo_preload_table[] = { + { "sudoers_policy", (void *) &sudoers_policy}, + { "sudoers_io", (void *) &sudoers_io}, + { (const char *)0, (void *)0 } +}; diff --git a/src/selinux.c b/src/selinux.c new file mode 100644 index 0000000..8050572 --- /dev/null +++ b/src/selinux.c @@ -0,0 +1,407 @@ +/* + * Copyright (c) 2009-2010 Todd C. Miller + * Copyright (c) 2008 Dan Walsh + * + * Borrowed heavily from newrole source code + * Authors: + * Anthony Colatrella + * Tim Fraser + * Steve Grubb + * Darrel Goeddel + * Michael Thompson + * Dan Walsh + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for SECCLASS_CHR_FILE */ +#include /* for is_selinux_enabled() */ +#include /* for context-mangling functions */ +#include +#include + +#ifdef HAVE_LINUX_AUDIT +# include +#endif + +#include "sudo.h" +#include "sudo_exec.h" + +static struct selinux_state { + security_context_t old_context; + security_context_t new_context; + security_context_t tty_context; + security_context_t new_tty_context; + const char *ttyn; + int ttyfd; + int enforcing; +} se_state; + +#ifdef HAVE_LINUX_AUDIT +static int +audit_role_change(const security_context_t old_context, + const security_context_t new_context, const char *ttyn) +{ + int au_fd, rc = -1; + char *message; + debug_decl(audit_role_change, SUDO_DEBUG_SELINUX) + + au_fd = audit_open(); + if (au_fd == -1) { + /* Kernel may not have audit support. */ + if (errno != EINVAL && errno != EPROTONOSUPPORT && errno != EAFNOSUPPORT +) + error(1, _("unable to open audit system")); + } else { + /* audit role change using the same format as newrole(1) */ + easprintf(&message, "newrole: old-context=%s new-context=%s", + old_context, new_context); + rc = audit_log_user_message(au_fd, AUDIT_USER_ROLE_CHANGE, + message, NULL, NULL, ttyn, 1); + if (rc <= 0) + warning(_("unable to send audit message")); + efree(message); + close(au_fd); + } + + debug_return_int(rc); +} +#endif + +/* + * This function attempts to revert the relabeling done to the tty. + * fd - referencing the opened ttyn + * ttyn - name of tty to restore + * + * Returns zero on success, non-zero otherwise + */ +int +selinux_restore_tty(void) +{ + int retval = 0; + security_context_t chk_tty_context = NULL; + debug_decl(selinux_restore_tty, SUDO_DEBUG_SELINUX) + + if (se_state.ttyfd == -1 || se_state.new_tty_context == NULL) + goto skip_relabel; + + /* Verify that the tty still has the context set by sudo. */ + if ((retval = fgetfilecon(se_state.ttyfd, &chk_tty_context)) < 0) { + warning(_("unable to fgetfilecon %s"), se_state.ttyn); + goto skip_relabel; + } + + if ((retval = strcmp(chk_tty_context, se_state.new_tty_context))) { + warningx(_("%s changed labels"), se_state.ttyn); + goto skip_relabel; + } + + if ((retval = fsetfilecon(se_state.ttyfd, se_state.tty_context)) < 0) + warning(_("unable to restore context for %s"), se_state.ttyn); + +skip_relabel: + if (se_state.ttyfd != -1) { + close(se_state.ttyfd); + se_state.ttyfd = -1; + } + if (chk_tty_context != NULL) { + freecon(chk_tty_context); + chk_tty_context = NULL; + } + debug_return_int(retval); +} + +/* + * This function attempts to relabel the tty. If this function fails, then + * the contexts are free'd and -1 is returned. On success, 0 is returned + * and tty_context and new_tty_context are set. + * + * This function will not fail if it can not relabel the tty when selinux is + * in permissive mode. + */ +static int +relabel_tty(const char *ttyn, int ptyfd) +{ + security_context_t tty_con = NULL; + security_context_t new_tty_con = NULL; + int fd; + debug_decl(relabel_tty, SUDO_DEBUG_SELINUX) + + se_state.ttyfd = ptyfd; + + /* It is perfectly legal to have no tty. */ + if (ptyfd == -1 && ttyn == NULL) + debug_return_int(0); + + /* If sudo is not allocating a pty for the command, open current tty. */ + if (ptyfd == -1) { + se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); + if (se_state.ttyfd == -1) { + warning(_("unable to open %s, not relabeling tty"), ttyn); + if (se_state.enforcing) + goto bad; + } + (void)fcntl(se_state.ttyfd, F_SETFL, + fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK); + } + + if (fgetfilecon(se_state.ttyfd, &tty_con) < 0) { + warning(_("unable to get current tty context, not relabeling tty")); + if (se_state.enforcing) + goto bad; + } + + if (tty_con && (security_compute_relabel(se_state.new_context, tty_con, + SECCLASS_CHR_FILE, &new_tty_con) < 0)) { + warning(_("unable to get new tty context, not relabeling tty")); + if (se_state.enforcing) + goto bad; + } + + if (new_tty_con != NULL) { + if (fsetfilecon(se_state.ttyfd, new_tty_con) < 0) { + warning(_("unable to set new tty context")); + if (se_state.enforcing) + goto bad; + } + } + + if (ptyfd != -1) { + /* Reopen pty that was relabeled, std{in,out,err} are reset later. */ + se_state.ttyfd = open(ttyn, O_RDWR|O_NOCTTY, 0); + if (se_state.ttyfd == -1) { + warning(_("unable to open %s"), ttyn); + if (se_state.enforcing) + goto bad; + } + if (dup2(se_state.ttyfd, ptyfd) == -1) { + warning("dup2"); + goto bad; + } + } else { + /* Re-open tty to get new label and reset std{in,out,err} */ + close(se_state.ttyfd); + se_state.ttyfd = open(ttyn, O_RDWR|O_NONBLOCK); + if (se_state.ttyfd == -1) { + warning(_("unable to open %s"), ttyn); + goto bad; + } + (void)fcntl(se_state.ttyfd, F_SETFL, + fcntl(se_state.ttyfd, F_GETFL, 0) & ~O_NONBLOCK); + for (fd = STDIN_FILENO; fd <= STDERR_FILENO; fd++) { + if (isatty(fd) && dup2(se_state.ttyfd, fd) == -1) { + warning("dup2"); + goto bad; + } + } + } + /* Retain se_state.ttyfd so we can restore label when command finishes. */ + (void)fcntl(se_state.ttyfd, F_SETFD, FD_CLOEXEC); + + se_state.ttyn = ttyn; + se_state.tty_context = tty_con; + se_state.new_tty_context = new_tty_con; + debug_return_int(0); + +bad: + if (se_state.ttyfd != -1 && se_state.ttyfd != ptyfd) { + close(se_state.ttyfd); + se_state.ttyfd = -1; + } + freecon(tty_con); + debug_return_int(-1); +} + +/* + * Returns a new security context based on the old context and the + * specified role and type. + */ +security_context_t +get_exec_context(security_context_t old_context, const char *role, const char *type) +{ + security_context_t new_context = NULL; + context_t context = NULL; + char *typebuf = NULL; + debug_decl(get_exec_context, SUDO_DEBUG_SELINUX) + + /* We must have a role, the type is optional (we can use the default). */ + if (!role) { + warningx(_("you must specify a role for type %s"), type); + errno = EINVAL; + goto bad; + } + if (!type) { + if (get_default_type(role, &typebuf)) { + warningx(_("unable to get default type for role %s"), role); + errno = EINVAL; + goto bad; + } + type = typebuf; + } + + /* + * Expand old_context into a context_t so that we extract and modify + * its components easily. + */ + context = context_new(old_context); + + /* + * Replace the role and type in "context" with the role and + * type we will be running the command as. + */ + if (context_role_set(context, role)) { + warning(_("failed to set new role %s"), role); + goto bad; + } + if (context_type_set(context, type)) { + warning(_("failed to set new type %s"), type); + goto bad; + } + + /* + * Convert "context" back into a string and verify it. + */ + new_context = estrdup(context_str(context)); + if (security_check_context(new_context) < 0) { + warningx(_("%s is not a valid context"), new_context); + errno = EINVAL; + goto bad; + } + +#ifdef DEBUG + warningx("Your new context is %s", new_context); +#endif + + context_free(context); + debug_return_ptr(new_context); + +bad: + efree(typebuf); + context_free(context); + freecon(new_context); + debug_return_ptr(NULL); +} + +/* + * Set the exec and tty contexts in preparation for fork/exec. + * Must run as root, before the uid change. + * If ptyfd is not -1, it indicates we are running + * in a pty and do not need to reset std{in,out,err}. + * Returns 0 on success and -1 on failure. + */ +int +selinux_setup(const char *role, const char *type, const char *ttyn, + int ptyfd) +{ + int rval = -1; + debug_decl(selinux_setup, SUDO_DEBUG_SELINUX) + + /* Store the caller's SID in old_context. */ + if (getprevcon(&se_state.old_context)) { + warning(_("failed to get old_context")); + goto done; + } + + se_state.enforcing = security_getenforce(); + if (se_state.enforcing < 0) { + warning(_("unable to determine enforcing mode.")); + goto done; + } + +#ifdef DEBUG + warningx("your old context was %s", se_state.old_context); +#endif + se_state.new_context = get_exec_context(se_state.old_context, role, type); + if (!se_state.new_context) + goto done; + + if (relabel_tty(ttyn, ptyfd) < 0) { + warning(_("unable to setup tty context for %s"), se_state.new_context); + goto done; + } + +#ifdef DEBUG + if (se_state.ttyfd != -1) { + warningx("your old tty context is %s", se_state.tty_context); + warningx("your new tty context is %s", se_state.new_tty_context); + } +#endif + +#ifdef HAVE_LINUX_AUDIT + audit_role_change(se_state.old_context, se_state.new_context, + se_state.ttyn); +#endif + + rval = 0; + +done: + debug_return_int(rval); +} + +void +selinux_execve(const char *path, char *const argv[], char *const envp[], + int noexec) +{ + char **nargv; + int argc, serrno; + debug_decl(selinux_execve, SUDO_DEBUG_SELINUX) + + if (setexeccon(se_state.new_context)) { + warning(_("unable to set exec context to %s"), se_state.new_context); + if (se_state.enforcing) + debug_return; + } + +#ifdef HAVE_SETKEYCREATECON + if (setkeycreatecon(se_state.new_context)) { + warning(_("unable to set key creation context to %s"), se_state.new_context); + if (se_state.enforcing) + debug_return; + } +#endif /* HAVE_SETKEYCREATECON */ + + /* + * Build new argv with sesh as argv[0]. + * If argv[0] ends in -noexec, sesh will disable execute + * for the command it runs. + */ + for (argc = 0; argv[argc] != NULL; argc++) + continue; + nargv = emalloc2(argc + 2, sizeof(char *)); + if (noexec) + nargv[0] = *argv[0] == '-' ? "-sesh-noexec" : "sesh-noexec"; + else + nargv[0] = *argv[0] == '-' ? "-sesh" : "sesh"; + nargv[1] = (char *)path; + memcpy(&nargv[2], &argv[1], argc * sizeof(char *)); /* copies NULL */ + + /* sesh will handle noexec for us. */ + sudo_execve(_PATH_SUDO_SESH, nargv, envp, 0); + serrno = errno; + free(nargv); + errno = serrno; + debug_return; +} diff --git a/src/sesh.c b/src/sesh.c new file mode 100644 index 0000000..d6b56c3 --- /dev/null +++ b/src/sesh.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SETLOCALE +# include +#endif +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "gettext.h" +#include "sudo_conf.h" +#include "sudo_debug.h" +#include "sudo_exec.h" +#include "sudo_plugin.h" + +sudo_conv_t sudo_conv; /* NULL in non-plugin */ + +/* + * Cleanup hook for error()/errorx() + */ +void +cleanup(int gotsignal) +{ + return; +} + +int +main(int argc, char *argv[], char *envp[]) +{ + char *cp, *cmnd; + int noexec = 0; + debug_decl(main, SUDO_DEBUG_MAIN) + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + bindtextdomain(PACKAGE_NAME, LOCALEDIR); + textdomain(PACKAGE_NAME); + + if (argc < 2) + errorx(EXIT_FAILURE, _("requires at least one argument")); + + /* Read sudo.conf. */ + sudo_conf_read(); + + /* If argv[0] ends in -noexec, pass the flag to sudo_execve() */ + if ((cp = strrchr(argv[0], '-')) != NULL && cp != argv[0]) + noexec = strcmp(cp, "-noexec") == 0; + + /* Shift argv and make a copy of the command to execute. */ + argv++; + argc--; + cmnd = estrdup(argv[0]); + + /* If invoked as a login shell, modify argv[0] accordingly. */ + if (argv[-1][0] == '-') { + if ((cp = strrchr(argv[0], '/')) == NULL) + cp = argv[0]; + *cp = '-'; + } + sudo_execve(cmnd, argv, envp, noexec); + warning(_("unable to execute %s"), argv[0]); + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, EXIT_FAILURE); + _exit(EXIT_FAILURE); +} diff --git a/src/sudo.c b/src/sudo.c new file mode 100644 index 0000000..2fee548 --- /dev/null +++ b/src/sudo.c @@ -0,0 +1,1259 @@ +/* + * Copyright (c) 2009-2012 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. + */ + +#ifdef __TANDEM +# include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +#endif +#ifdef HAVE_SETLOCALE +# include +#endif +#ifdef HAVE_LOGIN_CAP_H +# include +# ifndef LOGIN_SETENV +# define LOGIN_SETENV 0 +# endif +#endif +#ifdef HAVE_PROJECT_H +# include +# include +#endif +#ifdef HAVE_SELINUX +# include +#endif +#ifdef HAVE_SETAUTHDB +# include +#endif /* HAVE_SETAUTHDB */ +#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) +# ifdef __hpux +# undef MAXINT +# include +# else +# include +# endif /* __hpux */ +# include +#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ +#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) +# include +#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) +# include +# include +#endif + +#include "sudo.h" +#include "sudo_plugin.h" +#include "sudo_plugin_int.h" +#include + +/* + * Local variables + */ +struct plugin_container policy_plugin; +struct plugin_container_list io_plugins; +struct user_details user_details; +const char *list_user, *runas_user, *runas_group; /* extern for parse_args.c */ +static int sudo_mode; + +/* + * Local functions + */ +static void fix_fds(void); +static void disable_coredumps(void); +static void sudo_check_suid(const char *path); +static char **get_user_info(struct user_details *); +static void command_info_to_details(char * const info[], + struct command_details *details); + +/* Policy plugin convenience functions. */ +static int policy_open(struct plugin_container *plugin, char * const settings[], + char * const user_info[], char * const user_env[]); +static void policy_close(struct plugin_container *plugin, int exit_status, + int error); +static int policy_show_version(struct plugin_container *plugin, int verbose); +static int policy_check(struct plugin_container *plugin, int argc, + char * const argv[], char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); +static int policy_list(struct plugin_container *plugin, int argc, + char * const argv[], int verbose, const char *list_user); +static int policy_validate(struct plugin_container *plugin); +static void policy_invalidate(struct plugin_container *plugin, int remove); + +/* I/O log plugin convenience functions. */ +static int iolog_open(struct plugin_container *plugin, char * const settings[], + char * const user_info[], char * const command_details[], + int argc, char * const argv[], char * const user_env[]); +static void iolog_close(struct plugin_container *plugin, int exit_status, + int error); +static int iolog_show_version(struct plugin_container *plugin, int verbose); +static void iolog_unlink(struct plugin_container *plugin); + +#ifdef RLIMIT_CORE +static struct rlimit corelimit; +#endif /* RLIMIT_CORE */ +#if defined(__linux__) +static struct rlimit nproclimit; +#endif + +int +main(int argc, char *argv[], char *envp[]) +{ + int nargc, ok, exitcode = 0; + char **nargv, **settings, **env_add; + char **user_info, **command_info, **argv_out, **user_env_out; + struct plugin_container *plugin, *next; + struct command_details command_details; + sigset_t mask; + debug_decl(main, SUDO_DEBUG_MAIN) + +#if defined(SUDO_DEVEL) && defined(__OpenBSD__) + { + extern char *malloc_options; + malloc_options = "AFGJPR"; + } +#endif + +#if !defined(HAVE_GETPROGNAME) && !defined(HAVE___PROGNAME) + if (argc > 0) + setprogname(argv[0]); +#endif + +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + bindtextdomain(PACKAGE_NAME, LOCALEDIR); + textdomain(PACKAGE_NAME); + + /* Must be done before we do any password lookups */ +#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) + (void) set_auth_parameters(argc, argv); +# ifdef HAVE_INITPRIVS + initprivs(); +# endif +#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ + + /* Make sure we are setuid root. */ + sudo_check_suid(argv[0]); + + /* Reset signal mask and make sure fds 0-2 are open. */ + (void) sigemptyset(&mask); + (void) sigprocmask(SIG_SETMASK, &mask, NULL); + fix_fds(); + + /* Fill in user_info with user name, uid, cwd, etc. */ + memset(&user_details, 0, sizeof(user_details)); + user_info = get_user_info(&user_details); + + /* Read sudo.conf. */ + sudo_conf_read(); + + /* Disable core dumps if not enabled in sudo.conf. */ + disable_coredumps(); + + /* Parse command line arguments. */ + sudo_mode = parse_args(argc, argv, &nargc, &nargv, &settings, &env_add); + sudo_debug_printf(SUDO_DEBUG_DEBUG, "sudo_mode %d", sudo_mode); + + /* Print sudo version early, in case of plugin init failure. */ + if (ISSET(sudo_mode, MODE_VERSION)) { + printf(_("Sudo version %s\n"), PACKAGE_VERSION); + if (user_details.uid == ROOT_UID) + (void) printf(_("Configure options: %s\n"), CONFIGURE_ARGS); + } + + /* Load plugins. */ + if (!sudo_load_plugins(&policy_plugin, &io_plugins)) + errorx(1, _("fatal error, unable to load plugins")); + + /* Open policy plugin. */ + ok = policy_open(&policy_plugin, settings, user_info, envp); + if (ok != 1) { + if (ok == -2) + usage(1); + else + errorx(1, _("unable to initialize policy plugin")); + } + + switch (sudo_mode & MODE_MASK) { + case MODE_VERSION: + policy_show_version(&policy_plugin, !user_details.uid); + tq_foreach_fwd(&io_plugins, plugin) { + ok = iolog_open(plugin, settings, user_info, NULL, + nargc, nargv, envp); + if (ok == 1) + iolog_show_version(plugin, !user_details.uid); + } + break; + case MODE_VALIDATE: + case MODE_VALIDATE|MODE_INVALIDATE: + ok = policy_validate(&policy_plugin); + exit(ok != 1); + case MODE_KILL: + case MODE_INVALIDATE: + policy_invalidate(&policy_plugin, sudo_mode == MODE_KILL); + exit(0); + break; + case MODE_CHECK: + case MODE_CHECK|MODE_INVALIDATE: + case MODE_LIST: + case MODE_LIST|MODE_INVALIDATE: + ok = policy_list(&policy_plugin, nargc, nargv, + ISSET(sudo_mode, MODE_LONG_LIST), list_user); + exit(ok != 1); + case MODE_EDIT: + case MODE_RUN: + ok = policy_check(&policy_plugin, nargc, nargv, env_add, + &command_info, &argv_out, &user_env_out); + sudo_debug_printf(SUDO_DEBUG_INFO, "policy plugin returns %d", ok); + if (ok != 1) { + if (ok == -2) + usage(1); + exit(1); /* plugin printed error message */ + } + /* Open I/O plugins once policy plugin succeeds. */ + for (plugin = io_plugins.first; plugin != NULL; plugin = next) { + next = plugin->next; + ok = iolog_open(plugin, settings, user_info, + command_info, nargc, nargv, envp); + switch (ok) { + case 1: + break; + case 0: + /* I/O plugin asked to be disabled, remove and free. */ + iolog_unlink(plugin); + break; + case -2: + usage(1); + break; + default: + errorx(1, _("error initializing I/O plugin %s"), + plugin->name); + } + } + /* Setup command details and run command/edit. */ + command_info_to_details(command_info, &command_details); + command_details.argv = argv_out; + command_details.envp = user_env_out; + if (ISSET(sudo_mode, MODE_BACKGROUND)) + SET(command_details.flags, CD_BACKGROUND); + /* Become full root (not just setuid) so user cannot kill us. */ + (void) setuid(ROOT_UID); + /* Restore coredumpsize resource limit before running. */ +#ifdef RLIMIT_CORE + if (sudo_conf_disable_coredump()) + (void) setrlimit(RLIMIT_CORE, &corelimit); +#endif /* RLIMIT_CORE */ + if (ISSET(command_details.flags, CD_SUDOEDIT)) { + exitcode = sudo_edit(&command_details); + } else { + exitcode = run_command(&command_details); + } + /* The close method was called by sudo_edit/run_command. */ + break; + default: + errorx(1, _("unexpected sudo mode 0x%x"), sudo_mode); + } + sudo_debug_exit_int(__func__, __FILE__, __LINE__, sudo_debug_subsys, exitcode); + exit(exitcode); +} + +/* + * Ensure that stdin, stdout and stderr are open; set to /dev/null if not. + * Some operating systems do this automatically in the kernel or libc. + */ +static void +fix_fds(void) +{ + int miss[3], devnull = -1; + debug_decl(fix_fds, SUDO_DEBUG_UTIL) + + /* + * stdin, stdout and stderr must be open; set them to /dev/null + * if they are closed. + */ + miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1; + miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1; + miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1; + if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) { + if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1) + error(1, _("unable to open %s"), _PATH_DEVNULL); + if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1) + error(1, "dup2"); + if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1) + error(1, "dup2"); + if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1) + error(1, "dup2"); + if (devnull > STDERR_FILENO) + close(devnull); + } + debug_return; +} + +/* + * Allocate space for groups and fill in using getgrouplist() + * for when we cannot use getgroups(). + */ +static int +fill_group_list(struct user_details *ud) +{ + int maxgroups, tries, rval = -1; + debug_decl(fill_group_list, SUDO_DEBUG_UTIL) + +#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) + maxgroups = (int)sysconf(_SC_NGROUPS_MAX); + if (maxgroups < 0) +#endif + maxgroups = NGROUPS_MAX; + + /* + * It is possible to belong to more groups in the group database + * than NGROUPS_MAX. We start off with NGROUPS_MAX * 2 entries + * and double this as needed. + */ + ud->groups = NULL; + ud->ngroups = maxgroups; + for (tries = 0; tries < 10 && rval == -1; tries++) { + ud->ngroups *= 2; + efree(ud->groups); + ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); + rval = getgrouplist(ud->username, ud->gid, ud->groups, &ud->ngroups); + } + debug_return_int(rval); +} + +static char * +get_user_groups(struct user_details *ud) +{ + char *cp, *gid_list = NULL; + size_t glsize; + int i, len; + debug_decl(get_user_groups, SUDO_DEBUG_UTIL) + + /* + * Systems with mbr_check_membership() support more than NGROUPS_MAX + * groups so we cannot use getgroups(). + */ + ud->groups = NULL; +#ifndef HAVE_MBR_CHECK_MEMBERSHIP + if ((ud->ngroups = getgroups(0, NULL)) > 0) { + ud->groups = emalloc2(ud->ngroups, sizeof(GETGROUPS_T)); + if (getgroups(ud->ngroups, ud->groups) < 0) { + efree(ud->groups); + ud->groups = NULL; + } + } +#endif /* HAVE_MBR_CHECK_MEMBERSHIP */ + if (ud->groups == NULL) { + if (fill_group_list(ud) == -1) + error(1, _("unable to get group vector")); + } + + /* + * Format group list as a comma-separated string of gids. + */ + glsize = sizeof("groups=") - 1 + (ud->ngroups * (MAX_UID_T_LEN + 1)); + gid_list = emalloc(glsize); + memcpy(gid_list, "groups=", sizeof("groups=") - 1); + cp = gid_list + sizeof("groups=") - 1; + for (i = 0; i < ud->ngroups; i++) { + /* XXX - check rval */ + len = snprintf(cp, glsize - (cp - gid_list), "%s%u", + i ? "," : "", (unsigned int)ud->groups[i]); + cp += len; + } + debug_return_str(gid_list); +} + +/* + * Return user information as an array of name=value pairs. + * and fill in struct user_details (which shares the same strings). + */ +static char ** +get_user_info(struct user_details *ud) +{ + char *cp, **user_info, cwd[PATH_MAX], host[MAXHOSTNAMELEN]; + struct passwd *pw; + int fd, i = 0; + debug_decl(get_user_info, SUDO_DEBUG_UTIL) + + /* XXX - bound check number of entries */ + user_info = emalloc2(32, sizeof(char *)); + + ud->pid = getpid(); + ud->ppid = getppid(); + ud->pgid = getpgid(0); + ud->tcpgid = (pid_t)-1; + fd = open(_PATH_TTY, O_RDWR|O_NOCTTY|O_NONBLOCK, 0); + if (fd != -1) { + ud->tcpgid = tcgetpgrp(fd); + close(fd); + } + ud->sid = getsid(0); + + ud->uid = getuid(); + ud->euid = geteuid(); + ud->gid = getgid(); + ud->egid = getegid(); + + pw = getpwuid(ud->uid); + if (pw == NULL) + errorx(1, _("unknown uid %u: who are you?"), (unsigned int)ud->uid); + + user_info[i] = fmt_string("user", pw->pw_name); + if (user_info[i] == NULL) + errorx(1, _("unable to allocate memory")); + ud->username = user_info[i] + sizeof("user=") - 1; + + /* Stash user's shell for use with the -s flag; don't pass to plugin. */ + if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '\0') { + ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL; + } + ud->shell = estrdup(ud->shell); + + easprintf(&user_info[++i], "pid=%d", (int)ud->pid); + easprintf(&user_info[++i], "ppid=%d", (int)ud->ppid); + easprintf(&user_info[++i], "pgid=%d", (int)ud->pgid); + easprintf(&user_info[++i], "tcpgid=%d", (int)ud->tcpgid); + easprintf(&user_info[++i], "sid=%d", (int)ud->sid); + + easprintf(&user_info[++i], "uid=%u", (unsigned int)ud->uid); + easprintf(&user_info[++i], "euid=%u", (unsigned int)ud->euid); + easprintf(&user_info[++i], "gid=%u", (unsigned int)ud->gid); + easprintf(&user_info[++i], "egid=%u", (unsigned int)ud->egid); + + if ((cp = get_user_groups(ud)) != NULL) + user_info[++i] = cp; + + if (getcwd(cwd, sizeof(cwd)) != NULL) { + user_info[++i] = fmt_string("cwd", cwd); + if (user_info[i] == NULL) + errorx(1, _("unable to allocate memory")); + ud->cwd = user_info[i] + sizeof("cwd=") - 1; + } + + if ((cp = get_process_ttyname()) != NULL) { + user_info[++i] = fmt_string("tty", cp); + if (user_info[i] == NULL) + errorx(1, _("unable to allocate memory")); + ud->tty = user_info[i] + sizeof("tty=") - 1; + efree(cp); + } + + if (gethostname(host, sizeof(host)) == 0) + host[sizeof(host) - 1] = '\0'; + else + strlcpy(host, "localhost", sizeof(host)); + user_info[++i] = fmt_string("host", host); + if (user_info[i] == NULL) + errorx(1, _("unable to allocate memory")); + ud->host = user_info[i] + sizeof("host=") - 1; + + get_ttysize(&ud->ts_lines, &ud->ts_cols); + easprintf(&user_info[++i], "lines=%d", ud->ts_lines); + easprintf(&user_info[++i], "cols=%d", ud->ts_cols); + + user_info[++i] = NULL; + + debug_return_ptr(user_info); +} + +/* + * Convert a command_info array into a command_details structure. + */ +static void +command_info_to_details(char * const info[], struct command_details *details) +{ + int i; + long lval; + unsigned long ulval; + char *cp, *ep; + debug_decl(command_info_to_details, SUDO_DEBUG_PCOMM) + + memset(details, 0, sizeof(*details)); + details->closefrom = -1; + +#define SET_STRING(s, n) \ + if (strncmp(s, info[i], sizeof(s) - 1) == 0 && info[i][sizeof(s) - 1]) { \ + details->n = info[i] + sizeof(s) - 1; \ + break; \ + } + + sudo_debug_printf(SUDO_DEBUG_INFO, "command info from plugin:"); + for (i = 0; info[i] != NULL; i++) { + sudo_debug_printf(SUDO_DEBUG_INFO, " %d: %s", i, info[i]); + switch (info[i][0]) { + case 'c': + SET_STRING("chroot=", chroot) + SET_STRING("command=", command) + SET_STRING("cwd=", cwd) + if (strncmp("closefrom=", info[i], sizeof("closefrom=") - 1) == 0) { + cp = info[i] + sizeof("closefrom=") - 1; + if (*cp == '\0') + break; + errno = 0; + lval = strtol(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + !(errno == ERANGE && + (lval == LONG_MAX || lval == LONG_MIN)) && + lval < INT_MAX && lval > INT_MIN) { + details->closefrom = (int)lval; + } + break; + } + break; + case 'l': + SET_STRING("login_class=", login_class) + break; + case 'n': + /* XXX - bounds check -NZERO to NZERO (inclusive). */ + if (strncmp("nice=", info[i], sizeof("nice=") - 1) == 0) { + cp = info[i] + sizeof("nice=") - 1; + if (*cp == '\0') + break; + errno = 0; + lval = strtol(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + !(errno == ERANGE && + (lval == LONG_MAX || lval == LONG_MIN)) && + lval < INT_MAX && lval > INT_MIN) { + details->priority = (int)lval; + SET(details->flags, CD_SET_PRIORITY); + } + break; + } + if (strncmp("noexec=", info[i], sizeof("noexec=") - 1) == 0) { + if (atobool(info[i] + sizeof("noexec=") - 1) == true) + SET(details->flags, CD_NOEXEC); + break; + } + break; + case 'p': + if (strncmp("preserve_groups=", info[i], sizeof("preserve_groups=") - 1) == 0) { + if (atobool(info[i] + sizeof("preserve_groups=") - 1) == true) + SET(details->flags, CD_PRESERVE_GROUPS); + break; + } + break; + case 'r': + if (strncmp("runas_egid=", info[i], sizeof("runas_egid=") - 1) == 0) { + cp = info[i] + sizeof("runas_egid=") - 1; + if (*cp == '\0') + break; + errno = 0; + ulval = strtoul(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + details->egid = (gid_t)ulval; + SET(details->flags, CD_SET_EGID); + } + break; + } + if (strncmp("runas_euid=", info[i], sizeof("runas_euid=") - 1) == 0) { + cp = info[i] + sizeof("runas_euid=") - 1; + if (*cp == '\0') + break; + errno = 0; + ulval = strtoul(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + details->euid = (uid_t)ulval; + SET(details->flags, CD_SET_EUID); + } + break; + } + if (strncmp("runas_gid=", info[i], sizeof("runas_gid=") - 1) == 0) { + cp = info[i] + sizeof("runas_gid=") - 1; + if (*cp == '\0') + break; + errno = 0; + ulval = strtoul(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + details->gid = (gid_t)ulval; + SET(details->flags, CD_SET_GID); + } + break; + } + if (strncmp("runas_groups=", info[i], sizeof("runas_groups=") - 1) == 0) { + int j; + + /* count groups, alloc and fill in */ + cp = info[i] + sizeof("runas_groups=") - 1; + if (*cp == '\0') + break; + for (;;) { + details->ngroups++; + if ((cp = strchr(cp, ',')) == NULL) + break; + cp++; + } + if (details->ngroups != 0) { + details->groups = + emalloc2(details->ngroups, sizeof(GETGROUPS_T)); + cp = info[i] + sizeof("runas_groups=") - 1; + for (j = 0; j < details->ngroups;) { + errno = 0; + ulval = strtoul(cp, &ep, 0); + if (*cp == '\0' || (*ep != ',' && *ep != '\0') || + (ulval == ULONG_MAX && errno == ERANGE)) { + break; + } + details->groups[j++] = (gid_t)ulval; + cp = ep + 1; + } + details->ngroups = j; + } + break; + } + if (strncmp("runas_uid=", info[i], sizeof("runas_uid=") - 1) == 0) { + cp = info[i] + sizeof("runas_uid=") - 1; + if (*cp == '\0') + break; + errno = 0; + ulval = strtoul(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + details->uid = (uid_t)ulval; + SET(details->flags, CD_SET_UID); + } + break; + } + break; + case 's': + SET_STRING("selinux_role=", selinux_role) + SET_STRING("selinux_type=", selinux_type) + if (strncmp("set_utmp=", info[i], sizeof("set_utmp=") - 1) == 0) { + if (atobool(info[i] + sizeof("set_utmp=") - 1) == true) + SET(details->flags, CD_SET_UTMP); + break; + } + if (strncmp("sudoedit=", info[i], sizeof("sudoedit=") - 1) == 0) { + if (atobool(info[i] + sizeof("sudoedit=") - 1) == true) + SET(details->flags, CD_SUDOEDIT); + break; + } + break; + case 't': + if (strncmp("timeout=", info[i], sizeof("timeout=") - 1) == 0) { + cp = info[i] + sizeof("timeout=") - 1; + if (*cp == '\0') + break; + errno = 0; + lval = strtol(cp, &ep, 0); + if (*cp != '\0' && *ep == '\0' && + !(errno == ERANGE && + (lval == LONG_MAX || lval == LONG_MIN)) && + lval <= INT_MAX && lval >= 0) { + details->timeout = (int)lval; + SET(details->flags, CD_SET_TIMEOUT); + } + break; + } + break; + case 'u': + if (strncmp("umask=", info[i], sizeof("umask=") - 1) == 0) { + cp = info[i] + sizeof("umask=") - 1; + if (*cp == '\0') + break; + errno = 0; + ulval = strtoul(cp, &ep, 8); + if (*cp != '\0' && *ep == '\0' && + (errno != ERANGE || ulval != ULONG_MAX)) { + details->umask = (uid_t)ulval; + SET(details->flags, CD_SET_UMASK); + } + break; + } + if (strncmp("use_pty=", info[i], sizeof("use_pty=") - 1) == 0) { + if (atobool(info[i] + sizeof("use_pty=") - 1) == true) + SET(details->flags, CD_USE_PTY); + break; + } + SET_STRING("utmp_user=", utmp_user) + break; + } + } + + if (!ISSET(details->flags, CD_SET_EUID)) + details->euid = details->uid; + +#ifdef HAVE_SETAUTHDB + aix_setauthdb(IDtouser(details->euid)); +#endif + details->pw = getpwuid(details->euid); + if (details->pw != NULL && (details->pw = pw_dup(details->pw)) == NULL) + errorx(1, _("unable to allocate memory")); +#ifdef HAVE_SETAUTHDB + aix_restoreauthdb(); +#endif + +#ifdef HAVE_SELINUX + if (details->selinux_role != NULL && is_selinux_enabled() > 0) + SET(details->flags, CD_RBAC_ENABLED); +#endif + debug_return; +} + +static void +sudo_check_suid(const char *path) +{ + struct stat sb; + debug_decl(sudo_check_suid, SUDO_DEBUG_PCOMM) + + if (geteuid() != 0) { + if (strchr(path, '/') != NULL && stat(path, &sb) == 0) { + /* Try to determine why sudo was not running as root. */ + if (sb.st_uid != ROOT_UID || !ISSET(sb.st_mode, S_ISUID)) { + errorx(1, + _("%s must be owned by uid %d and have the setuid bit set"), + path, ROOT_UID); + } else { + errorx(1, _("effective uid is not %d, is %s on a file system " + "with the 'nosuid' option set or an NFS file system without" + " root privileges?"), ROOT_UID, path); + } + } else { + errorx(1, + _("effective uid is not %d, is sudo installed setuid root?"), + ROOT_UID); + } + } + debug_return; +} + +/* + * Disable core dumps to avoid dropping a core with user password in it. + * We will reset this limit before executing the command. + * Not all operating systems disable core dumps for setuid processes. + */ +static void +disable_coredumps(void) +{ +#if defined(__linux__) || defined(RLIMIT_CORE) + struct rlimit rl; +#endif + debug_decl(disable_coredumps, SUDO_DEBUG_UTIL) + +#if defined(__linux__) + /* + * Unlimit the number of processes since Linux's setuid() will + * apply resource limits when changing uid and return EAGAIN if + * nproc would be violated by the uid switch. + */ + (void) getrlimit(RLIMIT_NPROC, &nproclimit); + rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_NPROC, &rl)) { + memcpy(&rl, &nproclimit, sizeof(struct rlimit)); + rl.rlim_cur = rl.rlim_max; + (void)setrlimit(RLIMIT_NPROC, &rl); + } +#endif /* __linux__ */ +#ifdef RLIMIT_CORE + /* + * Turn off core dumps? + */ + if (sudo_conf_disable_coredump()) { + (void) getrlimit(RLIMIT_CORE, &corelimit); + memcpy(&rl, &corelimit, sizeof(struct rlimit)); + rl.rlim_cur = 0; + (void) setrlimit(RLIMIT_CORE, &rl); + } +#endif /* RLIMIT_CORE */ + debug_return; +} + +#ifdef HAVE_PROJECT_H +static void +set_project(struct passwd *pw) +{ + struct project proj; + char buf[PROJECT_BUFSZ]; + int errval; + debug_decl(set_project, SUDO_DEBUG_UTIL) + + /* + * Collect the default project for the user and settaskid + */ + setprojent(); + if (getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf)) != NULL) { + errval = setproject(proj.pj_name, pw->pw_name, TASK_NORMAL); + switch(errval) { + case 0: + break; + case SETPROJ_ERR_TASK: + switch (errno) { + case EAGAIN: + warningx(_("resource control limit has been reached")); + break; + case ESRCH: + warningx(_("user \"%s\" is not a member of project \"%s\""), + pw->pw_name, proj.pj_name); + break; + case EACCES: + warningx(_("the invoking task is final")); + break; + default: + warningx(_("could not join project \"%s\""), proj.pj_name); + } + case SETPROJ_ERR_POOL: + switch (errno) { + case EACCES: + warningx(_("no resource pool accepting default bindings " + "exists for project \"%s\""), proj.pj_name); + break; + case ESRCH: + warningx(_("specified resource pool does not exist for " + "project \"%s\""), proj.pj_name); + break; + default: + warningx(_("could not bind to default resource pool for " + "project \"%s\""), proj.pj_name); + } + break; + default: + if (errval <= 0) { + warningx(_("setproject failed for project \"%s\""), proj.pj_name); + } else { + warningx(_("warning, resource control assignment failed for " + "project \"%s\""), proj.pj_name); + } + } + } else { + warning("getdefaultproj"); + } + endprojent(); + debug_return; +} +#endif /* HAVE_PROJECT_H */ + +/* + * Setup the execution environment immediately prior to the call to execve() + * Returns true on success and false on failure. + */ +bool +exec_setup(struct command_details *details, const char *ptyname, int ptyfd) +{ + bool rval = false; + debug_decl(exec_setup, SUDO_DEBUG_EXEC) + +#ifdef HAVE_SELINUX + if (ISSET(details->flags, CD_RBAC_ENABLED)) { + if (selinux_setup(details->selinux_role, details->selinux_type, + ptyname ? ptyname : user_details.tty, ptyfd) == -1) + goto done; + } +#endif + + if (details->pw != NULL) { +#ifdef HAVE_PROJECT_H + set_project(details->pw); +#endif +#ifdef HAVE_GETUSERATTR + aix_prep_user(details->pw->pw_name, ptyname ? ptyname : user_details.tty); +#endif +#ifdef HAVE_LOGIN_CAP_H + if (details->login_class) { + int flags; + login_cap_t *lc; + + /* + * We only use setusercontext() to set the nice value and rlimits + * unless this is a login shell (sudo -i). + */ + lc = login_getclass((char *)details->login_class); + if (!lc) { + warningx(_("unknown login class %s"), details->login_class); + errno = ENOENT; + goto done; + } + if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { + /* Set everything except user, group and login name. */ + flags = LOGIN_SETALL; + CLR(flags, LOGIN_SETGROUP|LOGIN_SETLOGIN|LOGIN_SETUSER|LOGIN_SETENV|LOGIN_SETPATH); + CLR(details->flags, CD_SET_UMASK); /* LOGIN_UMASK instead */ + } else { + flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY; + } + if (setusercontext(lc, details->pw, details->pw->pw_uid, flags)) { + if (details->pw->pw_uid != ROOT_UID) { + warning(_("unable to set user context")); + goto done; + } else + warning(_("unable to set user context")); + } + } +#endif /* HAVE_LOGIN_CAP_H */ + } + + /* + * Set groups, including supplementary group vector. + */ + if (!ISSET(details->flags, CD_PRESERVE_GROUPS)) { + if (details->ngroups >= 0) { + if (sudo_setgroups(details->ngroups, details->groups) < 0) { + warning(_("unable to set supplementary group IDs")); + goto done; + } + } + } +#ifdef HAVE_SETEUID + if (ISSET(details->flags, CD_SET_EGID) && setegid(details->egid)) { + warning(_("unable to set effective gid to runas gid %u"), + (unsigned int)details->egid); + goto done; + } +#endif + if (ISSET(details->flags, CD_SET_GID) && setgid(details->gid)) { + warning(_("unable to set gid to runas gid %u"), + (unsigned int)details->gid); + goto done; + } + + if (ISSET(details->flags, CD_SET_PRIORITY)) { + if (setpriority(PRIO_PROCESS, 0, details->priority) != 0) { + warning(_("unable to set process priority")); + goto done; + } + } + if (ISSET(details->flags, CD_SET_UMASK)) + (void) umask(details->umask); + if (details->chroot) { + if (chroot(details->chroot) != 0 || chdir("/") != 0) { + warning(_("unable to change root to %s"), details->chroot); + goto done; + } + } + +#ifdef HAVE_SETRESUID + if (setresuid(details->uid, details->euid, details->euid) != 0) { + warning(_("unable to change to runas uid (%u, %u)"), details->uid, + details->euid); + goto done; + } +#elif HAVE_SETREUID + if (setreuid(details->uid, details->euid) != 0) { + warning(_("unable to change to runas uid (%u, %u)"), + (unsigned int)details->uid, (unsigned int)details->euid); + goto done; + } +#else + if (seteuid(details->euid) != 0 || setuid(details->euid) != 0) { + warning(_("unable to change to runas uid (%u, %u)"), details->uid, + details->euid); + goto done; + } +#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */ + + /* + * Only change cwd if we have chroot()ed or the policy modules + * specifies a different cwd. Must be done after uid change. + */ + if (details->cwd) { + if (details->chroot || strcmp(details->cwd, user_details.cwd) != 0) { + /* Note: cwd is relative to the new root, if any. */ + if (chdir(details->cwd) != 0) { + warning(_("unable to change directory to %s"), details->cwd); + goto done; + } + } + } + + /* + * Restore nproc resource limit if pam_limits didn't do it for us. + * We must do this *after* the uid change to avoid potential EAGAIN + * from setuid(). + */ +#if defined(__linux__) + { + struct rlimit rl; + if (getrlimit(RLIMIT_NPROC, &rl) == 0) { + if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY) + (void) setrlimit(RLIMIT_NPROC, &nproclimit); + } + } +#endif + + rval = true; + +done: + debug_return_bool(rval); +} + +/* + * Run the command and wait for it to complete. + */ +int +run_command(struct command_details *details) +{ + struct plugin_container *plugin; + struct command_status cstat; + int exitcode = 1; + debug_decl(run_command, SUDO_DEBUG_EXEC) + + cstat.type = CMD_INVALID; + cstat.val = 0; + + sudo_execute(details, &cstat); + + switch (cstat.type) { + case CMD_ERRNO: + /* exec_setup() or execve() returned an error. */ + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling policy close with errno %d", cstat.val); + policy_close(&policy_plugin, 0, cstat.val); + tq_foreach_fwd(&io_plugins, plugin) { + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling I/O close with errno %d", cstat.val); + iolog_close(plugin, 0, cstat.val); + } + exitcode = 1; + break; + case CMD_WSTATUS: + /* Command ran, exited or was killed. */ + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling policy close with wait status %d", cstat.val); + policy_close(&policy_plugin, cstat.val, 0); + tq_foreach_fwd(&io_plugins, plugin) { + sudo_debug_printf(SUDO_DEBUG_DEBUG, + "calling I/O close with wait status %d", cstat.val); + iolog_close(plugin, cstat.val, 0); + } + if (WIFEXITED(cstat.val)) + exitcode = WEXITSTATUS(cstat.val); + else if (WIFSIGNALED(cstat.val)) + exitcode = WTERMSIG(cstat.val) | 128; + break; + default: + warningx(_("unexpected child termination condition: %d"), cstat.type); + break; + } + debug_return_int(exitcode); +} + +static int +policy_open(struct plugin_container *plugin, char * const settings[], + char * const user_info[], char * const user_env[]) +{ + int rval; + debug_decl(policy_open, SUDO_DEBUG_PCOMM) + + /* + * Backwards compatibility for older API versions + */ + switch (plugin->u.generic->version) { + case SUDO_API_MKVERSION(1, 0): + case SUDO_API_MKVERSION(1, 1): + rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version, + sudo_conversation, _sudo_printf, settings, user_info, user_env); + break; + default: + rval = plugin->u.policy->open(SUDO_API_VERSION, sudo_conversation, + _sudo_printf, settings, user_info, user_env, plugin->options); + } + + debug_return_bool(rval); +} + +static void +policy_close(struct plugin_container *plugin, int exit_status, int error) +{ + debug_decl(policy_close, SUDO_DEBUG_PCOMM) + plugin->u.policy->close(exit_status, error); + debug_return; +} + +static int +policy_show_version(struct plugin_container *plugin, int verbose) +{ + debug_decl(policy_show_version, SUDO_DEBUG_PCOMM) + debug_return_bool(plugin->u.policy->show_version(verbose)); +} + +static int +policy_check(struct plugin_container *plugin, int argc, char * const argv[], + char *env_add[], char **command_info[], char **argv_out[], + char **user_env_out[]) +{ + debug_decl(policy_check, SUDO_DEBUG_PCOMM) + debug_return_bool(plugin->u.policy->check_policy(argc, argv, env_add, + command_info, argv_out, user_env_out)); +} + +static int +policy_list(struct plugin_container *plugin, int argc, char * const argv[], + int verbose, const char *list_user) +{ + debug_decl(policy_list, SUDO_DEBUG_PCOMM) + if (plugin->u.policy->list == NULL) { + warningx(_("policy plugin %s does not support listing privileges"), + plugin->name); + debug_return_bool(false); + } + debug_return_bool(plugin->u.policy->list(argc, argv, verbose, list_user)); +} + +static int +policy_validate(struct plugin_container *plugin) +{ + debug_decl(policy_validate, SUDO_DEBUG_PCOMM) + if (plugin->u.policy->validate == NULL) { + warningx(_("policy plugin %s does not support the -v option"), + plugin->name); + debug_return_bool(false); + } + debug_return_bool(plugin->u.policy->validate()); +} + +static void +policy_invalidate(struct plugin_container *plugin, int remove) +{ + debug_decl(policy_invalidate, SUDO_DEBUG_PCOMM) + if (plugin->u.policy->invalidate == NULL) { + errorx(1, _("policy plugin %s does not support the -k/-K options"), + plugin->name); + } + plugin->u.policy->invalidate(remove); + debug_return; +} + +int +policy_init_session(struct command_details *details) +{ + int rval = true; + debug_decl(policy_init_session, SUDO_DEBUG_PCOMM) + + if (policy_plugin.u.policy->init_session) { + /* + * Backwards compatibility for older API versions + */ + switch (policy_plugin.u.generic->version) { + case SUDO_API_MKVERSION(1, 0): + case SUDO_API_MKVERSION(1, 1): + rval = policy_plugin.u.policy_1_0->init_session(details->pw); + break; + default: + rval = policy_plugin.u.policy->init_session(details->pw, + &details->envp); + } + } + debug_return_bool(rval); +} + +static int +iolog_open(struct plugin_container *plugin, char * const settings[], + char * const user_info[], char * const command_info[], + int argc, char * const argv[], char * const user_env[]) +{ + int rval; + debug_decl(iolog_open, SUDO_DEBUG_PCOMM) + + /* + * Backwards compatibility for older API versions + */ + switch (plugin->u.generic->version) { + case SUDO_API_MKVERSION(1, 0): + rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version, + sudo_conversation, _sudo_printf, settings, user_info, argc, argv, + user_env); + break; + case SUDO_API_MKVERSION(1, 1): + rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version, + sudo_conversation, _sudo_printf, settings, user_info, + command_info, argc, argv, user_env); + break; + default: + rval = plugin->u.io->open(SUDO_API_VERSION, sudo_conversation, + _sudo_printf, settings, user_info, command_info, + argc, argv, user_env, plugin->options); + } + debug_return_bool(rval); +} + +static void +iolog_close(struct plugin_container *plugin, int exit_status, int error) +{ + debug_decl(iolog_close, SUDO_DEBUG_PCOMM) + plugin->u.io->close(exit_status, error); + debug_return; +} + +static int +iolog_show_version(struct plugin_container *plugin, int verbose) +{ + debug_decl(iolog_show_version, SUDO_DEBUG_PCOMM) + debug_return_bool(plugin->u.io->show_version(verbose)); +} + +/* + * Remove the specified I/O logging plugin from the io_plugins list. + * Deregisters any hooks before unlinking, then frees the container. + */ +static void +iolog_unlink(struct plugin_container *plugin) +{ + debug_decl(iolog_unlink, SUDO_DEBUG_PCOMM) + + /* Deregister hooks, if any. */ + if (plugin->u.io->version >= SUDO_API_MKVERSION(1, 2)) { + if (plugin->u.io->deregister_hooks != NULL) + plugin->u.io->deregister_hooks(SUDO_HOOK_VERSION, + deregister_hook); + } + /* Remove from io_plugins list and free. */ + tq_remove(&io_plugins, plugin); + efree(plugin); + + debug_return; +} diff --git a/src/sudo.h b/src/sudo.h new file mode 100644 index 0000000..c50f1e1 --- /dev/null +++ b/src/sudo.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 1993-1996, 1998-2005, 2007-2012 + * 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. + * + * $Sudo: sudo.h,v 1.290 2009/12/12 16:12:26 millert Exp $ + */ + +#ifndef _SUDO_SUDO_H +#define _SUDO_SUDO_H + +#include +#include +#ifdef HAVE_STDBOOL_H +# include +#else +# include "compat/stdbool.h" +#endif /* HAVE_STDBOOL_H */ + +#include "missing.h" +#include "alloc.h" +#include "error.h" +#include "fileops.h" +#include "list.h" +#include "sudo_conf.h" +#include "sudo_debug.h" +#include "gettext.h" + +#ifdef __TANDEM +# define ROOT_UID 65535 +#else +# define ROOT_UID 0 +#endif + +/* + * Various modes sudo can be in (based on arguments) in hex + */ +#define MODE_RUN 0x00000001 +#define MODE_EDIT 0x00000002 +#define MODE_VALIDATE 0x00000004 +#define MODE_INVALIDATE 0x00000008 +#define MODE_KILL 0x00000010 +#define MODE_VERSION 0x00000020 +#define MODE_HELP 0x00000040 +#define MODE_LIST 0x00000080 +#define MODE_CHECK 0x00000100 +#define MODE_MASK 0x0000ffff + +/* Mode flags */ +/* XXX - prune this */ +#define MODE_BACKGROUND 0x00010000 +#define MODE_SHELL 0x00020000 +#define MODE_LOGIN_SHELL 0x00040000 +#define MODE_IMPLIED_SHELL 0x00080000 +#define MODE_RESET_HOME 0x00100000 +#define MODE_PRESERVE_GROUPS 0x00200000 +#define MODE_PRESERVE_ENV 0x00400000 +#define MODE_NONINTERACTIVE 0x00800000 +#define MODE_LONG_LIST 0x01000000 + +/* + * We used to use the system definition of PASS_MAX or _PASSWD_LEN, + * but that caused problems with various alternate authentication + * methods. So, we just define our own and assume that it is >= the + * system max. + */ +#define SUDO_PASS_MAX 256 + +/* + * Flags for tgetpass() + */ +#define TGP_NOECHO 0x00 /* turn echo off reading pw (default) */ +#define TGP_ECHO 0x01 /* leave echo on when reading passwd */ +#define TGP_STDIN 0x02 /* read from stdin, not /dev/tty */ +#define TGP_ASKPASS 0x04 /* read from askpass helper program */ +#define TGP_MASK 0x08 /* mask user input when reading */ +#define TGP_NOECHO_TRY 0x10 /* turn off echo if possible */ + +struct user_details { + pid_t pid; + pid_t ppid; + pid_t pgid; + pid_t tcpgid; + pid_t sid; + uid_t uid; + uid_t euid; + uid_t gid; + uid_t egid; + const char *username; + const char *cwd; + const char *tty; + const char *host; + const char *shell; + GETGROUPS_T *groups; + int ngroups; + int ts_cols; + int ts_lines; +}; + +#define CD_SET_UID 0x0001 +#define CD_SET_EUID 0x0002 +#define CD_SET_GID 0x0004 +#define CD_SET_EGID 0x0008 +#define CD_PRESERVE_GROUPS 0x0010 +#define CD_NOEXEC 0x0020 +#define CD_SET_PRIORITY 0x0040 +#define CD_SET_UMASK 0x0080 +#define CD_SET_TIMEOUT 0x0100 +#define CD_SUDOEDIT 0x0200 +#define CD_BACKGROUND 0x0400 +#define CD_RBAC_ENABLED 0x0800 +#define CD_USE_PTY 0x1000 +#define CD_SET_UTMP 0x2000 + +struct command_details { + uid_t uid; + uid_t euid; + gid_t gid; + gid_t egid; + mode_t umask; + int priority; + int timeout; + int ngroups; + int closefrom; + int flags; + struct passwd *pw; + GETGROUPS_T *groups; + const char *command; + const char *cwd; + const char *login_class; + const char *chroot; + const char *selinux_role; + const char *selinux_type; + const char *utmp_user; + char **argv; + char **envp; +}; + +/* Status passed between parent and child via socketpair */ +struct command_status { +#define CMD_INVALID 0 +#define CMD_ERRNO 1 +#define CMD_WSTATUS 2 +#define CMD_SIGNO 3 + int type; + int val; +}; + +struct timeval; + +/* For error() and errorx() (XXX - needed?) */ +void cleanup(int); + +/* tgetpass.c */ +char *tgetpass(const char *, int, int); +int tty_present(void); + +/* zero_bytes.c */ +void zero_bytes(volatile void *, size_t); + +/* exec.c */ +int sudo_execute(struct command_details *details, struct command_status *cstat); +void save_signals(void); +void restore_signals(void); + +/* term.c */ +int term_cbreak(int); +int term_copy(int, int); +int term_noecho(int); +int term_raw(int, int); +int term_restore(int, int); + +/* fmt_string.h */ +char *fmt_string(const char *var, const char *value); + +/* atobool.c */ +bool atobool(const char *str); + +/* parse_args.c */ +int parse_args(int argc, char **argv, int *nargc, char ***nargv, + char ***settingsp, char ***env_addp); +extern int tgetpass_flags; + +/* get_pty.c */ +int get_pty(int *master, int *slave, char *name, size_t namesz, uid_t uid); + +/* ttysize.c */ +void get_ttysize(int *rowp, int *colp); + +/* sudo.c */ +bool exec_setup(struct command_details *details, const char *ptyname, int ptyfd); +int policy_init_session(struct command_details *details); +int run_command(struct command_details *details); +extern const char *list_user, *runas_user, *runas_group; +extern struct user_details user_details; + +/* sudo_edit.c */ +int sudo_edit(struct command_details *details); + +/* parse_args.c */ +void usage(int); + +/* selinux.c */ +int selinux_restore_tty(void); +int selinux_setup(const char *role, const char *type, const char *ttyn, + int ttyfd); +void selinux_execve(const char *path, char *const argv[], char *const envp[], + int noexec); + +/* aix.c */ +void aix_prep_user(char *user, const char *tty); +void aix_restoreauthdb(void); +void aix_setauthdb(char *user); + +/* hooks.c */ +/* XXX - move to sudo_plugin_int.h? */ +struct sudo_hook; +int register_hook(struct sudo_hook *hook); +int deregister_hook(struct sudo_hook *hook); +int process_hooks_getenv(const char *name, char **val); +int process_hooks_setenv(const char *name, const char *value, int overwrite); +int process_hooks_putenv(char *string); +int process_hooks_unsetenv(const char *name); + +/* env_hooks.c */ +char *getenv_unhooked(const char *name); + +/* interfaces.c */ +int get_net_ifs(char **addrinfo); + +/* setgroups.c */ +int sudo_setgroups(int ngids, const GETGROUPS_T *gids); + +/* ttyname.c */ +char *get_process_ttyname(void); + +#endif /* _SUDO_SUDO_H */ diff --git a/src/sudo_edit.c b/src/sudo_edit.c new file mode 100644 index 0000000..f7df6e8 --- /dev/null +++ b/src/sudo_edit.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2004-2008, 2010-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. + */ + +#include + +#include +#include +#include +#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 */ +#include +#include +#include +#include +#include +#include +#if TIME_WITH_SYS_TIME +# include +#endif + +#include "sudo.h" + +#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) + +static void +switch_user(uid_t euid, gid_t egid, int ngroups, GETGROUPS_T *groups) +{ + int serrno = errno; + debug_decl(switch_user, SUDO_DEBUG_EDIT) + + /* When restoring root, change euid first; otherwise change it last. */ + if (euid == ROOT_UID) { + if (seteuid(ROOT_UID) != 0) + error(1, "seteuid(ROOT_UID)"); + } + if (setegid(egid) != 0) + error(1, "setegid(%d)", (int)egid); + if (ngroups != -1) { + if (sudo_setgroups(ngroups, groups) != 0) + error(1, "setgroups"); + } + if (euid != ROOT_UID) { + if (seteuid(euid) != 0) + error(1, "seteuid(%d)", (int)euid); + } + errno = serrno; + + debug_return; +} + +/* + * Wrapper to allow users to edit privileged files with their own uid. + */ +int +sudo_edit(struct command_details *command_details) +{ + struct command_details editor_details; + ssize_t nread, nwritten; + const char *tmpdir; + char *cp, *suff, **nargv, **ap, **files = NULL; + char buf[BUFSIZ]; + int rc, i, j, ac, ofd, tfd, nargc, rval, tmplen; + int editor_argc = 0, nfiles = 0; + struct stat sb; + struct timeval tv, tv1, tv2; + struct tempfile { + char *tfile; + char *ofile; + struct timeval omtim; + off_t osize; + } *tf = NULL; + debug_decl(sudo_edit, SUDO_DEBUG_EDIT) + + /* + * Set real, effective and saved uids to root. + * We will change the euid as needed below. + */ + if (setuid(ROOT_UID) != 0) { + warning(_("unable to change uid to root (%u)"), ROOT_UID); + goto cleanup; + } + + /* + * Find our temporary directory, one of /var/tmp, /usr/tmp, or /tmp + */ + if (stat(_PATH_VARTMP, &sb) == 0 && S_ISDIR(sb.st_mode)) + tmpdir = _PATH_VARTMP; +#ifdef _PATH_USRTMP + else if (stat(_PATH_USRTMP, &sb) == 0 && S_ISDIR(sb.st_mode)) + tmpdir = _PATH_USRTMP; +#endif + else + tmpdir = _PATH_TMP; + tmplen = strlen(tmpdir); + while (tmplen > 0 && tmpdir[tmplen - 1] == '/') + tmplen--; + + /* + * The user's editor must be separated from the files to be + * edited by a "--" option. + */ + for (ap = command_details->argv; *ap != NULL; ap++) { + if (files) + nfiles++; + else if (strcmp(*ap, "--") == 0) + files = ap + 1; + else + editor_argc++; + } + if (nfiles == 0) { + warningx(_("plugin error: missing file list for sudoedit")); + goto cleanup; + } + + /* + * For each file specified by the user, make a temporary version + * and copy the contents of the original to it. + */ + tf = emalloc2(nfiles, sizeof(*tf)); + zero_bytes(tf, nfiles * sizeof(*tf)); + for (i = 0, j = 0; i < nfiles; i++) { + rc = -1; + switch_user(command_details->euid, command_details->egid, + command_details->ngroups, command_details->groups); + if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) { + if (ofd == -1) { + zero_bytes(&sb, sizeof(sb)); /* new file */ + rc = 0; + } else { + rc = fstat(ofd, &sb); + } + } + switch_user(ROOT_UID, user_details.egid, + user_details.ngroups, user_details.groups); + if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) { + if (rc) + warning("%s", files[i]); + else + warningx(_("%s: not a regular file"), files[i]); + if (ofd != -1) + close(ofd); + continue; + } + tf[j].ofile = files[i]; + tf[j].osize = sb.st_size; + mtim_get(&sb, &tf[j].omtim); + if ((cp = strrchr(tf[j].ofile, '/')) != NULL) + cp++; + else + cp = tf[j].ofile; + suff = strrchr(cp, '.'); + if (suff != NULL) { + easprintf(&tf[j].tfile, "%.*s/%.*sXXXXXXXX%s", tmplen, tmpdir, + (int)(size_t)(suff - cp), cp, suff); + } else { + easprintf(&tf[j].tfile, "%.*s/%s.XXXXXXXX", tmplen, tmpdir, cp); + } + if (seteuid(user_details.uid) != 0) + error(1, "seteuid(%d)", (int)user_details.uid); + tfd = mkstemps(tf[j].tfile, suff ? strlen(suff) : 0); + if (seteuid(ROOT_UID) != 0) + error(1, "seteuid(ROOT_UID)"); + if (tfd == -1) { + warning("mkstemps"); + goto cleanup; + } + if (ofd != -1) { + while ((nread = read(ofd, buf, sizeof(buf))) != 0) { + if ((nwritten = write(tfd, buf, nread)) != nread) { + if (nwritten == -1) + warning("%s", tf[j].tfile); + else + warningx(_("%s: short write"), tf[j].tfile); + goto cleanup; + } + } + close(ofd); + } + /* + * We always update the stashed mtime because the time + * resolution of the filesystem the temporary file is on may + * not match that of the filesystem where the file to be edited + * resides. It is OK if touch() fails since we only use the info + * to determine whether or not a file has been modified. + */ + (void) touch(tfd, NULL, &tf[j].omtim); + rc = fstat(tfd, &sb); + if (!rc) + mtim_get(&sb, &tf[j].omtim); + close(tfd); + j++; + } + if ((nfiles = j) == 0) + goto cleanup; /* no files readable, you lose */ + + /* + * Allocate space for the new argument vector and fill it in. + * We concatenate the editor with its args and the file list + * to create a new argv. + */ + nargc = editor_argc + nfiles; + nargv = (char **) emalloc2(nargc + 1, sizeof(char *)); + for (ac = 0; ac < editor_argc; ac++) + nargv[ac] = command_details->argv[ac]; + for (i = 0; i < nfiles && ac < nargc; ) + nargv[ac++] = tf[i++].tfile; + nargv[ac] = NULL; + + /* + * Run the editor with the invoking user's creds, + * keeping track of the time spent in the editor. + */ + gettimeofday(&tv1, NULL); + memcpy(&editor_details, command_details, sizeof(editor_details)); + editor_details.uid = user_details.uid; + editor_details.euid = user_details.uid; + editor_details.gid = user_details.gid; + editor_details.egid = user_details.gid; + editor_details.ngroups = user_details.ngroups; + editor_details.groups = user_details.groups; + editor_details.argv = nargv; + rval = run_command(&editor_details); + gettimeofday(&tv2, NULL); + + /* Copy contents of temp files to real ones */ + for (i = 0; i < nfiles; i++) { + rc = -1; + if (seteuid(user_details.uid) != 0) + error(1, "seteuid(%d)", (int)user_details.uid); + if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) { + rc = fstat(tfd, &sb); + } + if (seteuid(ROOT_UID) != 0) + error(1, "seteuid(ROOT_UID)"); + if (rc || !S_ISREG(sb.st_mode)) { + if (rc) + warning("%s", tf[i].tfile); + else + warningx(_("%s: not a regular file"), tf[i].tfile); + warningx(_("%s left unmodified"), tf[i].ofile); + if (tfd != -1) + close(tfd); + continue; + } + mtim_get(&sb, &tv); + if (tf[i].osize == sb.st_size && timevalcmp(&tf[i].omtim, &tv, ==)) { + /* + * If mtime and size match but the user spent no measurable + * time in the editor we can't tell if the file was changed. + */ + timevalsub(&tv1, &tv2); + if (timevalisset(&tv2)) { + warningx(_("%s unchanged"), tf[i].ofile); + unlink(tf[i].tfile); + close(tfd); + continue; + } + } + switch_user(command_details->euid, command_details->egid, + command_details->ngroups, command_details->groups); + ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644); + switch_user(ROOT_UID, user_details.egid, + user_details.ngroups, user_details.groups); + if (ofd == -1) { + warning(_("unable to write to %s"), tf[i].ofile); + warningx(_("contents of edit session left in %s"), tf[i].tfile); + close(tfd); + continue; + } + while ((nread = read(tfd, buf, sizeof(buf))) > 0) { + if ((nwritten = write(ofd, buf, nread)) != nread) { + if (nwritten == -1) + warning("%s", tf[i].ofile); + else + warningx(_("%s: short write"), tf[i].ofile); + break; + } + } + if (nread == 0) { + /* success, got EOF */ + unlink(tf[i].tfile); + } else if (nread < 0) { + warning(_("unable to read temporary file")); + warningx(_("contents of edit session left in %s"), tf[i].tfile); + } else { + warning(_("unable to write to %s"), tf[i].ofile); + warningx(_("contents of edit session left in %s"), tf[i].tfile); + } + close(ofd); + } + debug_return_int(rval); + +cleanup: + /* Clean up temp files and return. */ + if (tf != NULL) { + for (i = 0; i < nfiles; i++) { + if (tf[i].tfile != NULL) + unlink(tf[i].tfile); + } + } + debug_return_int(1); +} + +#else /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ + +/* + * Must have the ability to change the effective uid to use sudoedit. + */ +int +sudo_edit(struct command_details *command_details) +{ + debug_decl(sudo_edit, SUDO_DEBUG_EDIT) + debug_return_int(1); +} + +#endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ diff --git a/src/sudo_exec.h b/src/sudo_exec.h new file mode 100644 index 0000000..d9ce2e8 --- /dev/null +++ b/src/sudo_exec.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-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_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 sudo_execve(const char *path, char *const argv[], char *const envp[], int noexec); +int pipe_nonblock(int fds[2]); + +/* exec_pty.c */ +struct command_details; +struct command_status; +int fork_pty(struct command_details *details, int sv[], int *maxfd); +int perform_io(fd_set *fdsr, fd_set *fdsw, struct command_status *cstat); +int suspend_parent(int signo); +void fd_set_iobs(fd_set *fdsr, fd_set *fdsw); +void handler(int s); +void pty_close(struct command_status *cstat); +void pty_setup(uid_t uid, const char *tty, const char *utmp_user); +void terminate_child(pid_t pid, bool use_pgrp); +extern int signal_pipe[2]; + +/* utmp.c */ +bool utmp_login(const char *from_line, const char *to_line, int ttyfd, + const char *user); +bool utmp_logout(const char *line, int status); + +#endif /* _SUDO_EXEC_H */ diff --git a/src/sudo_noexec.c b/src/sudo_noexec.c new file mode 100644 index 0000000..af1915f --- /dev/null +++ b/src/sudo_noexec.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2004-2005, 2010-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. + */ + +#include + +#include + +#include +#include +#ifdef HAVE_SPAWN_H +#include +#endif + +#include "missing.h" + +/* + * Dummy versions of the execve() family of syscalls. We don't need + * to stub out all of them, just the ones that correspond to actual + * system calls (which varies by OS). Note that it is still possible + * to access the real syscalls via the syscall() interface but very + * few programs actually do that. + */ + +#define DUMMY_BODY \ +{ \ + errno = EACCES; \ + return -1; \ +} + +#define DUMMY2(fn, t1, t2) \ +int \ +fn(t1 a1, t2 a2) \ +DUMMY_BODY + +#define DUMMY3(fn, t1, t2, t3) \ +int \ +fn(t1 a1, t2 a2, t3 a3) \ +DUMMY_BODY + +#define DUMMY6(fn, t1, t2, t3, t4, t5, t6) \ +int \ +fn(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \ +DUMMY_BODY + +#define DUMMY_VA(fn, t1, t2) \ +int \ +fn(t1 a1, t2 a2, ...) \ +DUMMY_BODY + +DUMMY_VA(execl, const char *, const char *) +DUMMY_VA(_execl, const char *, const char *) +DUMMY_VA(__execl, const char *, const char *) +DUMMY_VA(execle, const char *, const char *) +DUMMY_VA(_execle, const char *, const char *) +DUMMY_VA(__execle, const char *, const char *) +DUMMY_VA(execlp, const char *, const char *) +DUMMY_VA(_execlp, const char *, const char *) +DUMMY_VA(__execlp, const char *, const char *) +DUMMY3(exect, const char *, char * const *, char * const *) +DUMMY3(_exect, const char *, char * const *, char * const *) +DUMMY3(__exect, const char *, char * const *, char * const *) +DUMMY2(execv, const char *, char * const *) +DUMMY2(_execv, const char *, char * const *) +DUMMY2(__execv, const char *, char * const *) +DUMMY2(execvp, const char *, char * const *) +DUMMY2(_execvp, const char *, char * const *) +DUMMY2(__execvp, const char *, char * const *) +DUMMY3(execvP, const char *, const char *, char * const *) +DUMMY3(_execvP, const char *, const char *, char * const *) +DUMMY3(__execvP, const char *, const char *, char * const *) +DUMMY3(execve, const char *, char * const *, char * const *) +DUMMY3(_execve, const char *, char * const *, char * const *) +DUMMY3(__execve, const char *, char * const *, char * const *) +DUMMY3(execvpe, const char *, char * const *, char * const *) +DUMMY3(_execvpe, const char *, char * const *, char * const *) +DUMMY3(__execvpe, const char *, char * const *, char * const *) +DUMMY3(fexecve, int , char * const *, char * const *) +DUMMY3(_fexecve, int , char * const *, char * const *) +DUMMY3(__fexecve, int , char * const *, char * const *) +#ifdef HAVE_SPAWN_H +DUMMY6(posix_spawn, pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char * const *, char * const *) +DUMMY6(_posix_spawn, pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char * const *, char * const *) +DUMMY6(__posix_spawn, pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char * const *, char * const *) +DUMMY6(posix_spawnp, pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char * const *, char * const *) +DUMMY6(_posix_spawnp, pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char * const *, char * const *) +DUMMY6(__posix_spawnp, pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char * const *, char * const *) +#endif /* HAVE_SPAWN_H */ diff --git a/src/sudo_plugin_int.h b/src/sudo_plugin_int.h new file mode 100644 index 0000000..aff2344 --- /dev/null +++ b/src/sudo_plugin_int.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2010-2012 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_PLUGIN_INT_H +#define _SUDO_PLUGIN_INT_H + +/* + * All plugin structures start with a type and a version. + */ +struct generic_plugin { + unsigned int type; + unsigned int version; + /* the rest depends on the type... */ +}; + +/* + * Backwards-compatible structures for API bumps. + */ +struct policy_plugin_1_0 { + unsigned int type; + unsigned int version; + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], char * const user_env[]); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*check_policy)(int argc, char * const argv[], + char *env_add[], char **command_info[], + char **argv_out[], char **user_env_out[]); + int (*list)(int argc, char * const argv[], int verbose, + const char *list_user); + int (*validate)(void); + void (*invalidate)(int remove); + int (*init_session)(struct passwd *pwd); +}; +struct io_plugin_1_0 { + unsigned int type; + unsigned int version; + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], int argc, char * const argv[], + char * const user_env[]); + void (*close)(int exit_status, int error); + int (*show_version)(int verbose); + int (*log_ttyin)(const char *buf, unsigned int len); + int (*log_ttyout)(const char *buf, unsigned int len); + int (*log_stdin)(const char *buf, unsigned int len); + int (*log_stdout)(const char *buf, unsigned int len); + int (*log_stderr)(const char *buf, unsigned int len); +}; +struct io_plugin_1_1 { + unsigned int type; + unsigned int version; + int (*open)(unsigned int version, sudo_conv_t conversation, + sudo_printf_t sudo_printf, char * const settings[], + char * const user_info[], char * const command_info[], + int argc, char * const argv[], char * const user_env[]); + void (*close)(int exit_status, int error); /* wait status or error */ + int (*show_version)(int verbose); + int (*log_ttyin)(const char *buf, unsigned int len); + int (*log_ttyout)(const char *buf, unsigned int len); + int (*log_stdin)(const char *buf, unsigned int len); + int (*log_stdout)(const char *buf, unsigned int len); + int (*log_stderr)(const char *buf, unsigned int len); +}; + +/* + * Sudo plugin internals. + */ +struct plugin_container { + struct plugin_container *prev; /* required */ + struct plugin_container *next; /* required */ + const char *name; + char * const *options; + void *handle; + union { + struct generic_plugin *generic; + struct policy_plugin *policy; + struct policy_plugin_1_0 *policy_1_0; + struct io_plugin *io; + struct io_plugin_1_0 *io_1_0; + struct io_plugin_1_1 *io_1_1; + } u; +}; +TQ_DECLARE(plugin_container) + +extern struct plugin_container_list policy_plugins; +extern struct plugin_container_list io_plugins; + +int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[]); +int _sudo_printf(int msg_type, const char *fmt, ...); + +bool sudo_load_plugins(struct plugin_container *policy_plugin, + struct plugin_container_list *io_plugins); + +#endif /* _SUDO_PLUGIN_INT_H */ diff --git a/src/sudo_usage.h.in b/src/sudo_usage.h.in new file mode 100644 index 0000000..4f6288b --- /dev/null +++ b/src/sudo_usage.h.in @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2007-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. + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SUDO_USAGE_H +#define _SUDO_USAGE_H + +/* + * Usage strings for sudo. These are here because we + * need to be able to substitute values from configure. + */ +#define SUDO_USAGE1 " [-D level] -h | -K | -k | -V" +#define SUDO_USAGE2 " -v [-AknS] @BSDAUTH_USAGE@[-D level] [-g groupname|#gid] [-p prompt] [-u user name|#uid]" +#define SUDO_USAGE3 " -l[l] [-AknS] @BSDAUTH_USAGE@[-D level] [-g groupname|#gid] [-p prompt] [-U user name] [-u user name|#uid] [-g groupname|#gid] [command]" +#define SUDO_USAGE4 " [-AbEHknPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] [-D level] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] []" +#define SUDO_USAGE5 " -e [-AknS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] [-D level] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] file ..." + +/* + * Configure script arguments used to build sudo. + */ +#define CONFIGURE_ARGS "@CONFIGURE_ARGS@" + +#endif /* _SUDO_USAGE_H */ diff --git a/src/tgetpass.c b/src/tgetpass.c new file mode 100644 index 0000000..b23db4c --- /dev/null +++ b/src/tgetpass.c @@ -0,0 +1,334 @@ +/* + * 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. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#ifdef __TANDEM +# include +#endif + +#include + +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#include + +#include "sudo.h" + +static volatile sig_atomic_t signo[NSIG]; + +static void handler(int); +static char *getln(int, char *, size_t, int); +static char *sudo_askpass(const char *, const char *); + +/* + * Like getpass(3) but with timeout and echo flags. + */ +char * +tgetpass(const char *prompt, int timeout, int flags) +{ + sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm; + sigaction_t savetstp, savettin, savettou, savepipe; + char *pass; + static const char *askpass; + static char buf[SUDO_PASS_MAX + 1]; + int i, input, output, save_errno, neednl = 0, need_restart; + debug_decl(tgetpass, SUDO_DEBUG_CONV) + + (void) fflush(stdout); + + if (askpass == NULL) { + askpass = getenv_unhooked("SUDO_ASKPASS"); + if (askpass == NULL || *askpass == '\0') + askpass = sudo_conf_askpass_path(); + } + + /* If no tty present and we need to disable echo, try askpass. */ + if (!ISSET(flags, TGP_STDIN|TGP_ECHO|TGP_ASKPASS|TGP_NOECHO_TRY) && + !tty_present()) { + if (askpass == NULL || getenv_unhooked("DISPLAY") == NULL) { + warningx(_("no tty present and no askpass program specified")); + debug_return_str(NULL); + } + SET(flags, TGP_ASKPASS); + } + + /* If using a helper program to get the password, run it instead. */ + if (ISSET(flags, TGP_ASKPASS)) { + if (askpass == NULL || *askpass == '\0') + errorx(1, _("no askpass program specified, try setting SUDO_ASKPASS")); + debug_return_str_masked(sudo_askpass(askpass, prompt)); + } + +restart: + for (i = 0; i < NSIG; i++) + signo[i] = 0; + pass = NULL; + save_errno = 0; + need_restart = 0; + /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */ + if (ISSET(flags, TGP_STDIN) || + (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) { + input = STDIN_FILENO; + output = STDERR_FILENO; + } + + /* + * If we are using a tty but are not the foreground pgrp this will + * generate SIGTTOU, so do it *before* installing the signal handlers. + */ + if (!ISSET(flags, TGP_ECHO)) { + if (ISSET(flags, TGP_MASK)) + neednl = term_cbreak(input); + else + neednl = term_noecho(input); + } + + /* + * Catch signals that would otherwise cause the user to end + * up with echo turned off in the shell. + */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */ + sa.sa_handler = handler; + (void) sigaction(SIGALRM, &sa, &savealrm); + (void) sigaction(SIGINT, &sa, &saveint); + (void) sigaction(SIGHUP, &sa, &savehup); + (void) sigaction(SIGQUIT, &sa, &savequit); + (void) sigaction(SIGTERM, &sa, &saveterm); + (void) sigaction(SIGTSTP, &sa, &savetstp); + (void) sigaction(SIGTTIN, &sa, &savettin); + (void) sigaction(SIGTTOU, &sa, &savettou); + + /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */ + sa.sa_handler = SIG_IGN; + (void) sigaction(SIGPIPE, &sa, &savepipe); + + if (prompt) { + if (write(output, prompt, strlen(prompt)) == -1) + goto restore; + } + + if (timeout > 0) + alarm(timeout); + pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK)); + alarm(0); + save_errno = errno; + + if (neednl || pass == NULL) { + if (write(output, "\n", 1) == -1) + goto restore; + } + +restore: + /* Restore old tty settings and signals. */ + if (!ISSET(flags, TGP_ECHO)) + term_restore(input, 1); + (void) sigaction(SIGALRM, &savealrm, NULL); + (void) sigaction(SIGINT, &saveint, NULL); + (void) sigaction(SIGHUP, &savehup, NULL); + (void) sigaction(SIGQUIT, &savequit, NULL); + (void) sigaction(SIGTERM, &saveterm, NULL); + (void) sigaction(SIGTSTP, &savetstp, NULL); + (void) sigaction(SIGTTIN, &savettin, NULL); + (void) sigaction(SIGTTOU, &savettou, NULL); + (void) sigaction(SIGTTOU, &savepipe, NULL); + if (input != STDIN_FILENO) + (void) close(input); + + /* + * If we were interrupted by a signal, resend it to ourselves + * now that we have restored the signal handlers. + */ + for (i = 0; i < NSIG; i++) { + if (signo[i]) { + kill(getpid(), i); + switch (i) { + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + need_restart = 1; + break; + } + } + } + if (need_restart) + goto restart; + + if (save_errno) + errno = save_errno; + + debug_return_str_masked(pass); +} + +/* + * Fork a child and exec sudo-askpass to get the password from the user. + */ +static char * +sudo_askpass(const char *askpass, const char *prompt) +{ + static char buf[SUDO_PASS_MAX + 1], *pass; + sigaction_t sa, saved_sa_pipe; + int pfd[2]; + pid_t pid; + debug_decl(sudo_askpass, SUDO_DEBUG_CONV) + + if (pipe(pfd) == -1) + error(1, _("unable to create pipe")); + + if ((pid = fork()) == -1) + error(1, _("unable to fork")); + + if (pid == 0) { + /* child, point stdout to output side of the pipe and exec askpass */ + if (dup2(pfd[1], STDOUT_FILENO) == -1) { + warning("dup2"); + _exit(255); + } + (void) setuid(ROOT_UID); + if (setgid(user_details.gid)) { + warning(_("unable to set gid to %u"), (unsigned int)user_details.gid); + _exit(255); + } + if (setuid(user_details.uid)) { + warning(_("unable to set uid to %u"), (unsigned int)user_details.uid); + _exit(255); + } + closefrom(STDERR_FILENO + 1); + execl(askpass, askpass, prompt, (char *)NULL); + warning(_("unable to run %s"), askpass); + _exit(255); + } + + /* Ignore SIGPIPE in case child exits prematurely */ + zero_bytes(&sa, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_INTERRUPT; + sa.sa_handler = SIG_IGN; + (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe); + + /* Get response from child (askpass) and restore SIGPIPE handler */ + (void) close(pfd[1]); + pass = getln(pfd[0], buf, sizeof(buf), 0); + (void) close(pfd[0]); + (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL); + + if (pass == NULL) + errno = EINTR; /* make cancel button simulate ^C */ + + debug_return_str_masked(pass); +} + +extern int term_erase, term_kill; + +static char * +getln(int fd, char *buf, size_t bufsiz, int feedback) +{ + size_t left = bufsiz; + ssize_t nr = -1; + char *cp = buf; + char c = '\0'; + debug_decl(getln, SUDO_DEBUG_CONV) + + if (left == 0) { + errno = EINVAL; + debug_return_str(NULL); /* sanity */ + } + + while (--left) { + nr = read(fd, &c, 1); + if (nr != 1 || c == '\n' || c == '\r') + break; + if (feedback) { + if (c == term_kill) { + while (cp > buf) { + if (write(fd, "\b \b", 3) == -1) + break; + --cp; + } + left = bufsiz; + continue; + } else if (c == term_erase) { + if (cp > buf) { + if (write(fd, "\b \b", 3) == -1) + break; + --cp; + left++; + } + continue; + } + ignore_result(write(fd, "*", 1)); + } + *cp++ = c; + } + *cp = '\0'; + if (feedback) { + /* erase stars */ + while (cp > buf) { + if (write(fd, "\b \b", 3) == -1) + break; + --cp; + } + } + + debug_return_str_masked(nr == 1 ? buf : NULL); +} + +static void +handler(int s) +{ + if (s != SIGALRM) + signo[s] = 1; +} + +int +tty_present(void) +{ + int fd; + debug_decl(tty_present, SUDO_DEBUG_UTIL) + + if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1) + close(fd); + debug_return_bool(fd != -1); +} diff --git a/src/ttyname.c b/src/ttyname.c new file mode 100644 index 0000000..aa06acf --- /dev/null +++ b/src/ttyname.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2012 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. + */ + +#include + +/* Large files not supported by procfs.h */ +#if defined(HAVE_PROCFS_H) || defined(HAVE_SYS_PROCFS_H) +# undef _FILE_OFFSET_BITS +# undef _LARGE_FILES +#endif + +#include +#include +#include +#if defined(MAJOR_IN_MKDEV) +# include +#elif defined(MAJOR_IN_SYSMACROS) +# include +#endif +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#include +#include +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif +#if defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) || defined (HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) || defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) +# include +#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) +# include +# include +#endif +#if defined(HAVE_PROCFS_H) +# include +#elif defined(HAVE_SYS_PROCFS_H) +# include +#endif + +#include "sudo.h" + +/* + * How to access the tty device number in struct kinfo_proc. + */ +#if defined(HAVE_STRUCT_KINFO_PROC2_P_TDEV) +# define SUDO_KERN_PROC KERN_PROC2 +# define sudo_kinfo_proc kinfo_proc2 +# define sudo_kp_tdev p_tdev +# define sudo_kp_namelen 6 +#elif defined(HAVE_STRUCT_KINFO_PROC_P_TDEV) +# define SUDO_KERN_PROC KERN_PROC +# define sudo_kinfo_proc kinfo_proc +# define sudo_kp_tdev p_tdev +# define sudo_kp_namelen 6 +#elif defined(HAVE_STRUCT_KINFO_PROC_KI_TDEV) +# define SUDO_KERN_PROC KERN_PROC +# define sudo_kinfo_proc kinfo_proc +# define sudo_kp_tdev ki_tdev +# define sudo_kp_namelen 4 +#elif defined(HAVE_STRUCT_KINFO_PROC_KP_EPROC_E_TDEV) +# define SUDO_KERN_PROC KERN_PROC +# define sudo_kinfo_proc kinfo_proc +# define sudo_kp_tdev kp_eproc.e_tdev +# define sudo_kp_namelen 4 +#endif + +#if defined(sudo_kp_tdev) +/* + * Like ttyname() but uses a dev_t instead of an open fd. + * Caller is responsible for freeing the returned string. + * The BSD version uses devname() + */ +static char * +sudo_ttyname_dev(dev_t tdev) +{ + char *dev, *tty = NULL; + debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL) + + /* Some versions of devname() return NULL on failure, others do not. */ + dev = devname(tdev, S_IFCHR); + if (dev != NULL && *dev != '?' && *dev != '#') { + if (*dev != '/') { + /* devname() doesn't use the /dev/ prefix, add one... */ + size_t len = sizeof(_PATH_DEV) + strlen(dev); + tty = emalloc(len); + strlcpy(tty, _PATH_DEV, len); + strlcat(tty, dev, len); + } else { + /* Should not happen but just in case... */ + tty = estrdup(dev); + } + } + debug_return_str(tty); +} +#elif defined(HAVE__TTYNAME_DEV) +extern char *_ttyname_dev(dev_t rdev, char *buffer, size_t buflen); + +/* + * Like ttyname() but uses a dev_t instead of an open fd. + * Caller is responsible for freeing the returned string. + * This version is just a wrapper around _ttyname_dev(). + */ +static char * +sudo_ttyname_dev(dev_t tdev) +{ + char buf[TTYNAME_MAX], *tty; + debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL) + + tty = _ttyname_dev(tdev, buf, sizeof(buf)); + + debug_return_str(estrdup(tty)); +} +#else +/* + * Devices to search before doing a breadth-first scan. + */ +static char *search_devs[] = { + "/dev/console", + "/dev/wscons", + "/dev/pts/", + "/dev/vt/", + "/dev/term/", + "/dev/zcons/", + NULL +}; + +static char *ignore_devs[] = { + "/dev/fd/", + "/dev/stdin", + "/dev/stdout", + "/dev/stderr", + NULL +}; + +/* + * Do a breadth-first scan of dir looking for the specified device. + */ +static +char *sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin) +{ + DIR *d; + char pathbuf[PATH_MAX], **subdirs = NULL, *devname = NULL; + size_t sdlen, d_len, len, num_subdirs = 0, max_subdirs = 0; + struct dirent *dp; + struct stat sb; + int i; + debug_decl(sudo_ttyname_scan, SUDO_DEBUG_UTIL) + + if (dir[0] == '\0' || (d = opendir(dir)) == NULL) + goto done; + + sdlen = strlen(dir); + if (dir[sdlen - 1] == '/') + sdlen--; + if (sdlen + 1 >= sizeof(pathbuf)) { + errno = ENAMETOOLONG; + warning("%.*s/", (int)sdlen, dir); + goto done; + } + memcpy(pathbuf, dir, sdlen); + pathbuf[sdlen++] = '/'; + pathbuf[sdlen] = '\0'; + + while ((dp = readdir(d)) != NULL) { + /* Skip anything starting with "." */ + if (dp->d_name[0] == '.') + continue; + + d_len = NAMLEN(dp); + if (sdlen + d_len >= sizeof(pathbuf)) + continue; + memcpy(&pathbuf[sdlen], dp->d_name, d_len + 1); /* copy NUL too */ + d_len += sdlen; + + for (i = 0; ignore_devs[i] != NULL; i++) { + len = strlen(ignore_devs[i]); + if (ignore_devs[i][len - 1] == '/') + len--; + if (d_len == len && strncmp(pathbuf, ignore_devs[i], len) == 0) + break; + } + if (ignore_devs[i] != NULL) + continue; + if (!builtin) { + /* Skip entries in search_devs; we already checked them. */ + for (i = 0; search_devs[i] != NULL; i++) { + len = strlen(search_devs[i]); + if (search_devs[i][len - 1] == '/') + len--; + if (d_len == len && strncmp(pathbuf, search_devs[i], len) == 0) + break; + } + if (search_devs[i] != NULL) + continue; + } +# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF) + /* Use d_type to avoid a stat() if possible. */ + /* Convert d_type to stat-style type bits but follow links. */ + if (dp->d_type != DT_LNK && dp->d_type != DT_CHR) + sb.st_mode = DTTOIF(dp->d_type); + else +# endif + if (stat(pathbuf, &sb) == -1) + continue; + if (S_ISDIR(sb.st_mode)) { + if (!builtin) { + /* Add to list of subdirs to search. */ + if (num_subdirs + 1 > max_subdirs) { + max_subdirs += 64; + subdirs = erealloc3(subdirs, max_subdirs, sizeof(char *)); + } + subdirs[num_subdirs++] = estrdup(pathbuf); + } + continue; + } + if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { + devname = estrdup(pathbuf); + break; + } + } + closedir(d); + + /* Search subdirs if we didn't find it in the root level. */ + for (i = 0; devname == NULL && i < num_subdirs; i++) + devname = sudo_ttyname_scan(subdirs[i], rdev, false); + +done: + for (i = 0; i < num_subdirs; i++) + efree(subdirs[i]); + efree(subdirs); + debug_return_str(devname); +} + +/* + * Like ttyname() but uses a dev_t instead of an open fd. + * Caller is responsible for freeing the returned string. + * Generic version. + */ +static char * +sudo_ttyname_dev(dev_t rdev) +{ + struct stat sb; + size_t len; + char buf[PATH_MAX], **sd, *devname, *tty = NULL; + debug_decl(sudo_ttyname_dev, SUDO_DEBUG_UTIL) + + /* + * First check search_devs. + */ + for (sd = search_devs; (devname = *sd) != NULL; sd++) { + len = strlen(devname); + if (devname[len - 1] == '/') { + /* Special case /dev/pts */ + if (strcmp(devname, "/dev/pts/") == 0) { + (void)snprintf(buf, sizeof(buf), "%spts/%u", _PATH_DEV, + (unsigned int)minor(rdev)); + if (stat(buf, &sb) == 0) { + if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { + tty = estrdup(buf); + break; + } + } + continue; + } + /* Traverse directory */ + tty = sudo_ttyname_scan(devname, rdev, true); + } else { + if (stat(devname, &sb) == 0) { + if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) { + tty = estrdup(devname); + break; + } + } + } + } + + /* + * Not found? Do a breadth-first traversal of /dev/. + */ + if (tty == NULL) + tty = sudo_ttyname_scan(_PATH_DEV, rdev, false); + + debug_return_str(tty); +} +#endif + +#if defined(sudo_kp_tdev) +/* + * Return a string from ttyname() containing the tty to which the process is + * attached or NULL if there is no tty associated with the process (or its + * parent). First tries sysctl using the current pid, then the parent's pid. + * Falls back on ttyname of std{in,out,err} if that fails. + */ +char * +get_process_ttyname(void) +{ + char *tty = NULL; + struct sudo_kinfo_proc *ki_proc = NULL; + size_t size = sizeof(*ki_proc); + int i, mib[6], rc; + debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) + + /* + * Lookup tty for this process and, failing that, our parent. + * Even if we redirect std{in,out,err} the kernel should still know. + */ + for (i = 0; tty == NULL && i < 2; i++) { + mib[0] = CTL_KERN; + mib[1] = SUDO_KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = i ? (int)getppid() : (int)getpid(); + mib[4] = sizeof(*ki_proc); + mib[5] = 1; + do { + size += size / 10; + ki_proc = erealloc(ki_proc, size); + rc = sysctl(mib, sudo_kp_namelen, ki_proc, &size, NULL, 0); + } while (rc == -1 && errno == ENOMEM); + if (rc != -1) { + if (ki_proc->sudo_kp_tdev != (dev_t)-1) { + tty = sudo_ttyname_dev(ki_proc->sudo_kp_tdev); + if (tty == NULL) { + sudo_debug_printf(SUDO_DEBUG_WARN, + "unable to map device number %u to name", + ki_proc->sudo_kp_tdev); + } + } + } else { + sudo_debug_printf(SUDO_DEBUG_WARN, + "unable to resolve tty via KERN_PROC: %s", strerror(errno)); + } + } + efree(ki_proc); + + /* If all else fails, fall back on ttyname(). */ + if (tty == NULL) { + if ((tty = ttyname(STDIN_FILENO)) != NULL || + (tty = ttyname(STDOUT_FILENO)) != NULL || + (tty = ttyname(STDERR_FILENO)) != NULL) + tty = estrdup(tty); + } + + debug_return_str(tty); +} +#elif defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) +/* + * Return a string from ttyname() containing the tty to which the process is + * attached or NULL if there is no tty associated with the process (or its + * parent). First tries /proc/pid/psinfo, then /proc/ppid/psinfo. + * Falls back on ttyname of std{in,out,err} if that fails. + */ +char * +get_process_ttyname(void) +{ + char path[PATH_MAX], *tty = NULL; + struct stat sb; + struct psinfo psinfo; + ssize_t nread; + int i, fd; + debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) + + /* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */ + for (i = 0; tty == NULL && i < 2; i++) { + (void)snprintf(path, sizeof(path), "/proc/%u/psinfo", + i ? (unsigned int)getppid() : (unsigned int)getpid()); + if ((fd = open(path, O_RDONLY, 0)) == -1) + continue; + nread = read(fd, &psinfo, sizeof(psinfo)); + close(fd); + if (nread == (ssize_t)sizeof(psinfo) && psinfo.pr_ttydev != (dev_t)-1) { + tty = sudo_ttyname_dev(psinfo.pr_ttydev); + } + } + + /* If all else fails, fall back on ttyname(). */ + if (tty == NULL) { + if ((tty = ttyname(STDIN_FILENO)) != NULL || + (tty = ttyname(STDOUT_FILENO)) != NULL || + (tty = ttyname(STDERR_FILENO)) != NULL) + tty = estrdup(tty); + } + + debug_return_str(tty); +} +#elif defined(__linux__) +/* + * Return a string from ttyname() containing the tty to which the process is + * attached or NULL if there is no tty associated with the process (or its + * parent). First tries field 7 in /proc/pid/stat, then /proc/ppid/stat. + * Falls back on ttyname of std{in,out,err} if that fails. + */ +char * +get_process_ttyname(void) +{ + char *line = NULL, *tty = NULL; + size_t linesize = 0; + ssize_t len; + int i; + debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) + + /* Try to determine the tty from pr_ttydev in /proc/pid/psinfo. */ + for (i = 0; tty == NULL && i < 2; i++) { + FILE *fp; + char path[PATH_MAX]; + (void)snprintf(path, sizeof(path), "/proc/%u/stat", + i ? (unsigned int)getppid() : (unsigned int)getpid()); + if ((fp = fopen(path, "r")) == NULL) + continue; + len = getline(&line, &linesize, fp); + fclose(fp); + if (len != -1) { + /* Field 7 is the tty dev (0 if no tty) */ + char *cp = line; + int field = 1; + while (*cp != '\0') { + if (*cp++ == ' ') { + if (++field == 7) { + dev_t tdev = (dev_t)atoi(cp); + if (tdev > 0) + tty = sudo_ttyname_dev(tdev); + break; + } + } + } + } + } + efree(line); + + /* If all else fails, fall back on ttyname(). */ + if (tty == NULL) { + if ((tty = ttyname(STDIN_FILENO)) != NULL || + (tty = ttyname(STDOUT_FILENO)) != NULL || + (tty = ttyname(STDERR_FILENO)) != NULL) + tty = estrdup(tty); + } + + debug_return_str(tty); +} +#else +/* + * Return a string from ttyname() containing the tty to which the process is + * attached or NULL if there is no tty associated with the process. + * parent). + */ +char * +get_process_ttyname(void) +{ + char *tty; + debug_decl(get_process_ttyname, SUDO_DEBUG_UTIL) + + if ((tty = ttyname(STDIN_FILENO)) == NULL) { + if ((tty = ttyname(STDOUT_FILENO)) == NULL) + tty = ttyname(STDERR_FILENO); + } + + debug_return_str(estrdup(tty)); +} +#endif diff --git a/src/utmp.c b/src/utmp.c new file mode 100644 index 0000000..427cdc5 --- /dev/null +++ b/src/utmp.c @@ -0,0 +1,374 @@ +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# 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 +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_UNISTD_H +# include +#endif /* HAVE_UNISTD_H */ +#if TIME_WITH_SYS_TIME +# include +#endif +#ifdef HAVE_UTMPX_H +# include +#else +# include +#endif /* HAVE_UTMPX_H */ +#ifdef HAVE_GETTTYENT +# include +#endif +#include + +#include "sudo.h" +#include "sudo_exec.h" + +/* + * Simplify handling of utmp vs. utmpx + */ +#if !defined(HAVE_GETUTXID) && defined(HAVE_GETUTID) +# define getutxline(u) getutline(u) +# define pututxline(u) pututline(u) +# define setutxent() setutent() +# define endutxent() endutent() +#endif /* !HAVE_GETUTXID && HAVE_GETUTID */ + +#ifdef HAVE_GETUTXID +typedef struct utmpx sudo_utmp_t; +#else +typedef struct utmp sudo_utmp_t; +/* Older systems have ut_name, not us_user */ +# if !defined(HAVE_STRUCT_UTMP_UT_USER) && !defined(ut_user) +# define ut_user ut_name +# endif +#endif + +/* HP-UX has __e_termination and __e_exit, others lack the __ */ +#if defined(HAVE_STRUCT_UTMPX_UT_EXIT_E_TERMINATION) || defined(HAVE_STRUCT_UTMP_UT_EXIT_E_TERMINATION) +# undef __e_termination +# define __e_termination e_termination +# undef __e_exit +# define __e_exit e_exit +#endif + +#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID) +/* + * Create ut_id from the new ut_line and the old ut_id. + */ +static void +utmp_setid(sudo_utmp_t *old, sudo_utmp_t *new) +{ + const char *line = new->ut_line; + size_t idlen; + debug_decl(utmp_setid, SUDO_DEBUG_UTMP) + + /* Skip over "tty" in the id if old entry did too. */ + if (old != NULL) { + if (strncmp(line, "tty", 3) == 0) { + idlen = MIN(sizeof(old->ut_id), 3); + if (strncmp(old->ut_id, "tty", idlen) != 0) + line += 3; + } + } + + /* Store as much as will fit, skipping parts of the beginning as needed. */ + idlen = strlen(line); + if (idlen > sizeof(new->ut_id)) { + line += idlen - sizeof(new->ut_id); + idlen = sizeof(new->ut_id); + } + strncpy(new->ut_id, line, idlen); + + debug_return; +} +#endif /* HAVE_GETUTXID || HAVE_GETUTID */ + +/* + * Store time in utmp structure. + */ +static void +utmp_settime(sudo_utmp_t *ut) +{ + struct timeval tv; + debug_decl(utmp_settime, SUDO_DEBUG_UTMP) + + gettimeofday(&tv, NULL); + +#if defined(HAVE_STRUCT_UTMP_UT_TV) || defined(HAVE_STRUCT_UTMPX_UT_TV) + ut->ut_tv.tv_sec = tv.tv_sec; + ut->ut_tv.tv_usec = tv.tv_usec; +#else + ut->ut_time = tv.tv_sec; +#endif + + debug_return; +} + +/* + * Fill in a utmp entry, using an old entry as a template if there is one. + */ +static void +utmp_fill(const char *line, const char *user, sudo_utmp_t *ut_old, + sudo_utmp_t *ut_new) +{ + debug_decl(utmp_file, SUDO_DEBUG_UTMP) + + if (ut_old == NULL) { + memset(ut_new, 0, sizeof(*ut_new)); + if (user == NULL) { + strncpy(ut_new->ut_user, user_details.username, + sizeof(ut_new->ut_user)); + } + } else if (ut_old != ut_new) { + memcpy(ut_new, ut_old, sizeof(*ut_new)); + } + if (user != NULL) + strncpy(ut_new->ut_user, user, sizeof(ut_new->ut_user)); + strncpy(ut_new->ut_line, line, sizeof(ut_new->ut_line)); +#if defined(HAVE_STRUCT_UTMPX_UT_ID) || defined(HAVE_STRUCT_UTMP_UT_ID) + utmp_setid(ut_old, ut_new); +#endif +#if defined(HAVE_STRUCT_UTMPX_UT_PID) || defined(HAVE_STRUCT_UTMP_UT_PID) + ut_new->ut_pid = getpid(); +#endif + utmp_settime(ut_new); +#if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE) + ut_new->ut_type = USER_PROCESS; +#endif + debug_return; +} + +/* + * There are two basic utmp file types: + * + * POSIX: sequential access with new entries appended to the end. + * Manipulated via {get,put}utent()/{get,put}getutxent(). + * + * Legacy: sparse file indexed by ttyslot() * sizeof(struct utmp) + */ +#if defined(HAVE_GETUTXID) || defined(HAVE_GETUTID) +bool +utmp_login(const char *from_line, const char *to_line, int ttyfd, + const char *user) +{ + sudo_utmp_t utbuf, *ut_old = NULL; + bool rval = false; + debug_decl(utmp_login, SUDO_DEBUG_UTMP) + + /* Strip off /dev/ prefix from line as needed. */ + if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + to_line += sizeof(_PATH_DEV) - 1; + setutxent(); + if (from_line != NULL) { + if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + from_line += sizeof(_PATH_DEV) - 1; + + /* Lookup old line. */ + memset(&utbuf, 0, sizeof(utbuf)); + strncpy(utbuf.ut_line, from_line, sizeof(utbuf.ut_line)); + ut_old = getutxline(&utbuf); + } + utmp_fill(to_line, user, ut_old, &utbuf); + if (pututxline(&utbuf) != NULL) + rval = true; + endutxent(); + + debug_return_bool(rval); +} + +bool +utmp_logout(const char *line, int status) +{ + bool rval = false; + sudo_utmp_t *ut, utbuf; + debug_decl(utmp_logout, SUDO_DEBUG_UTMP) + + /* Strip off /dev/ prefix from line as needed. */ + if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + line += sizeof(_PATH_DEV) - 1; + + memset(&utbuf, 0, sizeof(utbuf)); + strncpy(utbuf.ut_line, line, sizeof(utbuf.ut_line)); + if ((ut = getutxline(&utbuf)) != NULL) { + memset(ut->ut_user, 0, sizeof(ut->ut_user)); +# if defined(HAVE_STRUCT_UTMPX_UT_TYPE) || defined(HAVE_STRUCT_UTMP_UT_TYPE) + ut->ut_type = DEAD_PROCESS; +# endif +# if defined(HAVE_STRUCT_UTMPX_UT_EXIT) || defined(HAVE_STRUCT_UTMP_UT_EXIT) + ut->ut_exit.__e_exit = WEXITSTATUS(status); + ut->ut_exit.__e_termination = WIFEXITED(status) ? WEXITSTATUS(status) : 0; +# endif + utmp_settime(ut); + if (pututxline(ut) != NULL) + rval = true; + } + debug_return_bool(rval); +} + +#else /* !HAVE_GETUTXID && !HAVE_GETUTID */ + +/* + * Find the slot for the specified line (tty name and file descriptor). + * Returns a slot suitable for seeking into utmp on success or <= 0 on error. + * If getttyent() is available we can use that to compute the slot. + */ +# ifdef HAVE_GETTTYENT +static int +utmp_slot(const char *line, int ttyfd) +{ + int slot = 1; + struct ttyent *tty; + debug_decl(utmp_slot, SUDO_DEBUG_UTMP) + + setttyent(); + while ((tty = getttyent()) != NULL) { + if (strcmp(line, tty->ty_name) == 0) + break; + slot++; + } + endttyent(); + debug_return_int(tty ? slot : 0); +} +# else +static int +utmp_slot(const char *line, int ttyfd) +{ + int sfd, slot; + debug_decl(utmp_slot, SUDO_DEBUG_UTMP) + + /* + * Temporarily point stdin to the tty since ttyslot() + * doesn't take an argument. + */ + if ((sfd = dup(STDIN_FILENO)) == -1) + error(1, _("unable to save stdin")); + if (dup2(ttyfd, STDIN_FILENO) == -1) + error(1, _("unable to dup2 stdin")); + slot = ttyslot(); + if (dup2(sfd, STDIN_FILENO) == -1) + error(1, _("unable to restore stdin")); + close(sfd); + + debug_return_int(slot); +} +# endif /* HAVE_GETTTYENT */ + +bool +utmp_login(const char *from_line, const char *to_line, int ttyfd, + const char *user) +{ + sudo_utmp_t utbuf, *ut_old = NULL; + bool rval = false; + int slot; + FILE *fp; + debug_decl(utmp_login, SUDO_DEBUG_UTMP) + + /* Strip off /dev/ prefix from line as needed. */ + if (strncmp(to_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + to_line += sizeof(_PATH_DEV) - 1; + + /* Find slot for new entry. */ + slot = utmp_slot(to_line, ttyfd); + if (slot <= 0) + goto done; + + if ((fp = fopen(_PATH_UTMP, "r+")) == NULL) + goto done; + + if (from_line != NULL) { + if (strncmp(from_line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + from_line += sizeof(_PATH_DEV) - 1; + + /* Lookup old line. */ + while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) { +# ifdef HAVE_STRUCT_UTMP_UT_ID + if (utbuf.ut_type != LOGIN_PROCESS && utbuf.ut_type != USER_PROCESS) + continue; +# endif + if (utbuf.ut_user[0] && + !strncmp(utbuf.ut_line, from_line, sizeof(utbuf.ut_line))) { + ut_old = &utbuf; + break; + } + } + } + utmp_fill(to_line, user, ut_old, &utbuf); + if (fseek(fp, slot * (long)sizeof(utbuf), SEEK_SET) == 0) { + if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1) + rval = true; + } + fclose(fp); + +done: + debug_return_bool(rval); +} + +bool +utmp_logout(const char *line, int status) +{ + sudo_utmp_t utbuf; + bool rval = false; + FILE *fp; + debug_decl(utmp_logout, SUDO_DEBUG_UTMP) + + if ((fp = fopen(_PATH_UTMP, "r+")) == NULL) + debug_return_int(rval); + + /* Strip off /dev/ prefix from line as needed. */ + if (strncmp(line, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + line += sizeof(_PATH_DEV) - 1; + + while (fread(&utbuf, sizeof(utbuf), 1, fp) == 1) { + if (!strncmp(utbuf.ut_line, line, sizeof(utbuf.ut_line))) { + memset(utbuf.ut_user, 0, sizeof(utbuf.ut_user)); +# if defined(HAVE_STRUCT_UTMP_UT_TYPE) + utbuf.ut_type = DEAD_PROCESS; +# endif + utmp_settime(&utbuf); + /* Back up and overwrite record. */ + if (fseek(fp, 0L - (long)sizeof(utbuf), SEEK_CUR) == 0) { + if (fwrite(&utbuf, sizeof(utbuf), 1, fp) == 1) + rval = true; + } + break; + } + } + fclose(fp); + + debug_return_bool(rval); +} +#endif /* HAVE_GETUTXID || HAVE_GETUTID */ diff --git a/strcasecmp.c b/strcasecmp.c deleted file mode 100644 index d14fdfb..0000000 --- a/strcasecmp.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2004-2005 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. - */ - -#include -#include -#include - -/* - * Case insensitive string compare routines, same semantics as str[n]cmp() - * (assumes ASCII..). - * Derived from a public domain implementation included with the pdksh shell. - */ -static const char ichars[256] = { - 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, - 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff -}; - -int -strcasecmp(s1, s2) - const char *s1; - const char *s2; -{ - const unsigned char *us1 = (const unsigned char *) s1; - const unsigned char *us2 = (const unsigned char *) s2; - - while (ichars[*us1] == ichars[*us2++]) { - if (*us1++ == '\0') - return 0; - } - return ichars[*us1] - ichars[*--us2]; -} - -int -strncasecmp(s1, s2, n) - const char *s1; - const char *s2; - size_t n; -{ - const unsigned char *us1 = (const unsigned char *) s1; - const unsigned char *us2 = (const unsigned char *) s2; - - while (n != 0 && ichars[*us1] == ichars[*us2++]) { - if (*us1++ == '\0') - return 0; - n--; - } - return n ? ichars[*us1] - ichars[*--us2] : 0; -} diff --git a/strerror.c b/strerror.c deleted file mode 100644 index cacd3f6..0000000 --- a/strerror.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 1999-2005 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. - */ - -#include -#include - -#include -#include - -/* - * Map errno -> error string. - */ -char * -strerror(n) - int n; -{ - extern int sys_nerr; - extern char *sys_errlist[]; - - if (n > 0 && n < sys_nerr) - return(sys_errlist[n]); - errno = EINVAL; - return("Unknown error"); -} diff --git a/strlcat.c b/strlcat.c deleted file mode 100644 index 97a803b..0000000 --- a/strlcat.c +++ /dev/null @@ -1,62 +0,0 @@ -/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ - -/* - * Copyright (c) 1998, 2003-2005 Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include - -#include -#include - - -/* - * Appends src to string dst of size siz (unlike strncat, siz is the - * full size of dst, not space left). At most siz-1 characters - * will be copied. Always NUL terminates (unless siz <= strlen(dst)). - * Returns strlen(src) + MIN(siz, strlen(initial dst)). - * If retval >= siz, truncation occurred. - */ -size_t -strlcat(dst, src, siz) - char *dst; - const char *src; - size_t siz; -{ - char *d = dst; - const char *s = src; - size_t n = siz; - size_t dlen; - - /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') - d++; - dlen = d - dst; - n = siz - dlen; - - if (n == 0) - return(dlen + strlen(s)); - while (*s != '\0') { - if (n != 1) { - *d++ = *s; - n--; - } - s++; - } - *d = '\0'; - - return(dlen + (s - src)); /* count does not include NUL */ -} diff --git a/strlcpy.c b/strlcpy.c deleted file mode 100644 index 8d301c3..0000000 --- a/strlcpy.c +++ /dev/null @@ -1,56 +0,0 @@ -/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ - -/* - * Copyright (c) 1998, 2003-2005 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. - */ - -#include - -#include -#include - -/* - * Copy src to string dst of size siz. At most siz-1 characters - * will be copied. Always NUL terminates (unless siz == 0). - * Returns strlen(src); if retval >= siz, truncation occurred. - */ -size_t -strlcpy(dst, src, siz) - char *dst; - const char *src; - size_t siz; -{ - char *d = dst; - const char *s = src; - size_t n = siz; - - /* Copy as many bytes as will fit */ - if (n != 0 && --n != 0) { - do { - if ((*d++ = *s++) == 0) - break; - } while (--n != 0); - } - - /* Not enough room in dst, add NUL and traverse rest of src */ - if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++) - ; - } - - return(s - src - 1); /* count does not include NUL */ -} diff --git a/strsignal.c b/strsignal.c deleted file mode 100644 index cead4ad..0000000 --- a/strsignal.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include -#include - -#include -#include - -#if defined(HAVE_DECL_SYS_SIGLIST) && HAVE_DECL_SYS_SIGLIST == 1 -# define my_sys_siglist sys_siglist -#elif defined(HAVE_DECL__SYS_SIGLIST) && HAVE_DECL__SYS_SIGLIST == 1 -# define my_sys_siglist _sys_siglist -#elif defined(HAVE_DECL___SYS_SIGLIST) && HAVE_DECL___SYS_SIGLIST == 1 -# define my_sys_siglist __sys_siglist -#else -extern const char *const my_sys_siglist[NSIG]; -#endif - -/* - * Get signal description string - */ -char * -strsignal(signo) - int signo; -{ - if (signo > 0 && signo < NSIG) - return((char *)my_sys_siglist[signo]); - return("Unknown signal"); -} diff --git a/sudo.c b/sudo.c deleted file mode 100644 index 159a2c8..0000000 --- a/sudo.c +++ /dev/null @@ -1,1403 +0,0 @@ -/* - * Copyright (c) 1993-1996, 1998-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. - * - * For a brief history of sudo, please see the HISTORY file included - * with this distribution. - */ - -#define _SUDO_MAIN - -#ifdef __TANDEM -# include -#endif - -#include - -#include -#include -#include -#include -#include -#ifdef HAVE_SETRLIMIT -# include -# include -#endif -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include -#include -#include -#include -#include -#if TIME_WITH_SYS_TIME -# include -#endif -#ifdef HAVE_SETLOCALE -# include -#endif -#include -#include -#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) -# ifdef __hpux -# undef MAXINT -# include -# else -# include -# endif /* __hpux */ -# include -#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ -#ifdef HAVE_LOGIN_CAP_H -# include -# ifndef LOGIN_DEFROOTCLASS -# define LOGIN_DEFROOTCLASS "daemon" -# endif -#endif -#ifdef HAVE_PROJECT_H -# include -# include -#endif -#ifdef HAVE_MBR_CHECK_MEMBERSHIP -# include -#endif - -#include "sudo.h" -#include "lbuf.h" -#include "interfaces.h" -#include - -#ifdef USING_NONUNIX_GROUPS -# include "nonunix.h" -#endif - -#if defined(HAVE_PAM) && !defined(NO_PAM_SESSION) -# define CMND_WAIT TRUE -#else -# define CMND_WAIT FALSE -#endif - -/* - * Prototypes - */ -static void init_vars __P((char **)); -static int set_cmnd __P((int)); -static void initial_setup __P((void)); -static void set_loginclass __P((struct passwd *)); -static void set_project __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 */ - -/* - * Globals - */ -int Argc, NewArgc; -char **Argv, **NewArgv; -char *prev_user; -int user_closefrom = -1; -struct sudo_user sudo_user; -struct passwd *auth_pw, *list_pw; -struct interface *interfaces; -int num_interfaces; -int tgetpass_flags; -int long_list; -uid_t timestamp_uid; -extern int errorlineno; -extern int parse_error; -extern char *errorfile; -#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) -static struct rlimit corelimit; -#endif /* RLIMIT_CORE && !SUDO_DEVEL */ -#if defined(__linux__) -static struct rlimit nproclimit; -#endif -#ifdef HAVE_LOGIN_CAP_H -login_cap_t *lc; -#endif /* HAVE_LOGIN_CAP_H */ -sigaction_t saved_sa_int, saved_sa_quit, saved_sa_tstp; -char *runas_user; -char *runas_group; -static struct sudo_nss_list *snl; -int sudo_mode; - -/* For getopt(3) */ -extern char *optarg; -extern int optind; - -int -main(argc, argv, envp) - int argc; - char *argv[]; - char *envp[]; -{ - int sources = 0, validated; - int fd, cmnd_status, pwflag, rc = 0; - sigaction_t sa; - struct sudo_nss *nss; -#if defined(SUDO_DEVEL) && defined(__OpenBSD__) - extern char *malloc_options; - malloc_options = "AFGJPR"; -#endif - -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); -#endif - - Argv = argv; - if ((Argc = argc) < 1) - usage(1); - - /* Must be done as the first thing... */ -#if defined(HAVE_GETPRPWNAM) && defined(HAVE_SET_AUTH_PARAMETERS) - (void) set_auth_parameters(Argc, Argv); -# ifdef HAVE_INITPRIVS - initprivs(); -# endif -#endif /* HAVE_GETPRPWNAM && HAVE_SET_AUTH_PARAMETERS */ - - if (geteuid() != 0) - errorx(1, "must be setuid root"); - - /* - * Signal setup: - * Ignore keyboard-generated signals so the user cannot interrupt - * us at some point and avoid the logging. - * Install handler to wait for children when they exit. - */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGINT, &sa, &saved_sa_int); - (void) sigaction(SIGQUIT, &sa, &saved_sa_quit); - (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp); - - /* Initialize environment functions (including replacements). */ - env_init(FALSE); - - /* - * Turn off core dumps and make sure fds 0-2 are open. - */ - initial_setup(); - sudo_setpwent(); - sudo_setgrent(); - - /* Parse our arguments. */ - sudo_mode = parse_args(Argc, Argv); - - /* Setup defaults data structures. */ - init_defaults(); - - /* Load the list of local ip addresses and netmasks. */ - load_interfaces(); - - pwflag = 0; - if (ISSET(sudo_mode, MODE_SHELL)) - user_cmnd = "shell"; - else if (ISSET(sudo_mode, MODE_EDIT)) - user_cmnd = "sudoedit"; - else { - switch (sudo_mode) { - case MODE_VERSION: - show_version(); - break; - case MODE_HELP: - usage(0); - break; - case MODE_VALIDATE: - case MODE_VALIDATE|MODE_INVALIDATE: - user_cmnd = "validate"; - pwflag = I_VERIFYPW; - break; - case MODE_KILL: - case MODE_INVALIDATE: - user_cmnd = "kill"; - pwflag = -1; - break; - case MODE_LISTDEFS: - list_options(); - exit(0); - break; - case MODE_LIST: - case MODE_LIST|MODE_INVALIDATE: - user_cmnd = "list"; - pwflag = I_LISTPW; - break; - case MODE_CHECK: - case MODE_CHECK|MODE_INVALIDATE: - pwflag = I_LISTPW; - break; - } - } - - /* Must have a command to run... */ - if (user_cmnd == NULL && NewArgc == 0) - usage(1); - - init_vars(envp); /* XXX - move this later? */ - -#ifdef USING_NONUNIX_GROUPS - sudo_nonunix_groupcheck_init(); /* initialise nonunix groups impl */ -#endif /* USING_NONUNIX_GROUPS */ - - /* Parse nsswitch.conf for sudoers order. */ - snl = sudo_read_nss(); - - /* Open and parse sudoers, set global defaults */ - tq_foreach_fwd(snl, nss) { - if (nss->open(nss) == 0 && nss->parse(nss) == 0) { - sources++; - if (nss->setdefs(nss) != 0) - log_error(NO_STDERR|NO_EXIT, "problem with defaults entries"); - } - } - if (sources == 0) - log_error(0, "no valid sudoers sources found, quitting"); - - /* XXX - collect post-sudoers parse settings into a function */ - - /* - * Set runas passwd/group entries based on command line or sudoers. - * Note that if runas_group was specified without runas_user we - * defer setting runas_pw so the match routines know to ignore it. - */ - if (runas_group != NULL) { - set_runasgr(runas_group); - if (runas_user != NULL) - set_runaspw(runas_user); - } else - set_runaspw(runas_user ? runas_user : def_runas_default); - - if (!update_defaults(SETDEF_RUNAS)) - log_error(NO_STDERR|NO_EXIT, "problem with defaults entries"); - - if (def_fqdn) - set_fqdn(); /* deferred until after sudoers is parsed */ - - /* Set login class if applicable. */ - set_loginclass(sudo_user.pw); - - /* Update initial shell now that runas is set. */ - if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) - NewArgv[0] = runas_pw->pw_shell; - - /* This goes after sudoers is parsed since it may have timestamp options. */ - if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) { - remove_timestamp((sudo_mode == MODE_KILL)); - cleanup(0); - exit(0); - } - - /* Is root even allowed to run sudo? */ - if (user_uid == 0 && !def_root_sudo) { - (void) fprintf(stderr, - "Sorry, %s has been configured to not allow root to run it.\n", - getprogname()); - exit(1); - } - - /* Check for -C overriding def_closefrom. */ - if (user_closefrom >= 0 && user_closefrom != def_closefrom) { - if (!def_closefrom_override) - errorx(1, "you are not permitted to use the -C option"); - else - def_closefrom = user_closefrom; - } - - cmnd_status = set_cmnd(sudo_mode); - -#ifdef HAVE_SETLOCALE - if (!setlocale(LC_ALL, def_sudoers_locale)) { - warningx("unable to set locale to \"%s\", using \"C\"", - def_sudoers_locale); - setlocale(LC_ALL, "C"); - } -#endif - - validated = FLAG_NO_USER | FLAG_NO_HOST; - tq_foreach_fwd(snl, nss) { - validated = nss->lookup(nss, validated, pwflag); - - if (ISSET(validated, VALIDATE_OK)) { - /* Handle "= auth" in netsvc.conf */ - if (nss->ret_if_found) - break; - } else { - /* Handle [NOTFOUND=return] */ - if (nss->ret_if_notfound) - break; - } - } - - if (safe_cmnd == NULL) - safe_cmnd = estrdup(user_cmnd); - -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); -#endif - - /* If only a group was specified, set runas_pw based on invoking user. */ - if (runas_pw == NULL) - set_runaspw(user_name); - - /* - * Look up the timestamp dir owner if one is specified. - */ - if (def_timestampowner) { - struct passwd *pw; - - if (*def_timestampowner == '#') - pw = sudo_getpwuid(atoi(def_timestampowner + 1)); - else - pw = sudo_getpwnam(def_timestampowner); - if (!pw) - log_error(0, "timestamp owner (%s): No such user", - def_timestampowner); - timestamp_uid = pw->pw_uid; - } - - /* If given the -P option, set the "preserve_groups" flag. */ - if (ISSET(sudo_mode, MODE_PRESERVE_GROUPS)) - def_preserve_groups = TRUE; - - /* If no command line args and "set_home" is not set, error out. */ - if (ISSET(sudo_mode, MODE_IMPLIED_SHELL) && !def_shell_noargs) - usage(1); - - /* Bail if a tty is required and we don't have one. */ - if (def_requiretty) { - if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) { - audit_failure(NewArgv, "no tty"); - log_error(NO_MAIL, "sorry, you must have a tty to run sudo"); - } else - (void) close(fd); - } - - /* Use askpass value from sudoers unless user specified their own. */ - if (def_askpass && !user_askpass) - user_askpass = def_askpass; - - /* - * We don't reset the environment for sudoedit or if the user - * specified the -E command line flag and they have setenv privs. - */ - if (ISSET(sudo_mode, MODE_EDIT) || - (ISSET(sudo_mode, MODE_PRESERVE_ENV) && def_setenv)) - def_env_reset = FALSE; - - /* Build a new environment that avoids any nasty bits. */ - rebuild_env(def_noexec); - - /* 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); - - /* If run as root with SUDO_USER set, set sudo_user.pw to that user. */ - /* XXX - causes confusion when root is not listed in sudoers */ - if (sudo_mode & (MODE_RUN | MODE_EDIT) && prev_user != NULL) { - if (user_uid == 0 && strcmp(prev_user, "root") != 0) { - struct passwd *pw; - - if ((pw = sudo_getpwnam(prev_user)) != NULL) { - sudo_user.pw = pw; -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - mbr_uid_to_uuid(user_uid, user_uuid); -#endif - } - } - } - - if (ISSET(validated, VALIDATE_OK)) { - /* Create Ubuntu-style dot file to indicate sudo was successful. */ - create_admin_success_flag(); - - /* Finally tell the user if the command did not exist. */ - if (cmnd_status == NOT_FOUND_DOT) { - audit_failure(NewArgv, "command in current directory"); - errorx(1, "ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd); - } else if (cmnd_status == NOT_FOUND) { - audit_failure(NewArgv, "%s: command not found", user_cmnd); - errorx(1, "%s: command not found", user_cmnd); - } - - /* If user specified env vars make sure sudoers allows it. */ - if (ISSET(sudo_mode, MODE_RUN) && !def_setenv) { - if (ISSET(sudo_mode, MODE_PRESERVE_ENV)) - log_error(NO_MAIL, - "sorry, you are not allowed to preserve the environment"); - else - validate_env_vars(sudo_user.env_vars); - } - -#ifdef _PATH_SUDO_IO_LOGDIR - /* Get next session ID so we can log it. */ - if (ISSET(sudo_mode, (MODE_RUN | MODE_EDIT)) && (def_log_input || def_log_output)) - io_nextid(); -#endif - log_allowed(validated); - if (ISSET(sudo_mode, MODE_CHECK)) - rc = display_cmnd(snl, list_pw ? list_pw : sudo_user.pw); - else if (ISSET(sudo_mode, MODE_LIST)) - display_privs(snl, list_pw ? list_pw : sudo_user.pw); - - /* Cleanup sudoers sources */ - tq_foreach_fwd(snl, nss) - nss->close(nss); - -#ifdef USING_NONUNIX_GROUPS - /* Finished with the groupcheck code */ - sudo_nonunix_groupcheck_cleanup(); -#endif - - /* Deferred exit due to sudo_ldap_close() */ - if (ISSET(sudo_mode, (MODE_VALIDATE|MODE_CHECK|MODE_LIST))) - exit(rc); - - /* Must audit before uid change. */ - audit_success(NewArgv); - - if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { - char *p; - - /* Convert /bin/sh -> -sh so shell knows it is a login shell */ - if ((p = strrchr(NewArgv[0], '/')) == NULL) - p = NewArgv[0]; - *p = '-'; - NewArgv[0] = p; - -#if defined(__linux__) || defined(_AIX) - /* Insert system-wide environment variables. */ - read_env_file(_PATH_ENVIRONMENT, TRUE); -#endif - } - - if (ISSET(sudo_mode, MODE_RUN)) { - /* Insert system-wide environment variables. */ - if (def_env_file) - read_env_file(def_env_file, FALSE); - - /* Insert user-specified environment variables. */ - insert_env_vars(sudo_user.env_vars); - } - - /* Restore signal handlers before we exec. */ - (void) sigaction(SIGINT, &saved_sa_int, NULL); - (void) sigaction(SIGQUIT, &saved_sa_quit, NULL); - (void) sigaction(SIGTSTP, &saved_sa_tstp, NULL); - - if (ISSET(sudo_mode, MODE_EDIT)) { - exit(sudo_edit(NewArgc, NewArgv, envp)); - } else { - exit(run_command(safe_cmnd, NewArgv, env_get(), runas_pw->pw_uid, - CMND_WAIT)); - } - } else if (ISSET(validated, FLAG_NO_USER | FLAG_NO_HOST)) { - audit_failure(NewArgv, "No user or host"); - log_denial(validated, 1); - exit(1); - } else { - if (def_path_info) { - /* - * We'd like to not leak path info at all here, but that can - * *really* confuse the users. To really close the leak we'd - * have to say "not allowed to run foo" even when the problem - * is just "no foo in path" since the user can trivially set - * their path to just contain a single dir. - */ - log_denial(validated, - !(cmnd_status == NOT_FOUND_DOT || cmnd_status == NOT_FOUND)); - if (cmnd_status == NOT_FOUND) - warningx("%s: command not found", user_cmnd); - else if (cmnd_status == NOT_FOUND_DOT) - warningx("ignoring `%s' found in '.'\nUse `sudo ./%s' if this is the `%s' you wish to run.", user_cmnd, user_cmnd, user_cmnd); - } else { - /* Just tell the user they are not allowed to run foo. */ - log_denial(validated, 1); - } - audit_failure(NewArgv, "validation failure"); - exit(1); - } - exit(0); /* not reached */ -} - -/* - * Initialize timezone, set umask, fill in ``sudo_user'' struct and - * load the ``interfaces'' array. - */ -static void -init_vars(envp) - char **envp; -{ - char *p, **ep, thost[MAXHOSTNAMELEN + 1]; - int nohostname; - - /* Sanity check command from user. */ - if (user_cmnd == NULL && strlen(NewArgv[0]) >= PATH_MAX) - errorx(1, "%s: File name too long", NewArgv[0]); - -#ifdef HAVE_TZSET - (void) tzset(); /* set the timezone if applicable */ -#endif /* HAVE_TZSET */ - - /* Default value for cmnd and cwd, overridden later. */ - if (user_cmnd == NULL) - user_cmnd = NewArgv[0]; - (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd)); - - /* - * We avoid gethostbyname() if possible since we don't want - * sudo to block if DNS or NIS is hosed. - * "host" is the (possibly fully-qualified) hostname and - * "shost" is the unqualified form of the hostname. - */ - nohostname = gethostname(thost, sizeof(thost)); - if (nohostname) { - user_host = user_shost = "localhost"; - } else { - thost[sizeof(thost) - 1] = '\0'; - user_host = estrdup(thost); - if ((p = strchr(user_host, '.'))) { - *p = '\0'; - user_shost = estrdup(user_host); - *p = '.'; - } else { - user_shost = user_host; - } - } - - if ((p = ttyname(STDIN_FILENO)) || (p = ttyname(STDOUT_FILENO)) || - (p = ttyname(STDERR_FILENO))) { - user_tty = user_ttypath = estrdup(p); - if (strncmp(user_tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) - user_tty += sizeof(_PATH_DEV) - 1; - } else - user_tty = "unknown"; - - for (ep = envp; *ep; ep++) { - /* XXX - don't fill in if empty string */ - switch (**ep) { - case 'D': - if (strncmp("DISPLAY=", *ep, 8) == 0) - user_display = *ep + 8; - break; - case 'K': - if (strncmp("KRB5CCNAME=", *ep, 11) == 0) - user_ccname = *ep + 11; - break; - case 'P': - if (strncmp("PATH=", *ep, 5) == 0) - user_path = *ep + 5; - break; - case 'S': - if (strncmp("SHELL=", *ep, 6) == 0) - user_shell = *ep + 6; - else if (!user_prompt && strncmp("SUDO_PROMPT=", *ep, 12) == 0) - user_prompt = *ep + 12; - else if (strncmp("SUDO_USER=", *ep, 10) == 0) - prev_user = *ep + 10; - else if (strncmp("SUDO_ASKPASS=", *ep, 13) == 0) - user_askpass = *ep + 13; - break; - } - } - - /* - * Get a local copy of the user's struct passwd with the shadow password - * if necessary. It is assumed that euid is 0 at this point so we - * can read the shadow passwd file if necessary. - */ - if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) { - /* Need to make a fake struct passwd for logging to work. */ - struct passwd pw; - char pw_name[MAX_UID_T_LEN + 1]; - - pw.pw_uid = getuid(); - (void) snprintf(pw_name, sizeof(pw_name), "%lu", - (unsigned long) pw.pw_uid); - pw.pw_name = pw_name; - sudo_user.pw = &pw; - - /* - * If we are in -k/-K mode, just spew to stderr. It is not unusual for - * users to place "sudo -k" in a .logout file which can cause sudo to - * be run during reboot after the YP/NIS/NIS+/LDAP/etc daemon has died. - */ - if (sudo_mode == MODE_KILL || sudo_mode == MODE_INVALIDATE) - errorx(1, "unknown uid: %s", pw_name); - log_error(0, "unknown uid: %s", pw_name); - } -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - mbr_uid_to_uuid(user_uid, user_uuid); -#endif - if (user_shell == NULL || *user_shell == '\0') - user_shell = estrdup(sudo_user.pw->pw_shell); - - /* It is now safe to use log_error() and set_perms() */ - -#ifdef HAVE_GETGROUPS - if ((user_ngroups = getgroups(0, NULL)) > 0) { - user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T)); - if (getgroups(user_ngroups, user_groups) < 0) - log_error(USE_ERRNO|MSG_ONLY, "can't get group vector"); - } -#endif - - if (nohostname) - log_error(USE_ERRNO|MSG_ONLY, "can't get hostname"); - - /* - * Get current working directory. Try as user, fall back to root. - */ - set_perms(PERM_USER); - if (!getcwd(user_cwd, sizeof(user_cwd))) { - set_perms(PERM_ROOT); - if (!getcwd(user_cwd, sizeof(user_cwd))) { - warningx("cannot get working directory"); - (void) strlcpy(user_cwd, "unknown", sizeof(user_cwd)); - } - } else - set_perms(PERM_ROOT); - - /* - * If we were given the '-e', '-i' or '-s' options we need to redo - * NewArgv and NewArgc. - */ - if (ISSET(sudo_mode, MODE_EDIT)) { - NewArgv--; - NewArgc++; - NewArgv[0] = "sudoedit"; - } else if (ISSET(sudo_mode, MODE_SHELL)) { - char **av; - - /* Allocate an extra slot for execve() failure (ENOEXEC). */ - av = (char **) emalloc2(5, sizeof(char *)); - av++; - - av[0] = user_shell; /* may be updated later */ - if (NewArgc > 0) { - size_t cmnd_size = 1024; - char *cmnd, *src, *dst, **ap; - - 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 */ - *dst = '\0'; - av[1] = "-c"; - av[2] = cmnd; - NewArgc = 2; - } - av[++NewArgc] = NULL; - NewArgv = av; - } -} - -/* - * Fill in user_cmnd, user_args, user_base and user_stat variables - * and apply any command-specific defaults entries. - */ -static int -set_cmnd(sudo_mode) - int sudo_mode; -{ - int rval; - char *path = user_path; - - /* Set project if applicable. */ - set_project(runas_pw); - - /* Resolve the path and return. */ - rval = FOUND; - user_stat = emalloc(sizeof(struct stat)); - if (sudo_mode & (MODE_RUN | MODE_EDIT | MODE_CHECK)) { - if (ISSET(sudo_mode, MODE_RUN | MODE_CHECK)) { - if (def_secure_path && !user_is_exempt()) - path = def_secure_path; - set_perms(PERM_RUNAS); - rval = find_path(NewArgv[0], &user_cmnd, user_stat, path, - def_ignore_dot); - set_perms(PERM_ROOT); - if (rval != FOUND) { - /* Failed as root, try as invoking user. */ - set_perms(PERM_USER); - rval = find_path(NewArgv[0], &user_cmnd, user_stat, path, - def_ignore_dot); - set_perms(PERM_ROOT); - } - } - - /* set user_args */ - if (NewArgc > 1) { - char *to, **from; - size_t size, n; - - /* If we didn't realloc NewArgv it is contiguous so just count. */ - if (!ISSET(sudo_mode, MODE_SHELL)) { - size = (size_t) (NewArgv[NewArgc-1] - NewArgv[1]) + - strlen(NewArgv[NewArgc-1]) + 1; - } else { - for (size = 0, from = NewArgv + 1; *from; from++) - size += strlen(*from) + 1; - } - - /* Alloc and build up user_args. */ - user_args = (char *) emalloc(size); - for (to = user_args, from = NewArgv + 1; *from; from++) { - n = strlcpy(to, *from, size - (to - user_args)); - if (n >= size - (to - user_args)) - errorx(1, "internal error, init_vars() overflow"); - to += n; - *to++ = ' '; - } - *--to = '\0'; - } - } - if ((user_base = strrchr(user_cmnd, '/')) != NULL) - user_base++; - else - user_base = user_cmnd; - - if (!update_defaults(SETDEF_CMND)) - log_error(NO_STDERR|NO_EXIT, "problem with defaults entries"); - - if (!runas_user && !runas_group) - set_runaspw(def_runas_default); /* may have been updated above */ - - return(rval); -} - -/* - * Setup the execution environment immediately prior to the call to execve() - * Returns TRUE on success and FALSE on failure. - */ -int -exec_setup(rbac_enabled, ttyname, ttyfd) - int rbac_enabled; - const char *ttyname; - int ttyfd; -{ - int rval = FALSE; - -#ifdef HAVE_SELINUX - if (rbac_enabled) { - if (selinux_setup(user_role, user_type, ttyname, ttyfd) == -1) - goto done; - } -#endif - - /* 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. - */ - if (ISSET(sudo_mode, MODE_EDIT)) { - set_perms(PERM_FULL_USER); - rval = TRUE; - goto done; - } - - /* - * Set umask based on sudoers. - * If user's umask is more restrictive, OR in those bits too - * unless umask_override is set. - */ - if (def_umask != 0777) { - if (def_umask_override) { - umask(def_umask); - } else { - mode_t mask = umask(def_umask); - mask |= def_umask; - if (mask != def_umask) - umask(mask); - } - } - - /* Restore coredumpsize resource limit. */ -#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) - (void) setrlimit(RLIMIT_CORE, &corelimit); -#endif /* RLIMIT_CORE && !SUDO_DEVEL */ - - if (ISSET(sudo_mode, MODE_RUN)) - set_perms(PERM_FULL_RUNAS); - - if (ISSET(sudo_mode, MODE_LOGIN_SHELL)) { - /* Change to target user's homedir. */ - if (chdir(runas_pw->pw_dir) == -1) { - warning("unable to change directory to %s", runas_pw->pw_dir); - goto done; - } - } - - /* - * Restore nproc resource limit if pam_limits didn't do it for us. - * We must do this *after* the uid change to avoid potential EAGAIN - * from setuid(). - */ -#if defined(__linux__) - { - struct rlimit rl; - if (getrlimit(RLIMIT_NPROC, &rl) == 0) { - if (rl.rlim_cur == RLIM_INFINITY && rl.rlim_max == RLIM_INFINITY) - (void) setrlimit(RLIMIT_NPROC, &nproclimit); - } - } -#endif - - rval = TRUE; - -done: - return(rval); -} - -/* - * Run the command and wait for it to complete. - */ -int -run_command(path, argv, envp, uid, dowait) - const char *path; - char *argv[]; - char *envp[]; - uid_t uid; - int dowait; -{ - struct command_status cstat; - int exitcode = 1; - -#ifdef PROFILING - exit(0); -#endif - - cstat.type = CMD_INVALID; - cstat.val = 0; - - sudo_execve(path, argv, envp, uid, &cstat, dowait, - ISSET(sudo_mode, MODE_BACKGROUND)); - - switch (cstat.type) { - case CMD_ERRNO: - /* exec_setup() or execve() returned an error. */ - warningx("unable to execute %s: %s", path, strerror(cstat.val)); - exitcode = 127; - break; - case CMD_WSTATUS: - /* Command ran, exited or was killed. */ - if (WIFEXITED(cstat.val)) - exitcode = WEXITSTATUS(cstat.val); - else if (WIFSIGNALED(cstat.val)) - exitcode = WTERMSIG(cstat.val) | 128; - break; - default: - warningx("unexpected child termination condition: %d", cstat.type); - break; - } -#ifdef HAVE_PAM - pam_end_session(); -#endif /* HAVE_PAM */ -#ifdef _PATH_SUDO_IO_LOGDIR - io_log_close(); -#endif - return(exitcode); -} - -/* - * Open sudoers and sanity check mode/owner/type. - * Returns a handle to the sudoers file or NULL on error. - */ -FILE * -open_sudoers(sudoers, doedit, keepopen) - const char *sudoers; - int doedit; - int *keepopen; -{ - struct stat statbuf; - FILE *fp = NULL; - int rootstat; - - /* - * Fix the mode and group on sudoers file from old default. - * Only works if file system is readable/writable by root. - */ - if ((rootstat = stat_sudoers(sudoers, &statbuf)) == 0 && - SUDOERS_UID == statbuf.st_uid && SUDOERS_MODE != 0400 && - (statbuf.st_mode & 0007777) == 0400) { - - if (chmod(sudoers, SUDOERS_MODE) == 0) { - warningx("fixed mode on %s", sudoers); - SET(statbuf.st_mode, SUDOERS_MODE); - if (statbuf.st_gid != SUDOERS_GID) { - if (chown(sudoers, (uid_t) -1, SUDOERS_GID) == 0) { - warningx("set group on %s", sudoers); - statbuf.st_gid = SUDOERS_GID; - } else - warning("unable to set group on %s", sudoers); - } - } else - warning("unable to fix mode on %s", sudoers); - } - - /* - * Sanity checks on sudoers file. Must be done as sudoers - * file owner. We already did a stat as root, so use that - * data if we can't stat as sudoers file owner. - */ - set_perms(PERM_SUDOERS); - - if (rootstat != 0 && stat_sudoers(sudoers, &statbuf) != 0) - log_error(USE_ERRNO|NO_EXIT, "can't stat %s", sudoers); - else if (!S_ISREG(statbuf.st_mode)) - log_error(NO_EXIT, "%s is not a regular file", sudoers); - else if ((statbuf.st_mode & 07777) != 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); - 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); - else if ((fp = fopen(sudoers, "r")) == NULL) - log_error(USE_ERRNO|NO_EXIT, "can't open %s", sudoers); - else { - /* - * Make sure we can actually read sudoers so we can present the - * user with a reasonable error message (unlike the lexer). - */ - if (statbuf.st_size != 0 && fgetc(fp) == EOF) { - log_error(USE_ERRNO|NO_EXIT, "can't read %s", sudoers); - fclose(fp); - fp = NULL; - } - } - - if (fp != NULL) { - rewind(fp); - (void) fcntl(fileno(fp), F_SETFD, 1); - } - - set_perms(PERM_ROOT); /* change back to root */ - return(fp); -} - -/* - * Close all open files (except std*) and turn off core dumps. - * Also sets the set_perms() pointer to the correct function. - */ -static void -initial_setup() -{ - int miss[3], devnull = -1; -#if defined(__linux__) || (defined(RLIMIT_CORE) && !defined(SUDO_DEVEL)) - struct rlimit rl; -#endif - -#if defined(__linux__) - /* - * Unlimit the number of processes since Linux's setuid() will - * apply resource limits when changing uid and return EAGAIN if - * nproc would be violated by the uid switch. - */ - (void) getrlimit(RLIMIT_NPROC, &nproclimit); - rl.rlim_cur = rl.rlim_max = RLIM_INFINITY; - if (setrlimit(RLIMIT_NPROC, &rl)) { - memcpy(&rl, &nproclimit, sizeof(struct rlimit)); - rl.rlim_cur = rl.rlim_max; - (void)setrlimit(RLIMIT_NPROC, &rl); - } -#endif /* __linux__ */ -#if defined(RLIMIT_CORE) && !defined(SUDO_DEVEL) - /* - * Turn off core dumps. - */ - (void) getrlimit(RLIMIT_CORE, &corelimit); - memcpy(&rl, &corelimit, sizeof(struct rlimit)); - rl.rlim_cur = 0; - (void) setrlimit(RLIMIT_CORE, &rl); -#endif /* RLIMIT_CORE && !SUDO_DEVEL */ - - /* - * stdin, stdout and stderr must be open; set them to /dev/null - * if they are closed and close all other fds. - */ - miss[STDIN_FILENO] = fcntl(STDIN_FILENO, F_GETFL, 0) == -1; - miss[STDOUT_FILENO] = fcntl(STDOUT_FILENO, F_GETFL, 0) == -1; - miss[STDERR_FILENO] = fcntl(STDERR_FILENO, F_GETFL, 0) == -1; - if (miss[STDIN_FILENO] || miss[STDOUT_FILENO] || miss[STDERR_FILENO]) { - if ((devnull = open(_PATH_DEVNULL, O_RDWR, 0644)) == -1) - error(1, "unable to open %s", _PATH_DEVNULL); - if (miss[STDIN_FILENO] && dup2(devnull, STDIN_FILENO) == -1) - error(1, "dup2"); - if (miss[STDOUT_FILENO] && dup2(devnull, STDOUT_FILENO) == -1) - error(1, "dup2"); - if (miss[STDERR_FILENO] && dup2(devnull, STDERR_FILENO) == -1) - error(1, "dup2"); - if (devnull > STDERR_FILENO) - close(devnull); - } -} - -#ifdef HAVE_LOGIN_CAP_H -static void -set_loginclass(pw) - struct passwd *pw; -{ - int errflags; - - /* - * Don't make it a fatal error if the user didn't specify the login - * class themselves. We do this because if login.conf gets - * corrupted we want the admin to be able to use sudo to fix it. - */ - if (login_class) - errflags = NO_MAIL|MSG_ONLY; - else - errflags = NO_MAIL|MSG_ONLY|NO_EXIT; - - if (login_class && strcmp(login_class, "-") != 0) { - if (user_uid != 0 && - strcmp(runas_user ? runas_user : def_runas_default, "root") != 0) - errorx(1, "only root can use -c %s", login_class); - } else { - login_class = pw->pw_class; - if (!login_class || !*login_class) - login_class = - (pw->pw_uid == 0) ? LOGIN_DEFROOTCLASS : LOGIN_DEFCLASS; - } - - lc = login_getclass(login_class); - if (!lc || !lc->lc_class || strcmp(lc->lc_class, login_class) != 0) { - log_error(errflags, "unknown login class: %s", login_class); - if (!lc) - lc = login_getclass(NULL); /* needed for login_getstyle() later */ - } -} -#else -static void -set_loginclass(pw) - struct passwd *pw; -{ -} -#endif /* HAVE_LOGIN_CAP_H */ - -#ifdef HAVE_PROJECT_H -static void -set_project(pw) - struct passwd *pw; -{ - int errflags = NO_MAIL|MSG_ONLY|NO_EXIT; - int errval; - struct project proj; - struct project *resultp = '\0'; - char buf[1024]; - - /* - * Collect the default project for the user and settaskid - */ - setprojent(); - if (resultp = getdefaultproj(pw->pw_name, &proj, buf, sizeof(buf))) { - errval = setproject(resultp->pj_name, pw->pw_name, TASK_NORMAL); - if (errval != 0) { - switch(errval) { - case SETPROJ_ERR_TASK: - if (errno == EAGAIN) - log_error(errflags, "resource control limit has been reached"); - else if (errno == ESRCH) - log_error(errflags, "user \"%s\" is not a member of " - "project \"%s\"", pw->pw_name, resultp->pj_name); - else if (errno == EACCES) - log_error(errflags, "the invoking task is final"); - else - log_error(errflags, "could not join project \"%s\"", - resultp->pj_name); - break; - case SETPROJ_ERR_POOL: - if (errno == EACCES) - log_error(errflags, "no resource pool accepting " - "default bindings exists for project \"%s\"", - resultp->pj_name); - else if (errno == ESRCH) - log_error(errflags, "specified resource pool does " - "not exist for project \"%s\"", resultp->pj_name); - else - log_error(errflags, "could not bind to default " - "resource pool for project \"%s\"", resultp->pj_name); - break; - default: - if (errval <= 0) { - log_error(errflags, "setproject failed for project \"%s\"", - resultp->pj_name); - } else { - log_error(errflags, "warning, resource control assignment " - "failed for project \"%s\"", resultp->pj_name); - } - } - } - } else { - log_error(errflags, "getdefaultproj() error: %s", strerror(errno)); - } - endprojent(); -} -#else -static void -set_project(pw) - struct passwd *pw; -{ -} -#endif /* HAVE_PROJECT_H */ - -/* - * Look up the fully qualified domain name and set user_host and user_shost. - */ -void -set_fqdn() -{ -#ifdef HAVE_GETADDRINFO - struct addrinfo *res0, hint; -#else - struct hostent *hp; -#endif - char *p; - -#ifdef HAVE_GETADDRINFO - zero_bytes(&hint, sizeof(hint)); - hint.ai_family = PF_UNSPEC; - hint.ai_flags = AI_CANONNAME; - if (getaddrinfo(user_host, NULL, &hint, &res0) != 0) { -#else - if (!(hp = gethostbyname(user_host))) { -#endif - log_error(MSG_ONLY|NO_EXIT, - "unable to resolve host %s", user_host); - } else { - if (user_shost != user_host) - efree(user_shost); - efree(user_host); -#ifdef HAVE_GETADDRINFO - user_host = estrdup(res0->ai_canonname); - freeaddrinfo(res0); -#else - user_host = estrdup(hp->h_name); -#endif - } - if ((p = strchr(user_host, '.'))) { - *p = '\0'; - user_shost = estrdup(user_host); - *p = '.'; - } else { - user_shost = user_host; - } -} - -/* - * Get passwd entry for the user we are going to run commands as. - * By default, this is "root". Updates runas_pw as a side effect. - */ -static void -set_runaspw(user) - char *user; -{ - if (*user == '#') { - if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) - runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); - } else { - if ((runas_pw = sudo_getpwnam(user)) == NULL) { - audit_failure(NewArgv, "unknown user: %s", user); - log_error(NO_MAIL|MSG_ONLY, "unknown user: %s", user); - } - } -} - -/* - * Get group entry for the group we are going to run commands as. - * Updates runas_pw as a side effect. - */ -static void -set_runasgr(group) - char *group; -{ - if (*group == '#') { - if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) - runas_gr = sudo_fakegrnam(group); - } else { - if ((runas_gr = sudo_getgrnam(group)) == NULL) - log_error(NO_MAIL|MSG_ONLY, "unknown group: %s", group); - } -} - -/* - * 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() - */ -void -cleanup(gotsignal) - int gotsignal; -{ - struct sudo_nss *nss; - - if (!gotsignal) { - if (snl != NULL) { - tq_foreach_fwd(snl, nss) - nss->close(nss); - } -#ifdef USING_NONUNIX_GROUPS - sudo_nonunix_groupcheck_cleanup(); -#endif - sudo_endpwent(); - sudo_endgrent(); -#ifdef _PATH_SUDO_IO_LOGDIR - io_log_close(); -#endif - } - term_restore(STDIN_FILENO, 0); -#ifdef HAVE_SELINUX - selinux_restore_tty(); -#endif -} - -static void -show_version() -{ - (void) printf("Sudo version %s\n", PACKAGE_VERSION); - if (getuid() == 0) { - putchar('\n'); - (void) printf("Configure args: %s\n", CONFIGURE_ARGS); - (void) printf("Sudoers path: %s\n", _PATH_SUDOERS); -#ifdef HAVE_LDAP -# ifdef _PATH_NSSWITCH_CONF - (void) printf("nsswitch path: %s\n", _PATH_NSSWITCH_CONF); -# endif - (void) printf("ldap.conf path: %s\n", _PATH_LDAP_CONF); - (void) printf("ldap.secret path: %s\n", _PATH_LDAP_SECRET); -#endif - dump_auth_methods(); - dump_defaults(); - dump_interfaces(); - } - exit(0); -} - -#ifdef USE_ADMIN_FLAG -static void -create_admin_success_flag() -{ - struct stat statbuf; - char flagfile[PATH_MAX]; - int fd, n; - - /* Check whether the user is in the admin group. */ - if (!user_in_group(sudo_user.pw, "admin")) - return; - - /* Build path to flag file. */ - n = snprintf(flagfile, sizeof(flagfile), "%s/.sudo_as_admin_successful", - user_dir); - if (n <= 0 || n >= sizeof(flagfile)) - return; - - /* Create admin flag file if it doesn't already exist. */ - set_perms(PERM_USER); - if (stat(flagfile, &statbuf) == 0) { - set_perms(PERM_ROOT); - return; - } - - fd = open(flagfile, O_CREAT|O_WRONLY|O_EXCL, 0644); - close(fd); - set_perms(PERM_ROOT); -} -#else /* !USE_ADMIN_FLAG */ -static void -create_admin_success_flag() -{ - /* STUB */ -} -#endif /* USE_ADMIN_FLAG */ diff --git a/sudo.cat b/sudo.cat deleted file mode 100644 index 9f85ccd..0000000 --- a/sudo.cat +++ /dev/null @@ -1,660 +0,0 @@ - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - -NNAAMMEE - sudo, sudoedit - execute a command as another user - -SSYYNNOOPPSSIISS - ssuuddoo --hh | --KK | --kk | --LL | --VV - - ssuuddoo --vv [--AAkknnSS] [--aa _a_u_t_h___t_y_p_e] [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] - [--uu _u_s_e_r_n_a_m_e|_#_u_i_d] - - ssuuddoo --ll[[ll]] [--AAkknnSS] [--aa _a_u_t_h___t_y_p_e] [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] - [--UU _u_s_e_r _n_a_m_e] [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] [_c_o_m_m_a_n_d] - - ssuuddoo [--AAbbEEHHnnPPSS] [--aa _a_u_t_h___t_y_p_e] [--CC _f_d] [--cc _c_l_a_s_s|_-] - [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] [--rr _r_o_l_e] [--tt _t_y_p_e] - [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] [VVAARR=_v_a_l_u_e] [--ii | --ss] [_c_o_m_m_a_n_d] - - ssuuddooeeddiitt [--AAnnSS] [--aa _a_u_t_h___t_y_p_e] [--CC _f_d] [--cc _c_l_a_s_s|_-] - [--gg _g_r_o_u_p _n_a_m_e|_#_g_i_d] [--pp _p_r_o_m_p_t] [--uu _u_s_e_r _n_a_m_e|_#_u_i_d] file ... - -DDEESSCCRRIIPPTTIIOONN - ssuuddoo allows a permitted user to execute a _c_o_m_m_a_n_d as the superuser or - another user, as specified in the _s_u_d_o_e_r_s file. The real and effective - uid and gid are set to match those of the target user as specified in - the passwd file and the group vector is initialized based on the group - file (unless the --PP option was specified). If the invoking user is - root or if the target user is the same as the invoking user, no - password is required. Otherwise, ssuuddoo requires that users authenticate - themselves with a password by default (NOTE: in the default - configuration this is the user's password, not the root password). - Once a user has been authenticated, a time stamp is updated and the - user may then use sudo without a password for a short period of time (5 - minutes unless overridden in _s_u_d_o_e_r_s). - - When invoked as ssuuddooeeddiitt, the --ee option (described below), is implied. - - ssuuddoo determines who is an authorized user by consulting the file - _/_e_t_c_/_s_u_d_o_e_r_s. By running ssuuddoo with the --vv option, a user can update - the time stamp without running a _c_o_m_m_a_n_d. If a password is required, - ssuuddoo will exit if the user's password is not entered within a - configurable time limit. The default password prompt timeout is 5 - minutes. - - If a user who is not listed in the _s_u_d_o_e_r_s file tries to run a command - via ssuuddoo, mail is sent to the proper authorities, as defined at - configure time or in the _s_u_d_o_e_r_s file (defaults to root). Note that - the mail will not be sent if an unauthorized user tries to run sudo - with the --ll or --vv option. This allows users to determine for - themselves whether or not they are allowed to use ssuuddoo. - - If ssuuddoo is run by root and the SUDO_USER environment variable is set, - ssuuddoo will use this value to determine who the actual user is. This can - be used by a user to log commands through sudo even when a root shell - has been invoked. It also allows the --ee option to remain useful even - when being run via a sudo-run script or program. Note however, that - - - -1.7.4 July 19, 2010 1 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - the sudoers lookup is still done for root, not the user specified by - SUDO_USER. - - ssuuddoo can log both successful and unsuccessful attempts (as well as - errors) to _s_y_s_l_o_g(3), a log file, or both. By default ssuuddoo will log - via _s_y_s_l_o_g(3) but this is changeable at configure time or via the - _s_u_d_o_e_r_s file. - -OOPPTTIIOONNSS - ssuuddoo accepts the following command line options: - - -A Normally, if ssuuddoo requires a password, it will read it from - the current terminal. If the --AA (_a_s_k_p_a_s_s) option is - specified, a (possibly graphical) helper program is - executed to read the user's password and output the - password to the standard output. If the SUDO_ASKPASS - environment variable is set, it specifies the path to the - helper program. Otherwise, the value specified by the - _a_s_k_p_a_s_s option in _s_u_d_o_e_r_s(4) is used. - - -a _t_y_p_e The --aa (_a_u_t_h_e_n_t_i_c_a_t_i_o_n _t_y_p_e) option causes ssuuddoo to use the - specified authentication type when validating the user, as - allowed by _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. The system administrator may - specify a list of sudo-specific authentication methods by - adding an "auth-sudo" entry in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f. This - option is only available on systems that support BSD - authentication. - - -b The --bb (_b_a_c_k_g_r_o_u_n_d) option tells ssuuddoo to run the given - command in the background. Note that if you use the --bb - option you cannot use shell job control to manipulate the - process. - - -C _f_d Normally, ssuuddoo will close all open file descriptors other - than standard input, standard output and standard error. - The --CC (_c_l_o_s_e _f_r_o_m) option allows the user to specify a - starting point above the standard error (file descriptor - three). Values less than three are not permitted. This - option is only available if the administrator has enabled - the _c_l_o_s_e_f_r_o_m___o_v_e_r_r_i_d_e option in _s_u_d_o_e_r_s(4). - - -c _c_l_a_s_s The --cc (_c_l_a_s_s) option causes ssuuddoo to run the specified - command with resources limited by the specified login - class. The _c_l_a_s_s argument can be either a class name as - defined in _/_e_t_c_/_l_o_g_i_n_._c_o_n_f, or a single '-' character. - Specifying a _c_l_a_s_s of - indicates that the command should - be run restricted by the default login capabilities for the - user the command is run as. If the _c_l_a_s_s argument - specifies an existing user class, the command must be run - as root, or the ssuuddoo command must be run from a shell that - is already root. This option is only available on systems - with BSD login classes. - - -E The --EE (_p_r_e_s_e_r_v_e _e_n_v_i_r_o_n_m_e_n_t) option will override the - - - -1.7.4 July 19, 2010 2 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - _e_n_v___r_e_s_e_t option in _s_u_d_o_e_r_s(4)). It is only available when - either the matching command has the SETENV tag or the - _s_e_t_e_n_v option is set in _s_u_d_o_e_r_s(4). - - -e The --ee (_e_d_i_t) option indicates that, instead of running a - command, the user wishes to edit one or more files. In - lieu of a command, the string "sudoedit" is used when - consulting the _s_u_d_o_e_r_s file. If the user is authorized by - _s_u_d_o_e_r_s the following steps are taken: - - 1. Temporary copies are made of the files to be edited - with the owner set to the invoking user. - - 2. The editor specified by the SUDO_EDITOR, VISUAL or - EDITOR environment variables is run to edit the - temporary files. If none of SUDO_EDITOR, VISUAL or - EDITOR are set, the first program listed in the _e_d_i_t_o_r - _s_u_d_o_e_r_s variable is used. - - 3. If they have been modified, the temporary files are - copied back to their original location and the - temporary versions are removed. - - If the specified file does not exist, it will be created. - Note that unlike most commands run by ssuuddoo, the editor is - run with the invoking user's environment unmodified. If, - for some reason, ssuuddoo is unable to update a file with its - edited version, the user will receive a warning and the - edited copy will remain in a temporary file. - - -g _g_r_o_u_p Normally, ssuuddoo sets the primary group to the one specified - by the passwd database for the user the command is being - run as (by default, root). The --gg (_g_r_o_u_p) option causes - ssuuddoo to run the specified command with the primary group - set to _g_r_o_u_p. To specify a _g_i_d instead of a _g_r_o_u_p _n_a_m_e, - use _#_g_i_d. When running commands as a _g_i_d, many shells - require that the '#' be escaped with a backslash ('\'). If - no --uu option is specified, the command will be run as the - invoking user (not root). In either case, the primary - group will be set to _g_r_o_u_p. - - -H The --HH (_H_O_M_E) option sets the HOME environment variable to - the homedir of the target user (root by default) as - specified in _p_a_s_s_w_d(4). The default handling of the HOME - environment variable depends on _s_u_d_o_e_r_s(4) settings. By - default, ssuuddoo will set HOME if _e_n_v___r_e_s_e_t or _a_l_w_a_y_s___s_e_t___h_o_m_e - 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. - - -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 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - specified in the _p_a_s_s_w_d(4) entry of the target user as a - login shell. This means that login-specific resource files - such as .profile or .login will be read by the shell. If a - command is specified, it is passed to the shell for - execution. Otherwise, an interactive shell is executed. - ssuuddoo attempts to change to that user's home directory - before running the shell. It also initializes the - environment, leaving _D_I_S_P_L_A_Y and _T_E_R_M unchanged, setting - _H_O_M_E, _M_A_I_L, _S_H_E_L_L, _U_S_E_R, _L_O_G_N_A_M_E, and _P_A_T_H, as well as the - contents of _/_e_t_c_/_e_n_v_i_r_o_n_m_e_n_t on Linux and AIX systems. All - other environment variables are removed. - - -K The --KK (sure _k_i_l_l) option is like --kk except that it removes - the user's time stamp entirely and may not be used in - conjunction with a command or other option. This option - does not require a password. - - -k When used by itself, the --kk (_k_i_l_l) option to ssuuddoo - invalidates the user's time stamp by setting the time on it - to the Epoch. The next time ssuuddoo is run a password will be - required. This option does not require a password and was - added to allow a user to revoke ssuuddoo permissions from a - .logout file. - - When used in conjunction with a command or an option that - may require a password, the --kk option will cause ssuuddoo to - ignore the user's time stamp file. As a result, ssuuddoo will - prompt for a password (if one is required by _s_u_d_o_e_r_s) and - will not update the user's time stamp file. - - -L The --LL (_l_i_s_t defaults) option will list the parameters that - may be set in a _D_e_f_a_u_l_t_s line along with a short - description for each. This option will be removed from a - future version of ssuuddoo. - - -l[l] [_c_o_m_m_a_n_d] - If no _c_o_m_m_a_n_d is specified, the --ll (_l_i_s_t) option will list - the allowed (and forbidden) commands for the invoking user - (or the user specified by the --UU option) on the current - host. If a _c_o_m_m_a_n_d is specified and is permitted by - _s_u_d_o_e_r_s, the fully-qualified path to the command is - displayed along with any command line arguments. If - _c_o_m_m_a_n_d is specified but not allowed, ssuuddoo will exit with a - status value of 1. If the --ll option is specified with an ll - argument (i.e. --llll), or if --ll is specified multiple times, - a longer list format is used. - - -n The --nn (_n_o_n_-_i_n_t_e_r_a_c_t_i_v_e) option prevents ssuuddoo from - prompting the user for a password. If a password is - required for the command to run, ssuuddoo will display an error - messages and exit. - - -P The --PP (_p_r_e_s_e_r_v_e _g_r_o_u_p _v_e_c_t_o_r) option causes ssuuddoo to - preserve the invoking user's group vector unaltered. By - - - -1.7.4 July 19, 2010 4 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - default, ssuuddoo will initialize the group vector to the list - of groups the target user is in. The real and effective - group IDs, however, are still set to match the target user. - - -p _p_r_o_m_p_t The --pp (_p_r_o_m_p_t) option allows you to override the default - password prompt and use a custom one. The following - percent (`%') escapes are supported: - - %H expanded to the local host name including the domain - name (on if the machine's host name is fully qualified - or the _f_q_d_n _s_u_d_o_e_r_s option is set) - - %h expanded to the local host name without the domain name - - %p expanded to the user whose password is being asked for - (respects the _r_o_o_t_p_w, _t_a_r_g_e_t_p_w and _r_u_n_a_s_p_w flags in - _s_u_d_o_e_r_s) - - %U expanded to the login name of the user the command will - be run as (defaults to root) - - %u expanded to the invoking user's login name - - %% two consecutive % characters are collapsed into a - single % character - - The prompt specified by the --pp option will override the - system password prompt on systems that support PAM unless - the _p_a_s_s_p_r_o_m_p_t___o_v_e_r_r_i_d_e flag is disabled in _s_u_d_o_e_r_s. - - -r _r_o_l_e The --rr (_r_o_l_e) option causes the new (SELinux) security - context to have the role specified by _r_o_l_e. - - -S The --SS (_s_t_d_i_n) option causes ssuuddoo to read the password from - the standard input instead of the terminal device. The - password must be followed by a newline character. - - -s [command] - The --ss (_s_h_e_l_l) option runs the shell specified by the _S_H_E_L_L - environment variable if it is set or the shell as specified - in _p_a_s_s_w_d(4). If a command is specified, it is passed to - the shell for execution. Otherwise, an interactive shell - is executed. - - -t _t_y_p_e The --tt (_t_y_p_e) option causes the new (SELinux) security - context to have the type specified by _t_y_p_e. If no type is - specified, the default type is derived from the specified - role. - - -U _u_s_e_r The --UU (_o_t_h_e_r _u_s_e_r) option is used in conjunction with the - --ll option to specify the user whose privileges should be - listed. Only root or a user with ssuuddoo ALL on the current - host may use this option. - - - - -1.7.4 July 19, 2010 5 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - -u _u_s_e_r The --uu (_u_s_e_r) option causes ssuuddoo to run the specified - command as a user other than _r_o_o_t. To specify a _u_i_d - instead of a _u_s_e_r _n_a_m_e, use _#_u_i_d. When running commands as - a _u_i_d, many shells require that the '#' be escaped with a - backslash ('\'). Note that if the _t_a_r_g_e_t_p_w Defaults option - is set (see _s_u_d_o_e_r_s(4)) it is not possible to run commands - with a uid not listed in the password database. - - -V The --VV (_v_e_r_s_i_o_n) option causes ssuuddoo to print the version - number and exit. If the invoking user is already root the - --VV option will print out a list of the defaults ssuuddoo was - compiled with as well as the machine's local network - addresses. - - -v If given the --vv (_v_a_l_i_d_a_t_e) option, ssuuddoo will update the - user's time stamp, prompting for the user's password if - necessary. This extends the ssuuddoo timeout for another 5 - minutes (or whatever the timeout is set to in _s_u_d_o_e_r_s) but - does not run a command. - - -- The ---- option indicates that ssuuddoo should stop processing - command line arguments. - - Environment variables to be set for the command may also be passed on - the command line in the form of VVAARR=_v_a_l_u_e, e.g. - LLDD__LLIIBBRRAARRYY__PPAATTHH=_/_u_s_r_/_l_o_c_a_l_/_p_k_g_/_l_i_b. Variables passed on the command - line are subject to the same restrictions as normal environment - variables with one important exception. If the _s_e_t_e_n_v option is set in - _s_u_d_o_e_r_s, the command to be run has the SETENV tag set or the command - matched is ALL, the user may set variables that would overwise be - forbidden. See _s_u_d_o_e_r_s(4) for more information. - -RREETTUURRNN VVAALLUUEESS - Upon successful execution of a program, the exit status from ssuuddoo will - simply be the exit status of the program that was executed. - - Otherwise, ssuuddoo quits with an exit value of 1 if there is a - configuration/permission problem or if ssuuddoo cannot execute the given - command. In the latter case the error string is printed to stderr. If - ssuuddoo cannot _s_t_a_t(2) one or more entries in the user's PATH an error is - printed on stderr. (If the directory does not exist or if it is not - really a directory, the entry is ignored and no error is printed.) - This should not happen under normal circumstances. The most common - reason for _s_t_a_t(2) to return "permission denied" is if you are running - an automounter and one of the directories in your PATH is on a machine - that is currently unreachable. - -SSEECCUURRIITTYY NNOOTTEESS - ssuuddoo tries to be safe when executing external commands. - - There are two distinct ways to deal with environment variables. By - default, the _e_n_v___r_e_s_e_t _s_u_d_o_e_r_s option is enabled. This causes commands - to be executed with a minimal environment containing TERM, PATH, HOME, - SHELL, LOGNAME, USER and USERNAME in addition to variables from the - - - -1.7.4 July 19, 2010 6 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - invoking process permitted by the _e_n_v___c_h_e_c_k and _e_n_v___k_e_e_p _s_u_d_o_e_r_s - options. There is effectively a whitelist for environment variables. - - If, however, the _e_n_v___r_e_s_e_t option is disabled in _s_u_d_o_e_r_s, any variables - not explicitly denied by the _e_n_v___c_h_e_c_k and _e_n_v___d_e_l_e_t_e options are - inherited from the invoking process. In this case, _e_n_v___c_h_e_c_k and - _e_n_v___d_e_l_e_t_e behave like a blacklist. Since it is not possible to - blacklist all potentially dangerous environment variables, use of the - default _e_n_v___r_e_s_e_t behavior is encouraged. - - In all cases, environment variables with a value beginning with () are - removed as they could be interpreted as bbaasshh functions. The list of - environment variables that ssuuddoo allows or denies is contained in the - output of sudo -V when run as root. - - Note that the dynamic linker on most operating systems will remove - variables that can control dynamic linking from the environment of - setuid executables, including ssuuddoo. Depending on the operating system - this may include _RLD*, DYLD_*, LD_*, LDR_*, LIBPATH, SHLIB_PATH, and - others. These type of variables are removed from the environment - before ssuuddoo even begins execution and, as such, it is not possible for - ssuuddoo to preserve them. - - To prevent command spoofing, ssuuddoo checks "." and "" (both denoting - current directory) last when searching for a command in the user's PATH - (if one or both are in the PATH). Note, however, that the actual PATH - environment variable is _n_o_t modified and is passed unchanged to the - program that ssuuddoo executes. - - ssuuddoo will check the ownership of its time stamp directory - (_/_v_a_r_/_a_d_m_/_s_u_d_o by default) and ignore the directory's contents if it is - not owned by root or if it is writable by a user other than root. On - systems that allow non-root users to give away files via _c_h_o_w_n(2), if - the time stamp directory is located in a directory writable by anyone - (e.g., _/_t_m_p), it is possible for a user to create the time stamp - directory before ssuuddoo is run. However, because ssuuddoo checks the - ownership and mode of the directory and its contents, the only damage - that can be done is to "hide" files by putting them in the time stamp - dir. This is unlikely to happen since once the time stamp dir is owned - by root and inaccessible by any other user, the user placing files - there would be unable to get them back out. To get around this issue - you can use a directory that is not world-writable for the time stamps - (_/_v_a_r_/_a_d_m_/_s_u_d_o for instance) or create _/_v_a_r_/_a_d_m_/_s_u_d_o with the - appropriate owner (root) and permissions (0700) in the system startup - files. - - ssuuddoo will not honor time stamps set far in the future. Timestamps with - a date greater than current_time + 2 * TIMEOUT will be ignored and sudo - will log and complain. This is done to keep a user from creating - his/her own time stamp with a bogus date on systems that allow users to - give away files. - - On systems where the boot time is available, ssuuddoo will also not honor - time stamps from before the machine booted. - - - -1.7.4 July 19, 2010 7 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - Since time stamp files live in the file system, they can outlive a - user's login session. As a result, a user may be able to login, run a - command with ssuuddoo after authenticating, logout, login again, and run - ssuuddoo without authenticating so long as the time stamp file's - modification time is within 5 minutes (or whatever the timeout is set - to in _s_u_d_o_e_r_s). When the _t_t_y___t_i_c_k_e_t_s option is enabled in _s_u_d_o_e_r_s, the - time stamp has per-tty granularity but still may outlive the user's - session. On Linux systems where the devpts filesystem is used, Solaris - systems with the devices filesystem, as well as other systems that - utilize a devfs filesystem that monotonically increase the inode number - of devices as they are created (such as Mac OS X), ssuuddoo is able to - determine when a tty-based time stamp file is stale and will ignore it. - Administrators should not rely on this feature as it is not universally - available. - - Please note that ssuuddoo will normally only log the command it explicitly - runs. If a user runs a command such as sudo su or sudo sh, subsequent - commands run from that shell will _n_o_t be logged, nor will ssuuddoo's access - control affect them. The same is true for commands that offer shell - escapes (including most editors). Because of this, care must be taken - when giving users access to commands via ssuuddoo to verify that the - command does not inadvertently give the user an effective root shell. - For more information, please see the PREVENTING SHELL ESCAPES section - in _s_u_d_o_e_r_s(4). - -EENNVVIIRROONNMMEENNTT - ssuuddoo utilizes the following environment variables: - - EDITOR Default editor to use in --ee (sudoedit) mode if neither - SUDO_EDITOR nor VISUAL is set - - MAIL In --ii mode or when _e_n_v___r_e_s_e_t is enabled in _s_u_d_o_e_r_s, set - to the mail spool of the target user - - HOME Set to the home directory of the target user if --ii or - --HH are specified, _e_n_v___r_e_s_e_t or _a_l_w_a_y_s___s_e_t___h_o_m_e are set - in _s_u_d_o_e_r_s, or when the --ss option is specified and - _s_e_t___h_o_m_e is set in _s_u_d_o_e_r_s - - PATH Set to a sane value if the _s_e_c_u_r_e___p_a_t_h sudoers option - is set. - - SHELL Used to determine shell to run with -s option - - SUDO_ASKPASS Specifies the path to a helper program used to read the - password if no terminal is available or if the -A - option is specified. - - SUDO_COMMAND Set to the command run by sudo - - SUDO_EDITOR Default editor to use in --ee (sudoedit) mode - - SUDO_GID Set to the group ID of the user who invoked sudo - - - - -1.7.4 July 19, 2010 8 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - SUDO_PROMPT Used as the default password prompt - - SUDO_PS1 If set, PS1 will be set to its value for the program - being run - - SUDO_UID Set to the user ID of the user who invoked sudo - - SUDO_USER Set to the login of the user who invoked sudo - - USER Set to the target user (root unless the --uu option is - specified) - - VISUAL Default editor to use in --ee (sudoedit) mode if - SUDO_EDITOR is not set - -FFIILLEESS - _/_e_t_c_/_s_u_d_o_e_r_s List of who can run what - - _/_v_a_r_/_a_d_m_/_s_u_d_o Directory containing time stamps - - _/_e_t_c_/_e_n_v_i_r_o_n_m_e_n_t Initial environment for --ii mode on Linux and - AIX - -EEXXAAMMPPLLEESS - Note: the following examples assume suitable _s_u_d_o_e_r_s(4) entries. - - To get a file listing of an unreadable directory: - - $ sudo ls /usr/local/protected - - To list the home directory of user yaz on a machine where the file - system holding ~yaz is not exported as root: - - $ sudo -u yaz ls ~yaz - - To edit the _i_n_d_e_x_._h_t_m_l file as user www: - - $ sudo -u www vi ~www/htdocs/index.html - - To view system logs only accessible to root and users in the adm group: - - $ sudo -g adm view /var/log/syslog - - To run an editor as jim with a different primary group: - - $ sudo -u jim -g audio vi ~jim/sound.txt - - To shutdown a machine: - - $ sudo shutdown -r +15 "quick reboot" - - To make a usage listing of the directories in the /home partition. - Note that this runs the commands in a sub-shell to make the cd and file - redirection work. - - - -1.7.4 July 19, 2010 9 - - - - - -SUDO(1m) MAINTENANCE COMMANDS SUDO(1m) - - - $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE" - -SSEEEE AALLSSOO - _g_r_e_p(1), _s_u(1), _s_t_a_t(2), _l_o_g_i_n___c_a_p(3), _p_a_s_s_w_d(4), _s_u_d_o_e_r_s(5), - _v_i_s_u_d_o(1m) - -AAUUTTHHOORRSS - Many people have worked on ssuuddoo over the years; this version consists - of code written primarily by: - - Todd C. Miller - - See the HISTORY file in the ssuuddoo distribution or visit - http://www.sudo.ws/sudo/history.html for a short history of ssuuddoo. - -CCAAVVEEAATTSS - There is no easy way to prevent a user from gaining a root shell if - that user is allowed to run arbitrary commands via ssuuddoo. Also, many - programs (such as editors) allow the user to run commands via shell - escapes, thus avoiding ssuuddoo's checks. However, on most systems it is - possible to prevent shell escapes with ssuuddoo's _n_o_e_x_e_c functionality. - See the _s_u_d_o_e_r_s(4) manual for details. - - It is not meaningful to run the cd command directly via sudo, e.g., - - $ sudo cd /usr/local/protected - - since when the command exits the parent process (your shell) will still - be the same. Please see the EXAMPLES section for more information. - - If users have sudo ALL there is nothing to prevent them from creating - their own program that gives them a root shell regardless of any '!' - elements in the user specification. - - Running shell scripts via ssuuddoo can expose the same kernel bugs that - make setuid shell scripts unsafe on some operating systems (if your OS - has a /dev/fd/ directory, setuid shell scripts are generally safe). - -BBUUGGSS - If you feel you have found a bug in ssuuddoo, please submit a bug report at - http://www.sudo.ws/sudo/bugs/ - -SSUUPPPPOORRTT - Limited free support is available via the sudo-users mailing list, see - http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search - the archives. - -DDIISSCCLLAAIIMMEERR - ssuuddoo is provided ``AS IS'' and any express or implied warranties, - including, but not limited to, the implied warranties of - merchantability and fitness for a particular purpose are disclaimed. - See the LICENSE file distributed with ssuuddoo or - http://www.sudo.ws/sudo/license.html for complete details. - - - - -1.7.4 July 19, 2010 10 - - diff --git a/sudo.h b/sudo.h deleted file mode 100644 index f946291..0000000 --- a/sudo.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 1993-1996, 1998-2005, 2007-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_SUDO_H -#define _SUDO_SUDO_H - -#include -#include -#include "compat.h" -#include "alloc.h" -#include "defaults.h" -#include "error.h" -#include "list.h" -#include "logging.h" -#include "missing.h" -#include "sudo_nss.h" - -#ifdef HAVE_MBR_CHECK_MEMBERSHIP -# include -#endif - -/* - * Info pertaining to the invoking user. - */ -struct sudo_user { - struct passwd *pw; - struct passwd *_runas_pw; - struct group *_runas_gr; - struct stat *cmnd_stat; - char *path; - char *shell; - char *tty; - char *ttypath; - char *host; - char *shost; - char *prompt; - char *cmnd; - char *cmnd_args; - char *cmnd_base; - char *cmnd_safe; - char *class_name; - char *krb5_ccname; - char *display; - char *askpass; - int ngroups; - GETGROUPS_T *groups; - struct list_member *env_vars; -#ifdef HAVE_SELINUX - char *role; - char *type; -#endif - char cwd[PATH_MAX]; - char sessid[7]; -#ifdef HAVE_MBR_CHECK_MEMBERSHIP - uuid_t uuid; -#endif -}; - -/* Status passed between parent and child via socketpair */ -struct command_status { -#define CMD_INVALID 0 -#define CMD_ERRNO 1 -#define CMD_WSTATUS 2 -#define CMD_SIGNO 3 - int type; - int val; -}; - -/* - * Return values for sudoers_lookup(), also used as arguments for log_auth() - * Note: cannot use '0' as a value here. - */ -/* XXX - VALIDATE_SUCCESS and VALIDATE_FAILURE instead? */ -#define VALIDATE_ERROR 0x001 -#define VALIDATE_OK 0x002 -#define VALIDATE_NOT_OK 0x004 -#define FLAG_CHECK_USER 0x010 -#define FLAG_NO_USER 0x020 -#define FLAG_NO_HOST 0x040 -#define FLAG_NO_CHECK 0x080 - -/* - * Pseudo-boolean values - */ -#undef TRUE -#define TRUE 1 -#undef FALSE -#define FALSE 0 - -/* - * find_path()/load_cmnd() return values - */ -#define FOUND 1 -#define NOT_FOUND 0 -#define NOT_FOUND_DOT -1 - -/* - * Various modes sudo can be in (based on arguments) in hex - */ -#define MODE_RUN 0x00000001 -#define MODE_EDIT 0x00000002 -#define MODE_VALIDATE 0x00000004 -#define MODE_INVALIDATE 0x00000008 -#define MODE_KILL 0x00000010 -#define MODE_VERSION 0x00000020 -#define MODE_HELP 0x00000040 -#define MODE_LIST 0x00000080 -#define MODE_CHECK 0x00000100 -#define MODE_LISTDEFS 0x00000200 -#define MODE_MASK 0x0000ffff - -/* Mode flags */ -#define MODE_BACKGROUND 0x00010000 -#define MODE_SHELL 0x00020000 -#define MODE_LOGIN_SHELL 0x00040000 -#define MODE_IMPLIED_SHELL 0x00080000 -#define MODE_RESET_HOME 0x00100000 -#define MODE_PRESERVE_GROUPS 0x00200000 -#define MODE_PRESERVE_ENV 0x00400000 -#define MODE_NONINTERACTIVE 0x00800000 - -/* - * Used with set_perms() - */ -#define PERM_ROOT 0x00 -#define PERM_USER 0x01 -#define PERM_FULL_USER 0x02 -#define PERM_SUDOERS 0x03 -#define PERM_RUNAS 0x04 -#define PERM_FULL_RUNAS 0x05 -#define PERM_TIMESTAMP 0x06 -#define PERM_NOEXIT 0x10 /* flag */ -#define PERM_MASK 0xf0 - -/* - * Shortcuts for sudo_user contents. - */ -#define user_name (sudo_user.pw->pw_name) -#define user_passwd (sudo_user.pw->pw_passwd) -#define user_uid (sudo_user.pw->pw_uid) -#define user_uuid (sudo_user.uuid) -#define user_gid (sudo_user.pw->pw_gid) -#define user_dir (sudo_user.pw->pw_dir) -#define user_shell (sudo_user.shell) -#define user_ngroups (sudo_user.ngroups) -#define user_groups (sudo_user.groups) -#define user_tty (sudo_user.tty) -#define user_ttypath (sudo_user.ttypath) -#define user_cwd (sudo_user.cwd) -#define user_cmnd (sudo_user.cmnd) -#define user_args (sudo_user.cmnd_args) -#define user_base (sudo_user.cmnd_base) -#define user_stat (sudo_user.cmnd_stat) -#define user_path (sudo_user.path) -#define user_prompt (sudo_user.prompt) -#define user_host (sudo_user.host) -#define user_shost (sudo_user.shost) -#define user_ccname (sudo_user.krb5_ccname) -#define user_display (sudo_user.display) -#define user_askpass (sudo_user.askpass) -#define safe_cmnd (sudo_user.cmnd_safe) -#define login_class (sudo_user.class_name) -#define runas_pw (sudo_user._runas_pw) -#define runas_gr (sudo_user._runas_gr) -#define user_role (sudo_user.role) -#define user_type (sudo_user.type) - -/* - * We used to use the system definition of PASS_MAX or _PASSWD_LEN, - * but that caused problems with various alternate authentication - * methods. So, we just define our own and assume that it is >= the - * system max. - */ -#define SUDO_PASS_MAX 256 - -/* - * Flags for lock_file() - */ -#define SUDO_LOCK 1 /* lock a file */ -#define SUDO_TLOCK 2 /* test & lock a file (non-blocking) */ -#define SUDO_UNLOCK 4 /* unlock a file */ - -/* - * Flags for tgetpass() - */ -#define TGP_ECHO 0x01 /* leave echo on when reading passwd */ -#define TGP_STDIN 0x02 /* read from stdin, not /dev/tty */ -#define TGP_ASKPASS 0x04 /* read from askpass helper program */ - -struct lbuf; -struct passwd; -struct stat; -struct timeval; - -/* aix.c */ -void aix_prep_user __P((char *, char *)); -void aix_setauthdb __P((char *user)); -void aix_restoreauthdb __P((void)); - -/* boottime.c */ -int get_boottime __P((struct timeval *)); - -/* check.c */ -int user_is_exempt __P((void)); -void check_user __P((int, int)); -void remove_timestamp __P((int)); - -/* env.c */ -char **env_get __P((void)); -void env_init __P((int lazy)); -void init_envtables __P((void)); -void insert_env_vars __P((struct list_member *)); -void read_env_file __P((const char *, int)); -void rebuild_env __P((int)); -void validate_env_vars __P((struct list_member *)); - -/* exec.c */ -int sudo_execve __P((const char *path, char *argv[], char *envp[], uid_t uid, - struct command_status *cstat, int dowait, int bgmode)); - -/* fileops.c */ -char *sudo_parseln __P((FILE *)); -int lock_file __P((int, int)); -int touch __P((int, char *, struct timeval *)); - -/* find_path.c */ -int find_path __P((char *, char **, struct stat *, char *, int)); - -/* getspwuid.c */ -char *sudo_getepw __P((const struct passwd *)); - -/* gettime.c */ -int gettime __P((struct timeval *)); - -/* goodpath.c */ -char *sudo_goodpath __P((const char *, struct stat *)); - -/* gram.y */ -int yyparse __P((void)); - -/* iolog.c */ -int io_log_open __P((void)); -int log_stderr __P((const char *buf, unsigned int len)); -int log_stdin __P((const char *buf, unsigned int len)); -int log_stdout __P((const char *buf, unsigned int len)); -int log_ttyin __P((const char *buf, unsigned int len)); -int log_ttyout __P((const char *buf, unsigned int len)); -void io_log_close __P((void)); -void io_nextid __P((void)); - -/* pam.c */ -int pam_begin_session __P((struct passwd *)); -int pam_end_session __P((void)); - -/* parse.c */ -int sudo_file_open __P((struct sudo_nss *)); -int sudo_file_close __P((struct sudo_nss *)); -int sudo_file_setdefs __P((struct sudo_nss *)); -int sudo_file_lookup __P((struct sudo_nss *, int, int)); -int sudo_file_parse __P((struct sudo_nss *)); -int sudo_file_display_cmnd __P((struct sudo_nss *, struct passwd *)); -int sudo_file_display_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *)); -int sudo_file_display_bound_defaults __P((struct sudo_nss *, struct passwd *, struct lbuf *)); -int sudo_file_display_privs __P((struct sudo_nss *, struct passwd *, struct lbuf *)); - -/* parse_args.c */ -int parse_args __P((int, char **)); - -/* get_pty.c */ -int get_pty __P((int *master, int *slave, char *name, size_t namesz, uid_t uid)); - -/* pwutil.c */ -int user_in_group __P((struct passwd *, const char *)); -struct group *sudo_fakegrnam __P((const char *)); -struct group *sudo_getgrgid __P((gid_t)); -struct group *sudo_getgrnam __P((const char *)); -struct passwd *sudo_fakepwnam __P((const char *, gid_t)); -struct passwd *sudo_getpwnam __P((const char *)); -struct passwd *sudo_getpwuid __P((uid_t)); -void sudo_endgrent __P((void)); -void sudo_endpwent __P((void)); -void sudo_endspent __P((void)); -void sudo_setgrent __P((void)); -void sudo_setpwent __P((void)); -void sudo_setspent __P((void)); - -/* selinux.c */ -int selinux_restore_tty __P((void)); -int selinux_setup __P((const char *role, const char *type, const char *ttyn, - int ttyfd)); -void selinux_execve __P((const char *path, char *argv[], char *envp[])); - -/* set_perms.c */ -int set_perms __P((int)); - -/* sudo.c */ -FILE *open_sudoers __P((const char *, int, int *)); -int exec_setup __P((int, const char *, int)); -void cleanup __P((int)); -void set_fqdn __P((void)); - -/* sudo_auth.c */ -void verify_user __P((struct passwd *, char *)); -void pass_warn __P((FILE *)); -void dump_auth_methods __P((void)); - -/* sudo_nss.c */ -void display_privs __P((struct sudo_nss_list *, struct passwd *)); -int display_cmnd __P((struct sudo_nss_list *, struct passwd *)); - -/* term.c */ -int term_cbreak __P((int)); -int term_copy __P((int, int)); -int term_noecho __P((int)); -int term_raw __P((int, int)); -int term_restore __P((int, int)); - -/* tgetpass.c */ -char *tgetpass __P((const char *, int, int)); -int tty_present __P((void)); - -/* timestr.c */ -char *get_timestr __P((time_t, int)); - -/* toke.l */ -#define YY_DECL int yylex __P((void)) -YY_DECL; - -/* zero_bytes.c */ -void zero_bytes __P((volatile void *, size_t)); - -/* Only provide extern declarations outside of sudo.c. */ -#ifndef _SUDO_MAIN -extern struct sudo_user sudo_user; -extern struct passwd *auth_pw, *list_pw; - -extern int tgetpass_flags; -extern int long_list; -extern int sudo_mode; -extern uid_t timestamp_uid; -/* XXX - conflicts with the one in visudo */ -int run_command __P((const char *path, char *argv[], char *envp[], uid_t uid, int dowait)); -#endif -#ifndef errno -extern int errno; -#endif - -#endif /* _SUDO_SUDO_H */ diff --git a/sudo.man.in b/sudo.man.in deleted file mode 100644 index 3d67a76..0000000 --- a/sudo.man.in +++ /dev/null @@ -1,802 +0,0 @@ -.\" Copyright (c) 1994-1996, 1998-2005, 2007-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. -.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" Sponsored in part by the Defense Advanced Research Projects -.\" Agency (DARPA) and Air Force Research Laboratory, Air Force -.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. -.\" -.nr SL @SEMAN@ -.nr BA @BAMAN@ -.nr LC @LCMAN@ -.nr PT @password_timeout@ -.\" -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` -. ds C' -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "SUDO @mansectsu@" -.TH SUDO @mansectsu@ "July 19, 2010" "1.7.4" "MAINTENANCE COMMANDS" -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -sudo, sudoedit \- execute a command as another user -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBsudo\fR \fB\-h\fR | \fB\-K\fR | \fB\-k\fR | \fB\-L\fR | \fB\-V\fR -.PP -\&\fBsudo\fR \fB\-v\fR [\fB\-AknS\fR] -.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] -[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] -[\fB\-u\fR\ \fIusername\fR|\fI#uid\fR] -.PP -\&\fBsudo\fR \fB\-l[l]\fR [\fB\-AknS\fR] -.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] -[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] -[\fB\-U\fR\ \fIuser\ name\fR] [\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] [\fIcommand\fR] -.PP -\&\fBsudo\fR [\fB\-AbEHnPS\fR] -.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] -[\fB\-C\fR\ \fIfd\fR] -.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR] -[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] -.if \n(SL [\fB\-r\fR\ \fIrole\fR] [\fB\-t\fR\ \fItype\fR] -[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] -[\fB\s-1VAR\s0\fR=\fIvalue\fR] [\fB\-i\fR\ |\ \fB\-s\fR] [\fIcommand\fR] -.PP -\&\fBsudoedit\fR [\fB\-AnS\fR] -.if \n(BA [\fB\-a\fR\ \fIauth_type\fR] -[\fB\-C\fR\ \fIfd\fR] -.if \n(LC [\fB\-c\fR\ \fIclass\fR|\fI\-\fR] -[\fB\-g\fR\ \fIgroup\ name\fR|\fI#gid\fR] [\fB\-p\fR\ \fIprompt\fR] -[\fB\-u\fR\ \fIuser\ name\fR|\fI#uid\fR] file ... -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fBsudo\fR allows a permitted user to execute a \fIcommand\fR as the -superuser or another user, as specified in the \fIsudoers\fR file. -The real and effective uid and gid are set to match those of the -target user as specified in the passwd file and the group vector -is initialized based on the group file (unless the \fB\-P\fR option was -specified). If the invoking user is root or if the target user is -the same as the invoking user, no password is required. Otherwise, -\&\fBsudo\fR requires that users authenticate themselves with a password -by default (\s-1NOTE:\s0 in the default configuration this is the user's -password, not the root password). Once a user has been authenticated, -a time stamp is updated and the user may then use sudo without a -password for a short period of time (\f(CW\*(C`@timeout@\*(C'\fR minutes unless -overridden in \fIsudoers\fR). -.PP -When invoked as \fBsudoedit\fR, the \fB\-e\fR option (described below), -is implied. -.PP -\&\fBsudo\fR determines who is an authorized user by consulting the file -\&\fI@sysconfdir@/sudoers\fR. By running \fBsudo\fR with the \fB\-v\fR option, -a user can update the time stamp without running a \fIcommand\fR. If -a password is required, \fBsudo\fR will exit if the user's password -is not entered within a configurable time limit. The default -password prompt timeout is -.ie \n(PT \f(CW\*(C`@password_timeout@\*(C'\fR minutes. -.el unlimited. -.PP -If a user who is not listed in the \fIsudoers\fR file tries to run a -command via \fBsudo\fR, mail is sent to the proper authorities, as -defined at configure time or in the \fIsudoers\fR file (defaults to -\&\f(CW\*(C`@mailto@\*(C'\fR). Note that the mail will not be sent if an unauthorized -user tries to run sudo with the \fB\-l\fR or \fB\-v\fR option. This allows -users to determine for themselves whether or not they are allowed -to use \fBsudo\fR. -.PP -If \fBsudo\fR is run by root and the \f(CW\*(C`SUDO_USER\*(C'\fR environment variable -is set, \fBsudo\fR will use this value to determine who the actual -user is. This can be used by a user to log commands through sudo -even when a root shell has been invoked. It also allows the \fB\-e\fR -option to remain useful even when being run via a sudo-run script or -program. Note however, that the sudoers lookup is still done for -root, not the user specified by \f(CW\*(C`SUDO_USER\*(C'\fR. -.PP -\&\fBsudo\fR can log both successful and unsuccessful attempts (as well -as errors) to \fIsyslog\fR\|(3), a log file, or both. By default \fBsudo\fR -will log via \fIsyslog\fR\|(3) but this is changeable at configure time -or via the \fIsudoers\fR file. -.SH "OPTIONS" -.IX Header "OPTIONS" -\&\fBsudo\fR accepts the following command line options: -.IP "\-A" 12 -.IX Item "-A" -Normally, if \fBsudo\fR requires a password, it will read it from the -current terminal. If the \fB\-A\fR (\fIaskpass\fR) option is specified, -a (possibly graphical) helper program is executed to read the -user's password and output the password to the standard output. If -the \f(CW\*(C`SUDO_ASKPASS\*(C'\fR environment variable is set, it specifies the -path to the helper program. Otherwise, the value specified by the -\&\fIaskpass\fR option in \fIsudoers\fR\|(@mansectform@) is used. -.if \n(BA \{\ -.IP "\-a \fItype\fR" 12 -.IX Item "-a type" -The \fB\-a\fR (\fIauthentication type\fR) option causes \fBsudo\fR to use the -specified authentication type when validating the user, as allowed -by \fI/etc/login.conf\fR. The system administrator may specify a list -of sudo-specific authentication methods by adding an \*(L"auth-sudo\*(R" -entry in \fI/etc/login.conf\fR. This option is only available on systems -that support \s-1BSD\s0 authentication. -\} -.IP "\-b" 12 -.IX Item "-b" -The \fB\-b\fR (\fIbackground\fR) option tells \fBsudo\fR to run the given -command in the background. Note that if you use the \fB\-b\fR -option you cannot use shell job control to manipulate the process. -.IP "\-C \fIfd\fR" 12 -.IX Item "-C fd" -Normally, \fBsudo\fR will close all open file descriptors other than -standard input, standard output and standard error. The \fB\-C\fR -(\fIclose from\fR) option allows the user to specify a starting point -above the standard error (file descriptor three). Values less than -three are not permitted. This option is only available if the -administrator has enabled the \fIclosefrom_override\fR option in -\&\fIsudoers\fR\|(@mansectform@). -.if \n(LC \{\ -.IP "\-c \fIclass\fR" 12 -.IX Item "-c class" -The \fB\-c\fR (\fIclass\fR) option causes \fBsudo\fR to run the specified command -with resources limited by the specified login class. The \fIclass\fR -argument can be either a class name as defined in \fI/etc/login.conf\fR, -or a single '\-' character. Specifying a \fIclass\fR of \f(CW\*(C`\-\*(C'\fR indicates -that the command should be run restricted by the default login -capabilities for the user the command is run as. If the \fIclass\fR -argument specifies an existing user class, the command must be run -as root, or the \fBsudo\fR command must be run from a shell that is already -root. This option is only available on systems with \s-1BSD\s0 login classes. -\} -.IP "\-E" 12 -.IX Item "-E" -The \fB\-E\fR (\fIpreserve\fR \fIenvironment\fR) option will override the -\&\fIenv_reset\fR option in \fIsudoers\fR\|(@mansectform@)). It is only -available when either the matching command has the \f(CW\*(C`SETENV\*(C'\fR tag -or the \fIsetenv\fR option is set in \fIsudoers\fR\|(@mansectform@). -.IP "\-e" 12 -.IX Item "-e" -The \fB\-e\fR (\fIedit\fR) option indicates that, instead of running -a command, the user wishes to edit one or more files. In lieu -of a command, the string \*(L"sudoedit\*(R" is used when consulting -the \fIsudoers\fR file. If the user is authorized by \fIsudoers\fR -the following steps are taken: -.RS 12 -.IP "1." 4 -Temporary copies are made of the files to be edited with the owner -set to the invoking user. -.IP "2." 4 -The editor specified by the \f(CW\*(C`SUDO_EDITOR\*(C'\fR, \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR -environment variables is run to edit the temporary files. If none -of \f(CW\*(C`SUDO_EDITOR\*(C'\fR, \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR are set, the first program -listed in the \fIeditor\fR \fIsudoers\fR variable is used. -.IP "3." 4 -If they have been modified, the temporary files are copied back to -their original location and the temporary versions are removed. -.RE -.RS 12 -.Sp -If the specified file does not exist, it will be created. Note -that unlike most commands run by \fBsudo\fR, the editor is run with -the invoking user's environment unmodified. If, for some reason, -\&\fBsudo\fR is unable to update a file with its edited version, the -user will receive a warning and the edited copy will remain in a -temporary file. -.RE -.IP "\-g \fIgroup\fR" 12 -.IX Item "-g group" -Normally, \fBsudo\fR sets the primary group to the one specified by -the passwd database for the user the command is being run as (by -default, root). The \fB\-g\fR (\fIgroup\fR) option causes \fBsudo\fR to run -the specified command with the primary group set to \fIgroup\fR. To -specify a \fIgid\fR instead of a \fIgroup name\fR, use \fI#gid\fR. When -running commands as a \fIgid\fR, many shells require that the '#' be -escaped with a backslash ('\e'). If no \fB\-u\fR option is specified, -the command will be run as the invoking user (not root). In either -case, the primary group will be set to \fIgroup\fR. -.IP "\-H" 12 -.IX Item "-H" -The \fB\-H\fR (\fI\s-1HOME\s0\fR) option sets the \f(CW\*(C`HOME\*(C'\fR environment variable -to the homedir of the target user (root by default) as specified -in \fIpasswd\fR\|(@mansectform@). The default handling of the \f(CW\*(C`HOME\*(C'\fR environment -variable depends on \fIsudoers\fR\|(@mansectform@) settings. By default, \fBsudo\fR -will set \f(CW\*(C`HOME\*(C'\fR if \fIenv_reset\fR or \fIalways_set_home\fR are set, or -if \fIset_home\fR is set and the \fB\-s\fR option is specified on the -command line. -.IP "\-h" 12 -.IX Item "-h" -The \fB\-h\fR (\fIhelp\fR) option causes \fBsudo\fR to print a usage message and exit. -.IP "\-i [command]" 12 -.IX Item "-i [command]" -The \fB\-i\fR (\fIsimulate initial login\fR) option runs the shell specified -in the \fIpasswd\fR\|(@mansectform@) entry of the target user as a login shell. This -means that login-specific resource files such as \f(CW\*(C`.profile\*(C'\fR or -\&\f(CW\*(C`.login\*(C'\fR will be read by the shell. If a command is specified, -it is passed to the shell for execution. Otherwise, an interactive -shell is executed. \fBsudo\fR attempts to change to that user's home -directory before running the shell. It also initializes the -environment, leaving \fI\s-1DISPLAY\s0\fR and \fI\s-1TERM\s0\fR unchanged, setting -\&\fI\s-1HOME\s0\fR, \fI\s-1MAIL\s0\fR, \fI\s-1SHELL\s0\fR, \fI\s-1USER\s0\fR, \fI\s-1LOGNAME\s0\fR, and \fI\s-1PATH\s0\fR, as well as -the contents of \fI/etc/environment\fR on Linux and \s-1AIX\s0 systems. -All other environment variables are removed. -.IP "\-K" 12 -.IX Item "-K" -The \fB\-K\fR (sure \fIkill\fR) option is like \fB\-k\fR except that it removes -the user's time stamp entirely and may not be used in conjunction -with a command or other option. This option does not require a -password. -.IP "\-k" 12 -.IX Item "-k" -When used by itself, the \fB\-k\fR (\fIkill\fR) option to \fBsudo\fR invalidates -the user's time stamp by setting the time on it to the Epoch. The -next time \fBsudo\fR is run a password will be required. This option -does not require a password and was added to allow a user to revoke -\&\fBsudo\fR permissions from a .logout file. -.Sp -When used in conjunction with a command or an option that may require -a password, the \fB\-k\fR option will cause \fBsudo\fR to ignore the user's -time stamp file. As a result, \fBsudo\fR will prompt for a password -(if one is required by \fIsudoers\fR) and will not update the user's -time stamp file. -.IP "\-L" 12 -.IX Item "-L" -The \fB\-L\fR (\fIlist\fR defaults) option will list the parameters that -may be set in a \fIDefaults\fR line along with a short description for -each. This option will be removed from a future version of \fBsudo\fR. -.IP "\-l[l] [\fIcommand\fR]" 12 -.IX Item "-l[l] [command]" -If no \fIcommand\fR is specified, the \fB\-l\fR (\fIlist\fR) option will list -the allowed (and forbidden) commands for the invoking user (or the -user specified by the \fB\-U\fR option) on the current host. If a -\&\fIcommand\fR is specified and is permitted by \fIsudoers\fR, the -fully-qualified path to the command is displayed along with any -command line arguments. If \fIcommand\fR is specified but not allowed, -\&\fBsudo\fR will exit with a status value of 1. If the \fB\-l\fR option is -specified with an \fBl\fR argument (i.e. \fB\-ll\fR), or if \fB\-l\fR -is specified multiple times, a longer list format is used. -.IP "\-n" 12 -.IX Item "-n" -The \fB\-n\fR (\fInon-interactive\fR) option prevents \fBsudo\fR from prompting -the user for a password. If a password is required for the command -to run, \fBsudo\fR will display an error messages and exit. -.IP "\-P" 12 -.IX Item "-P" -The \fB\-P\fR (\fIpreserve\fR \fIgroup vector\fR) option causes \fBsudo\fR to -preserve the invoking user's group vector unaltered. By default, -\&\fBsudo\fR will initialize the group vector to the list of groups the -target user is in. The real and effective group IDs, however, are -still set to match the target user. -.IP "\-p \fIprompt\fR" 12 -.IX Item "-p prompt" -The \fB\-p\fR (\fIprompt\fR) option allows you to override the default -password prompt and use a custom one. The following percent (`\f(CW\*(C`%\*(C'\fR') -escapes are supported: -.RS 12 -.ie n .IP "%H" 4 -.el .IP "\f(CW%H\fR" 4 -.IX Item "%H" -expanded to the local host name including the domain name -(on if the machine's host name is fully qualified or the \fIfqdn\fR -\&\fIsudoers\fR option is set) -.ie n .IP "%h" 4 -.el .IP "\f(CW%h\fR" 4 -.IX Item "%h" -expanded to the local host name without the domain name -.ie n .IP "%p" 4 -.el .IP "\f(CW%p\fR" 4 -.IX Item "%p" -expanded to the user whose password is being asked for (respects the -\&\fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in \fIsudoers\fR) -.ie n .IP "%U" 4 -.el .IP "\f(CW%U\fR" 4 -.IX Item "%U" -expanded to the login name of the user the command will -be run as (defaults to root) -.ie n .IP "%u" 4 -.el .IP "\f(CW%u\fR" 4 -.IX Item "%u" -expanded to the invoking user's login name -.ie n .IP "\*(C`%%\*(C'" 4 -.el .IP "\f(CW\*(C`%%\*(C'\fR" 4 -.IX Item "%%" -two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character -.RE -.RS 12 -.Sp -The prompt specified by the \fB\-p\fR option will override the system -password prompt on systems that support \s-1PAM\s0 unless the -\&\fIpassprompt_override\fR flag is disabled in \fIsudoers\fR. -.RE -.if \n(SL \{\ -.IP "\-r \fIrole\fR" 12 -.IX Item "-r role" -The \fB\-r\fR (\fIrole\fR) option causes the new (SELinux) security context to -have the role specified by \fIrole\fR. -\} -.IP "\-S" 12 -.IX Item "-S" -The \fB\-S\fR (\fIstdin\fR) option causes \fBsudo\fR to read the password from -the standard input instead of the terminal device. The password must -be followed by a newline character. -.IP "\-s [command]" 12 -.IX Item "-s [command]" -The \fB\-s\fR (\fIshell\fR) option runs the shell specified by the \fI\s-1SHELL\s0\fR -environment variable if it is set or the shell as specified in -\&\fIpasswd\fR\|(@mansectform@). If a command is specified, it is passed to the shell -for execution. Otherwise, an interactive shell is executed. -.if \n(SL \{\ -.IP "\-t \fItype\fR" 12 -.IX Item "-t type" -The \fB\-t\fR (\fItype\fR) option causes the new (SELinux) security context to -have the type specified by \fItype\fR. If no type is specified, the default -type is derived from the specified role. -\} -.IP "\-U \fIuser\fR" 12 -.IX Item "-U user" -The \fB\-U\fR (\fIother user\fR) option is used in conjunction with the \fB\-l\fR -option to specify the user whose privileges should be listed. Only -root or a user with \fBsudo\fR \f(CW\*(C`ALL\*(C'\fR on the current host may use this -option. -.IP "\-u \fIuser\fR" 12 -.IX Item "-u user" -The \fB\-u\fR (\fIuser\fR) option causes \fBsudo\fR to run the specified -command as a user other than \fIroot\fR. To specify a \fIuid\fR instead -of a \fIuser name\fR, use \fI#uid\fR. When running commands as a \fIuid\fR, -many shells require that the '#' be escaped with a backslash ('\e'). -Note that if the \fItargetpw\fR Defaults option is set (see \fIsudoers\fR\|(@mansectform@)) -it is not possible to run commands with a uid not listed in the -password database. -.IP "\-V" 12 -.IX Item "-V" -The \fB\-V\fR (\fIversion\fR) option causes \fBsudo\fR to print the version -number and exit. If the invoking user is already root the \fB\-V\fR -option will print out a list of the defaults \fBsudo\fR was compiled -with as well as the machine's local network addresses. -.IP "\-v" 12 -.IX Item "-v" -If given the \fB\-v\fR (\fIvalidate\fR) option, \fBsudo\fR will update the -user's time stamp, prompting for the user's password if necessary. -This extends the \fBsudo\fR timeout for another \f(CW\*(C`@timeout@\*(C'\fR minutes -(or whatever the timeout is set to in \fIsudoers\fR) but does not run -a command. -.IP "\-\-" 12 -The \fB\-\-\fR option indicates that \fBsudo\fR should stop processing command -line arguments. -.PP -Environment variables to be set for the command may also be passed -on the command line in the form of \fB\s-1VAR\s0\fR=\fIvalue\fR, e.g. -\&\fB\s-1LD_LIBRARY_PATH\s0\fR=\fI/usr/local/pkg/lib\fR. Variables passed on the -command line are subject to the same restrictions as normal environment -variables with one important exception. If the \fIsetenv\fR option -is set in \fIsudoers\fR, the command to be run has the \f(CW\*(C`SETENV\*(C'\fR tag -set or the command matched is \f(CW\*(C`ALL\*(C'\fR, the user may set variables -that would overwise be forbidden. See \fIsudoers\fR\|(@mansectform@) for more information. -.SH "RETURN VALUES" -.IX Header "RETURN VALUES" -Upon successful execution of a program, the exit status from \fBsudo\fR -will simply be the exit status of the program that was executed. -.PP -Otherwise, \fBsudo\fR quits with an exit value of 1 if there is a -configuration/permission problem or if \fBsudo\fR cannot execute the -given command. In the latter case the error string is printed to -stderr. If \fBsudo\fR cannot \fIstat\fR\|(2) one or more entries in the user's -\&\f(CW\*(C`PATH\*(C'\fR an error is printed on stderr. (If the directory does not -exist or if it is not really a directory, the entry is ignored and -no error is printed.) This should not happen under normal -circumstances. The most common reason for \fIstat\fR\|(2) to return -\&\*(L"permission denied\*(R" is if you are running an automounter and one -of the directories in your \f(CW\*(C`PATH\*(C'\fR is on a machine that is currently -unreachable. -.SH "SECURITY NOTES" -.IX Header "SECURITY NOTES" -\&\fBsudo\fR tries to be safe when executing external commands. -.PP -There are two distinct ways to deal with environment variables. -By default, the \fIenv_reset\fR \fIsudoers\fR option is enabled. -This causes commands to be executed with a minimal environment -containing \f(CW\*(C`TERM\*(C'\fR, \f(CW\*(C`PATH\*(C'\fR, \f(CW\*(C`HOME\*(C'\fR, \f(CW\*(C`SHELL\*(C'\fR, \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR -and \f(CW\*(C`USERNAME\*(C'\fR in addition to variables from the invoking process -permitted by the \fIenv_check\fR and \fIenv_keep\fR \fIsudoers\fR options. -There is effectively a whitelist for environment variables. -.PP -If, however, the \fIenv_reset\fR option is disabled in \fIsudoers\fR, any -variables not explicitly denied by the \fIenv_check\fR and \fIenv_delete\fR -options are inherited from the invoking process. In this case, -\&\fIenv_check\fR and \fIenv_delete\fR behave like a blacklist. Since it -is not possible to blacklist all potentially dangerous environment -variables, use of the default \fIenv_reset\fR behavior is encouraged. -.PP -In all cases, environment variables with a value beginning with -\&\f(CW\*(C`()\*(C'\fR are removed as they could be interpreted as \fBbash\fR functions. -The list of environment variables that \fBsudo\fR allows or denies is -contained in the output of \f(CW\*(C`sudo \-V\*(C'\fR when run as root. -.PP -Note that the dynamic linker on most operating systems will remove -variables that can control dynamic linking from the environment of -setuid executables, including \fBsudo\fR. Depending on the operating -system this may include \f(CW\*(C`_RLD*\*(C'\fR, \f(CW\*(C`DYLD_*\*(C'\fR, \f(CW\*(C`LD_*\*(C'\fR, \f(CW\*(C`LDR_*\*(C'\fR, -\&\f(CW\*(C`LIBPATH\*(C'\fR, \f(CW\*(C`SHLIB_PATH\*(C'\fR, and others. These type of variables are -removed from the environment before \fBsudo\fR even begins execution -and, as such, it is not possible for \fBsudo\fR to preserve them. -.PP -To prevent command spoofing, \fBsudo\fR checks \*(L".\*(R" and "" (both denoting -current directory) last when searching for a command in the user's -\&\s-1PATH\s0 (if one or both are in the \s-1PATH\s0). Note, however, that the -actual \f(CW\*(C`PATH\*(C'\fR environment variable is \fInot\fR modified and is passed -unchanged to the program that \fBsudo\fR executes. -.PP -\&\fBsudo\fR will check the ownership of its time stamp directory -(\fI@timedir@\fR by default) and ignore the directory's contents if -it is not owned by root or if it is writable by a user other than -root. On systems that allow non-root users to give away files via -\&\fIchown\fR\|(2), if the time stamp directory is located in a directory -writable by anyone (e.g., \fI/tmp\fR), it is possible for a user to -create the time stamp directory before \fBsudo\fR is run. However, -because \fBsudo\fR checks the ownership and mode of the directory and -its contents, the only damage that can be done is to \*(L"hide\*(R" files -by putting them in the time stamp dir. This is unlikely to happen -since once the time stamp dir is owned by root and inaccessible by -any other user, the user placing files there would be unable to get -them back out. To get around this issue you can use a directory -that is not world-writable for the time stamps (\fI/var/adm/sudo\fR for -instance) or create \fI@timedir@\fR with the appropriate owner (root) -and permissions (0700) in the system startup files. -.PP -\&\fBsudo\fR will not honor time stamps set far in the future. -Timestamps with a date greater than current_time + 2 * \f(CW\*(C`TIMEOUT\*(C'\fR -will be ignored and sudo will log and complain. This is done to -keep a user from creating his/her own time stamp with a bogus -date on systems that allow users to give away files. -.PP -On systems where the boot time is available, \fBsudo\fR will also not -honor time stamps from before the machine booted. -.PP -Since time stamp files live in the file system, they can outlive a -user's login session. As a result, a user may be able to login, -run a command with \fBsudo\fR after authenticating, logout, login -again, and run \fBsudo\fR without authenticating so long as the time -stamp file's modification time is within \f(CW\*(C`@timeout@\*(C'\fR minutes (or -whatever the timeout is set to in \fIsudoers\fR). When the \fItty_tickets\fR -option is enabled in \fIsudoers\fR, the time stamp has per-tty granularity -but still may outlive the user's session. On Linux systems where -the devpts filesystem is used, Solaris systems with the devices -filesystem, as well as other systems that utilize a devfs filesystem -that monotonically increase the inode number of devices as they are -created (such as Mac \s-1OS\s0 X), \fBsudo\fR is able to determine when a -tty-based time stamp file is stale and will ignore it. Administrators -should not rely on this feature as it is not universally available. -.PP -Please note that \fBsudo\fR will normally only log the command it -explicitly runs. If a user runs a command such as \f(CW\*(C`sudo su\*(C'\fR or -\&\f(CW\*(C`sudo sh\*(C'\fR, subsequent commands run from that shell will \fInot\fR be -logged, nor will \fBsudo\fR's access control affect them. The same -is true for commands that offer shell escapes (including most -editors). Because of this, care must be taken when giving users -access to commands via \fBsudo\fR to verify that the command does not -inadvertently give the user an effective root shell. For more -information, please see the \f(CW\*(C`PREVENTING SHELL ESCAPES\*(C'\fR section in -\&\fIsudoers\fR\|(@mansectform@). -.SH "ENVIRONMENT" -.IX Header "ENVIRONMENT" -\&\fBsudo\fR utilizes the following environment variables: -.ie n .IP "\*(C`EDITOR\*(C'" 16 -.el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16 -.IX Item "EDITOR" -Default editor to use in \fB\-e\fR (sudoedit) mode if neither \f(CW\*(C`SUDO_EDITOR\*(C'\fR -nor \f(CW\*(C`VISUAL\*(C'\fR is set -.ie n .IP "\*(C`MAIL\*(C'" 16 -.el .IP "\f(CW\*(C`MAIL\*(C'\fR" 16 -.IX Item "MAIL" -In \fB\-i\fR mode or when \fIenv_reset\fR is enabled in \fIsudoers\fR, set -to the mail spool of the target user -.ie n .IP "\*(C`HOME\*(C'" 16 -.el .IP "\f(CW\*(C`HOME\*(C'\fR" 16 -.IX Item "HOME" -Set to the home directory of the target user if \fB\-i\fR or \fB\-H\fR are -specified, \fIenv_reset\fR or \fIalways_set_home\fR are set in \fIsudoers\fR, -or when the \fB\-s\fR option is specified and \fIset_home\fR is set in -\&\fIsudoers\fR -.ie n .IP "\*(C`PATH\*(C'" 16 -.el .IP "\f(CW\*(C`PATH\*(C'\fR" 16 -.IX Item "PATH" -Set to a sane value if the \fIsecure_path\fR sudoers option is set. -.ie n .IP "\*(C`SHELL\*(C'" 16 -.el .IP "\f(CW\*(C`SHELL\*(C'\fR" 16 -.IX Item "SHELL" -Used to determine shell to run with \f(CW\*(C`\-s\*(C'\fR option -.ie n .IP "\*(C`SUDO_ASKPASS\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_ASKPASS\*(C'\fR" 16 -.IX Item "SUDO_ASKPASS" -Specifies the path to a helper program used to read the password -if no terminal is available or if the \f(CW\*(C`\-A\*(C'\fR option is specified. -.ie n .IP "\*(C`SUDO_COMMAND\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_COMMAND\*(C'\fR" 16 -.IX Item "SUDO_COMMAND" -Set to the command run by sudo -.ie n .IP "\*(C`SUDO_EDITOR\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_EDITOR\*(C'\fR" 16 -.IX Item "SUDO_EDITOR" -Default editor to use in \fB\-e\fR (sudoedit) mode -.ie n .IP "\*(C`SUDO_GID\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_GID\*(C'\fR" 16 -.IX Item "SUDO_GID" -Set to the group \s-1ID\s0 of the user who invoked sudo -.ie n .IP "\*(C`SUDO_PROMPT\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_PROMPT\*(C'\fR" 16 -.IX Item "SUDO_PROMPT" -Used as the default password prompt -.ie n .IP "\*(C`SUDO_PS1\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_PS1\*(C'\fR" 16 -.IX Item "SUDO_PS1" -If set, \f(CW\*(C`PS1\*(C'\fR will be set to its value for the program being run -.ie n .IP "\*(C`SUDO_UID\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_UID\*(C'\fR" 16 -.IX Item "SUDO_UID" -Set to the user \s-1ID\s0 of the user who invoked sudo -.ie n .IP "\*(C`SUDO_USER\*(C'" 16 -.el .IP "\f(CW\*(C`SUDO_USER\*(C'\fR" 16 -.IX Item "SUDO_USER" -Set to the login of the user who invoked sudo -.ie n .IP "\*(C`USER\*(C'" 16 -.el .IP "\f(CW\*(C`USER\*(C'\fR" 16 -.IX Item "USER" -Set to the target user (root unless the \fB\-u\fR option is specified) -.ie n .IP "\*(C`VISUAL\*(C'" 16 -.el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16 -.IX Item "VISUAL" -Default editor to use in \fB\-e\fR (sudoedit) mode if \f(CW\*(C`SUDO_EDITOR\*(C'\fR -is not set -.SH "FILES" -.IX Header "FILES" -.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24 -.el .IP "\fI@sysconfdir@/sudoers\fR" 24 -.IX Item "@sysconfdir@/sudoers" -List of who can run what -.ie n .IP "\fI@timedir@\fR" 24 -.el .IP "\fI@timedir@\fR" 24 -.IX Item "@timedir@" -Directory containing time stamps -.IP "\fI/etc/environment\fR" 24 -.IX Item "/etc/environment" -Initial environment for \fB\-i\fR mode on Linux and \s-1AIX\s0 -.SH "EXAMPLES" -.IX Header "EXAMPLES" -Note: the following examples assume suitable \fIsudoers\fR\|(@mansectform@) entries. -.PP -To get a file listing of an unreadable directory: -.PP -.Vb 1 -\& $ sudo ls /usr/local/protected -.Ve -.PP -To list the home directory of user yaz on a machine where the -file system holding ~yaz is not exported as root: -.PP -.Vb 1 -\& $ sudo \-u yaz ls ~yaz -.Ve -.PP -To edit the \fIindex.html\fR file as user www: -.PP -.Vb 1 -\& $ sudo \-u www vi ~www/htdocs/index.html -.Ve -.PP -To view system logs only accessible to root and users in the adm group: -.PP -.Vb 1 -\& $ sudo \-g adm view /var/log/syslog -.Ve -.PP -To run an editor as jim with a different primary group: -.PP -.Vb 1 -\& $ sudo \-u jim \-g audio vi ~jim/sound.txt -.Ve -.PP -To shutdown a machine: -.PP -.Vb 1 -\& $ sudo shutdown \-r +15 "quick reboot" -.Ve -.PP -To make a usage listing of the directories in the /home -partition. Note that this runs the commands in a sub-shell -to make the \f(CW\*(C`cd\*(C'\fR and file redirection work. -.PP -.Vb 1 -\& $ sudo sh \-c "cd /home ; du \-s * | sort \-rn > USAGE" -.Ve -.SH "SEE ALSO" -.IX Header "SEE ALSO" -\&\fIgrep\fR\|(1), \fIsu\fR\|(1), \fIstat\fR\|(2), -.if \n(LC \&\fIlogin_cap\fR\|(3), -\&\fIpasswd\fR\|(@mansectform@), \fIsudoers\fR\|(5), \fIvisudo\fR\|(@mansectsu@) -.SH "AUTHORS" -.IX Header "AUTHORS" -Many people have worked on \fBsudo\fR over the years; this -version consists of code written primarily by: -.PP -.Vb 1 -\& Todd C. Miller -.Ve -.PP -See the \s-1HISTORY\s0 file in the \fBsudo\fR distribution or visit -http://www.sudo.ws/sudo/history.html for a short history -of \fBsudo\fR. -.SH "CAVEATS" -.IX Header "CAVEATS" -There is no easy way to prevent a user from gaining a root shell -if that user is allowed to run arbitrary commands via \fBsudo\fR. -Also, many programs (such as editors) allow the user to run commands -via shell escapes, thus avoiding \fBsudo\fR's checks. However, on -most systems it is possible to prevent shell escapes with \fBsudo\fR's -\&\fInoexec\fR functionality. See the \fIsudoers\fR\|(@mansectform@) manual -for details. -.PP -It is not meaningful to run the \f(CW\*(C`cd\*(C'\fR command directly via sudo, e.g., -.PP -.Vb 1 -\& $ sudo cd /usr/local/protected -.Ve -.PP -since when the command exits the parent process (your shell) will -still be the same. Please see the \s-1EXAMPLES\s0 section for more information. -.PP -If users have sudo \f(CW\*(C`ALL\*(C'\fR there is nothing to prevent them from -creating their own program that gives them a root shell regardless -of any '!' elements in the user specification. -.PP -Running shell scripts via \fBsudo\fR can expose the same kernel bugs that -make setuid shell scripts unsafe on some operating systems (if your \s-1OS\s0 -has a /dev/fd/ directory, setuid shell scripts are generally safe). -.SH "BUGS" -.IX Header "BUGS" -If you feel you have found a bug in \fBsudo\fR, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ -.SH "SUPPORT" -.IX Header "SUPPORT" -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or -search the archives. -.SH "DISCLAIMER" -.IX Header "DISCLAIMER" -\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 -file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudo.man.pl b/sudo.man.pl deleted file mode 100644 index e8e6125..0000000 --- a/sudo.man.pl +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/perl -p - -BEGIN { - %tags = ( 'a', 'BA', 'c', 'LC', 'r', 'SL', 't', 'SL'); - $cond = -1; -} - -# Initialize the numeric register we use for conditionals -if ($cond == -1) { - $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.nr PT \@password_timeout\@\n.\\\"\n$_"; - $cond = 0; -} - -# Add conditionals -if (/^\.IP.*-([acrt])/) { - $_ = ".if \\n($tags{$1} \\{\\\n$_"; - $cond = 1; -} elsif ($cond && /^\.(Sh|SS|IP|PP)/) { - $_ = "\\}\n$_"; - $cond = 0; -} - -if (/-a.*auth_type/) { - $_ = ".if \\n($tags{'a'} $_"; -} elsif (/(-c.*class.*\||login_cap)/) { - $_ = ".if \\n($tags{'c'} $_"; -} elsif (/-r.*role.*-t.*type/) { - $_ = ".if \\n($tags{'r'} $_"; -} - -# Fix up broken pod2man formatting of F<@foo@/bar> -s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g; - -# Try to deal sensibly with password_timeout being set to 0 by default -s/([^ ]*\@password_timeout\@[^ ]* minutes.$)/\n.ie \\n(PT $1\n.el unlimited./; diff --git a/sudo.pod b/sudo.pod deleted file mode 100644 index 33bcb6a..0000000 --- a/sudo.pod +++ /dev/null @@ -1,701 +0,0 @@ -Copyright (c) 1994-1996, 1998-2005, 2007-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. -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Sponsored in part by the Defense Advanced Research Projects -Agency (DARPA) and Air Force Research Laboratory, Air Force -Materiel Command, USAF, under agreement number F39502-99-1-0512. - -=pod - -=head1 NAME - -sudo, sudoedit - execute a command as another user - -=head1 SYNOPSIS - -B B<-h> | B<-K> | B<-k> | B<-L> | B<-V> - -B B<-v> [B<-AknS>] -S<[B<-a> I]> -S<[B<-g> I|I<#gid>]> S<[B<-p> I]> -S<[B<-u> I|I<#uid>]> - -B B<-l[l]> [B<-AknS>] -S<[B<-a> I]> -S<[B<-g> I|I<#gid>]> S<[B<-p> I]> -S<[B<-U> I]> S<[B<-u> I|I<#uid>]> [I] - -B [B<-AbEHnPS>] -S<[B<-a> I]> -S<[B<-C> I]> -S<[B<-c> I|I<->]> -S<[B<-g> I|I<#gid>]> S<[B<-p> I]> -S<[B<-r> I]> S<[B<-t> I]> -S<[B<-u> I|I<#uid>]> -S<[B=I]> S<[B<-i> | B<-s>]> [I] - -B [B<-AnS>] -S<[B<-a> I]> -S<[B<-C> I]> -S<[B<-c> I|I<->]> -S<[B<-g> I|I<#gid>]> S<[B<-p> I]> -S<[B<-u> I|I<#uid>]> file ... - -=head1 DESCRIPTION - -B allows a permitted user to execute a I as the -superuser or another user, as specified in the I file. -The real and effective uid and gid are set to match those of the -target user as specified in the passwd file and the group vector -is initialized based on the group file (unless the B<-P> option was -specified). If the invoking user is root or if the target user is -the same as the invoking user, no password is required. Otherwise, -B requires that users authenticate themselves with a password -by default (NOTE: in the default configuration this is the user's -password, not the root password). Once a user has been authenticated, -a time stamp is updated and the user may then use sudo without a -password for a short period of time (C<@timeout@> minutes unless -overridden in I). - -When invoked as B, the B<-e> option (described below), -is implied. - -B determines who is an authorized user by consulting the file -F<@sysconfdir@/sudoers>. By running B with the B<-v> option, -a user can update the time stamp without running a I. If -a password is required, B will exit if the user's password -is not entered within a configurable time limit. The default -password prompt timeout is C<@password_timeout@> minutes. - -If a user who is not listed in the I file tries to run a -command via B, mail is sent to the proper authorities, as -defined at configure time or in the I file (defaults to -C<@mailto@>). Note that the mail will not be sent if an unauthorized -user tries to run sudo with the B<-l> or B<-v> option. This allows -users to determine for themselves whether or not they are allowed -to use B. - -If B is run by root and the C environment variable -is set, B will use this value to determine who the actual -user is. This can be used by a user to log commands through sudo -even when a root shell has been invoked. It also allows the B<-e> -option to remain useful even when being run via a sudo-run script or -program. Note however, that the sudoers lookup is still done for -root, not the user specified by C. - -B can log both successful and unsuccessful attempts (as well -as errors) to syslog(3), a log file, or both. By default B -will log via syslog(3) but this is changeable at configure time -or via the I file. - -=head1 OPTIONS - -B accepts the following command line options: - -=over 12 - -=item -A - -Normally, if B requires a password, it will read it from the -current terminal. If the B<-A> (I) option is specified, -a (possibly graphical) helper program is executed to read the -user's password and output the password to the standard output. If -the C environment variable is set, it specifies the -path to the helper program. Otherwise, the value specified by the -I option in L is used. - -=item -a I - -The B<-a> (I) option causes B to use the -specified authentication type when validating the user, as allowed -by F. The system administrator may specify a list -of sudo-specific authentication methods by adding an "auth-sudo" -entry in F. This option is only available on systems -that support BSD authentication. - -=item -b - -The B<-b> (I) option tells B to run the given -command in the background. Note that if you use the B<-b> -option you cannot use shell job control to manipulate the process. - -=item -C I - -Normally, B will close all open file descriptors other than -standard input, standard output and standard error. The B<-C> -(I) option allows the user to specify a starting point -above the standard error (file descriptor three). Values less than -three are not permitted. This option is only available if the -administrator has enabled the I option in -L. - -=item -c I - -The B<-c> (I) option causes B to run the specified command -with resources limited by the specified login class. The I -argument can be either a class name as defined in F, -or a single '-' character. Specifying a I of C<-> indicates -that the command should be run restricted by the default login -capabilities for the user the command is run as. If the I -argument specifies an existing user class, the command must be run -as root, or the B command must be run from a shell that is already -root. This option is only available on systems with BSD login classes. - -=item -E - -The B<-E> (I I) option will override the -I option in L). It is only -available when either the matching command has the C tag -or the I option is set in L. - -=item -e - -The B<-e> (I) option indicates that, instead of running -a command, the user wishes to edit one or more files. In lieu -of a command, the string "sudoedit" is used when consulting -the I file. If the user is authorized by I -the following steps are taken: - -=over 4 - -=item 1. - -Temporary copies are made of the files to be edited with the owner -set to the invoking user. - -=item 2. - -The editor specified by the C, C or C -environment variables is run to edit the temporary files. If none -of C, C or C are set, the first program -listed in the I I variable is used. - -=item 3. - -If they have been modified, the temporary files are copied back to -their original location and the temporary versions are removed. - -=back - -If the specified file does not exist, it will be created. Note -that unlike most commands run by B, the editor is run with -the invoking user's environment unmodified. If, for some reason, -B is unable to update a file with its edited version, the -user will receive a warning and the edited copy will remain in a -temporary file. - -=item -g I - -Normally, B sets the primary group to the one specified by -the passwd database for the user the command is being run as (by -default, root). The B<-g> (I) option causes B to run -the specified command with the primary group set to I. To -specify a I instead of a I, use I<#gid>. When -running commands as a I, many shells require that the '#' be -escaped with a backslash ('\'). If no B<-u> option is specified, -the command will be run as the invoking user (not root). In either -case, the primary group will be set to I. - -=item -H - -The B<-H> (I) option sets the C environment variable -to the homedir of the target user (root by default) as specified -in passwd(5). The default handling of the C environment -variable depends on L settings. By default, B -will set C if I or I are set, or -if I is set and the B<-s> option is specified on the -command line. - -=item -h - -The B<-h> (I) option causes B to print a usage message and exit. - -=item -i [command] - -The B<-i> (I) option runs the shell specified -in the L entry of the target user as a login shell. This -means that login-specific resource files such as C<.profile> or -C<.login> will be read by the shell. If a command is specified, -it is passed to the shell for execution. Otherwise, an interactive -shell is executed. B attempts to change to that user's home -directory before running the shell. It also initializes the -environment, leaving I and I unchanged, setting -I, I, I, I, I, and I, as well as -the contents of F on Linux and AIX systems. -All other environment variables are removed. - -=item -K - -The B<-K> (sure I) option is like B<-k> except that it removes -the user's time stamp entirely and may not be used in conjunction -with a command or other option. This option does not require a -password. - -=item -k - -When used by itself, the B<-k> (I) option to B invalidates -the user's time stamp by setting the time on it to the Epoch. The -next time B is run a password will be required. This option -does not require a password and was added to allow a user to revoke -B permissions from a .logout file. - -When used in conjunction with a command or an option that may require -a password, the B<-k> option will cause B to ignore the user's -time stamp file. As a result, B will prompt for a password -(if one is required by I) and will not update the user's -time stamp file. - -=item -L - -The B<-L> (I defaults) option will list the parameters that -may be set in a I line along with a short description for -each. This option will be removed from a future version of B. - -=item -l[l] [I] - -If no I is specified, the B<-l> (I) option will list -the allowed (and forbidden) commands for the invoking user (or the -user specified by the B<-U> option) on the current host. If a -I is specified and is permitted by I, the -fully-qualified path to the command is displayed along with any -command line arguments. If I is specified but not allowed, -B will exit with a status value of 1. If the B<-l> option is -specified with an B argument (i.e. B<-ll>), or if B<-l> -is specified multiple times, a longer list format is used. - -=item -n - -The B<-n> (I) option prevents B from prompting -the user for a password. If a password is required for the command -to run, B will display an error messages and exit. - -=item -P - -The B<-P> (I I) option causes B to -preserve the invoking user's group vector unaltered. By default, -B will initialize the group vector to the list of groups the -target user is in. The real and effective group IDs, however, are -still set to match the target user. - -=item -p I - -The B<-p> (I) option allows you to override the default -password prompt and use a custom one. The following percent (`C<%>') -escapes are supported: - -=over 4 - -=item C<%H> - -expanded to the local host name including the domain name -(on if the machine's host name is fully qualified or the I -I option is set) - -=item C<%h> - -expanded to the local host name without the domain name - -=item C<%p> - -expanded to the user whose password is being asked for (respects the -I, I and I flags in I) - -=item C<%U> - -expanded to the login name of the user the command will -be run as (defaults to root) - -=item C<%u> - -expanded to the invoking user's login name - -=item C<%%> - -two consecutive C<%> characters are collapsed into a single C<%> character - -=back - -The prompt specified by the B<-p> option will override the system -password prompt on systems that support PAM unless the -I flag is disabled in I. - -=item -r I - -The B<-r> (I) option causes the new (SELinux) security context to -have the role specified by I. - -=item -S - -The B<-S> (I) option causes B to read the password from -the standard input instead of the terminal device. The password must -be followed by a newline character. - -=item -s [command] - -The B<-s> (I) option runs the shell specified by the I -environment variable if it is set or the shell as specified in -L. If a command is specified, it is passed to the shell -for execution. Otherwise, an interactive shell is executed. - -=item -t I - -The B<-t> (I) option causes the new (SELinux) security context to -have the type specified by I. If no type is specified, the default -type is derived from the specified role. - -=item -U I - -The B<-U> (I) option is used in conjunction with the B<-l> -option to specify the user whose privileges should be listed. Only -root or a user with B C on the current host may use this -option. - -=item -u I - -The B<-u> (I) option causes B to run the specified -command as a user other than I. To specify a I instead -of a I, use I<#uid>. When running commands as a I, -many shells require that the '#' be escaped with a backslash ('\'). -Note that if the I Defaults option is set (see L) -it is not possible to run commands with a uid not listed in the -password database. - -=item -V - -The B<-V> (I) option causes B to print the version -number and exit. If the invoking user is already root the B<-V> -option will print out a list of the defaults B was compiled -with as well as the machine's local network addresses. - -=item -v - -If given the B<-v> (I) option, B will update the -user's time stamp, prompting for the user's password if necessary. -This extends the B timeout for another C<@timeout@> minutes -(or whatever the timeout is set to in I) but does not run -a command. - -=item -- - -The B<--> option indicates that B should stop processing command -line arguments. - -=back - -Environment variables to be set for the command may also be passed -on the command line in the form of B=I, e.g. -B=I. Variables passed on the -command line are subject to the same restrictions as normal environment -variables with one important exception. If the I option -is set in I, the command to be run has the C tag -set or the command matched is C, the user may set variables -that would overwise be forbidden. See L for more information. - -=head1 RETURN VALUES - -Upon successful execution of a program, the exit status from B -will simply be the exit status of the program that was executed. - -Otherwise, B quits with an exit value of 1 if there is a -configuration/permission problem or if B cannot execute the -given command. In the latter case the error string is printed to -stderr. If B cannot L one or more entries in the user's -C an error is printed on stderr. (If the directory does not -exist or if it is not really a directory, the entry is ignored and -no error is printed.) This should not happen under normal -circumstances. The most common reason for L to return -"permission denied" is if you are running an automounter and one -of the directories in your C is on a machine that is currently -unreachable. - -=head1 SECURITY NOTES - -B tries to be safe when executing external commands. - -There are two distinct ways to deal with environment variables. -By default, the I I option is enabled. -This causes commands to be executed with a minimal environment -containing C, C, C, C, C, C -and C in addition to variables from the invoking process -permitted by the I and I I options. -There is effectively a whitelist for environment variables. - -If, however, the I option is disabled in I, any -variables not explicitly denied by the I and I -options are inherited from the invoking process. In this case, -I and I behave like a blacklist. Since it -is not possible to blacklist all potentially dangerous environment -variables, use of the default I behavior is encouraged. - -In all cases, environment variables with a value beginning with -C<()> are removed as they could be interpreted as B functions. -The list of environment variables that B allows or denies is -contained in the output of C when run as root. - -Note that the dynamic linker on most operating systems will remove -variables that can control dynamic linking from the environment of -setuid executables, including B. Depending on the operating -system this may include C<_RLD*>, C, C, C, -C, C, and others. These type of variables are -removed from the environment before B even begins execution -and, as such, it is not possible for B to preserve them. - -To prevent command spoofing, B checks "." and "" (both denoting -current directory) last when searching for a command in the user's -PATH (if one or both are in the PATH). Note, however, that the -actual C environment variable is I modified and is passed -unchanged to the program that B executes. - -B will check the ownership of its time stamp directory -(F<@timedir@> by default) and ignore the directory's contents if -it is not owned by root or if it is writable by a user other than -root. On systems that allow non-root users to give away files via -L, if the time stamp directory is located in a directory -writable by anyone (e.g., F), it is possible for a user to -create the time stamp directory before B is run. However, -because B checks the ownership and mode of the directory and -its contents, the only damage that can be done is to "hide" files -by putting them in the time stamp dir. This is unlikely to happen -since once the time stamp dir is owned by root and inaccessible by -any other user, the user placing files there would be unable to get -them back out. To get around this issue you can use a directory -that is not world-writable for the time stamps (F for -instance) or create F<@timedir@> with the appropriate owner (root) -and permissions (0700) in the system startup files. - -B will not honor time stamps set far in the future. -Timestamps with a date greater than current_time + 2 * C -will be ignored and sudo will log and complain. This is done to -keep a user from creating his/her own time stamp with a bogus -date on systems that allow users to give away files. - -On systems where the boot time is available, B will also not -honor time stamps from before the machine booted. - -Since time stamp files live in the file system, they can outlive a -user's login session. As a result, a user may be able to login, -run a command with B after authenticating, logout, login -again, and run B without authenticating so long as the time -stamp file's modification time is within C<@timeout@> minutes (or -whatever the timeout is set to in I). When the I -option is enabled in I, the time stamp has per-tty granularity -but still may outlive the user's session. On Linux systems where -the devpts filesystem is used, Solaris systems with the devices -filesystem, as well as other systems that utilize a devfs filesystem -that monotonically increase the inode number of devices as they are -created (such as Mac OS X), B is able to determine when a -tty-based time stamp file is stale and will ignore it. Administrators -should not rely on this feature as it is not universally available. - -Please note that B will normally only log the command it -explicitly runs. If a user runs a command such as C or -C, subsequent commands run from that shell will I be -logged, nor will B's access control affect them. The same -is true for commands that offer shell escapes (including most -editors). Because of this, care must be taken when giving users -access to commands via B to verify that the command does not -inadvertently give the user an effective root shell. For more -information, please see the C section in -L. - -=head1 ENVIRONMENT - -B utilizes the following environment variables: - -=over 16 - -=item C - -Default editor to use in B<-e> (sudoedit) mode if neither C -nor C is set - -=item C - -In B<-i> mode or when I is enabled in I, set -to the mail spool of the target user - -=item C - -Set to the home directory of the target user if B<-i> or B<-H> are -specified, I or I are set in I, -or when the B<-s> option is specified and I is set in -I - -=item C - -Set to a sane value if the I sudoers option is set. - -=item C - -Used to determine shell to run with C<-s> option - -=item C - -Specifies the path to a helper program used to read the password -if no terminal is available or if the C<-A> option is specified. - -=item C - -Set to the command run by sudo - -=item C - -Default editor to use in B<-e> (sudoedit) mode - -=item C - -Set to the group ID of the user who invoked sudo - -=item C - -Used as the default password prompt - -=item C - -If set, C will be set to its value for the program being run - -=item C - -Set to the user ID of the user who invoked sudo - -=item C - -Set to the login of the user who invoked sudo - -=item C - -Set to the target user (root unless the B<-u> option is specified) - -=item C - -Default editor to use in B<-e> (sudoedit) mode if C -is not set - -=back - -=head1 FILES - -=over 24 - -=item F<@sysconfdir@/sudoers> - -List of who can run what - -=item F<@timedir@> - -Directory containing time stamps - -=item F - -Initial environment for B<-i> mode on Linux and AIX - -=back - -=head1 EXAMPLES - -Note: the following examples assume suitable L entries. - -To get a file listing of an unreadable directory: - - $ sudo ls /usr/local/protected - -To list the home directory of user yaz on a machine where the -file system holding ~yaz is not exported as root: - - $ sudo -u yaz ls ~yaz - -To edit the F file as user www: - - $ sudo -u www vi ~www/htdocs/index.html - -To view system logs only accessible to root and users in the adm group: - - $ sudo -g adm view /var/log/syslog - -To run an editor as jim with a different primary group: - - $ sudo -u jim -g audio vi ~jim/sound.txt - -To shutdown a machine: - - $ sudo shutdown -r +15 "quick reboot" - -To make a usage listing of the directories in the /home -partition. Note that this runs the commands in a sub-shell -to make the C and file redirection work. - - $ sudo sh -c "cd /home ; du -s * | sort -rn > USAGE" - -=head1 SEE ALSO - -L, L, L, -L, -L, L, L - -=head1 AUTHORS - -Many people have worked on B over the years; this -version consists of code written primarily by: - - Todd C. Miller - -See the HISTORY file in the B distribution or visit -http://www.sudo.ws/sudo/history.html for a short history -of B. - -=head1 CAVEATS - -There is no easy way to prevent a user from gaining a root shell -if that user is allowed to run arbitrary commands via B. -Also, many programs (such as editors) allow the user to run commands -via shell escapes, thus avoiding B's checks. However, on -most systems it is possible to prevent shell escapes with B's -I functionality. See the L manual -for details. - -It is not meaningful to run the C command directly via sudo, e.g., - - $ sudo cd /usr/local/protected - -since when the command exits the parent process (your shell) will -still be the same. Please see the EXAMPLES section for more information. - -If users have sudo C there is nothing to prevent them from -creating their own program that gives them a root shell regardless -of any '!' elements in the user specification. - -Running shell scripts via B can expose the same kernel bugs that -make setuid shell scripts unsafe on some operating systems (if your OS -has a /dev/fd/ directory, setuid shell scripts are generally safe). - -=head1 BUGS - -If you feel you have found a bug in B, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ - -=head1 SUPPORT - -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or -search the archives. - -=head1 DISCLAIMER - -B is provided ``AS IS'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the LICENSE -file distributed with B or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudo.pp b/sudo.pp index 1f203d8..5167826 100644 --- a/sudo.pp +++ b/sudo.pp @@ -6,32 +6,48 @@ name="sudo" pp_kit_package="sudo" fi - summary="Provide limited super-user priveleges to specific users" + summary="Provide limited super-user privileges to specific users" description="Sudo is a program designed to allow a sysadmin to give \ 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-2012 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 @@ -58,14 +74,17 @@ still allow people to get their work done." # Note that the order must match that of sudoers. case "$pp_rpm_distro" in centos*|rhel*) + chmod u+w ${pp_destdir}${sudoersdir}/sudoers /bin/ed - ${pp_destdir}${sudoersdir}/sudoers <<-'EOF' /Locale settings/+1,s/^# // /Desktop path settings/+1,s/^# // w q EOF + chmod u-w ${pp_destdir}${sudoersdir}/sudoers ;; sles*) + chmod u+w ${pp_destdir}${sudoersdir}/sudoers /bin/ed - ${pp_destdir}${sudoersdir}/sudoers <<-'EOF' /Locale settings/+1,s/^# // /ConsoleKit session/+1,s/^# // @@ -74,6 +93,7 @@ still allow people to get their work done." w q EOF + chmod u-w ${pp_destdir}${sudoersdir}/sudoers ;; esac @@ -136,10 +156,12 @@ 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. + chmod u+w ${pp_destdir}${sudoersdir}/sudoers /bin/ed - ${pp_destdir}${sudoersdir}/sudoers <<-'EOF' /Locale settings/+1,s/^# // /X11 resource/+1,s/^# // @@ -147,6 +169,7 @@ still allow people to get their work done." w q EOF + chmod u-w ${pp_destdir}${sudoersdir}/sudoers mkdir -p ${pp_destdir}/etc/pam.d cat > ${pp_destdir}/etc/pam.d/sudo <<-EOF #%PAM-1.0 @@ -157,21 +180,44 @@ still allow people to get their work done." session required pam_permit.so session required pam_limits.so EOF +%endif -%set [aix] - summary="Configurable super-user privileges" +%if [macos] + pp_macos_pkg_type=flat + pp_macos_bundle_id=ws.sudo.pkg.sudo + pp_macos_pkg_license=doc/LICENSE + pp_macos_pkg_readme=${pp_wrkdir}/ReadMe.txt + perl -pe 'last if (/^What/i && $seen++)' NEWS > ${pp_wrkdir}/ReadMe.txt +%endif + + # OS-level directories that should generally exist but might not. + extradirs=`echo ${pp_destdir}/${mandir}/[mc]* | sed "s#${pp_destdir}/##g"` + extradirs="$extradirs `dirname $docdir` `dirname $timedir`" + test -d ${pp_destdir}/etc/pam.d && extradirs="${extradirs} /etc/pam.d" + for dir in $bindir $sbindir $libexecdir $includedir $extradirs; do + while test "$dir" != "/"; do + osdirs="${osdirs}${osdirs+ }$dir/" + dir=`dirname $dir` + done + done + osdirs=`echo $osdirs | tr " " "\n" | sort -u` %files - $bindir/sudo 4111 root: - $bindir/sudoedit 4111 root: - $sbindir/visudo 0111 - $bindir/sudoreplay 0111 - $libexecdir/* + $osdirs - + $bindir/sudo 4111 root: + $bindir/sudoedit 4111 root: + $sbindir/visudo 0111 + $bindir/sudoreplay 0111 + $includedir/sudo_plugin.h 0444 + $libexecdir/* 0755 optional $sudoersdir/sudoers.d/ 0750 $sudoers_uid:$sudoers_gid $timedir/ 0700 root: - $docdir/ - $docdir/* - /etc/pam.d/* volatile,optional + $docdir/ 0755 + $docdir/sudoers2ldif 0555 optional,ignore-others + $docdir/* 0444 + $localedir/ - optional + $localedir/** 0444 optional + /etc/pam.d/* 0444 volatile,optional %if [rpm,deb] $sudoersdir/sudoers $sudoers_mode $sudoers_uid:$sudoers_gid volatile %else @@ -188,9 +234,16 @@ still allow people to get their work done." %post [!rpm,deb] # Don't overwrite an existing sudoers file +%if [solaris] + sudoersdir=${PKG_INSTALL_ROOT}%{sudoersdir} +%else sudoersdir=%{sudoersdir} +%endif if test ! -r $sudoersdir/sudoers; then - cp -p $sudoersdir/sudoers.dist $sudoersdir/sudoers + cp $sudoersdir/sudoers.dist $sudoersdir/sudoers + chmod %{sudoers_mode} $sudoersdir/sudoers + chown %{sudoers_uid} $sudoersdir/sudoers + chgrp %{sudoers_gid} $sudoersdir/sudoers fi %post [deb] diff --git a/sudo_edit.c b/sudo_edit.c deleted file mode 100644 index f8666d9..0000000 --- a/sudo_edit.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (c) 2004-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. - */ - -#include - -#if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID) - -#include -#include -#include -#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 */ -#include -#include -#include -#include -#include -#include -#if TIME_WITH_SYS_TIME -# include -#endif - -#include "sudo.h" - -static char *find_editor __P((int *argc_out, char ***argv_out)); - -extern char **NewArgv; /* XXX */ - -/* - * Wrapper to allow users to edit privileged files with their own uid. - */ -int -sudo_edit(argc, argv, envp) - int argc; - char *argv[]; - char *envp[]; -{ - ssize_t nread, nwritten; - const char *tmpdir; - char *cp, *suff, **nargv, *editor, **files; - char **editor_argv = NULL; - char buf[BUFSIZ]; - int rc, i, j, ac, ofd, tfd, nargc, rval, nfiles, tmplen; - int editor_argc = 0; - struct stat sb; - struct timeval tv, tv1, tv2; - struct tempfile { - char *tfile; - char *ofile; - struct timeval omtim; - off_t osize; - } *tf; - - /* Determine user's editor. */ - editor = find_editor(&editor_argc, &editor_argv); - if (editor == NULL) - return 1; - - /* - * Find our temporary directory, one of /var/tmp, /usr/tmp, or /tmp - */ - if (stat(_PATH_VARTMP, &sb) == 0 && S_ISDIR(sb.st_mode)) - tmpdir = _PATH_VARTMP; -#ifdef _PATH_USRTMP - else if (stat(_PATH_USRTMP, &sb) == 0 && S_ISDIR(sb.st_mode)) - tmpdir = _PATH_USRTMP; -#endif - else - tmpdir = _PATH_TMP; - tmplen = strlen(tmpdir); - while (tmplen > 0 && tmpdir[tmplen - 1] == '/') - tmplen--; - - /* - * For each file specified by the user, make a temporary version - * and copy the contents of the original to it. - */ - files = argv + 1; - nfiles = argc - 1; - tf = emalloc2(nfiles, sizeof(*tf)); - zero_bytes(tf, nfiles * sizeof(*tf)); - for (i = 0, j = 0; i < nfiles; i++) { - rc = -1; - set_perms(PERM_RUNAS); - if ((ofd = open(files[i], O_RDONLY, 0644)) != -1 || errno == ENOENT) { - if (ofd == -1) { - zero_bytes(&sb, sizeof(sb)); /* new file */ - rc = 0; - } else { -#ifdef HAVE_FSTAT - rc = fstat(ofd, &sb); -#else - rc = stat(tf[j].ofile, &sb); -#endif - } - } - set_perms(PERM_ROOT); - if (rc || (ofd != -1 && !S_ISREG(sb.st_mode))) { - if (rc) - warning("%s", files[i]); - else - warningx("%s: not a regular file", files[i]); - if (ofd != -1) - close(ofd); - continue; - } - tf[j].ofile = files[i]; - tf[j].osize = sb.st_size; - mtim_get(&sb, &tf[j].omtim); - if ((cp = strrchr(tf[j].ofile, '/')) != NULL) - cp++; - else - cp = tf[j].ofile; - suff = strrchr(cp, '.'); - if (suff != NULL) { - easprintf(&tf[j].tfile, "%.*s/%.*sXXXXXXXX%s", tmplen, tmpdir, (int)(size_t)(suff - cp), cp, suff); - } else { - easprintf(&tf[j].tfile, "%.*s/%s.XXXXXXXX", tmplen, tmpdir, cp); - } - set_perms(PERM_USER); - tfd = mkstemps(tf[j].tfile, suff ? strlen(suff) : 0); - set_perms(PERM_ROOT); - if (tfd == -1) { - warning("mkstemps"); - goto cleanup; - } - if (ofd != -1) { - while ((nread = read(ofd, buf, sizeof(buf))) != 0) { - if ((nwritten = write(tfd, buf, nread)) != nread) { - if (nwritten == -1) - warning("%s", tf[j].tfile); - else - warningx("%s: short write", tf[j].tfile); - goto cleanup; - } - } - close(ofd); - } - /* - * We always update the stashed mtime because the time - * resolution of the filesystem the temporary file is on may - * not match that of the filesystem where the file to be edited - * resides. It is OK if touch() fails since we only use the info - * to determine whether or not a file has been modified. - */ - (void) touch(tfd, NULL, &tf[j].omtim); -#ifdef HAVE_FSTAT - rc = fstat(tfd, &sb); -#else - rc = stat(tf[j].tfile, &sb); -#endif - if (!rc) - mtim_get(&sb, &tf[j].omtim); - close(tfd); - j++; - } - if ((nfiles = j) == 0) - return 1; /* no files readable, you lose */ - - /* - * Allocate space for the new argument vector and fill it in. - * We concatenate the editor with its args and the file list - * to create a new argv. - * We allocate an extra slot to be used if execve() fails. - */ - nargc = editor_argc + nfiles; - nargv = (char **) emalloc2(1 + nargc + 1, sizeof(char *)); - nargv++; - for (ac = 0; ac < editor_argc; ac++) - nargv[ac] = editor_argv[ac]; - for (i = 0; i < nfiles && ac < nargc; ) - nargv[ac++] = tf[i++].tfile; - nargv[ac] = NULL; - - /* - * Run the editor with the invoking user's creds, - * keeping track of the time spent in the editor. - */ - gettime(&tv1); - rval = run_command(editor, nargv, envp, user_uid, TRUE); - gettime(&tv2); - - /* Copy contents of temp files to real ones */ - for (i = 0; i < nfiles; i++) { - rc = -1; - set_perms(PERM_USER); - if ((tfd = open(tf[i].tfile, O_RDONLY, 0644)) != -1) { -#ifdef HAVE_FSTAT - rc = fstat(tfd, &sb); -#else - rc = stat(tf[i].tfile, &sb); -#endif - } - set_perms(PERM_ROOT); - if (rc || !S_ISREG(sb.st_mode)) { - if (rc) - warning("%s", tf[i].tfile); - else - warningx("%s: not a regular file", tf[i].tfile); - warningx("%s left unmodified", tf[i].ofile); - if (tfd != -1) - close(tfd); - continue; - } - mtim_get(&sb, &tv); - if (tf[i].osize == sb.st_size && timevalcmp(&tf[i].omtim, &tv, ==)) { - /* - * If mtime and size match but the user spent no measurable - * time in the editor we can't tell if the file was changed. - */ - timevalsub(&tv1, &tv2); - if (timevalisset(&tv2)) { - warningx("%s unchanged", tf[i].ofile); - unlink(tf[i].tfile); - close(tfd); - continue; - } - } - set_perms(PERM_RUNAS); - ofd = open(tf[i].ofile, O_WRONLY|O_TRUNC|O_CREAT, 0644); - set_perms(PERM_ROOT); - if (ofd == -1) { - warning("unable to write to %s", tf[i].ofile); - warningx("contents of edit session left in %s", tf[i].tfile); - close(tfd); - continue; - } - while ((nread = read(tfd, buf, sizeof(buf))) > 0) { - if ((nwritten = write(ofd, buf, nread)) != nread) { - if (nwritten == -1) - warning("%s", tf[i].ofile); - else - warningx("%s: short write", tf[i].ofile); - break; - } - } - if (nread == 0) { - /* success, got EOF */ - unlink(tf[i].tfile); - } else if (nread < 0) { - warning("unable to read temporary file"); - warningx("contents of edit session left in %s", tf[i].tfile); - } else { - warning("unable to write to %s", tf[i].ofile); - warningx("contents of edit session left in %s", tf[i].tfile); - } - close(ofd); - } - - return rval; -cleanup: - /* Clean up temp files and return. */ - for (i = 0; i < nfiles; i++) { - if (tf[i].tfile != NULL) - unlink(tf[i].tfile); - } - return 1; -} - -static char * -resolve_editor(editor, argc_out, argv_out) - char *editor; - int *argc_out; - char ***argv_out; -{ - char *cp, **nargv, *editor_path = NULL; - int ac, nargc, wasblank; - - editor = estrdup(editor); /* becomes part of argv_out */ - - /* - * Split editor into an argument vector; editor is reused (do not free). - * The EDITOR and VISUAL environment variables may contain command - * line args so look for those and alloc space for them too. - */ - nargc = 1; - for (wasblank = FALSE, cp = editor; *cp != '\0'; cp++) { - if (isblank((unsigned char) *cp)) - wasblank = TRUE; - else if (wasblank) { - wasblank = FALSE; - nargc++; - } - } - /* If we can't find the editor in the user's PATH, give up. */ - cp = strtok(editor, " \t"); - if (cp == NULL || - find_path(cp, &editor_path, NULL, getenv("PATH"), 0) != FOUND) { - efree(editor); - return NULL; - } - nargv = (char **) emalloc2(nargc + 1, sizeof(char *)); - for (ac = 0; cp != NULL && ac < nargc; ac++) { - nargv[ac] = cp; - cp = strtok(NULL, " \t"); - } - nargv[ac] = NULL; - - *argc_out = nargc; - *argv_out = nargv; - return editor_path; -} - -/* - * Determine which editor to use. We don't need to worry about restricting - * this to a "safe" editor since it runs with the uid of the invoking user, - * not the runas (privileged) user. - * Fills in argv_out with an argument vector suitable for execve() that - * includes the editor with the specified files. - */ -static char * -find_editor(argc_out, argv_out) - int *argc_out; - char ***argv_out; -{ - char *cp, *editor, *editor_path = NULL, **ev, *ev0[4]; - - /* - * If any of SUDO_EDITOR, VISUAL or EDITOR are set, choose the first one. - */ - ev0[0] = "SUDO_EDITOR"; - ev0[1] = "VISUAL"; - ev0[2] = "EDITOR"; - ev0[3] = NULL; - for (ev = ev0; *ev != NULL; ev++) { - if ((editor = getenv(*ev)) != NULL && *editor != '\0') { - editor_path = resolve_editor(editor, argc_out, argv_out); - if (editor_path != NULL) - break; - } - } - if (editor_path == NULL) { - /* def_editor could be a path, split it up */ - editor = estrdup(def_editor); - cp = strtok(editor, ":"); - while (cp != NULL && editor_path == NULL) { - editor_path = resolve_editor(cp, argc_out, argv_out); - cp = strtok(NULL, ":"); - } - if (editor_path) - efree(editor); - } - if (!editor_path) { - audit_failure(NewArgv, "%s: command not found", editor); - warningx("%s: command not found", editor); - } - return editor_path; -} - -#else /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ - -/* - * Must have the ability to change the effective uid to use sudoedit. - */ -int -sudo_edit(argc, argv, envp) - int argc; - char *argv[]; - char *envp[]; -{ - return 1; -} - -#endif /* HAVE_SETRESUID || HAVE_SETREUID || HAVE_SETEUID */ diff --git a/sudo_exec.h b/sudo_exec.h deleted file mode 100644 index 6e26913..0000000 --- a/sudo_exec.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 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. - */ - -#ifndef _SUDO_EXEC_H -#define _SUDO_EXEC_H - -/* - * Symbols shared between exec.c and exec_pty.c - */ - -/* exec.c */ -int my_execve __P((const char *path, char *argv[], char *envp[])); - -/* exec_pty.c */ -int fork_pty __P((const char *path, char *argv[], char *envp[], int sv[], - int rbac_enabled, int *maxfd)); -int perform_io __P((fd_set *fdsr, fd_set *fdsw, struct command_status *cstat)); -int suspend_parent __P((int signo)); -void fd_set_iobs __P((fd_set *fdsr, fd_set *fdsw)); -void 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]; - -#endif /* _SUDO_EXEC_H */ diff --git a/sudo_noexec.c b/sudo_noexec.c deleted file mode 100644 index eff07b9..0000000 --- a/sudo_noexec.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2004-2005 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. - */ - -#include - -#include -#ifndef HAVE_TIMESPEC -# include -#endif -#ifdef __STDC__ -# include -#else -# include -#endif - -#include - -/* - * Dummy versions of the execve() family of syscalls. We don't need - * to stub out all of them, just the ones that correspond to actual - * system calls (which varies by OS). Note that it is still possible - * to access the real syscalls via the syscall() interface but very - * few programs actually do that. - */ - -#ifndef errno -extern int errno; -#endif - -#define DUMMY_BODY \ -{ \ - errno = EACCES; \ - return(-1); \ -} - -#ifdef __STDC__ - -#define DUMMY2(fn, t1, t2) \ -int \ -fn(t1 a1, t2 a2) \ -DUMMY_BODY - -#define DUMMY3(fn, t1, t2, t3) \ -int \ -fn(t1 a1, t2 a2, t3 a3) \ -DUMMY_BODY - -#define DUMMY_VA(fn, t1, t2) \ -int \ -fn(t1 a1, t2 a2, ...) \ -DUMMY_BODY - -#else /* !__STDC__ */ - -#define DUMMY2(fn, t1, t2) \ -int \ -fn(a1, a2) \ -t1 a1; t2 a2; \ -DUMMY_BODY - -#define DUMMY3(fn, t1, t2, t3) \ -int \ -fn(a1, a2, a3) \ -t1 a1; t2 a2; t3 a3; \ -DUMMY_BODY - -#define DUMMY_VA(fn, t1, t2) \ -int \ -fn(a1, a2, va_alist) \ -t1 a1; t2 a2; va_dcl \ -DUMMY_BODY - -#endif /* !__STDC__ */ - -DUMMY_VA(execl, const char *, const char *) -DUMMY_VA(_execl, const char *, const char *) -DUMMY_VA(__execl, const char *, const char *) -DUMMY_VA(execle, const char *, const char *) -DUMMY_VA(_execle, const char *, const char *) -DUMMY_VA(__execle, const char *, const char *) -DUMMY_VA(execlp, const char *, const char *) -DUMMY_VA(_execlp, const char *, const char *) -DUMMY_VA(__execlp, const char *, const char *) -DUMMY2(execv, const char *, char * const *) -DUMMY2(_execv, const char *, char * const *) -DUMMY2(__execv, const char *, char * const *) -DUMMY2(execvp, const char *, char * const *) -DUMMY2(_execvp, const char *, char * const *) -DUMMY2(__execvp, const char *, char * const *) -DUMMY3(execvP, const char *, const char *, char * const *) -DUMMY3(_execvP, const char *, const char *, char * const *) -DUMMY3(__execvP, const char *, const char *, char * const *) -DUMMY3(execve, const char *, char * const *, char * const *) -DUMMY3(_execve, const char *, char * const *, char * const *) -DUMMY3(__execve, const char *, char * const *, char * const *) -DUMMY3(fexecve, int , char * const *, char * const *) -DUMMY3(_fexecve, int , char * const *, char * const *) -DUMMY3(__fexecve, int , char * const *, char * const *) diff --git a/sudo_nss.c b/sudo_nss.c deleted file mode 100644 index e21aaae..0000000 --- a/sudo_nss.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2007-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. - */ - -#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 */ -#include -#include -#include - -#include "sudo.h" -#include "lbuf.h" - -extern struct sudo_nss sudo_nss_file; -#ifdef HAVE_LDAP -extern struct sudo_nss sudo_nss_ldap; -#endif - -#if defined(HAVE_LDAP) && defined(_PATH_NSSWITCH_CONF) -/* - * Read in /etc/nsswitch.conf - * Returns a tail queue of matches. - */ -struct sudo_nss_list * -sudo_read_nss() -{ - FILE *fp; - char *cp; - int saw_files = FALSE; - int saw_ldap = FALSE; - int got_match = FALSE; - static struct sudo_nss_list snl; - - if ((fp = fopen(_PATH_NSSWITCH_CONF, "r")) == NULL) - goto nomatch; - - while ((cp = sudo_parseln(fp)) != NULL) { - /* Skip blank or comment lines */ - if (*cp == '\0') - continue; - - /* Look for a line starting with "sudoers:" */ - if (strncasecmp(cp, "sudoers:", 8) != 0) - continue; - - /* Parse line */ - for ((cp = strtok(cp + 8, " \t")); cp != NULL; (cp = strtok(NULL, " \t"))) { - if (strcasecmp(cp, "files") == 0 && !saw_files) { - tq_append(&snl, &sudo_nss_file); - got_match = TRUE; - } else if (strcasecmp(cp, "ldap") == 0 && !saw_ldap) { - tq_append(&snl, &sudo_nss_ldap); - got_match = TRUE; - } else if (strcasecmp(cp, "[NOTFOUND=return]") == 0 && got_match) { - /* NOTFOUND affects the most recent entry */ - tq_last(&snl)->ret_if_notfound = TRUE; - got_match = FALSE; - } else - got_match = FALSE; - } - /* Only parse the first "sudoers:" line */ - break; - } - fclose(fp); - -nomatch: - /* Default to files only if no matches */ - if (tq_empty(&snl)) - tq_append(&snl, &sudo_nss_file); - - return(&snl); -} - -#else /* HAVE_LDAP && _PATH_NSSWITCH_CONF */ - -# if defined(HAVE_LDAP) && defined(_PATH_NETSVC_CONF) - -/* - * Read in /etc/netsvc.conf (like nsswitch.conf on AIX) - * Returns a tail queue of matches. - */ -struct sudo_nss_list * -sudo_read_nss() -{ - FILE *fp; - char *cp, *ep; - int saw_files = FALSE; - int saw_ldap = FALSE; - int got_match = FALSE; - static struct sudo_nss_list snl; - - if ((fp = fopen(_PATH_NETSVC_CONF, "r")) == NULL) - goto nomatch; - - while ((cp = sudo_parseln(fp)) != NULL) { - /* Skip blank or comment lines */ - if (*cp == '\0') - continue; - - /* Look for a line starting with "sudoers = " */ - if (strncasecmp(cp, "sudoers", 7) != 0) - continue; - cp += 7; - while (isspace((unsigned char)*cp)) - cp++; - if (*cp++ != '=') - continue; - - /* Parse line */ - for ((cp = strtok(cp, ",")); cp != NULL; (cp = strtok(NULL, ","))) { - /* Trim leading whitespace. */ - while (isspace((unsigned char)*cp)) - cp++; - - if (!saw_files && strncasecmp(cp, "files", 5) == 0 && - (isspace((unsigned char)cp[5]) || cp[5] == '\0')) { - tq_append(&snl, &sudo_nss_file); - got_match = TRUE; - ep = &cp[5]; - } else if (!saw_ldap && strncasecmp(cp, "ldap", 4) == 0 && - (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { - tq_append(&snl, &sudo_nss_ldap); - got_match = TRUE; - ep = &cp[4]; - } else { - got_match = FALSE; - } - - /* check for = auth qualifier */ - if (got_match && *ep) { - cp = ep; - while (isspace((unsigned char)*cp) || *cp == '=') - cp++; - if (strncasecmp(cp, "auth", 4) == 0 && - (isspace((unsigned char)cp[4]) || cp[4] == '\0')) { - tq_last(&snl)->ret_if_found = TRUE; - } - } - } - /* Only parse the first "sudoers" line */ - break; - } - fclose(fp); - -nomatch: - /* Default to files only if no matches */ - if (tq_empty(&snl)) - tq_append(&snl, &sudo_nss_file); - - return(&snl); -} - -# else /* !_PATH_NETSVC_CONF && !_PATH_NSSWITCH_CONF */ - -/* - * Non-nsswitch.conf version with hard-coded order. - */ -struct sudo_nss_list * -sudo_read_nss() -{ - static struct sudo_nss_list snl; - -# ifdef HAVE_LDAP - tq_append(&snl, &sudo_nss_ldap); -# endif - tq_append(&snl, &sudo_nss_file); - - return(&snl); -} - -# endif /* !HAVE_LDAP || !_PATH_NETSVC_CONF */ - -#endif /* HAVE_LDAP && _PATH_NSSWITCH_CONF */ - -/* Reset user_groups based on passwd entry. */ -static void -reset_groups(pw) - struct passwd *pw; -{ -#if defined(HAVE_INITGROUPS) && defined(HAVE_GETGROUPS) - if (pw != sudo_user.pw) { -# ifdef HAVE_SETAUTHDB - aix_setauthdb(pw->pw_name); -# endif - (void) initgroups(pw->pw_name, pw->pw_gid); - efree(user_groups); - user_groups = NULL; - if ((user_ngroups = getgroups(0, NULL)) > 0) { - user_groups = emalloc2(user_ngroups, sizeof(GETGROUPS_T)); - if (getgroups(user_ngroups, user_groups) < 0) - log_error(USE_ERRNO|MSG_ONLY, "can't get group vector"); - } -# ifdef HAVE_SETAUTHDB - aix_restoreauthdb(); -# endif - } -#endif /* HAVE_INITGROUPS && HAVE_GETGROUPS */ -} - -static int -output(buf) - const char *buf; -{ - return fputs(buf, stdout); -} - -/* - * Print out privileges for the specified user. - * We only get here if the user is allowed to run something on this host. - */ -void -display_privs(snl, pw) - struct sudo_nss_list *snl; - struct passwd *pw; -{ - struct sudo_nss *nss; - struct lbuf lbuf; - int count; - - /* Reset group vector so group matching works correctly. */ - reset_groups(pw); - - lbuf_init(&lbuf, output, 4, NULL); - - /* Display defaults from all sources. */ - lbuf_append(&lbuf, "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); - } - - /* Display Runas and Cmnd-specific defaults from all sources. */ - lbuf.len = 0; - lbuf_append(&lbuf, "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); - } - - /* Display privileges from all sources. */ - lbuf.len = 0; - lbuf_append(&lbuf, "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); - } - if (count) { - lbuf_print(&lbuf); - } - - lbuf_destroy(&lbuf); -} - -/* - * Check user_cmnd against sudoers and print the matching entry if the - * command is allowed. - */ -int -display_cmnd(snl, pw) - struct sudo_nss_list *snl; - struct passwd *pw; -{ - struct sudo_nss *nss; - - /* Reset group vector so group matching works correctly. */ - reset_groups(pw); - - tq_foreach_fwd(snl, nss) { - if (nss->display_cmnd(nss, pw) == 0) - return(0); - } - return(1); -} diff --git a/sudo_nss.h b/sudo_nss.h deleted file mode 100644 index f036add..0000000 --- a/sudo_nss.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2007-2009 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. - */ - -struct lbuf; -struct passwd; - -struct sudo_nss { - struct sudo_nss *prev; - struct sudo_nss *next; - int (*open) __P((struct sudo_nss *nss)); - int (*close) __P((struct sudo_nss *nss)); - int (*parse) __P((struct sudo_nss *nss)); - int (*setdefs) __P((struct sudo_nss *nss)); - int (*lookup) __P((struct sudo_nss *nss, int, int)); - int (*display_cmnd) __P((struct sudo_nss *nss, struct passwd *)); - int (*display_defaults) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *)); - int (*display_bound_defaults) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *)); - int (*display_privs) __P((struct sudo_nss *nss, struct passwd *, struct lbuf *)); - void *handle; - short ret_if_found; - short ret_if_notfound; -}; - -TQ_DECLARE(sudo_nss) - -struct sudo_nss_list *sudo_read_nss __P((void)); diff --git a/sudo_usage.h.in b/sudo_usage.h.in deleted file mode 100644 index af15b87..0000000 --- a/sudo_usage.h.in +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2007-2009 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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SUDO_USAGE_H -#define _SUDO_USAGE_H - -void usage __P((int)) __attribute__((__noreturn__)); - -/* - * Usage strings for sudo. These are here because we - * need to be able to substitute values from configure. - */ -#define SUDO_USAGE1 " -h | -K | -k | -L | -V" -#define SUDO_USAGE2 " -v [-AknS] @BSDAUTH_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid]" -#define SUDO_USAGE3 " -l[l] [-AknS] @BSDAUTH_USAGE@[-g groupname|#gid] [-p prompt] [-U user name] [-u user name|#uid] [-g groupname|#gid] [command]" -#define SUDO_USAGE4 " [-AbEHknPS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] [-g groupname|#gid] [VAR=value] [-i|-s] []" -#define SUDO_USAGE5 " -e [-AknS] @BSDAUTH_USAGE@@SELINUX_USAGE@[-C fd] @LOGINCAP_USAGE@[-g groupname|#gid] [-p prompt] [-u user name|#uid] file ..." - -/* - * Configure script arguments used to build sudo. - */ -#define CONFIGURE_ARGS "@CONFIGURE_ARGS@" - -#endif /* _SUDO_USAGE_H */ diff --git a/sudoers.cat b/sudoers.cat deleted file mode 100644 index 1649855..0000000 --- a/sudoers.cat +++ /dev/null @@ -1,1782 +0,0 @@ - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - -NNAAMMEE - sudoers - list of which users may execute what - -DDEESSCCRRIIPPTTIIOONN - The _s_u_d_o_e_r_s file is composed of two types of entries: aliases - (basically variables) and user specifications (which specify who may - run what). - - When multiple entries match for a user, they are applied in order. - Where there are multiple matches, the last match is used (which is not - necessarily the most specific match). - - The _s_u_d_o_e_r_s grammar will be described below in Extended Backus-Naur - Form (EBNF). Don't despair if you don't know what EBNF is; it is - fairly simple, and the definitions below are annotated. - - QQuuiicckk gguuiiddee ttoo EEBBNNFF - EBNF is a concise and exact way of describing the grammar of a - language. Each EBNF definition is made up of _p_r_o_d_u_c_t_i_o_n _r_u_l_e_s. E.g., - - symbol ::= definition | alternate1 | alternate2 ... - - Each _p_r_o_d_u_c_t_i_o_n _r_u_l_e references others and thus makes up a grammar for - the language. EBNF also contains the following operators, which many - readers will recognize from regular expressions. Do not, however, - confuse them with "wildcard" characters, which have different meanings. - - ? Means that the preceding symbol (or group of symbols) is optional. - That is, it may appear once or not at all. - - * Means that the preceding symbol (or group of symbols) may appear - zero or more times. - - + Means that the preceding symbol (or group of symbols) may appear - one or more times. - - Parentheses may be used to group symbols together. For clarity, we - will use single quotes ('') to designate what is a verbatim character - string (as opposed to a symbol name). - - AAlliiaasseess - There are four kinds of aliases: User_Alias, Runas_Alias, Host_Alias - and Cmnd_Alias. - - Alias ::= 'User_Alias' User_Alias (':' User_Alias)* | - 'Runas_Alias' Runas_Alias (':' Runas_Alias)* | - 'Host_Alias' Host_Alias (':' Host_Alias)* | - 'Cmnd_Alias' Cmnd_Alias (':' Cmnd_Alias)* - - User_Alias ::= NAME '=' User_List - - Runas_Alias ::= NAME '=' Runas_List - - Host_Alias ::= NAME '=' Host_List - - - -1.7.4 July 21, 2010 1 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - - Cmnd_Alias ::= NAME '=' Cmnd_List - - NAME ::= [A-Z]([A-Z][0-9]_)* - - Each _a_l_i_a_s definition is of the form - - Alias_Type NAME = item1, item2, ... - - where _A_l_i_a_s___T_y_p_e is one of User_Alias, Runas_Alias, Host_Alias, or - Cmnd_Alias. A NAME is a string of uppercase letters, numbers, and - underscore characters ('_'). A NAME mmuusstt start with an uppercase - letter. It is possible to put several alias definitions of the same - type on a single line, joined by a colon (':'). E.g., - - Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 - - The definitions of what constitutes a valid _a_l_i_a_s member follow. - - User_List ::= User | - User ',' User_List - - User ::= '!'* user name | - '!'* '#'uid | - '!'* '%'group | - '!'* '+'netgroup | - '!'* '%:'nonunix_group | - '!'* 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 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. - - The nonunix_group syntax depends on the underlying implementation. For - instance, the QAS AD backend supports the following formats: - - +o Group in the same domain: "Group Name" - - +o Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN" - - +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 July 21, 2010 2 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - - Runas_Member ::= '!'* user name | - '!'* '#'uid | - '!'* '%'group | - '!'* +netgroup | - '!'* Runas_Alias - - A Runas_List is similar to a User_List except that instead of - User_Aliases it can contain Runas_Aliases. Note that user names and - groups are matched as strings. In other words, two users (groups) with - the same uid (gid) are considered to be distinct. If you wish to match - all user names with the same uid (e.g. root and toor), you can use a - uid instead (#0 in the example given). - - Host_List ::= Host | - Host ',' Host_List - - Host ::= '!'* host name | - '!'* ip_addr | - '!'* network(/netmask)? | - '!'* '+'netgroup | - '!'* Host_Alias - - A Host_List is made up of one or more host names, IP addresses, network - numbers, netgroups (prefixed with '+') and other aliases. Again, the - value of an item may be negated with the '!' operator. If you do not - specify a netmask along with the network number, ssuuddoo will query each - of the local host's network interfaces and, if the network number - corresponds to one of the hosts's network interfaces, the corresponding - netmask will be used. The netmask may be specified either in standard - IP address notation (e.g. 255.255.255.0 or ffff:ffff:ffff:ffff::), or - CIDR notation (number of bits, e.g. 24 or 64). A host name may include - shell-style wildcards (see the Wildcards section below), but unless the - host name command on your machine returns the fully qualified host - name, you'll need to use the _f_q_d_n option for wildcards to be useful. - Note ssuuddoo only inspects actual network interfaces; this means that IP - address 127.0.0.1 (localhost) will never match. Also, the host name - "localhost" will only match if that is the actual host name, which is - usually only the case for non-networked systems. - - Cmnd_List ::= Cmnd | - Cmnd ',' Cmnd_List - - commandname ::= file name | - file name args | - file name '""' - - Cmnd ::= '!'* commandname | - '!'* directory | - '!'* "sudoedit" | - '!'* Cmnd_Alias - - A Cmnd_List is a list of one or more commandnames, directories, and - other aliases. A commandname is a fully qualified file name which may - - - -1.7.4 July 21, 2010 3 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - include shell-style wildcards (see the Wildcards section below). A - simple file name allows the user to run the command with any arguments - he/she wishes. However, you may also specify command line arguments - (including wildcards). Alternately, you can specify "" to indicate - that the command may only be run wwiitthhoouutt command line arguments. A - directory is a fully qualified path name ending in a '/'. When you - specify a directory in a Cmnd_List, the user will be able to run any - file within that directory (but not in any subdirectories therein). - - If a Cmnd has associated command line arguments, then the arguments in - the Cmnd must match exactly those given by the user on the command line - (or match the wildcards if there are any). Note that the following - characters must be escaped with a '\' if they are used in command - arguments: ',', ':', '=', '\'. The special command "sudoedit" is used - to permit a user to run ssuuddoo with the --ee option (or as ssuuddooeeddiitt). It - may take command line arguments just as a normal command does. - - DDeeffaauullttss - Certain configuration options may be changed from their default values - at runtime via one or more Default_Entry lines. These may affect all - users on any host, all users on a specific host, a specific user, a - specific command, or commands being run as a specific user. Note that - per-command entries may not include command line arguments. If you - need to specify arguments, define a Cmnd_Alias and reference that - instead. - - Default_Type ::= 'Defaults' | - 'Defaults' '@' Host_List | - 'Defaults' ':' User_List | - 'Defaults' '!' Cmnd_List | - 'Defaults' '>' Runas_List - - Default_Entry ::= Default_Type Parameter_List - - Parameter_List ::= Parameter | - Parameter ',' Parameter_List - - Parameter ::= Parameter '=' Value | - Parameter '+=' Value | - Parameter '-=' Value | - '!'* Parameter - - Parameters may be 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.4 July 21, 2010 4 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - Defaults entries are parsed in the following order: generic, host and - user Defaults first, then runas Defaults and finally command defaults. - - See "SUDOERS OPTIONS" for a list of supported Defaults parameters. - - UUsseerr SSppeecciiffiiccaattiioonn - User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \ - (':' Host_List '=' Cmnd_Spec_List)* - - Cmnd_Spec_List ::= Cmnd_Spec | - Cmnd_Spec ',' Cmnd_Spec_List - - Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd - - Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' - - SELinux_Spec ::= ('ROLE=role' | 'TYPE=type') - - Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | - 'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | - 'LOG_OUTPUT:' | 'NOLOG_OUTPUT:') - - A uusseerr ssppeecciiffiiccaattiioonn determines which commands a user may run (and as - 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) - what'. Let's break that down into its constituent parts: - - RRuunnaass__SSppeecc - A Runas_Spec determines the user and/or the group that a command may be - run as. A fully-specified Runas_Spec consists of two Runas_Lists (as - defined above) separated by a colon (':') and enclosed in a set of - parentheses. The first Runas_List indicates which users the command - may be run as via ssuuddoo's --uu option. The second defines a list of - groups that can be specified via ssuuddoo's --gg option. If both Runas_Lists - are specified, the command may be run with any combination of users and - groups listed in their respective Runas_Lists. If only the first is - specified, the command may be run as any user in the list but no --gg - option may be specified. If the first Runas_List is empty but the - second is specified, the command may be run as the invoking user with - the group set to any listed in the Runas_List. If no Runas_Spec is - specified the command may be run as 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.4 July 21, 2010 5 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - It is also possible to override a Runas_Spec later on in an entry. If - we modify the entry like so: - - dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm - - Then user ddggbb is now allowed to run _/_b_i_n_/_l_s as ooppeerraattoorr, but _/_b_i_n_/_k_i_l_l - and _/_u_s_r_/_b_i_n_/_l_p_r_m as rroooott. - - We can extend this to allow ddggbb to run /bin/ls with either the user or - group set to ooppeerraattoorr: - - dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \ - /usr/bin/lprm - - 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. - - tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \ - /usr/local/bin/minicom - - 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 - is specified with the command it will override any default values - specified in _s_u_d_o_e_r_s. A role or type specified on the command line, - however, will supercede the values in _s_u_d_o_e_r_s. - - TTaagg__SSppeecc - A command may have zero or more tags associated with it. There are - eight possible tag values, NOPASSWD, PASSWD, NOEXEC, EXEC, SETENV, - NOSETENV, LOG_INPUT, NOLOG_INPUT, LOG_OUTPUT and NOLOG_OUTPUT. Once a - tag is set on a Cmnd, subsequent Cmnds in the Cmnd_Spec_List, inherit - the tag unless it is overridden by the opposite tag (i.e.: PASSWD - overrides NOPASSWD and NOEXEC overrides EXEC). - - _N_O_P_A_S_S_W_D _a_n_d _P_A_S_S_W_D - - By default, ssuuddoo requires that a user authenticate him or herself - before running a command. This behavior can be modified via the - NOPASSWD tag. Like a Runas_Spec, the NOPASSWD tag sets a default for - the commands that follow it in the Cmnd_Spec_List. Conversely, the - PASSWD tag can be used to reverse things. For example: - - ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm - - would allow the user rraayy to run _/_b_i_n_/_k_i_l_l, _/_b_i_n_/_l_s, and _/_u_s_r_/_b_i_n_/_l_p_r_m - as rroooott on the machine rushmore without authenticating himself. If we - only want rraayy to be able to run _/_b_i_n_/_k_i_l_l without a password the entry - would be: - - ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm - - Note, however, that the PASSWD tag has no effect on users who are in - - - -1.7.4 July 21, 2010 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 - user on the current host, he or she will be able to run sudo -l without - a password. Additionally, a user may only run sudo -v without a - password if the NOPASSWD tag is present for all a user's entries that - pertain to the current host. This behavior may be overridden via the - verifypw and listpw options. - - _N_O_E_X_E_C _a_n_d _E_X_E_C - - If ssuuddoo has been compiled with _n_o_e_x_e_c support and the underlying - operating system supports it, the NOEXEC tag can be used to prevent a - dynamically-linked executable from running further commands itself. - - In the following example, user aaaarroonn may run _/_u_s_r_/_b_i_n_/_m_o_r_e and - _/_u_s_r_/_b_i_n_/_v_i but shell escapes will be disabled. - - aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi - - See the "PREVENTING SHELL ESCAPES" section below for more details on - how NOEXEC works and whether or not it will work on your system. - - _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. - - _L_O_G___I_N_P_U_T _a_n_d _N_O_L_O_G___I_N_P_U_T - - These tags override the value of the _l_o_g___i_n_p_u_t option on a per-command - basis. For more information, see the description of _l_o_g___i_n_p_u_t in the - "SUDOERS OPTIONS" section below. - - _L_O_G___O_U_T_P_U_T _a_n_d _N_O_L_O_G___O_U_T_P_U_T - - These tags override the value of the _l_o_g___o_u_t_p_u_t option on a per-command - basis. For more information, see the description of _l_o_g___o_u_t_p_u_t in the - "SUDOERS OPTIONS" section below. - - WWiillddccaarrddss - ssuuddoo allows shell-style _w_i_l_d_c_a_r_d_s (aka meta or glob characters) to be - used in host names, path names and command line arguments in the - _s_u_d_o_e_r_s file. Wildcard matching is done via the PPOOSSIIXX _g_l_o_b(3) and - _f_n_m_a_t_c_h(3) routines. Note that these are _n_o_t regular expressions. - - * Matches any set of zero or more characters. - - ? Matches any single character. - - - -1.7.4 July 21, 2010 7 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - [...] Matches any character in the specified range. - - [!...] Matches any character nnoott in the specified range. - - \x For any character "x", evaluates to "x". This is used to - escape special characters such as: "*", "?", "[", and "}". - - POSIX character classes may also be used if your system's _g_l_o_b(3) and - _f_n_m_a_t_c_h(3) functions support them. However, because the ':' character - has special meaning in _s_u_d_o_e_r_s, it must be escaped. For example: - - /bin/ls [[\:alpha\:]]* - - Would match any file name beginning with a letter. - - Note that a forward slash ('/') will nnoott be matched by wildcards used - 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: - - /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. - - EExxcceeppttiioonnss ttoo wwiillddccaarrdd rruulleess - The following exceptions apply to the above rules: - - "" If the empty string "" is the only command line argument in the - _s_u_d_o_e_r_s entry it means that command is not allowed to be run - with aannyy arguments. - - IInncclluuddiinngg ootthheerr ffiilleess ffrroomm wwiitthhiinn ssuuddooeerrss - It is possible to include other _s_u_d_o_e_r_s files from within the _s_u_d_o_e_r_s - file currently being parsed using the #include and #includedir - directives. - - This can be used, for example, to keep a site-wide _s_u_d_o_e_r_s file in - addition to a local, per-machine file. For the sake of this example - the site-wide _s_u_d_o_e_r_s will be _/_e_t_c_/_s_u_d_o_e_r_s and the per-machine one will - be _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. To include _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l from within - _/_e_t_c_/_s_u_d_o_e_r_s we would use the following line in _/_e_t_c_/_s_u_d_o_e_r_s: - - #include /etc/sudoers.local - - When ssuuddoo reaches this line it will suspend processing of the current - file (_/_e_t_c_/_s_u_d_o_e_r_s) and switch to _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l. Upon reaching - the end of _/_e_t_c_/_s_u_d_o_e_r_s_._l_o_c_a_l, the rest of _/_e_t_c_/_s_u_d_o_e_r_s will be - processed. Files that are included may themselves include other files. - A hard limit of 128 nested include files is enforced to prevent include - file loops. - - The file name may include the %h escape, signifying the short form of - the host name. I.e., if the machine's host name is "xerxes", then - - #include /etc/sudoers.%h - - - -1.7.4 July 21, 2010 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 - the system package manager can drop _s_u_d_o_e_r_s rules into as part of - package installation. For example, given: - - #includedir /etc/sudoers.d - - ssuuddoo will read each file in _/_e_t_c_/_s_u_d_o_e_r_s_._d, skipping file names that - end in ~ or contain a . character to avoid causing problems with - package manager or editor temporary/backup files. Files are parsed in - sorted lexical order. That is, _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_0_1___f_i_r_s_t will be parsed - before _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1_0___s_e_c_o_n_d. Be aware that because the sorting is - lexical, not numeric, _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1___w_h_o_o_p_s would be loaded aafftteerr - _/_e_t_c_/_s_u_d_o_e_r_s_._d_/_1_0___s_e_c_o_n_d. Using a consistent number of leading zeroes - in the file names can be used to avoid such problems. - - Note that unlike files included via #include, vviissuuddoo will not edit the - 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. - - OOtthheerr ssppeecciiaall cchhaarraacctteerrss aanndd rreesseerrvveedd wwoorrddss - The pound sign ('#') is used to indicate a comment (unless it is part - of a #include directive or unless it occurs in the context of a user - name and is followed by one or more digits, in which case it is treated - as a uid). Both the comment character and any text after it, up to the - end of the line, are ignored. - - The reserved word AALLLL is a built-in _a_l_i_a_s that always causes a match to - succeed. It can be used wherever one might otherwise use a Cmnd_Alias, - User_Alias, Runas_Alias, or Host_Alias. You should not try to define - your own _a_l_i_a_s called AALLLL as the built-in alias will be used in - preference to your own. Please note that using AALLLL can be dangerous - since in a command context, it allows the user to run aannyy command on - the system. - - An exclamation point ('!') can be used as a logical _n_o_t operator both - in an _a_l_i_a_s and in front of a Cmnd. This allows one to exclude certain - values. Note, however, that using a ! in conjunction with the built-in - ALL alias to allow a user to run "all but a few" commands rarely works - as intended (see SECURITY NOTES below). - - Long lines can be continued with a backslash ('\') as the last - character on the line. - - Whitespace between elements in a list as well as special syntactic - characters in a _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 July 21, 2010 9 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - -SSUUDDOOEERRSS OOPPTTIIOONNSS - ssuuddoo's behavior can be modified by Default_Entry lines, as explained - earlier. A list of all supported Defaults parameters, grouped by type, - are listed below. - - BBoooolleeaann FFllaaggss: - - always_set_home If enabled, ssuuddoo will set the HOME environment variable - to the home directory of the target user (which is root - unless the --uu option is used). This effectively means - 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. - - authenticate If set, users must authenticate themselves via a - password (or other means of authentication) before they - may run commands. This default may be overridden via - the PASSWD and NOPASSWD tags. This flag is _o_n by - default. - - closefrom_override - If set, the user may use ssuuddoo's --CC option which - overrides the default starting point at which ssuuddoo - begins closing open file descriptors. This flag is _o_f_f - by default. - - compress_io If set, and ssuuddoo is configured to log a command's input - or output, the I/O logs will be compressed using zzlliibb. - This flag is _o_n by default when ssuuddoo is compiled with - zzlliibb support. - - env_editor If set, vviissuuddoo will use the value of the EDITOR or - VISUAL environment variables before falling back on the - default editor list. Note that this may create a - security hole as it allows the user to run any - arbitrary command as root without logging. A safer - alternative is to place a colon-separated list of - editors in the editor variable. vviissuuddoo will then only - use the EDITOR or VISUAL if they match a value - specified in editor. This flag is _o_f_f by default. - - env_reset If set, ssuuddoo will reset the environment to only contain - the LOGNAME, MAIL, SHELL, USER, USERNAME and the SUDO_* - variables. Any variables in the caller's environment - that match the env_keep and env_check lists are then - added. The default contents of the env_keep and - env_check lists are displayed when ssuuddoo is run by root - with the _-_V option. If the _s_e_c_u_r_e___p_a_t_h option is set, - its value will be used for the PATH environment - 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 July 21, 2010 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 - when the pattern references a network file system that - is mounted on demand (automounted). The _f_a_s_t___g_l_o_b - option causes ssuuddoo to use the _f_n_m_a_t_c_h(3) function, - which does not access the file system to do its - matching. The disadvantage of _f_a_s_t___g_l_o_b is that it is - unable to match relative path names such as _._/_l_s or - _._._/_b_i_n_/_l_s. This has security implications when path - names that include globbing characters are used with - the negation operator, '!', as such rules can be - trivially bypassed. As such, this option should not be - used when _s_u_d_o_e_r_s contains rules that contain negated - path names which include globbing characters. This - flag is _o_f_f by default. - - fqdn Set this flag if you want to put fully qualified host - 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 - that turning on _f_q_d_n requires ssuuddoo to make DNS lookups - which may make ssuuddoo unusable if DNS stops working (for - example if the machine is not plugged into the - network). Also note that you must use the host's - official name as DNS knows it. That is, you may not - use a host alias (CNAME entry) due to performance - issues and the fact that there is no way to get all - aliases from DNS. If your machine's host name (as - returned by the hostname command) is already fully - qualified you shouldn't need to set _f_q_d_n. This flag is - _o_f_f by default. - - ignore_dot If set, ssuuddoo will ignore '.' or '' (current dir) in the - PATH environment variable; the PATH itself is not - modified. This flag is _o_f_f by default. - - ignore_local_sudoers - If set via LDAP, parsing of _/_e_t_c_/_s_u_d_o_e_r_s will be - skipped. This is intended for Enterprises that wish to - prevent the usage of local sudoers files so that only - LDAP is used. This thwarts the efforts of rogue - operators who would attempt to add roles to - _/_e_t_c_/_s_u_d_o_e_r_s. When this option is present, - _/_e_t_c_/_s_u_d_o_e_r_s does not even need to exist. Since this - option tells ssuuddoo how to behave when no specific LDAP - entries have been matched, this sudoOption is only - meaningful for the cn=defaults section. This flag is - _o_f_f by default. - - insults If set, ssuuddoo will insult users when they enter an - incorrect password. This flag is _o_f_f by default. - - log_host If set, the host name will be logged in the (non- - - - -1.7.4 July 21, 2010 11 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - syslog) ssuuddoo log file. This flag is _o_f_f by default. - - 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. - - long_otp_prompt When validating with a One Time Password (OPT) scheme - such as SS//KKeeyy or OOPPIIEE, a two-line prompt is used to - make it easier to cut and paste the challenge to a - local window. It's not as pretty as the default but - some people find it more convenient. This flag is _o_f_f - by default. - - mail_always Send mail to the _m_a_i_l_t_o user every time a users runs - ssuuddoo. This flag is _o_f_f by default. - - mail_badpass Send mail to the _m_a_i_l_t_o user if the user running ssuuddoo - does not enter the correct password. This flag is _o_f_f - by default. - - mail_no_host If set, mail will be sent to the _m_a_i_l_t_o user if the - invoking user exists in the _s_u_d_o_e_r_s file, but is not - allowed to run commands on the current host. This flag - is _o_f_f by default. - - mail_no_perms If set, mail will be sent to the _m_a_i_l_t_o user if the - invoking user is allowed to use ssuuddoo but the command - they are trying is not listed in their _s_u_d_o_e_r_s file - entry or is explicitly denied. This flag is _o_f_f by - default. - - mail_no_user If set, mail will be sent to the _m_a_i_l_t_o user if the - invoking user is not in the _s_u_d_o_e_r_s file. This flag is - _o_n by default. - - noexec If set, all commands run via ssuuddoo will behave as if the - NOEXEC tag has been set, unless overridden by a EXEC - tag. See the description of _N_O_E_X_E_C _a_n_d _E_X_E_C below as - well as the "PREVENTING SHELL ESCAPES" section at the - end of this manual. This flag is _o_f_f by default. - - 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 - gather information on the location of executables that - the normal user does not have access to. The - disadvantage is that if the executable is simply not in - the user's PATH, ssuuddoo will tell the user that they are - not allowed to run it, which can be confusing. This - flag is _o_n by default. - - passprompt_override - 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 July 21, 2010 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. - - preserve_groups By default, ssuuddoo will initialize the group vector to - the list of groups the target user is in. When - _p_r_e_s_e_r_v_e___g_r_o_u_p_s is set, the user's existing group - vector is left unaltered. The real and effective group - IDs, however, are still set to match the target user. - This flag is _o_f_f by default. - - pwfeedback By default, ssuuddoo reads the password like most other - Unix programs, by turning off echo until the user hits - the return (or enter) key. Some users become confused - by this as it appears to them that ssuuddoo has hung at - this point. When _p_w_f_e_e_d_b_a_c_k is set, ssuuddoo will provide - visual feedback when the user presses a key. Note that - this does have a security impact as an onlooker may be - able to determine the length of the password being - entered. This flag is _o_f_f by default. - - requiretty If set, ssuuddoo will only run when the user is logged in - to a real tty. When this flag is set, ssuuddoo can only be - run from a login session and not via other means such - as _c_r_o_n(1m) or cgi-bin scripts. This flag is _o_f_f by - default. - - root_sudo If set, root is allowed to run ssuuddoo too. Disabling - this prevents users from "chaining" ssuuddoo commands to - get a root shell by doing something like "sudo sudo - /bin/sh". Note, however, that turning off _r_o_o_t___s_u_d_o - will also prevent root from running ssuuddooeeddiitt. - Disabling _r_o_o_t___s_u_d_o provides no real additional - security; it exists purely for historical reasons. - This flag is _o_n by default. - - rootpw If set, ssuuddoo will prompt for the root password instead - of the password of the invoking user. This flag is _o_f_f - 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.4 July 21, 2010 13 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - 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 - system) use LOGNAME to determine the real identity of - the user, it may be desirable to change this behavior. - This can be done by negating the set_logname option. - Note that if the _e_n_v___r_e_s_e_t option has not been - disabled, entries in the _e_n_v___k_e_e_p list will override - the value of _s_e_t___l_o_g_n_a_m_e. This flag is _o_n by default. - - setenv Allow the user to disable the _e_n_v___r_e_s_e_t option from the - command line. Additionally, environment variables set - via 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. This flag is - _o_f_f by default. - - shell_noargs If set and ssuuddoo is invoked with no arguments it acts as - if the --ss option had been given. That is, it runs a - shell as root (the shell is determined by the SHELL - environment variable if it is set, falling back on the - shell listed in the invoking user's /etc/passwd entry - if not). This flag is _o_f_f by default. - - stay_setuid Normally, when ssuuddoo executes a command the real and - effective UIDs are set to the target user (root by - default). This option changes that behavior such that - the real UID is left as the invoking user's UID. In - other words, this makes ssuuddoo act as a setuid wrapper. - This can be useful on systems that disable some - potentially dangerous functionality when a program is - run setuid. This option is only effective on systems - with either the _s_e_t_r_e_u_i_d_(_) or _s_e_t_r_e_s_u_i_d_(_) function. - This flag is _o_f_f by default. - - 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 July 21, 2010 14 - - - - - -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. - - tty_tickets If set, users must authenticate on a per-tty basis. - With this flag enabled, ssuuddoo will use a file named for - the tty the user is logged in on in the user's time - stamp directory. If disabled, the time stamp of the - directory is used instead. This flag is _o_n by default. - - umask_override If set, ssuuddoo will set the umask as specified by _s_u_d_o_e_r_s - without modification. This makes it possible to - specify a more permissive umask in _s_u_d_o_e_r_s than the - user's own umask and matches historical behavior. If - _u_m_a_s_k___o_v_e_r_r_i_d_e is not set, ssuuddoo will set the umask to - be the union of the user's umask and what is specified - in _s_u_d_o_e_r_s. This flag is _o_f_f by default. - - use_loginclass If set, ssuuddoo will apply the defaults specified for the - target user's login class if one exists. Only - available if ssuuddoo is configured with the - --with-logincap option. This flag is _o_f_f by default. - - use_pty If set, ssuuddoo will run the command in a pseudo-pty even - if no I/O logging is being gone. A malicious program - run under ssuuddoo could conceivably fork a background - process that retains to the user's terminal device - after the main program has finished executing. Use of - this option will make that impossible. - - visiblepw By default, ssuuddoo will refuse to run if the user must - enter a password but it is not possible to disable echo - on the terminal. If the _v_i_s_i_b_l_e_p_w flag is set, ssuuddoo - will prompt for a password even when it would be - visible on the screen. This makes it possible to run - things like "rsh somehost sudo ls" since _r_s_h(1) does - not allocate a tty. This flag is _o_f_f by default. - - IInntteeggeerrss: - - closefrom Before it executes a command, ssuuddoo will close all open - file descriptors other than standard input, standard - - - -1.7.4 July 21, 2010 15 - - - - - -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. - - 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 - log files. This has no effect on the syslog log file, - only the file log. The default is 80 (use 0 or negate - the option to disable word wrap). - - passwd_timeout Number of minutes before the ssuuddoo password prompt times - out, or 0 for no timeout. The timeout may include a - fractional component if minute granularity is - insufficient, for example 2.5. The default is 5. - - timestamp_timeout - Number of minutes that can elapse before ssuuddoo will ask - for a passwd again. The timeout may include a - fractional component if minute granularity is - insufficient, for example 2.5. The default is 5. Set - this to 0 to always prompt for a password. If set to a - value less than 0 the user's timestamp will never - expire. This can be used to allow users to create or - delete their own timestamps via sudo -v and sudo -k - respectively. - - umask Umask to use when running the command. Negate this - option or set it to 0777 to preserve the user's umask. - The actual umask that is used will be the union of the - user's umask and 0022. This guarantees that ssuuddoo never - lowers the umask when running a command. Note on - systems that use PAM, the default PAM configuration may - specify its own umask which will override the value set - in _s_u_d_o_e_r_s. - - SSttrriinnggss: - - badpass_message Message that is displayed if a user enters an incorrect - password. The default is Sorry, try again. unless - insults are enabled. - - editor A colon (':') separated list of editors allowed to be - used with vviissuuddoo. vviissuuddoo will choose the editor that - matches the user's EDITOR environment variable if - possible, or the first editor in the list that exists - and is executable. The default is "vi". - - - - -1.7.4 July 21, 2010 16 - - - - - -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 - 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 - LD_PRELOAD or its equivalent. Defaults to - _/_u_s_r_/_l_o_c_a_l_/_l_i_b_e_x_e_c_/_s_u_d_o___n_o_e_x_e_c_._s_o. - - passprompt The default prompt to use when asking for a password; - can be overridden via the --pp option or the SUDO_PROMPT - environment variable. The following percent (`%') - escapes are supported: - - %H expanded to the local host name including the - domain name (on if the machine's host name is fully - qualified or the _f_q_d_n option is set) - - %h expanded to the local host name without the domain - name - - %p expanded to the user whose password is being asked - for (respects the _r_o_o_t_p_w, _t_a_r_g_e_t_p_w and _r_u_n_a_s_p_w - flags in _s_u_d_o_e_r_s) - - %U expanded to the login name of the user the command - will be run as (defaults to root) - - %u expanded to the invoking user's login name - - %% two consecutive % characters are collapsed into a - single % character - - The default value is Password:. - - role The default SELinux role to use when constructing a new - security context to run the command. The default role - may be overridden on a per-command basis in _s_u_d_o_e_r_s or - via command line options. This option is only - available whe ssuuddoo is built with SELinux support. - - runas_default The default user to run commands as if the --uu option is - not specified on the command line. This defaults to - root. Note that if _r_u_n_a_s___d_e_f_a_u_l_t is set it mmuusstt occur - before any Runas_Alias specifications. - - syslog_badpri Syslog priority to use when user authenticates - unsuccessfully. Defaults to alert. - - syslog_goodpri Syslog priority to use when user authenticates - successfully. Defaults to notice. - - - - -1.7.4 July 21, 2010 17 - - - - - -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. - - timestampowner The owner of the timestamp directory and the timestamps - stored therein. The default is root. - - type The default SELinux type to use when constructing a new - security context to run the command. The default type - may be overridden on a per-command basis in _s_u_d_o_e_r_s or - via command line options. This option is only - available whe ssuuddoo is built with SELinux support. - - SSttrriinnggss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: - - askpass The _a_s_k_p_a_s_s option specifies the fully qualified path to a - helper program used to read the user's password when no - terminal is available. This may be the case when ssuuddoo is - executed from a graphical (as opposed to text-based) - application. The program specified by _a_s_k_p_a_s_s should - display the argument passed to it as the prompt and write - the user's password to the standard output. The value of - _a_s_k_p_a_s_s may be overridden by the SUDO_ASKPASS environment - variable. - - env_file The _e_n_v___f_i_l_e options specifies the fully qualified path to - a file containing variables to be set in the environment of - the program being run. Entries in this file should either - be of the form VARIABLE=value or export VARIABLE=value. - The value may optionally be surrounded by single or double - quotes. Variables in this file are subject to other ssuuddoo - environment settings such as _e_n_v___k_e_e_p and _e_n_v___c_h_e_c_k. - - exempt_group - Users in this group are exempt from password and PATH - requirements. This is not set by default. - - lecture This option controls when a short lecture will be printed - along with the password prompt. It has the following - possible values: - - always Always lecture the user. - - never Never lecture the user. - - once Only lecture the user the first time they run ssuuddoo. - - If no value is specified, a value of _o_n_c_e is implied. - Negating the option results in a value of _n_e_v_e_r being used. - The default value is _o_n_c_e. - - - - -1.7.4 July 21, 2010 18 - - - - - -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: - - 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 - password. - - always The user must always enter a password to use the --ll - option. - - any At least one of 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 password. - - never The user need never enter a password to use the --ll - option. - - If no value is specified, a value of _a_n_y is implied. - Negating the option results in a value of _n_e_v_e_r being used. - The default value is _a_n_y. - - logfile Path to the ssuuddoo log file (not the syslog log file). - Setting a path turns on logging to a file; negating this - option turns it off. By default, ssuuddoo logs via syslog. - - mailerflags Flags to use when invoking mailer. Defaults to --tt. - - mailerpath Path to mail program used to send warning mail. Defaults - to the path to sendmail found at configure time. - - mailfrom Address to use for the "from" address when sending warning - and error mail. The address should be enclosed in double - quotes (") to protect against ssuuddoo interpreting the @ sign. - Defaults to the name of the user running ssuuddoo. - - mailto Address to send warning and error mail to. The address - should be enclosed in double quotes (") to protect against - ssuuddoo interpreting the @ sign. Defaults to root. - - secure_path Path used for every command run from ssuuddoo. If you don't - trust the people running ssuuddoo to have a sane PATH - environment variable you may want to use this. Another use - is if you want to have the "root path" be separate from the - "user path." Users in the group specified by the - _e_x_e_m_p_t___g_r_o_u_p option are not affected by _s_e_c_u_r_e___p_a_t_h. This - option is not set by default. - - syslog Syslog facility if syslog is being used for logging (negate - - - -1.7.4 July 21, 2010 19 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - 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: - - 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 - password. - - always The user must always enter a password to use the --vv - option. - - any At least one of 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 password. - - never The user need never enter a password to use the --vv - option. - - If no value is specified, a value of _a_l_l is implied. - Negating the option results in a value of _n_e_v_e_r being used. - The default value is _a_l_l. - - LLiissttss tthhaatt ccaann bbee uusseedd iinn aa bboooolleeaann ccoonntteexxtt: - - env_check Environment variables to be removed from the user's - environment if the variable's value contains % or / - characters. This can be used to guard against printf- - style format vulnerabilities in poorly-written - programs. The argument may be a double-quoted, space- - separated list or a single value without double-quotes. - The list can be replaced, added to, deleted from, or - disabled by using the =, +=, -=, and ! operators - respectively. Regardless of whether the env_reset - option is enabled or disabled, variables specified by - env_check will be preserved in the environment if they - pass the aforementioned check. The default list of - environment variables to check is displayed when ssuuddoo - is run by root with the _-_V option. - - env_delete Environment variables to be removed from the user's - environment when the _e_n_v___r_e_s_e_t option is not in effect. - The argument may be a double-quoted, space-separated - list or a single value without double-quotes. The list - can be replaced, added to, deleted from, or disabled by - using the =, +=, -=, and ! operators respectively. The - default list of environment variables to remove is - displayed when ssuuddoo is run by root with the _-_V option. - Note that many operating systems will remove - potentially dangerous variables from the environment of - any setuid process (such as ssuuddoo). - - env_keep Environment variables to be preserved in the user's - - - -1.7.4 July 21, 2010 20 - - - - - -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. - - When logging via _s_y_s_l_o_g(3), ssuuddoo accepts the following values for the - syslog facility (the value of the ssyysslloogg Parameter): aauutthhpprriivv (if your - OS supports it), aauutthh, ddaaeemmoonn, uusseerr, llooccaall00, llooccaall11, llooccaall22, llooccaall33, - llooccaall44, llooccaall55, llooccaall66, and llooccaall77. The following syslog priorities - are supported: aalleerrtt, ccrriitt, ddeebbuugg, eemmeerrgg, eerrrr, iinnffoo, nnoottiiccee, and - wwaarrnniinngg. - -FFIILLEESS - _/_e_t_c_/_s_u_d_o_e_r_s List of who can run what - - _/_e_t_c_/_g_r_o_u_p Local groups file - - _/_e_t_c_/_n_e_t_g_r_o_u_p List of network groups - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o I/O log files - -EEXXAAMMPPLLEESS - Below are example _s_u_d_o_e_r_s entries. Admittedly, some of these are a bit - contrived. First, we allow a few environment variables to pass and - then define our _a_l_i_a_s_e_s: - - # Run X applications through sudo; HOME is used to find the - # .Xauthority file. Note that other programs use HOME to find - # configuration files and this may lead to privilege escalation! - Defaults env_keep += "DISPLAY HOME" - - # User alias specification - User_Alias FULLTIMERS = millert, mikef, dowdy - User_Alias PARTTIMERS = bostley, jwfox, crawl - User_Alias WEBMASTERS = will, wendy, wim - - # Runas alias specification - Runas_Alias OP = root, operator - Runas_Alias DB = oracle, sybase - Runas_Alias ADMINGRP = adm, oper - - # Host alias specification - Host_Alias SPARC = bigtime, eclipse, moet, anchor :\ - SGI = grolsch, dandelion, black :\ - ALPHA = widget, thalamus, foobar :\ - HPPA = boa, nag, python - Host_Alias CUNETS = 128.138.0.0/255.255.0.0 - Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 - Host_Alias SERVERS = master, mail, www, ns - - - -1.7.4 July 21, 2010 21 - - - - - -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 - Cmnd_Alias REBOOT = /usr/sbin/reboot - Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \ - /usr/local/bin/tcsh, /usr/bin/rsh, \ - /usr/local/bin/zsh - Cmnd_Alias SU = /usr/bin/su - Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less - - Here we override some of the compiled in default values. We want ssuuddoo - to log via _s_y_s_l_o_g(3) using the _a_u_t_h facility in all cases. We don't - want to subject the full time staff to the ssuuddoo lecture, user mmiilllleerrtt - need not give a password, and we don't want to reset the LOGNAME, USER - or USERNAME environment variables when running commands as root. - Additionally, on the machines in the _S_E_R_V_E_R_S Host_Alias, we keep an - additional local log file and make sure we log the year in each log - line since the log entries will be kept around for several years. - Lastly, we disable shell escapes for the commands in the PAGERS - Cmnd_Alias (_/_u_s_r_/_b_i_n_/_m_o_r_e, _/_u_s_r_/_b_i_n_/_p_g and _/_u_s_r_/_b_i_n_/_l_e_s_s). - - # Override built-in defaults - Defaults syslog=auth - Defaults>root !set_logname - Defaults:FULLTIMERS !lecture - Defaults:millert !authenticate - Defaults@SERVERS log_year, logfile=/var/log/sudo.log - Defaults!PAGERS noexec - - The _U_s_e_r _s_p_e_c_i_f_i_c_a_t_i_o_n is the part that actually determines who may run - what. - - root ALL = (ALL) ALL - %wheel ALL = (ALL) ALL - - We let rroooott and any user in group wwhheeeell run any command on any host as - any user. - - FULLTIMERS ALL = NOPASSWD: ALL - - Full time sysadmins (mmiilllleerrtt, mmiikkeeff, and ddoowwddyy) may run any command on - any host without authenticating themselves. - - PARTTIMERS ALL = ALL - - Part time sysadmins (bboossttlleeyy, jjwwffooxx, and ccrraawwll) may run any command on - any host but they must authenticate themselves first (since the entry - lacks the NOPASSWD tag). - - - -1.7.4 July 21, 2010 22 - - - - - -SUDOERS(4) MAINTENANCE COMMANDS SUDOERS(4) - - - 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 - 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. - - lisa CUNETS = ALL - - The user lliissaa may run any command on any host in the _C_U_N_E_T_S alias (the - class B network 128.138.0.0). - - operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\ - sudoedit /etc/printcap, /usr/oper/bin/ - - The ooppeerraattoorr user may run commands limited to simple maintenance. - Here, those are commands related to backups, killing processes, the - printing system, shutting down the system, and any commands in the - directory _/_u_s_r_/_o_p_e_r_/_b_i_n_/. - - joe ALL = /usr/bin/su operator - - The user jjooee may only _s_u(1) to operator. - - pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root - - %opers ALL = (: ADMINGRP) /usr/sbin/ - - Users in the ooppeerrss group may run commands in _/_u_s_r_/_s_b_i_n_/ as themselves - with any group in the _A_D_M_I_N_G_R_P Runas_Alias (the aaddmm and ooppeerr groups). - - The user ppeettee is allowed to change anyone's password except for root on - the _H_P_P_A machines. Note that this assumes _p_a_s_s_w_d(1) does not take - multiple user names on the command line. - - bob SPARC = (OP) ALL : SGI = (OP) ALL - - The user bboobb may run anything on the _S_P_A_R_C and _S_G_I machines as any user - listed in the _O_P Runas_Alias (rroooott and ooppeerraattoorr). - - jim +biglab = ALL - - The user jjiimm may run any command on machines in the _b_i_g_l_a_b netgroup. - ssuuddoo knows that "biglab" is a netgroup due to the '+' prefix. - - +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser - - Users in the sseeccrreettaarriieess netgroup need to help manage the printers as - well as add and remove users, so they are allowed to run those commands - on all machines. - - fred ALL = (DB) NOPASSWD: ALL - - - - -1.7.4 July 21, 2010 23 - - - - - -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. - - 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. - - jen ALL, !SERVERS = ALL - - The user jjeenn may run any command on any machine except for those in the - _S_E_R_V_E_R_S Host_Alias (master, mail, www and ns). - - jill SERVERS = /usr/bin/, !SU, !SHELLS - - For any machine in the _S_E_R_V_E_R_S Host_Alias, jjiillll may run any commands in - the directory _/_u_s_r_/_b_i_n_/ except for those commands belonging to the _S_U - and _S_H_E_L_L_S Cmnd_Aliases. - - steve CSNETS = (operator) /usr/local/op_commands/ - - The user sstteevvee may run any command in the directory - /usr/local/op_commands/ but only as user operator. - - matt valkyrie = KILL - - On his personal workstation, valkyrie, mmaatttt needs to be able to kill - hung processes. - - WEBMASTERS www = (www) ALL, (root) /usr/bin/su www - - On the host www, any user in the _W_E_B_M_A_S_T_E_R_S User_Alias (will, wendy, - and wim), may run any command as user www (which owns the web pages) or - simply _s_u(1) to www. - - ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ - /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM - - Any user may mount or unmount a CD-ROM on the machines in the CDROM - Host_Alias (orion, perseus, hercules) without entering a password. - This is a bit tedious for users to type, so it is a prime candidate for - encapsulating in a shell script. - -SSEECCUURRIITTYY NNOOTTEESS - It is generally not effective to "subtract" commands from ALL using the - '!' operator. A user can trivially circumvent this by copying the - desired command to a different name and then executing that. For - example: - - bill ALL = ALL, !SU, !SHELLS - - Doesn't really prevent 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 - - - -1.7.4 July 21, 2010 24 - - - - - -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 - security issue for rules that subtract or revoke privileges. - - For example, given the following _s_u_d_o_e_r_s entry: - - john ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*, - /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root - - User jjoohhnn can still run /usr/bin/passwd root if _f_a_s_t___g_l_o_b is enabled by - changing to _/_u_s_r_/_b_i_n and running ./passwd root instead. - -PPRREEVVEENNTTIINNGG SSHHEELLLL EESSCCAAPPEESS - Once ssuuddoo executes a program, that program is free to do whatever it - pleases, including run other programs. This can be a security issue - since it is not uncommon for a program to allow shell escapes, which - lets a user bypass ssuuddoo's access control and logging. Common programs - that permit shell escapes include shells (obviously), editors, - paginators, mail and terminal programs. - - There are two basic approaches to this problem: - - restrict Avoid giving users access to commands that allow the user to - run arbitrary commands. Many editors have a restricted mode - where shell escapes are disabled, though ssuuddooeeddiitt is a better - solution to running editors via ssuuddoo. Due to the large - number of programs that offer shell escapes, restricting - users to the set of programs that do not if often unworkable. - - noexec Many systems that support shared libraries have the ability - to override default library functions by pointing an - environment variable (usually LD_PRELOAD) to an alternate - shared library. On such systems, ssuuddoo's _n_o_e_x_e_c functionality - can be used to prevent a program run by ssuuddoo from executing - any other programs. Note, however, that this applies only to - native dynamically-linked executables. Statically-linked - executables and foreign executables running under binary - emulation are not affected. - - To tell whether or not ssuuddoo supports _n_o_e_x_e_c, you can run the - following as root: - - sudo -V | grep "dummy exec" - - If the resulting output contains a line that begins with: - - File containing dummy exec functions: - - - - -1.7.4 July 21, 2010 25 - - - - - -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. - Check your operating system's manual pages for the dynamic - linker (usually ld.so, ld.so.1, dyld, dld.sl, rld, or loader) - to see if LD_PRELOAD is supported. - - To enable _n_o_e_x_e_c for a command, use the NOEXEC tag as - documented in the User Specification section above. Here is - that example again: - - aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi - - This allows user aaaarroonn to run _/_u_s_r_/_b_i_n_/_m_o_r_e and _/_u_s_r_/_b_i_n_/_v_i - with _n_o_e_x_e_c enabled. This will prevent those two commands - from executing other commands (such as a shell). If you are - unsure whether or not your system is capable of supporting - _n_o_e_x_e_c you can always just try it out and see if it works. - - Note that restricting shell escapes is not a panacea. Programs running - as root are still capable of many potentially hazardous operations - (such as changing or overwriting files) that could lead to unintended - privilege escalation. In the specific case of an editor, a safer - approach is to give the user permission to run ssuuddooeeddiitt. - -SSEEEE AALLSSOO - _r_s_h(1), _s_u(1), _f_n_m_a_t_c_h(3), _g_l_o_b(3), _s_u_d_o(1m), _v_i_s_u_d_o(8) - -CCAAVVEEAATTSS - The _s_u_d_o_e_r_s file should aallwwaayyss be edited by the vviissuuddoo command which - locks the file and does grammatical checking. It is imperative that - _s_u_d_o_e_r_s be free of syntax errors since ssuuddoo will not run with a - syntactically incorrect _s_u_d_o_e_r_s file. - - When using netgroups of machines (as opposed to users), if you store - fully qualified host name in the netgroup (as is usually the case), you - either need to have the machine's host name be fully qualified as - returned by the hostname command or use the _f_q_d_n option in _s_u_d_o_e_r_s. - -BBUUGGSS - If you feel you have found a bug in ssuuddoo, please submit a bug report at - http://www.sudo.ws/sudo/bugs/ - -SSUUPPPPOORRTT - Limited free support is available via the sudo-users mailing list, see - http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search - the archives. - - - - - -1.7.4 July 21, 2010 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 - merchantability and fitness for a particular purpose are disclaimed. - See the LICENSE file distributed with ssuuddoo or - http://www.sudo.ws/sudo/license.html for complete details. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -1.7.4 July 21, 2010 27 - - diff --git a/sudoers.in b/sudoers.in deleted file mode 100644 index 42e639e..0000000 --- a/sudoers.in +++ /dev/null @@ -1,90 +0,0 @@ -## sudoers file. -## -## This file MUST be edited with the 'visudo' command as root. -## Failure to use 'visudo' may result in syntax or file permission errors -## that prevent sudo from running. -## -## See the sudoers man page for the details on how to write a sudoers file. -## - -## -## Host alias specification -## -## Groups of machines. These may include host names (optionally with wildcards), -## IP addresses, network numbers or netgroups. -# Host_Alias WEBSERVERS = www1, www2, www3 - -## -## User alias specification -## -## Groups of users. These may consist of user names, uids, Unix groups, -## or netgroups. -# User_Alias ADMINS = millert, dowdy, mikef - -## -## Cmnd alias specification -## -## Groups of commands. Often used to group related commands together. -# Cmnd_Alias PROCESSES = /usr/bin/nice, /bin/kill, /usr/bin/renice, \ -# /usr/bin/pkill, /usr/bin/top - -## -## Defaults specification -## -## You may wish to keep some of the following environment variables -## when running commands via sudo. -## -## Locale settings -# Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET" -## -## Run X applications through sudo; HOME is used to find the -## .Xauthority file. Note that other programs use HOME to find -## configuration files and this may lead to privilege escalation! -# Defaults env_keep += "HOME" -## -## X11 resource path settings -# Defaults env_keep += "XAPPLRESDIR XFILESEARCHPATH XUSERFILESEARCHPATH" -## -## Desktop path settings -# Defaults env_keep += "QTDIR KDEDIR" -## -## Allow sudo-run commands to inherit the callers' ConsoleKit session -# Defaults env_keep += "XDG_SESSION_COOKIE" -## -## Uncomment to enable special input methods. Care should be taken as -## this may allow users to subvert the command being run via sudo. -# Defaults env_keep += "XMODIFIERS GTK_IM_MODULE QT_IM_MODULE QT_IM_SWITCHER" -## -## Uncomment to enable logging of a command's output, except for -## sudoreplay and reboot. Use sudoreplay to play back logged sessions. -# Defaults log_output -# Defaults!/usr/bin/sudoreplay !log_output -# Defaults!/usr/local/bin/sudoreplay !log_output -# Defaults!/sbin/reboot !log_output - -## -## Runas alias specification -## - -## -## User privilege specification -## -root ALL=(ALL) ALL - -## Uncomment to allow members of group wheel to execute any command -# %wheel ALL=(ALL) ALL - -## Same thing without a password -# %wheel ALL=(ALL) NOPASSWD: ALL - -## Uncomment to allow members of group sudo to execute any command -# %sudo ALL=(ALL) ALL - -## Uncomment to allow any user to run sudo if they know the password -## of the user they are running the command as (root by default). -# Defaults targetpw # Ask for the password of the target user -# ALL ALL=(ALL) ALL # WARNING: only use this together with 'Defaults targetpw' - -## Read drop-in files from @sysconfdir@/sudoers.d -## (the '#' here does not indicate a comment) -#includedir @sysconfdir@/sudoers.d diff --git a/sudoers.ldap.cat b/sudoers.ldap.cat deleted file mode 100644 index 20374d4..0000000 --- a/sudoers.ldap.cat +++ /dev/null @@ -1,792 +0,0 @@ - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - -NNAAMMEE - sudoers.ldap - sudo LDAP configuration - -DDEESSCCRRIIPPTTIIOONN - In addition to the standard _s_u_d_o_e_r_s file, ssuuddoo may be configured via - LDAP. This can be especially useful for synchronizing _s_u_d_o_e_r_s in a - large, distributed environment. - - Using LDAP for _s_u_d_o_e_r_s has several benefits: - - +o ssuuddoo no longer needs to read _s_u_d_o_e_r_s in its entirety. When LDAP is - used, there are only two or three LDAP queries per invocation. - This makes it especially fast and particularly usable in LDAP - environments. - - +o ssuuddoo no longer exits if there is a typo in _s_u_d_o_e_r_s. It is not - possible to load LDAP data into the server that does not conform to - the sudoers schema, so proper syntax is guaranteed. It is still - possible to have typos in a user or host name, but this will not - prevent ssuuddoo from running. - - +o It is possible to specify per-entry options that override the - global default options. _/_e_t_c_/_s_u_d_o_e_r_s only supports default options - and limited options associated with user/host/commands/aliases. - The syntax is complicated and can be difficult for users to - understand. Placing the options directly in the entry is more - natural. - - +o The vviissuuddoo program is no longer needed. vviissuuddoo provides locking - and syntax checking of the _/_e_t_c_/_s_u_d_o_e_r_s file. Since LDAP updates - are atomic, locking is no longer necessary. Because syntax is - checked when the data is inserted into LDAP, there is no need for a - specialized tool to check syntax. - - Another major difference between LDAP and file-based _s_u_d_o_e_r_s is that in - LDAP, ssuuddoo-specific Aliases are not supported. - - 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. - Since Unix groups and netgroups can also be stored in LDAP there is no - real need for ssuuddoo-specific aliases. - - Cmnd_Aliases are not really required either since it is possible to - have multiple users listed in a sudoRole. Instead of defining a - Cmnd_Alias that is referenced by multiple users, one can create a - sudoRole that contains the commands and assign multiple users to it. - - SSUUDDOOeerrss LLDDAAPP ccoonnttaaiinneerr - The _s_u_d_o_e_r_s configuration is contained in the ou=SUDOers LDAP - container. - - Sudo first looks for the cn=default entry in the SUDOers container. If - found, the multi-valued sudoOption attribute is parsed in the same - - - -1.7.4 July 12, 2010 1 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - manner as a global Defaults line in _/_e_t_c_/_s_u_d_o_e_r_s. In the following - example, the SSH_AUTH_SOCK variable will be preserved in the - environment for all users. - - dn: cn=defaults,ou=SUDOers,dc=example,dc=com - objectClass: top - objectClass: sudoRole - cn: defaults - description: Default sudoOption's go here - sudoOption: env_keep+=SSH_AUTH_SOCK - - The equivalent of a sudoer in LDAP is a sudoRole. It consists of the - following components: - - ssuuddooUUsseerr - A user name, uid (prefixed with '#'), Unix group (prefixed with a - '%') or user netgroup (prefixed with a '+'). - - ssuuddooHHoosstt - A host name, IP address, IP network, or host netgroup (prefixed - with a '+'). The special value ALL will match any host. - - ssuuddooCCoommmmaanndd - A Unix command with optional command line arguments, potentially - including globbing characters (aka wild cards). The special value - ALL will match any command. If a command is prefixed with an - exclamation point '!', the user will be prohibited from running - that command. - - ssuuddooOOppttiioonn - Identical in function to the global options described above, but - specific to the sudoRole in which it resides. - - ssuuddooRRuunnAAssUUsseerr - A user name or uid (prefixed with '#') that commands may be run as - or a Unix group (prefixed with a '%') or user netgroup (prefixed - with a '+') that contains a list of users that commands may be run - as. The special value ALL will match any user. - - 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: - - - - - - - - -1.7.4 July 12, 2010 2 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - dn: cn=%wheel,ou=SUDOers,dc=example,dc=com - objectClass: top - objectClass: sudoRole - cn: %wheel - sudoUser: %wheel - sudoHost: ALL - sudoCommand: ALL - - AAnnaattoommyy ooff LLDDAAPP ssuuddooeerrss llooookkuupp - When looking up a sudoer using LDAP there are only two or three LDAP - queries per invocation. The first query is to parse the global - options. The second is to match against the user's name and the groups - that the user belongs to. (The special ALL tag is matched in this - query too.) If no match is returned for the user's name and groups, a - third query returns all entries containing user netgroups and checks to - see if the user belongs to any of them. - - 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). - - Here is an example: - - # /etc/sudoers: - # Allow all commands except shell - johnny ALL=(root) ALL,!/bin/sh - # Always allows all commands because ALL is matched last - puddles ALL=(root) !/bin/sh,ALL - - # LDAP equivalent of johnny - # Allows all commands except shell - dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com - objectClass: sudoRole - objectClass: top - cn: role1 - sudoUser: johnny - sudoHost: ALL - sudoCommand: ALL - sudoCommand: !/bin/sh - - # LDAP equivalent of puddles - # Notice that even though ALL comes last, it still behaves like - # role1 since the LDAP code assumes the more paranoid configuration - dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com - objectClass: sudoRole - objectClass: top - cn: role2 - sudoUser: puddles - sudoHost: ALL - sudoCommand: !/bin/sh - - - -1.7.4 July 12, 2010 3 - - - - - -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. - - # does not match all but joe - # rather, does not match anyone - sudoUser: !joe - - # does not match all but joe - # rather, matches everyone including Joe - sudoUser: ALL - sudoUser: !joe - - # does not match all but web01 - # rather, matches all hosts including web01 - sudoHost: ALL - sudoHost: !web01 - - SSuuddooeerrss SScchheemmaa - In order to use ssuuddoo's LDAP support, the ssuuddoo schema must be installed - on your LDAP server. In addition, be sure to index the 'sudoUser' - attribute. - - Three versions of the schema: one for OpenLDAP servers - (_s_c_h_e_m_a_._O_p_e_n_L_D_A_P), one for Netscape-derived servers (_s_c_h_e_m_a_._i_P_l_a_n_e_t), - and one for Microsoft Active Directory (_s_c_h_e_m_a_._A_c_t_i_v_e_D_i_r_e_c_t_o_r_y) may be - found in the ssuuddoo distribution. - - The schema for ssuuddoo in OpenLDAP form is included in the EXAMPLES - section. - - CCoonnffiigguurriinngg llddaapp..ccoonnff - Sudo reads the _/_e_t_c_/_l_d_a_p_._c_o_n_f file for LDAP-specific configuration. - Typically, this file is shared amongst different LDAP-aware clients. - As such, most of the settings are not ssuuddoo-specific. Note that ssuuddoo - parses _/_e_t_c_/_l_d_a_p_._c_o_n_f itself and may support options that differ from - those described in the _l_d_a_p_._c_o_n_f(4) manual. - - Also note that on systems using the OpenLDAP libraries, default values - 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 - supported by ssuuddoo are honored. Configuration options are listed below - in upper case but are parsed in a case-independent manner. - - UURRII ldap[s]://[hostname[:port]] ... - Specifies a whitespace-delimited list of one or more URIs - describing the LDAP server(s) to connect to. The _p_r_o_t_o_c_o_l may be - 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, - - - -1.7.4 July 12, 2010 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 - include an optional _p_o_r_t separated by a colon (':'). The HHOOSSTT - parameter is deprecated in favor of the UURRII specification and is - included for backwards compatibility. - - PPOORRTT port_number - If no UURRII is specified, the PPOORRTT parameter specifies the default - port to connect to on the LDAP server if a HHOOSSTT parameter does not - specify the port itself. If no PPOORRTT parameter is used, the default - is port 389 for LDAP and port 636 for LDAP over TLS (SSL). The - PPOORRTT parameter is deprecated in favor of the UURRII specification and - is included for backwards compatibility. - - BBIINNDD__TTIIMMEELLIIMMIITT seconds - The BBIINNDD__TTIIMMEELLIIMMIITT parameter specifies the amount of time, in - seconds, to wait while trying to connect to an LDAP server. If - multiple UURRIIs or HHOOSSTTs are specified, this is the amount of time to - wait before trying the next one in the list. - - TTIIMMEELLIIMMIITT seconds - The TTIIMMEELLIIMMIITT parameter specifies the amount of time, in seconds, - to wait for a response to an LDAP query. - - 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__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.4 July 12, 2010 5 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - BBIINNDDPPWW secret - The BBIINNDDPPWW parameter specifies the password to use when performing - LDAP operations. This is typically used in conjunction with the - BBIINNDDDDNN parameter. - - RROOOOTTBBIINNDDDDNN DN - The RROOOOTTBBIINNDDDDNN parameter specifies the identity, in the form of a - Distinguished Name (DN), to use when performing privileged LDAP - operations, such as _s_u_d_o_e_r_s queries. The password corresponding to - the identity should be stored in _/_e_t_c_/_l_d_a_p_._s_e_c_r_e_t. If not - specified, the BBIINNDDDDNN identity is used (if any). - - LLDDAAPP__VVEERRSSIIOONN number - The version of the LDAP protocol to use when connecting to the - server. The default value is protocol version 3. - - SSSSLL on/true/yes/off/false/no - If the SSSSLL parameter is set to on, true or yes, TLS (SSL) - encryption is always used when communicating with the LDAP server. - Typically, this involves connecting to the server on port 636 - (ldaps). - - SSSSLL start_tls - If the SSSSLL parameter is set to start_tls, the LDAP server - connection is initiated normally and TLS encryption is begun before - the bind credentials are sent. This has the advantage of not - requiring a dedicated port for encrypted communications. This - parameter is only supported by LDAP servers that honor the - start_tls extension, such as the OpenLDAP server. - - TTLLSS__CCHHEECCKKPPEEEERR on/true/yes/off/false/no - If enabled, TTLLSS__CCHHEECCKKPPEEEERR will cause the LDAP server's TLS - certificated to be verified. If the server's TLS certificate - cannot be verified (usually because it is signed by an unknown - certificate authority), ssuuddoo will be unable to connect to it. If - TTLLSS__CCHHEECCKKPPEEEERR is disabled, no check is made. Note that disabling - the check creates an opportunity for man-in-the-middle attacks - since the server's identity will not be authenticated. If - possible, the CA's certificate should be installed locally so it - can be verified. - - TTLLSS__CCAACCEERRTT file name - An alias for TTLLSS__CCAACCEERRTTFFIILLEE. - - 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 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - 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 - OpenLDAP libraries. - - TTLLSS__CCEERRTT file name - The path to a file containing the client certificate which can be - used to authenticate the client to the LDAP server. The - certificate type depends on the LDAP libraries used. - - OpenLDAP: - tls_cert /etc/ssl/client_cert.pem - - Netscape-derived: - tls_cert /var/ldap/cert7.db - - When using Netscape-derived libraries, this file may also contain - Certificate Authority certificates. - - TTLLSS__KKEEYY file name - The path to a file containing the private key which matches the - certificate specified by TTLLSS__CCEERRTT. The private key must not be - password-protected. The key type depends on the LDAP libraries - used. - - OpenLDAP: - tls_key /etc/ssl/client_key.pem - - Netscape-derived: - tls_key /var/ldap/key3.db - - TTLLSS__RRAANNDDFFIILLEE file name - The TTLLSS__RRAANNDDFFIILLEE parameter specifies the path to an entropy source - for systems that lack a random device. It is generally used in - conjunction with _p_r_n_g_d or _e_g_d. This option is only supported by - the OpenLDAP libraries. - - TTLLSS__CCIIPPHHEERRSS cipher list - The TTLLSS__CCIIPPHHEERRSS parameter allows the administer to restrict which - encryption algorithms may be used for TLS (SSL) connections. See - the OpenSSL manual for a list of valid ciphers. This option is - only supported by the OpenLDAP libraries. - - 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.4 July 12, 2010 7 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - RROOOOTTSSAASSLL__AAUUTTHH__IIDD identity - The SASL user name to use when RROOOOTTUUSSEE__SSAASSLL is enabled. - - SSAASSLL__SSEECCPPRROOPPSS none/properties - SASL security properties or _n_o_n_e for no properties. See the SASL - programmer's manual for details. - - KKRRBB55__CCCCNNAAMMEE file name - The path to the Kerberos 5 credential cache to use when - authenticating with the remote server. - - See the ldap.conf entry in the EXAMPLES section. - - CCoonnffiigguurriinngg nnsssswwiittcchh..ccoonnff - Unless it is disabled at build time, ssuuddoo consults the Name Service - Switch file, _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f, to specify the _s_u_d_o_e_r_s search order. - Sudo looks for a line beginning with sudoers: and uses this to - determine the search order. Note that ssuuddoo does not stop searching - after the first match and later matches take precedence over earlier - ones. - - The following sources are recognized: - - files read sudoers from F - ldap read sudoers from LDAP - - In addition, the entry [NOTFOUND=return] will short-circuit the search - if the user was not found in the preceding source. - - To consult LDAP first followed by the local sudoers file (if it - exists), use: - - sudoers: ldap files - - The local _s_u_d_o_e_r_s file can be ignored completely by using: - - sudoers: ldap - - If the _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f file is not present or there is no sudoers - line, the following default is assumed: - - 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.4 July 12, 2010 8 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - sudoers = ldap, files - - The local _s_u_d_o_e_r_s file can be ignored completely by using: - - sudoers = ldap - - To treat LDAP as authoratative and only use the local sudoers file if - the user is not present in LDAP, use: - - sudoers = ldap = auth, files - - Note that in the above example, the auth qualfier only affects user - lookups; both LDAP and _s_u_d_o_e_r_s will be queried for Defaults entries. - - If the _/_e_t_c_/_n_e_t_s_v_c_._c_o_n_f file is not present or there is no sudoers - line, the following default is assumed: - - sudoers = files - -FFIILLEESS - _/_e_t_c_/_l_d_a_p_._c_o_n_f LDAP configuration file - - _/_e_t_c_/_n_s_s_w_i_t_c_h_._c_o_n_f determines sudoers source order - - _/_e_t_c_/_n_e_t_s_v_c_._c_o_n_f determines sudoers source order on AIX - -EEXXAAMMPPLLEESS - EExxaammppllee llddaapp..ccoonnff - # Either specify one or more URIs or one or more host:port pairs. - # If neither is specified sudo will default to localhost, port 389. - # - #host ldapserver - #host ldapserver1 ldapserver2:390 - # - # Default port if host is specified without one, defaults to 389. - #port 389 - # - # URI will override the host and port settings. - uri ldap://ldapserver - #uri ldaps://secureldapserver - #uri ldaps://secureldapserver ldap://ldapserver - # - # The amount of time, in seconds, to wait while trying to connect to - # an LDAP server. - bind_timelimit 30 - # - # The amount of time, in seconds, to wait while performing an LDAP query. - timelimit 30 - # - # Must be set or sudo will ignore LDAP; may be specified multiple times. - sudoers_base ou=SUDOers,dc=example,dc=com - # - # verbose sudoers matching from ldap - #sudoers_debug 2 - - - -1.7.4 July 12, 2010 9 - - - - - -SUDOERS.LDAP(4) MAINTENANCE COMMANDS SUDOERS.LDAP(4) - - - # - # optional proxy credentials - #binddn - #bindpw - #rootbinddn - # - # LDAP protocol version, defaults to 3 - #ldap_version 3 - # - # Define if you want to use an encrypted LDAP connection. - # Typically, you must also set the port to 636 (ldaps). - #ssl on - # - # Define if you want to use port 389 and switch to - # encryption before the bind credentials are sent. - # Only supported by LDAP servers that support the start_tls - # extension such as OpenLDAP. - #ssl start_tls - # - # Additional TLS options follow that allow tweaking of the - # SSL/TLS connection. - # - #tls_checkpeer yes # verify server SSL certificate - #tls_checkpeer no # ignore server SSL certificate - # - # If you enable tls_checkpeer, specify either tls_cacertfile - # or tls_cacertdir. Only supported when using OpenLDAP. - # - #tls_cacertfile /etc/certs/trusted_signers.pem - #tls_cacertdir /etc/certs - # - # For systems that don't have /dev/random - # use this along with PRNGD or EGD.pl to seed the - # random number pool to generate cryptographic session keys. - # Only supported when using OpenLDAP. - # - #tls_randfile /etc/egd-pool - # - # You may restrict which ciphers are used. Consult your SSL - # documentation for which options go here. - # Only supported when using OpenLDAP. - # - #tls_ciphers - # - # Sudo can provide a client certificate when communicating to - # the LDAP server. - # Tips: - # * Enable both lines at the same time. - # * Do not password protect the key file. - # * Ensure the keyfile is only readable by root. - # - # For OpenLDAP: - #tls_cert /etc/certs/client_cert.pem - #tls_key /etc/certs/client_key.pem - - - -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 - # default names (e.g. cert8.db and key4.db), or the path to the cert - # and key files themselves. However, a bug in version 5.0 of the LDAP - # SDK will prevent specific file names from working. For this reason - # it is suggested that tls_cert and tls_key be set to a directory, - # not a file name. - # - # The certificate database specified by tls_cert may contain CA certs - # and/or the client's cert. If the client's cert is included, tls_key - # should be specified as well. - # For backward compatibility, "sslpath" may be used in place of tls_cert. - #tls_cert /var/ldap - #tls_key /var/ldap - # - # If using SASL authentication for LDAP (OpenSSL) - # use_sasl yes - # sasl_auth_id - # rootuse_sasl yes - # rootsasl_auth_id - # sasl_secprops none - # krb5_ccname /etc/.ldapcache - - SSuuddoo sscchheemmaa ffoorr OOppeennLLDDAAPP - The following schema is in OpenLDAP format. 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. - - attributetype ( 1.3.6.1.4.1.15953.9.1.1 - NAME 'sudoUser' - DESC 'User(s) who may run sudo' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.2 - NAME 'sudoHost' - DESC 'Host(s) who may run sudo' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.3 - NAME 'sudoCommand' - DESC 'Command(s) to be executed by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.4 - NAME 'sudoRunAs' - DESC 'User(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - - -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' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.6 - NAME 'sudoRunAsUser' - DESC 'User(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.7 - NAME 'sudoRunAsGroup' - DESC 'Group(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL - DESC 'Sudoer Entries' - MUST ( cn ) - MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ - sudoRunAsGroup $ sudoOption $ description ) - ) - -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. - -BBUUGGSS - If you feel you have found a bug in ssuuddoo, please submit a bug report at - http://www.sudo.ws/sudo/bugs/ - -SSUUPPPPOORRTT - Limited free support is available via the sudo-users mailing list, see - http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search - the archives. - -DDIISSCCLLAAIIMMEERR - ssuuddoo is provided ``AS IS'' and any express or implied warranties, - including, but not limited to, the implied warranties of - merchantability and fitness for a particular purpose are disclaimed. - See the LICENSE file distributed with ssuuddoo or - http://www.sudo.ws/sudo/license.html for complete details. - - - - - - - -1.7.4 July 12, 2010 12 - - diff --git a/sudoers.ldap.man.in b/sudoers.ldap.man.in deleted file mode 100644 index 66a1b03..0000000 --- a/sudoers.ldap.man.in +++ /dev/null @@ -1,826 +0,0 @@ -.\" Copyright (c) 2003-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. -.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` -. ds C' -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "SUDOERS.LDAP @mansectform@" -.TH SUDOERS.LDAP @mansectform@ "July 12, 2010" "1.7.4" "MAINTENANCE COMMANDS" -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -sudoers.ldap \- sudo LDAP configuration -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -In addition to the standard \fIsudoers\fR file, \fBsudo\fR may be configured -via \s-1LDAP\s0. This can be especially useful for synchronizing \fIsudoers\fR -in a large, distributed environment. -.PP -Using \s-1LDAP\s0 for \fIsudoers\fR has several benefits: -.IP "\(bu" 4 -\&\fBsudo\fR no longer needs to read \fIsudoers\fR in its entirety. When -\&\s-1LDAP\s0 is used, there are only two or three \s-1LDAP\s0 queries per invocation. -This makes it especially fast and particularly usable in \s-1LDAP\s0 -environments. -.IP "\(bu" 4 -\&\fBsudo\fR no longer exits if there is a typo in \fIsudoers\fR. -It is not possible to load \s-1LDAP\s0 data into the server that does -not conform to the sudoers schema, so proper syntax is guaranteed. -It is still possible to have typos in a user or host name, but -this will not prevent \fBsudo\fR from running. -.IP "\(bu" 4 -It is possible to specify per-entry options that override the global -default options. \fI@sysconfdir@/sudoers\fR only supports default options and -limited options associated with user/host/commands/aliases. The -syntax is complicated and can be difficult for users to understand. -Placing the options directly in the entry is more natural. -.IP "\(bu" 4 -The \fBvisudo\fR program is no longer needed. \fBvisudo\fR provides -locking and syntax checking of the \fI@sysconfdir@/sudoers\fR file. -Since \s-1LDAP\s0 updates are atomic, locking is no longer necessary. -Because syntax is checked when the data is inserted into \s-1LDAP\s0, there -is no need for a specialized tool to check syntax. -.PP -Another major difference between \s-1LDAP\s0 and file-based \fIsudoers\fR -is that in \s-1LDAP\s0, \fBsudo\fR\-specific Aliases are not supported. -.PP -For the most part, there is really no need for \fBsudo\fR\-specific -Aliases. Unix groups or user netgroups can be used in place of -User_Aliases and RunasAliases. Host netgroups can be used in place -of HostAliases. Since Unix groups and netgroups can also be stored -in \s-1LDAP\s0 there is no real need for \fBsudo\fR\-specific aliases. -.PP -Cmnd_Aliases are not really required either since it is possible -to have multiple users listed in a sudoRole. Instead of defining -a Cmnd_Alias that is referenced by multiple users, one can create -a sudoRole that contains the commands and assign multiple users -to it. -.SS "SUDOers \s-1LDAP\s0 container" -.IX Subsection "SUDOers LDAP container" -The \fIsudoers\fR configuration is contained in the \f(CW\*(C`ou=SUDOers\*(C'\fR \s-1LDAP\s0 -container. -.PP -Sudo first looks for the \f(CW\*(C`cn=default\*(C'\fR entry in the SUDOers container. -If found, the multi-valued \f(CW\*(C`sudoOption\*(C'\fR attribute is parsed in the -same manner as a global \f(CW\*(C`Defaults\*(C'\fR line in \fI@sysconfdir@/sudoers\fR. In -the following example, the \f(CW\*(C`SSH_AUTH_SOCK\*(C'\fR variable will be preserved -in the environment for all users. -.PP -.Vb 6 -\& dn: cn=defaults,ou=SUDOers,dc=example,dc=com -\& objectClass: top -\& objectClass: sudoRole -\& cn: defaults -\& description: Default sudoOption\*(Aqs go here -\& sudoOption: env_keep+=SSH_AUTH_SOCK -.Ve -.PP -The equivalent of a sudoer in \s-1LDAP\s0 is a \f(CW\*(C`sudoRole\*(C'\fR. It consists of -the following components: -.IP "\fBsudoUser\fR" 4 -.IX Item "sudoUser" -A user name, uid (prefixed with \f(CW\*(Aq#\*(Aq\fR), Unix group (prefixed with -a \f(CW\*(Aq%\*(Aq\fR) or user netgroup (prefixed with a \f(CW\*(Aq+\*(Aq\fR). -.IP "\fBsudoHost\fR" 4 -.IX Item "sudoHost" -A host name, \s-1IP\s0 address, \s-1IP\s0 network, or host netgroup (prefixed -with a \f(CW\*(Aq+\*(Aq\fR). -The special value \f(CW\*(C`ALL\*(C'\fR will match any host. -.IP "\fBsudoCommand\fR" 4 -.IX Item "sudoCommand" -A Unix command with optional command line arguments, potentially -including globbing characters (aka wild cards). -The special value \f(CW\*(C`ALL\*(C'\fR will match any command. -If a command is prefixed with an exclamation point \f(CW\*(Aq!\*(Aq\fR, the -user will be prohibited from running that command. -.IP "\fBsudoOption\fR" 4 -.IX Item "sudoOption" -Identical in function to the global options described above, but -specific to the \f(CW\*(C`sudoRole\*(C'\fR in which it resides. -.IP "\fBsudoRunAsUser\fR" 4 -.IX Item "sudoRunAsUser" -A user name or uid (prefixed with \f(CW\*(Aq#\*(Aq\fR) that commands may be run -as or a Unix group (prefixed with a \f(CW\*(Aq%\*(Aq\fR) or user netgroup (prefixed -with a \f(CW\*(Aq+\*(Aq\fR) that contains a list of users that commands may be -run as. -The special value \f(CW\*(C`ALL\*(C'\fR will match any user. -.IP "\fBsudoRunAsGroup\fR" 4 -.IX Item "sudoRunAsGroup" -A Unix group or gid (prefixed with \f(CW\*(Aq#\*(Aq\fR) that commands may be run as. -The special value \f(CW\*(C`ALL\*(C'\fR will match any group. -.PP -Each component listed above should contain a single value, but there -may be multiple instances of each component type. A sudoRole must -contain at least one \f(CW\*(C`sudoUser\*(C'\fR, \f(CW\*(C`sudoHost\*(C'\fR and \f(CW\*(C`sudoCommand\*(C'\fR. -.PP -The following example allows users in group wheel to run any command -on any host via \fBsudo\fR: -.PP -.Vb 7 -\& dn: cn=%wheel,ou=SUDOers,dc=example,dc=com -\& objectClass: top -\& objectClass: sudoRole -\& cn: %wheel -\& sudoUser: %wheel -\& sudoHost: ALL -\& sudoCommand: ALL -.Ve -.SS "Anatomy of \s-1LDAP\s0 sudoers lookup" -.IX Subsection "Anatomy of LDAP sudoers lookup" -When looking up a sudoer using \s-1LDAP\s0 there are only two or three -\&\s-1LDAP\s0 queries per invocation. The first query is to parse the global -options. The second is to match against the user's name and the -groups that the user belongs to. (The special \s-1ALL\s0 tag is matched -in this query too.) If no match is returned for the user's name -and groups, a third query returns all entries containing user -netgroups and checks to see if the user belongs to any of them. -.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. -This is called paranoid behavior (not necessarily the most specific -match). -.PP -Here is an example: -.PP -.Vb 5 -\& # /etc/sudoers: -\& # Allow all commands except shell -\& johnny ALL=(root) ALL,!/bin/sh -\& # Always allows all commands because ALL is matched last -\& puddles ALL=(root) !/bin/sh,ALL -\& -\& # LDAP equivalent of johnny -\& # Allows all commands except shell -\& dn: cn=role1,ou=Sudoers,dc=my\-domain,dc=com -\& objectClass: sudoRole -\& objectClass: top -\& cn: role1 -\& sudoUser: johnny -\& sudoHost: ALL -\& sudoCommand: ALL -\& sudoCommand: !/bin/sh -\& -\& # LDAP equivalent of puddles -\& # Notice that even though ALL comes last, it still behaves like -\& # role1 since the LDAP code assumes the more paranoid configuration -\& dn: cn=role2,ou=Sudoers,dc=my\-domain,dc=com -\& objectClass: sudoRole -\& objectClass: top -\& cn: role2 -\& sudoUser: puddles -\& sudoHost: ALL -\& sudoCommand: !/bin/sh -\& sudoCommand: ALL -.Ve -.PP -Another difference is that negations on the Host, User or Runas are -currently ignorred. For example, the following attributes do not -behave the way one might expect. -.PP -.Vb 3 -\& # does not match all but joe -\& # rather, does not match anyone -\& sudoUser: !joe -\& -\& # does not match all but joe -\& # rather, matches everyone including Joe -\& sudoUser: ALL -\& sudoUser: !joe -\& -\& # does not match all but web01 -\& # rather, matches all hosts including web01 -\& sudoHost: ALL -\& sudoHost: !web01 -.Ve -.SS "Sudoers Schema" -.IX Subsection "Sudoers Schema" -In order to use \fBsudo\fR's \s-1LDAP\s0 support, the \fBsudo\fR schema must be -installed on your \s-1LDAP\s0 server. In addition, be sure to index the -\&'sudoUser' attribute. -.PP -Three versions of the schema: one for OpenLDAP servers (\fIschema.OpenLDAP\fR), -one for Netscape-derived servers (\fIschema.iPlanet\fR), and one for -Microsoft Active Directory (\fIschema.ActiveDirectory\fR) may -be found in the \fBsudo\fR distribution. -.PP -The schema for \fBsudo\fR in OpenLDAP form is included in the \s-1EXAMPLES\s0 -section. -.SS "Configuring ldap.conf" -.IX Subsection "Configuring ldap.conf" -Sudo reads the \fI@ldap_conf@\fR file for LDAP-specific configuration. -Typically, this file is shared amongst different LDAP-aware clients. -As such, most of the settings are not \fBsudo\fR\-specific. Note that -\&\fBsudo\fR parses \fI@ldap_conf@\fR itself and may support options -that differ from those described in the \fIldap.conf\fR\|(@mansectform@) manual. -.PP -Also note that on systems using the OpenLDAP libraries, default -values specified in \fI/etc/openldap/ldap.conf\fR or the user's -\&\fI.ldaprc\fR files are not used. -.PP -Only those options explicitly listed in \fI@ldap_conf@\fR that are -supported by \fBsudo\fR are honored. Configuration options are listed -below in upper case but are parsed in a case-independent manner. -.IP "\fB\s-1URI\s0\fR ldap[s]://[hostname[:port]] ..." 4 -.IX Item "URI ldap[s]://[hostname[:port]] ..." -Specifies a whitespace-delimited list of one or more URIs describing -the \s-1LDAP\s0 server(s) to connect to. The \fIprotocol\fR may be either -\&\fBldap\fR or \fBldaps\fR, the latter being for servers that support \s-1TLS\s0 -(\s-1SSL\s0) encryption. If no \fIport\fR is specified, the default is port -389 for \f(CW\*(C`ldap://\*(C'\fR or port 636 for \f(CW\*(C`ldaps://\*(C'\fR. If no \fIhostname\fR -is specified, \fBsudo\fR will connect to \fBlocalhost\fR. Multiple \fB\s-1URI\s0\fR -lines are treated identically to a \fB\s-1URI\s0\fR line containing multiple -entries. Only systems using the OpenSSL libraries support the -mixing of \f(CW\*(C`ldap://\*(C'\fR and \f(CW\*(C`ldaps://\*(C'\fR URIs. The Netscape-derived -libraries used on most commercial versions of Unix are only capable -of supporting one or the other. -.IP "\fB\s-1HOST\s0\fR name[:port] ..." 4 -.IX Item "HOST name[:port] ..." -If no \fB\s-1URI\s0\fR is specified, the \fB\s-1HOST\s0\fR parameter specifies a -whitespace-delimited list of \s-1LDAP\s0 servers to connect to. Each host -may include an optional \fIport\fR separated by a colon (':'). The -\&\fB\s-1HOST\s0\fR parameter is deprecated in favor of the \fB\s-1URI\s0\fR specification -and is included for backwards compatibility. -.IP "\fB\s-1PORT\s0\fR port_number" 4 -.IX Item "PORT port_number" -If no \fB\s-1URI\s0\fR is specified, the \fB\s-1PORT\s0\fR parameter specifies the -default port to connect to on the \s-1LDAP\s0 server if a \fB\s-1HOST\s0\fR parameter -does not specify the port itself. If no \fB\s-1PORT\s0\fR parameter is used, -the default is port 389 for \s-1LDAP\s0 and port 636 for \s-1LDAP\s0 over \s-1TLS\s0 -(\s-1SSL\s0). The \fB\s-1PORT\s0\fR parameter is deprecated in favor of the \fB\s-1URI\s0\fR -specification and is included for backwards compatibility. -.IP "\fB\s-1BIND_TIMELIMIT\s0\fR seconds" 4 -.IX Item "BIND_TIMELIMIT seconds" -The \fB\s-1BIND_TIMELIMIT\s0\fR parameter specifies the amount of time, in seconds, -to wait while trying to connect to an \s-1LDAP\s0 server. If multiple \fB\s-1URI\s0\fRs or -\&\fB\s-1HOST\s0\fRs are specified, this is the amount of time to wait before trying -the next one in the list. -.IP "\fB\s-1TIMELIMIT\s0\fR seconds" 4 -.IX Item "TIMELIMIT seconds" -The \fB\s-1TIMELIMIT\s0\fR parameter specifies the amount of time, in seconds, -to wait for a response to an \s-1LDAP\s0 query. -.IP "\fB\s-1SUDOERS_BASE\s0\fR base" 4 -.IX Item "SUDOERS_BASE base" -The base \s-1DN\s0 to use when performing \fBsudo\fR \s-1LDAP\s0 queries. Typically -this is of the form \f(CW\*(C`ou=SUDOers,dc=example,dc=com\*(C'\fR for the domain -\&\f(CW\*(C`example.com\*(C'\fR. 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_DEBUG\s0\fR debug_level" 4 -.IX Item "SUDOERS_DEBUG debug_level" -This sets the debug level for \fBsudo\fR \s-1LDAP\s0 queries. Debugging -information is printed to the standard error. A value of 1 results -in a moderate amount of debugging information. A value of 2 shows -the results of the matches themselves. This parameter should not -be set in a production environment as the extra information is -likely to confuse users. -.IP "\fB\s-1BINDDN\s0\fR \s-1DN\s0" 4 -.IX Item "BINDDN DN" -The \fB\s-1BINDDN\s0\fR parameter specifies the identity, in the form of a -Distinguished Name (\s-1DN\s0), to use when performing \s-1LDAP\s0 operations. -If not specified, \s-1LDAP\s0 operations are performed with an anonymous -identity. By default, most \s-1LDAP\s0 servers will allow anonymous access. -.IP "\fB\s-1BINDPW\s0\fR secret" 4 -.IX Item "BINDPW secret" -The \fB\s-1BINDPW\s0\fR parameter specifies the password to use when performing -\&\s-1LDAP\s0 operations. This is typically used in conjunction with the -\&\fB\s-1BINDDN\s0\fR parameter. -.IP "\fB\s-1ROOTBINDDN\s0\fR \s-1DN\s0" 4 -.IX Item "ROOTBINDDN DN" -The \fB\s-1ROOTBINDDN\s0\fR parameter specifies the identity, in the form of -a Distinguished Name (\s-1DN\s0), to use when performing privileged \s-1LDAP\s0 -operations, such as \fIsudoers\fR queries. The password corresponding -to the identity should be stored in \fI@ldap_secret@\fR. -If not specified, the \fB\s-1BINDDN\s0\fR identity is used (if any). -.IP "\fB\s-1LDAP_VERSION\s0\fR number" 4 -.IX Item "LDAP_VERSION number" -The version of the \s-1LDAP\s0 protocol to use when connecting to the server. -The default value is protocol version 3. -.IP "\fB\s-1SSL\s0\fR on/true/yes/off/false/no" 4 -.IX Item "SSL on/true/yes/off/false/no" -If the \fB\s-1SSL\s0\fR parameter is set to \f(CW\*(C`on\*(C'\fR, \f(CW\*(C`true\*(C'\fR or \f(CW\*(C`yes\*(C'\fR, \s-1TLS\s0 -(\s-1SSL\s0) encryption is always used when communicating with the \s-1LDAP\s0 -server. Typically, this involves connecting to the server on port -636 (ldaps). -.IP "\fB\s-1SSL\s0\fR start_tls" 4 -.IX Item "SSL start_tls" -If the \fB\s-1SSL\s0\fR parameter is set to \f(CW\*(C`start_tls\*(C'\fR, the \s-1LDAP\s0 server -connection is initiated normally and \s-1TLS\s0 encryption is begun before -the bind credentials are sent. This has the advantage of not -requiring a dedicated port for encrypted communications. This -parameter is only supported by \s-1LDAP\s0 servers that honor the \f(CW\*(C`start_tls\*(C'\fR -extension, such as the OpenLDAP server. -.IP "\fB\s-1TLS_CHECKPEER\s0\fR on/true/yes/off/false/no" 4 -.IX Item "TLS_CHECKPEER on/true/yes/off/false/no" -If enabled, \fB\s-1TLS_CHECKPEER\s0\fR will cause the \s-1LDAP\s0 server's \s-1TLS\s0 -certificated to be verified. If the server's \s-1TLS\s0 certificate cannot -be verified (usually because it is signed by an unknown certificate -authority), \fBsudo\fR will be unable to connect to it. If \fB\s-1TLS_CHECKPEER\s0\fR -is disabled, no check is made. Note that disabling the check creates -an opportunity for man-in-the-middle attacks since the server's -identity will not be authenticated. If possible, the \s-1CA\s0's certificate -should be installed locally so it can be verified. -.IP "\fB\s-1TLS_CACERT\s0\fR file name" 4 -.IX Item "TLS_CACERT file name" -An alias for \fB\s-1TLS_CACERTFILE\s0\fR. -.IP "\fB\s-1TLS_CACERTFILE\s0\fR file name" 4 -.IX Item "TLS_CACERTFILE file name" -The path to a certificate authority bundle which contains the certificates -for all the Certificate Authorities the client knows to be valid, -e.g. \fI/etc/ssl/ca\-bundle.pem\fR. -This option is only supported by the OpenLDAP libraries. -Netscape-derived \s-1LDAP\s0 libraries use the same certificate -database for \s-1CA\s0 and client certificates (see \fB\s-1TLS_CERT\s0\fR). -.IP "\fB\s-1TLS_CACERTDIR\s0\fR directory" 4 -.IX Item "TLS_CACERTDIR directory" -Similar to \fB\s-1TLS_CACERTFILE\s0\fR but instead of a file, it is a -directory containing individual Certificate Authority certificates, -e.g. \fI/etc/ssl/certs\fR. -The directory specified by \fB\s-1TLS_CACERTDIR\s0\fR is checked after -\&\fB\s-1TLS_CACERTFILE\s0\fR. -This option is only supported by the OpenLDAP libraries. -.IP "\fB\s-1TLS_CERT\s0\fR file name" 4 -.IX Item "TLS_CERT file name" -The path to a file containing the client certificate which can -be used to authenticate the client to the \s-1LDAP\s0 server. -The certificate type depends on the \s-1LDAP\s0 libraries used. -.Sp -OpenLDAP: - \f(CW\*(C`tls_cert /etc/ssl/client_cert.pem\*(C'\fR -.Sp -Netscape-derived: - \f(CW\*(C`tls_cert /var/ldap/cert7.db\*(C'\fR -.Sp -When using Netscape-derived libraries, this file may also contain -Certificate Authority certificates. -.IP "\fB\s-1TLS_KEY\s0\fR file name" 4 -.IX Item "TLS_KEY file name" -The path to a file containing the private key which matches the -certificate specified by \fB\s-1TLS_CERT\s0\fR. The private key must not be -password-protected. The key type depends on the \s-1LDAP\s0 libraries -used. -.Sp -OpenLDAP: - \f(CW\*(C`tls_key /etc/ssl/client_key.pem\*(C'\fR -.Sp -Netscape-derived: - \f(CW\*(C`tls_key /var/ldap/key3.db\*(C'\fR -.IP "\fB\s-1TLS_RANDFILE\s0\fR file name" 4 -.IX Item "TLS_RANDFILE file name" -The \fB\s-1TLS_RANDFILE\s0\fR parameter specifies the path to an entropy -source for systems that lack a random device. It is generally used -in conjunction with \fIprngd\fR or \fIegd\fR. -This option is only supported by the OpenLDAP libraries. -.IP "\fB\s-1TLS_CIPHERS\s0\fR cipher list" 4 -.IX Item "TLS_CIPHERS cipher list" -The \fB\s-1TLS_CIPHERS\s0\fR parameter allows the administer to restrict -which encryption algorithms may be used for \s-1TLS\s0 (\s-1SSL\s0) connections. -See the OpenSSL manual for a list of valid ciphers. -This option is only supported by the OpenLDAP libraries. -.IP "\fB\s-1USE_SASL\s0\fR on/true/yes/off/false/no" 4 -.IX Item "USE_SASL on/true/yes/off/false/no" -Enable \fB\s-1USE_SASL\s0\fR for \s-1LDAP\s0 servers that support \s-1SASL\s0 authentication. -.IP "\fB\s-1SASL_AUTH_ID\s0\fR identity" 4 -.IX Item "SASL_AUTH_ID identity" -The \s-1SASL\s0 user name to use when connecting to the \s-1LDAP\s0 server. -By default, \fBsudo\fR will use an anonymous connection. -.IP "\fB\s-1ROOTUSE_SASL\s0\fR on/true/yes/off/false/no" 4 -.IX Item "ROOTUSE_SASL on/true/yes/off/false/no" -Enable \fB\s-1ROOTUSE_SASL\s0\fR to enable \s-1SASL\s0 authentication when connecting -to an \s-1LDAP\s0 server from a privileged process, such as \fBsudo\fR. -.IP "\fB\s-1ROOTSASL_AUTH_ID\s0\fR identity" 4 -.IX Item "ROOTSASL_AUTH_ID identity" -The \s-1SASL\s0 user name to use when \fB\s-1ROOTUSE_SASL\s0\fR is enabled. -.IP "\fB\s-1SASL_SECPROPS\s0\fR none/properties" 4 -.IX Item "SASL_SECPROPS none/properties" -\&\s-1SASL\s0 security properties or \fInone\fR for no properties. See the -\&\s-1SASL\s0 programmer's manual for details. -.IP "\fB\s-1KRB5_CCNAME\s0\fR file name" 4 -.IX Item "KRB5_CCNAME file name" -The path to the Kerberos 5 credential cache to use when authenticating -with the remote server. -.PP -See the \f(CW\*(C`ldap.conf\*(C'\fR entry in the \s-1EXAMPLES\s0 section. -.SS "Configuring nsswitch.conf" -.IX Subsection "Configuring nsswitch.conf" -Unless it is disabled at build time, \fBsudo\fR consults the Name -Service Switch file, \fI@nsswitch_conf@\fR, to specify the \fIsudoers\fR -search order. Sudo looks for a line beginning with \f(CW\*(C`sudoers\*(C'\fR: and -uses this to determine the search order. Note that \fBsudo\fR does -not stop searching after the first match and later matches take -precedence over earlier ones. -.PP -The following sources are recognized: -.PP -.Vb 2 -\& files read sudoers from F<@sysconfdir@/sudoers> -\& ldap read sudoers from LDAP -.Ve -.PP -In addition, the entry \f(CW\*(C`[NOTFOUND=return]\*(C'\fR will short-circuit the -search if the user was not found in the preceding source. -.PP -To consult \s-1LDAP\s0 first followed by the local sudoers file (if it -exists), use: -.PP -.Vb 1 -\& sudoers: ldap files -.Ve -.PP -The local \fIsudoers\fR file can be ignored completely by using: -.PP -.Vb 1 -\& sudoers: ldap -.Ve -.PP -If the \fI@nsswitch_conf@\fR file is not present or there is no -sudoers line, the following default is assumed: -.PP -.Vb 1 -\& sudoers: files -.Ve -.PP -Note that \fI@nsswitch_conf@\fR is supported even when the underlying -operating system does not use an nsswitch.conf file. -.SS "Configuring netsvc.conf" -.IX Subsection "Configuring netsvc.conf" -On \s-1AIX\s0 systems, the \fI@netsvc_conf@\fR file is consulted instead of -\&\fI@nsswitch_conf@\fR. \fBsudo\fR simply treats \fInetsvc.conf\fR as a -variant of \fInsswitch.conf\fR; information in the previous section -unrelated to the file format itself still applies. -.PP -To consult \s-1LDAP\s0 first followed by the local sudoers file (if it -exists), use: -.PP -.Vb 1 -\& sudoers = ldap, files -.Ve -.PP -The local \fIsudoers\fR file can be ignored completely by using: -.PP -.Vb 1 -\& sudoers = ldap -.Ve -.PP -To treat \s-1LDAP\s0 as authoratative and only use the local sudoers file -if the user is not present in \s-1LDAP\s0, use: -.PP -.Vb 1 -\& sudoers = ldap = auth, files -.Ve -.PP -Note that in the above example, the \f(CW\*(C`auth\*(C'\fR qualfier only affects -user lookups; both \s-1LDAP\s0 and \fIsudoers\fR will be queried for \f(CW\*(C`Defaults\*(C'\fR -entries. -.PP -If the \fI@netsvc_conf@\fR file is not present or there is no -sudoers line, the following default is assumed: -.PP -.Vb 1 -\& sudoers = files -.Ve -.SH "FILES" -.IX Header "FILES" -.ie n .IP "\fI@ldap_conf@\fR" 24 -.el .IP "\fI@ldap_conf@\fR" 24 -.IX Item "@ldap_conf@" -\&\s-1LDAP\s0 configuration file -.ie n .IP "\fI@nsswitch_conf@\fR" 24 -.el .IP "\fI@nsswitch_conf@\fR" 24 -.IX Item "@nsswitch_conf@" -determines sudoers source order -.ie n .IP "\fI@netsvc_conf@\fR" 24 -.el .IP "\fI@netsvc_conf@\fR" 24 -.IX Item "@netsvc_conf@" -determines sudoers source order on \s-1AIX\s0 -.SH "EXAMPLES" -.IX Header "EXAMPLES" -.SS "Example ldap.conf" -.IX Subsection "Example ldap.conf" -.Vb 10 -\& # Either specify one or more URIs or one or more host:port pairs. -\& # If neither is specified sudo will default to localhost, port 389. -\& # -\& #host ldapserver -\& #host ldapserver1 ldapserver2:390 -\& # -\& # Default port if host is specified without one, defaults to 389. -\& #port 389 -\& # -\& # URI will override the host and port settings. -\& uri ldap://ldapserver -\& #uri ldaps://secureldapserver -\& #uri ldaps://secureldapserver ldap://ldapserver -\& # -\& # The amount of time, in seconds, to wait while trying to connect to -\& # an LDAP server. -\& bind_timelimit 30 -\& # -\& # The amount of time, in seconds, to wait while performing an LDAP query. -\& timelimit 30 -\& # -\& # Must be set or sudo will ignore LDAP; may be specified multiple times. -\& sudoers_base ou=SUDOers,dc=example,dc=com -\& # -\& # verbose sudoers matching from ldap -\& #sudoers_debug 2 -\& # -\& # optional proxy credentials -\& #binddn -\& #bindpw -\& #rootbinddn -\& # -\& # LDAP protocol version, defaults to 3 -\& #ldap_version 3 -\& # -\& # Define if you want to use an encrypted LDAP connection. -\& # Typically, you must also set the port to 636 (ldaps). -\& #ssl on -\& # -\& # Define if you want to use port 389 and switch to -\& # encryption before the bind credentials are sent. -\& # Only supported by LDAP servers that support the start_tls -\& # extension such as OpenLDAP. -\& #ssl start_tls -\& # -\& # Additional TLS options follow that allow tweaking of the -\& # SSL/TLS connection. -\& # -\& #tls_checkpeer yes # verify server SSL certificate -\& #tls_checkpeer no # ignore server SSL certificate -\& # -\& # If you enable tls_checkpeer, specify either tls_cacertfile -\& # or tls_cacertdir. Only supported when using OpenLDAP. -\& # -\& #tls_cacertfile /etc/certs/trusted_signers.pem -\& #tls_cacertdir /etc/certs -\& # -\& # For systems that don\*(Aqt have /dev/random -\& # use this along with PRNGD or EGD.pl to seed the -\& # random number pool to generate cryptographic session keys. -\& # Only supported when using OpenLDAP. -\& # -\& #tls_randfile /etc/egd\-pool -\& # -\& # You may restrict which ciphers are used. Consult your SSL -\& # documentation for which options go here. -\& # Only supported when using OpenLDAP. -\& # -\& #tls_ciphers -\& # -\& # Sudo can provide a client certificate when communicating to -\& # the LDAP server. -\& # Tips: -\& # * Enable both lines at the same time. -\& # * Do not password protect the key file. -\& # * Ensure the keyfile is only readable by root. -\& # -\& # For OpenLDAP: -\& #tls_cert /etc/certs/client_cert.pem -\& #tls_key /etc/certs/client_key.pem -\& # -\& # For SunONE or iPlanet LDAP, tls_cert and tls_key may specify either -\& # a directory, in which case the files in the directory must have the -\& # default names (e.g. cert8.db and key4.db), or the path to the cert -\& # and key files themselves. However, a bug in version 5.0 of the LDAP -\& # SDK will prevent specific file names from working. For this reason -\& # it is suggested that tls_cert and tls_key be set to a directory, -\& # not a file name. -\& # -\& # The certificate database specified by tls_cert may contain CA certs -\& # and/or the client\*(Aqs cert. If the client\*(Aqs cert is included, tls_key -\& # should be specified as well. -\& # For backward compatibility, "sslpath" may be used in place of tls_cert. -\& #tls_cert /var/ldap -\& #tls_key /var/ldap -\& # -\& # If using SASL authentication for LDAP (OpenSSL) -\& # use_sasl yes -\& # sasl_auth_id -\& # rootuse_sasl yes -\& # rootsasl_auth_id -\& # sasl_secprops none -\& # krb5_ccname /etc/.ldapcache -.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. -.PP -.Vb 6 -\& attributetype ( 1.3.6.1.4.1.15953.9.1.1 -\& NAME \*(AqsudoUser\*(Aq -\& DESC \*(AqUser(s) who may run sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SUBSTR caseExactIA5SubstringsMatch -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& attributetype ( 1.3.6.1.4.1.15953.9.1.2 -\& NAME \*(AqsudoHost\*(Aq -\& DESC \*(AqHost(s) who may run sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SUBSTR caseExactIA5SubstringsMatch -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& attributetype ( 1.3.6.1.4.1.15953.9.1.3 -\& NAME \*(AqsudoCommand\*(Aq -\& DESC \*(AqCommand(s) to be executed by sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& attributetype ( 1.3.6.1.4.1.15953.9.1.4 -\& NAME \*(AqsudoRunAs\*(Aq -\& DESC \*(AqUser(s) impersonated by sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& attributetype ( 1.3.6.1.4.1.15953.9.1.5 -\& NAME \*(AqsudoOption\*(Aq -\& DESC \*(AqOptions(s) followed by sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& attributetype ( 1.3.6.1.4.1.15953.9.1.6 -\& NAME \*(AqsudoRunAsUser\*(Aq -\& DESC \*(AqUser(s) impersonated by sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& attributetype ( 1.3.6.1.4.1.15953.9.1.7 -\& NAME \*(AqsudoRunAsGroup\*(Aq -\& DESC \*(AqGroup(s) impersonated by sudo\*(Aq -\& EQUALITY caseExactIA5Match -\& SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) -\& -\& objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME \*(AqsudoRole\*(Aq SUP top STRUCTURAL -\& DESC \*(AqSudoer Entries\*(Aq -\& MUST ( cn ) -\& MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ -\& sudoRunAsGroup $ sudoOption $ description ) -\& ) -.Ve -.SH "SEE ALSO" -.IX Header "SEE ALSO" -\&\fIldap.conf\fR\|(@mansectform@), \fIsudoers\fR\|(5) -.SH "CAVEATS" -.IX Header "CAVEATS" -The way that \fIsudoers\fR is parsed differs between Note that there -are differences in the way that LDAP-based \fIsudoers\fR is parsed -compared to file-based \fIsudoers\fR. See the \*(L"Differences between -\&\s-1LDAP\s0 and non-LDAP sudoers\*(R" section for more information. -.SH "BUGS" -.IX Header "BUGS" -If you feel you have found a bug in \fBsudo\fR, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ -.SH "SUPPORT" -.IX Header "SUPPORT" -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or -search the archives. -.SH "DISCLAIMER" -.IX Header "DISCLAIMER" -\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 -file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudoers.ldap.pod b/sudoers.ldap.pod deleted file mode 100644 index f7a39c9..0000000 --- a/sudoers.ldap.pod +++ /dev/null @@ -1,742 +0,0 @@ -Copyright (c) 2003-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. -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=pod - -=head1 NAME - -sudoers.ldap - sudo LDAP configuration - -=head1 DESCRIPTION - -In addition to the standard I file, B may be configured -via LDAP. This can be especially useful for synchronizing I -in a large, distributed environment. - -Using LDAP for I has several benefits: - -=over 4 - -=item * - -B no longer needs to read I in its entirety. When -LDAP is used, there are only two or three LDAP queries per invocation. -This makes it especially fast and particularly usable in LDAP -environments. - -=item * - -B no longer exits if there is a typo in I. -It is not possible to load LDAP data into the server that does -not conform to the sudoers schema, so proper syntax is guaranteed. -It is still possible to have typos in a user or host name, but -this will not prevent B from running. - -=item * - -It is possible to specify per-entry options that override the global -default options. F<@sysconfdir@/sudoers> only supports default options and -limited options associated with user/host/commands/aliases. The -syntax is complicated and can be difficult for users to understand. -Placing the options directly in the entry is more natural. - -=item * - -The B program is no longer needed. B provides -locking and syntax checking of the F<@sysconfdir@/sudoers> file. -Since LDAP updates are atomic, locking is no longer necessary. -Because syntax is checked when the data is inserted into LDAP, there -is no need for a specialized tool to check syntax. - -=back - -Another major difference between LDAP and file-based I -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 -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 -a Cmnd_Alias that is referenced by multiple users, one can create -a sudoRole that contains the commands and assign multiple users -to it. - -=head2 SUDOers LDAP container - -The I configuration is contained in the C LDAP -container. - -Sudo first looks for the C entry in the SUDOers container. -If found, the multi-valued C attribute is parsed in the -same manner as a global C line in F<@sysconfdir@/sudoers>. In -the following example, the C variable will be preserved -in the environment for all users. - - dn: cn=defaults,ou=SUDOers,dc=example,dc=com - objectClass: top - objectClass: sudoRole - cn: defaults - description: Default sudoOption's go here - sudoOption: env_keep+=SSH_AUTH_SOCK - -The equivalent of a sudoer in LDAP is a C. It consists of -the following components: - -=over 4 - -=item B - -A user name, uid (prefixed with C<'#'>), Unix group (prefixed with -a C<'%'>) or user netgroup (prefixed with a C<'+'>). - -=item B - -A host name, IP address, IP network, or host netgroup (prefixed -with a C<'+'>). -The special value C will match any host. - -=item B - -A Unix command with optional command line arguments, potentially -including globbing characters (aka wild cards). -The special value C will match any command. -If a command is prefixed with an exclamation point C<'!'>, the -user will be prohibited from running that command. - -=item B - -Identical in function to the global options described above, but -specific to the C in which it resides. - -=item B - -A user name or uid (prefixed with C<'#'>) that commands may be run -as or a Unix group (prefixed with a C<'%'>) or user netgroup (prefixed -with a C<'+'>) that contains a list of users that commands may be -run as. -The special value C will match any user. - -=item B - -A Unix group or gid (prefixed with C<'#'>) that commands may be run as. -The special value C will match any group. - -=back - -Each component listed above should contain a single value, but there -may be multiple instances of each component type. A sudoRole must -contain at least one C, C and C. - -The following example allows users in group wheel to run any command -on any host via B: - - dn: cn=%wheel,ou=SUDOers,dc=example,dc=com - objectClass: top - objectClass: sudoRole - cn: %wheel - sudoUser: %wheel - sudoHost: ALL - sudoCommand: ALL - -=head2 Anatomy of LDAP sudoers lookup - -When looking up a sudoer using LDAP there are only two or three -LDAP queries per invocation. The first query is to parse the global -options. The second is to match against the user's name and the -groups that the user belongs to. (The special ALL tag is matched -in this query too.) If no match is returned for the user's name -and groups, a third query returns all entries containing user -netgroups and checks to see if the user belongs to any of them. - -=head2 Differences between LDAP and non-LDAP sudoers - -There are some subtle differences in the way sudoers is handled -once in LDAP. Probably the biggest is that according to the RFC, -LDAP ordering is arbitrary and you cannot expect that Attributes -and Entries are returned in any specific order. If there are -conflicting command rules on an entry, the negative takes precedence. -This is called paranoid behavior (not necessarily the most specific -match). - -Here is an example: - - # /etc/sudoers: - # Allow all commands except shell - johnny ALL=(root) ALL,!/bin/sh - # Always allows all commands because ALL is matched last - puddles ALL=(root) !/bin/sh,ALL - - # LDAP equivalent of johnny - # Allows all commands except shell - dn: cn=role1,ou=Sudoers,dc=my-domain,dc=com - objectClass: sudoRole - objectClass: top - cn: role1 - sudoUser: johnny - sudoHost: ALL - sudoCommand: ALL - sudoCommand: !/bin/sh - - # LDAP equivalent of puddles - # Notice that even though ALL comes last, it still behaves like - # role1 since the LDAP code assumes the more paranoid configuration - dn: cn=role2,ou=Sudoers,dc=my-domain,dc=com - objectClass: sudoRole - objectClass: top - cn: role2 - sudoUser: puddles - sudoHost: ALL - sudoCommand: !/bin/sh - sudoCommand: ALL - -Another difference is that negations on the Host, User or Runas are -currently ignorred. For example, the following attributes do not -behave the way one might expect. - - # does not match all but joe - # rather, does not match anyone - sudoUser: !joe - - # does not match all but joe - # rather, matches everyone including Joe - sudoUser: ALL - sudoUser: !joe - - # does not match all but web01 - # rather, matches all hosts including web01 - sudoHost: ALL - sudoHost: !web01 - -=head2 Sudoers Schema - -In order to use B's LDAP support, the B schema must be -installed on your LDAP server. In addition, be sure to index the -'sudoUser' attribute. - -Three versions of the schema: one for OpenLDAP servers (F), -one for Netscape-derived servers (F), and one for -Microsoft Active Directory (F) may -be found in the B distribution. - -The schema for B in OpenLDAP form is included in the L -section. - -=head2 Configuring ldap.conf - -Sudo reads the F<@ldap_conf@> file for LDAP-specific configuration. -Typically, this file is shared amongst different LDAP-aware clients. -As such, most of the settings are not B-specific. Note that -B parses F<@ldap_conf@> itself and may support options -that differ from those described in the L manual. - -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 -supported by B are honored. Configuration options are listed -below in upper case but are parsed in a case-independent manner. - -=over 4 - -=item B ldap[s]://[hostname[:port]] ... - -Specifies a whitespace-delimited list of one or more URIs describing -the LDAP server(s) to connect to. The I may be either -B or B, the latter being for servers that support TLS -(SSL) encryption. If no I is specified, the default is port -389 for C or port 636 for C. If no I -is specified, B will connect to B. Multiple B -lines are treated identically to a B line containing multiple -entries. Only systems using the OpenSSL libraries support the -mixing of C and C URIs. The Netscape-derived -libraries used on most commercial versions of Unix are only capable -of supporting one or the other. - -=item B name[:port] ... - -If no B is specified, the B parameter specifies a -whitespace-delimited list of LDAP servers to connect to. Each host -may include an optional I separated by a colon (':'). The -B parameter is deprecated in favor of the B specification -and is included for backwards compatibility. - -=item B port_number - -If no B is specified, the B parameter specifies the -default port to connect to on the LDAP server if a B parameter -does not specify the port itself. If no B parameter is used, -the default is port 389 for LDAP and port 636 for LDAP over TLS -(SSL). The B parameter is deprecated in favor of the B -specification and is included for backwards compatibility. - -=item B seconds - -The B parameter specifies the amount of time, in seconds, -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 - -The B parameter specifies the amount of time, in seconds, -to wait for a response to an LDAP query. - -=item B base - -The base DN to use when performing B LDAP queries. Typically -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 debug_level - -This sets the debug level for B LDAP queries. Debugging -information is printed to the standard error. A value of 1 results -in a moderate amount of debugging information. A value of 2 shows -the results of the matches themselves. This parameter should not -be set in a production environment as the extra information is -likely to confuse users. - -=item B DN - -The B parameter specifies the identity, in the form of a -Distinguished Name (DN), to use when performing LDAP operations. -If not specified, LDAP operations are performed with an anonymous -identity. By default, most LDAP servers will allow anonymous access. - -=item B secret - -The B parameter specifies the password to use when performing -LDAP operations. This is typically used in conjunction with the -B parameter. - -=item B DN - -The B parameter specifies the identity, in the form of -a Distinguished Name (DN), to use when performing privileged LDAP -operations, such as I queries. The password corresponding -to the identity should be stored in F<@ldap_secret@>. -If not specified, the B identity is used (if any). - -=item B number - -The version of the LDAP protocol to use when connecting to the server. -The default value is protocol version 3. - -=item B on/true/yes/off/false/no - -If the B parameter is set to C, C or C, TLS -(SSL) encryption is always used when communicating with the LDAP -server. Typically, this involves connecting to the server on port -636 (ldaps). - -=item B start_tls - -If the B parameter is set to C, the LDAP server -connection is initiated normally and TLS encryption is begun before -the bind credentials are sent. This has the advantage of not -requiring a dedicated port for encrypted communications. This -parameter is only supported by LDAP servers that honor the C -extension, such as the OpenLDAP server. - -=item B on/true/yes/off/false/no - -If enabled, B will cause the LDAP server's TLS -certificated to be verified. If the server's TLS certificate cannot -be verified (usually because it is signed by an unknown certificate -authority), B will be unable to connect to it. If B -is disabled, no check is made. Note that disabling the check creates -an opportunity for man-in-the-middle attacks since the server's -identity will not be authenticated. If possible, the CA's certificate -should be installed locally so it can be verified. - -=item B file name - -An alias for B. - -=item B file name - -The path to a certificate authority bundle which contains the certificates -for all the Certificate Authorities the client knows to be valid, -e.g. F. -This option is only supported by the OpenLDAP libraries. -Netscape-derived LDAP libraries use the same certificate -database for CA and client certificates (see B). - -=item B directory - -Similar to B but instead of a file, it is a -directory containing individual Certificate Authority certificates, -e.g. F. -The directory specified by B is checked after -B. -This option is only supported by the OpenLDAP libraries. - -=item B file name - -The path to a file containing the client certificate which can -be used to authenticate the client to the LDAP server. -The certificate type depends on the LDAP libraries used. - -OpenLDAP: - C - -Netscape-derived: - C - -When using Netscape-derived libraries, this file may also contain -Certificate Authority certificates. - -=item B file name - -The path to a file containing the private key which matches the -certificate specified by B. The private key must not be -password-protected. The key type depends on the LDAP libraries -used. - -OpenLDAP: - C - -Netscape-derived: - C - -=item B file name - -The B parameter specifies the path to an entropy -source for systems that lack a random device. It is generally used -in conjunction with I or I. -This option is only supported by the OpenLDAP libraries. - -=item B cipher list - -The B parameter allows the administer to restrict -which encryption algorithms may be used for TLS (SSL) connections. -See the OpenSSL manual for a list of valid ciphers. -This option is only supported by the OpenLDAP libraries. - -=item B on/true/yes/off/false/no - -Enable B for LDAP servers that support SASL authentication. - -=item B identity - -The SASL user name to use when connecting to the LDAP server. -By default, B will use an anonymous connection. - -=item B on/true/yes/off/false/no - -Enable B to enable SASL authentication when connecting -to an LDAP server from a privileged process, such as B. - -=item B identity - -The SASL user name to use when B is enabled. - -=item B none/properties - -SASL security properties or I for no properties. See the -SASL programmer's manual for details. - -=item B file name - -The path to the Kerberos 5 credential cache to use when authenticating -with the remote server. - -=back - -See the C entry in the L section. - -=head2 Configuring nsswitch.conf - -Unless it is disabled at build time, B consults the Name -Service Switch file, F<@nsswitch_conf@>, to specify the I -search order. Sudo looks for a line beginning with C: and -uses this to determine the search order. Note that B does -not stop searching after the first match and later matches take -precedence over earlier ones. - -The following sources are recognized: - - files read sudoers from F<@sysconfdir@/sudoers> - ldap read sudoers from LDAP - -In addition, the entry C<[NOTFOUND=return]> will short-circuit the -search if the user was not found in the preceding source. - -To consult LDAP first followed by the local sudoers file (if it -exists), use: - - sudoers: ldap files - -The local I file can be ignored completely by using: - - sudoers: ldap - -If the F<@nsswitch_conf@> file is not present or there is no -sudoers line, the following default is assumed: - - sudoers: files - -Note that F<@nsswitch_conf@> is supported even when the underlying -operating system does not use an nsswitch.conf file. - -=head2 Configuring netsvc.conf - -On AIX systems, the F<@netsvc_conf@> file is consulted instead of -F<@nsswitch_conf@>. B simply treats I as a -variant of I; information in the previous section -unrelated to the file format itself still applies. - -To consult LDAP first followed by the local sudoers file (if it -exists), use: - - sudoers = ldap, files - -The local I file can be ignored completely by using: - - sudoers = ldap - -To treat LDAP as authoratative and only use the local sudoers file -if the user is not present in LDAP, use: - - sudoers = ldap = auth, files - -Note that in the above example, the C qualfier only affects -user lookups; both LDAP and I will be queried for C -entries. - -If the F<@netsvc_conf@> file is not present or there is no -sudoers line, the following default is assumed: - - sudoers = files - -=head1 FILES - -=over 24 - -=item F<@ldap_conf@> - -LDAP configuration file - -=item F<@nsswitch_conf@> - -determines sudoers source order - -=item F<@netsvc_conf@> - -determines sudoers source order on AIX - -=back - -=head1 EXAMPLES - -=head2 Example ldap.conf - - # Either specify one or more URIs or one or more host:port pairs. - # If neither is specified sudo will default to localhost, port 389. - # - #host ldapserver - #host ldapserver1 ldapserver2:390 - # - # Default port if host is specified without one, defaults to 389. - #port 389 - # - # URI will override the host and port settings. - uri ldap://ldapserver - #uri ldaps://secureldapserver - #uri ldaps://secureldapserver ldap://ldapserver - # - # The amount of time, in seconds, to wait while trying to connect to - # an LDAP server. - bind_timelimit 30 - # - # The amount of time, in seconds, to wait while performing an LDAP query. - timelimit 30 - # - # Must be set or sudo will ignore LDAP; may be specified multiple times. - sudoers_base ou=SUDOers,dc=example,dc=com - # - # verbose sudoers matching from ldap - #sudoers_debug 2 - # - # optional proxy credentials - #binddn - #bindpw - #rootbinddn - # - # LDAP protocol version, defaults to 3 - #ldap_version 3 - # - # Define if you want to use an encrypted LDAP connection. - # Typically, you must also set the port to 636 (ldaps). - #ssl on - # - # Define if you want to use port 389 and switch to - # encryption before the bind credentials are sent. - # Only supported by LDAP servers that support the start_tls - # extension such as OpenLDAP. - #ssl start_tls - # - # Additional TLS options follow that allow tweaking of the - # SSL/TLS connection. - # - #tls_checkpeer yes # verify server SSL certificate - #tls_checkpeer no # ignore server SSL certificate - # - # If you enable tls_checkpeer, specify either tls_cacertfile - # or tls_cacertdir. Only supported when using OpenLDAP. - # - #tls_cacertfile /etc/certs/trusted_signers.pem - #tls_cacertdir /etc/certs - # - # For systems that don't have /dev/random - # use this along with PRNGD or EGD.pl to seed the - # random number pool to generate cryptographic session keys. - # Only supported when using OpenLDAP. - # - #tls_randfile /etc/egd-pool - # - # You may restrict which ciphers are used. Consult your SSL - # documentation for which options go here. - # Only supported when using OpenLDAP. - # - #tls_ciphers - # - # Sudo can provide a client certificate when communicating to - # the LDAP server. - # Tips: - # * Enable both lines at the same time. - # * Do not password protect the key file. - # * Ensure the keyfile is only readable by root. - # - # For OpenLDAP: - #tls_cert /etc/certs/client_cert.pem - #tls_key /etc/certs/client_key.pem - # - # For SunONE or iPlanet LDAP, tls_cert and tls_key may specify either - # a directory, in which case the files in the directory must have the - # default names (e.g. cert8.db and key4.db), or the path to the cert - # and key files themselves. However, a bug in version 5.0 of the LDAP - # SDK will prevent specific file names from working. For this reason - # it is suggested that tls_cert and tls_key be set to a directory, - # not a file name. - # - # The certificate database specified by tls_cert may contain CA certs - # and/or the client's cert. If the client's cert is included, tls_key - # should be specified as well. - # For backward compatibility, "sslpath" may be used in place of tls_cert. - #tls_cert /var/ldap - #tls_key /var/ldap - # - # If using SASL authentication for LDAP (OpenSSL) - # use_sasl yes - # sasl_auth_id - # rootuse_sasl yes - # rootsasl_auth_id - # sasl_secprops none - # krb5_ccname /etc/.ldapcache - -=head2 Sudo schema for OpenLDAP - -The following schema is in OpenLDAP format. Simply copy it to the -schema directory (e.g. F), add the proper -C line in C and restart B. - - attributetype ( 1.3.6.1.4.1.15953.9.1.1 - NAME 'sudoUser' - DESC 'User(s) who may run sudo' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.2 - NAME 'sudoHost' - DESC 'Host(s) who may run sudo' - EQUALITY caseExactIA5Match - SUBSTR caseExactIA5SubstringsMatch - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.3 - NAME 'sudoCommand' - DESC 'Command(s) to be executed by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.4 - NAME 'sudoRunAs' - DESC 'User(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.5 - NAME 'sudoOption' - DESC 'Options(s) followed by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.6 - NAME 'sudoRunAsUser' - DESC 'User(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - attributetype ( 1.3.6.1.4.1.15953.9.1.7 - NAME 'sudoRunAsGroup' - DESC 'Group(s) impersonated by sudo' - EQUALITY caseExactIA5Match - SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) - - objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL - DESC 'Sudoer Entries' - MUST ( cn ) - MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ - sudoRunAsGroup $ sudoOption $ description ) - ) - -=head1 SEE ALSO - -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. - -=head1 BUGS - -If you feel you have found a bug in B, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ - -=head1 SUPPORT - -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or -search the archives. - -=head1 DISCLAIMER - -B is provided ``AS IS'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the LICENSE -file distributed with B or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudoers.man.in b/sudoers.man.in deleted file mode 100644 index 5dff200..0000000 --- a/sudoers.man.in +++ /dev/null @@ -1,1758 +0,0 @@ -.\" Copyright (c) 1994-1996, 1998-2005, 2007-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. -.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" Sponsored in part by the Defense Advanced Research Projects -.\" Agency (DARPA) and Air Force Research Laboratory, Air Force -.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. -.\" -.nr SL @SEMAN@ -.nr BA @BAMAN@ -.nr LC @LCMAN@ -.\" -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` -. ds C' -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "SUDOERS @mansectform@" -.TH SUDOERS @mansectform@ "July 21, 2010" "1.7.4" "MAINTENANCE COMMANDS" -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -sudoers \- list of which users may execute what -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -The \fIsudoers\fR file is composed of two types of entries: aliases -(basically variables) and user specifications (which specify who -may run what). -.PP -When multiple entries match for a user, they are applied in order. -Where there are multiple matches, the last match is used (which is -not necessarily the most specific match). -.PP -The \fIsudoers\fR grammar will be described below in Extended Backus-Naur -Form (\s-1EBNF\s0). Don't despair if you don't know what \s-1EBNF\s0 is; it is -fairly simple, and the definitions below are annotated. -.SS "Quick guide to \s-1EBNF\s0" -.IX Subsection "Quick guide to EBNF" -\&\s-1EBNF\s0 is a concise and exact way of describing the grammar of a language. -Each \s-1EBNF\s0 definition is made up of \fIproduction rules\fR. E.g., -.PP -.Vb 1 -\& symbol ::= definition | alternate1 | alternate2 ... -.Ve -.PP -Each \fIproduction rule\fR references others and thus makes up a -grammar for the language. \s-1EBNF\s0 also contains the following -operators, which many readers will recognize from regular -expressions. Do not, however, confuse them with \*(L"wildcard\*(R" -characters, which have different meanings. -.ie n .IP "\*(C`?\*(C'" 4 -.el .IP "\f(CW\*(C`?\*(C'\fR" 4 -.IX Item "?" -Means that the preceding symbol (or group of symbols) is optional. -That is, it may appear once or not at all. -.ie n .IP "\*(C`*\*(C'" 4 -.el .IP "\f(CW\*(C`*\*(C'\fR" 4 -.IX Item "*" -Means that the preceding symbol (or group of symbols) may appear -zero or more times. -.ie n .IP "\*(C`+\*(C'" 4 -.el .IP "\f(CW\*(C`+\*(C'\fR" 4 -.IX Item "+" -Means that the preceding symbol (or group of symbols) may appear -one or more times. -.PP -Parentheses may be used to group symbols together. For clarity, -we will use single quotes ('') to designate what is a verbatim character -string (as opposed to a symbol name). -.SS "Aliases" -.IX Subsection "Aliases" -There are four kinds of aliases: \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, -\&\f(CW\*(C`Host_Alias\*(C'\fR and \f(CW\*(C`Cmnd_Alias\*(C'\fR. -.PP -.Vb 4 -\& Alias ::= \*(AqUser_Alias\*(Aq User_Alias (\*(Aq:\*(Aq User_Alias)* | -\& \*(AqRunas_Alias\*(Aq Runas_Alias (\*(Aq:\*(Aq Runas_Alias)* | -\& \*(AqHost_Alias\*(Aq Host_Alias (\*(Aq:\*(Aq Host_Alias)* | -\& \*(AqCmnd_Alias\*(Aq Cmnd_Alias (\*(Aq:\*(Aq Cmnd_Alias)* -\& -\& User_Alias ::= NAME \*(Aq=\*(Aq User_List -\& -\& Runas_Alias ::= NAME \*(Aq=\*(Aq Runas_List -\& -\& Host_Alias ::= NAME \*(Aq=\*(Aq Host_List -\& -\& Cmnd_Alias ::= NAME \*(Aq=\*(Aq Cmnd_List -\& -\& NAME ::= [A\-Z]([A\-Z][0\-9]_)* -.Ve -.PP -Each \fIalias\fR definition is of the form -.PP -.Vb 1 -\& Alias_Type NAME = item1, item2, ... -.Ve -.PP -where \fIAlias_Type\fR is one of \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, \f(CW\*(C`Host_Alias\*(C'\fR, -or \f(CW\*(C`Cmnd_Alias\*(C'\fR. A \f(CW\*(C`NAME\*(C'\fR is a string of uppercase letters, numbers, -and underscore characters ('_'). A \f(CW\*(C`NAME\*(C'\fR \fBmust\fR start with an -uppercase letter. It is possible to put several alias definitions -of the same type on a single line, joined by a colon (':'). E.g., -.PP -.Vb 1 -\& Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 -.Ve -.PP -The definitions of what constitutes a valid \fIalias\fR member follow. -.PP -.Vb 2 -\& User_List ::= User | -\& User \*(Aq,\*(Aq User_List -\& -\& User ::= \*(Aq!\*(Aq* user name | -\& \*(Aq!\*(Aq* \*(Aq#\*(Aquid | -\& \*(Aq!\*(Aq* \*(Aq%\*(Aqgroup | -\& \*(Aq!\*(Aq* \*(Aq+\*(Aqnetgroup | -\& \*(Aq!\*(Aq* \*(Aq%:\*(Aqnonunix_group | -\& \*(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: -.IP "\(bu" 4 -Group in the same domain: \*(L"Group Name\*(R" -.IP "\(bu" 4 -Group in any domain: \*(L"Group Name@FULLY.QUALIFIED.DOMAIN\*(R" -.IP "\(bu" 4 -Group \s-1SID:\s0 \*(L"S\-1\-2\-34\-5678901234\-5678901234\-5678901234\-567\*(R" -.PP -Note that quotes around group names are optional. Unquoted strings must -use a backslash (\e) to escape spaces and the '@' symbol. -.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* +netgroup | -\& \*(Aq!\*(Aq* Runas_Alias -.Ve -.PP -A \f(CW\*(C`Runas_List\*(C'\fR is similar to a \f(CW\*(C`User_List\*(C'\fR except that instead -of \f(CW\*(C`User_Alias\*(C'\fRes it can contain \f(CW\*(C`Runas_Alias\*(C'\fRes. Note that -user names and groups are matched as strings. In other words, two -users (groups) with the same uid (gid) are considered to be distinct. -If you wish to match all user names with the same uid (e.g.\ root -and toor), you can use a uid instead (#0 in the example given). -.PP -.Vb 2 -\& Host_List ::= Host | -\& Host \*(Aq,\*(Aq Host_List -\& -\& Host ::= \*(Aq!\*(Aq* host name | -\& \*(Aq!\*(Aq* ip_addr | -\& \*(Aq!\*(Aq* network(/netmask)? | -\& \*(Aq!\*(Aq* \*(Aq+\*(Aqnetgroup | -\& \*(Aq!\*(Aq* Host_Alias -.Ve -.PP -A \f(CW\*(C`Host_List\*(C'\fR is made up of one or more host names, \s-1IP\s0 addresses, -network numbers, netgroups (prefixed with '+') and other aliases. -Again, the value of an item may be negated with the '!' operator. -If you do not specify a netmask along with the network number, -\&\fBsudo\fR will query each of the local host's network interfaces and, -if the network number corresponds to one of the hosts's network -interfaces, the corresponding netmask will be used. The netmask -may be specified either in standard \s-1IP\s0 address notation -(e.g.\ 255.255.255.0 or ffff:ffff:ffff:ffff::), -or \s-1CIDR\s0 notation (number of bits, e.g.\ 24 or 64). A host name may -include shell-style wildcards (see the Wildcards section below), -but unless the \f(CW\*(C`host name\*(C'\fR command on your machine returns the fully -qualified host name, you'll need to use the \fIfqdn\fR option for -wildcards to be useful. Note \fBsudo\fR only inspects actual network -interfaces; this means that \s-1IP\s0 address 127.0.0.1 (localhost) will -never match. Also, the host name \*(L"localhost\*(R" will only match if -that is the actual host name, which is usually only the case for -non-networked systems. -.PP -.Vb 2 -\& Cmnd_List ::= Cmnd | -\& Cmnd \*(Aq,\*(Aq Cmnd_List -\& -\& commandname ::= file name | -\& file name args | -\& file name \*(Aq""\*(Aq -\& -\& Cmnd ::= \*(Aq!\*(Aq* commandname | -\& \*(Aq!\*(Aq* directory | -\& \*(Aq!\*(Aq* "sudoedit" | -\& \*(Aq!\*(Aq* Cmnd_Alias -.Ve -.PP -A \f(CW\*(C`Cmnd_List\*(C'\fR is a list of one or more commandnames, directories, and other -aliases. A commandname is a fully qualified file name which may include -shell-style wildcards (see the Wildcards section below). A simple -file name allows the user to run the command with any arguments he/she -wishes. However, you may also specify command line arguments (including -wildcards). Alternately, you can specify \f(CW""\fR to indicate that the command -may only be run \fBwithout\fR command line arguments. A directory is a -fully qualified path name ending in a '/'. When you specify a directory -in a \f(CW\*(C`Cmnd_List\*(C'\fR, the user will be able to run any file within that directory -(but not in any subdirectories therein). -.PP -If a \f(CW\*(C`Cmnd\*(C'\fR has associated command line arguments, then the arguments -in the \f(CW\*(C`Cmnd\*(C'\fR must match exactly those given by the user on the command line -(or match the wildcards if there are any). Note that the following -characters must be escaped with a '\e' if they are used in command -arguments: ',', ':', '=', '\e'. The special command \f(CW"sudoedit"\fR -is used to permit a user to run \fBsudo\fR with the \fB\-e\fR option (or -as \fBsudoedit\fR). It may take command line arguments just as -a normal command does. -.SS "Defaults" -.IX Subsection "Defaults" -Certain configuration options may be changed from their default -values at runtime via one or more \f(CW\*(C`Default_Entry\*(C'\fR lines. These -may affect all users on any host, all users on a specific host, a -specific user, a specific command, or commands being run as a specific user. -Note that per-command entries may not include command line arguments. -If you need to specify arguments, define a \f(CW\*(C`Cmnd_Alias\*(C'\fR and reference -that instead. -.PP -.Vb 5 -\& Default_Type ::= \*(AqDefaults\*(Aq | -\& \*(AqDefaults\*(Aq \*(Aq@\*(Aq Host_List | -\& \*(AqDefaults\*(Aq \*(Aq:\*(Aq User_List | -\& \*(AqDefaults\*(Aq \*(Aq!\*(Aq Cmnd_List | -\& \*(AqDefaults\*(Aq \*(Aq>\*(Aq Runas_List -\& -\& Default_Entry ::= Default_Type Parameter_List -\& -\& Parameter_List ::= Parameter | -\& Parameter \*(Aq,\*(Aq Parameter_List -\& -\& Parameter ::= Parameter \*(Aq=\*(Aq Value | -\& Parameter \*(Aq+=\*(Aq Value | -\& Parameter \*(Aq\-=\*(Aq Value | -\& \*(Aq!\*(Aq* Parameter -.Ve -.PP -Parameters may be \fBflags\fR, \fBinteger\fR values, \fBstrings\fR, or \fBlists\fR. -Flags are implicitly boolean and can be turned off via the '!' -operator. Some integer, string and list parameters may also be -used in a boolean context to disable them. Values may be enclosed -in double quotes (\f(CW\*(C`"\*(C'\fR) when they contain multiple words. Special -characters may be escaped with a backslash (\f(CW\*(C`\e\*(C'\fR). -.PP -Lists have two additional assignment operators, \f(CW\*(C`+=\*(C'\fR and \f(CW\*(C`\-=\*(C'\fR. -These operators are used to add to and delete from a list respectively. -It is not an error to use the \f(CW\*(C`\-=\*(C'\fR operator to remove an element -that does not exist in a list. -.PP -Defaults entries are parsed in the following order: generic, host -and user Defaults first, then runas Defaults and finally command -defaults. -.PP -See \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" for a list of supported Defaults parameters. -.SS "User Specification" -.IX Subsection "User Specification" -.Vb 2 -\& User_Spec ::= User_List Host_List \*(Aq=\*(Aq Cmnd_Spec_List \e -\& (\*(Aq:\*(Aq Host_List \*(Aq=\*(Aq Cmnd_Spec_List)* -\& -\& Cmnd_Spec_List ::= Cmnd_Spec | -\& Cmnd_Spec \*(Aq,\*(Aq Cmnd_Spec_List -\& -.ie \n(SL \& Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd -.el \& Cmnd_Spec ::= Runas_Spec? Tag_Spec* Cmnd -\& -\& Runas_Spec ::= \*(Aq(\*(Aq Runas_List? (\*(Aq:\*(Aq Runas_List)? \*(Aq)\*(Aq -\& -.if \n(SL \{\ -\& SELinux_Spec ::= (\*(AqROLE=role\*(Aq | \*(AqTYPE=type\*(Aq) -\& -\} -\& Tag_Spec ::= (\*(AqNOPASSWD:\*(Aq | \*(AqPASSWD:\*(Aq | \*(AqNOEXEC:\*(Aq | \*(AqEXEC:\*(Aq | -\& \*(AqSETENV:\*(Aq | \*(AqNOSETENV:\*(Aq | \*(AqLOG_INPUT:\*(Aq | \*(AqNOLOG_INPUT:\*(Aq | -\& \*(AqLOG_OUTPUT:\*(Aq | \*(AqNOLOG_OUTPUT:\*(Aq) -.Ve -.PP -A \fBuser specification\fR determines which commands a user may run -(and as what user) on specified hosts. By default, commands are -run as \fBroot\fR, but this can be changed on a per-command basis. -.PP -The basic structure of a user specification is `who = where (as_whom) -what'. Let's break that down into its constituent parts: -.SS "Runas_Spec" -.IX Subsection "Runas_Spec" -A \f(CW\*(C`Runas_Spec\*(C'\fR determines the user and/or the group that a command -may be run as. A fully-specified \f(CW\*(C`Runas_Spec\*(C'\fR consists of two -\&\f(CW\*(C`Runas_List\*(C'\fRs (as defined above) separated by a colon (':') and -enclosed in a set of parentheses. The first \f(CW\*(C`Runas_List\*(C'\fR indicates -which users the command may be run as via \fBsudo\fR's \fB\-u\fR option. -The second defines a list of groups that can be specified via -\&\fBsudo\fR's \fB\-g\fR option. If both \f(CW\*(C`Runas_List\*(C'\fRs are specified, the -command may be run with any combination of users and groups listed -in their respective \f(CW\*(C`Runas_List\*(C'\fRs. If only the first is specified, -the command may be run as any user in the list but no \fB\-g\fR option -may be specified. If the first \f(CW\*(C`Runas_List\*(C'\fR is empty but the -second is specified, the command may be run as the invoking user -with the group set to any listed in the \f(CW\*(C`Runas_List\*(C'\fR. If no -\&\f(CW\*(C`Runas_Spec\*(C'\fR is specified the command may be run as \fBroot\fR and -no group may be specified. -.PP -A \f(CW\*(C`Runas_Spec\*(C'\fR sets the default for the commands that follow it. -What this means is that for the entry: -.PP -.Vb 1 -\& dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm -.Ve -.PP -The user \fBdgb\fR may run \fI/bin/ls\fR, \fI/bin/kill\fR, and -\&\fI/usr/bin/lprm\fR \*(-- but only as \fBoperator\fR. E.g., -.PP -.Vb 1 -\& $ sudo \-u operator /bin/ls. -.Ve -.PP -It is also possible to override a \f(CW\*(C`Runas_Spec\*(C'\fR later on in an -entry. If we modify the entry like so: -.PP -.Vb 1 -\& dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm -.Ve -.PP -Then user \fBdgb\fR is now allowed to run \fI/bin/ls\fR as \fBoperator\fR, -but \fI/bin/kill\fR and \fI/usr/bin/lprm\fR as \fBroot\fR. -.PP -We can extend this to allow \fBdgb\fR to run \f(CW\*(C`/bin/ls\*(C'\fR with either -the user or group set to \fBoperator\fR: -.PP -.Vb 2 -\& dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \e -\& /usr/bin/lprm -.Ve -.PP -In the following example, user \fBtcm\fR may run commands that access -a modem device file with the dialer group. Note that in this example -only the group will be set, the command still runs as user \fBtcm\fR. -.PP -.Vb 2 -\& tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \e -\& /usr/local/bin/minicom -.Ve -.if \n(SL \{\ -.SS "SELinux_Spec" -.IX Subsection "SELinux_Spec" -On systems with SELinux support, \fIsudoers\fR entries may optionally have -an SELinux role and/or type associated with a command. If a role or -type is specified with the command it will override any default values -specified in \fIsudoers\fR. A role or type specified on the command line, -however, will supercede the values in \fIsudoers\fR. -\} -.SS "Tag_Spec" -.IX Subsection "Tag_Spec" -A command may have zero or more tags associated with it. There are -eight possible tag values, \f(CW\*(C`NOPASSWD\*(C'\fR, \f(CW\*(C`PASSWD\*(C'\fR, \f(CW\*(C`NOEXEC\*(C'\fR, -\&\f(CW\*(C`EXEC\*(C'\fR, \f(CW\*(C`SETENV\*(C'\fR, \f(CW\*(C`NOSETENV\*(C'\fR, \f(CW\*(C`LOG_INPUT\*(C'\fR, \f(CW\*(C`NOLOG_INPUT\*(C'\fR, -\&\f(CW\*(C`LOG_OUTPUT\*(C'\fR and \f(CW\*(C`NOLOG_OUTPUT\*(C'\fR. Once a tag is set on a \f(CW\*(C`Cmnd\*(C'\fR, -subsequent \f(CW\*(C`Cmnd\*(C'\fRs in the \f(CW\*(C`Cmnd_Spec_List\*(C'\fR, inherit the tag unless -it is overridden by the opposite tag (i.e.: \f(CW\*(C`PASSWD\*(C'\fR overrides -\&\f(CW\*(C`NOPASSWD\*(C'\fR and \f(CW\*(C`NOEXEC\*(C'\fR overrides \f(CW\*(C`EXEC\*(C'\fR). -.PP -\fI\s-1NOPASSWD\s0 and \s-1PASSWD\s0\fR -.IX Subsection "NOPASSWD and PASSWD" -.PP -By default, \fBsudo\fR requires that a user authenticate him or herself -before running a command. This behavior can be modified via the -\&\f(CW\*(C`NOPASSWD\*(C'\fR tag. Like a \f(CW\*(C`Runas_Spec\*(C'\fR, the \f(CW\*(C`NOPASSWD\*(C'\fR tag sets -a default for the commands that follow it in the \f(CW\*(C`Cmnd_Spec_List\*(C'\fR. -Conversely, the \f(CW\*(C`PASSWD\*(C'\fR tag can be used to reverse things. -For example: -.PP -.Vb 1 -\& ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm -.Ve -.PP -would allow the user \fBray\fR to run \fI/bin/kill\fR, \fI/bin/ls\fR, and -\&\fI/usr/bin/lprm\fR as \fBroot\fR on the machine rushmore without -authenticating himself. If we only want \fBray\fR to be able to -run \fI/bin/kill\fR without a password the entry would be: -.PP -.Vb 1 -\& ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm -.Ve -.PP -Note, however, that the \f(CW\*(C`PASSWD\*(C'\fR tag has no effect on users who are -in the group specified by the \fIexempt_group\fR option. -.PP -By default, if the \f(CW\*(C`NOPASSWD\*(C'\fR tag is applied to any of the entries -for a user on the current host, he or she will be able to run -\&\f(CW\*(C`sudo \-l\*(C'\fR without a password. Additionally, a user may only run -\&\f(CW\*(C`sudo \-v\*(C'\fR without a password if the \f(CW\*(C`NOPASSWD\*(C'\fR tag is present -for all a user's entries that pertain to the current host. -This behavior may be overridden via the verifypw and listpw options. -.PP -\fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR -.IX Subsection "NOEXEC and EXEC" -.PP -If \fBsudo\fR has been compiled with \fInoexec\fR support and the underlying -operating system supports it, the \f(CW\*(C`NOEXEC\*(C'\fR tag can be used to prevent -a dynamically-linked executable from running further commands itself. -.PP -In the following example, user \fBaaron\fR may run \fI/usr/bin/more\fR -and \fI/usr/bin/vi\fR but shell escapes will be disabled. -.PP -.Vb 1 -\& aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi -.Ve -.PP -See the \*(L"\s-1PREVENTING\s0 \s-1SHELL\s0 \s-1ESCAPES\s0\*(R" section below for more details -on how \f(CW\*(C`NOEXEC\*(C'\fR works and whether or not it will work on your system. -.PP -\fI\s-1SETENV\s0 and \s-1NOSETENV\s0\fR -.IX Subsection "SETENV and NOSETENV" -.PP -These tags override the value of the \fIsetenv\fR option on a per-command -basis. Note that if \f(CW\*(C`SETENV\*(C'\fR has been set for a command, 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. -.PP -\fI\s-1LOG_INPUT\s0 and \s-1NOLOG_INPUT\s0\fR -.IX Subsection "LOG_INPUT and NOLOG_INPUT" -.PP -These tags override the value of the \fIlog_input\fR option on a -per-command basis. For more information, see the description of -\&\fIlog_input\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below. -.PP -\fI\s-1LOG_OUTPUT\s0 and \s-1NOLOG_OUTPUT\s0\fR -.IX Subsection "LOG_OUTPUT and NOLOG_OUTPUT" -.PP -These tags override the value of the \fIlog_output\fR option on a -per-command basis. For more information, see the description of -\&\fIlog_output\fR in the \*(L"\s-1SUDOERS\s0 \s-1OPTIONS\s0\*(R" section below. -.SS "Wildcards" -.IX Subsection "Wildcards" -\&\fBsudo\fR allows shell-style \fIwildcards\fR (aka meta or glob characters) -to be used in host names, path names and command line arguments in -the \fIsudoers\fR file. Wildcard matching is done via the \fB\s-1POSIX\s0\fR -\&\fIglob\fR\|(3) and \fIfnmatch\fR\|(3) routines. Note that these are \fInot\fR -regular expressions. -.ie n .IP "\*(C`*\*(C'" 8 -.el .IP "\f(CW\*(C`*\*(C'\fR" 8 -.IX Item "*" -Matches any set of zero or more characters. -.ie n .IP "\*(C`?\*(C'" 8 -.el .IP "\f(CW\*(C`?\*(C'\fR" 8 -.IX Item "?" -Matches any single character. -.ie n .IP "\*(C`[...]\*(C'" 8 -.el .IP "\f(CW\*(C`[...]\*(C'\fR" 8 -.IX Item "[...]" -Matches any character in the specified range. -.ie n .IP "\*(C`[!...]\*(C'" 8 -.el .IP "\f(CW\*(C`[!...]\*(C'\fR" 8 -.IX Item "[!...]" -Matches any character \fBnot\fR in the specified range. -.ie n .IP "\*(C`\ex\*(C'" 8 -.el .IP "\f(CW\*(C`\ex\*(C'\fR" 8 -.IX Item "x" -For any character \*(L"x\*(R", evaluates to \*(L"x\*(R". This is used to -escape special characters such as: \*(L"*\*(R", \*(L"?\*(R", \*(L"[\*(R", and \*(L"}\*(R". -.PP -\&\s-1POSIX\s0 character classes may also be used if your system's \fIglob\fR\|(3) -and \fIfnmatch\fR\|(3) functions support them. However, because the -\&\f(CW\*(Aq:\*(Aq\fR character has special meaning in \fIsudoers\fR, it must be -escaped. For example: -.PP -.Vb 1 -\& /bin/ls [[\e:alpha\e:]]* -.Ve -.PP -Would match any file name beginning with a letter. -.PP -Note that a forward slash ('/') will \fBnot\fR be matched by -wildcards used in the path name. When matching the command -line arguments, however, a slash \fBdoes\fR get matched by -wildcards. This is to make a path like: -.PP -.Vb 1 -\& /usr/bin/* -.Ve -.PP -match \fI/usr/bin/who\fR but not \fI/usr/bin/X11/xterm\fR. -.SS "Exceptions to wildcard rules" -.IX Subsection "Exceptions to wildcard rules" -The following exceptions apply to the above rules: -.ie n .IP """""" 8 -.el .IP "\f(CW``''\fR" 8 -.IX Item """""" -If the empty string \f(CW""\fR is the only command line argument in the -\&\fIsudoers\fR entry it means that command is not allowed to be run -with \fBany\fR arguments. -.SS "Including other files from within sudoers" -.IX Subsection "Including other files from within sudoers" -It is possible to include other \fIsudoers\fR files from within the -\&\fIsudoers\fR file currently being parsed using the \f(CW\*(C`#include\*(C'\fR and -\&\f(CW\*(C`#includedir\*(C'\fR directives. -.PP -This can be used, for example, to keep a site-wide \fIsudoers\fR file -in addition to a local, per-machine file. For the sake of this -example the site-wide \fIsudoers\fR will be \fI/etc/sudoers\fR and the -per-machine one will be \fI/etc/sudoers.local\fR. To include -\&\fI/etc/sudoers.local\fR from within \fI/etc/sudoers\fR we would use the -following line in \fI/etc/sudoers\fR: -.Sp -.RS 4 -\&\f(CW\*(C`#include /etc/sudoers.local\*(C'\fR -.RE -.PP -When \fBsudo\fR reaches this line it will suspend processing of the -current file (\fI/etc/sudoers\fR) and switch to \fI/etc/sudoers.local\fR. -Upon reaching the end of \fI/etc/sudoers.local\fR, the rest of -\&\fI/etc/sudoers\fR will be processed. Files that are included may -themselves include other files. A hard limit of 128 nested include -files is enforced to prevent include file loops. -.PP -The file name may include the \f(CW%h\fR escape, signifying the short form -of the host name. I.e., if the machine's host name is \*(L"xerxes\*(R", then -.PP -\&\f(CW\*(C`#include /etc/sudoers.%h\*(C'\fR -.PP -will cause \fBsudo\fR to include the file \fI/etc/sudoers.xerxes\fR. -.PP -The \f(CW\*(C`#includedir\*(C'\fR directive can be used to create a \fIsudo.d\fR -directory that the system package manager can drop \fIsudoers\fR rules -into as part of package installation. For example, given: -.PP -\&\f(CW\*(C`#includedir /etc/sudoers.d\*(C'\fR -.PP -\&\fBsudo\fR will read each file in \fI/etc/sudoers.d\fR, skipping file -names that end in \f(CW\*(C`~\*(C'\fR or contain a \f(CW\*(C`.\*(C'\fR character to avoid causing -problems with package manager or editor temporary/backup files. -Files are parsed in sorted lexical order. That is, -\&\fI/etc/sudoers.d/01_first\fR will be parsed before -\&\fI/etc/sudoers.d/10_second\fR. Be aware that because the sorting is -lexical, not numeric, \fI/etc/sudoers.d/1_whoops\fR would be loaded -\&\fBafter\fR \fI/etc/sudoers.d/10_second\fR. Using a consistent number -of leading zeroes in the file names can be used to avoid such -problems. -.PP -Note that unlike files included via \f(CW\*(C`#include\*(C'\fR, \fBvisudo\fR will not -edit the files in a \f(CW\*(C`#includedir\*(C'\fR directory unless one of them -contains a syntax error. It is still possible to run \fBvisudo\fR -with the \f(CW\*(C`\-f\*(C'\fR flag to edit the files directly. -.SS "Other special characters and reserved words" -.IX Subsection "Other special characters and reserved words" -The pound sign ('#') is used to indicate a comment (unless it is -part of a #include directive or unless it occurs in the context of -a user name and is followed by one or more digits, in which case -it is treated as a uid). Both the comment character and any text -after it, up to the end of the line, are ignored. -.PP -The reserved word \fB\s-1ALL\s0\fR is a built-in \fIalias\fR that always causes -a match to succeed. It can be used wherever one might otherwise -use a \f(CW\*(C`Cmnd_Alias\*(C'\fR, \f(CW\*(C`User_Alias\*(C'\fR, \f(CW\*(C`Runas_Alias\*(C'\fR, or \f(CW\*(C`Host_Alias\*(C'\fR. -You should not try to define your own \fIalias\fR called \fB\s-1ALL\s0\fR as the -built-in alias will be used in preference to your own. Please note -that using \fB\s-1ALL\s0\fR can be dangerous since in a command context, it -allows the user to run \fBany\fR command on the system. -.PP -An exclamation point ('!') can be used as a logical \fInot\fR operator -both in an \fIalias\fR and in front of a \f(CW\*(C`Cmnd\*(C'\fR. This allows one to -exclude certain values. Note, however, that using a \f(CW\*(C`!\*(C'\fR in -conjunction with the built-in \f(CW\*(C`ALL\*(C'\fR alias to allow a user to -run \*(L"all but a few\*(R" commands rarely works as intended (see \s-1SECURITY\s0 -\&\s-1NOTES\s0 below). -.PP -Long lines can be continued with a backslash ('\e') as the last -character on the line. -.PP -Whitespace between elements in a list as well as special syntactic -characters in a \fIUser Specification\fR ('=', ':', '(', ')') is optional. -.PP -The following characters must be escaped with a backslash ('\e') when -used as part of a word (e.g.\ a user name or host name): -\&'@', '!', '=', ':', ',', '(', ')', '\e'. -.SH "SUDOERS OPTIONS" -.IX Header "SUDOERS OPTIONS" -\&\fBsudo\fR's behavior can be modified by \f(CW\*(C`Default_Entry\*(C'\fR lines, as -explained earlier. A list of all supported Defaults parameters, -grouped by type, are listed below. -.PP -\&\fBBoolean Flags\fR: -.IP "always_set_home" 16 -.IX Item "always_set_home" -If enabled, \fBsudo\fR will set the \f(CW\*(C`HOME\*(C'\fR environment variable to the -home directory of the target user (which is root unless the \fB\-u\fR -option is used). This effectively means that the \fB\-H\fR option is -always implied. Note that \f(CW\*(C`HOME\*(C'\fR is already set when the the -\&\fIenv_reset\fR option is enabled, so \fIalways_set_home\fR is only -effective for configurations where \fIenv_reset\fR is disabled. -This flag is \fIoff\fR by default. -.IP "authenticate" 16 -.IX Item "authenticate" -If set, users must authenticate themselves via a password (or other -means of authentication) before they may run commands. This default -may be overridden via the \f(CW\*(C`PASSWD\*(C'\fR and \f(CW\*(C`NOPASSWD\*(C'\fR tags. -This flag is \fIon\fR by default. -.IP "closefrom_override" 16 -.IX Item "closefrom_override" -If set, the user may use \fBsudo\fR's \fB\-C\fR option which -overrides the default starting point at which \fBsudo\fR begins -closing open file descriptors. This flag is \fIoff\fR by default. -.IP "compress_io" 16 -.IX Item "compress_io" -If set, and \fBsudo\fR is configured to log a command's input or output, -the I/O logs will be compressed using \fBzlib\fR. This flag is \fIon\fR -by default when \fBsudo\fR is compiled with \fBzlib\fR support. -.IP "env_editor" 16 -.IX Item "env_editor" -If set, \fBvisudo\fR will use the value of the \s-1EDITOR\s0 or \s-1VISUAL\s0 -environment variables before falling back on the default editor list. -Note that this may create a security hole as it allows the user to -run any arbitrary command as root without logging. A safer alternative -is to place a colon-separated list of editors in the \f(CW\*(C`editor\*(C'\fR -variable. \fBvisudo\fR will then only use the \s-1EDITOR\s0 or \s-1VISUAL\s0 if -they match a value specified in \f(CW\*(C`editor\*(C'\fR. This flag is \fI@env_editor@\fR by -default. -.IP "env_reset" 16 -.IX Item "env_reset" -If set, \fBsudo\fR will reset the environment to only contain the -\&\s-1LOGNAME\s0, \s-1MAIL\s0, \s-1SHELL\s0, \s-1USER\s0, \s-1USERNAME\s0 and the \f(CW\*(C`SUDO_*\*(C'\fR variables. Any -variables in the caller's environment that match the \f(CW\*(C`env_keep\*(C'\fR -and \f(CW\*(C`env_check\*(C'\fR lists are then added. The default contents of the -\&\f(CW\*(C`env_keep\*(C'\fR and \f(CW\*(C`env_check\*(C'\fR lists are displayed when \fBsudo\fR is -run by root with the \fI\-V\fR option. If the \fIsecure_path\fR option -is set, its value will be used for the \f(CW\*(C`PATH\*(C'\fR environment variable. -This flag is \fIon\fR by default. -.IP "fast_glob" 16 -.IX Item "fast_glob" -Normally, \fBsudo\fR uses the \fIglob\fR\|(3) function to do shell-style -globbing when matching path names. However, since it accesses the -file system, \fIglob\fR\|(3) can take a long time to complete for some -patterns, especially when the pattern references a network file -system that is mounted on demand (automounted). The \fIfast_glob\fR -option causes \fBsudo\fR to use the \fIfnmatch\fR\|(3) function, which does -not access the file system to do its matching. The disadvantage -of \fIfast_glob\fR is that it is unable to match relative path names -such as \fI./ls\fR or \fI../bin/ls\fR. This has security implications -when path names that include globbing characters are used with the -negation operator, \f(CW\*(Aq!\*(Aq\fR, as such rules can be trivially bypassed. -As such, this option should not be used when \fIsudoers\fR contains rules -that contain negated path names which include globbing characters. -This flag is \fIoff\fR by default. -.IP "fqdn" 16 -.IX Item "fqdn" -Set this flag if you want to put fully qualified host names in the -\&\fIsudoers\fR file. I.e., instead of myhost you would use myhost.mydomain.edu. -You may still use the short form if you wish (and even mix the two). -Beware that turning on \fIfqdn\fR requires \fBsudo\fR to make \s-1DNS\s0 lookups -which may make \fBsudo\fR unusable if \s-1DNS\s0 stops working (for example -if the machine is not plugged into the network). Also note that -you must use the host's official name as \s-1DNS\s0 knows it. That is, -you may not use a host alias (\f(CW\*(C`CNAME\*(C'\fR entry) due to performance -issues and the fact that there is no way to get all aliases from -\&\s-1DNS\s0. If your machine's host name (as returned by the \f(CW\*(C`hostname\*(C'\fR -command) is already fully qualified you shouldn't need to set -\&\fIfqdn\fR. This flag is \fI@fqdn@\fR by default. -.IP "ignore_dot" 16 -.IX Item "ignore_dot" -If set, \fBsudo\fR will ignore '.' or '' (current dir) in the \f(CW\*(C`PATH\*(C'\fR -environment variable; the \f(CW\*(C`PATH\*(C'\fR itself is not modified. This -flag is \fI@ignore_dot@\fR by default. -.IP "ignore_local_sudoers" 16 -.IX Item "ignore_local_sudoers" -If set via \s-1LDAP\s0, parsing of \fI@sysconfdir@/sudoers\fR will be skipped. -This is intended for Enterprises that wish to prevent the usage of local -sudoers files so that only \s-1LDAP\s0 is used. This thwarts the efforts of -rogue operators who would attempt to add roles to \fI@sysconfdir@/sudoers\fR. -When this option is present, \fI@sysconfdir@/sudoers\fR does not even need to -exist. Since this option tells \fBsudo\fR how to behave when no specific \s-1LDAP\s0 -entries have been matched, this sudoOption is only meaningful for the -\&\f(CW\*(C`cn=defaults\*(C'\fR section. This flag is \fIoff\fR by default. -.IP "insults" 16 -.IX Item "insults" -If set, \fBsudo\fR will insult users when they enter an incorrect -password. This flag is \fI@insults@\fR by default. -.IP "log_host" 16 -.IX Item "log_host" -If set, the host name will be logged in the (non-syslog) \fBsudo\fR log file. -This flag is \fIoff\fR by default. -.IP "log_year" 16 -.IX Item "log_year" -If set, the four-digit year will be logged in the (non-syslog) \fBsudo\fR log file. -This flag is \fIoff\fR by default. -.IP "long_otp_prompt" 16 -.IX Item "long_otp_prompt" -When validating with a One Time Password (\s-1OPT\s0) scheme such as -\&\fBS/Key\fR or \fB\s-1OPIE\s0\fR, a two-line prompt is used to make it easier -to cut and paste the challenge to a local window. It's not as -pretty as the default but some people find it more convenient. This -flag is \fI@long_otp_prompt@\fR by default. -.IP "mail_always" 16 -.IX Item "mail_always" -Send mail to the \fImailto\fR user every time a users runs \fBsudo\fR. -This flag is \fIoff\fR by default. -.IP "mail_badpass" 16 -.IX Item "mail_badpass" -Send mail to the \fImailto\fR user if the user running \fBsudo\fR does not -enter the correct password. This flag is \fIoff\fR by default. -.IP "mail_no_host" 16 -.IX Item "mail_no_host" -If set, mail will be sent to the \fImailto\fR user if the invoking -user exists in the \fIsudoers\fR file, but is not allowed to run -commands on the current host. This flag is \fI@mail_no_host@\fR by default. -.IP "mail_no_perms" 16 -.IX Item "mail_no_perms" -If set, mail will be sent to the \fImailto\fR user if the invoking -user is allowed to use \fBsudo\fR but the command they are trying is not -listed in their \fIsudoers\fR file entry or is explicitly denied. -This flag is \fI@mail_no_perms@\fR by default. -.IP "mail_no_user" 16 -.IX Item "mail_no_user" -If set, mail will be sent to the \fImailto\fR user if the invoking -user is not in the \fIsudoers\fR file. This flag is \fI@mail_no_user@\fR -by default. -.IP "noexec" 16 -.IX Item "noexec" -If set, all commands run via \fBsudo\fR will behave as if the \f(CW\*(C`NOEXEC\*(C'\fR -tag has been set, unless overridden by a \f(CW\*(C`EXEC\*(C'\fR tag. See the -description of \fI\s-1NOEXEC\s0 and \s-1EXEC\s0\fR below as well as the \*(L"\s-1PREVENTING\s0 \s-1SHELL\s0 -\&\s-1ESCAPES\s0\*(R" section at the end of this manual. This flag is \fIoff\fR by default. -.IP "path_info" 16 -.IX Item "path_info" -Normally, \fBsudo\fR will tell the user when a command could not be -found in their \f(CW\*(C`PATH\*(C'\fR environment variable. Some sites may wish -to disable this as it could be used to gather information on the -location of executables that the normal user does not have access -to. The disadvantage is that if the executable is simply not in -the user's \f(CW\*(C`PATH\*(C'\fR, \fBsudo\fR will tell the user that they are not -allowed to run it, which can be confusing. This flag is \fI@path_info@\fR -by default. -.IP "passprompt_override" 16 -.IX Item "passprompt_override" -The password prompt specified by \fIpassprompt\fR will normally only -be used if the password prompt provided by systems such as \s-1PAM\s0 matches -the string \*(L"Password:\*(R". If \fIpassprompt_override\fR is set, \fIpassprompt\fR -will always be used. This flag is \fIoff\fR by default. -.IP "preserve_groups" 16 -.IX Item "preserve_groups" -By default, \fBsudo\fR will initialize the group vector to the list of -groups the target user is in. When \fIpreserve_groups\fR is set, the -user's existing group vector is left unaltered. The real and -effective group IDs, however, are still set to match the target -user. This flag is \fIoff\fR by default. -.IP "pwfeedback" 16 -.IX Item "pwfeedback" -By default, \fBsudo\fR reads the password like most other Unix programs, -by turning off echo until the user hits the return (or enter) key. -Some users become confused by this as it appears to them that \fBsudo\fR -has hung at this point. When \fIpwfeedback\fR is set, \fBsudo\fR will -provide visual feedback when the user presses a key. Note that -this does have a security impact as an onlooker may be able to -determine the length of the password being entered. -This flag is \fIoff\fR by default. -.IP "requiretty" 16 -.IX Item "requiretty" -If set, \fBsudo\fR will only run when the user is logged in to a real -tty. When this flag is set, \fBsudo\fR can only be run from a login -session and not via other means such as \fIcron\fR\|(@mansectsu@) or cgi-bin scripts. -This flag is \fIoff\fR by default. -.IP "root_sudo" 16 -.IX Item "root_sudo" -If set, root is allowed to run \fBsudo\fR too. Disabling this prevents users -from \*(L"chaining\*(R" \fBsudo\fR commands to get a root shell by doing something -like \f(CW"sudo sudo /bin/sh"\fR. Note, however, that turning off \fIroot_sudo\fR -will also prevent root from running \fBsudoedit\fR. -Disabling \fIroot_sudo\fR provides no real additional security; it -exists purely for historical reasons. -This flag is \fI@root_sudo@\fR by default. -.IP "rootpw" 16 -.IX Item "rootpw" -If set, \fBsudo\fR will prompt for the root password instead of the password -of the invoking user. This flag is \fIoff\fR by default. -.IP "runaspw" 16 -.IX Item "runaspw" -If set, \fBsudo\fR will prompt for the password of the user defined by the -\&\fIrunas_default\fR option (defaults to \f(CW\*(C`@runas_default@\*(C'\fR) instead of the -password of the invoking user. This flag is \fIoff\fR by default. -.IP "set_home" 16 -.IX Item "set_home" -If enabled and \fBsudo\fR is invoked with the \fB\-s\fR option the \f(CW\*(C`HOME\*(C'\fR -environment variable will be set to the home directory of the target -user (which is root unless the \fB\-u\fR option is used). This effectively -makes the \fB\-s\fR option imply \fB\-H\fR. Note that \f(CW\*(C`HOME\*(C'\fR is already -set when the the \fIenv_reset\fR option is enabled, so \fIset_home\fR is -only effective for configurations where \fIenv_reset\fR is disabled. -This flag is \fIoff\fR by default. -.IP "set_logname" 16 -.IX Item "set_logname" -Normally, \fBsudo\fR will set the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR and \f(CW\*(C`USERNAME\*(C'\fR -environment variables to the name of the target user (usually root -unless the \fB\-u\fR option is given). However, since some programs -(including the \s-1RCS\s0 revision control system) use \f(CW\*(C`LOGNAME\*(C'\fR to -determine the real identity of the user, it may be desirable to -change this behavior. This can be done by negating the set_logname -option. Note that if the \fIenv_reset\fR option has not been disabled, -entries in the \fIenv_keep\fR list will override the value of -\&\fIset_logname\fR. This flag is \fIon\fR by default. -.IP "setenv" 16 -.IX Item "setenv" -Allow the user to disable the \fIenv_reset\fR option from the command -line. Additionally, environment variables set via the command line -are not subject to the restrictions imposed by \fIenv_check\fR, -\&\fIenv_delete\fR, or \fIenv_keep\fR. As such, only trusted users should -be allowed to set variables in this manner. This flag is \fIoff\fR -by default. -.IP "shell_noargs" 16 -.IX Item "shell_noargs" -If set and \fBsudo\fR is invoked with no arguments it acts as if the -\&\fB\-s\fR option had been given. That is, it runs a shell as root (the -shell is determined by the \f(CW\*(C`SHELL\*(C'\fR environment variable if it is -set, falling back on the shell listed in the invoking user's -/etc/passwd entry if not). This flag is \fIoff\fR by default. -.IP "stay_setuid" 16 -.IX Item "stay_setuid" -Normally, when \fBsudo\fR executes a command the real and effective -UIDs are set to the target user (root by default). This option -changes that behavior such that the real \s-1UID\s0 is left as the invoking -user's \s-1UID\s0. In other words, this makes \fBsudo\fR act as a setuid -wrapper. This can be useful on systems that disable some potentially -dangerous functionality when a program is run setuid. This option -is only effective on systems with either the \fIsetreuid()\fR or \fIsetresuid()\fR -function. This flag is \fIoff\fR by default. -.IP "targetpw" 16 -.IX Item "targetpw" -If set, \fBsudo\fR will prompt for the password of the user specified -by the \fB\-u\fR option (defaults to \f(CW\*(C`root\*(C'\fR) instead of the password -of the invoking user. In addition, the timestamp file name will -include the target user's name. Note that this flag precludes the -use of a uid not listed in the passwd database as an argument to -the \fB\-u\fR option. This flag is \fIoff\fR by default. -.IP "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 -enabled, \fBsudo\fR will use a file named for the tty the user is -logged in on in the user's time stamp directory. If disabled, the -time stamp of the directory is used instead. This flag is -\&\fI@tty_tickets@\fR by default. -.IP "umask_override" 16 -.IX Item "umask_override" -If set, \fBsudo\fR will set the umask as specified by \fIsudoers\fR without -modification. This makes it possible to specify a more permissive -umask in \fIsudoers\fR than the user's own umask and matches historical -behavior. If \fIumask_override\fR is not set, \fBsudo\fR will set the -umask to be the union of the user's umask and what is specified in -\&\fIsudoers\fR. This flag is \fIoff\fR by default. -.if \n(LC \{\ -.IP "use_loginclass" 16 -.IX Item "use_loginclass" -If set, \fBsudo\fR will apply the defaults specified for the target user's -login class if one exists. Only available if \fBsudo\fR is configured with -the \-\-with\-logincap option. This flag is \fIoff\fR by default. -\} -.IP "use_pty" 16 -.IX Item "use_pty" -If set, \fBsudo\fR will run the command in a pseudo-pty even if no I/O -logging is being gone. A malicious program run under \fBsudo\fR could -conceivably fork a background process that retains to the user's -terminal device after the main program has finished executing. Use -of this option will make that impossible. -.IP "visiblepw" 16 -.IX Item "visiblepw" -By default, \fBsudo\fR will refuse to run if the user must enter a -password but it is not possible to disable echo on the terminal. -If the \fIvisiblepw\fR flag is set, \fBsudo\fR will prompt for a password -even when it would be visible on the screen. This makes it possible -to run things like \f(CW"rsh somehost sudo ls"\fR since \fIrsh\fR\|(1) does -not allocate a tty. This flag is \fIoff\fR by default. -.PP -\&\fBIntegers\fR: -.IP "closefrom" 16 -.IX Item "closefrom" -Before it executes a command, \fBsudo\fR will close all open file -descriptors other than standard input, standard output and standard -error (ie: file descriptors 0\-2). The \fIclosefrom\fR option can be used -to specify a different file descriptor at which to start closing. -The default is \f(CW3\fR. -.IP "passwd_tries" 16 -.IX Item "passwd_tries" -The number of tries a user gets to enter his/her password before -\&\fBsudo\fR logs the failure and exits. The default is \f(CW\*(C`@passwd_tries@\*(C'\fR. -.PP -\&\fBIntegers that can be used in a boolean context\fR: -.IP "loglinelen" 16 -.IX Item "loglinelen" -Number of characters per line for the file log. This value is used -to decide when to wrap lines for nicer log files. This has no -effect on the syslog log file, only the file log. The default is -\&\f(CW\*(C`@loglen@\*(C'\fR (use 0 or negate the option to disable word wrap). -.IP "passwd_timeout" 16 -.IX Item "passwd_timeout" -Number of minutes before the \fBsudo\fR password prompt times out, or -\&\f(CW0\fR for no timeout. The timeout may include a fractional component -if minute granularity is insufficient, for example \f(CW2.5\fR. The -default is \f(CW\*(C`@password_timeout@\*(C'\fR. -.IP "timestamp_timeout" 16 -.IX Item "timestamp_timeout" -Number of minutes that can elapse before \fBsudo\fR will ask for a -passwd again. The timeout may include a fractional component if -minute granularity is insufficient, for example \f(CW2.5\fR. The default -is \f(CW\*(C`@timeout@\*(C'\fR. Set this to \f(CW0\fR to always prompt for a password. -If set to a value less than \f(CW0\fR the user's timestamp will never -expire. This can be used to allow users to create or delete their -own timestamps via \f(CW\*(C`sudo \-v\*(C'\fR and \f(CW\*(C`sudo \-k\*(C'\fR respectively. -.IP "umask" 16 -.IX Item "umask" -Umask to use when running the command. Negate this option or set -it to 0777 to preserve the user's umask. The actual umask that is -used will be the union of the user's umask and \f(CW\*(C`@sudo_umask@\*(C'\fR. -This guarantees that \fBsudo\fR never lowers the umask when running a -command. Note on systems that use \s-1PAM\s0, the default \s-1PAM\s0 configuration -may specify its own umask which will override the value set in -\&\fIsudoers\fR. -.PP -\&\fBStrings\fR: -.IP "badpass_message" 16 -.IX Item "badpass_message" -Message that is displayed if a user enters an incorrect password. -The default is \f(CW\*(C`@badpass_message@\*(C'\fR unless insults are enabled. -.IP "editor" 16 -.IX Item "editor" -A colon (':') separated list of editors allowed to be used with -\&\fBvisudo\fR. \fBvisudo\fR will choose the editor that matches the user's -\&\s-1EDITOR\s0 environment variable if possible, or the first editor in the -list that exists and is executable. The default is \f(CW"@editor@"\fR. -.IP "mailsub" 16 -.IX Item "mailsub" -Subject of the mail sent to the \fImailto\fR user. The escape \f(CW%h\fR -will expand to the host name of the machine. -Default is \f(CW\*(C`@mailsub@\*(C'\fR. -.IP "noexec_file" 16 -.IX Item "noexec_file" -Path to a shared library containing dummy versions of the \fIexecv()\fR, -\&\fIexecve()\fR and \fIfexecve()\fR library functions that just return an error. -This is used to implement the \fInoexec\fR functionality on systems that -support \f(CW\*(C`LD_PRELOAD\*(C'\fR or its equivalent. Defaults to \fI@noexec_file@\fR. -.IP "passprompt" 16 -.IX Item "passprompt" -The default prompt to use when asking for a password; can be overridden -via the \fB\-p\fR option or the \f(CW\*(C`SUDO_PROMPT\*(C'\fR environment variable. -The following percent (`\f(CW\*(C`%\*(C'\fR') escapes are supported: -.RS 16 -.ie n .IP "%H" 4 -.el .IP "\f(CW%H\fR" 4 -.IX Item "%H" -expanded to the local host name including the domain name -(on if the machine's host name is fully qualified or the \fIfqdn\fR -option is set) -.ie n .IP "%h" 4 -.el .IP "\f(CW%h\fR" 4 -.IX Item "%h" -expanded to the local host name without the domain name -.ie n .IP "%p" 4 -.el .IP "\f(CW%p\fR" 4 -.IX Item "%p" -expanded to the user whose password is being asked for (respects the -\&\fIrootpw\fR, \fItargetpw\fR and \fIrunaspw\fR flags in \fIsudoers\fR) -.ie n .IP "%U" 4 -.el .IP "\f(CW%U\fR" 4 -.IX Item "%U" -expanded to the login name of the user the command will -be run as (defaults to root) -.ie n .IP "%u" 4 -.el .IP "\f(CW%u\fR" 4 -.IX Item "%u" -expanded to the invoking user's login name -.ie n .IP "\*(C`%%\*(C'" 4 -.el .IP "\f(CW\*(C`%%\*(C'\fR" 4 -.IX Item "%%" -two consecutive \f(CW\*(C`%\*(C'\fR characters are collapsed into a single \f(CW\*(C`%\*(C'\fR character -.RE -.RS 16 -.Sp -The default value is \f(CW\*(C`@passprompt@\*(C'\fR. -.RE -.if \n(SL \{\ -.IP "role" 16 -.IX Item "role" -The default SELinux role to use when constructing a new security -context to run the command. The default role may be overridden on -a per-command basis in \fIsudoers\fR or via command line options. -This option is only available whe \fBsudo\fR is built with SELinux support. -\} -.IP "runas_default" 16 -.IX Item "runas_default" -The default user to run commands as if the \fB\-u\fR option is not specified -on the command line. This defaults to \f(CW\*(C`@runas_default@\*(C'\fR. -Note that if \fIrunas_default\fR is set it \fBmust\fR occur before -any \f(CW\*(C`Runas_Alias\*(C'\fR specifications. -.IP "syslog_badpri" 16 -.IX Item "syslog_badpri" -Syslog priority to use when user authenticates unsuccessfully. -Defaults to \f(CW\*(C`@badpri@\*(C'\fR. -.IP "syslog_goodpri" 16 -.IX Item "syslog_goodpri" -Syslog priority to use when user authenticates successfully. -Defaults to \f(CW\*(C`@goodpri@\*(C'\fR. -.IP "sudoers_locale" 16 -.IX Item "sudoers_locale" -Locale to use when parsing the sudoers file. Note that changing -the locale may affect how sudoers is interpreted. -Defaults to \f(CW"C"\fR. -.IP "timestampdir" 16 -.IX Item "timestampdir" -The directory in which \fBsudo\fR stores its timestamp files. -The default is \fI@timedir@\fR. -.IP "timestampowner" 16 -.IX Item "timestampowner" -The owner of the timestamp directory and the timestamps stored therein. -The default is \f(CW\*(C`root\*(C'\fR. -.if \n(SL \{\ -.IP "type" 16 -.IX Item "type" -The default SELinux type to use when constructing a new security -context to run the command. The default type may be overridden on -a per-command basis in \fIsudoers\fR or via command line options. -This option is only available whe \fBsudo\fR is built with SELinux support. -\} -.PP -\&\fBStrings that can be used in a boolean context\fR: -.IP "askpass" 12 -.IX Item "askpass" -The \fIaskpass\fR option specifies the fully qualified path to a helper -program used to read the user's password when no terminal is -available. This may be the case when \fBsudo\fR is executed from a -graphical (as opposed to text-based) application. The program -specified by \fIaskpass\fR should display the argument passed to it -as the prompt and write the user's password to the standard output. -The value of \fIaskpass\fR may be overridden by the \f(CW\*(C`SUDO_ASKPASS\*(C'\fR -environment variable. -.IP "env_file" 12 -.IX Item "env_file" -The \fIenv_file\fR options specifies the fully qualified path to a -file containing variables to be set in the environment of the program -being run. Entries in this file should either be of the form -\&\f(CW\*(C`VARIABLE=value\*(C'\fR or \f(CW\*(C`export VARIABLE=value\*(C'\fR. The value may -optionally be surrounded by single or double quotes. Variables in -this file are subject to other \fBsudo\fR environment settings such -as \fIenv_keep\fR and \fIenv_check\fR. -.IP "exempt_group" 12 -.IX Item "exempt_group" -Users in this group are exempt from password and \s-1PATH\s0 requirements. -This is not set by default. -.IP "lecture" 12 -.IX Item "lecture" -This option controls when a short lecture will be printed along with -the password prompt. It has the following possible values: -.RS 12 -.IP "always" 8 -.IX Item "always" -Always lecture the user. -.IP "never" 8 -.IX Item "never" -Never lecture the user. -.IP "once" 8 -.IX Item "once" -Only lecture the user the first time they run \fBsudo\fR. -.RE -.RS 12 -.Sp -If no value is specified, a value of \fIonce\fR is implied. -Negating the option results in a value of \fInever\fR being used. -The default value is \fI@lecture@\fR. -.RE -.IP "lecture_file" 12 -.IX Item "lecture_file" -Path to a file containing an alternate \fBsudo\fR lecture that will -be used in place of the standard lecture if the named file exists. -By default, \fBsudo\fR uses a built-in lecture. -.IP "listpw" 12 -.IX Item "listpw" -This option controls when a password will be required when a -user runs \fBsudo\fR with the \fB\-l\fR option. It has the following possible values: -.RS 12 -.IP "all" 8 -.IX Item "all" -All the user's \fIsudoers\fR entries for the current host must have -the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. -.IP "always" 8 -.IX Item "always" -The user must always enter a password to use the \fB\-l\fR option. -.IP "any" 8 -.IX Item "any" -At least one of the user's \fIsudoers\fR entries for the current host -must have the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. -.IP "never" 8 -.IX Item "never" -The user need never enter a password to use the \fB\-l\fR option. -.RE -.RS 12 -.Sp -If no value is specified, a value of \fIany\fR is implied. -Negating the option results in a value of \fInever\fR being used. -The default value is \fIany\fR. -.RE -.IP "logfile" 12 -.IX Item "logfile" -Path to the \fBsudo\fR log file (not the syslog log file). Setting a path -turns on logging to a file; negating this option turns it off. -By default, \fBsudo\fR logs via syslog. -.IP "mailerflags" 12 -.IX Item "mailerflags" -Flags to use when invoking mailer. Defaults to \fB\-t\fR. -.IP "mailerpath" 12 -.IX Item "mailerpath" -Path to mail program used to send warning mail. -Defaults to the path to sendmail found at configure time. -.IP "mailfrom" 12 -.IX Item "mailfrom" -Address to use for the \*(L"from\*(R" address when sending warning and error -mail. The address should be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR) to -protect against \fBsudo\fR interpreting the \f(CW\*(C`@\*(C'\fR sign. Defaults to -the name of the user running \fBsudo\fR. -.IP "mailto" 12 -.IX Item "mailto" -Address to send warning and error mail to. The address should -be enclosed in double quotes (\f(CW\*(C`"\*(C'\fR) to protect against \fBsudo\fR -interpreting the \f(CW\*(C`@\*(C'\fR sign. Defaults to \f(CW\*(C`@mailto@\*(C'\fR. -.IP "secure_path" 12 -.IX Item "secure_path" -Path used for every command run from \fBsudo\fR. If you don't trust the -people running \fBsudo\fR to have a sane \f(CW\*(C`PATH\*(C'\fR environment variable you may -want to use this. Another use is if you want to have the \*(L"root path\*(R" -be separate from the \*(L"user path.\*(R" Users in the group specified by the -\&\fIexempt_group\fR option are not affected by \fIsecure_path\fR. -This option is @secure_path@ by default. -.IP "syslog" 12 -.IX Item "syslog" -Syslog facility if syslog is being used for logging (negate to -disable syslog logging). Defaults to \f(CW\*(C`@logfac@\*(C'\fR. -.IP "verifypw" 12 -.IX Item "verifypw" -This option controls when a password will be required when a user runs -\&\fBsudo\fR with the \fB\-v\fR option. It has the following possible values: -.RS 12 -.IP "all" 8 -.IX Item "all" -All the user's \fIsudoers\fR entries for the current host must have -the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. -.IP "always" 8 -.IX Item "always" -The user must always enter a password to use the \fB\-v\fR option. -.IP "any" 8 -.IX Item "any" -At least one of the user's \fIsudoers\fR entries for the current host -must have the \f(CW\*(C`NOPASSWD\*(C'\fR flag set to avoid entering a password. -.IP "never" 8 -.IX Item "never" -The user need never enter a password to use the \fB\-v\fR option. -.RE -.RS 12 -.Sp -If no value is specified, a value of \fIall\fR is implied. -Negating the option results in a value of \fInever\fR being used. -The default value is \fIall\fR. -.RE -.PP -\&\fBLists that can be used in a boolean context\fR: -.IP "env_check" 16 -.IX Item "env_check" -Environment variables to be removed from the user's environment if -the variable's value contains \f(CW\*(C`%\*(C'\fR or \f(CW\*(C`/\*(C'\fR characters. This can -be used to guard against printf-style format vulnerabilities in -poorly-written programs. The argument may be a double-quoted, -space-separated list or a single value without double-quotes. The -list can be replaced, added to, deleted from, or disabled by using -the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and \f(CW\*(C`!\*(C'\fR operators respectively. Regardless -of whether the \f(CW\*(C`env_reset\*(C'\fR option is enabled or disabled, variables -specified by \f(CW\*(C`env_check\*(C'\fR will be preserved in the environment if -they pass the aforementioned check. The default list of environment -variables to check is displayed when \fBsudo\fR is run by root with -the \fI\-V\fR option. -.IP "env_delete" 16 -.IX Item "env_delete" -Environment variables to be removed from the user's environment -when the \fIenv_reset\fR option is not in effect. The argument may -be a double-quoted, space-separated list or a single value without -double-quotes. The list can be replaced, added to, deleted from, -or disabled by using the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and \f(CW\*(C`!\*(C'\fR operators -respectively. The default list of environment variables to remove -is displayed when \fBsudo\fR is run by root with the \fI\-V\fR option. -Note that many operating systems will remove potentially dangerous -variables from the environment of any setuid process (such as -\&\fBsudo\fR). -.IP "env_keep" 16 -.IX Item "env_keep" -Environment variables to be preserved in the user's environment -when the \fIenv_reset\fR option is in effect. This allows fine-grained -control over the environment \fBsudo\fR\-spawned processes will receive. -The argument may be a double-quoted, space-separated list or a -single value without double-quotes. The list can be replaced, added -to, deleted from, or disabled by using the \f(CW\*(C`=\*(C'\fR, \f(CW\*(C`+=\*(C'\fR, \f(CW\*(C`\-=\*(C'\fR, and -\&\f(CW\*(C`!\*(C'\fR operators respectively. The default list of variables to keep -is displayed when \fBsudo\fR is run by root with the \fI\-V\fR option. -.PP -When logging via \fIsyslog\fR\|(3), \fBsudo\fR accepts the following values -for the syslog facility (the value of the \fBsyslog\fR Parameter): -\&\fBauthpriv\fR (if your \s-1OS\s0 supports it), \fBauth\fR, \fBdaemon\fR, \fBuser\fR, -\&\fBlocal0\fR, \fBlocal1\fR, \fBlocal2\fR, \fBlocal3\fR, \fBlocal4\fR, \fBlocal5\fR, -\&\fBlocal6\fR, and \fBlocal7\fR. The following syslog priorities are -supported: \fBalert\fR, \fBcrit\fR, \fBdebug\fR, \fBemerg\fR, \fBerr\fR, \fBinfo\fR, -\&\fBnotice\fR, and \fBwarning\fR. -.SH "FILES" -.IX Header "FILES" -.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24 -.el .IP "\fI@sysconfdir@/sudoers\fR" 24 -.IX Item "@sysconfdir@/sudoers" -List of who can run what -.IP "\fI/etc/group\fR" 24 -.IX Item "/etc/group" -Local groups file -.IP "\fI/etc/netgroup\fR" 24 -.IX Item "/etc/netgroup" -List of network groups -.IP "\fI/var/log/sudo\-io\fR" 24 -.IX Item "/var/log/sudo-io" -I/O log files -.SH "EXAMPLES" -.IX Header "EXAMPLES" -Below are example \fIsudoers\fR entries. Admittedly, some of -these are a bit contrived. First, we allow a few environment -variables to pass and then define our \fIaliases\fR: -.PP -.Vb 4 -\& # Run X applications through sudo; HOME is used to find the -\& # .Xauthority file. Note that other programs use HOME to find -\& # configuration files and this may lead to privilege escalation! -\& Defaults env_keep += "DISPLAY HOME" -\& -\& # User alias specification -\& User_Alias FULLTIMERS = millert, mikef, dowdy -\& User_Alias PARTTIMERS = bostley, jwfox, crawl -\& User_Alias WEBMASTERS = will, wendy, wim -\& -\& # Runas alias specification -\& Runas_Alias OP = root, operator -\& Runas_Alias DB = oracle, sybase -\& Runas_Alias ADMINGRP = adm, oper -\& -\& # Host alias specification -\& Host_Alias SPARC = bigtime, eclipse, moet, anchor :\e -\& SGI = grolsch, dandelion, black :\e -\& ALPHA = widget, thalamus, foobar :\e -\& HPPA = boa, nag, python -\& Host_Alias CUNETS = 128.138.0.0/255.255.0.0 -\& Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 -\& Host_Alias SERVERS = master, mail, www, ns -\& Host_Alias CDROM = orion, perseus, hercules -\& -\& # Cmnd alias specification -\& Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\e -\& /usr/sbin/restore, /usr/sbin/rrestore -\& Cmnd_Alias KILL = /usr/bin/kill -\& Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm -\& Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown -\& Cmnd_Alias HALT = /usr/sbin/halt -\& Cmnd_Alias REBOOT = /usr/sbin/reboot -\& Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \e -\& /usr/local/bin/tcsh, /usr/bin/rsh, \e -\& /usr/local/bin/zsh -\& Cmnd_Alias SU = /usr/bin/su -\& Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less -.Ve -.PP -Here we override some of the compiled in default values. We want -\&\fBsudo\fR to log via \fIsyslog\fR\|(3) using the \fIauth\fR facility in all -cases. We don't want to subject the full time staff to the \fBsudo\fR -lecture, user \fBmillert\fR need not give a password, and we don't -want to reset the \f(CW\*(C`LOGNAME\*(C'\fR, \f(CW\*(C`USER\*(C'\fR or \f(CW\*(C`USERNAME\*(C'\fR environment -variables when running commands as root. Additionally, on the -machines in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, we keep an additional -local log file and make sure we log the year in each log line since -the log entries will be kept around for several years. Lastly, we -disable shell escapes for the commands in the \s-1PAGERS\s0 \f(CW\*(C`Cmnd_Alias\*(C'\fR -(\fI/usr/bin/more\fR, \fI/usr/bin/pg\fR and \fI/usr/bin/less\fR). -.PP -.Vb 7 -\& # Override built\-in defaults -\& Defaults syslog=auth -\& Defaults>root !set_logname -\& Defaults:FULLTIMERS !lecture -\& Defaults:millert !authenticate -\& Defaults@SERVERS log_year, logfile=/var/log/sudo.log -\& Defaults!PAGERS noexec -.Ve -.PP -The \fIUser specification\fR is the part that actually determines who may -run what. -.PP -.Vb 2 -\& root ALL = (ALL) ALL -\& %wheel ALL = (ALL) ALL -.Ve -.PP -We let \fBroot\fR and any user in group \fBwheel\fR run any command on any -host as any user. -.PP -.Vb 1 -\& FULLTIMERS ALL = NOPASSWD: ALL -.Ve -.PP -Full time sysadmins (\fBmillert\fR, \fBmikef\fR, and \fBdowdy\fR) may run any -command on any host without authenticating themselves. -.PP -.Vb 1 -\& PARTTIMERS ALL = ALL -.Ve -.PP -Part time sysadmins (\fBbostley\fR, \fBjwfox\fR, and \fBcrawl\fR) may run any -command on any host but they must authenticate themselves first -(since the entry lacks the \f(CW\*(C`NOPASSWD\*(C'\fR tag). -.PP -.Vb 1 -\& jack CSNETS = ALL -.Ve -.PP -The user \fBjack\fR may run any command on the machines in the \fI\s-1CSNETS\s0\fR alias -(the networks \f(CW128.138.243.0\fR, \f(CW128.138.204.0\fR, and \f(CW128.138.242.0\fR). -Of those networks, only \f(CW128.138.204.0\fR has an explicit netmask (in -\&\s-1CIDR\s0 notation) indicating it is a class C network. For the other -networks in \fI\s-1CSNETS\s0\fR, the local machine's netmask will be used -during matching. -.PP -.Vb 1 -\& lisa CUNETS = ALL -.Ve -.PP -The user \fBlisa\fR may run any command on any host in the \fI\s-1CUNETS\s0\fR alias -(the class B network \f(CW128.138.0.0\fR). -.PP -.Vb 2 -\& operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\e -\& sudoedit /etc/printcap, /usr/oper/bin/ -.Ve -.PP -The \fBoperator\fR user may run commands limited to simple maintenance. -Here, those are commands related to backups, killing processes, the -printing system, shutting down the system, and any commands in the -directory \fI/usr/oper/bin/\fR. -.PP -.Vb 1 -\& joe ALL = /usr/bin/su operator -.Ve -.PP -The user \fBjoe\fR may only \fIsu\fR\|(1) to operator. -.PP -.Vb 1 -\& pete HPPA = /usr/bin/passwd [A\-Za\-z]*, !/usr/bin/passwd root -\& -\& %opers ALL = (: ADMINGRP) /usr/sbin/ -.Ve -.PP -Users in the \fBopers\fR group may run commands in \fI/usr/sbin/\fR as themselves -with any group in the \fI\s-1ADMINGRP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (the \fBadm\fR and \fBoper\fR -groups). -.PP -The user \fBpete\fR is allowed to change anyone's password except for -root on the \fI\s-1HPPA\s0\fR machines. Note that this assumes \fIpasswd\fR\|(1) -does not take multiple user names on the command line. -.PP -.Vb 1 -\& bob SPARC = (OP) ALL : SGI = (OP) ALL -.Ve -.PP -The user \fBbob\fR may run anything on the \fI\s-1SPARC\s0\fR and \fI\s-1SGI\s0\fR machines -as any user listed in the \fI\s-1OP\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR (\fBroot\fR and \fBoperator\fR). -.PP -.Vb 1 -\& jim +biglab = ALL -.Ve -.PP -The user \fBjim\fR may run any command on machines in the \fIbiglab\fR netgroup. -\&\fBsudo\fR knows that \*(L"biglab\*(R" is a netgroup due to the '+' prefix. -.PP -.Vb 1 -\& +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser -.Ve -.PP -Users in the \fBsecretaries\fR netgroup need to help manage the printers -as well as add and remove users, so they are allowed to run those -commands on all machines. -.PP -.Vb 1 -\& fred ALL = (DB) NOPASSWD: ALL -.Ve -.PP -The user \fBfred\fR can run commands as any user in the \fI\s-1DB\s0\fR \f(CW\*(C`Runas_Alias\*(C'\fR -(\fBoracle\fR or \fBsybase\fR) without giving a password. -.PP -.Vb 1 -\& john ALPHA = /usr/bin/su [!\-]*, !/usr/bin/su *root* -.Ve -.PP -On the \fI\s-1ALPHA\s0\fR machines, user \fBjohn\fR may su to anyone except root -but he is not allowed to specify any options to the \fIsu\fR\|(1) command. -.PP -.Vb 1 -\& jen ALL, !SERVERS = ALL -.Ve -.PP -The user \fBjen\fR may run any command on any machine except for those -in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR (master, mail, www and ns). -.PP -.Vb 1 -\& jill SERVERS = /usr/bin/, !SU, !SHELLS -.Ve -.PP -For any machine in the \fI\s-1SERVERS\s0\fR \f(CW\*(C`Host_Alias\*(C'\fR, \fBjill\fR may run -any commands in the directory \fI/usr/bin/\fR except for those commands -belonging to the \fI\s-1SU\s0\fR and \fI\s-1SHELLS\s0\fR \f(CW\*(C`Cmnd_Aliases\*(C'\fR. -.PP -.Vb 1 -\& steve CSNETS = (operator) /usr/local/op_commands/ -.Ve -.PP -The user \fBsteve\fR may run any command in the directory /usr/local/op_commands/ -but only as user operator. -.PP -.Vb 1 -\& matt valkyrie = KILL -.Ve -.PP -On his personal workstation, valkyrie, \fBmatt\fR needs to be able to -kill hung processes. -.PP -.Vb 1 -\& WEBMASTERS www = (www) ALL, (root) /usr/bin/su www -.Ve -.PP -On the host www, any user in the \fI\s-1WEBMASTERS\s0\fR \f(CW\*(C`User_Alias\*(C'\fR (will, -wendy, and wim), may run any command as user www (which owns the -web pages) or simply \fIsu\fR\|(1) to www. -.PP -.Vb 2 -\& ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\e -\& /sbin/mount \-o nosuid\e,nodev /dev/cd0a /CDROM -.Ve -.PP -Any user may mount or unmount a CD-ROM on the machines in the \s-1CDROM\s0 -\&\f(CW\*(C`Host_Alias\*(C'\fR (orion, perseus, hercules) without entering a password. -This is a bit tedious for users to type, so it is a prime candidate -for encapsulating in a shell script. -.SH "SECURITY NOTES" -.IX Header "SECURITY NOTES" -It is generally not effective to \*(L"subtract\*(R" commands from \f(CW\*(C`ALL\*(C'\fR -using the '!' operator. A user can trivially circumvent this -by copying the desired command to a different name and then -executing that. For example: -.PP -.Vb 1 -\& bill ALL = ALL, !SU, !SHELLS -.Ve -.PP -Doesn't really prevent \fBbill\fR from running the commands listed in -\&\fI\s-1SU\s0\fR or \fI\s-1SHELLS\s0\fR since he can simply copy those commands to a -different name, or use a shell escape from an editor or other -program. Therefore, these kind of restrictions should be considered -advisory at best (and reinforced by policy). -.PP -Furthermore, if the \fIfast_glob\fR option is in use, it is not possible -to reliably negate commands where the path name includes globbing -(aka wildcard) characters. This is because the C library's -\&\fIfnmatch\fR\|(3) function cannot resolve relative paths. While this -is typically only an inconvenience for rules that grant privileges, -it can result in a security issue for rules that subtract or revoke -privileges. -.PP -For example, given the following \fIsudoers\fR entry: -.PP -.Vb 2 -\& john ALL = /usr/bin/passwd [a\-zA\-Z0\-9]*, /usr/bin/chsh [a\-zA\-Z0\-9]*, -\& /usr/bin/chfn [a\-zA\-Z0\-9]*, !/usr/bin/* root -.Ve -.PP -User \fBjohn\fR can still run \f(CW\*(C`/usr/bin/passwd root\*(C'\fR if \fIfast_glob\fR is -enabled by changing to \fI/usr/bin\fR and running \f(CW\*(C`./passwd root\*(C'\fR instead. -.SH "PREVENTING SHELL ESCAPES" -.IX Header "PREVENTING SHELL ESCAPES" -Once \fBsudo\fR executes a program, that program is free to do whatever -it pleases, including run other programs. This can be a security -issue since it is not uncommon for a program to allow shell escapes, -which lets a user bypass \fBsudo\fR's access control and logging. -Common programs that permit shell escapes include shells (obviously), -editors, paginators, mail and terminal programs. -.PP -There are two basic approaches to this problem: -.IP "restrict" 10 -.IX Item "restrict" -Avoid giving users access to commands that allow the user to run -arbitrary commands. Many editors have a restricted mode where shell -escapes are disabled, though \fBsudoedit\fR is a better solution to -running editors via \fBsudo\fR. Due to the large number of programs that -offer shell escapes, restricting users to the set of programs that -do not if often unworkable. -.IP "noexec" 10 -.IX Item "noexec" -Many systems that support shared libraries have the ability to -override default library functions by pointing an environment -variable (usually \f(CW\*(C`LD_PRELOAD\*(C'\fR) to an alternate shared library. -On such systems, \fBsudo\fR's \fInoexec\fR functionality can be used to -prevent a program run by \fBsudo\fR from executing any other programs. -Note, however, that this applies only to native dynamically-linked -executables. Statically-linked executables and foreign executables -running under binary emulation are not affected. -.Sp -To tell whether or not \fBsudo\fR supports \fInoexec\fR, you can run -the following as root: -.Sp -.Vb 1 -\& sudo \-V | grep "dummy exec" -.Ve -.Sp -If the resulting output contains a line that begins with: -.Sp -.Vb 1 -\& File containing dummy exec functions: -.Ve -.Sp -then \fBsudo\fR may be able to replace the exec family of functions -in the standard library with its own that simply return an error. -Unfortunately, there is no foolproof way to know whether or not -\&\fInoexec\fR will work at compile-time. \fInoexec\fR should work on -SunOS, Solaris, *BSD, Linux, \s-1IRIX\s0, Tru64 \s-1UNIX\s0, MacOS X, and HP-UX -11.x. It is known \fBnot\fR to work on \s-1AIX\s0 and UnixWare. \fInoexec\fR -is expected to work on most operating systems that support the -\&\f(CW\*(C`LD_PRELOAD\*(C'\fR environment variable. Check your operating system's -manual pages for the dynamic linker (usually ld.so, ld.so.1, dyld, -dld.sl, rld, or loader) to see if \f(CW\*(C`LD_PRELOAD\*(C'\fR is supported. -.Sp -To enable \fInoexec\fR for a command, use the \f(CW\*(C`NOEXEC\*(C'\fR tag as documented -in the User Specification section above. Here is that example again: -.Sp -.Vb 1 -\& aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi -.Ve -.Sp -This allows user \fBaaron\fR to run \fI/usr/bin/more\fR and \fI/usr/bin/vi\fR -with \fInoexec\fR enabled. This will prevent those two commands from -executing other commands (such as a shell). If you are unsure -whether or not your system is capable of supporting \fInoexec\fR you -can always just try it out and see if it works. -.PP -Note that restricting shell escapes is not a panacea. Programs -running as root are still capable of many potentially hazardous -operations (such as changing or overwriting files) that could lead -to unintended privilege escalation. In the specific case of an -editor, a safer approach is to give the user permission to run -\&\fBsudoedit\fR. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -\&\fIrsh\fR\|(1), \fIsu\fR\|(1), \fIfnmatch\fR\|(3), \fIglob\fR\|(3), \fIsudo\fR\|(@mansectsu@), \fIvisudo\fR\|(8) -.SH "CAVEATS" -.IX Header "CAVEATS" -The \fIsudoers\fR file should \fBalways\fR be edited by the \fBvisudo\fR -command which locks the file and does grammatical checking. It is -imperative that \fIsudoers\fR be free of syntax errors since \fBsudo\fR -will not run with a syntactically incorrect \fIsudoers\fR file. -.PP -When using netgroups of machines (as opposed to users), if you -store fully qualified host name in the netgroup (as is usually the -case), you either need to have the machine's host name be fully qualified -as returned by the \f(CW\*(C`hostname\*(C'\fR command or use the \fIfqdn\fR option in -\&\fIsudoers\fR. -.SH "BUGS" -.IX Header "BUGS" -If you feel you have found a bug in \fBsudo\fR, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ -.SH "SUPPORT" -.IX Header "SUPPORT" -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or -search the archives. -.SH "DISCLAIMER" -.IX Header "DISCLAIMER" -\&\fBsudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 -file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudoers.man.pl b/sudoers.man.pl deleted file mode 100644 index 6e5da2c..0000000 --- a/sudoers.man.pl +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/perl -p - -BEGIN { - $cond = -1; -} - -# Initialize the numeric register we use for conditionals -if ($cond == -1) { - $_ = ".nr SL \@SEMAN\@\n.nr BA \@BAMAN\@\n.nr LC \@LCMAN\@\n.\\\"\n$_"; - $cond = 0; -} - -# Make SELinux_Spec conditional -if (/(.*)SELinux_Spec\? (.*)$/) { - $_ = ".ie \\n(SL $_.el $1$2\n"; -} elsif (/^(.*SELinux_Spec ::=)/) { - $_ = ".if \\n(SL \\{\\\n$_"; -} elsif (/^(.*Tag_Spec ::=)/) { - $_ = "\\}\n$_"; -} - -if (/^\.S[Sh] "SELinux_Spec"/) { - $_ = ".if \\n(SL \\{\\\n$_"; - $cond = 1; -} elsif (/^\.IP "(role|type)"/) { - $_ = ".if \\n(SL \\{\\\n$_"; - $cond = 1; -} elsif (/^\.IP "use_loginclass"/) { - $_ = ".if \\n(LC \\{\\\n$_"; - $cond = 1; -} elsif ($cond && /^\.(Sh|SS|IP|PP)/) { - $_ = "\\}\n$_"; - $cond = 0; -} - -# Fix up broken pod2man formatting of F<@foo@/bar> -s/\\fI\\f(\(C)?I\@([^\@]*)\\fI\@/\\fI\@$2\@/g; -s/\\f\(\CW\@([^\@]*)\\fR\@/\@$1\@/g; -#\f(CW@secure_path\fR@ diff --git a/sudoers.pod b/sudoers.pod deleted file mode 100644 index 798295c..0000000 --- a/sudoers.pod +++ /dev/null @@ -1,1688 +0,0 @@ -Copyright (c) 1994-1996, 1998-2005, 2007-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. -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Sponsored in part by the Defense Advanced Research Projects -Agency (DARPA) and Air Force Research Laboratory, Air Force -Materiel Command, USAF, under agreement number F39502-99-1-0512. - -=pod - -=head1 NAME - -sudoers - list of which users may execute what - -=head1 DESCRIPTION - -The I file is composed of two types of entries: aliases -(basically variables) and user specifications (which specify who -may run what). - -When multiple entries match for a user, they are applied in order. -Where there are multiple matches, the last match is used (which is -not necessarily the most specific match). - -The I grammar will be described below in Extended Backus-Naur -Form (EBNF). Don't despair if you don't know what EBNF is; it is -fairly simple, and the definitions below are annotated. - -=head2 Quick guide to EBNF - -EBNF is a concise and exact way of describing the grammar of a language. -Each EBNF definition is made up of I. E.g., - - symbol ::= definition | alternate1 | alternate2 ... - -Each I references others and thus makes up a -grammar for the language. EBNF also contains the following -operators, which many readers will recognize from regular -expressions. Do not, however, confuse them with "wildcard" -characters, which have different meanings. - -=over 4 - -=item C - -Means that the preceding symbol (or group of symbols) is optional. -That is, it may appear once or not at all. - -=item C<*> - -Means that the preceding symbol (or group of symbols) may appear -zero or more times. - -=item C<+> - -Means that the preceding symbol (or group of symbols) may appear -one or more times. - -=back - -Parentheses may be used to group symbols together. For clarity, -we will use single quotes ('') to designate what is a verbatim character -string (as opposed to a symbol name). - -=head2 Aliases - -There are four kinds of aliases: C, C, -C and C. - - Alias ::= 'User_Alias' User_Alias (':' User_Alias)* | - 'Runas_Alias' Runas_Alias (':' Runas_Alias)* | - 'Host_Alias' Host_Alias (':' Host_Alias)* | - 'Cmnd_Alias' Cmnd_Alias (':' Cmnd_Alias)* - - User_Alias ::= NAME '=' User_List - - Runas_Alias ::= NAME '=' Runas_List - - Host_Alias ::= NAME '=' Host_List - - Cmnd_Alias ::= NAME '=' Cmnd_List - - NAME ::= [A-Z]([A-Z][0-9]_)* - -Each I definition is of the form - - Alias_Type NAME = item1, item2, ... - -where I is one of C, C, C, -or C. A C is a string of uppercase letters, numbers, -and underscore characters ('_'). A C B start with an -uppercase letter. It is possible to put several alias definitions -of the same type on a single line, joined by a colon (':'). E.g., - - Alias_Type NAME = item1, item2, item3 : NAME = item4, item5 - -The definitions of what constitutes a valid I member follow. - - User_List ::= User | - User ',' User_List - - User ::= '!'* user name | - '!'* '#'uid | - '!'* '%'group | - '!'* '+'netgroup | - '!'* '%:'nonunix_group | - '!'* 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: - -=over 4 - -=item * - -Group in the same domain: "Group Name" - -=item * - -Group in any domain: "Group Name@FULLY.QUALIFIED.DOMAIN" - -=item * - -Group SID: "S-1-2-34-5678901234-5678901234-5678901234-567" - -=back - -Note that quotes around group names are optional. Unquoted strings must -use a backslash (\) to escape spaces and the '@' symbol. - - Runas_List ::= Runas_Member | - Runas_Member ',' Runas_List - - Runas_Member ::= '!'* user name | - '!'* '#'uid | - '!'* '%'group | - '!'* +netgroup | - '!'* Runas_Alias - -A C is similar to a C except that instead -of Ces it can contain Ces. Note that -user names and groups are matched as strings. In other words, two -users (groups) with the same uid (gid) are considered to be distinct. -If you wish to match all user names with the same uid (e.g.Eroot -and toor), you can use a uid instead (#0 in the example given). - - Host_List ::= Host | - Host ',' Host_List - - Host ::= '!'* host name | - '!'* ip_addr | - '!'* network(/netmask)? | - '!'* '+'netgroup | - '!'* Host_Alias - -A C is made up of one or more host names, IP addresses, -network numbers, netgroups (prefixed with '+') and other aliases. -Again, the value of an item may be negated with the '!' operator. -If you do not specify a netmask along with the network number, -B will query each of the local host's network interfaces and, -if the network number corresponds to one of the hosts's network -interfaces, the corresponding netmask will be used. The netmask -may be specified either in standard IP address notation -(e.g.E255.255.255.0 or ffff:ffff:ffff:ffff::), -or CIDR notation (number of bits, e.g.E24 or 64). A host name may -include shell-style wildcards (see the L section below), -but unless the C command on your machine returns the fully -qualified host name, you'll need to use the I option for -wildcards to be useful. Note B only inspects actual network -interfaces; this means that IP address 127.0.0.1 (localhost) will -never match. Also, the host name "localhost" will only match if -that is the actual host name, which is usually only the case for -non-networked systems. - - Cmnd_List ::= Cmnd | - Cmnd ',' Cmnd_List - - commandname ::= file name | - file name args | - file name '""' - - Cmnd ::= '!'* commandname | - '!'* directory | - '!'* "sudoedit" | - '!'* Cmnd_Alias - -A C is a list of one or more commandnames, directories, and other -aliases. A commandname is a fully qualified file name which may include -shell-style wildcards (see the L section below). A simple -file name allows the user to run the command with any arguments he/she -wishes. However, you may also specify command line arguments (including -wildcards). Alternately, you can specify C<""> to indicate that the command -may only be run B command line arguments. A directory is a -fully qualified path name ending in a '/'. When you specify a directory -in a C, the user will be able to run any file within that directory -(but not in any subdirectories therein). - -If a C has associated command line arguments, then the arguments -in the C must match exactly those given by the user on the command line -(or match the wildcards if there are any). Note that the following -characters must be escaped with a '\' if they are used in command -arguments: ',', ':', '=', '\'. The special command C<"sudoedit"> -is used to permit a user to run B with the B<-e> option (or -as B). It may take command line arguments just as -a normal command does. - -=head2 Defaults - -Certain configuration options may be changed from their default -values at runtime via one or more C lines. These -may affect all users on any host, all users on a specific host, a -specific user, a specific command, or commands being run as a specific user. -Note that per-command entries may not include command line arguments. -If you need to specify arguments, define a C and reference -that instead. - - Default_Type ::= 'Defaults' | - 'Defaults' '@' Host_List | - 'Defaults' ':' User_List | - 'Defaults' '!' Cmnd_List | - 'Defaults' '>' Runas_List - - Default_Entry ::= Default_Type Parameter_List - - Parameter_List ::= Parameter | - Parameter ',' Parameter_List - - Parameter ::= Parameter '=' Value | - Parameter '+=' Value | - Parameter '-=' Value | - '!'* Parameter - -Parameters may be B, B values, B, or B. -Flags are implicitly boolean and can be turned off via the '!' -operator. Some integer, string and list parameters may also be -used in a boolean context to disable them. Values may be enclosed -in double quotes (C<">) when they contain multiple words. Special -characters may be escaped with a backslash (C<\>). - -Lists have two additional assignment operators, C<+=> and C<-=>. -These operators are used to add to and delete from a list respectively. -It is not an error to use the C<-=> operator to remove an element -that does not exist in a list. - -Defaults entries are parsed in the following order: generic, host -and user Defaults first, then runas Defaults and finally command -defaults. - -See L<"SUDOERS OPTIONS"> for a list of supported Defaults parameters. - -=head2 User Specification - - User_Spec ::= User_List Host_List '=' Cmnd_Spec_List \ - (':' Host_List '=' Cmnd_Spec_List)* - - Cmnd_Spec_List ::= Cmnd_Spec | - Cmnd_Spec ',' Cmnd_Spec_List - - Cmnd_Spec ::= Runas_Spec? SELinux_Spec? Tag_Spec* Cmnd - - Runas_Spec ::= '(' Runas_List? (':' Runas_List)? ')' - - SELinux_Spec ::= ('ROLE=role' | 'TYPE=type') - - Tag_Spec ::= ('NOPASSWD:' | 'PASSWD:' | 'NOEXEC:' | 'EXEC:' | - 'SETENV:' | 'NOSETENV:' | 'LOG_INPUT:' | 'NOLOG_INPUT:' | - 'LOG_OUTPUT:' | 'NOLOG_OUTPUT:') - -A B 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) -what'. Let's break that down into its constituent parts: - -=head2 Runas_Spec - -A C determines the user and/or the group that a command -may be run as. A fully-specified C consists of two -Cs (as defined above) separated by a colon (':') and -enclosed in a set of parentheses. The first C indicates -which users the command may be run as via B's B<-u> option. -The second defines a list of groups that can be specified via -B's B<-g> option. If both Cs are specified, the -command may be run with any combination of users and groups listed -in their respective Cs. If only the first is specified, -the command may be run as any user in the list but no B<-g> option -may be specified. If the first C is empty but the -second is specified, the command may be run as the invoking user -with the group set to any listed in the C. If no -C is specified the command may be run as B and -no group may be specified. - -A C sets the default for the commands that follow it. -What this means is that for the entry: - - dgb boulder = (operator) /bin/ls, /bin/kill, /usr/bin/lprm - -The user B may run F, F, and -F -- but only as B. E.g., - - $ 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: - - dgb boulder = (operator) /bin/ls, (root) /bin/kill, /usr/bin/lprm - -Then user B is now allowed to run F as B, -but F and F as B. - -We can extend this to allow B to run C with either -the user or group set to B: - - dgb boulder = (operator : operator) /bin/ls, (root) /bin/kill, \ - /usr/bin/lprm - -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. - - tcm boulder = (:dialer) /usr/bin/tip, /usr/bin/cu, \ - /usr/local/bin/minicom - -=head2 SELinux_Spec - -On systems with SELinux support, I entries may optionally have -an SELinux role and/or type associated with a command. If a role or -type is specified with the command it will override any default values -specified in I. A role or type specified on the command line, -however, will supercede the values in I. - -=head2 Tag_Spec - -A command may have zero or more tags associated with it. There are -eight possible tag values, C, C, C, -C, C, C, C, C, -C and C. Once a tag is set on a C, -subsequent Cs in the C, inherit the tag unless -it is overridden by the opposite tag (i.e.: C overrides -C and C overrides C). - -=head3 NOPASSWD and PASSWD - -By default, B requires that a user authenticate him or herself -before running a command. This behavior can be modified via the -C tag. Like a C, the C tag sets -a default for the commands that follow it in the C. -Conversely, the C tag can be used to reverse things. -For example: - - ray rushmore = NOPASSWD: /bin/kill, /bin/ls, /usr/bin/lprm - -would allow the user B to run F, F, and -F as B on the machine rushmore without -authenticating himself. If we only want B to be able to -run F without a password the entry would be: - - ray rushmore = NOPASSWD: /bin/kill, PASSWD: /bin/ls, /usr/bin/lprm - -Note, however, that the C tag has no effect on users who are -in the group specified by the I option. - -By default, if the C tag is applied to any of the entries -for a user on the current host, he or she will be able to run -C without a password. Additionally, a user may only run -C without a password if the C tag is present -for all a user's entries that pertain to the current host. -This behavior may be overridden via the verifypw and listpw options. - -=head3 NOEXEC and EXEC - -If B has been compiled with I support and the underlying -operating system supports it, the C tag can be used to prevent -a dynamically-linked executable from running further commands itself. - -In the following example, user B may run F -and F but shell escapes will be disabled. - - aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi - -See the L section below for more details -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. - -=head3 LOG_INPUT and NOLOG_INPUT - -These tags override the value of the I option on a -per-command basis. For more information, see the description of -I in the L<"SUDOERS OPTIONS"> section below. - -=head3 LOG_OUTPUT and NOLOG_OUTPUT - -These tags override the value of the I option on a -per-command basis. For more information, see the description of -I in the L<"SUDOERS OPTIONS"> section below. - -=head2 Wildcards - -B allows shell-style I (aka meta or glob characters) -to be used in host names, path names and command line arguments in -the I file. Wildcard matching is done via the B -L and L routines. Note that these are I -regular expressions. - -=over 8 - -=item C<*> - -Matches any set of zero or more characters. - -=item C - -Matches any single character. - -=item C<[...]> - -Matches any character in the specified range. - -=item C<[!...]> - -Matches any character B in the specified range. - -=item C<\x> - -For any character "x", evaluates to "x". This is used to -escape special characters such as: "*", "?", "[", and "}". - -=back - -POSIX character classes may also be used if your system's L -and L functions support them. However, because the -C<':'> character has special meaning in I, it must be -escaped. For example: - - /bin/ls [[\:alpha\:]]* - -Would match any file name beginning with a letter. - -Note that a forward slash ('/') will B be matched by -wildcards used in the path name. When matching the command -line arguments, however, a slash B get matched by -wildcards. This is to make a path like: - - /usr/bin/* - -match F but not F. - -=head2 Exceptions to wildcard rules - -The following exceptions apply to the above rules: - -=over 8 - -=item C<""> - -If the empty string C<""> is the only command line argument in the -I entry it means that command is not allowed to be run -with B arguments. - -=back - -=head2 Including other files from within sudoers - -It is possible to include other I files from within the -I file currently being parsed using the C<#include> and -C<#includedir> directives. - -This can be used, for example, to keep a site-wide I file -in addition to a local, per-machine file. For the sake of this -example the site-wide I will be F and the -per-machine one will be F. To include -F from within F we would use the -following line in F: - -=over 4 - -C<#include /etc/sudoers.local> - -=back - -When B reaches this line it will suspend processing of the -current file (F) and switch to F. -Upon reaching the end of F, the rest of -F will be processed. Files that are included may -themselves include other files. A hard limit of 128 nested include -files is enforced to prevent include file loops. - -The file name may include the C<%h> escape, signifying the short form -of the host name. I.e., if the machine's host name is "xerxes", then - -C<#include /etc/sudoers.%h> - -will cause B to include the file F. - -The C<#includedir> directive can be used to create a F -directory that the system package manager can drop I rules -into as part of package installation. For example, given: - -C<#includedir /etc/sudoers.d> - -B will read each file in F, skipping file -names that end in C<~> or contain a C<.> character to avoid causing -problems with package manager or editor temporary/backup files. -Files are parsed in sorted lexical order. That is, -F will be parsed before -F. Be aware that because the sorting is -lexical, not numeric, F would be loaded -B F. Using a consistent number -of leading zeroes in the file names can be used to avoid such -problems. - -Note that unlike files included via C<#include>, B will not -edit the files in a C<#includedir> directory unless one of them -contains a syntax error. It is still possible to run B -with the C<-f> flag to edit the files directly. - -=head2 Other special characters and reserved words - -The pound sign ('#') is used to indicate a comment (unless it is -part of a #include directive or unless it occurs in the context of -a user name and is followed by one or more digits, in which case -it is treated as a uid). Both the comment character and any text -after it, up to the end of the line, are ignored. - -The reserved word B is a built-in I that always causes -a match to succeed. It can be used wherever one might otherwise -use a C, C, C, or C. -You should not try to define your own I called B as the -built-in alias will be used in preference to your own. Please note -that using B can be dangerous since in a command context, it -allows the user to run B command on the system. - -An exclamation point ('!') can be used as a logical I operator -both in an I and in front of a C. This allows one to -exclude certain values. Note, however, that using a C in -conjunction with the built-in C alias to allow a user to -run "all but a few" commands rarely works as intended (see SECURITY -NOTES below). - -Long lines can be continued with a backslash ('\') as the last -character on the line. - -Whitespace between elements in a list as well as special syntactic -characters in a I ('=', ':', '(', ')') 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 - -B's behavior can be modified by C lines, as -explained earlier. A list of all supported Defaults parameters, -grouped by type, are listed below. - -B: - -=over 16 - -=item always_set_home - -If enabled, B will set the C environment variable to the -home directory of the target user (which is root unless the B<-u> -option is used). This effectively means that the B<-H> option is -always implied. Note that C is already set when the the -I option is enabled, so I is only -effective for configurations where I is disabled. -This flag is I by default. - -=item authenticate - -If set, users must authenticate themselves via a password (or other -means of authentication) before they may run commands. This default -may be overridden via the C and C tags. -This flag is I by default. - -=item closefrom_override - -If set, the user may use B's B<-C> option which -overrides the default starting point at which B begins -closing open file descriptors. This flag is I by default. - -=item compress_io - -If set, and B is configured to log a command's input or output, -the I/O logs will be compressed using B. This flag is I -by default when B is compiled with B support. - -=item env_editor - -If set, B will use the value of the EDITOR or VISUAL -environment variables before falling back on the default editor list. -Note that this may create a security hole as it allows the user to -run any arbitrary command as root without logging. A safer alternative -is to place a colon-separated list of editors in the C -variable. B will then only use the EDITOR or VISUAL if -they match a value specified in C. This flag is I<@env_editor@> by -default. - -=item env_reset - -If set, B will reset the environment to only contain the -LOGNAME, MAIL, SHELL, USER, USERNAME and the C variables. Any -variables in the caller's environment that match the C -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. - -=item fast_glob - -Normally, B uses the L function to do shell-style -globbing when matching path names. However, since it accesses the -file system, L can take a long time to complete for some -patterns, especially when the pattern references a network file -system that is mounted on demand (automounted). The I -option causes B to use the L function, which does -not access the file system to do its matching. The disadvantage -of I is that it is unable to match relative path names -such as F<./ls> or F<../bin/ls>. This has security implications -when path names that include globbing characters are used with the -negation operator, C<'!'>, as such rules can be trivially bypassed. -As such, this option should not be used when I contains rules -that contain negated path names which include globbing characters. -This flag is I by default. - -=item fqdn - -Set this flag if you want to put fully qualified host names in the -I file. I.e., instead of myhost you would use myhost.mydomain.edu. -You may still use the short form if you wish (and even mix the two). -Beware that turning on I requires B to make DNS lookups -which may make B unusable if DNS stops working (for example -if the machine is not plugged into the network). Also note that -you must use the host's official name as DNS knows it. That is, -you may not use a host alias (C entry) due to performance -issues and the fact that there is no way to get all aliases from -DNS. If your machine's host name (as returned by the C -command) is already fully qualified you shouldn't need to set -I. This flag is I<@fqdn@> by default. - -=item ignore_dot - -If set, B will ignore '.' or '' (current dir) in the C -environment variable; the C itself is not modified. This -flag is I<@ignore_dot@> by default. - -=item ignore_local_sudoers - -If set via LDAP, parsing of F<@sysconfdir@/sudoers> will be skipped. -This is intended for Enterprises that wish to prevent the usage of local -sudoers files so that only LDAP is used. This thwarts the efforts of -rogue operators who would attempt to add roles to F<@sysconfdir@/sudoers>. -When this option is present, F<@sysconfdir@/sudoers> does not even need to -exist. Since this option tells B how to behave when no specific LDAP -entries have been matched, this sudoOption is only meaningful for the -C section. This flag is I by default. - -=item insults - -If set, B will insult users when they enter an incorrect -password. This flag is I<@insults@> by default. - -=item log_host - -If set, the host name will be logged in the (non-syslog) B log file. -This flag is I by default. - -=item log_year - -If set, the four-digit year will be logged in the (non-syslog) B log file. -This flag is I by default. - -=item long_otp_prompt - -When validating with a One Time Password (OPT) scheme such as -B or B, a two-line prompt is used to make it easier -to cut and paste the challenge to a local window. It's not as -pretty as the default but some people find it more convenient. This -flag is I<@long_otp_prompt@> by default. - -=item mail_always - -Send mail to the I user every time a users runs B. -This flag is I by default. - -=item mail_badpass - -Send mail to the I user if the user running B does not -enter the correct password. This flag is I by default. - -=item mail_no_host - -If set, mail will be sent to the I user if the invoking -user exists in the I file, but is not allowed to run -commands on the current host. This flag is I<@mail_no_host@> by default. - -=item mail_no_perms - -If set, mail will be sent to the I user if the invoking -user is allowed to use B but the command they are trying is not -listed in their I file entry or is explicitly denied. -This flag is I<@mail_no_perms@> by default. - -=item mail_no_user - -If set, mail will be sent to the I user if the invoking -user is not in the I file. This flag is I<@mail_no_user@> -by default. - -=item noexec - -If set, all commands run via B will behave as if the C -tag has been set, unless overridden by a C tag. See the -description of I below as well as the L section at the end of this manual. This flag is I by default. - -=item path_info - -Normally, B will tell the user when a command could not be -found in their C environment variable. Some sites may wish -to disable this as it could be used to gather information on the -location of executables that the normal user does not have access -to. The disadvantage is that if the executable is simply not in -the user's C, B will tell the user that they are not -allowed to run it, which can be confusing. This flag is I<@path_info@> -by default. - -=item passprompt_override - -The password prompt specified by I will normally only -be used if the password prompt provided by systems such as PAM matches -the string "Password:". If I is set, I -will always be used. This flag is I by default. - -=item preserve_groups - -By default, B will initialize the group vector to the list of -groups the target user is in. When I is set, the -user's existing group vector is left unaltered. The real and -effective group IDs, however, are still set to match the target -user. This flag is I by default. - -=item pwfeedback - -By default, B reads the password like most other Unix programs, -by turning off echo until the user hits the return (or enter) key. -Some users become confused by this as it appears to them that B -has hung at this point. When I is set, B will -provide visual feedback when the user presses a key. Note that -this does have a security impact as an onlooker may be able to -determine the length of the password being entered. -This flag is I by default. - -=item requiretty - -If set, B will only run when the user is logged in to a real -tty. When this flag is set, B can only be run from a login -session and not via other means such as L or cgi-bin scripts. -This flag is I by default. - -=item root_sudo - -If set, root is allowed to run B too. Disabling this prevents users -from "chaining" B commands to get a root shell by doing something -like C<"sudo sudo /bin/sh">. Note, however, that turning off I -will also prevent root from running B. -Disabling I provides no real additional security; it -exists purely for historical reasons. -This flag is I<@root_sudo@> by default. - -=item rootpw - -If set, B will prompt for the root password instead of the password -of the invoking user. This flag is I by default. - -=item runaspw - -If set, B will prompt for the password of the user defined by the -I option (defaults to C<@runas_default@>) instead of the -password of the invoking user. This flag is I by default. - -=item set_home - -If enabled and B is invoked with the B<-s> option the C -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. -This flag is I by default. - -=item set_logname - -Normally, B will set the C, C and C -environment variables to the name of the target user (usually root -unless the B<-u> option is given). However, since some programs -(including the RCS revision control system) use C to -determine the real identity of the user, it may be desirable to -change this behavior. This can be done by negating the set_logname -option. Note that if the I option has not been disabled, -entries in the I list will override the value of -I. This flag is I by default. - -=item setenv - -Allow the user to disable the I option from the command -line. Additionally, environment variables set via 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. This flag is I -by default. - -=item shell_noargs - -If set and B is invoked with no arguments it acts as if the -B<-s> option had been given. That is, it runs a shell as root (the -shell is determined by the C environment variable if it is -set, falling back on the shell listed in the invoking user's -/etc/passwd entry if not). This flag is I by default. - -=item stay_setuid - -Normally, when B executes a command the real and effective -UIDs are set to the target user (root by default). This option -changes that behavior such that the real UID is left as the invoking -user's UID. In other words, this makes B act as a setuid -wrapper. This can be useful on systems that disable some potentially -dangerous functionality when a program is run setuid. This option -is only effective on systems with either the setreuid() or setresuid() -function. This flag is I by default. - -=item targetpw - -If set, B will prompt for the password of the user specified -by the B<-u> option (defaults to C) instead of the password -of the invoking user. In addition, the timestamp file name will -include the target user's name. Note that this flag precludes the -use of a uid not listed in the passwd database as an argument to -the B<-u> option. This flag is I 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 -enabled, B will use a file named for the tty the user is -logged in on in the user's time stamp directory. If disabled, the -time stamp of the directory is used instead. This flag is -I<@tty_tickets@> by default. - -=item umask_override - -If set, B will set the umask as specified by I without -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. - -=item use_loginclass - -If set, B will apply the defaults specified for the target user's -login class if one exists. Only available if B is configured with -the --with-logincap option. This flag is I by default. - -=item use_pty - -If set, B will run the command in a pseudo-pty even if no I/O -logging is being gone. A malicious program run under B could -conceivably fork a background process that retains to the user's -terminal device after the main program has finished executing. Use -of this option will make that impossible. - -=item visiblepw - -By default, B will refuse to run if the user must enter a -password but it is not possible to disable echo on the terminal. -If the I flag is set, B will prompt for a password -even when it would be visible on the screen. This makes it possible -to run things like C<"rsh somehost sudo ls"> since L does -not allocate a tty. This flag is I by default. - -=back - -B: - -=over 16 - -=item closefrom - -Before it executes a command, B will close all open file -descriptors other than standard input, standard output and standard -error (ie: file descriptors 0-2). The I option can be used -to specify a different file descriptor at which to start closing. -The default is C<3>. - -=item passwd_tries - -The number of tries a user gets to enter his/her password before -B logs the failure and exits. The default is C<@passwd_tries@>. - -=back - -B: - -=over 16 - -=item loglinelen - -Number of characters per line for the file log. This value is used -to decide when to wrap lines for nicer log files. This has no -effect on the syslog log file, only the file log. The default is -C<@loglen@> (use 0 or negate the option to disable word wrap). - -=item passwd_timeout - -Number of minutes before the B password prompt times out, or -C<0> for no timeout. The timeout may include a fractional component -if minute granularity is insufficient, for example C<2.5>. The -default is C<@password_timeout@>. - -=item timestamp_timeout - -Number of minutes that can elapse before B will ask for a -passwd again. The timeout may include a fractional component if -minute granularity is insufficient, for example C<2.5>. The default -is C<@timeout@>. Set this to C<0> to always prompt for a password. -If set to a value less than C<0> the user's timestamp will never -expire. This can be used to allow users to create or delete their -own timestamps via C and C respectively. - -=item umask - -Umask to use when running the command. Negate this option or set -it to 0777 to preserve the user's umask. The actual umask that is -used will be the union of the user's umask and C<@sudo_umask@>. -This guarantees that B never lowers the umask when running a -command. Note on systems that use PAM, the default PAM configuration -may specify its own umask which will override the value set in -I. - -=back - -B: - -=over 16 - -=item badpass_message - -Message that is displayed if a user enters an incorrect password. -The default is C<@badpass_message@> unless insults are enabled. - -=item editor - -A colon (':') separated list of editors allowed to be used with -B. 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 mailsub - -Subject of the mail sent to the I user. The escape C<%h> -will expand to the host name of the machine. -Default is C<@mailsub@>. - -=item noexec_file - -Path to a shared library containing dummy versions of the execv(), -execve() and fexecve() library functions that just return an error. -This is used to implement the I functionality on systems that -support C or its equivalent. Defaults to F<@noexec_file@>. - -=item passprompt - -The default prompt to use when asking for a password; can be overridden -via the B<-p> option or the C environment variable. -The following percent (`C<%>') escapes are supported: - -=over 4 - -=item C<%H> - -expanded to the local host name including the domain name -(on if the machine's host name is fully qualified or the I -option is set) - -=item C<%h> - -expanded to the local host name without the domain name - -=item C<%p> - -expanded to the user whose password is being asked for (respects the -I, I and I flags in I) - -=item C<%U> - -expanded to the login name of the user the command will -be run as (defaults to root) - -=item C<%u> - -expanded to the invoking user's login name - -=item C<%%> - -two consecutive C<%> characters are collapsed into a single C<%> character - -=back - -The default value is C<@passprompt@>. - -=item role - -The default SELinux role to use when constructing a new security -context to run the command. The default role may be overridden on -a per-command basis in I or via command line options. -This option is only available whe B is built with SELinux support. - -=item runas_default - -The default user to run commands as if the B<-u> option is not specified -on the command line. This defaults to C<@runas_default@>. -Note that if I is set it B occur before -any C specifications. - -=item syslog_badpri - -Syslog priority to use when user authenticates unsuccessfully. -Defaults to C<@badpri@>. - -=item syslog_goodpri - -Syslog priority to use when user authenticates successfully. -Defaults to C<@goodpri@>. - -=item sudoers_locale - -Locale to use when parsing the sudoers file. Note that changing -the locale may affect how sudoers is interpreted. -Defaults to C<"C">. - -=item timestampdir - -The directory in which B stores its timestamp files. -The default is F<@timedir@>. - -=item timestampowner - -The owner of the timestamp directory and the timestamps stored therein. -The default is C. - -=item type - -The default SELinux type to use when constructing a new security -context to run the command. The default type may be overridden on -a per-command basis in I or via command line options. -This option is only available whe B is built with SELinux support. - -=back - -B: - -=over 12 - -=item askpass - -The I option specifies the fully qualified path to a helper -program used to read the user's password when no terminal is -available. This may be the case when B is executed from a -graphical (as opposed to text-based) application. The program -specified by I should display the argument passed to it -as the prompt and write the user's password to the standard output. -The value of I may be overridden by the C -environment variable. - -=item env_file - -The I options specifies the fully qualified path to a -file containing variables to be set in the environment of the program -being run. Entries in this file should either be of the form -C or C. The value may -optionally be surrounded by single or double quotes. Variables in -this file are subject to other B environment settings such -as I and I. - -=item exempt_group - -Users in this group are exempt from password and PATH requirements. -This is not set by default. - -=item lecture - -This option controls when a short lecture will be printed along with -the password prompt. It has the following possible values: - -=over 8 - -=item always - -Always lecture the user. - -=item never - -Never lecture the user. - -=item once - -Only lecture the user the first time they run B. - -=back - -If no value is specified, a value of I is implied. -Negating the option results in a value of I being used. -The default value is I<@lecture@>. - -=item lecture_file - -Path to a file containing an alternate B lecture that will -be used in place of the standard lecture if the named file exists. -By default, B uses a built-in lecture. - -=item listpw - -This option controls when a password will be required when a -user runs B with the B<-l> option. It has the following possible values: - -=over 8 - -=item all - -All the user's I entries for the current host must have -the C flag set to avoid entering a password. - -=item always - -The user must always enter a password to use the B<-l> option. - -=item any - -At least one of the user's I entries for the current host -must have the C flag set to avoid entering a password. - -=item never - -The user need never enter a password to use the B<-l> option. - -=back - -If no value is specified, a value of I is implied. -Negating the option results in a value of I being used. -The default value is I. - -=item logfile - -Path to the B log file (not the syslog log file). Setting a path -turns on logging to a file; negating this option turns it off. -By default, B logs via syslog. - -=item mailerflags - -Flags to use when invoking mailer. Defaults to B<-t>. - -=item mailerpath - -Path to mail program used to send warning mail. -Defaults to the path to sendmail found at configure time. - -=item mailfrom - -Address to use for the "from" address when sending warning and error -mail. The address should be enclosed in double quotes (C<">) to -protect against B interpreting the C<@> sign. Defaults to -the name of the user running B. - -=item mailto - -Address to send warning and error mail to. The address should -be enclosed in double quotes (C<">) to protect against B -interpreting the C<@> sign. Defaults to C<@mailto@>. - -=item secure_path - -Path used for every command run from B. If you don't trust the -people running B to have a sane C environment variable you may -want to use this. Another use is if you want to have the "root path" -be separate from the "user path." Users in the group specified by the -I option are not affected by I. -This option is @secure_path@ by default. - -=item syslog - -Syslog facility if syslog is being used for logging (negate to -disable syslog logging). Defaults to C<@logfac@>. - -=item verifypw - -This option controls when a password will be required when a user runs -B with the B<-v> option. It has the following possible values: - -=over 8 - -=item all - -All the user's I entries for the current host must have -the C flag set to avoid entering a password. - -=item always - -The user must always enter a password to use the B<-v> option. - -=item any - -At least one of the user's I entries for the current host -must have the C flag set to avoid entering a password. - -=item never - -The user need never enter a password to use the B<-v> option. - -=back - -If no value is specified, a value of I is implied. -Negating the option results in a value of I being used. -The default value is I. - -=back - -B: - -=over 16 - -=item env_check - -Environment variables to be removed from the user's environment if -the variable's value contains C<%> or C characters. This can -be used to guard against printf-style format vulnerabilities in -poorly-written programs. The argument may be a double-quoted, -space-separated list or a single value without double-quotes. The -list can be replaced, added to, deleted from, or disabled by using -the C<=>, C<+=>, C<-=>, and C operators respectively. Regardless -of whether the C option is enabled or disabled, variables -specified by C will be preserved in the environment if -they pass the aforementioned check. The default list of environment -variables to check is displayed when B is run by root with -the I<-V> option. - -=item env_delete - -Environment variables to be removed from the user's environment -when the I option is not in effect. The argument may -be a double-quoted, space-separated list or a single value without -double-quotes. The list can be replaced, added to, deleted from, -or disabled by using the C<=>, C<+=>, C<-=>, and C operators -respectively. The default list of environment variables to remove -is displayed when B is run by root with the I<-V> option. -Note that many operating systems will remove potentially dangerous -variables from the environment of any setuid process (such as -B). - -=item env_keep - -Environment variables to be preserved in the user's environment -when the I option is in effect. This allows fine-grained -control over the environment B-spawned processes will receive. -The argument may be a double-quoted, space-separated list or a -single value without double-quotes. The list can be replaced, added -to, deleted from, or disabled by using the C<=>, C<+=>, C<-=>, and -C operators respectively. The default list of variables to keep -is displayed when B is run by root with the I<-V> option. - -=back - -When logging via L, B accepts the following values -for the syslog facility (the value of the B Parameter): -B (if your OS supports it), B, B, B, -B, B, B, B, B, B, -B, and B. The following syslog priorities are -supported: B, B, B, B, B, B, -B, and B. - -=head1 FILES - -=over 24 - -=item F<@sysconfdir@/sudoers> - -List of who can run what - -=item F - -Local groups file - -=item F - -List of network groups - -=item F - -I/O log files - -=back - -=head1 EXAMPLES - -Below are example I entries. Admittedly, some of -these are a bit contrived. First, we allow a few environment -variables to pass and then define our I: - - # Run X applications through sudo; HOME is used to find the - # .Xauthority file. Note that other programs use HOME to find - # configuration files and this may lead to privilege escalation! - Defaults env_keep += "DISPLAY HOME" - - # User alias specification - User_Alias FULLTIMERS = millert, mikef, dowdy - User_Alias PARTTIMERS = bostley, jwfox, crawl - User_Alias WEBMASTERS = will, wendy, wim - - # Runas alias specification - Runas_Alias OP = root, operator - Runas_Alias DB = oracle, sybase - Runas_Alias ADMINGRP = adm, oper - - # Host alias specification - Host_Alias SPARC = bigtime, eclipse, moet, anchor :\ - SGI = grolsch, dandelion, black :\ - ALPHA = widget, thalamus, foobar :\ - HPPA = boa, nag, python - Host_Alias CUNETS = 128.138.0.0/255.255.0.0 - Host_Alias CSNETS = 128.138.243.0, 128.138.204.0/24, 128.138.242.0 - Host_Alias SERVERS = master, mail, www, ns - Host_Alias CDROM = orion, perseus, hercules - - # Cmnd alias specification - Cmnd_Alias DUMPS = /usr/bin/mt, /usr/sbin/dump, /usr/sbin/rdump,\ - /usr/sbin/restore, /usr/sbin/rrestore - Cmnd_Alias KILL = /usr/bin/kill - Cmnd_Alias PRINTING = /usr/sbin/lpc, /usr/bin/lprm - Cmnd_Alias SHUTDOWN = /usr/sbin/shutdown - Cmnd_Alias HALT = /usr/sbin/halt - Cmnd_Alias REBOOT = /usr/sbin/reboot - Cmnd_Alias SHELLS = /usr/bin/sh, /usr/bin/csh, /usr/bin/ksh, \ - /usr/local/bin/tcsh, /usr/bin/rsh, \ - /usr/local/bin/zsh - Cmnd_Alias SU = /usr/bin/su - Cmnd_Alias PAGERS = /usr/bin/more, /usr/bin/pg, /usr/bin/less - -Here we override some of the compiled in default values. We want -B to log via L using the I facility in all -cases. We don't want to subject the full time staff to the B -lecture, user B need not give a password, and we don't -want to reset the C, C or C environment -variables when running commands as root. Additionally, on the -machines in the I C, we keep an additional -local log file and make sure we log the year in each log line since -the log entries will be kept around for several years. Lastly, we -disable shell escapes for the commands in the PAGERS C -(F, F and F). - - # Override built-in defaults - Defaults syslog=auth - Defaults>root !set_logname - Defaults:FULLTIMERS !lecture - Defaults:millert !authenticate - Defaults@SERVERS log_year, logfile=/var/log/sudo.log - Defaults!PAGERS noexec - -The I is the part that actually determines who may -run what. - - root ALL = (ALL) ALL - %wheel ALL = (ALL) ALL - -We let B and any user in group B run any command on any -host as any user. - - FULLTIMERS ALL = NOPASSWD: ALL - -Full time sysadmins (B, B, and B) may run any -command on any host without authenticating themselves. - - PARTTIMERS ALL = ALL - -Part time sysadmins (B, B, and B) may run any -command on any host but they must authenticate themselves first -(since the entry lacks the C tag). - - jack CSNETS = ALL - -The user B may run any command on the machines in the I alias -(the networks C<128.138.243.0>, C<128.138.204.0>, and C<128.138.242.0>). -Of those networks, only C<128.138.204.0> has an explicit netmask (in -CIDR notation) indicating it is a class C network. For the other -networks in I, the local machine's netmask will be used -during matching. - - lisa CUNETS = ALL - -The user B may run any command on any host in the I alias -(the class B network C<128.138.0.0>). - - operator ALL = DUMPS, KILL, SHUTDOWN, HALT, REBOOT, PRINTING,\ - sudoedit /etc/printcap, /usr/oper/bin/ - -The B user may run commands limited to simple maintenance. -Here, those are commands related to backups, killing processes, the -printing system, shutting down the system, and any commands in the -directory F. - - joe ALL = /usr/bin/su operator - -The user B may only L to operator. - - pete HPPA = /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root - - %opers ALL = (: ADMINGRP) /usr/sbin/ - -Users in the B group may run commands in F as themselves -with any group in the I C (the B and B -groups). - -The user B is allowed to change anyone's password except for -root on the I machines. Note that this assumes L -does not take multiple user names on the command line. - - bob SPARC = (OP) ALL : SGI = (OP) ALL - -The user B may run anything on the I and I machines -as any user listed in the I C (B and B). - - jim +biglab = ALL - -The user B may run any command on machines in the I netgroup. -B knows that "biglab" is a netgroup due to the '+' prefix. - - +secretaries ALL = PRINTING, /usr/bin/adduser, /usr/bin/rmuser - -Users in the B netgroup need to help manage the printers -as well as add and remove users, so they are allowed to run those -commands on all machines. - - fred ALL = (DB) NOPASSWD: ALL - -The user B can run commands as any user in the I C -(B or B) without giving a password. - - john ALPHA = /usr/bin/su [!-]*, !/usr/bin/su *root* - -On the I machines, user B may su to anyone except root -but he is not allowed to specify any options to the L command. - - jen ALL, !SERVERS = ALL - -The user B may run any command on any machine except for those -in the I C (master, mail, www and ns). - - jill SERVERS = /usr/bin/, !SU, !SHELLS - -For any machine in the I C, B may run -any commands in the directory F except for those commands -belonging to the I and I C. - - steve CSNETS = (operator) /usr/local/op_commands/ - -The user B may run any command in the directory /usr/local/op_commands/ -but only as user operator. - - matt valkyrie = KILL - -On his personal workstation, valkyrie, B needs to be able to -kill hung processes. - - WEBMASTERS www = (www) ALL, (root) /usr/bin/su www - -On the host www, any user in the I C (will, -wendy, and wim), may run any command as user www (which owns the -web pages) or simply L to www. - - ALL CDROM = NOPASSWD: /sbin/umount /CDROM,\ - /sbin/mount -o nosuid\,nodev /dev/cd0a /CDROM - -Any user may mount or unmount a CD-ROM on the machines in the CDROM -C (orion, perseus, hercules) without entering a password. -This is a bit tedious for users to type, so it is a prime candidate -for encapsulating in a shell script. - -=head1 SECURITY NOTES - -It is generally not effective to "subtract" commands from C -using the '!' operator. A user can trivially circumvent this -by copying the desired command to a different name and then -executing that. For example: - - bill ALL = ALL, !SU, !SHELLS - -Doesn't really prevent B from running the commands listed in -I or I since he can simply copy those commands to a -different name, or use a shell escape from an editor or other -program. Therefore, these kind of restrictions should be considered -advisory at best (and reinforced by policy). - -Furthermore, if the I option is in use, it is not possible -to reliably negate commands where the path name includes globbing -(aka wildcard) characters. This is because the C library's -L function cannot resolve relative paths. While this -is typically only an inconvenience for rules that grant privileges, -it can result in a security issue for rules that subtract or revoke -privileges. - -For example, given the following I entry: - - john ALL = /usr/bin/passwd [a-zA-Z0-9]*, /usr/bin/chsh [a-zA-Z0-9]*, - /usr/bin/chfn [a-zA-Z0-9]*, !/usr/bin/* root - -User B can still run C if I is -enabled by changing to F and running C<./passwd root> instead. - -=head1 PREVENTING SHELL ESCAPES - -Once B executes a program, that program is free to do whatever -it pleases, including run other programs. This can be a security -issue since it is not uncommon for a program to allow shell escapes, -which lets a user bypass B's access control and logging. -Common programs that permit shell escapes include shells (obviously), -editors, paginators, mail and terminal programs. - -There are two basic approaches to this problem: - -=over 10 - -=item restrict - -Avoid giving users access to commands that allow the user to run -arbitrary commands. Many editors have a restricted mode where shell -escapes are disabled, though B is a better solution to -running editors via B. Due to the large number of programs that -offer shell escapes, restricting users to the set of programs that -do not if often unworkable. - -=item noexec - -Many systems that support shared libraries have the ability to -override default library functions by pointing an environment -variable (usually C) to an alternate shared library. -On such systems, B's I functionality can be used to -prevent a program run by B from executing any other programs. -Note, however, that this applies only to native dynamically-linked -executables. Statically-linked executables and foreign executables -running under binary emulation are not affected. - -To tell whether or not B supports I, you can run -the following as root: - - sudo -V | grep "dummy exec" - -If the resulting output contains a line that begins with: - - File containing dummy exec functions: - -then B may be able to replace the exec family of functions -in the standard library with its own that simply return an error. -Unfortunately, there is no foolproof way to know whether or not -I will work at compile-time. I should work on -SunOS, Solaris, *BSD, Linux, IRIX, Tru64 UNIX, MacOS X, and HP-UX -11.x. It is known B to work on AIX and UnixWare. I -is expected to work on most operating systems that support the -C environment variable. Check your operating system's -manual pages for the dynamic linker (usually ld.so, ld.so.1, dyld, -dld.sl, rld, or loader) to see if C is supported. - -To enable I for a command, use the C tag as documented -in the User Specification section above. Here is that example again: - - aaron shanty = NOEXEC: /usr/bin/more, /usr/bin/vi - -This allows user B to run F and F -with I enabled. This will prevent those two commands from -executing other commands (such as a shell). If you are unsure -whether or not your system is capable of supporting I you -can always just try it out and see if it works. - -=back - -Note that restricting shell escapes is not a panacea. Programs -running as root are still capable of many potentially hazardous -operations (such as changing or overwriting files) that could lead -to unintended privilege escalation. In the specific case of an -editor, a safer approach is to give the user permission to run -B. - -=head1 SEE ALSO - -L, L, L, L, L, L - -=head1 CAVEATS - -The I file should B be edited by the B -command which locks the file and does grammatical checking. It is -imperative that I be free of syntax errors since B -will not run with a syntactically incorrect I file. - -When using netgroups of machines (as opposed to users), if you -store fully qualified host name in the netgroup (as is usually the -case), you either need to have the machine's host name be fully qualified -as returned by the C command or use the I option in -I. - -=head1 BUGS - -If you feel you have found a bug in B, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ - -=head1 SUPPORT - -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or -search the archives. - -=head1 DISCLAIMER - -B is provided ``AS IS'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the LICENSE -file distributed with B or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudoers2ldif b/sudoers2ldif deleted file mode 100644 index 0fe0ad1..0000000 --- a/sudoers2ldif +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env perl -use strict; - -# -# Converts a sudoers file to LDIF format in prepration for loading into -# the LDAP server. -# - -# BUGS: -# Does not yet handle multiple lines with : in them -# Does not yet remove quotation marks from options -# Does not yet escape + at the beginning of a dn -# Does not yet handle line wraps correctly -# Does not yet handle multiple roles with same name (needs tiebreaker) -# -# CAVEATS: -# Sudoers entries can have multiple RunAs entries that override former ones, -# with LDAP sudoRunAs{Group,User} applies to all commands in a sudoRole - -my %RA; -my %UA; -my %HA; -my %CA; -my $base=$ENV{SUDOERS_BASE} or die "$0: Container SUDOERS_BASE undefined\n"; -my @options=(); - -my $did_defaults=0; - -# parse sudoers one line at a time -while (<>){ - - # remove comment - s/#.*//; - - # line continuation - $_.=<> while s/\\\s*$//s; - - # cleanup newline - chomp; - - # ignore blank lines - next if /^\s*$/; - - if (/^Defaults\s+/i) { - my $opt=$'; - $opt=~s/\s+$//; # remove trailing whitespace - push @options,$opt; - } elsif (/^(\S+)\s+(.+)=\s*(.*)/) { - - # Aliases or Definitions - my ($p1,$p2,$p3)=($1,$2,$3); - $p2=~s/\s+$//; # remove trailing whitespace - $p3=~s/\s+$//; # remove trailing whitespace - - if ($p1 eq "User_Alias") { - $UA{$p2}=$p3; - } elsif ($p1 eq "Runas_Alias") { - $RA{$p2}=$p3; - } elsif ($p1 eq "Host_Alias") { - $HA{$p2}=$p3; - } elsif ($p1 eq "Cmnd_Alias") { - $CA{$p2}=$p3; - } else { - if (!$did_defaults++){ - # do this once - print "dn: cn=defaults,$base\n"; - print "objectClass: top\n"; - print "objectClass: sudoRole\n"; - print "cn: defaults\n"; - print "description: Default sudoOption's go here\n"; - print "sudoOption: $_\n" foreach @options; - print "\n"; - } - # Definition - my @users=split /\s*,\s*/,$p1; - my @hosts=split /\s*,\s*/,$p2; - my @cmds= split /\s*,\s*/,$p3; - @options=(); - print "dn: cn=$users[0],$base\n"; - print "objectClass: top\n"; - print "objectClass: sudoRole\n"; - print "cn: $users[0]\n"; - # will clobber options - print "sudoUser: $_\n" foreach expand(\%UA,@users); - print "sudoHost: $_\n" foreach expand(\%HA,@hosts); - foreach (@cmds) { - if (s/^\(([^\)]+)\)\s*//) { - my @runas = split(/:\s*/, $1); - if (defined($runas[0])) { - print "sudoRunAsUser: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[0])); - } - if (defined($runas[1])) { - print "sudoRunAsGroup: $_\n" foreach expand(\%RA, split(/,\s*/, $runas[1])); - } - } - } - print "sudoCommand: $_\n" foreach expand(\%CA,@cmds); - print "sudoOption: $_\n" foreach @options; - print "\n"; - } - - } else { - print "parse error: $_\n"; - } - -} - -# -# recursively expand hash elements -sub expand{ - my $ref=shift; - my @a=(); - - # preen the line a little - foreach (@_){ - # if NOPASSWD: directive found, mark entire entry as not requiring - s/NOPASSWD:\s*// && push @options,"!authenticate"; - s/PASSWD:\s*// && push @options,"authenticate"; - s/NOEXEC:\s*// && push @options,"noexec"; - s/EXEC:\s*// && push @options,"!noexec"; - s/SETENV:\s*// && push @options,"setenv"; - s/NOSETENV:\s*// && push @options,"!setenv"; - s/\w+://; # silently remove other directives - s/\s+$//; # right trim - } - - # do the expanding - push @a,$ref->{$_} ? expand($ref,split /\s*,\s*/,$ref->{$_}):$_ foreach @_; - @a; -} - - diff --git a/sudoreplay.c b/sudoreplay.c deleted file mode 100644 index 58b8639..0000000 --- a/sudoreplay.c +++ /dev/null @@ -1,958 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_SELECT_H -#include -#endif /* HAVE_SYS_SELECT_H */ -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#if TIME_WITH_SYS_TIME -# include -#endif -#ifndef HAVE_TIMESPEC -# include -#endif -#include -#include -#include -#include -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif -#ifdef HAVE_REGCOMP -# include -#endif -#ifdef HAVE_ZLIB_H -# include -#endif -#ifdef HAVE_SETLOCALE -# include -#endif -#include - -#include - -#include "compat.h" -#include "alloc.h" -#include "error.h" -#include "missing.h" - -#ifndef LINE_MAX -# define LINE_MAX 2048 -#endif - -/* Must match the defines in iolog.c */ -#define IOFD_STDIN 0 -#define IOFD_STDOUT 1 -#define IOFD_STDERR 2 -#define IOFD_TTYIN 3 -#define IOFD_TTYOUT 4 -#define IOFD_TIMING 5 -#define IOFD_MAX 6 - -/* Bitmap of iofds to be replayed */ -unsigned int replay_filter = (1 << IOFD_STDOUT) | (1 << IOFD_STDERR) | - (1 << IOFD_TTYOUT); - -/* For getopt(3) */ -extern char *optarg; -extern int optind; - -int Argc; -char **Argv; - -union io_fd { - FILE *f; -#ifdef HAVE_ZLIB_H - gzFile g; -#endif - void *v; -}; - -/* - * Info present in the I/O log file - */ -struct log_info { - char *cwd; - char *user; - char *runas_user; - char *runas_group; - char *tty; - char *cmd; - time_t tstamp; -}; - -/* - * Handle expressions like: - * ( user millert or user root ) and tty console and command /bin/sh - */ -struct search_node { - struct search_node *next; -#define ST_EXPR 1 -#define ST_TTY 2 -#define ST_USER 3 -#define ST_PATTERN 4 -#define ST_RUNASUSER 5 -#define ST_RUNASGROUP 6 -#define ST_FROMDATE 7 -#define ST_TODATE 8 -#define ST_CWD 9 - char type; - char negated; - char or; - char pad; - union { -#ifdef HAVE_REGCOMP - regex_t cmdre; -#endif - time_t tstamp; - char *cwd; - char *tty; - char *user; - char *pattern; - char *runas_group; - char *runas_user; - struct search_node *expr; - void *ptr; - } u; -} *search_expr; - -#define STACK_NODE_SIZE 32 -static struct search_node *node_stack[32]; -static int stack_top; - -static const char *session_dir = _PATH_SUDO_IO_LOGDIR; - -static union io_fd io_fds[IOFD_MAX]; -static const char *io_fnames[IOFD_MAX] = { - "/stdin", - "/stdout", - "/stderr", - "/ttyin", - "/ttyout", - "/timing" -}; - -extern time_t get_date __P((char *)); -extern char *get_timestr __P((time_t, int)); -extern int term_raw __P((int, int)); -extern int term_restore __P((int, int)); -extern void zero_bytes __P((volatile void *, size_t)); -void 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 *open_io_fd __P((char *pathbuf, int len, const char *suffix)); -static int parse_timing __P((const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes)); - -#ifdef HAVE_REGCOMP -# define REGEX_T regex_t -#else -# define REGEX_T char -#endif - -#define VALID_ID(s) (isalnum((unsigned char)(s)[0]) && \ - isalnum((unsigned char)(s)[1]) && isalnum((unsigned char)(s)[2]) && \ - isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \ - isalnum((unsigned char)(s)[5]) && (s)[6] == '\0') - -int -main(argc, argv) - int argc; - char *argv[]; -{ - int ch, idx, plen, nready, interactive = 0, listonly = 0; - const char *id, *user = NULL, *pattern = NULL, *tty = NULL, *decimal = "."; - char path[PATH_MAX], buf[LINE_MAX], *cp, *ep; - double seconds, to_wait, speed = 1.0, max_wait = 0; - FILE *lfile; - fd_set *fdsw; - sigaction_t sa; - size_t len, nbytes, nread, off; - ssize_t nwritten; - - Argc = argc; - Argv = argv; - -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); - decimal = localeconv()->decimal_point; -#endif - - while ((ch = getopt(argc, argv, "d:f:lm:s:V")) != -1) { - switch(ch) { - case 'd': - session_dir = optarg; - break; - case 'f': - /* Set the replay filter. */ - replay_filter = 0; - for (cp = strtok(optarg, ","); cp; cp = strtok(NULL, ",")) { - if (strcmp(cp, "stdout") == 0) - SET(replay_filter, 1 << IOFD_STDOUT); - else if (strcmp(cp, "stderr") == 0) - SET(replay_filter, 1 << IOFD_STDERR); - else if (strcmp(cp, "ttyout") == 0) - SET(replay_filter, 1 << IOFD_TTYOUT); - else - errorx(1, "invalid filter option: %s", optarg); - } - break; - case 'l': - listonly = 1; - break; - case 'm': - errno = 0; - max_wait = strtod(optarg, &ep); - if (*ep != '\0' || errno != 0) - errorx(1, "invalid max wait: %s", optarg); - break; - case 's': - errno = 0; - speed = strtod(optarg, &ep); - if (*ep != '\0' || errno != 0) - errorx(1, "invalid speed factor: %s", optarg); - break; - case 'V': - (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION); - exit(0); - default: - usage(); - /* NOTREACHED */ - } - - } - argc -= optind; - argv += optind; - - if (listonly) - exit(list_sessions(argc, argv, pattern, user, tty)); - - if (argc != 1) - usage(); - - /* 6 digit ID in base 36, e.g. 01G712AB */ - id = argv[0]; - if (!VALID_ID(id)) - errorx(1, "invalid ID %s", id); - - plen = snprintf(path, sizeof(path), "%s/%.2s/%.2s/%.2s/timing", - session_dir, id, &id[2], &id[4]); - if (plen <= 0 || plen >= sizeof(path)) - errorx(1, "%s/%.2s/%.2s/%.2s/%.2s/timing: %s", session_dir, - id, &id[2], &id[4], strerror(ENAMETOOLONG)); - plen -= 7; - - /* Open files for replay, applying replay filter for the -f flag. */ - for (idx = 0; idx < IOFD_MAX; idx++) { - if (ISSET(replay_filter, 1 << idx) || idx == IOFD_TIMING) { - io_fds[idx].v = open_io_fd(path, plen, io_fnames[idx]); - if (io_fds[idx].v == NULL) - error(1, "unable to open %s", path); - } - } - - /* Read log file. */ - path[plen] = '\0'; - strlcat(path, "/log", sizeof(path)); - lfile = fopen(path, "r"); - if (lfile == NULL) - error(1, "unable to open %s", path); - cp = NULL; - len = 0; - getline(&cp, &len, lfile); /* log */ - getline(&cp, &len, lfile); /* cwd */ - getline(&cp, &len, lfile); /* command */ - printf("Replaying sudo session: %s", cp); - free(cp); - fclose(lfile); - - fflush(stdout); - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESETHAND; - sa.sa_handler = cleanup; - (void) sigaction(SIGINT, &sa, NULL); - (void) sigaction(SIGKILL, &sa, NULL); - (void) sigaction(SIGTERM, &sa, NULL); - (void) sigaction(SIGHUP, &sa, NULL); - sa.sa_flags = SA_RESTART; - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGTSTP, &sa, NULL); - (void) sigaction(SIGQUIT, &sa, NULL); - - /* XXX - read user input from /dev/tty and set STDOUT to raw if not a pipe */ - /* Set stdin to raw mode if it is a tty */ - interactive = isatty(STDIN_FILENO); - if (interactive) { - ch = fcntl(STDIN_FILENO, F_GETFL, 0); - if (ch != -1) - (void) fcntl(STDIN_FILENO, F_SETFL, ch | O_NONBLOCK); - if (!term_raw(STDIN_FILENO, 1)) - error(1, "cannot set tty to raw mode"); - } - fdsw = (fd_set *)emalloc2(howmany(STDOUT_FILENO + 1, NFDBITS), - sizeof(fd_mask)); - - /* - * Timing file consists of line of the format: "%f %d\n" - */ -#ifdef HAVE_ZLIB_H - while (gzgets(io_fds[IOFD_TIMING].g, buf, sizeof(buf)) != NULL) { -#else - while (fgets(buf, sizeof(buf), io_fds[IOFD_TIMING].f) != NULL) { -#endif - if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes)) - errorx(1, "invalid timing file line: %s", buf); - - if (interactive) - check_input(STDIN_FILENO, &speed); - - /* Adjust delay using speed factor and clamp to max_wait */ - to_wait = seconds / speed; - if (max_wait && to_wait > max_wait) - to_wait = max_wait; - delay(to_wait); - - /* Even if we are not relaying, we still have to delay. */ - if (io_fds[idx].v == NULL) - continue; - - /* All output is sent to stdout. */ - while (nbytes != 0) { - if (nbytes > sizeof(buf)) - len = sizeof(buf); - else - len = nbytes; -#ifdef HAVE_ZLIB_H - nread = gzread(io_fds[idx].g, buf, len); -#else - nread = fread(buf, 1, len, io_fds[idx].f); -#endif - nbytes -= nread; - off = 0; - do { - /* no stdio, must be unbuffered */ - nwritten = write(STDOUT_FILENO, buf + off, nread - off); - if (nwritten == -1) { - if (errno == EINTR) - continue; - if (errno == EAGAIN) { - FD_SET(STDOUT_FILENO, fdsw); - do { - nready = select(STDOUT_FILENO + 1, NULL, fdsw, NULL, NULL); - } while (nready == -1 && errno == EINTR); - if (nready == 1) - continue; - } - error(1, "writing to standard output"); - } - off += nwritten; - } while (nread > off); - } - } - term_restore(STDIN_FILENO, 1); - exit(0); -} - -static void -delay(secs) - double secs; -{ - struct timespec ts, rts; - int rval; - - /* - * Typical max resolution is 1/HZ but we can't portably check that. - * If the interval is small enough, just ignore it. - */ - if (secs < 0.0001) - return; - - rts.tv_sec = secs; - rts.tv_nsec = (secs - (double) rts.tv_sec) * 1000000000.0; - do { - memcpy(&ts, &rts, sizeof(ts)); - rval = nanosleep(&ts, &rts); - } while (rval == -1 && errno == EINTR); - if (rval == -1) - error(1, "nanosleep: tv_sec %ld, tv_nsec %ld", ts.tv_sec, ts.tv_nsec); -} - -static void * -open_io_fd(path, len, suffix) - char *path; - int len; - const char *suffix; -{ - path[len] = '\0'; - strlcat(path, suffix, PATH_MAX); - -#ifdef HAVE_ZLIB_H - return gzopen(path, "r"); -#else - return fopen(path, "r"); -#endif -} - -/* - * Build expression list from search args - */ -static int -parse_expr(headp, argv) - struct search_node **headp; - char *argv[]; -{ - struct search_node *sn, *newsn; - char or = 0, not = 0, type, **av; - - sn = *headp; - for (av = argv; *av; av++) { - switch (av[0][0]) { - case 'a': /* and (ignore) */ - if (strncmp(*av, "and", strlen(*av)) != 0) - goto bad; - continue; - case 'o': /* or */ - if (strncmp(*av, "or", strlen(*av)) != 0) - goto bad; - or = 1; - continue; - case '!': /* negate */ - if (av[0][1] != '\0') - goto bad; - not = 1; - continue; - case 'c': /* command */ - if (av[0][1] == '\0') - errorx(1, "ambiguous expression \"%s\"", *av); - if (strncmp(*av, "cwd", strlen(*av)) == 0) - type = ST_CWD; - else if (strncmp(*av, "command", strlen(*av)) == 0) - type = ST_PATTERN; - else - goto bad; - break; - case 'f': /* from date */ - if (strncmp(*av, "fromdate", strlen(*av)) != 0) - goto bad; - type = ST_FROMDATE; - break; - case 'g': /* runas group */ - if (strncmp(*av, "group", strlen(*av)) != 0) - goto bad; - type = ST_RUNASGROUP; - break; - case 'r': /* runas user */ - if (strncmp(*av, "runas", strlen(*av)) != 0) - goto bad; - type = ST_RUNASUSER; - break; - case 't': /* tty or to date */ - if (av[0][1] == '\0') - errorx(1, "ambiguous expression \"%s\"", *av); - if (strncmp(*av, "todate", strlen(*av)) == 0) - type = ST_TODATE; - else if (strncmp(*av, "tty", strlen(*av)) == 0) - type = ST_TTY; - else - goto bad; - break; - case 'u': /* user */ - if (strncmp(*av, "user", strlen(*av)) != 0) - goto bad; - type = ST_USER; - break; - case '(': /* start sub-expression */ - if (av[0][1] != '\0') - goto bad; - if (stack_top + 1 == STACK_NODE_SIZE) { - errorx(1, "too many parenthesized expressions, max %d", - STACK_NODE_SIZE); - } - node_stack[stack_top++] = sn; - type = ST_EXPR; - break; - case ')': /* end sub-expression */ - if (av[0][1] != '\0') - goto bad; - /* pop */ - if (--stack_top < 0) - errorx(1, "unmatched ')' in expression"); - if (node_stack[stack_top]) - sn->next = node_stack[stack_top]->next; - return(av - argv + 1); - bad: - default: - errorx(1, "unknown search term \"%s\"", *av); - /* NOTREACHED */ - } - - /* Allocate new search node */ - newsn = emalloc(sizeof(*newsn)); - newsn->next = NULL; - newsn->type = type; - newsn->or = or; - newsn->negated = not; - if (type == ST_EXPR) { - av += parse_expr(&newsn->u.expr, av + 1); - } else { - if (*(++av) == NULL) - errorx(1, "%s requires an argument", av[-1]); -#ifdef HAVE_REGCOMP - if (type == ST_PATTERN) { - if (regcomp(&newsn->u.cmdre, *av, REG_EXTENDED|REG_NOSUB) != 0) - errorx(1, "invalid regex: %s", *av); - } else -#endif - if (type == ST_TODATE || type == ST_FROMDATE) { - newsn->u.tstamp = get_date(*av); - if (newsn->u.tstamp == -1) - errorx(1, "could not parse date \"%s\"", *av); - } else { - newsn->u.ptr = *av; - } - } - not = or = 0; /* reset state */ - if (sn) - sn->next = newsn; - else - *headp = newsn; - sn = newsn; - } - if (stack_top) - errorx(1, "unmatched '(' in expression"); - if (or) - errorx(1, "illegal trailing \"or\""); - if (not) - errorx(1, "illegal trailing \"!\""); - - return(av - argv); -} - -static int -match_expr(head, log) - struct search_node *head; - struct log_info *log; -{ - struct search_node *sn; - int matched = 1, rc; - - for (sn = head; sn; sn = sn->next) { - /* If we have no match, skip ahead to the next OR entry. */ - if (!matched && !sn->or) - continue; - - switch (sn->type) { - case ST_EXPR: - matched = match_expr(sn->u.expr, log); - break; - case ST_CWD: - matched = strcmp(sn->u.cwd, log->cwd) == 0; - break; - case ST_TTY: - matched = strcmp(sn->u.tty, log->tty) == 0; - break; - case ST_RUNASGROUP: - matched = strcmp(sn->u.runas_group, log->runas_group) == 0; - break; - case ST_RUNASUSER: - matched = strcmp(sn->u.runas_user, log->runas_user) == 0; - break; - case ST_USER: - matched = strcmp(sn->u.user, log->user) == 0; - break; - case ST_PATTERN: -#ifdef HAVE_REGCOMP - rc = regexec(&sn->u.cmdre, log->cmd, 0, NULL, 0); - if (rc && rc != REG_NOMATCH) { - char buf[BUFSIZ]; - regerror(rc, &sn->u.cmdre, buf, sizeof(buf)); - errorx(1, "%s", buf); - } - matched = rc == REG_NOMATCH ? 0 : 1; -#else - matched = strstr(log.cmd, sn->u.pattern) != NULL; -#endif - break; - case ST_FROMDATE: - matched = log->tstamp >= sn->u.tstamp; - break; - case ST_TODATE: - matched = log->tstamp <= sn->u.tstamp; - break; - } - if (sn->negated) - matched = !matched; - } - return(matched); -} - -static int -list_session_dir(pathbuf, re, user, tty) - char *pathbuf; - REGEX_T *re; - const char *user; - const char *tty; -{ - FILE *fp; - DIR *d; - struct dirent *dp; - char *buf = NULL, *cmd = NULL, *cwd = NULL, idstr[7], *cp; - struct log_info li; - size_t bufsize = 0, cwdsize = 0, cmdsize = 0, plen; - - plen = strlen(pathbuf); - d = opendir(pathbuf); - if (d == NULL && errno != ENOTDIR) { - warning("cannot opendir %s", pathbuf); - return(-1); - } - while ((dp = readdir(d)) != NULL) { - if (NAMLEN(dp) != 2 || !isalnum((unsigned char)dp->d_name[0]) || - !isalnum((unsigned char)dp->d_name[1])) - continue; - - /* open log file, print id and command */ - pathbuf[plen + 0] = '/'; - pathbuf[plen + 1] = dp->d_name[0]; - pathbuf[plen + 2] = dp->d_name[1]; - pathbuf[plen + 3] = '/'; - pathbuf[plen + 4] = 'l'; - pathbuf[plen + 5] = 'o'; - pathbuf[plen + 6] = 'g'; - pathbuf[plen + 7] = '\0'; - fp = fopen(pathbuf, "r"); - if (fp == NULL) { - warning("unable to open %s", pathbuf); - continue; - } - - /* - * ID file has three lines: - * 1) a log info line - * 2) cwd - * 3) command with args - */ - if (getline(&buf, &bufsize, fp) == -1 || - getline(&cwd, &cwdsize, fp) == -1 || - getline(&cmd, &cmdsize, fp) == -1) { - fclose(fp); - continue; - } - fclose(fp); - - /* crack the log line: timestamp:user:runas_user:runas_group:tty */ - buf[strcspn(buf, "\n")] = '\0'; - if ((li.tstamp = atoi(buf)) == 0) - continue; - - if ((cp = strchr(buf, ':')) == NULL) - continue; - *cp++ = '\0'; - li.user = cp; - - if ((cp = strchr(cp, ':')) == NULL) - continue; - *cp++ = '\0'; - li.runas_user = cp; - - if ((cp = strchr(cp, ':')) == NULL) - continue; - *cp++ = '\0'; - li.runas_group = cp; - - if ((cp = strchr(cp, ':')) == NULL) - continue; - *cp++ = '\0'; - li.tty = cp; - - cwd[strcspn(cwd, "\n")] = '\0'; - li.cwd = cwd; - - cmd[strcspn(cmd, "\n")] = '\0'; - li.cmd = cmd; - - /* Match on search expression if there is one. */ - if (search_expr && !match_expr(search_expr, &li)) - continue; - - /* Convert from /var/log/sudo-sessions/00/00/01 to 000001 */ - idstr[0] = pathbuf[plen - 5]; - idstr[1] = pathbuf[plen - 4]; - idstr[2] = pathbuf[plen - 2]; - idstr[3] = pathbuf[plen - 1]; - idstr[4] = pathbuf[plen + 1]; - idstr[5] = pathbuf[plen + 2]; - idstr[6] = '\0'; - printf("%s : %s : TTY=%s ; CWD=%s ; USER=%s ; ", - get_timestr(li.tstamp, 1), li.user, li.tty, li.cwd, li.runas_user); - if (*li.runas_group) - printf("GROUP=%s ; ", li.runas_group); - printf("TSID=%s ; COMMAND=%s\n", idstr, li.cmd); - } - return(0); -} - -static int -list_sessions(argc, argv, pattern, user, tty) - int argc; - char **argv; - const char *pattern; - const char *user; - const char *tty; -{ - DIR *d1, *d2; - struct dirent *dp1, *dp2; - REGEX_T rebuf, *re = NULL; - size_t sdlen; - char pathbuf[PATH_MAX]; - - /* Parse search expression if present */ - parse_expr(&search_expr, argv); - - d1 = opendir(session_dir); - if (d1 == NULL) - error(1, "unable to open %s", session_dir); - -#ifdef HAVE_REGCOMP - /* optional regex */ - if (pattern) { - re = &rebuf; - if (regcomp(re, pattern, REG_EXTENDED|REG_NOSUB) != 0) - errorx(1, "invalid regex: %s", pattern); - } -#else - re = (char *) pattern; -#endif /* HAVE_REGCOMP */ - - sdlen = strlcpy(pathbuf, session_dir, sizeof(pathbuf)); - if (sdlen + sizeof("/00/00/00/log") >= sizeof(pathbuf)) { - errno = ENAMETOOLONG; - error(1, "%s/00/00/00/log", session_dir); - } - - /* - * Three levels of directory, e.g. 00/00/00 .. ZZ/ZZ/ZZ - * We do a depth-first traversal. - */ - while ((dp1 = readdir(d1)) != NULL) { - if (NAMLEN(dp1) != 2 || !isalnum((unsigned char)dp1->d_name[0]) || - !isalnum((unsigned char)dp1->d_name[1])) - continue; - - pathbuf[sdlen + 0] = '/'; - pathbuf[sdlen + 1] = dp1->d_name[0]; - pathbuf[sdlen + 2] = dp1->d_name[1]; - pathbuf[sdlen + 3] = '\0'; - d2 = opendir(pathbuf); - if (d2 == NULL) - continue; - - while ((dp2 = readdir(d2)) != NULL) { - if (NAMLEN(dp2) != 2 || !isalnum((unsigned char)dp2->d_name[0]) || - !isalnum((unsigned char)dp2->d_name[1])) - continue; - - pathbuf[sdlen + 3] = '/'; - pathbuf[sdlen + 4] = dp2->d_name[0]; - pathbuf[sdlen + 5] = dp2->d_name[1]; - pathbuf[sdlen + 6] = '\0'; - list_session_dir(pathbuf, re, user, tty); - } - closedir(d2); - } - closedir(d1); - return(0); -} - -/* - * Check input for ' ', '<', '>' - * pause, slow, fast - */ -static void -check_input(ttyfd, speed) - int ttyfd; - double *speed; -{ - fd_set *fdsr; - int nready, paused = 0; - struct timeval tv; - char ch; - ssize_t n; - - fdsr = (fd_set *)emalloc2(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask)); - - for (;;) { - FD_SET(ttyfd, fdsr); - tv.tv_sec = 0; - tv.tv_usec = 0; - - nready = select(ttyfd + 1, fdsr, NULL, NULL, paused ? NULL : &tv); - if (nready != 1) - break; - n = read(ttyfd, &ch, 1); - if (n == 1) { - if (paused) { - paused = 0; - continue; - } - switch (ch) { - case ' ': - paused = 1; - break; - case '<': - *speed /= 2; - break; - case '>': - *speed *= 2; - break; - } - } - } - free(fdsr); -} - -/* - * Parse a timing line, which is formatted as: - * index sleep_time num_bytes - * Where index is IOFD_*, sleep_time is the number of seconds to sleep - * before writing the data and num_bytes is the number of bytes to output. - * Returns 1 on success and 0 on failure. - */ -static int -parse_timing(buf, decimal, idx, seconds, nbytes) - const char *buf; - const char *decimal; - int *idx; - double *seconds; - size_t *nbytes; -{ - unsigned long ul; - long l; - double d, fract = 0; - char *cp, *ep; - - /* Parse index */ - ul = strtoul(buf, &ep, 10); - if (ul > IOFD_MAX) - goto bad; - *idx = (int)ul; - for (cp = ep + 1; isspace((unsigned char) *cp); cp++) - continue; - - /* - * Parse number of seconds. Sudo logs timing data in the C locale - * but this may not match the current locale so we cannot use strtod(). - * Furthermore, sudo < 1.7.4 logged with the user's locale so we need - * to be able to parse those logs too. - */ - errno = 0; - l = strtol(cp, &ep, 10); - if ((errno == ERANGE && (l == LONG_MAX || l == LONG_MIN)) || - l < 0 || l > INT_MAX || - (*ep != '.' && strncmp(ep, decimal, strlen(decimal)) != 0)) { - goto bad; - } - *seconds = (double)l; - cp = ep + (*ep == '.' ? 1 : strlen(decimal)); - d = 10.0; - while (isdigit((unsigned char) *cp)) { - fract += (*cp - '0') / d; - d *= 10; - cp++; - } - *seconds += fract; - while (isspace((unsigned char) *cp)) - cp++; - - errno = 0; - ul = strtoul(cp, &ep, 10); - if (errno == ERANGE && ul == ULONG_MAX) - goto bad; - *nbytes = (size_t)ul; - - return 1; -bad: - return 0; -} - -static void -usage() -{ - fprintf(stderr, - "usage: %s [-d directory] [-m max_wait] [-s speed_factor] ID\n", - getprogname()); - fprintf(stderr, - "usage: %s [-d directory] -l [search expression]\n", - getprogname()); - exit(1); -} - -/* - * Cleanup hook for error()/errorx() - */ -void -cleanup(signo) - int signo; -{ - term_restore(STDIN_FILENO, 0); - if (signo) - kill(getpid(), signo); -} diff --git a/sudoreplay.cat b/sudoreplay.cat deleted file mode 100644 index 9c03469..0000000 --- a/sudoreplay.cat +++ /dev/null @@ -1,330 +0,0 @@ - - - -SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) - - -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 [--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 - replaying, ssuuddoorreeppllaayy can play the session back in real-time, or the - playback speed may be adjusted (faster or slower) based on the command - line options. The _I_D should be a six character sequence of digits and - upper case letters, e.g. 0100A5, which is logged by ssuuddoo when a - command is run with session logging enabled. - - In list mode, ssuuddoorreeppllaayy can be used to find the ID of a session based - on a number of criteria such as the user, tty or command run. - - In replay mode, if the standard output has not been redirected, - ssuuddoorreeppllaayy will act on the following keys: - - ' ' (space) - Pause output; press any key to resume. - - '<' Reduce the playback speed by one half. - - '>' Double the playback speed. - -OOPPTTIIOONNSS - ssuuddoorreeppllaayy accepts the following command line options: - - -d _d_i_r_e_c_t_o_r_y - Use _d_i_r_e_c_t_o_r_y to for the session logs instead of the - default, _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o. - - -f _f_i_l_t_e_r By default, ssuuddoorreeppllaayy will play back the command's - standard output, standard error and tty output. The _-_f - option can be used to select which of these to output. The - _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 - 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 - - - - - -SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) - - - regular expression support, a simple substring - match is performed instead. - - cwd _d_i_r_e_c_t_o_r_y - Evaluates to true if the command was run with the - specified current working directory. - - fromdate _d_a_t_e - Evaluates to true if the command was run on or - after _d_a_t_e. See "Date and time format" for a - description of supported date and time formats. - - group _r_u_n_a_s___g_r_o_u_p - Evaluates to true if the command was run with the - specified _r_u_n_a_s___g_r_o_u_p. Note that unless a - _r_u_n_a_s___g_r_o_u_p was explicitly specified when ssuuddoo was - run this field will be empty in the log. - - runas _r_u_n_a_s___u_s_e_r - Evaluates to true if the command was run as the - specified _r_u_n_a_s___u_s_e_r. Note that ssuuddoo runs commands - as user _r_o_o_t by default. - - todate _d_a_t_e - Evaluates to true if the command was run on or - prior to _d_a_t_e. See "Date and time format" for a - description of supported date and time formats. - - tty _t_t_y Evaluates to true if the command was run on the - specified terminal device. The _t_t_y should be - specified without the _/_d_e_v_/ prefix, e.g. _t_t_y_0_1 - instead of _/_d_e_v_/_t_t_y_0_1. - - user _u_s_e_r _n_a_m_e - Evaluates to true if the ID matches a command run - by _u_s_e_r _n_a_m_e. - - Predicates may be abbreviated to the shortest unique string - (currently all predicates may be shortened to a single - character). - - Predicates may be combined using _a_n_d, _o_r and _! operators as - well as '(' and ')' for grouping (note that parentheses - must generally be escaped from the shell). The _a_n_d - operator is optional, adjacent predicates have an implied - _a_n_d unless separated by an _o_r. - - -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 - - - - - -SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) - - - point number, .e.g. _2_._5. - - -s _s_p_e_e_d___f_a_c_t_o_r - This option causes ssuuddoorreeppllaayy to adjust the number of - seconds it will wait between key presses or program output. - This can be used to slow down or speed up the display. For - example, a _s_p_e_e_d___f_a_c_t_o_r of _2 would make the output twice as - fast whereas a _s_p_e_e_d___f_a_c_t_o_r of <.5> would make the output - twice as slow. - - -V The --VV (version) option causes ssuuddoorreeppllaayy to print its - version number and exit. - - DDaattee aanndd ttiimmee ffoorrmmaatt - The time and date may be specified multiple ways, common formats - include: - - HH:MM:SS am MM/DD/CCYY timezone - 24 hour time may be used in place of am/pm. - - HH:MM:SS am Month, Day Year timezone - 24 hour time may be used in place of am/pm, and month and day - names may be abbreviated. Note that month and day of the week - names must be specified in English. - - CCYY-MM-DD HH:MM:SS - ISO time format - - DD Month CCYY HH:MM:SS - The month name may be abbreviated. - - Either time or date may be omitted, the am/pm and timezone are - optional. If no date is specified, the current day is assumed; if no - time is specified, the first second of the specified date is used. The - less significant parts of both time and date may also be omitted, in - which case zero is assumed. For example, the following are all valid: - - The following are all valid time and date specifications: - - now The current time and date. - - tomorrow - Exactly one day from now. - - yesterday - 24 hours ago. - - 2 hours ago - 2 hours ago. - - next Friday - The first second of the next Friday. - - - - - -1.7.4 July 12, 2010 3 - - - - - -SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) - - - this week - The current time but the first day of the coming week. - - a fortnight ago - The current time but 14 days ago. - - 10:01 am 9/17/2009 - 10:01 am, September 17, 2009. - - 10:01 am - 10:01 am on the current day. - - 10 10:00 am on the current day. - - 9/17/2009 - 00:00 am, September 17, 2009. - - 10:01 am Sep 17, 2009 - 10:01 am, September 17, 2009. - -FFIILLEESS - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o The default I/O log directory. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_l_o_g - Example session log info. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_s_t_d_i_n - Example session standard input log. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_s_t_d_o_u_t - Example session standard output log. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_s_t_d_e_r_r - Example session standard error log. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_t_t_y_i_n - Example session tty input file. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_t_t_y_o_u_t - Example session tty output file. - - _/_v_a_r_/_l_o_g_/_s_u_d_o_-_i_o_/_0_0_/_0_0_/_0_1_/_t_i_m_i_n_g - Example session timing file. - - Note that the _s_t_d_i_n, _s_t_d_o_u_t and _s_t_d_e_r_r files will be empty unless ssuuddoo - was used as part of a pipeline for a particular command. - -EEXXAAMMPPLLEESS - List sessions run by user _m_i_l_l_e_r_t: - - 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 - - - - - -SUDOREPLAY(1m) MAINTENANCE COMMANDS SUDOREPLAY(1m) - - - sudoreplay -l user bob command vi - - List sessions run by user _j_e_f_f that match a regular expression: - - sudoreplay -l user jeff command '/bin/[a-z]*sh' - - List sessions run by jeff or bob on the console: - - sudoreplay -l ( user jeff or user bob ) tty console - -SSEEEE AALLSSOO - _s_u_d_o(1m), _s_c_r_i_p_t(1) - -AAUUTTHHOORR - Todd C. Miller - -BBUUGGSS - If you feel you have found a bug in ssuuddoorreeppllaayy, please submit a bug - report at http://www.sudo.ws/sudo/bugs/ - -SSUUPPPPOORRTT - Limited free support is available via the sudo-users mailing list, see - http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search - the archives. - -DDIISSCCLLAAIIMMEERR - ssuuddoorreeppllaayy is provided ``AS IS'' and any express or implied warranties, - including, but not limited to, the implied warranties of - merchantability and fitness for a particular purpose are disclaimed. - See the LICENSE file distributed with ssuuddoo or - http://www.sudo.ws/sudo/license.html for complete details. - - - - - - - - - - - - - - - - - - - - - - - - - - -1.7.4 July 12, 2010 5 - - diff --git a/sudoreplay.man.in b/sudoreplay.man.in deleted file mode 100644 index 1ed044d..0000000 --- a/sudoreplay.man.in +++ /dev/null @@ -1,404 +0,0 @@ -.\" Copyright (c) 2009-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. -.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` -. ds C' -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "SUDOREPLAY @mansectsu@" -.TH SUDOREPLAY @mansectsu@ "July 12, 2010" "1.7.4" "MAINTENANCE COMMANDS" -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -sudoreplay \- replay sudo session logs -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBsudoreplay\fR [\fB\-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] -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fBsudoreplay\fR plays back or lists the session logs created by -\&\fBsudo\fR. When replaying, \fBsudoreplay\fR can play the session back -in real-time, or the playback speed may be adjusted (faster or -slower) based on the command line options. The \fI\s-1ID\s0\fR should be -a six character sequence of digits and upper case letters, e.g. -0100A5, which is logged by \fBsudo\fR when a command is run with -session logging enabled. -.PP -In list mode, \fBsudoreplay\fR can be used to find the \s-1ID\s0 of a session -based on a number of criteria such as the user, tty or command run. -.PP -In replay mode, if the standard output has not been redirected, -\&\fBsudoreplay\fR will act on the following keys: -.IP "' ' (space)" 8 -.IX Item "' ' (space)" -Pause output; press any key to resume. -.IP "'<'" 8 -Reduce the playback speed by one half. -.IP "'>'" 8 -Double the playback speed. -.SH "OPTIONS" -.IX Header "OPTIONS" -\&\fBsudoreplay\fR accepts the following command line options: -.IP "\-d \fIdirectory\fR" 12 -.IX Item "-d directory" -Use \fIdirectory\fR to for the session logs instead of the default, -\&\fI/var/log/sudo\-io\fR. -.IP "\-f \fIfilter\fR" 12 -.IX Item "-f filter" -By default, \fBsudoreplay\fR will play back the command's standard -output, standard error and tty output. The \fI\-f\fR option can be -used to select which of these to output. The \fIfilter\fR argument -is a comma-separated list, consisting of one or more of following: -\&\fIstdout\fR, \fIstderr\fR, and \fIttyout\fR. -.IP "\-l" 12 -.IX Item "-l" -Enable \*(L"list mode\*(R". In this mode, \fBsudoreplay\fR will list available -session IDs. If a \fIsearch expression\fR is specified, it will be -used to restrict the IDs that are displayed. An expression is -composed of the following predicates: -.RS 12 -.IP "command \fIcommand pattern\fR" 8 -.IX Item "command command pattern" -Evaluates to true if the command run matches \fIcommand pattern\fR. -On systems with \s-1POSIX\s0 regular expression support, the pattern may -be an extended regular expression. On systems without \s-1POSIX\s0 regular -expression support, a simple substring match is performed instead. -.IP "cwd \fIdirectory\fR" 8 -.IX Item "cwd directory" -Evaluates to true if the command was run with the specified current -working directory. -.IP "fromdate \fIdate\fR" 8 -.IX Item "fromdate date" -Evaluates to true if the command was run on or after \fIdate\fR. -See \*(L"Date and time format\*(R" for a description of supported -date and time formats. -.IP "group \fIrunas_group\fR" 8 -.IX Item "group runas_group" -Evaluates to true if the command was run with the specified -\&\fIrunas_group\fR. Note that unless a \fIrunas_group\fR was explicitly -specified when \fBsudo\fR was run this field will be empty in the log. -.IP "runas \fIrunas_user\fR" 8 -.IX Item "runas runas_user" -Evaluates to true if the command was run as the specified \fIrunas_user\fR. -Note that \fBsudo\fR runs commands as user \fIroot\fR by default. -.IP "todate \fIdate\fR" 8 -.IX Item "todate date" -Evaluates to true if the command was run on or prior to \fIdate\fR. -See \*(L"Date and time format\*(R" for a description of supported -date and time formats. -.IP "tty \fItty\fR" 8 -.IX Item "tty tty" -Evaluates to true if the command was run on the specified terminal -device. The \fItty\fR should be specified without the \fI/dev/\fR prefix, -e.g. \fItty01\fR instead of \fI/dev/tty01\fR. -.IP "user \fIuser name\fR" 8 -.IX Item "user user name" -Evaluates to true if the \s-1ID\s0 matches a command run by \fIuser name\fR. -.RE -.RS 12 -.Sp -Predicates may be abbreviated to the shortest unique string (currently -all predicates may be shortened to a single character). -.Sp -Predicates may be combined using \fIand\fR, \fIor\fR and \fI!\fR operators -as well as \f(CW\*(Aq(\*(Aq\fR and \f(CW\*(Aq)\*(Aq\fR for grouping (note that parentheses -must generally be escaped from the shell). The \fIand\fR operator is -optional, adjacent predicates have an implied \fIand\fR unless separated -by an \fIor\fR. -.RE -.IP "\-m \fImax_wait\fR" 12 -.IX Item "-m max_wait" -Specify an upper bound on how long to wait between key presses or -output data. By default, \fBsudo_replay\fR will accurately reproduce -the delays between key presses or program output. However, this -can be tedious when the session includes long pauses. When the -\&\fI\-m\fR option is specified, \fBsudoreplay\fR will limit these pauses -to at most \fImax_wait\fR seconds. The value may be specified as a -floating point number, .e.g. \fI2.5\fR. -.IP "\-s \fIspeed_factor\fR" 12 -.IX Item "-s speed_factor" -This option causes \fBsudoreplay\fR to adjust the number of seconds -it will wait between key presses or program output. This can be -used to slow down or speed up the display. For example, a -\&\fIspeed_factor\fR of \fI2\fR would make the output twice as fast whereas -a \fIspeed_factor\fR of <.5> would make the output twice as slow. -.IP "\-V" 12 -.IX Item "-V" -The \fB\-V\fR (version) option causes \fBsudoreplay\fR to print its version number -and exit. -.SS "Date and time format" -.IX Subsection "Date and time format" -The time and date may be specified multiple ways, common formats include: -.IP "\s-1HH:MM:SS\s0 am \s-1MM/DD/CCYY\s0 timezone" 8 -.IX Item "HH:MM:SS am MM/DD/CCYY timezone" -24 hour time may be used in place of am/pm. -.IP "\s-1HH:MM:SS\s0 am Month, Day Year timezone" 8 -.IX Item "HH:MM:SS am Month, Day Year timezone" -24 hour time may be used in place of am/pm, and month and day names -may be abbreviated. Note that month and day of the week names must -be specified in English. -.IP "CCYY-MM-DD \s-1HH:MM:SS\s0" 8 -.IX Item "CCYY-MM-DD HH:MM:SS" -\&\s-1ISO\s0 time format -.IP "\s-1DD\s0 Month \s-1CCYY\s0 \s-1HH:MM:SS\s0" 8 -.IX Item "DD Month CCYY HH:MM:SS" -The month name may be abbreviated. -.PP -Either time or date may be omitted, the am/pm and timezone are -optional. If no date is specified, the current day is assumed; if -no time is specified, the first second of the specified date is -used. The less significant parts of both time and date may also -be omitted, in which case zero is assumed. For example, the following -are all valid: -.PP -The following are all valid time and date specifications: -.IP "now" 8 -.IX Item "now" -The current time and date. -.IP "tomorrow" 8 -.IX Item "tomorrow" -Exactly one day from now. -.IP "yesterday" 8 -.IX Item "yesterday" -24 hours ago. -.IP "2 hours ago" 8 -.IX Item "2 hours ago" -2 hours ago. -.IP "next Friday" 8 -.IX Item "next Friday" -The first second of the next Friday. -.IP "this week" 8 -.IX Item "this week" -The current time but the first day of the coming week. -.IP "a fortnight ago" 8 -.IX Item "a fortnight ago" -The current time but 14 days ago. -.IP "10:01 am 9/17/2009" 8 -.IX Item "10:01 am 9/17/2009" -10:01 am, September 17, 2009. -.IP "10:01 am" 8 -.IX Item "10:01 am" -10:01 am on the current day. -.IP "10" 8 -.IX Item "10" -10:00 am on the current day. -.IP "9/17/2009" 8 -.IX Item "9/17/2009" -00:00 am, September 17, 2009. -.IP "10:01 am Sep 17, 2009" 8 -.IX Item "10:01 am Sep 17, 2009" -10:01 am, September 17, 2009. -.SH "FILES" -.IX Header "FILES" -.IP "\fI/var/log/sudo\-io\fR" 24 -.IX Item "/var/log/sudo-io" -The default I/O log directory. -.IP "\fI/var/log/sudo\-io/00/00/01/log\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/log" -Example session log info. -.IP "\fI/var/log/sudo\-io/00/00/01/stdin\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/stdin" -Example session standard input log. -.IP "\fI/var/log/sudo\-io/00/00/01/stdout\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/stdout" -Example session standard output log. -.IP "\fI/var/log/sudo\-io/00/00/01/stderr\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/stderr" -Example session standard error log. -.IP "\fI/var/log/sudo\-io/00/00/01/ttyin\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/ttyin" -Example session tty input file. -.IP "\fI/var/log/sudo\-io/00/00/01/ttyout\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/ttyout" -Example session tty output file. -.IP "\fI/var/log/sudo\-io/00/00/01/timing\fR" 24 -.IX Item "/var/log/sudo-io/00/00/01/timing" -Example session timing file. -.PP -Note that the \fIstdin\fR, \fIstdout\fR and \fIstderr\fR files will be empty -unless \fBsudo\fR was used as part of a pipeline for a particular -command. -.SH "EXAMPLES" -.IX Header "EXAMPLES" -List sessions run by user \fImillert\fR: -.PP -.Vb 1 -\& sudoreplay \-l user millert -.Ve -.PP -List sessions run by user \fIbob\fR with a command containing the string vi: -.PP -.Vb 1 -\& sudoreplay \-l user bob command vi -.Ve -.PP -List sessions run by user \fIjeff\fR that match a regular expression: -.PP -.Vb 1 -\& sudoreplay \-l user jeff command \*(Aq/bin/[a\-z]*sh\*(Aq -.Ve -.PP -List sessions run by jeff or bob on the console: -.PP -.Vb 1 -\& sudoreplay \-l ( user jeff or user bob ) tty console -.Ve -.SH "SEE ALSO" -.IX Header "SEE ALSO" -\&\fIsudo\fR\|(@mansectsu@), \fIscript\fR\|(1) -.SH "AUTHOR" -.IX Header "AUTHOR" -Todd C. Miller -.SH "BUGS" -.IX Header "BUGS" -If you feel you have found a bug in \fBsudoreplay\fR, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ -.SH "SUPPORT" -.IX Header "SUPPORT" -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or -search the archives. -.SH "DISCLAIMER" -.IX Header "DISCLAIMER" -\&\fBsudoreplay\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 -file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/sudoreplay.pod b/sudoreplay.pod deleted file mode 100644 index c36f913..0000000 --- a/sudoreplay.pod +++ /dev/null @@ -1,341 +0,0 @@ -Copyright (c) 2009-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. -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -=pod - -=head1 NAME - -sudoreplay - replay sudo session logs - -=head1 SYNOPSIS - -B [B<-d> I] [B<-f> I] [B<-m> I] [B<-s> I] ID - -B [B<-d> I] -l [search expression] - -=head1 DESCRIPTION - -B plays back or lists the session logs created by -B. When replaying, B can play the session back -in real-time, or the playback speed may be adjusted (faster or -slower) based on the command line options. The I should be -a six character sequence of digits and upper case letters, e.g. -0100A5, which is logged by B when a command is run with -session logging enabled. - -In list mode, B can be used to find the ID of a session -based on a number of criteria such as the user, tty or command run. - -In replay mode, if the standard output has not been redirected, -B will act on the following keys: - -=over 8 - -=item ' ' (space) - -Pause output; press any key to resume. - -=item '<' - -Reduce the playback speed by one half. - -=item '>' - -Double the playback speed. - -=back - -=head1 OPTIONS - -B accepts the following command line options: - -=over 12 - -=item -d I - -Use I to for the session logs instead of the default, -F. - -=item -f I - -By default, B will play back the command's standard -output, standard error and tty output. The I<-f> option can be -used to select which of these to output. The I argument -is a comma-separated list, consisting of one or more of following: -I, I, and I. - -=item -l - -Enable "list mode". In this mode, B will list available -session IDs. If a I is specified, it will be -used to restrict the IDs that are displayed. An expression is -composed of the following predicates: - -=over 8 - -=item command I - -Evaluates to true if the command run matches I. -On systems with POSIX regular expression support, the pattern may -be an extended regular expression. On systems without POSIX regular -expression support, a simple substring match is performed instead. - -=item cwd I - -Evaluates to true if the command was run with the specified current -working directory. - -=item fromdate I - -Evaluates to true if the command was run on or after I. -See L<"Date and time format"> for a description of supported -date and time formats. - -=item group I - -Evaluates to true if the command was run with the specified -I. Note that unless a I was explicitly -specified when B was run this field will be empty in the log. - -=item runas I - -Evaluates to true if the command was run as the specified I. -Note that B runs commands as user I by default. - -=item todate I - -Evaluates to true if the command was run on or prior to I. -See L<"Date and time format"> for a description of supported -date and time formats. - -=item tty I - -Evaluates to true if the command was run on the specified terminal -device. The I should be specified without the F prefix, -e.g. F instead of F. - -=item user I - -Evaluates to true if the ID matches a command run by I. - -=back - -Predicates may be abbreviated to the shortest unique string (currently -all predicates may be shortened to a single character). - -Predicates may be combined using I, I and I operators -as well as C<'('> and C<')'> for grouping (note that parentheses -must generally be escaped from the shell). The I operator is -optional, adjacent predicates have an implied I unless separated -by an I. - -=item -m I - -Specify an upper bound on how long to wait between key presses or -output data. By default, B will accurately reproduce -the delays between key presses or program output. However, this -can be tedious when the session includes long pauses. When the -I<-m> option is specified, B will limit these pauses -to at most I seconds. The value may be specified as a -floating point number, .e.g. I<2.5>. - -=item -s I - -This option causes B to adjust the number of seconds -it will wait between key presses or program output. This can be -used to slow down or speed up the display. For example, a -I of I<2> would make the output twice as fast whereas -a I of <.5> would make the output twice as slow. - -=item -V - -The B<-V> (version) option causes B to print its version number -and exit. - -=back - -=head2 Date and time format - -The time and date may be specified multiple ways, common formats include: - -=over 8 - -=item HH:MM:SS am MM/DD/CCYY timezone - -24 hour time may be used in place of am/pm. - -=item HH:MM:SS am Month, Day Year timezone - -24 hour time may be used in place of am/pm, and month and day names -may be abbreviated. Note that month and day of the week names must -be specified in English. - -=item CCYY-MM-DD HH:MM:SS - -ISO time format - -=item DD Month CCYY HH:MM:SS - -The month name may be abbreviated. - -=back - -Either time or date may be omitted, the am/pm and timezone are -optional. If no date is specified, the current day is assumed; if -no time is specified, the first second of the specified date is -used. The less significant parts of both time and date may also -be omitted, in which case zero is assumed. For example, the following -are all valid: - -The following are all valid time and date specifications: - -=over 8 - -=item now - -The current time and date. - -=item tomorrow - -Exactly one day from now. - -=item yesterday - -24 hours ago. - -=item 2 hours ago - -2 hours ago. - -=item next Friday - -The first second of the next Friday. - -=item this week - -The current time but the first day of the coming week. - -=item a fortnight ago - -The current time but 14 days ago. - -=item 10:01 am 9/17/2009 - -10:01 am, September 17, 2009. - -=item 10:01 am - -10:01 am on the current day. - -=item 10 - -10:00 am on the current day. - -=item 9/17/2009 - -00:00 am, September 17, 2009. - -=item 10:01 am Sep 17, 2009 - -10:01 am, September 17, 2009. - -=back - -=head1 FILES - -=over 24 - -=item F - -The default I/O log directory. - -=item F - -Example session log info. - -=item F - -Example session standard input log. - -=item F - -Example session standard output log. - -=item F - -Example session standard error log. - -=item F - -Example session tty input file. - -=item F - -Example session tty output file. - -=item F - -Example session timing file. - -=back - -Note that the I, I and I files will be empty -unless B was used as part of a pipeline for a particular -command. - -=head1 EXAMPLES - -List sessions run by user I: - - sudoreplay -l user millert - -List sessions run by user I with a command containing the string vi: - - sudoreplay -l user bob command vi - -List sessions run by user I that match a regular expression: - - sudoreplay -l user jeff command '/bin/[a-z]*sh' - -List sessions run by jeff or bob on the console: - - sudoreplay -l ( user jeff or user bob ) tty console - -=head1 SEE ALSO - -L, L - -=head1 AUTHOR - -Todd C. Miller - -=head1 BUGS - -If you feel you have found a bug in B, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ - -=head1 SUPPORT - -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or -search the archives. - -=head1 DISCLAIMER - -B is provided ``AS IS'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the LICENSE -file distributed with B or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/term.c b/term.c deleted file mode 100644 index a3cad61..0000000 --- a/term.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2009-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. - */ - -#include - -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_TERMIOS_H -# include -#else -# ifdef HAVE_TERMIO_H -# include -# else -# include -# include -# endif /* HAVE_TERMIO_H */ -#endif /* HAVE_TERMIOS_H */ - -#include "sudo.h" - -#ifndef TCSASOFT -# define TCSASOFT 0 -#endif -#ifndef ECHONL -# define ECHONL 0 -#endif -#ifndef IEXTEN -# define IEXTEN 0 -#endif -#ifndef IUCLC -# define IUCLC 0 -#endif - -#ifndef _POSIX_VDISABLE -# ifdef VDISABLE -# define _POSIX_VDISABLE VDISABLE -# else -# define _POSIX_VDISABLE 0 -# endif -#endif - -/* - * Compat macros for non-termios systems. - */ -#ifndef HAVE_TERMIOS_H -# ifdef HAVE_TERMIO_H -# undef termios -# define termios termio -# define tcgetattr(f, t) ioctl(f, TCGETA, t) -# define tcsetattr(f, a, t) ioctl(f, a, t) -# undef TCSAFLUSH -# define TCSAFLUSH TCSETAF -# undef TCSADRAIN -# define TCSADRAIN TCSETAW -# else /* SGTTY */ -# undef termios -# define termios sgttyb -# define c_lflag sg_flags -# define tcgetattr(f, t) ioctl(f, TIOCGETP, t) -# define tcsetattr(f, a, t) ioctl(f, a, t) -# undef TCSAFLUSH -# define TCSAFLUSH TIOCSETP -# undef TCSADRAIN -# define TCSADRAIN TIOCSETN -# endif /* HAVE_TERMIO_H */ -#endif /* HAVE_TERMIOS_H */ - -typedef struct termios sudo_term_t; - -static sudo_term_t term, oterm; -static int changed; -int term_erase; -int term_kill; - -int -term_restore(fd, flush) - int fd; - int flush; -{ - if (changed) { - int flags = TCSASOFT; - flags |= flush ? TCSAFLUSH : TCSADRAIN; - if (tcsetattr(fd, flags, &oterm) != 0) - return(0); - changed = 0; - } - return(1); -} - -int -term_noecho(fd) - int fd; -{ - if (!changed && tcgetattr(fd, &oterm) != 0) - return(0); - (void) memcpy(&term, &oterm, sizeof(term)); - CLR(term.c_lflag, ECHO|ECHONL); -#ifdef VSTATUS - term.c_cc[VSTATUS] = _POSIX_VDISABLE; -#endif - if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { - changed = 1; - return(1); - } - return(0); -} - -#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H) - -int -term_raw(fd, isig) - int fd; - int isig; -{ - struct termios term; - - if (!changed && tcgetattr(fd, &oterm) != 0) - return(0); - (void) memcpy(&term, &oterm, sizeof(term)); - /* Set terminal to raw mode */ - term.c_cc[VMIN] = 1; - term.c_cc[VTIME] = 0; - CLR(term.c_lflag, ECHO | ECHONL | ICANON | ISIG | IEXTEN); - if (isig) - SET(term.c_lflag, ISIG); - CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON); - if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { - changed = 1; - return(1); - } - return(0); -} - -int -term_cbreak(fd) - int fd; -{ - if (!changed && tcgetattr(fd, &oterm) != 0) - return(0); - (void) memcpy(&term, &oterm, sizeof(term)); - /* Set terminal to half-cooked mode */ - term.c_cc[VMIN] = 1; - term.c_cc[VTIME] = 0; - CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN); - SET(term.c_lflag, ISIG); -#ifdef VSTATUS - term.c_cc[VSTATUS] = _POSIX_VDISABLE; -#endif - if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { - term_erase = term.c_cc[VERASE]; - term_kill = term.c_cc[VKILL]; - changed = 1; - return(1); - } - return(0); -} - -int -term_copy(src, dst) - int src; - int dst; -{ - struct termios tt; - - if (tcgetattr(src, &tt) != 0) - return(0); - /* XXX - add TCSANOW compat define */ - if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0) - return(0); - return(1); -} - -#else /* SGTTY */ - -int -term_raw(fd, isig) - int fd; - int isig; -{ - if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0) - return(0); - (void) memcpy(&term, &oterm, sizeof(term)); - /* Set terminal to raw mode */ - /* XXX - how to support isig? */ - CLR(term.c_lflag, ECHO); - SET(term.sg_flags, RAW); - if (ioctl(fd, TIOCSETP, &term) == 0) { - changed = 1; - return(1); - } - return(0); -} - -int -term_cbreak(fd) - int fd; -{ - if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0) - return(0); - (void) memcpy(&term, &oterm, sizeof(term)); - /* Set terminal to half-cooked mode */ - CLR(term.c_lflag, ECHO); - SET(term.sg_flags, CBREAK); - if (ioctl(fd, TIOCSETP, &term) == 0) { - term_erase = term.sg_erase; - term_kill = term.sg_kill; - changed = 1; - return(1); - } - return(0); -} - -int -term_copy(src, dst) - int src; - int dst; -{ - struct sgttyb b; - struct tchars tc; - struct ltchars lc; - int l, lb; - - if (ioctl(src, TIOCGETP, &b) != 0 || ioctl(src, TIOCGETC, &tc) != 0 || - ioctl(src, TIOCGETD, &l) != 0 || ioctl(src, TIOCGLTC, &lc) != 0 || - ioctl(src, TIOCLGET, &lb)) { - return(0); - } - if (ioctl(dst, TIOCSETP, &b) != 0 || ioctl(dst, TIOCSETC, &tc) != 0 || - ioctl(dst, TIOCSLTC, &lc) != 0 || ioctl(dst, TIOCLSET, &lb) != 0 || - ioctl(dst, TIOCSETD, &l) != 0) { - return(0); - } - return(1); -} - -#endif diff --git a/testsudoers.c b/testsudoers.c deleted file mode 100644 index 1bf2cd3..0000000 --- a/testsudoers.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Sponsored in part by the Defense Advanced Research Projects - * Agency (DARPA) and Air Force Research Laboratory, Air Force - * Materiel Command, USAF, under agreement number F39502-99-1-0512. - */ - -#define _SUDO_MAIN - -#include - -#include -#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 */ -#ifdef HAVE_FNMATCH -# include -#endif /* HAVE_FNMATCH */ -#ifdef HAVE_NETGROUP_H -# include -#endif /* HAVE_NETGROUP_H */ -#include -#include -#include -#include -#include -#include - -#include "sudo.h" -#include "interfaces.h" -#include "parse.h" -#include - -#ifndef HAVE_FNMATCH -# include "emul/fnmatch.h" -#endif /* HAVE_FNMATCH */ - -/* - * Globals - */ -int Argc, NewArgc; -char **Argv, **NewArgv; -int num_interfaces; -struct interface *interfaces; -struct sudo_user sudo_user; -struct passwd *list_pw; -extern int parse_error; - -/* For getopt(3) */ -extern char *optarg; -extern int optind; - -#if defined(SUDO_DEVEL) && defined(__OpenBSD__) -extern char *malloc_options; -#endif -#ifdef YYDEBUG -extern int yydebug; -#endif - -int print_alias __P((void *, void *)); -void dump_sudoers __P((void)); -void print_defaults __P((void)); -void print_privilege __P((struct privilege *)); -void print_userspecs __P((void)); -void usage __P((void)) __attribute__((__noreturn__)); -void set_runasgr __P((char *)); -void set_runaspw __P((char *)); - -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; - char **argv; -{ - struct cmndspec *cs; - struct privilege *priv; - struct userspec *us; - char *p, *grfile, *pwfile, *runas_group, *runas_user; - char hbuf[MAXHOSTNAMELEN + 1]; - int ch, dflag, rval, matched; - -#if defined(SUDO_DEVEL) && defined(__OpenBSD__) - malloc_options = "AFGJPR"; -#endif -#ifdef YYDEBUG - yydebug = 1; -#endif - - Argv = argv; - Argc = argc; - - dflag = 0; - grfile = pwfile = runas_group = runas_user = NULL; - while ((ch = getopt(argc, argv, "dg:G:h:p:u:")) != -1) { - switch (ch) { - case 'd': - dflag = 1; - break; - case 'h': - user_host = optarg; - break; - case 'G': - grfile = optarg; - break; - case 'g': - runas_group = optarg; - break; - case 'p': - pwfile = optarg; - break; - case 'u': - runas_user = optarg; - break; - default: - usage(); - break; - } - } - argc -= optind; - argv += optind; - NewArgc = argc; - NewArgv = argv; - - /* Set group/passwd file and init the cache. */ - if (grfile) - setgrfile(grfile); - if (pwfile) - setpwfile(pwfile); - sudo_setpwent(); - sudo_setgrent(); - - if (argc < 2) { - if (!dflag) - usage(); - if ((sudo_user.pw = sudo_getpwnam("nobody")) == NULL) - errorx(1, "no passwd entry for nobody!"); - user_cmnd = user_base = "true"; - } else { - if ((sudo_user.pw = sudo_getpwnam(*argv)) == NULL) - errorx(1, "no passwd entry for %s!", *argv); - user_cmnd = *++argv; - if ((p = strrchr(user_cmnd, '/')) != NULL) - user_base = p + 1; - else - user_base = user_cmnd; - NewArgc -= 2; - } - - if (user_host == NULL) { - if (gethostname(hbuf, sizeof(hbuf)) != 0) - error(1, "gethostname"); - hbuf[sizeof(hbuf) - 1] = '\0'; - user_host = hbuf; - } - if ((p = strchr(user_host, '.'))) { - *p = '\0'; - user_shost = estrdup(user_host); - *p = '.'; - } else { - user_shost = user_host; - } - - /* Fill in user_args from NewArgv. */ - if (NewArgc > 1) { - char *to, **from; - size_t size, n; - - for (size = 0, from = NewArgv + 1; *from; from++) - size += strlen(*from) + 1; - - user_args = (char *) emalloc(size); - for (to = user_args, from = NewArgv + 1; *from; from++) { - n = strlcpy(to, *from, size - (to - user_args)); - if (n >= size - (to - user_args)) - errorx(1, "internal error, init_vars() overflow"); - to += n; - *to++ = ' '; - } - *--to = '\0'; - } - - /* Initialize default values. */ - init_defaults(); - - /* Load ip addr/mask for each interface. */ - load_interfaces(); - - /* Allocate space for data structures in the parser. */ - init_parser("sudoers", 0); - - if (yyparse() != 0 || parse_error) - (void) fputs("Does not parse", stdout); - else - (void) fputs("Parses OK", stdout); - - if (!update_defaults(SETDEF_ALL)) - (void) fputs(" (problem with defaults entries)", stdout); - puts("."); - - /* - * Set runas passwd/group entries based on command line or sudoers. - * Note that if runas_group was specified without runas_user we - * defer setting runas_pw so the match routines know to ignore it. - */ - if (runas_group != NULL) { - set_runasgr(runas_group); - if (runas_user != NULL) - set_runaspw(runas_user); - } else - set_runaspw(runas_user ? runas_user : def_runas_default); - - if (dflag) { - (void) putchar('\n'); - dump_sudoers(); - if (argc < 2) - exit(0); - } - - /* This loop must match the one in sudoers_lookup() */ - printf("\nEntries for user %s:\n", user_name); - matched = UNSPEC; - tq_foreach_rev(&userspecs, us) { - if (userlist_matches(sudo_user.pw, &us->users) != ALLOW) - continue; - tq_foreach_rev(&us->privileges, priv) { - putchar('\n'); - print_privilege(priv); /* XXX */ - putchar('\n'); - if (hostlist_matches(&priv->hostlist) == ALLOW) { - puts("\thost matched"); - tq_foreach_rev(&priv->cmndlist, cs) { - if (runaslist_matches(&cs->runasuserlist, - &cs->runasgrouplist) == ALLOW) { - puts("\trunas matched"); - rval = cmnd_matches(cs->cmnd); - if (rval != UNSPEC) - matched = rval; - printf("\tcmnd %s\n", rval == ALLOW ? "allowed" : - rval == DENY ? "denied" : "unmatched"); - } - } - } else - puts("\thost unmatched"); - } - } - printf("\nCommand %s\n", matched == ALLOW ? "allowed" : - matched == DENY ? "denied" : "unmatched"); - - exit(0); -} - -void -set_runaspw(user) - char *user; -{ - if (*user == '#') { - if ((runas_pw = sudo_getpwuid(atoi(user + 1))) == NULL) - runas_pw = sudo_fakepwnam(user, runas_gr ? runas_gr->gr_gid : 0); - } else { - if ((runas_pw = sudo_getpwnam(user)) == NULL) - errorx(1, "unknown user: %s", user); - } -} - -void -set_runasgr(group) - char *group; -{ - if (*group == '#') { - if ((runas_gr = sudo_getgrgid(atoi(group + 1))) == NULL) - runas_gr = sudo_fakegrnam(group); - } else { - if ((runas_gr = sudo_getgrnam(group)) == NULL) - errorx(1, "unknown group: %s", group); - } -} - -void -sudo_setspent() -{ - return; -} - -void -sudo_endspent() -{ - return; -} - -char * -sudo_getepw(pw) - const struct passwd *pw; -{ - return (pw->pw_passwd); -} - -void -set_fqdn() -{ - return; -} - -FILE * -open_sudoers(path, isdir, keepopen) - const char *path; - int isdir; - int *keepopen; -{ - return(fopen(path, "r")); -} - -void -init_envtables() -{ - return; -} - -int -set_perms(perm) - int perm; -{ - return(1); -} - -void -cleanup(gotsignal) - int gotsignal; -{ - if (!gotsignal) { - sudo_endpwent(); - sudo_endgrent(); - } -} - -void -print_member(m) - struct member *m; -{ - struct sudo_command *c; - - if (m->negated) - putchar('!'); - if (m->name == NULL) - fputs("ALL", stdout); - else if (m->type != COMMAND) - fputs(m->name, stdout); - else { - c = (struct sudo_command *) m->name; - printf("%s%s%s", c->cmnd, c->args ? " " : "", - c->args ? c->args : ""); - } -} - -void -print_defaults() -{ - struct defaults *d; - struct member *m; - - tq_foreach_fwd(&defaults, d) { - (void) fputs("Defaults", stdout); - switch (d->type) { - case DEFAULTS_HOST: - putchar('@'); - break; - case DEFAULTS_USER: - putchar(':'); - break; - case DEFAULTS_RUNAS: - putchar('>'); - break; - case DEFAULTS_CMND: - putchar('!'); - break; - } - tq_foreach_fwd(&d->binding, m) { - if (m != tq_first(&d->binding)) - putchar(','); - print_member(m); - } - printf("\t%s%s", d->op == FALSE ? "!" : "", d->var); - if (d->val != NULL) { - printf("%c%s", d->op == TRUE ? '=' : d->op, d->val); - } - putchar('\n'); - } -} - -int -print_alias(v1, v2) - void *v1, *v2; -{ - struct alias *a = (struct alias *)v1; - struct member *m; - struct sudo_command *c; - - switch (a->type) { - case HOSTALIAS: - (void) printf("Host_Alias\t%s = ", a->name); - break; - case CMNDALIAS: - (void) printf("Cmnd_Alias\t%s = ", a->name); - break; - case USERALIAS: - (void) printf("User_Alias\t%s = ", a->name); - break; - case RUNASALIAS: - (void) printf("Runas_Alias\t%s = ", a->name); - break; - } - tq_foreach_fwd(&a->members, m) { - if (m != tq_first(&a->members)) - fputs(", ", stdout); - if (m->type == COMMAND) { - c = (struct sudo_command *) m->name; - printf("%s%s%s", c->cmnd, c->args ? " " : "", - c->args ? c->args : ""); - } else - fputs(m->name, stdout); - } - putchar('\n'); - return(0); -} - -void -print_privilege(priv) - struct privilege *priv; -{ - struct cmndspec *cs; - struct member *m; - struct privilege *p; - struct cmndtag tags; - - for (p = priv; p != NULL; p = p->next) { - if (p != priv) - fputs(" : ", stdout); - tq_foreach_fwd(&p->hostlist, m) { - if (m != tq_first(&p->hostlist)) - fputs(", ", stdout); - print_member(m); - } - fputs(" = ", stdout); - tags.nopasswd = tags.noexec = UNSPEC; - tq_foreach_fwd(&p->cmndlist, cs) { - if (cs != tq_first(&p->cmndlist)) - fputs(", ", stdout); - /* XXX - runasgrouplist too */ - if (!tq_empty(&cs->runasuserlist)) { - fputs("(", stdout); - tq_foreach_fwd(&cs->runasuserlist, m) { - if (m != tq_first(&cs->runasuserlist)) - fputs(", ", stdout); - print_member(m); - } - fputs(") ", stdout); - } -#ifdef HAVE_SELINUX - if (cs->role) - printf("ROLE=%s ", cs->role); - if (cs->type) - printf("TYPE=%s ", cs->type); -#endif /* HAVE_SELINUX */ - if (cs->tags.nopasswd != UNSPEC && cs->tags.nopasswd != tags.nopasswd) - printf("%sPASSWD: ", cs->tags.nopasswd ? "NO" : ""); - if (cs->tags.noexec != UNSPEC && cs->tags.noexec != tags.noexec) - printf("%sEXEC: ", cs->tags.noexec ? "NO" : ""); - print_member(cs->cmnd); - memcpy(&tags, &cs->tags, sizeof(tags)); - } - } -} - -void -print_userspecs() -{ - struct member *m; - struct userspec *us; - - tq_foreach_fwd(&userspecs, us) { - tq_foreach_fwd(&us->users, m) { - if (m != tq_first(&us->users)) - fputs(", ", stdout); - print_member(m); - } - putchar('\t'); - print_privilege(us->privileges.first); /* XXX */ - putchar('\n'); - } -} - -void -dump_sudoers() -{ - print_defaults(); - - putchar('\n'); - alias_apply(print_alias, NULL); - - putchar('\n'); - print_userspecs(); -} - -void -usage() -{ - (void) fprintf(stderr, "usage: %s [-d] [-G grfile] [-g group] [-h host] [-p pwfile] [-u user] [args]\n", getprogname()); - exit(1); -} diff --git a/tgetpass.c b/tgetpass.c deleted file mode 100644 index 8127eab..0000000 --- a/tgetpass.c +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - */ - -#ifdef __TANDEM -# include -#endif - -#include - -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#ifdef HAVE_UNISTD_H -# include -#endif /* HAVE_UNISTD_H */ -#include -#include -#include -#include - -#include "sudo.h" - -static volatile sig_atomic_t signo[NSIG]; - -static void handler __P((int)); -static char *getln __P((int, char *, size_t, int)); -static char *sudo_askpass __P((const char *)); - -/* - * Like getpass(3) but with timeout and echo flags. - */ -char * -tgetpass(prompt, timeout, flags) - const char *prompt; - int timeout; - int flags; -{ - sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm; - sigaction_t savetstp, savettin, savettou, savepipe; - char *pass; - static char buf[SUDO_PASS_MAX + 1]; - int i, input, output, save_errno, neednl = 0, need_restart; - - (void) fflush(stdout); - - /* If using a helper program to get the password, run it instead. */ - if (ISSET(flags, TGP_ASKPASS) && user_askpass) - return(sudo_askpass(prompt)); - -restart: - for (i = 0; i < NSIG; i++) - signo[i] = 0; - pass = NULL; - save_errno = 0; - need_restart = 0; - /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */ - if (ISSET(flags, TGP_STDIN) || - (input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) { - input = STDIN_FILENO; - output = STDERR_FILENO; - } - - /* - * If we are using a tty but are not the foreground pgrp this will - * generate SIGTTOU, so do it *before* installing the signal handlers. - */ - if (!ISSET(flags, TGP_ECHO)) { - if (def_pwfeedback) - neednl = term_cbreak(input); - else - neednl = term_noecho(input); - } - - /* - * Catch signals that would otherwise cause the user to end - * up with echo turned off in the shell. - */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_INTERRUPT; /* don't restart system calls */ - sa.sa_handler = handler; - (void) sigaction(SIGALRM, &sa, &savealrm); - (void) sigaction(SIGINT, &sa, &saveint); - (void) sigaction(SIGHUP, &sa, &savehup); - (void) sigaction(SIGQUIT, &sa, &savequit); - (void) sigaction(SIGTERM, &sa, &saveterm); - (void) sigaction(SIGTSTP, &sa, &savetstp); - (void) sigaction(SIGTTIN, &sa, &savettin); - (void) sigaction(SIGTTOU, &sa, &savettou); - - /* Ignore SIGPIPE in case stdin is a pipe and TGP_STDIN is set */ - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, &savepipe); - - if (prompt) - (void) write(output, prompt, strlen(prompt)); - - if (timeout > 0) - alarm(timeout); - pass = getln(input, buf, sizeof(buf), def_pwfeedback); - alarm(0); - save_errno = errno; - - if (neednl || pass == NULL) - (void) write(output, "\n", 1); - - /* Restore old tty settings and signals. */ - if (!ISSET(flags, TGP_ECHO)) - term_restore(input, 1); - (void) sigaction(SIGALRM, &savealrm, NULL); - (void) sigaction(SIGINT, &saveint, NULL); - (void) sigaction(SIGHUP, &savehup, NULL); - (void) sigaction(SIGQUIT, &savequit, NULL); - (void) sigaction(SIGTERM, &saveterm, NULL); - (void) sigaction(SIGTSTP, &savetstp, NULL); - (void) sigaction(SIGTTIN, &savettin, NULL); - (void) sigaction(SIGTTOU, &savettou, NULL); - (void) sigaction(SIGTTOU, &savepipe, NULL); - if (input != STDIN_FILENO) - (void) close(input); - - /* - * If we were interrupted by a signal, resend it to ourselves - * now that we have restored the signal handlers. - */ - for (i = 0; i < NSIG; i++) { - if (signo[i]) { - kill(getpid(), i); - switch (i) { - case SIGTSTP: - case SIGTTIN: - case SIGTTOU: - need_restart = 1; - break; - } - } - } - if (need_restart) - goto restart; - - if (save_errno) - errno = save_errno; - return(pass); -} - -/* - * Fork a child and exec sudo-askpass to get the password from the user. - */ -static char * -sudo_askpass(prompt) - const char *prompt; -{ - static char buf[SUDO_PASS_MAX + 1], *pass; - sigaction_t sa, saved_sa_pipe; - int pfd[2]; - pid_t pid; - - if (pipe(pfd) == -1) - error(1, "unable to create pipe"); - - if ((pid = fork()) == -1) - error(1, "unable to fork"); - - if (pid == 0) { - /* child, point stdout to output side of the pipe and exec askpass */ - if (dup2(pfd[1], STDOUT_FILENO) == -1) { - warning("dup2"); - _exit(255); - } - (void) dup2(pfd[1], STDOUT_FILENO); - set_perms(PERM_FULL_USER); - closefrom(STDERR_FILENO + 1); - execl(user_askpass, user_askpass, prompt, (char *)NULL); - warning("unable to run %s", user_askpass); - _exit(255); - } - - /* Ignore SIGPIPE in case child exits prematurely */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_INTERRUPT; - sa.sa_handler = SIG_IGN; - (void) sigaction(SIGPIPE, &sa, &saved_sa_pipe); - - /* Get response from child (askpass) and restore SIGPIPE handler */ - (void) close(pfd[1]); - pass = getln(pfd[0], buf, sizeof(buf), 0); - (void) close(pfd[0]); - (void) sigaction(SIGPIPE, &saved_sa_pipe, NULL); - - return(pass); -} - -extern int term_erase, term_kill; - -static char * -getln(fd, buf, bufsiz, feedback) - int fd; - char *buf; - size_t bufsiz; - int feedback; -{ - size_t left = bufsiz; - ssize_t nr = -1; - char *cp = buf; - char c = '\0'; - - if (left == 0) { - errno = EINVAL; - return(NULL); /* sanity */ - } - - while (--left) { - nr = read(fd, &c, 1); - if (nr != 1 || c == '\n' || c == '\r') - break; - if (feedback) { - if (c == term_kill) { - while (cp > buf) { - (void) write(fd, "\b \b", 3); - --cp; - } - left = bufsiz; - continue; - } else if (c == term_erase) { - if (cp > buf) { - (void) write(fd, "\b \b", 3); - --cp; - left++; - } - continue; - } - (void) write(fd, "*", 1); - } - *cp++ = c; - } - *cp = '\0'; - if (feedback) { - /* erase stars */ - while (cp > buf) { - (void) write(fd, "\b \b", 3); - --cp; - } - } - - return(nr == 1 ? buf : NULL); -} - -static void -handler(s) - int s; -{ - if (s != SIGALRM) - signo[s] = 1; -} - -int -tty_present() -{ - int fd; - - if ((fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) != -1) - close(fd); - return(fd != -1); -} diff --git a/timestr.c b/timestr.c deleted file mode 100644 index 3b2a18d..0000000 --- a/timestr.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 1999, 2009 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. - */ - -#include - -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif /* STDC_HEADERS */ -#include - -#include "compat.h" - -char *get_timestr __P((time_t, int)); - -/* - * Return an ascii string with the current date + time - * Uses strftime() if available, else falls back to ctime(). - */ -char * -get_timestr(tstamp, log_year) - time_t tstamp; - int log_year; -{ - char *s; -#ifdef HAVE_STRFTIME - static char buf[128]; - struct tm *timeptr; - - timeptr = localtime(&tstamp); - if (log_year) - s = "%h %e %T %Y"; - else - s = "%h %e %T"; - - /* strftime() does not guarantee to NUL-terminate so we must check. */ - buf[sizeof(buf) - 1] = '\0'; - if (strftime(buf, sizeof(buf), s, timeptr) && buf[sizeof(buf) - 1] == '\0') - return(buf); - -#endif /* HAVE_STRFTIME */ - - s = ctime(&tstamp) + 4; /* skip day of the week */ - if (log_year) - s[20] = '\0'; /* avoid the newline */ - else - s[15] = '\0'; /* don't care about year */ - - return(s); -} diff --git a/toke.c b/toke.c deleted file mode 100644 index e8b9243..0000000 --- a/toke.c +++ /dev/null @@ -1,3658 +0,0 @@ -/* $OpenBSD: flex.skl,v 1.10 2007/01/26 14:38:19 tsi Exp $ */ - -/* A lexical scanner generated by flex */ - -/* Scanner skeleton version: - * $Header: /home/cvs/openbsd/src/usr.bin/lex/flex.skl,v 1.10 2007/01/26 14:38:19 tsi Exp $ - */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 - -#include -#include - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include -#include - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#ifdef __STDC__ - -#define YY_USE_PROTOS -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include -#include -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#define YY_BUF_SIZE 16384 - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -extern int yyleng; -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yytext_ptr ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; - - -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - }; - -static YY_BUFFER_STATE yy_current_buffer = 0; - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - */ -#define YY_CURRENT_BUFFER yy_current_buffer - - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; - -static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) - - -#define yywrap() 1 -#define YY_SKIP_YYWRAP -typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; -typedef int yy_state_type; -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 50 -#define YY_END_OF_BUFFER 51 -static yyconst short int yy_accept[555] = - { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 51, 38, 46, 45, 44, 38, 49, 38, - 39, 40, 38, 41, 38, 38, 38, 38, 43, 42, - 49, 33, 33, 33, 33, 33, 33, 49, 38, 38, - 46, 49, 33, 33, 33, 33, 33, 1, 49, 38, - 38, 16, 15, 16, 15, 15, 49, 49, 49, 2, - 8, 7, 8, 3, 8, 4, 49, 12, 12, 12, - 10, 11, 38, 0, 46, 44, 38, 0, 0, 0, - 48, 0, 38, 28, 0, 0, 27, 0, 36, 36, - 0, 38, 38, 0, 38, 38, 38, 38, 0, 31, - - 33, 33, 33, 33, 33, 33, 38, 47, 38, 46, - 0, 0, 0, 0, 0, 0, 38, 38, 38, 38, - 38, 1, 0, 34, 34, 0, 38, 16, 16, 14, - 13, 14, 0, 0, 2, 8, 0, 5, 6, 8, - 8, 12, 0, 12, 12, 0, 9, 37, 37, 0, - 0, 28, 0, 0, 38, 38, 38, 38, 38, 0, - 0, 31, 31, 33, 33, 33, 33, 33, 33, 33, - 38, 0, 0, 0, 0, 0, 0, 38, 38, 38, - 38, 38, 0, 38, 9, 0, 38, 38, 38, 38, - 38, 38, 0, 32, 32, 32, 0, 0, 31, 31, - - 31, 31, 31, 31, 31, 33, 33, 33, 33, 33, - 33, 33, 38, 0, 0, 0, 0, 0, 0, 38, - 38, 38, 38, 38, 38, 38, 0, 0, 32, 32, - 32, 0, 31, 31, 0, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 0, 24, 33, 33, - 33, 33, 33, 38, 0, 0, 0, 0, 38, 38, - 38, 38, 38, 38, 38, 38, 0, 32, 0, 31, - 31, 31, 0, 0, 0, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 33, 33, - 33, 33, 33, 38, 0, 0, 0, 38, 38, 38, - - 29, 29, 29, 0, 0, 31, 31, 31, 31, 31, - 31, 31, 0, 0, 0, 0, 0, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 0, 23, 33, 33, 0, 22, 0, 25, 38, - 0, 0, 0, 38, 38, 38, 38, 29, 29, 29, - 29, 0, 31, 0, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 0, 0, 0, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 33, 33, 35, 0, 0, 0, 38, 19, 34, - 38, 30, 30, 30, 31, 0, 0, 0, 31, 31, - - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 0, 0, 0, 0, 0, 31, 31, 31, 31, - 31, 31, 31, 31, 0, 21, 0, 26, 0, 19, - 0, 0, 38, 0, 38, 38, 38, 30, 30, 30, - 30, 30, 0, 0, 0, 0, 0, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 0, 0, 0, - 20, 19, 0, 0, 19, 0, 38, 38, 38, 30, - 30, 0, 0, 0, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - - 31, 31, 20, 0, 17, 0, 38, 38, 38, 38, - 38, 0, 0, 0, 0, 0, 31, 31, 31, 31, - 31, 31, 31, 31, 0, 38, 38, 38, 31, 31, - 31, 31, 31, 31, 0, 38, 38, 38, 38, 38, - 31, 31, 31, 31, 31, 0, 18, 29, 29, 29, - 29, 29, 29, 0 - } ; - -static yyconst int yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 4, 5, 6, 1, 7, 1, 1, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 22, 22, 23, 24, 1, 1, - 25, 26, 10, 27, 28, 29, 30, 31, 32, 29, - 33, 34, 33, 33, 33, 33, 33, 35, 36, 37, - 33, 38, 39, 40, 41, 42, 43, 44, 33, 33, - 10, 45, 10, 1, 46, 1, 47, 48, 49, 50, - - 51, 52, 53, 53, 54, 53, 53, 55, 56, 57, - 58, 53, 53, 59, 60, 61, 62, 53, 53, 53, - 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst int yy_meta[63] = - { 0, - 1, 2, 3, 4, 5, 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, 12, 13, 14, 14, 14, 14, - 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13 - } ; - -static yyconst short int yy_base[621] = - { 0, - 0, 61, 62, 63, 69, 84, 128, 189, 250, 294, - 80, 101, 2394, 2348, 2390, 3541, 2387, 338, 381, 52, - 3541, 3541, 2345, 3541, 107, 391, 119, 137, 2351, 3541, - 3541, 443, 2330, 490, 2337, 2335, 2320, 541, 145, 55, - 167, 565, 2293, 2297, 2289, 2258, 2257, 2314, 193, 256, - 56, 0, 3541, 2311, 3541, 0, 264, 617, 77, 0, - 2261, 3541, 82, 3541, 99, 3541, 110, 2243, 126, 106, - 3541, 145, 2240, 306, 2282, 2279, 639, 2277, 2276, 2263, - 3541, 201, 209, 74, 2211, 347, 2208, 550, 276, 2199, - 587, 410, 669, 2210, 2210, 306, 358, 317, 2163, 179, - - 706, 0, 2154, 240, 2111, 2109, 389, 3541, 76, 355, - 2082, 2076, 2066, 2061, 2062, 63, 115, 219, 29, 212, - 98, 2116, 507, 361, 2071, 598, 154, 0, 2111, 256, - 3541, 3541, 636, 284, 0, 2069, 567, 3541, 3541, 2066, - 532, 2050, 2087, 271, 300, 288, 2089, 2038, 3541, 2057, - 2055, 1986, 669, 603, 745, 777, 809, 841, 2014, 2003, - 878, 268, 916, 953, 1996, 1980, 1971, 1945, 1911, 1915, - 236, 1862, 1866, 1856, 1843, 1848, 317, 157, 1851, 307, - 266, 258, 777, 296, 1880, 1877, 686, 402, 992, 1024, - 725, 337, 1839, 1838, 787, 499, 1782, 1781, 343, 755, - - 1056, 796, 694, 1094, 819, 1745, 393, 1736, 1728, 1711, - 1707, 1697, 373, 1681, 1666, 1651, 1664, 1623, 543, 400, - 556, 233, 506, 1133, 1165, 1197, 1657, 1655, 827, 1640, - 1638, 1637, 1621, 540, 858, 546, 895, 602, 1229, 0, - 935, 1240, 970, 731, 1278, 1002, 601, 3541, 1614, 1604, - 1610, 1595, 1583, 486, 1565, 1548, 1548, 387, 343, 380, - 616, 1010, 423, 1317, 1349, 1044, 1555, 1554, 1553, 1506, - 1379, 645, 1076, 1113, 1143, 652, 983, 1035, 1151, 1042, - 1418, 0, 1175, 1429, 1184, 866, 1467, 1207, 644, 1451, - 1458, 648, 672, 625, 1447, 1419, 680, 576, 487, 715, - - 1505, 1536, 1567, 1449, 1447, 1432, 1215, 1599, 1257, 903, - 1636, 1297, 1325, 1441, 1335, 1359, 1369, 841, 1024, 1067, - 1124, 1396, 1308, 1675, 0, 1448, 1686, 1484, 1265, 1724, - 1515, 955, 3541, 1423, 1364, 956, 3541, 975, 3541, 807, - 1350, 1300, 591, 1074, 569, 917, 1523, 155, 1762, 1793, - 1546, 1336, 1300, 1553, 768, 1576, 810, 1825, 0, 429, - 1836, 1584, 1404, 1873, 1618, 1655, 1705, 1743, 1288, 1335, - 1734, 1772, 1772, 1803, 1912, 0, 1805, 1923, 1781, 1492, - 1814, 993, 1156, 1276, 1251, 1244, 730, 635, 1952, 1222, - 1984, 2016, 2048, 2080, 1242, 1855, 1892, 1943, 1241, 1184, - - 1198, 1964, 1350, 2112, 0, 762, 2123, 1972, 1992, 2160, - 2000, 2024, 1227, 2034, 2058, 2068, 1369, 1609, 1934, 772, - 806, 2199, 0, 844, 1173, 3541, 1468, 3541, 1192, 2086, - 1389, 142, 991, 604, 736, 2140, 1038, 2209, 2241, 2273, - 2305, 2103, 2177, 1163, 2219, 2229, 2251, 1152, 1116, 1656, - 1706, 2257, 1837, 2337, 0, 881, 2348, 2281, 2088, 2385, - 2291, 2314, 2323, 2366, 1855, 1122, 927, 1042, 1031, 902, - 951, 990, 1725, 2416, 1836, 2437, 2450, 2482, 2514, 2434, - 1951, 2464, 2492, 2502, 936, 919, 1893, 2001, 2522, 2035, - 2546, 0, 1031, 2557, 2530, 2148, 2576, 838, 2595, 2604, - - 2473, 773, 3541, 659, 3541, 1065, 2612, 1195, 2644, 2676, - 2623, 2629, 618, 2655, 2665, 2686, 573, 566, 2049, 557, - 549, 2694, 0, 1078, 1545, 2708, 2740, 2772, 2716, 2724, - 2748, 509, 0, 455, 357, 2756, 1535, 2804, 2836, 2786, - 3541, 2792, 2816, 2185, 3541, 345, 3541, 2824, 2844, 2854, - 25, 2874, 2866, 3541, 2919, 2933, 2947, 2961, 2975, 2989, - 3003, 3017, 3031, 3045, 3051, 3065, 3079, 1107, 3093, 3107, - 3121, 3135, 3149, 3163, 3177, 3191, 3197, 3204, 3218, 3232, - 3238, 3245, 3251, 3257, 3263, 3270, 3276, 3282, 3288, 3295, - 3303, 3309, 3315, 3321, 3328, 3336, 3342, 3348, 3355, 3363, - - 3369, 3377, 3384, 3392, 3398, 3406, 3413, 3421, 3435, 3449, - 3455, 3463, 3470, 3484, 3490, 3498, 3504, 3512, 1600, 3526 - } ; - -static yyconst short int yy_def[621] = - { 0, - 554, 1, 1, 1, 555, 555, 556, 556, 557, 557, - 558, 558, 554, 559, 554, 554, 554, 560, 561, 562, - 554, 554, 563, 554, 564, 559, 26, 26, 565, 554, - 554, 554, 32, 32, 34, 34, 34, 559, 26, 559, - 554, 561, 32, 32, 34, 34, 34, 554, 554, 566, - 559, 567, 554, 567, 554, 567, 554, 561, 554, 568, - 569, 554, 569, 554, 569, 554, 570, 571, 571, 571, - 554, 554, 559, 559, 554, 554, 560, 572, 560, 573, - 554, 574, 554, 562, 575, 562, 563, 563, 564, 576, - 559, 559, 26, 565, 93, 93, 93, 93, 577, 578, - - 32, 34, 34, 34, 34, 34, 559, 554, 559, 554, - 554, 554, 554, 554, 554, 573, 559, 93, 559, 559, - 559, 554, 554, 566, 579, 559, 559, 567, 567, 554, - 554, 554, 574, 554, 568, 569, 569, 554, 554, 569, - 569, 571, 554, 571, 571, 554, 554, 559, 554, 573, - 580, 575, 575, 554, 559, 559, 559, 93, 158, 581, - 554, 582, 554, 32, 34, 34, 34, 34, 34, 34, - 559, 554, 554, 554, 554, 554, 573, 559, 158, 559, - 559, 559, 554, 559, 554, 580, 559, 559, 559, 559, - 559, 559, 583, 584, 584, 195, 585, 584, 586, 163, - - 554, 201, 201, 554, 201, 34, 34, 34, 34, 34, - 34, 34, 559, 554, 554, 554, 554, 554, 573, 559, - 559, 559, 559, 559, 559, 559, 554, 587, 587, 229, - 587, 588, 589, 590, 554, 591, 204, 591, 591, 239, - 591, 554, 242, 242, 554, 242, 554, 554, 34, 34, - 34, 34, 34, 559, 554, 554, 554, 573, 559, 559, - 559, 559, 559, 559, 559, 559, 592, 592, 593, 594, - 554, 554, 554, 554, 554, 595, 595, 596, 245, 596, - 596, 281, 596, 554, 284, 284, 554, 284, 34, 34, - 34, 34, 34, 559, 554, 554, 573, 559, 559, 559, - - 559, 559, 559, 554, 597, 598, 271, 554, 308, 308, - 554, 308, 554, 554, 554, 554, 554, 554, 599, 599, - 600, 287, 600, 600, 324, 600, 554, 327, 327, 554, - 327, 554, 554, 34, 34, 554, 554, 554, 554, 559, - 554, 554, 573, 559, 559, 559, 559, 559, 559, 559, - 559, 554, 601, 554, 602, 311, 602, 602, 358, 358, - 554, 361, 361, 554, 361, 554, 554, 554, 554, 603, - 603, 604, 330, 604, 604, 375, 604, 554, 378, 378, - 378, 34, 34, 559, 554, 554, 573, 559, 559, 559, - 559, 559, 559, 559, 554, 554, 554, 554, 605, 605, - - 606, 364, 606, 606, 404, 404, 554, 407, 407, 554, - 407, 554, 554, 554, 554, 554, 554, 607, 607, 608, - 608, 608, 422, 422, 554, 554, 554, 554, 554, 554, - 573, 573, 559, 609, 610, 559, 559, 559, 559, 559, - 559, 559, 554, 554, 554, 554, 554, 554, 611, 611, - 612, 410, 612, 612, 454, 454, 554, 457, 457, 554, - 457, 554, 554, 554, 554, 613, 613, 554, 614, 573, - 559, 609, 609, 609, 610, 610, 559, 559, 559, 559, - 559, 554, 554, 554, 554, 615, 615, 616, 460, 616, - 616, 491, 491, 554, 494, 494, 494, 554, 554, 554, - - 554, 554, 554, 614, 554, 573, 559, 559, 559, 559, - 559, 554, 554, 554, 554, 554, 554, 617, 617, 618, - 618, 618, 522, 522, 573, 559, 559, 559, 554, 554, - 554, 554, 619, 619, 620, 559, 559, 559, 559, 559, - 554, 554, 554, 554, 554, 620, 554, 559, 559, 559, - 559, 559, 559, 0, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554 - } ; - -static yyconst short int yy_nxt[3604] = - { 0, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 14, - 23, 24, 14, 14, 25, 26, 27, 28, 26, 26, - 26, 26, 26, 29, 30, 31, 14, 32, 32, 32, - 32, 33, 34, 34, 35, 34, 36, 34, 37, 34, - 34, 34, 34, 34, 38, 14, 39, 39, 39, 39, - 39, 39, 14, 14, 14, 14, 14, 14, 14, 40, - 14, 14, 41, 48, 48, 81, 42, 49, 49, 74, - 15, 53, 54, 74, 55, 85, 50, 50, 134, 108, - 55, 69, 16, 70, 71, 15, 53, 54, 180, 55, - 43, 44, 55, 56, 45, 55, 86, 554, 46, 74, - - 74, 47, 69, 16, 70, 71, 138, 55, 56, 145, - 90, 141, 108, 57, 90, 90, 109, 127, 86, 177, - 74, 51, 51, 139, 72, 171, 137, 144, 57, 15, - 16, 17, 90, 58, 96, 96, 96, 96, 96, 96, - 96, 96, 74, 137, 81, 72, 146, 147, 182, 142, - 143, 91, 97, 97, 97, 97, 97, 98, 73, 74, - 95, 95, 95, 95, 95, 95, 95, 95, 110, 347, - 143, 178, 59, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 15, 16, 17, 161, 58, 470, 111, 112, 74, 74, - - 113, 74, 163, 184, 114, 123, 220, 115, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, - 83, 83, 73, 59, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 15, 16, 17, 62, 58, 74, 134, 108, 125, - 63, 64, 65, 125, 125, 130, 108, 131, 181, 132, - 179, 166, 144, 131, 66, 132, 167, 74, 168, 90, - 74, 125, 161, 90, 90, 134, 108, 132, 132, 146, - 147, 200, 220, 213, 67, 15, 16, 17, 62, 58, - - 126, 90, 74, 145, 63, 64, 65, 73, 132, 73, - 74, 73, 222, 73, 73, 143, 220, 73, 66, 81, - 91, 159, 159, 159, 159, 159, 159, 159, 159, 73, - 73, 73, 159, 159, 159, 159, 159, 159, 67, 78, - 74, 78, 73, 78, 143, 78, 78, 547, 84, 78, - 84, 74, 84, 223, 84, 84, 110, 161, 84, 547, - 94, 78, 78, 78, 125, 219, 200, 220, 125, 125, - 298, 84, 84, 159, 159, 159, 159, 159, 159, 159, - 159, 74, 79, 81, 111, 112, 125, 74, 113, 81, - 134, 108, 114, 82, 247, 115, 83, 83, 83, 83, - - 83, 83, 83, 83, 92, 126, 93, 93, 93, 93, - 93, 93, 93, 93, 94, 187, 248, 74, 95, 95, - 95, 95, 95, 254, 74, 155, 156, 157, 155, 155, - 155, 155, 155, 74, 299, 74, 262, 95, 95, 95, - 95, 95, 95, 73, 74, 259, 74, 73, 297, 73, - 399, 399, 73, 73, 74, 73, 73, 73, 101, 101, - 101, 101, 101, 101, 101, 101, 94, 74, 354, 73, - 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, - 102, 102, 102, 102, 102, 102, 102, 74, 102, 95, - 95, 95, 95, 95, 95, 73, 73, 73, 73, 73, - - 73, 73, 73, 73, 73, 102, 102, 102, 102, 102, - 102, 102, 102, 554, 231, 231, 231, 102, 102, 102, - 102, 102, 83, 83, 83, 83, 83, 83, 83, 83, - 74, 74, 489, 134, 108, 294, 73, 73, 73, 73, - 73, 73, 107, 108, 73, 81, 73, 345, 73, 73, - 74, 87, 73, 87, 161, 87, 261, 87, 87, 235, - 161, 87, 554, 200, 73, 73, 73, 81, 136, 237, - 354, 136, 136, 87, 87, 87, 137, 82, 136, 94, - 83, 83, 83, 83, 83, 83, 83, 83, 89, 489, - 73, 136, 89, 81, 73, 73, 452, 258, 89, 124, - - 74, 73, 247, 124, 90, 73, 73, 473, 90, 124, - 89, 89, 73, 74, 90, 554, 161, 260, 116, 81, - 74, 124, 124, 73, 248, 237, 90, 90, 389, 133, - 344, 512, 554, 554, 554, 554, 554, 554, 554, 554, - 78, 387, 78, 148, 78, 332, 78, 78, 474, 336, - 78, 554, 554, 554, 554, 554, 554, 554, 554, 161, - 74, 505, 78, 78, 78, 300, 161, 333, 200, 74, - 152, 337, 152, 338, 152, 237, 152, 152, 340, 74, - 152, 433, 81, 79, 158, 158, 158, 158, 158, 158, - 158, 158, 152, 152, 152, 339, 158, 158, 158, 158, - - 158, 224, 225, 226, 224, 224, 224, 224, 224, 240, - 240, 240, 240, 240, 241, 158, 158, 158, 158, 158, - 158, 164, 164, 164, 164, 164, 164, 164, 164, 343, - 74, 431, 81, 164, 164, 164, 164, 164, 187, 473, - 188, 188, 188, 188, 188, 188, 282, 282, 282, 282, - 282, 283, 158, 158, 158, 158, 158, 158, 187, 74, - 188, 188, 188, 188, 188, 188, 188, 188, 346, 74, - 205, 205, 205, 205, 205, 205, 205, 205, 125, 432, - 476, 354, 125, 449, 449, 235, 161, 161, 125, 74, - 187, 356, 189, 189, 189, 189, 189, 189, 189, 189, - - 125, 125, 229, 229, 230, 231, 231, 231, 231, 231, - 197, 239, 239, 239, 239, 239, 239, 239, 239, 554, - 161, 74, 187, 554, 190, 190, 190, 190, 190, 191, - 188, 188, 554, 356, 238, 238, 238, 238, 238, 238, - 238, 238, 268, 268, 268, 268, 268, 268, 268, 268, - 197, 74, 161, 74, 73, 161, 192, 192, 192, 192, - 192, 192, 192, 192, 237, 466, 466, 384, 192, 192, - 192, 192, 192, 273, 274, 275, 273, 273, 273, 273, - 273, 325, 325, 325, 325, 325, 326, 192, 192, 192, - 192, 192, 192, 194, 195, 196, 196, 196, 196, 196, - - 196, 197, 486, 486, 81, 198, 198, 198, 198, 198, - 246, 246, 246, 246, 246, 246, 246, 246, 359, 359, - 359, 359, 359, 360, 198, 198, 198, 198, 198, 198, - 161, 201, 202, 203, 201, 201, 201, 201, 201, 204, - 235, 161, 452, 205, 205, 205, 205, 205, 235, 161, - 277, 277, 277, 277, 277, 277, 332, 336, 237, 402, - 506, 74, 205, 205, 205, 205, 205, 205, 206, 206, - 206, 206, 206, 206, 206, 206, 338, 390, 333, 337, - 206, 206, 206, 206, 206, 281, 281, 281, 281, 281, - 281, 281, 281, 554, 425, 74, 235, 161, 339, 192, - - 192, 192, 192, 192, 192, 187, 237, 188, 188, 188, - 188, 188, 188, 188, 188, 554, 426, 280, 280, 280, - 280, 280, 280, 280, 280, 301, 302, 303, 301, 301, - 301, 301, 301, 505, 474, 74, 74, 187, 161, 188, - 188, 188, 188, 188, 188, 188, 188, 279, 235, 161, - 471, 436, 518, 518, 74, 554, 161, 262, 279, 263, - 263, 263, 263, 263, 263, 279, 525, 81, 74, 235, - 161, 236, 236, 236, 236, 236, 236, 236, 236, 237, - 235, 161, 74, 238, 238, 238, 238, 238, 74, 313, - 279, 314, 314, 314, 314, 314, 314, 314, 314, 533, - - 533, 503, 238, 238, 238, 238, 238, 238, 161, 242, - 243, 244, 242, 242, 242, 242, 242, 245, 74, 135, - 135, 246, 246, 246, 246, 246, 313, 388, 315, 315, - 315, 315, 315, 315, 315, 315, 161, 235, 161, 402, - 246, 246, 246, 246, 246, 246, 262, 322, 263, 263, - 263, 263, 263, 263, 263, 263, 313, 427, 316, 316, - 316, 316, 316, 317, 314, 314, 288, 288, 288, 288, - 288, 288, 288, 288, 425, 356, 443, 74, 262, 428, - 264, 264, 264, 264, 264, 264, 264, 264, 235, 161, - 320, 320, 320, 320, 320, 320, 426, 354, 279, 324, - - 324, 324, 324, 324, 324, 324, 324, 356, 507, 74, - 262, 354, 265, 265, 265, 265, 265, 266, 263, 263, - 554, 402, 323, 323, 323, 323, 323, 323, 323, 323, - 312, 312, 312, 312, 312, 312, 312, 312, 468, 74, - 412, 74, 235, 161, 277, 277, 277, 277, 277, 277, - 277, 277, 237, 235, 161, 278, 278, 278, 278, 278, - 278, 278, 278, 279, 356, 307, 74, 280, 280, 280, - 280, 280, 358, 358, 358, 358, 358, 358, 358, 358, - 376, 376, 376, 376, 376, 377, 280, 280, 280, 280, - 280, 280, 161, 284, 285, 286, 284, 284, 284, 284, - - 284, 287, 161, 430, 429, 288, 288, 288, 288, 288, - 554, 279, 357, 357, 357, 357, 357, 357, 357, 357, - 74, 554, 161, 307, 288, 288, 288, 288, 288, 288, - 262, 322, 263, 263, 263, 263, 263, 263, 263, 263, - 366, 367, 368, 366, 366, 366, 366, 366, 313, 161, - 314, 314, 314, 314, 314, 314, 314, 314, 322, 233, - 386, 74, 262, 554, 263, 263, 263, 263, 263, 263, - 263, 263, 313, 402, 314, 314, 314, 314, 314, 314, - 314, 314, 313, 161, 314, 314, 314, 314, 314, 314, - 431, 81, 322, 74, 308, 309, 310, 308, 308, 308, - - 308, 308, 311, 469, 385, 383, 312, 312, 312, 312, - 312, 331, 331, 331, 331, 331, 331, 331, 331, 405, - 405, 405, 405, 405, 406, 312, 312, 312, 312, 312, - 312, 235, 161, 320, 320, 320, 320, 320, 320, 320, - 320, 279, 235, 161, 321, 321, 321, 321, 321, 321, - 321, 321, 322, 382, 313, 307, 323, 323, 323, 323, - 323, 235, 161, 371, 371, 371, 371, 371, 371, 427, - 233, 322, 197, 342, 341, 323, 323, 323, 323, 323, - 323, 161, 327, 328, 329, 327, 327, 327, 327, 327, - 330, 428, 335, 334, 331, 331, 331, 331, 331, 375, - - 375, 375, 375, 375, 375, 375, 375, 423, 423, 423, - 423, 423, 424, 331, 331, 331, 331, 331, 331, 347, - 348, 348, 348, 348, 348, 348, 348, 348, 554, 307, - 374, 374, 374, 374, 374, 374, 374, 374, 391, 392, - 393, 394, 391, 391, 391, 391, 525, 81, 536, 74, - 347, 349, 349, 349, 349, 349, 349, 349, 349, 535, - 347, 348, 348, 348, 348, 348, 348, 74, 396, 397, - 398, 396, 396, 396, 396, 396, 233, 197, 197, 74, - 74, 347, 350, 350, 350, 350, 350, 351, 348, 348, - 74, 365, 365, 365, 365, 365, 365, 365, 365, 404, - - 404, 404, 404, 404, 404, 404, 404, 255, 545, 296, - 295, 74, 354, 545, 355, 355, 355, 355, 355, 355, - 355, 355, 356, 161, 293, 292, 357, 357, 357, 357, - 357, 554, 373, 403, 403, 403, 403, 403, 403, 403, - 403, 291, 290, 289, 271, 357, 357, 357, 357, 357, - 357, 361, 362, 363, 361, 361, 361, 361, 361, 364, - 233, 197, 267, 365, 365, 365, 365, 365, 412, 354, - 413, 413, 413, 413, 413, 413, 413, 413, 197, 402, - 100, 255, 365, 365, 365, 365, 365, 365, 235, 161, - 371, 371, 371, 371, 371, 371, 371, 371, 322, 235, - - 161, 372, 372, 372, 372, 372, 372, 372, 372, 373, - 257, 255, 256, 374, 374, 374, 374, 374, 412, 354, - 414, 414, 414, 414, 414, 414, 414, 414, 554, 452, - 255, 253, 374, 374, 374, 374, 374, 374, 161, 378, - 379, 380, 378, 378, 378, 378, 378, 235, 161, 252, - 251, 381, 381, 381, 381, 381, 412, 322, 415, 415, - 415, 415, 415, 416, 413, 413, 250, 249, 94, 474, - 381, 381, 381, 381, 381, 381, 347, 348, 348, 348, - 348, 348, 348, 348, 348, 235, 161, 381, 381, 381, - 381, 381, 381, 381, 381, 373, 422, 422, 422, 422, - - 422, 422, 422, 422, 197, 233, 74, 347, 348, 348, - 348, 348, 348, 348, 348, 348, 554, 161, 235, 161, - 419, 419, 419, 419, 419, 419, 373, 554, 373, 421, - 421, 421, 421, 421, 421, 421, 421, 74, 354, 554, - 400, 400, 400, 400, 400, 400, 400, 400, 356, 354, - 554, 401, 401, 401, 401, 401, 401, 401, 401, 402, - 452, 197, 100, 403, 403, 403, 403, 403, 443, 161, - 444, 444, 444, 444, 444, 444, 444, 444, 373, 81, - 476, 185, 403, 403, 403, 403, 403, 403, 407, 408, - 409, 407, 407, 407, 407, 407, 410, 221, 218, 217, - - 411, 411, 411, 411, 411, 443, 354, 445, 445, 445, - 445, 445, 445, 445, 445, 216, 452, 215, 214, 411, - 411, 411, 411, 411, 411, 235, 161, 419, 419, 419, - 419, 419, 419, 419, 419, 373, 235, 161, 420, 420, - 420, 420, 420, 420, 420, 420, 212, 235, 161, 211, - 421, 421, 421, 421, 421, 434, 443, 373, 446, 446, - 446, 446, 446, 447, 444, 444, 481, 481, 481, 421, - 421, 421, 421, 421, 421, 434, 210, 434, 435, 411, - 411, 411, 411, 411, 411, 411, 411, 454, 454, 454, - 454, 454, 454, 454, 454, 74, 74, 436, 209, 437, - - 437, 437, 437, 437, 437, 437, 437, 455, 455, 455, - 455, 455, 456, 554, 354, 453, 453, 453, 453, 453, - 453, 453, 453, 208, 489, 207, 100, 92, 74, 436, - 153, 438, 438, 438, 438, 438, 438, 438, 438, 462, - 463, 464, 462, 462, 462, 462, 462, 412, 554, 413, - 413, 413, 413, 413, 413, 413, 413, 81, 489, 81, - 74, 436, 354, 439, 439, 439, 439, 439, 440, 441, - 441, 412, 489, 413, 413, 413, 413, 413, 413, 413, - 413, 412, 74, 413, 413, 413, 413, 413, 413, 434, - 185, 142, 74, 436, 143, 442, 442, 442, 437, 437, - - 437, 437, 437, 492, 492, 492, 492, 492, 493, 434, - 137, 434, 434, 137, 129, 183, 436, 122, 481, 481, - 481, 176, 175, 174, 74, 354, 173, 450, 450, 450, - 450, 450, 450, 450, 450, 402, 354, 172, 451, 451, - 451, 451, 451, 451, 451, 451, 452, 74, 170, 169, - 453, 453, 453, 453, 453, 477, 478, 479, 477, 477, - 477, 477, 477, 523, 523, 523, 523, 523, 524, 453, - 453, 453, 453, 453, 453, 457, 458, 459, 457, 457, - 457, 457, 457, 460, 74, 165, 100, 461, 461, 461, - 461, 461, 482, 483, 484, 482, 482, 482, 482, 482, - - 541, 541, 541, 541, 541, 541, 461, 461, 461, 461, - 461, 461, 235, 161, 467, 467, 467, 467, 467, 467, - 467, 467, 436, 73, 441, 441, 441, 441, 441, 441, - 441, 441, 443, 100, 444, 444, 444, 444, 444, 444, - 444, 444, 443, 154, 444, 444, 444, 444, 444, 444, - 444, 444, 88, 74, 436, 153, 441, 441, 441, 441, - 441, 441, 441, 441, 443, 81, 444, 444, 444, 444, - 444, 444, 461, 461, 461, 461, 461, 461, 461, 461, - 148, 149, 76, 75, 74, 74, 436, 143, 441, 441, - 441, 441, 441, 441, 480, 480, 491, 491, 491, 491, - - 491, 491, 491, 491, 554, 137, 490, 490, 490, 490, - 490, 490, 490, 490, 129, 122, 121, 74, 436, 120, - 480, 480, 480, 480, 480, 480, 480, 480, 161, 498, - 498, 498, 498, 498, 498, 498, 498, 161, 499, 499, - 499, 499, 499, 499, 499, 499, 119, 118, 117, 74, - 354, 106, 487, 487, 487, 487, 487, 487, 487, 487, - 452, 354, 105, 488, 488, 488, 488, 488, 488, 488, - 488, 489, 104, 103, 100, 490, 490, 490, 490, 490, - 161, 500, 500, 500, 500, 500, 501, 498, 498, 88, - 76, 75, 74, 554, 490, 490, 490, 490, 490, 490, - - 494, 495, 496, 494, 494, 494, 494, 494, 554, 554, - 554, 554, 497, 497, 497, 497, 497, 472, 554, 554, - 554, 472, 554, 472, 472, 554, 554, 472, 554, 554, - 554, 497, 497, 497, 497, 497, 497, 554, 475, 472, - 472, 472, 475, 554, 475, 475, 554, 554, 475, 480, - 480, 480, 480, 480, 480, 480, 480, 554, 554, 554, - 475, 475, 475, 507, 554, 508, 508, 508, 508, 508, - 508, 508, 508, 554, 554, 554, 554, 512, 74, 513, - 513, 513, 513, 513, 513, 513, 513, 161, 498, 498, - 498, 498, 498, 498, 74, 507, 554, 509, 509, 509, - - 509, 509, 509, 509, 509, 512, 554, 514, 514, 514, - 514, 514, 514, 514, 514, 512, 554, 515, 515, 515, - 515, 515, 516, 513, 513, 554, 74, 507, 554, 510, - 510, 510, 510, 510, 511, 508, 508, 497, 497, 497, - 497, 497, 497, 497, 497, 522, 522, 522, 522, 522, - 522, 522, 522, 554, 554, 554, 554, 554, 74, 354, - 554, 519, 519, 519, 519, 519, 519, 519, 519, 489, - 354, 554, 520, 520, 520, 520, 520, 520, 520, 520, - 554, 554, 554, 554, 521, 521, 521, 521, 521, 554, - 554, 521, 521, 521, 521, 521, 521, 521, 521, 554, - - 554, 554, 554, 521, 521, 521, 521, 521, 521, 161, - 498, 498, 498, 498, 498, 498, 498, 498, 161, 498, - 498, 498, 498, 498, 498, 498, 498, 526, 527, 528, - 526, 526, 526, 526, 526, 554, 507, 554, 508, 508, - 508, 508, 508, 508, 529, 530, 531, 529, 529, 529, - 529, 529, 554, 554, 554, 554, 74, 507, 554, 508, - 508, 508, 508, 508, 508, 508, 508, 74, 512, 554, - 513, 513, 513, 513, 513, 513, 513, 513, 512, 554, - 513, 513, 513, 513, 513, 513, 513, 513, 74, 507, - 554, 508, 508, 508, 508, 508, 508, 508, 508, 512, - - 554, 513, 513, 513, 513, 513, 513, 354, 554, 534, - 534, 534, 534, 534, 534, 534, 534, 554, 554, 554, - 74, 536, 554, 537, 537, 537, 537, 537, 537, 537, - 537, 541, 541, 541, 541, 541, 541, 541, 541, 542, - 542, 542, 542, 542, 542, 542, 542, 554, 554, 554, - 554, 554, 74, 536, 554, 538, 538, 538, 538, 538, - 538, 538, 538, 543, 543, 543, 543, 543, 544, 541, - 541, 548, 549, 550, 548, 548, 548, 548, 548, 554, - 554, 554, 554, 554, 74, 536, 554, 539, 539, 539, - 539, 539, 540, 537, 537, 554, 554, 554, 554, 536, - - 74, 537, 537, 537, 537, 537, 537, 541, 541, 541, - 541, 541, 541, 541, 541, 554, 74, 536, 554, 537, - 537, 537, 537, 537, 537, 537, 537, 554, 554, 554, - 74, 541, 541, 541, 541, 541, 541, 541, 541, 551, - 551, 551, 551, 551, 551, 551, 551, 554, 74, 536, - 554, 537, 537, 537, 537, 537, 537, 537, 537, 548, - 548, 548, 548, 548, 548, 548, 548, 554, 74, 552, - 552, 552, 552, 552, 553, 551, 551, 554, 554, 554, - 74, 551, 551, 551, 551, 551, 551, 554, 74, 551, - 551, 551, 551, 551, 551, 551, 551, 554, 74, 554, - - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 74, 554, 554, 554, 554, 554, 554, 554, 74, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 61, 61, 61, - 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, - 61, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 68, 73, 554, 554, 554, 73, - 554, 73, 73, 73, 554, 554, 73, 73, 73, 77, - 77, 554, 77, 77, 77, 77, 77, 77, 77, 77, - - 77, 77, 77, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 84, 554, 554, - 554, 84, 554, 84, 84, 84, 84, 554, 84, 84, - 84, 87, 554, 554, 554, 87, 554, 87, 87, 87, - 554, 554, 87, 87, 87, 89, 554, 554, 89, 89, - 89, 89, 89, 89, 554, 554, 89, 89, 89, 99, - 99, 554, 554, 554, 99, 124, 554, 554, 124, 124, - 124, 124, 124, 124, 554, 554, 124, 124, 124, 128, - 554, 554, 128, 128, 128, 128, 128, 128, 554, 128, - 554, 128, 128, 136, 554, 554, 136, 554, 136, 136, - - 136, 136, 136, 554, 136, 136, 136, 140, 140, 140, - 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, - 140, 142, 142, 554, 142, 554, 142, 142, 142, 142, - 142, 142, 142, 142, 142, 78, 78, 554, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 150, - 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, - 150, 150, 150, 151, 151, 554, 151, 151, 151, 151, - 151, 151, 151, 151, 151, 151, 151, 152, 554, 554, - 554, 152, 554, 152, 152, 152, 554, 554, 152, 152, - 152, 90, 554, 554, 90, 90, 90, 90, 90, 90, - - 554, 554, 90, 90, 90, 160, 160, 554, 554, 554, - 160, 162, 162, 162, 554, 554, 554, 162, 125, 554, - 554, 125, 125, 125, 125, 125, 125, 554, 554, 125, - 125, 125, 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 193, 193, 554, 554, - 554, 193, 199, 199, 199, 554, 554, 554, 199, 227, - 227, 554, 554, 554, 227, 228, 228, 554, 554, 554, - 228, 232, 232, 554, 554, 554, 232, 234, 234, 234, - 554, 554, 554, 234, 267, 267, 554, 554, 554, 267, - 269, 269, 554, 554, 554, 269, 270, 270, 554, 554, - - 554, 270, 272, 272, 272, 554, 554, 554, 272, 276, - 276, 276, 276, 554, 554, 554, 276, 304, 304, 554, - 554, 554, 304, 305, 305, 554, 554, 554, 305, 306, - 306, 554, 554, 554, 306, 318, 318, 318, 554, 554, - 554, 318, 319, 319, 319, 319, 554, 554, 554, 319, - 352, 352, 554, 554, 554, 352, 353, 353, 554, 554, - 554, 353, 369, 369, 369, 554, 554, 554, 369, 370, - 370, 370, 370, 554, 554, 554, 370, 395, 395, 554, - 554, 554, 395, 399, 554, 399, 399, 554, 554, 554, - 399, 417, 417, 417, 554, 554, 554, 417, 418, 418, - - 418, 418, 554, 554, 554, 418, 448, 448, 554, 554, - 554, 448, 449, 554, 449, 449, 554, 554, 554, 449, - 465, 465, 465, 554, 554, 554, 465, 466, 466, 466, - 554, 554, 554, 554, 466, 472, 554, 554, 472, 472, - 554, 472, 472, 472, 554, 554, 472, 472, 472, 475, - 554, 554, 475, 475, 554, 475, 475, 475, 554, 554, - 475, 475, 475, 485, 485, 554, 554, 554, 485, 486, - 554, 486, 486, 554, 554, 554, 486, 502, 502, 554, - 554, 554, 554, 502, 504, 504, 504, 504, 504, 504, - 504, 504, 504, 504, 504, 504, 504, 504, 517, 517, - - 554, 554, 554, 517, 518, 554, 518, 518, 554, 554, - 554, 518, 532, 532, 554, 554, 554, 532, 533, 554, - 533, 554, 554, 554, 554, 533, 546, 546, 546, 546, - 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, - 13, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - - 554, 554, 554 - } ; - -static yyconst short int yy_chk[3604] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 3, 4, 116, 2, 3, 4, 551, - 5, 5, 5, 119, 5, 20, 3, 4, 59, 59, - 5, 11, 11, 11, 11, 6, 6, 6, 119, 6, - 2, 2, 5, 5, 2, 6, 20, 84, 2, 40, - - 51, 2, 12, 12, 12, 12, 63, 6, 6, 70, - 25, 67, 67, 5, 25, 25, 40, 51, 84, 116, - 109, 3, 4, 65, 11, 109, 63, 69, 6, 7, - 7, 7, 25, 7, 27, 27, 27, 27, 27, 27, - 27, 27, 121, 65, 432, 12, 72, 72, 121, 72, - 70, 25, 28, 28, 28, 28, 28, 28, 39, 117, - 39, 39, 39, 39, 39, 39, 39, 39, 41, 348, - 69, 117, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 100, 8, 432, 41, 41, 127, 348, - - 41, 178, 100, 127, 41, 49, 178, 41, 49, 49, - 49, 49, 49, 49, 49, 49, 82, 82, 82, 82, - 82, 82, 82, 82, 83, 83, 83, 83, 83, 83, - 83, 83, 118, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 120, 130, 130, 50, - 9, 9, 9, 50, 50, 57, 57, 57, 120, 57, - 118, 104, 144, 57, 9, 57, 104, 222, 104, 89, - 171, 50, 162, 89, 89, 134, 134, 57, 57, 146, - 146, 162, 222, 171, 9, 10, 10, 10, 10, 10, - - 50, 89, 182, 145, 10, 10, 10, 74, 57, 74, - 181, 74, 181, 74, 74, 144, 182, 74, 10, 177, - 89, 96, 96, 96, 96, 96, 96, 96, 96, 74, - 74, 74, 98, 98, 98, 98, 98, 98, 10, 18, - 184, 18, 18, 18, 145, 18, 18, 546, 86, 18, - 86, 180, 86, 184, 86, 86, 110, 199, 86, 535, - 192, 18, 18, 18, 124, 177, 199, 180, 124, 124, - 259, 86, 86, 97, 97, 97, 97, 97, 97, 97, - 97, 192, 18, 19, 110, 110, 124, 259, 110, 258, - 107, 107, 110, 19, 207, 110, 19, 19, 19, 19, - - 19, 19, 19, 19, 26, 124, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 188, 207, 213, 26, 26, - 26, 26, 26, 213, 260, 92, 92, 92, 92, 92, - 92, 92, 92, 107, 260, 26, 263, 26, 26, 26, - 26, 26, 26, 32, 220, 220, 188, 32, 258, 32, - 360, 360, 32, 32, 92, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 263, 534, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, - - 32, 32, 32, 32, 32, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 196, 196, 196, 34, 34, 34, - 34, 34, 123, 123, 123, 123, 123, 123, 123, 123, - 254, 299, 532, 141, 141, 254, 34, 34, 34, 34, - 34, 34, 38, 38, 38, 219, 38, 299, 38, 38, - 223, 88, 38, 88, 234, 88, 223, 88, 88, 236, - 236, 88, 521, 234, 38, 38, 38, 42, 137, 236, - 520, 137, 137, 88, 88, 88, 141, 42, 137, 221, - 42, 42, 42, 42, 42, 42, 42, 42, 91, 518, - 91, 137, 91, 343, 91, 91, 517, 219, 91, 126, - - 221, 126, 247, 126, 154, 126, 126, 434, 154, 126, - 91, 91, 91, 345, 154, 238, 238, 221, 42, 58, - 298, 126, 126, 126, 247, 238, 154, 154, 345, 58, - 298, 513, 58, 58, 58, 58, 58, 58, 58, 58, - 77, 343, 77, 77, 77, 289, 77, 77, 434, 292, - 77, 133, 133, 133, 133, 133, 133, 133, 133, 272, - 261, 504, 77, 77, 77, 261, 276, 289, 272, 294, - 153, 292, 153, 293, 153, 276, 153, 153, 294, 388, - 153, 388, 297, 77, 93, 93, 93, 93, 93, 93, - 93, 93, 153, 153, 153, 293, 93, 93, 93, 93, - - 93, 187, 187, 187, 187, 187, 187, 187, 187, 203, - 203, 203, 203, 203, 203, 93, 93, 93, 93, 93, - 93, 101, 101, 101, 101, 101, 101, 101, 101, 297, - 187, 387, 387, 101, 101, 101, 101, 101, 191, 435, - 191, 191, 191, 191, 191, 191, 244, 244, 244, 244, - 244, 244, 101, 101, 101, 101, 101, 101, 155, 300, - 155, 155, 155, 155, 155, 155, 155, 155, 300, 191, - 200, 200, 200, 200, 200, 200, 200, 200, 183, 387, - 435, 355, 183, 406, 406, 420, 420, 502, 183, 155, - 156, 355, 156, 156, 156, 156, 156, 156, 156, 156, - - 183, 183, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 202, 202, 202, 202, 202, 202, 202, 202, 421, - 421, 156, 157, 357, 157, 157, 157, 157, 157, 157, - 157, 157, 205, 357, 205, 205, 205, 205, 205, 205, - 205, 205, 229, 229, 229, 229, 229, 229, 229, 229, - 229, 340, 498, 157, 158, 318, 158, 158, 158, 158, - 158, 158, 158, 158, 318, 424, 424, 340, 158, 158, - 158, 158, 158, 235, 235, 235, 235, 235, 235, 235, - 235, 286, 286, 286, 286, 286, 286, 158, 158, 158, - 158, 158, 158, 161, 161, 161, 161, 161, 161, 161, - - 161, 161, 456, 456, 470, 161, 161, 161, 161, 161, - 237, 237, 237, 237, 237, 237, 237, 237, 310, 310, - 310, 310, 310, 310, 161, 161, 161, 161, 161, 161, - 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, - 467, 467, 486, 163, 163, 163, 163, 163, 241, 241, - 241, 241, 241, 241, 241, 241, 332, 336, 241, 485, - 470, 346, 163, 163, 163, 163, 163, 163, 164, 164, - 164, 164, 164, 164, 164, 164, 338, 346, 332, 336, - 164, 164, 164, 164, 164, 243, 243, 243, 243, 243, - 243, 243, 243, 472, 382, 471, 277, 277, 338, 164, - - 164, 164, 164, 164, 164, 189, 277, 189, 189, 189, - 189, 189, 189, 189, 189, 246, 382, 246, 246, 246, - 246, 246, 246, 246, 246, 262, 262, 262, 262, 262, - 262, 262, 262, 469, 472, 433, 189, 190, 319, 190, - 190, 190, 190, 190, 190, 190, 190, 319, 278, 278, - 433, 437, 493, 493, 262, 280, 280, 266, 278, 266, - 266, 266, 266, 266, 266, 280, 506, 506, 190, 201, - 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, - 320, 320, 437, 201, 201, 201, 201, 201, 266, 273, - 320, 273, 273, 273, 273, 273, 273, 273, 273, 524, - - 524, 468, 201, 201, 201, 201, 201, 201, 204, 204, - 204, 204, 204, 204, 204, 204, 204, 204, 344, 568, - 568, 204, 204, 204, 204, 204, 274, 344, 274, 274, - 274, 274, 274, 274, 274, 274, 466, 321, 321, 449, - 204, 204, 204, 204, 204, 204, 224, 321, 224, 224, - 224, 224, 224, 224, 224, 224, 275, 383, 275, 275, - 275, 275, 275, 275, 275, 275, 279, 279, 279, 279, - 279, 279, 279, 279, 425, 448, 444, 224, 225, 383, - 225, 225, 225, 225, 225, 225, 225, 225, 283, 283, - 283, 283, 283, 283, 283, 283, 425, 400, 283, 285, - - 285, 285, 285, 285, 285, 285, 285, 400, 508, 225, - 226, 401, 226, 226, 226, 226, 226, 226, 226, 226, - 288, 401, 288, 288, 288, 288, 288, 288, 288, 288, - 307, 307, 307, 307, 307, 307, 307, 307, 429, 508, - 413, 226, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 239, 239, 242, 242, 242, 242, 242, 242, 242, - 242, 242, 242, 242, 399, 395, 390, 242, 242, 242, - 242, 242, 309, 309, 309, 309, 309, 309, 309, 309, - 329, 329, 329, 329, 329, 329, 242, 242, 242, 242, - 242, 242, 245, 245, 245, 245, 245, 245, 245, 245, - - 245, 245, 369, 386, 385, 245, 245, 245, 245, 245, - 312, 369, 312, 312, 312, 312, 312, 312, 312, 312, - 384, 323, 323, 353, 245, 245, 245, 245, 245, 245, - 264, 323, 264, 264, 264, 264, 264, 264, 264, 264, - 313, 313, 313, 313, 313, 313, 313, 313, 315, 370, - 315, 315, 315, 315, 315, 315, 315, 315, 370, 352, - 342, 264, 265, 403, 265, 265, 265, 265, 265, 265, - 265, 265, 316, 403, 316, 316, 316, 316, 316, 316, - 316, 316, 317, 417, 317, 317, 317, 317, 317, 317, - 431, 431, 417, 265, 271, 271, 271, 271, 271, 271, - - 271, 271, 271, 431, 341, 335, 271, 271, 271, 271, - 271, 322, 322, 322, 322, 322, 322, 322, 322, 363, - 363, 363, 363, 363, 363, 271, 271, 271, 271, 271, - 271, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 334, 314, 306, 284, 284, 284, 284, - 284, 326, 326, 326, 326, 326, 326, 326, 326, 427, - 305, 326, 304, 296, 295, 284, 284, 284, 284, 284, - 284, 287, 287, 287, 287, 287, 287, 287, 287, 287, - 287, 427, 291, 290, 287, 287, 287, 287, 287, 328, - - 328, 328, 328, 328, 328, 328, 328, 380, 380, 380, - 380, 380, 380, 287, 287, 287, 287, 287, 287, 301, - 301, 301, 301, 301, 301, 301, 301, 301, 331, 270, - 331, 331, 331, 331, 331, 331, 331, 331, 347, 347, - 347, 347, 347, 347, 347, 347, 525, 525, 537, 301, - 302, 302, 302, 302, 302, 302, 302, 302, 302, 525, - 351, 351, 351, 351, 351, 351, 351, 347, 354, 354, - 354, 354, 354, 354, 354, 354, 269, 268, 267, 537, - 302, 303, 303, 303, 303, 303, 303, 303, 303, 303, - 351, 356, 356, 356, 356, 356, 356, 356, 356, 362, - - 362, 362, 362, 362, 362, 362, 362, 257, 619, 256, - 255, 303, 308, 619, 308, 308, 308, 308, 308, 308, - 308, 308, 308, 418, 253, 252, 308, 308, 308, 308, - 308, 365, 418, 365, 365, 365, 365, 365, 365, 365, - 365, 251, 250, 249, 233, 308, 308, 308, 308, 308, - 308, 311, 311, 311, 311, 311, 311, 311, 311, 311, - 232, 231, 230, 311, 311, 311, 311, 311, 366, 450, - 366, 366, 366, 366, 366, 366, 366, 366, 228, 450, - 227, 218, 311, 311, 311, 311, 311, 311, 324, 324, - 324, 324, 324, 324, 324, 324, 324, 324, 324, 327, - - 327, 327, 327, 327, 327, 327, 327, 327, 327, 327, - 217, 216, 215, 327, 327, 327, 327, 327, 367, 451, - 367, 367, 367, 367, 367, 367, 367, 367, 473, 451, - 214, 212, 327, 327, 327, 327, 327, 327, 330, 330, - 330, 330, 330, 330, 330, 330, 330, 371, 371, 211, - 210, 330, 330, 330, 330, 330, 368, 371, 368, 368, - 368, 368, 368, 368, 368, 368, 209, 208, 206, 473, - 330, 330, 330, 330, 330, 330, 349, 349, 349, 349, - 349, 349, 349, 349, 349, 372, 372, 373, 373, 373, - 373, 373, 373, 373, 373, 372, 379, 379, 379, 379, - - 379, 379, 379, 379, 198, 197, 349, 350, 350, 350, - 350, 350, 350, 350, 350, 350, 374, 374, 377, 377, - 377, 377, 377, 377, 377, 377, 374, 381, 377, 381, - 381, 381, 381, 381, 381, 381, 381, 350, 358, 475, - 358, 358, 358, 358, 358, 358, 358, 358, 358, 361, - 453, 361, 361, 361, 361, 361, 361, 361, 361, 361, - 453, 194, 193, 361, 361, 361, 361, 361, 396, 465, - 396, 396, 396, 396, 396, 396, 396, 396, 465, 186, - 475, 185, 361, 361, 361, 361, 361, 361, 364, 364, - 364, 364, 364, 364, 364, 364, 364, 179, 176, 175, - - 364, 364, 364, 364, 364, 397, 487, 397, 397, 397, - 397, 397, 397, 397, 397, 174, 487, 173, 172, 364, - 364, 364, 364, 364, 364, 375, 375, 375, 375, 375, - 375, 375, 375, 375, 375, 375, 378, 378, 378, 378, - 378, 378, 378, 378, 378, 378, 170, 419, 419, 169, - 378, 378, 378, 378, 378, 389, 398, 419, 398, 398, - 398, 398, 398, 398, 398, 398, 481, 481, 481, 378, - 378, 378, 378, 378, 378, 389, 168, 389, 389, 402, - 402, 402, 402, 402, 402, 402, 402, 408, 408, 408, - 408, 408, 408, 408, 408, 481, 389, 391, 167, 391, - - 391, 391, 391, 391, 391, 391, 391, 409, 409, 409, - 409, 409, 409, 411, 488, 411, 411, 411, 411, 411, - 411, 411, 411, 166, 488, 165, 160, 159, 391, 392, - 152, 392, 392, 392, 392, 392, 392, 392, 392, 412, - 412, 412, 412, 412, 412, 412, 412, 414, 490, 414, - 414, 414, 414, 414, 414, 414, 414, 151, 490, 150, - 392, 393, 519, 393, 393, 393, 393, 393, 393, 393, - 393, 415, 519, 415, 415, 415, 415, 415, 415, 415, - 415, 416, 148, 416, 416, 416, 416, 416, 416, 430, - 147, 143, 393, 394, 142, 394, 394, 394, 394, 394, - - 394, 394, 394, 459, 459, 459, 459, 459, 459, 430, - 140, 430, 430, 136, 129, 125, 442, 122, 442, 442, - 442, 115, 114, 113, 394, 404, 112, 404, 404, 404, - 404, 404, 404, 404, 404, 404, 407, 111, 407, 407, - 407, 407, 407, 407, 407, 407, 407, 442, 106, 105, - 407, 407, 407, 407, 407, 436, 436, 436, 436, 436, - 436, 436, 436, 496, 496, 496, 496, 496, 496, 407, - 407, 407, 407, 407, 407, 410, 410, 410, 410, 410, - 410, 410, 410, 410, 436, 103, 99, 410, 410, 410, - 410, 410, 443, 443, 443, 443, 443, 443, 443, 443, - - 544, 544, 544, 544, 544, 544, 410, 410, 410, 410, - 410, 410, 422, 422, 422, 422, 422, 422, 422, 422, - 422, 422, 438, 95, 438, 438, 438, 438, 438, 438, - 438, 438, 445, 94, 445, 445, 445, 445, 445, 445, - 445, 445, 446, 90, 446, 446, 446, 446, 446, 446, - 446, 446, 87, 438, 439, 85, 439, 439, 439, 439, - 439, 439, 439, 439, 447, 80, 447, 447, 447, 447, - 447, 447, 452, 452, 452, 452, 452, 452, 452, 452, - 79, 78, 76, 75, 73, 439, 440, 68, 440, 440, - 440, 440, 440, 440, 440, 440, 458, 458, 458, 458, - - 458, 458, 458, 458, 461, 61, 461, 461, 461, 461, - 461, 461, 461, 461, 54, 48, 47, 440, 441, 46, - 441, 441, 441, 441, 441, 441, 441, 441, 462, 462, - 462, 462, 462, 462, 462, 462, 462, 463, 463, 463, - 463, 463, 463, 463, 463, 463, 45, 44, 43, 441, - 454, 37, 454, 454, 454, 454, 454, 454, 454, 454, - 454, 457, 36, 457, 457, 457, 457, 457, 457, 457, - 457, 457, 35, 33, 29, 457, 457, 457, 457, 457, - 464, 464, 464, 464, 464, 464, 464, 464, 464, 23, - 17, 15, 14, 13, 457, 457, 457, 457, 457, 457, - - 460, 460, 460, 460, 460, 460, 460, 460, 0, 0, - 0, 0, 460, 460, 460, 460, 460, 474, 0, 0, - 0, 474, 0, 474, 474, 0, 0, 474, 0, 0, - 0, 460, 460, 460, 460, 460, 460, 0, 476, 474, - 474, 474, 476, 0, 476, 476, 0, 0, 476, 480, - 480, 480, 480, 480, 480, 480, 480, 0, 0, 0, - 476, 476, 476, 477, 0, 477, 477, 477, 477, 477, - 477, 477, 477, 0, 0, 0, 0, 482, 480, 482, - 482, 482, 482, 482, 482, 482, 482, 501, 501, 501, - 501, 501, 501, 501, 477, 478, 0, 478, 478, 478, - - 478, 478, 478, 478, 478, 483, 0, 483, 483, 483, - 483, 483, 483, 483, 483, 484, 0, 484, 484, 484, - 484, 484, 484, 484, 484, 0, 478, 479, 0, 479, - 479, 479, 479, 479, 479, 479, 479, 489, 489, 489, - 489, 489, 489, 489, 489, 495, 495, 495, 495, 495, - 495, 495, 495, 0, 0, 0, 0, 0, 479, 491, - 0, 491, 491, 491, 491, 491, 491, 491, 491, 491, - 494, 0, 494, 494, 494, 494, 494, 494, 494, 494, - 0, 0, 0, 0, 494, 494, 494, 494, 494, 497, - 0, 497, 497, 497, 497, 497, 497, 497, 497, 0, - - 0, 0, 0, 494, 494, 494, 494, 494, 494, 499, - 499, 499, 499, 499, 499, 499, 499, 499, 500, 500, - 500, 500, 500, 500, 500, 500, 500, 507, 507, 507, - 507, 507, 507, 507, 507, 0, 511, 0, 511, 511, - 511, 511, 511, 511, 512, 512, 512, 512, 512, 512, - 512, 512, 0, 0, 0, 0, 507, 509, 0, 509, - 509, 509, 509, 509, 509, 509, 509, 511, 514, 0, - 514, 514, 514, 514, 514, 514, 514, 514, 515, 0, - 515, 515, 515, 515, 515, 515, 515, 515, 509, 510, - 0, 510, 510, 510, 510, 510, 510, 510, 510, 516, - - 0, 516, 516, 516, 516, 516, 516, 522, 0, 522, - 522, 522, 522, 522, 522, 522, 522, 0, 0, 0, - 510, 526, 0, 526, 526, 526, 526, 526, 526, 526, - 526, 529, 529, 529, 529, 529, 529, 529, 529, 530, - 530, 530, 530, 530, 530, 530, 530, 0, 0, 0, - 0, 0, 526, 527, 0, 527, 527, 527, 527, 527, - 527, 527, 527, 531, 531, 531, 531, 531, 531, 531, - 531, 536, 536, 536, 536, 536, 536, 536, 536, 0, - 0, 0, 0, 0, 527, 528, 0, 528, 528, 528, - 528, 528, 528, 528, 528, 0, 0, 0, 0, 540, - - 536, 540, 540, 540, 540, 540, 540, 542, 542, 542, - 542, 542, 542, 542, 542, 0, 528, 538, 0, 538, - 538, 538, 538, 538, 538, 538, 538, 0, 0, 0, - 540, 543, 543, 543, 543, 543, 543, 543, 543, 548, - 548, 548, 548, 548, 548, 548, 548, 0, 538, 539, - 0, 539, 539, 539, 539, 539, 539, 539, 539, 549, - 549, 549, 549, 549, 549, 549, 549, 0, 548, 550, - 550, 550, 550, 550, 550, 550, 550, 0, 0, 0, - 539, 553, 553, 553, 553, 553, 553, 0, 549, 552, - 552, 552, 552, 552, 552, 552, 552, 0, 550, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 553, 0, 0, 0, 0, 0, 0, 0, 552, 555, - 555, 555, 555, 555, 555, 555, 555, 555, 555, 555, - 555, 555, 555, 556, 556, 556, 556, 556, 556, 556, - 556, 556, 556, 556, 556, 556, 556, 557, 557, 557, - 557, 557, 557, 557, 557, 557, 557, 557, 557, 557, - 557, 558, 558, 558, 558, 558, 558, 558, 558, 558, - 558, 558, 558, 558, 558, 559, 0, 0, 0, 559, - 0, 559, 559, 559, 0, 0, 559, 559, 559, 560, - 560, 0, 560, 560, 560, 560, 560, 560, 560, 560, - - 560, 560, 560, 561, 561, 561, 561, 561, 561, 561, - 561, 561, 561, 561, 561, 561, 561, 562, 0, 0, - 0, 562, 0, 562, 562, 562, 562, 0, 562, 562, - 562, 563, 0, 0, 0, 563, 0, 563, 563, 563, - 0, 0, 563, 563, 563, 564, 0, 0, 564, 564, - 564, 564, 564, 564, 0, 0, 564, 564, 564, 565, - 565, 0, 0, 0, 565, 566, 0, 0, 566, 566, - 566, 566, 566, 566, 0, 0, 566, 566, 566, 567, - 0, 0, 567, 567, 567, 567, 567, 567, 0, 567, - 0, 567, 567, 569, 0, 0, 569, 0, 569, 569, - - 569, 569, 569, 0, 569, 569, 569, 570, 570, 570, - 570, 570, 570, 570, 570, 570, 570, 570, 570, 570, - 570, 571, 571, 0, 571, 0, 571, 571, 571, 571, - 571, 571, 571, 571, 571, 572, 572, 0, 572, 572, - 572, 572, 572, 572, 572, 572, 572, 572, 572, 573, - 573, 573, 573, 573, 573, 573, 573, 573, 573, 573, - 573, 573, 573, 574, 574, 0, 574, 574, 574, 574, - 574, 574, 574, 574, 574, 574, 574, 575, 0, 0, - 0, 575, 0, 575, 575, 575, 0, 0, 575, 575, - 575, 576, 0, 0, 576, 576, 576, 576, 576, 576, - - 0, 0, 576, 576, 576, 577, 577, 0, 0, 0, - 577, 578, 578, 578, 0, 0, 0, 578, 579, 0, - 0, 579, 579, 579, 579, 579, 579, 0, 0, 579, - 579, 579, 580, 580, 580, 580, 580, 580, 580, 580, - 580, 580, 580, 580, 580, 580, 581, 581, 0, 0, - 0, 581, 582, 582, 582, 0, 0, 0, 582, 583, - 583, 0, 0, 0, 583, 584, 584, 0, 0, 0, - 584, 585, 585, 0, 0, 0, 585, 586, 586, 586, - 0, 0, 0, 586, 587, 587, 0, 0, 0, 587, - 588, 588, 0, 0, 0, 588, 589, 589, 0, 0, - - 0, 589, 590, 590, 590, 0, 0, 0, 590, 591, - 591, 591, 591, 0, 0, 0, 591, 592, 592, 0, - 0, 0, 592, 593, 593, 0, 0, 0, 593, 594, - 594, 0, 0, 0, 594, 595, 595, 595, 0, 0, - 0, 595, 596, 596, 596, 596, 0, 0, 0, 596, - 597, 597, 0, 0, 0, 597, 598, 598, 0, 0, - 0, 598, 599, 599, 599, 0, 0, 0, 599, 600, - 600, 600, 600, 0, 0, 0, 600, 601, 601, 0, - 0, 0, 601, 602, 0, 602, 602, 0, 0, 0, - 602, 603, 603, 603, 0, 0, 0, 603, 604, 604, - - 604, 604, 0, 0, 0, 604, 605, 605, 0, 0, - 0, 605, 606, 0, 606, 606, 0, 0, 0, 606, - 607, 607, 607, 0, 0, 0, 607, 608, 608, 608, - 0, 0, 0, 0, 608, 609, 0, 0, 609, 609, - 0, 609, 609, 609, 0, 0, 609, 609, 609, 610, - 0, 0, 610, 610, 0, 610, 610, 610, 0, 0, - 610, 610, 610, 611, 611, 0, 0, 0, 611, 612, - 0, 612, 612, 0, 0, 0, 612, 613, 613, 0, - 0, 0, 0, 613, 614, 614, 614, 614, 614, 614, - 614, 614, 614, 614, 614, 614, 614, 614, 615, 615, - - 0, 0, 0, 615, 616, 0, 616, 616, 0, 0, - 0, 616, 617, 617, 0, 0, 0, 617, 618, 0, - 618, 0, 0, 0, 0, 618, 620, 620, 620, 620, - 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - 554, 554, 554, 554, 554, 554, 554, 554, 554, 554, - - 554, 554, 554 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "toke.l" -#define INITIAL 0 -#line 2 "toke.l" -/* - * Copyright (c) 1996, 1998-2005, 2007-2010 - * Todd C. Miller - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 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 -#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 */ -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif -#include -#include "sudo.h" -#include "parse.h" -#include - -extern YYSTYPE yylval; -extern int parse_error; -int sudolineno = 1; -char *sudoers; -static int sawspace = 0; -static int arg_len = 0; -static int arg_size = 0; - -static int append __P((char *, int)); -static int _fill __P((char *, int, int)); -static int fill_cmnd __P((char *, int)); -static int fill_args __P((char *, int, int)); -static int _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 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_UNPUT 1 -#define GOTDEFS 1 - -#define GOTCMND 2 - -#define STARTDEFS 3 - -#define INDEFS 4 - -#define INSTR 5 - -#line 1475 "lex.yy.c" - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); -#else -extern int yywrap YY_PROTO(( void )); -#endif -#endif - -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if defined(YY_STACK_USED) && YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif - -#else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 -#endif - -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#ifdef __STDC__ -#ifndef __cplusplus -#include -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ - -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ - { \ - int c = '*', n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - if ( yyleng > 0 ) \ - yy_current_buffer->yy_at_bol = \ - (yytext[yyleng - 1] == '\n'); \ - YY_USER_ACTION - -YY_DECL - { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - -#line 127 "toke.l" - -#line 1631 "lex.yy.c" - - if ( yy_init ) - { - yy_init = 0; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yy_start ) - yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_load_buffer_state(); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yy_start; - yy_current_state += YY_AT_BOL(); -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 555 ) - 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] != 3541 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - - -do_action: /* This label is used only to access EOF actions. */ - - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yy_hold_char; - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 128 "toke.l" -BEGIN STARTDEFS; - YY_BREAK -case 2: -YY_RULE_SETUP -#line 130 "toke.l" -{ - BEGIN INDEFS; - LEXTRACE("DEFVAR "); - if (!fill(yytext, yyleng)) - yyterminate(); - return(DEFVAR); - } - YY_BREAK - -case 3: -YY_RULE_SETUP -#line 139 "toke.l" -{ - BEGIN STARTDEFS; - LEXTRACE(", "); - return(','); - } /* return ',' */ - YY_BREAK -case 4: -YY_RULE_SETUP -#line 145 "toke.l" -{ - LEXTRACE("= "); - return('='); - } /* return '=' */ - YY_BREAK -case 5: -YY_RULE_SETUP -#line 150 "toke.l" -{ - LEXTRACE("+= "); - return('+'); - } /* return '+' */ - YY_BREAK -case 6: -YY_RULE_SETUP -#line 155 "toke.l" -{ - LEXTRACE("-= "); - return('-'); - } /* return '-' */ - YY_BREAK -case 7: -YY_RULE_SETUP -#line 160 "toke.l" -{ - LEXTRACE("BEGINSTR "); - yylval.string = NULL; - BEGIN INSTR; - } - YY_BREAK -case 8: -YY_RULE_SETUP -#line 166 "toke.l" -{ - LEXTRACE("WORD(2) "); - if (!fill(yytext, yyleng)) - yyterminate(); - return(WORD); - } - YY_BREAK - - -case 9: -YY_RULE_SETUP -#line 175 "toke.l" -{ - /* Line continuation char followed by newline. */ - ++sudolineno; - LEXTRACE("\n"); - } - YY_BREAK -case 10: -YY_RULE_SETUP -#line 181 "toke.l" -{ - LEXTRACE("ENDSTR "); - BEGIN INDEFS; - return(WORD); - } - YY_BREAK -case 11: -YY_RULE_SETUP -#line 187 "toke.l" -{ - LEXTRACE("BACKSLASH "); - if (!append(yytext, yyleng)) - yyterminate(); - } - YY_BREAK -case 12: -YY_RULE_SETUP -#line 193 "toke.l" -{ - LEXTRACE("STRBODY "); - if (!append(yytext, yyleng)) - yyterminate(); - } - YY_BREAK - - -case 13: -YY_RULE_SETUP -#line 201 "toke.l" -{ - /* quoted fnmatch glob char, pass verbatim */ - LEXTRACE("QUOTEDCHAR "); - if (!fill_args(yytext, 2, sawspace)) - yyterminate(); - sawspace = FALSE; - } - YY_BREAK -case 14: -YY_RULE_SETUP -#line 209 "toke.l" -{ - /* quoted sudoers special char, strip backslash */ - LEXTRACE("QUOTEDCHAR "); - if (!fill_args(yytext + 1, 1, sawspace)) - yyterminate(); - sawspace = FALSE; - } - YY_BREAK -case 15: -YY_RULE_SETUP -#line 217 "toke.l" -{ - BEGIN INITIAL; - yyless(0); - return(COMMAND); - } /* end of command line args */ - YY_BREAK -case 16: -YY_RULE_SETUP -#line 223 "toke.l" -{ - LEXTRACE("ARG "); - if (!fill_args(yytext, yyleng, sawspace)) - yyterminate(); - sawspace = FALSE; - } /* a command line arg */ - YY_BREAK - -case 17: -YY_RULE_SETUP -#line 231 "toke.l" -{ - char *path; - - if ((path = parse_include(yytext)) == NULL) - yyterminate(); - - LEXTRACE("INCLUDE\n"); - - /* Push current buffer and switch to include file */ - if (!push_include(path)) - yyterminate(); - } - YY_BREAK -case 18: -YY_RULE_SETUP -#line 244 "toke.l" -{ - char *path; - - if ((path = parse_include(yytext)) == NULL) - yyterminate(); - - LEXTRACE("INCLUDEDIR\n"); - - /* - * Push current buffer and switch to include file. - * We simply ignore empty directories. - */ - if (!push_includedir(path) && parse_error) - yyterminate(); - } - YY_BREAK -case 19: -YY_RULE_SETUP -#line 260 "toke.l" -{ - int n; - for (n = 0; isblank((unsigned char)yytext[n]); n++) - continue; - n += 8; - BEGIN GOTDEFS; - switch (yytext[n++]) { - case ':': - yyless(n); - LEXTRACE("DEFAULTS_USER "); - return(DEFAULTS_USER); - case '>': - yyless(n); - LEXTRACE("DEFAULTS_RUNAS "); - return(DEFAULTS_RUNAS); - case '@': - yyless(n); - LEXTRACE("DEFAULTS_HOST "); - return(DEFAULTS_HOST); - case '!': - yyless(n); - LEXTRACE("DEFAULTS_CMND "); - return(DEFAULTS_CMND); - default: - LEXTRACE("DEFAULTS "); - return(DEFAULTS); - } - } - YY_BREAK -case 20: -YY_RULE_SETUP -#line 289 "toke.l" -{ - int n; - for (n = 0; isblank((unsigned char)yytext[n]); n++) - continue; - switch (yytext[n]) { - case 'H': - LEXTRACE("HOSTALIAS "); - return(HOSTALIAS); - case 'C': - LEXTRACE("CMNDALIAS "); - return(CMNDALIAS); - case 'U': - LEXTRACE("USERALIAS "); - return(USERALIAS); - case 'R': - LEXTRACE("RUNASALIAS "); - return(RUNASALIAS); - } - } - YY_BREAK -case 21: -YY_RULE_SETUP -#line 309 "toke.l" -{ - /* cmnd does not require passwd for this user */ - LEXTRACE("NOPASSWD "); - return(NOPASSWD); - } - YY_BREAK -case 22: -YY_RULE_SETUP -#line 315 "toke.l" -{ - /* cmnd requires passwd for this user */ - LEXTRACE("PASSWD "); - return(PASSWD); - } - YY_BREAK -case 23: -YY_RULE_SETUP -#line 321 "toke.l" -{ - LEXTRACE("NOEXEC "); - return(NOEXEC); - } - YY_BREAK -case 24: -YY_RULE_SETUP -#line 326 "toke.l" -{ - LEXTRACE("EXEC "); - return(EXEC); - } - YY_BREAK -case 25: -YY_RULE_SETUP -#line 331 "toke.l" -{ - LEXTRACE("SETENV "); - return(SETENV); - } - YY_BREAK -case 26: -YY_RULE_SETUP -#line 336 "toke.l" -{ - LEXTRACE("NOSETENV "); - return(NOSETENV); - } - YY_BREAK -case 27: -YY_RULE_SETUP -#line 341 "toke.l" -{ - /* netgroup */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NETGROUP "); - return(NETGROUP); - } - YY_BREAK -case 28: -YY_RULE_SETUP -#line 349 "toke.l" -{ - /* UN*X group */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("USERGROUP "); - return(USERGROUP); - } - YY_BREAK -case 29: -YY_RULE_SETUP -#line 357 "toke.l" -{ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - YY_BREAK -case 30: -YY_RULE_SETUP -#line 364 "toke.l" -{ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - YY_BREAK -case 31: -YY_RULE_SETUP -#line 371 "toke.l" -{ - if (!ipv6_valid(yytext)) { - LEXTRACE("ERROR "); - return(ERROR); - } - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - YY_BREAK -case 32: -YY_RULE_SETUP -#line 382 "toke.l" -{ - if (!ipv6_valid(yytext)) { - LEXTRACE("ERROR "); - return(ERROR); - } - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - YY_BREAK -case 33: -YY_RULE_SETUP -#line 393 "toke.l" -{ - if (strcmp(yytext, "ALL") == 0) { - LEXTRACE("ALL "); - return(ALL); - } -#ifdef HAVE_SELINUX - /* XXX - restrict type/role to initial state */ - if (strcmp(yytext, "TYPE") == 0) { - LEXTRACE("TYPE "); - return(TYPE); - } - if (strcmp(yytext, "ROLE") == 0) { - LEXTRACE("ROLE "); - return(ROLE); - } -#endif /* HAVE_SELINUX */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("ALIAS "); - return(ALIAS); - } - YY_BREAK -case 34: -YY_RULE_SETUP -#line 415 "toke.l" -{ - /* no command args allowed for Defaults!/path */ - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - LEXTRACE("COMMAND "); - return(COMMAND); - } - YY_BREAK -case 35: -YY_RULE_SETUP -#line 423 "toke.l" -{ - BEGIN GOTCMND; - LEXTRACE("COMMAND "); - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - } /* sudo -e */ - YY_BREAK -case 36: -YY_RULE_SETUP -#line 430 "toke.l" -{ - /* directories can't have args... */ - if (yytext[yyleng - 1] == '/') { - LEXTRACE("COMMAND "); - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - return(COMMAND); - } else { - BEGIN GOTCMND; - LEXTRACE("COMMAND "); - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - } - } /* a pathname */ - YY_BREAK -case 37: -YY_RULE_SETUP -#line 445 "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); - } - } - YY_BREAK -case 38: -YY_RULE_SETUP -#line 462 "toke.l" -{ - /* a word */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("WORD(5) "); - return(WORD); - } - YY_BREAK -case 39: -YY_RULE_SETUP -#line 470 "toke.l" -{ - LEXTRACE("( "); - return ('('); - } - YY_BREAK -case 40: -YY_RULE_SETUP -#line 475 "toke.l" -{ - LEXTRACE(") "); - return(')'); - } - YY_BREAK -case 41: -YY_RULE_SETUP -#line 480 "toke.l" -{ - LEXTRACE(", "); - return(','); - } /* return ',' */ - YY_BREAK -case 42: -YY_RULE_SETUP -#line 485 "toke.l" -{ - LEXTRACE("= "); - return('='); - } /* return '=' */ - YY_BREAK -case 43: -YY_RULE_SETUP -#line 490 "toke.l" -{ - LEXTRACE(": "); - return(':'); - } /* return ':' */ - YY_BREAK -case 44: -YY_RULE_SETUP -#line 495 "toke.l" -{ - if (yyleng % 2 == 1) - return('!'); /* return '!' */ - } - YY_BREAK -case 45: -YY_RULE_SETUP -#line 500 "toke.l" -{ - BEGIN INITIAL; - ++sudolineno; - LEXTRACE("\n"); - return(COMMENT); - } /* return newline */ - YY_BREAK -case 46: -YY_RULE_SETUP -#line 507 "toke.l" -{ /* throw away space/tabs */ - sawspace = TRUE; /* but remember for fill_args */ - } - YY_BREAK -case 47: -YY_RULE_SETUP -#line 511 "toke.l" -{ - sawspace = TRUE; /* remember for fill_args */ - ++sudolineno; - LEXTRACE("\n\t"); - } /* throw away EOL after \ */ - YY_BREAK -case 48: -YY_RULE_SETUP -#line 517 "toke.l" -{ - BEGIN INITIAL; - ++sudolineno; - LEXTRACE("\n"); - return(COMMENT); - } /* comment, not uid/gid */ - YY_BREAK -case 49: -YY_RULE_SETUP -#line 524 "toke.l" -{ - LEXTRACE("ERROR "); - return(ERROR); - } /* parse error */ - YY_BREAK -case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(GOTDEFS): -case YY_STATE_EOF(GOTCMND): -case YY_STATE_EOF(STARTDEFS): -case YY_STATE_EOF(INDEFS): -case YY_STATE_EOF(INSTR): -#line 529 "toke.l" -{ - if (YY_START != INITIAL) { - BEGIN INITIAL; - LEXTRACE("ERROR "); - return(ERROR); - } - if (!pop_include()) - yyterminate(); - } - YY_BREAK -case 50: -YY_RULE_SETUP -#line 539 "toke.l" -ECHO; - YY_BREAK -#line 2285 "lex.yy.c" - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer() ) - { - case EOB_ACT_END_OF_FILE: - { - yy_did_buffer_switch_on_eof = 0; - - if ( yywrap() ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of yylex */ - - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( yy_current_buffer->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; - - else - { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; - - int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = yy_current_buffer->yy_buf_size - - number_to_move - 1; -#endif - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); - - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - if ( yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; - - return ret_val; - } - - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -static yy_state_type yy_get_previous_state() - { - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = yy_start; - yy_current_state += YY_AT_BOL(); - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 555 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; - } - - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { - register int yy_is_jam; - register char *yy_cp = yy_c_buf_p; - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 555 ) - 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 == 554); - - return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - - -#ifdef __cplusplus -static int yyinput() -#else -static int input() -#endif - { - int c; - - *yy_c_buf_p = yy_hold_char; - - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - /* This was really a NUL. */ - *yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; - - switch ( yy_get_next_buffer() ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin ); - - /* fall through */ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap() ) - return EOF; - - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - - yy_current_buffer->yy_at_bol = (c == '\n'); - - return c; - } - - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); - } - - -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) - return; - - if ( yy_current_buffer ) - { - /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - yy_current_buffer = new_buffer; - yy_load_buffer_state(); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } - - -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file ); - - return b; - } - - -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { - if ( ! b ) - return; - - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -#include -#endif -#endif - -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - int oerrno = errno; - - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - -#if defined(YY_ALWAYS_INTERACTIVE) && YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if defined(YY_NEVER_INTERACTIVE) && YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - errno = oerrno; - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif - - { - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == yy_current_buffer ) - yy_load_buffer_state(); - } - - -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b ); - - return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif - - -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; - } -#endif - - -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); - - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); - - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } - - yy_start_stack[yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); - } -#endif - - -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif - - -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } - - - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) - - -/* Internal utility routines. */ - -#ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; - } -#endif - -#ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; - } -#endif - - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { - return (void *) malloc( size ); - } - -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); - } - -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } - -#if defined(YY_MAIN) && YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 539 "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); -} - -struct path_list { - char *path; - struct path_list *next; -}; - -struct include_stack { - YY_BUFFER_STATE bs; - char *path; - struct path_list *more; /* more files in case of includedir */ - int lineno; - int keepopen; -}; - -static int -pl_compare(v1, v2) - const void *v1; - const void *v2; -{ - const struct path_list * const *p1 = v1; - const struct path_list * const *p2 = v2; - - return(strcmp((*p1)->path, (*p2)->path)); -} - -static char * -switch_dir(stack, dirpath) - struct include_stack *stack; - char *dirpath; -{ - DIR *dir; - int i, count = 0; - char *path = NULL; - struct dirent *dent; - struct stat sb; - struct path_list *pl, *first = NULL; - struct path_list **sorted = NULL; - - if (!(dir = opendir(dirpath))) { - yyerror(dirpath); - return(NULL); - } - while ((dent = readdir(dir))) { - /* Ignore files that end in '~' or have a '.' in them. */ - if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~' - || strchr(dent->d_name, '.') != NULL) { - continue; - } - if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) { - closedir(dir); - goto bad; - } - if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) { - efree(path); - continue; - } - pl = malloc(sizeof(*pl)); - if (pl == NULL) - goto bad; - pl->path = path; - pl->next = first; - first = pl; - count++; - } - closedir(dir); - - if (count == 0) - goto done; - - /* Sort the list as an array. */ - sorted = malloc(sizeof(*sorted) * count); - if (sorted == NULL) - goto bad; - pl = first; - for (i = 0; i < count; i++) { - sorted[i] = pl; - pl = pl->next; - } - qsort(sorted, count, sizeof(*sorted), pl_compare); - - /* Apply sorting to the list. */ - first = sorted[0]; - sorted[count - 1]->next = NULL; - for (i = 1; i < count; i++) - sorted[i - 1]->next = sorted[i]; - efree(sorted); - - /* Pull out the first element for parsing, leave the rest for later. */ - if (count) { - path = first->path; - pl = first->next; - efree(first); - stack->more = pl; - } else { - path = NULL; - } -done: - efree(dirpath); - return(path); -bad: - while (first != NULL) { - pl = first; - first = pl->next; - free(pl->path); - free(pl); - } - efree(sorted); - efree(dirpath); - efree(path); - return(NULL); -} - -#define MAX_SUDOERS_DEPTH 128 -#define SUDOERS_STACK_INCREMENT 16 - -static size_t istacksize, idepth; -static struct include_stack *istack; -static int keepopen; - -void -init_lexer() -{ - struct path_list *pl; - - while (idepth) { - idepth--; - while ((pl = istack[idepth].more) != NULL) { - istack[idepth].more = pl->next; - efree(pl->path); - efree(pl); - } - efree(istack[idepth].path); - if (idepth && !istack[idepth].keepopen) - fclose(istack[idepth].bs->yy_input_file); - yy_delete_buffer(istack[idepth].bs); - } - efree(istack); - istack = NULL; - istacksize = idepth = 0; - keepopen = FALSE; -} - -static int -_push_include(path, isdir) - char *path; - int isdir; -{ - struct path_list *pl; - FILE *fp; - - /* push current state onto stack */ - if (idepth >= istacksize) { - if (idepth > MAX_SUDOERS_DEPTH) { - yyerror("too many levels of includes"); - return(FALSE); - } - istacksize += SUDOERS_STACK_INCREMENT; - istack = (struct include_stack *) realloc(istack, - sizeof(*istack) * istacksize); - if (istack == NULL) { - yyerror("unable to allocate memory"); - return(FALSE); - } - } - if (isdir) { - if (!(path = switch_dir(&istack[idepth], path))) { - /* switch_dir() called yyerror() for us */ - return(FALSE); - } - while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) { - /* Unable to open path in includedir, go to next one, if any. */ - efree(path); - if ((pl = istack[idepth].more) == NULL) - return(FALSE); - path = pl->path; - istack[idepth].more = pl->next; - efree(pl); - } - } else { - if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) { - yyerror(path); - return(FALSE); - } - istack[idepth].more = NULL; - } - /* Push the old (current) file and open the new one. */ - istack[idepth].path = sudoers; /* push old path */ - istack[idepth].bs = YY_CURRENT_BUFFER; - istack[idepth].lineno = sudolineno; - istack[idepth].keepopen = keepopen; - idepth++; - sudolineno = 1; - sudoers = path; - yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); - - return(TRUE); -} - -static int -pop_include() -{ - struct path_list *pl; - FILE *fp; - - if (idepth == 0) - return(FALSE); - - if (!keepopen) - fclose(YY_CURRENT_BUFFER->yy_input_file); - yy_delete_buffer(YY_CURRENT_BUFFER); - /* If we are in an include dir, move to the next file. */ - while ((pl = istack[idepth - 1].more) != NULL) { - fp = open_sudoers(pl->path, FALSE, &keepopen); - if (fp != NULL) { - istack[idepth - 1].more = pl->next; - efree(sudoers); - sudoers = pl->path; - sudolineno = 1; - yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); - efree(pl); - break; - } - /* Unable to open path in include dir, go to next one. */ - istack[idepth - 1].more = pl->next; - efree(pl->path); - efree(pl); - } - /* If no path list, just pop the last dir on the stack. */ - if (pl == NULL) { - idepth--; - yy_switch_to_buffer(istack[idepth].bs); - efree(sudoers); - sudoers = istack[idepth].path; - sudolineno = istack[idepth].lineno; - keepopen = istack[idepth].keepopen; - } - return(TRUE); -} - -static char * -parse_include(base) - char *base; -{ - char *cp, *ep, *path; - int len = 0, subst = 0; - size_t shost_len = 0; - - /* Pull out path from #include line. */ - cp = base + sizeof("#include"); - if (*cp == 'i') - cp += 3; /* includedir */ - while (isblank((unsigned char) *cp)) - cp++; - ep = cp; - while (*ep != '\0' && !isspace((unsigned char) *ep)) { - if (ep[0] == '%' && ep[1] == 'h') { - shost_len = strlen(user_shost); - len += shost_len - 2; - subst = 1; - } - ep++; - } - - /* Make a copy of path and return it. */ - len += (int)(ep - cp); - if ((path = malloc(len + 1)) == NULL) - yyerror("unable to allocate memory"); - if (subst) { - /* substitute for %h */ - char *pp = path; - while (cp < ep) { - if (cp[0] == '%' && cp[1] == 'h') { - memcpy(pp, user_shost, shost_len); - pp += shost_len; - cp += 2; - continue; - } - *pp++ = *cp++; - } - *pp = '\0'; - } else { - memcpy(path, cp, len); - path[len] = '\0'; - } - - /* Push any excess characters (e.g. comment, newline) back to the lexer */ - if (*ep != '\0') - yyless((int)(ep - base)); - - return(path); -} - -/* - * Check to make sure an IPv6 address does not contain multiple instances - * of the string "::". Assumes strlen(s) >= 1. - * Returns TRUE if address is valid else FALSE. - */ -static int -ipv6_valid(s) - const char *s; -{ - int nmatch = 0; - - for (; *s != '\0'; s++) { - if (s[0] == ':' && s[1] == ':') { - if (++nmatch > 1) - break; - } - if (s[0] == '/') - nmatch = 0; /* reset if we hit netmask */ - } - - return (nmatch <= 1); -} diff --git a/toke.l b/toke.l deleted file mode 100644 index ce1fd4c..0000000 --- a/toke.l +++ /dev/null @@ -1,1023 +0,0 @@ -%{ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - * 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 -#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 */ -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) -#else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -#endif -#include -#include "sudo.h" -#include "parse.h" -#include - -extern YYSTYPE yylval; -extern int parse_error; -int sudolineno = 1; -char *sudoers; -static int sawspace = 0; -static int arg_len = 0; -static int arg_size = 0; - -static int append __P((char *, int)); -static int _fill __P((char *, int, int)); -static int fill_cmnd __P((char *, int)); -static int fill_args __P((char *, int, int)); -static int _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 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 -%} - -HEX16 [0-9A-Fa-f]{1,4} -OCTET (1?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]) -IPV4ADDR {OCTET}(\.{OCTET}){3} -IPV6ADDR ({HEX16}?:){2,7}{HEX16}?|({HEX16}?:){2,6}:{IPV4ADDR} - -HOSTNAME [[:alnum:]_-]+ -WORD ([^#>!=:,\(\) \t\n\\]|\\[^\n])+ -ID #-?[0-9]+ -PATH \/(\\[\,:= \t#]|[^\,:=\\ \t\n#])+ -ENVAR ([^#!=, \t\n\\\"]|\\[^\n])([^#=, \t\n\\\"]|\\[^\n])* -DEFVAR [a-z_]+ - -%option nounput -%option noyywrap - -%s GOTDEFS -%x GOTCMND -%x STARTDEFS -%x INDEFS -%x INSTR - -%% -[[:blank:]]+ BEGIN STARTDEFS; - -{DEFVAR} { - BEGIN INDEFS; - LEXTRACE("DEFVAR "); - if (!fill(yytext, yyleng)) - yyterminate(); - return(DEFVAR); - } - -{ - , { - BEGIN STARTDEFS; - LEXTRACE(", "); - return(','); - } /* return ',' */ - - = { - LEXTRACE("= "); - return('='); - } /* return '=' */ - - \+= { - LEXTRACE("+= "); - return('+'); - } /* return '+' */ - - -= { - LEXTRACE("-= "); - return('-'); - } /* return '-' */ - - \" { - LEXTRACE("BEGINSTR "); - yylval.string = NULL; - BEGIN INSTR; - } - - {ENVAR} { - LEXTRACE("WORD(2) "); - if (!fill(yytext, yyleng)) - yyterminate(); - return(WORD); - } -} - -{ - \\[[:blank:]]*\n[[:blank:]]* { - /* Line continuation char followed by newline. */ - ++sudolineno; - LEXTRACE("\n"); - } - - \" { - LEXTRACE("ENDSTR "); - BEGIN INDEFS; - return(WORD); - } - - \\ { - LEXTRACE("BACKSLASH "); - if (!append(yytext, yyleng)) - yyterminate(); - } - - ([^\"\n\\]|\\\")+ { - LEXTRACE("STRBODY "); - if (!append(yytext, yyleng)) - yyterminate(); - } -} - -{ - \\[\*\?\[\]\!] { - /* quoted fnmatch glob char, pass verbatim */ - LEXTRACE("QUOTEDCHAR "); - if (!fill_args(yytext, 2, sawspace)) - yyterminate(); - sawspace = FALSE; - } - - \\[:\\,= \t#] { - /* quoted sudoers special char, strip backslash */ - LEXTRACE("QUOTEDCHAR "); - if (!fill_args(yytext + 1, 1, sawspace)) - yyterminate(); - sawspace = FALSE; - } - - [#:\,=\n] { - BEGIN INITIAL; - yyless(0); - return(COMMAND); - } /* end of command line args */ - - [^#\\:, \t\n]+ { - LEXTRACE("ARG "); - if (!fill_args(yytext, yyleng, sawspace)) - yyterminate(); - sawspace = FALSE; - } /* a command line arg */ -} - -^#include[[:blank:]]+\/.*\n { - char *path; - - if ((path = parse_include(yytext)) == NULL) - yyterminate(); - - LEXTRACE("INCLUDE\n"); - - /* Push current buffer and switch to include file */ - if (!push_include(path)) - yyterminate(); - } - -^#includedir[[:blank:]]+\/.*\n { - char *path; - - if ((path = parse_include(yytext)) == NULL) - yyterminate(); - - LEXTRACE("INCLUDEDIR\n"); - - /* - * Push current buffer and switch to include file. - * We simply ignore empty directories. - */ - if (!push_includedir(path) && parse_error) - yyterminate(); - } - -^[[:blank:]]*Defaults([:@>\!]\!?{WORD})? { - int n; - for (n = 0; isblank((unsigned char)yytext[n]); n++) - continue; - n += 8; - BEGIN GOTDEFS; - switch (yytext[n++]) { - case ':': - yyless(n); - LEXTRACE("DEFAULTS_USER "); - return(DEFAULTS_USER); - case '>': - yyless(n); - LEXTRACE("DEFAULTS_RUNAS "); - return(DEFAULTS_RUNAS); - case '@': - yyless(n); - LEXTRACE("DEFAULTS_HOST "); - return(DEFAULTS_HOST); - case '!': - yyless(n); - LEXTRACE("DEFAULTS_CMND "); - return(DEFAULTS_CMND); - default: - LEXTRACE("DEFAULTS "); - return(DEFAULTS); - } - } - -^[[:blank:]]*(Host|Cmnd|User|Runas)_Alias { - int n; - for (n = 0; isblank((unsigned char)yytext[n]); n++) - continue; - switch (yytext[n]) { - case 'H': - LEXTRACE("HOSTALIAS "); - return(HOSTALIAS); - case 'C': - LEXTRACE("CMNDALIAS "); - return(CMNDALIAS); - case 'U': - LEXTRACE("USERALIAS "); - return(USERALIAS); - case 'R': - LEXTRACE("RUNASALIAS "); - return(RUNASALIAS); - } - } - -NOPASSWD[[:blank:]]*: { - /* cmnd does not require passwd for this user */ - LEXTRACE("NOPASSWD "); - return(NOPASSWD); - } - -PASSWD[[:blank:]]*: { - /* cmnd requires passwd for this user */ - LEXTRACE("PASSWD "); - return(PASSWD); - } - -NOEXEC[[:blank:]]*: { - LEXTRACE("NOEXEC "); - return(NOEXEC); - } - -EXEC[[:blank:]]*: { - LEXTRACE("EXEC "); - return(EXEC); - } - -SETENV[[:blank:]]*: { - LEXTRACE("SETENV "); - return(SETENV); - } - -NOSETENV[[:blank:]]*: { - LEXTRACE("NOSETENV "); - return(NOSETENV); - } - -\+{WORD} { - /* netgroup */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NETGROUP "); - return(NETGROUP); - } - -\%:?{WORD} { - /* UN*X group */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("USERGROUP "); - return(USERGROUP); - } - -{IPV4ADDR}(\/{IPV4ADDR})? { - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - -{IPV4ADDR}\/([12][0-9]*|3[0-2]*) { - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - -{IPV6ADDR}(\/{IPV6ADDR})? { - if (!ipv6_valid(yytext)) { - LEXTRACE("ERROR "); - return(ERROR); - } - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - -{IPV6ADDR}\/([0-9]|[1-9][0-9]|1[01][0-9]|12[0-8]) { - if (!ipv6_valid(yytext)) { - LEXTRACE("ERROR "); - return(ERROR); - } - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("NTWKADDR "); - return(NTWKADDR); - } - -[[:upper:]][[:upper:][:digit:]_]* { - if (strcmp(yytext, "ALL") == 0) { - LEXTRACE("ALL "); - return(ALL); - } -#ifdef HAVE_SELINUX - /* XXX - restrict type/role to initial state */ - if (strcmp(yytext, "TYPE") == 0) { - LEXTRACE("TYPE "); - return(TYPE); - } - if (strcmp(yytext, "ROLE") == 0) { - LEXTRACE("ROLE "); - return(ROLE); - } -#endif /* HAVE_SELINUX */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("ALIAS "); - return(ALIAS); - } - -({PATH}|sudoedit) { - /* no command args allowed for Defaults!/path */ - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - LEXTRACE("COMMAND "); - return(COMMAND); - } - -sudoedit { - BEGIN GOTCMND; - LEXTRACE("COMMAND "); - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - } /* sudo -e */ - -{PATH} { - /* directories can't have args... */ - if (yytext[yyleng - 1] == '/') { - LEXTRACE("COMMAND "); - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - return(COMMAND); - } else { - BEGIN GOTCMND; - LEXTRACE("COMMAND "); - if (!fill_cmnd(yytext, yyleng)) - yyterminate(); - } - } /* a pathname */ - -\"[^"\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); - } - } - -({ID}|{WORD}) { - /* a word */ - if (!fill(yytext, yyleng)) - yyterminate(); - LEXTRACE("WORD(5) "); - return(WORD); - } - -\( { - LEXTRACE("( "); - return ('('); - } - -\) { - LEXTRACE(") "); - return(')'); - } - -, { - LEXTRACE(", "); - return(','); - } /* return ',' */ - -= { - LEXTRACE("= "); - return('='); - } /* return '=' */ - -: { - LEXTRACE(": "); - return(':'); - } /* return ':' */ - -<*>!+ { - if (yyleng % 2 == 1) - return('!'); /* return '!' */ - } - -<*>\n { - BEGIN INITIAL; - ++sudolineno; - LEXTRACE("\n"); - return(COMMENT); - } /* return newline */ - -<*>[[:blank:]]+ { /* throw away space/tabs */ - sawspace = TRUE; /* but remember for fill_args */ - } - -<*>\\[[:blank:]]*\n { - sawspace = TRUE; /* remember for fill_args */ - ++sudolineno; - LEXTRACE("\n\t"); - } /* throw away EOL after \ */ - -#(-[^\n0-9].*|[^\n0-9-].*)?\n { - BEGIN INITIAL; - ++sudolineno; - LEXTRACE("\n"); - return(COMMENT); - } /* comment, not uid/gid */ - -<*>. { - LEXTRACE("ERROR "); - return(ERROR); - } /* parse error */ - -<*><> { - if (YY_START != INITIAL) { - BEGIN INITIAL; - LEXTRACE("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; -}; - -struct include_stack { - YY_BUFFER_STATE bs; - char *path; - struct path_list *more; /* more files in case of includedir */ - int lineno; - int keepopen; -}; - -static int -pl_compare(v1, v2) - const void *v1; - const void *v2; -{ - const struct path_list * const *p1 = v1; - const struct path_list * const *p2 = v2; - - return(strcmp((*p1)->path, (*p2)->path)); -} - -static char * -switch_dir(stack, dirpath) - struct include_stack *stack; - char *dirpath; -{ - DIR *dir; - int i, count = 0; - char *path = NULL; - struct dirent *dent; - struct stat sb; - struct path_list *pl, *first = NULL; - struct path_list **sorted = NULL; - - if (!(dir = opendir(dirpath))) { - yyerror(dirpath); - return(NULL); - } - while ((dent = readdir(dir))) { - /* Ignore files that end in '~' or have a '.' in them. */ - if (dent->d_name[0] == '\0' || dent->d_name[NAMLEN(dent) - 1] == '~' - || strchr(dent->d_name, '.') != NULL) { - continue; - } - if (asprintf(&path, "%s/%s", dirpath, dent->d_name) == -1) { - closedir(dir); - goto bad; - } - if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)) { - efree(path); - continue; - } - pl = malloc(sizeof(*pl)); - if (pl == NULL) - goto bad; - pl->path = path; - pl->next = first; - first = pl; - count++; - } - closedir(dir); - - if (count == 0) - goto done; - - /* Sort the list as an array. */ - sorted = malloc(sizeof(*sorted) * count); - if (sorted == NULL) - goto bad; - pl = first; - for (i = 0; i < count; i++) { - sorted[i] = pl; - pl = pl->next; - } - qsort(sorted, count, sizeof(*sorted), pl_compare); - - /* Apply sorting to the list. */ - first = sorted[0]; - sorted[count - 1]->next = NULL; - for (i = 1; i < count; i++) - sorted[i - 1]->next = sorted[i]; - efree(sorted); - - /* Pull out the first element for parsing, leave the rest for later. */ - if (count) { - path = first->path; - pl = first->next; - efree(first); - stack->more = pl; - } else { - path = NULL; - } -done: - efree(dirpath); - return(path); -bad: - while (first != NULL) { - pl = first; - first = pl->next; - free(pl->path); - free(pl); - } - efree(sorted); - efree(dirpath); - efree(path); - return(NULL); -} - -#define MAX_SUDOERS_DEPTH 128 -#define SUDOERS_STACK_INCREMENT 16 - -static size_t istacksize, idepth; -static struct include_stack *istack; -static int keepopen; - -void -init_lexer() -{ - struct path_list *pl; - - while (idepth) { - idepth--; - while ((pl = istack[idepth].more) != NULL) { - istack[idepth].more = pl->next; - efree(pl->path); - efree(pl); - } - efree(istack[idepth].path); - if (idepth && !istack[idepth].keepopen) - fclose(istack[idepth].bs->yy_input_file); - yy_delete_buffer(istack[idepth].bs); - } - efree(istack); - istack = NULL; - istacksize = idepth = 0; - keepopen = FALSE; -} - -static int -_push_include(path, isdir) - char *path; - int isdir; -{ - struct path_list *pl; - FILE *fp; - - /* push current state onto stack */ - if (idepth >= istacksize) { - if (idepth > MAX_SUDOERS_DEPTH) { - yyerror("too many levels of includes"); - return(FALSE); - } - istacksize += SUDOERS_STACK_INCREMENT; - istack = (struct include_stack *) realloc(istack, - sizeof(*istack) * istacksize); - if (istack == NULL) { - yyerror("unable to allocate memory"); - return(FALSE); - } - } - if (isdir) { - if (!(path = switch_dir(&istack[idepth], path))) { - /* switch_dir() called yyerror() for us */ - return(FALSE); - } - while ((fp = open_sudoers(path, FALSE, &keepopen)) == NULL) { - /* Unable to open path in includedir, go to next one, if any. */ - efree(path); - if ((pl = istack[idepth].more) == NULL) - return(FALSE); - path = pl->path; - istack[idepth].more = pl->next; - efree(pl); - } - } else { - if ((fp = open_sudoers(path, TRUE, &keepopen)) == NULL) { - yyerror(path); - return(FALSE); - } - istack[idepth].more = NULL; - } - /* Push the old (current) file and open the new one. */ - istack[idepth].path = sudoers; /* push old path */ - istack[idepth].bs = YY_CURRENT_BUFFER; - istack[idepth].lineno = sudolineno; - istack[idepth].keepopen = keepopen; - idepth++; - sudolineno = 1; - sudoers = path; - yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); - - return(TRUE); -} - -static int -pop_include() -{ - struct path_list *pl; - FILE *fp; - - if (idepth == 0) - return(FALSE); - - if (!keepopen) - fclose(YY_CURRENT_BUFFER->yy_input_file); - yy_delete_buffer(YY_CURRENT_BUFFER); - /* If we are in an include dir, move to the next file. */ - while ((pl = istack[idepth - 1].more) != NULL) { - fp = open_sudoers(pl->path, FALSE, &keepopen); - if (fp != NULL) { - istack[idepth - 1].more = pl->next; - efree(sudoers); - sudoers = pl->path; - sudolineno = 1; - yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE)); - efree(pl); - break; - } - /* Unable to open path in include dir, go to next one. */ - istack[idepth - 1].more = pl->next; - efree(pl->path); - efree(pl); - } - /* If no path list, just pop the last dir on the stack. */ - if (pl == NULL) { - idepth--; - yy_switch_to_buffer(istack[idepth].bs); - efree(sudoers); - sudoers = istack[idepth].path; - sudolineno = istack[idepth].lineno; - keepopen = istack[idepth].keepopen; - } - return(TRUE); -} - -static char * -parse_include(base) - char *base; -{ - char *cp, *ep, *path; - int len = 0, subst = 0; - size_t shost_len = 0; - - /* Pull out path from #include line. */ - cp = base + sizeof("#include"); - if (*cp == 'i') - cp += 3; /* includedir */ - while (isblank((unsigned char) *cp)) - cp++; - ep = cp; - while (*ep != '\0' && !isspace((unsigned char) *ep)) { - if (ep[0] == '%' && ep[1] == 'h') { - shost_len = strlen(user_shost); - len += shost_len - 2; - subst = 1; - } - ep++; - } - - /* Make a copy of path and return it. */ - len += (int)(ep - cp); - if ((path = malloc(len + 1)) == NULL) - yyerror("unable to allocate memory"); - if (subst) { - /* substitute for %h */ - char *pp = path; - while (cp < ep) { - if (cp[0] == '%' && cp[1] == 'h') { - memcpy(pp, user_shost, shost_len); - pp += shost_len; - cp += 2; - continue; - } - *pp++ = *cp++; - } - *pp = '\0'; - } else { - memcpy(path, cp, len); - path[len] = '\0'; - } - - /* Push any excess characters (e.g. comment, newline) back to the lexer */ - if (*ep != '\0') - yyless((int)(ep - base)); - - return(path); -} - -/* - * Check to make sure an IPv6 address does not contain multiple instances - * of the string "::". Assumes strlen(s) >= 1. - * Returns TRUE if address is valid else FALSE. - */ -static int -ipv6_valid(s) - const char *s; -{ - int nmatch = 0; - - for (; *s != '\0'; s++) { - if (s[0] == ':' && s[1] == ':') { - if (++nmatch > 1) - break; - } - if (s[0] == '/') - nmatch = 0; /* reset if we hit netmask */ - } - - return (nmatch <= 1); -} diff --git a/tsgetgrpw.c b/tsgetgrpw.c deleted file mode 100644 index 6f14d3f..0000000 --- a/tsgetgrpw.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (c) 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. - */ - -/* - * Trivial replacements for the libc get{gr,pw}{uid,nam}() routines - * for use by testsudoers in the sudo test harness. - * We need our own since many platforms don't provide set{pw,gr}file(). - */ - -#include - -#include -#include -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# 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 -# include -#endif /* HAVE_STRINGS_H */ -#include -#include -#include -#include - -#include "sudo.h" - -#ifndef LINE_MAX -# define LINE_MAX 2048 -#endif - -#undef GRMEM_MAX -#define GRMEM_MAX 200 - -static FILE *pwf; -static const char *pwfile = "/etc/passwd"; -static int pw_stayopen; - -static FILE *grf; -static const char *grfile = "/etc/group"; -static int gr_stayopen; - -void 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; -{ - pwfile = file; - if (pwf != NULL) - endpwent(); -} - -void -setpwent() -{ - if (pwf == NULL) { - pwf = fopen(pwfile, "r"); - if (pwf != NULL) - fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC); - } else { - rewind(pwf); - } - pw_stayopen = 1; -} - -void -endpwent() -{ - if (pwf != NULL) { - fclose(pwf); - pwf = NULL; - } - pw_stayopen = 0; -} - -struct passwd * -getpwent() -{ - static struct passwd pw; - static char pwbuf[LINE_MAX]; - size_t len; - char *cp, *colon; - - if ((colon = fgets(pwbuf, sizeof(pwbuf), pwf)) == NULL) - return(NULL); - - zero_bytes(&pw, sizeof(pw)); - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - pw.pw_name = cp; - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - pw.pw_passwd = cp; - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - pw.pw_uid = atoi(cp); - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - pw.pw_gid = atoi(cp); - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - pw.pw_gecos = cp; - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - pw.pw_dir = cp; - pw.pw_shell = colon; - len = strlen(colon); - if (len > 0 && colon[len - 1] == '\n') - colon[len - 1] = '\0'; - return(&pw); -} - -struct passwd * -getpwnam(name) - const char *name; -{ - struct passwd *pw; - - if (pwf == NULL) { - if ((pwf = fopen(pwfile, "r")) == NULL) - return(NULL); - fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC); - } else { - rewind(pwf); - } - while ((pw = getpwent()) != NULL) { - if (strcmp(pw->pw_name, name) == 0) - break; - } - if (!pw_stayopen) { - fclose(pwf); - pwf = NULL; - } - return(pw); -} - -struct passwd * -getpwuid(uid) - uid_t uid; -{ - struct passwd *pw; - - if (pwf == NULL) { - if ((pwf = fopen(pwfile, "r")) == NULL) - return(NULL); - fcntl(fileno(pwf), F_SETFD, FD_CLOEXEC); - } else { - rewind(pwf); - } - while ((pw = getpwent()) != NULL) { - if (pw->pw_uid == uid) - break; - } - if (!pw_stayopen) { - fclose(pwf); - pwf = NULL; - } - return(pw); -} - -void -setgrfile(file) - const char *file; -{ - grfile = file; - if (grf != NULL) - endgrent(); -} - -void -setgrent() -{ - if (grf == NULL) { - grf = fopen(grfile, "r"); - if (grf != NULL) - fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); - } else { - rewind(grf); - } - gr_stayopen = 1; -} - -void -endgrent() -{ - if (grf != NULL) { - fclose(grf); - grf = NULL; - } - gr_stayopen = 0; -} - -struct group * -getgrent() -{ - static struct group gr; - static char grbuf[LINE_MAX], *gr_mem[GRMEM_MAX+1]; - size_t len; - char *cp, *colon; - int n; - - if ((colon = fgets(grbuf, sizeof(grbuf), grf)) == NULL) - return(NULL); - - zero_bytes(&gr, sizeof(gr)); - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - gr.gr_name = cp; - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - gr.gr_passwd = cp; - if ((colon = strchr(cp = colon, ':')) == NULL) - return(NULL); - *colon++ = '\0'; - gr.gr_gid = atoi(cp); - len = strlen(colon); - if (len > 0 && colon[len - 1] == '\n') - colon[len - 1] = '\0'; - if (*colon != '\0') { - gr.gr_mem = gr_mem; - cp = strtok(colon, ","); - for (n = 0; cp != NULL && n < GRMEM_MAX; n++) { - gr.gr_mem[n] = cp; - cp = strtok(NULL, ","); - } - gr.gr_mem[n++] = NULL; - } else - gr.gr_mem = NULL; - return(&gr); -} - -struct group * -getgrnam(name) - const char *name; -{ - struct group *gr; - - if (grf == NULL) { - if ((grf = fopen(grfile, "r")) == NULL) - return(NULL); - fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); - } else { - rewind(grf); - } - while ((gr = getgrent()) != NULL) { - if (strcmp(gr->gr_name, name) == 0) - break; - } - if (!gr_stayopen) { - fclose(grf); - grf = NULL; - } - return(gr); -} - -struct group * -getgrgid(gid) - gid_t gid; -{ - struct group *gr; - - if (grf == NULL) { - if ((grf = fopen(grfile, "r")) == NULL) - return(NULL); - fcntl(fileno(grf), F_SETFD, FD_CLOEXEC); - } else { - rewind(grf); - } - while ((gr = getgrent()) != NULL) { - if (gr->gr_gid == gid) - break; - } - if (!gr_stayopen) { - fclose(grf); - grf = NULL; - } - return(gr); -} diff --git a/utimes.c b/utimes.c deleted file mode 100644 index 84f4c43..0000000 --- a/utimes.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2004-2005, 2007 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. - */ - -#include - -#include -#include -#include -#if TIME_WITH_SYS_TIME -# include -#endif - -#ifdef HAVE_UTIME_H -# include -#else -# include -#endif - -#include - -#ifndef HAVE_UTIMES -/* - * Emulate utimes() via utime() - */ -int -utimes(file, times) - const char *file; - const struct timeval *times; -{ - if (times != NULL) { - struct utimbuf utb; - - utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000); - utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000); - return(utime(file, &utb)); - } else - return(utime(file, NULL)); -} -#endif /* !HAVE_UTIMES */ - -#ifdef HAVE_FUTIME -/* - * Emulate futimes() via futime() - */ -int -futimes(fd, times) - int fd; - const struct timeval *times; -{ - if (times != NULL) { - struct utimbuf utb; - - utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000); - utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000); - return(futime(fd, &utb)); - } else - return(futime(fd, NULL)); -} -#endif /* HAVE_FUTIME */ diff --git a/vasgroups.c b/vasgroups.c deleted file mode 100644 index a7c6c34..0000000 --- a/vasgroups.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * (c) 2006 Quest Software, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Neither the name of Quest Software, Inc. nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "compat.h" -#include "logging.h" -#include "nonunix.h" -#include "sudo.h" -#include "parse.h" - - -/* Pseudo-boolean types */ -#undef TRUE -#undef FALSE -#define FALSE 0 -#define TRUE 1 - - -static vas_ctx_t *sudo_vas_ctx; -static vas_id_t *sudo_vas_id; -/* Don't use VAS_NAME_FLAG_NO_CACHE or lookups just won't work. - * -tedp, 2006-08-29 */ -static const int update_flags = 0; -static int sudo_vas_available = 0; -static char *err_msg = NULL; -static void *libvas_handle = NULL; - -/* libvas functions */ -static vas_err_t (*v_ctx_alloc) (vas_ctx_t **ctx); -static void (*v_ctx_free) (vas_ctx_t *ctx); -static vas_err_t (*v_id_alloc) (vas_ctx_t *ctx, const char *name, vas_id_t **id); -static void (*v_id_free) (vas_ctx_t *ctx, vas_id_t *id); -static vas_err_t (*v_id_establish_cred_keytab) (vas_ctx_t *ctx, vas_id_t *id, int credflags, const char *keytab); -static vas_err_t (*v_user_init) (vas_ctx_t *ctx, vas_id_t *id, const char *name, int flags, vas_user_t **user); -static void (*v_user_free) (vas_ctx_t *ctx, vas_user_t *user); -static vas_err_t (*v_group_init) (vas_ctx_t *ctx, vas_id_t *id, const char *name, int flags, vas_group_t **group); -static void (*v_group_free) (vas_ctx_t *ctx, vas_group_t *group); -static vas_err_t (*v_user_is_member) (vas_ctx_t *ctx, vas_id_t *id, vas_user_t *user, vas_group_t *group); -static const char* (*v_err_get_string) (vas_ctx_t *ctx, int with_cause); - - -static int resolve_vas_funcs(void); - - -/** - * Whether nonunix group lookups are available. - * @return 1 if available, 0 if not. - */ -int -sudo_nonunix_groupcheck_available(void) -{ - return sudo_vas_available; -} - - -/** - * Check if the user is in the group - * @param group group name which can be in DOMAIN\sam format or just the group - * name - * @param user user name - * @param pwd (unused) - * @return 1 if user is a member of the group, 0 if not (or error occurred) - */ -int -sudo_nonunix_groupcheck( const char* group, const char* user, const struct passwd* pwd ) -{ - static int error_cause_shown = FALSE; - int rval = FALSE; - vas_err_t vaserr; - vas_user_t* vas_user = NULL; - vas_group_t* vas_group = NULL; - - if (!sudo_vas_available) { - if (error_cause_shown == FALSE) { - /* Produce the saved error reason */ - warningx("Non-unix group checking unavailable: %s", - err_msg ? err_msg - : "(unknown cause)"); - error_cause_shown = TRUE; - } - return 0; - } - - /* resolve the user and group. The user will be a real Unix account name, - * while the group may be a unix name, or any group name accepted by - * vas_name_to_dn, which means any of: - * - Group Name - * - Group Name@FULLY.QUALIFIED.DOMAIN - * - CN=sudoers,CN=Users,DC=rcdev,DC=vintela,DC=com - * - S-1-2-34-5678901234-5678901234-5678901234-567 - * - * XXX - we may get non-VAS user accounts here. You can add local users to an - * Active Directory group through override files. Should we handle that case? - * */ - if( (vaserr = v_user_init( sudo_vas_ctx, sudo_vas_id, user, update_flags, &vas_user )) != VAS_ERR_SUCCESS ) { - if (vaserr == VAS_ERR_NOT_FOUND) { - /* No such user in AD. Probably a local user. */ - vaserr = VAS_ERR_SUCCESS; - } - goto FINISHED; - } - - if( (vaserr = v_group_init( sudo_vas_ctx, sudo_vas_id, group, update_flags, &vas_group )) != VAS_ERR_SUCCESS ) { - goto FINISHED; - } - - /* do the membership check */ - if( (vaserr = v_user_is_member( sudo_vas_ctx, sudo_vas_id, vas_user, vas_group )) == VAS_ERR_SUCCESS ) { - rval = TRUE; - } - else if (vaserr == VAS_ERR_NOT_FOUND) { - /* fake the vaserr code so no error is triggered */ - vaserr = VAS_ERR_SUCCESS; - } - - -FINISHED: /* cleanups */ - if (vaserr != VAS_ERR_SUCCESS && vaserr != VAS_ERR_NOT_FOUND ) { - warningx("Error while checking group membership " - "for user \"%s\", group \"%s\", error: %s%s.", user, group, - v_err_get_string(sudo_vas_ctx, 1), - /* A helpful hint if there seems to be a non-FQDN as the domain */ - (strchr(group, '@') && !strchr(group, '.')) - ? "\nMake sure the fully qualified domain name is specified" - : ""); - } - if( vas_group ) v_group_free( sudo_vas_ctx, vas_group ); - if( vas_user ) v_user_free( sudo_vas_ctx, vas_user ); - - return(rval); -} - - -static void -set_err_msg(const char *msg, ...) { - va_list ap; - - if (!msg) /* assert */ - return; - - if (err_msg) - free(err_msg); - - va_start(ap, msg); - - if (vasprintf(&err_msg, msg, ap) == -1) - err_msg = NULL; - - va_end(ap); -} - - -/** - * Initialise nonunix_groupcheck state. - */ -void -sudo_nonunix_groupcheck_init(void) -{ - vas_err_t vaserr; - void *libvas; - - if (err_msg) { - free(err_msg); - err_msg = NULL; - } - - libvas = dlopen(LIBVAS_SO, RTLD_LAZY); - if (!libvas) { - set_err_msg("dlopen() failed: %s", dlerror()); - return; - } - - libvas_handle = libvas; - - if (resolve_vas_funcs() != 0) - return; - - if (VAS_ERR_SUCCESS == (vaserr = v_ctx_alloc(&sudo_vas_ctx))) { - - if (VAS_ERR_SUCCESS == (vaserr = v_id_alloc(sudo_vas_ctx, "host/", &sudo_vas_id))) { - - if (update_flags & VAS_NAME_FLAG_NO_LDAP) { - sudo_vas_available = 1; - return; /* OK */ - } else { /* Get a keytab */ - if ((vaserr = v_id_establish_cred_keytab( sudo_vas_ctx, - sudo_vas_id, - VAS_ID_FLAG_USE_MEMORY_CCACHE - | VAS_ID_FLAG_KEEP_COPY_OF_CRED - | VAS_ID_FLAG_NO_INITIAL_TGT, - NULL )) == VAS_ERR_SUCCESS) { - sudo_vas_available = 1; - return; /* OK */ - } - - if (!err_msg) - set_err_msg("unable to establish creds: %s", - v_err_get_string(sudo_vas_ctx, 1)); - } - - v_id_free(sudo_vas_ctx, sudo_vas_id); - sudo_vas_id = NULL; - } - - /* This is the last opportunity to get an error message from libvas */ - if (!err_msg) - set_err_msg("Error initializing non-unix group checking: %s", - v_err_get_string(sudo_vas_ctx, 1)); - - v_ctx_free(sudo_vas_ctx); - sudo_vas_ctx = NULL; - } - - if (!err_msg) - set_err_msg("Failed to get a libvas handle for non-unix group checking (unknown cause)"); - - sudo_vas_available = 0; -} - - -/** - * Clean up nonunix_groupcheck state. - */ -void -sudo_nonunix_groupcheck_cleanup() -{ - if (err_msg) { - free(err_msg); - err_msg = NULL; - } - - if (sudo_vas_available) { - v_id_free(sudo_vas_ctx, sudo_vas_id); - sudo_vas_id = NULL; - - v_ctx_free(sudo_vas_ctx); - sudo_vas_ctx = NULL; - - sudo_vas_available = FALSE; - } - - if (libvas_handle) { - if (dlclose(libvas_handle) != 0) - warningx("dlclose() failed: %s", dlerror()); - libvas_handle = NULL; - } -} - -#define RESOLVE_OR_ERR(fptr, sym) \ - do { \ - void *_fptr = dlsym(libvas_handle, (sym)); \ - if (!_fptr) { \ - set_err_msg("dlsym() failed: %s", dlerror()); \ - return -1; \ - } \ - fptr = _fptr; \ - } while (0) - - -/** - * Resolve all the libvas functions. - * Returns -1 and sets err_msg if something went wrong, or 0 on success. - */ -int -resolve_vas_funcs(void) -{ - if (!libvas_handle) /* assert */ - return -1; - - RESOLVE_OR_ERR(v_ctx_alloc, "vas_ctx_alloc"); - RESOLVE_OR_ERR(v_ctx_free, "vas_ctx_free"); - RESOLVE_OR_ERR(v_id_alloc, "vas_id_alloc"); - RESOLVE_OR_ERR(v_id_free, "vas_id_free"); - RESOLVE_OR_ERR(v_id_establish_cred_keytab, "vas_id_establish_cred_keytab"); - RESOLVE_OR_ERR(v_user_init, "vas_user_init"); - RESOLVE_OR_ERR(v_user_free, "vas_user_free"); - RESOLVE_OR_ERR(v_group_init, "vas_group_init"); - RESOLVE_OR_ERR(v_group_free, "vas_group_free"); - RESOLVE_OR_ERR(v_user_is_member, "vas_user_is_member"); - RESOLVE_OR_ERR(v_err_get_string, "vas_err_get_string"); - - return 0; -} diff --git a/visudo.c b/visudo.c deleted file mode 100644 index ab8d587..0000000 --- a/visudo.c +++ /dev/null @@ -1,1182 +0,0 @@ -/* - * Copyright (c) 1996, 1998-2005, 2007-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. - */ - -/* - * Lock the sudoers file for safe editing (ala vipw) and check for parse errors. - */ - -#define _SUDO_MAIN - -#ifdef __TANDEM -# include -#endif - -#include - -#include -#include -#include -#include -#include -#ifndef __TANDEM -# include -#endif -#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 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if TIME_WITH_SYS_TIME -# include -#endif -#ifdef __STDC__ -# include -#else -# include -#endif - -#include "sudo.h" -#include "interfaces.h" -#include "parse.h" -#include "redblack.h" -#include - -struct sudoersfile { - struct sudoersfile *prev, *next; - char *path; - char *tpath; - int fd; - int modified; - int doedit; -}; -TQ_DECLARE(sudoersfile); - -/* - * Function prototypes - */ -static RETSIGTYPE quit __P((int)); -static char *get_args __P((char *)); -static char *get_editor __P((char **)); -static void get_hostname __P((void)); -static char whatnow __P((void)); -static int check_aliases __P((int, int)); -static int check_syntax __P((char *, int, int)); -static int edit_sudoers __P((struct sudoersfile *, char *, char *, int)); -static int install_sudoers __P((struct sudoersfile *, int)); -static int print_unused __P((void *, void *)); -static int reparse_sudoers __P((char *, char *, int, int)); -static int run_command __P((char *, char **)); -static void print_selfref __P((char *, int, int, int)); -static void print_undefined __P((char *, int, int, int)); -static void setup_signals __P((void)); -static void usage __P((void)) __attribute__((__noreturn__)); - -extern void yyerror __P((const char *)); -extern void yyrestart __P((FILE *)); - -/* - * External globals exported by the parser - */ -extern struct rbtree *aliases; -extern FILE *yyin; -extern char *sudoers, *errorfile; -extern int errorlineno, parse_error; -/* For getopt(3) */ -extern char *optarg; -extern int optind; - -/* - * Globals - */ -int Argc; -char **Argv; -int num_interfaces; -struct interface *interfaces; -struct sudo_user sudo_user; -struct passwd *list_pw; -static struct sudoersfile_list sudoerslist; -static struct rbtree *alias_freelist; - -int -main(argc, argv) - int argc; - char **argv; -{ - struct sudoersfile *sp; - char *args, *editor, *sudoers_path; - int ch, checkonly, quiet, strict, oldperms; -#if defined(SUDO_DEVEL) && defined(__OpenBSD__) - extern char *malloc_options; - malloc_options = "AFGJPR"; -#endif - - Argv = argv; - if ((Argc = argc) < 1) - usage(); - - /* - * Arg handling. - */ - checkonly = oldperms = quiet = strict = FALSE; - sudoers_path = _PATH_SUDOERS; - while ((ch = getopt(argc, argv, "Vcf:sq")) != -1) { - switch (ch) { - case 'V': - (void) printf("%s version %s\n", getprogname(), PACKAGE_VERSION); - exit(0); - case 'c': - checkonly++; /* check mode */ - break; - case 'f': - sudoers_path = optarg; /* sudoers file path */ - oldperms = TRUE; - break; - case 's': - strict++; /* strict mode */ - break; - case 'q': - quiet++; /* quiet mode */ - break; - default: - usage(); - } - } - argc -= optind; - argv += optind; - if (argc) - usage(); - - sudo_setpwent(); - sudo_setgrent(); - - /* Mock up a fake sudo_user struct. */ - user_cmnd = ""; - if ((sudo_user.pw = sudo_getpwuid(getuid())) == NULL) - errorx(1, "you don't exist in the passwd database"); - get_hostname(); - - /* Setup defaults data structures. */ - init_defaults(); - - if (checkonly) - exit(check_syntax(sudoers_path, quiet, strict)); - - /* - * Parse the existing sudoers file(s) in quiet mode to highlight any - * existing errors and to pull in editor and env_editor conf values. - */ - if ((yyin = open_sudoers(sudoers_path, TRUE, NULL)) == NULL) { - error(1, "%s", sudoers_path); - } - init_parser(sudoers_path, 0); - yyparse(); - (void) update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER); - - editor = get_editor(&args); - - /* Install signal handlers to clean up temp files if we are killed. */ - setup_signals(); - - /* Edit the sudoers file(s) */ - tq_foreach_fwd(&sudoerslist, sp) { - if (!sp->doedit) - continue; - if (sp != tq_first(&sudoerslist)) { - printf("press return to edit %s: ", sp->path); - while ((ch = getchar()) != EOF && ch != '\n') - continue; - } - edit_sudoers(sp, editor, args, -1); - } - - /* Check edited files for a parse error and re-edit any that fail. */ - reparse_sudoers(editor, args, strict, quiet); - - /* Install the sudoers temp files. */ - tq_foreach_fwd(&sudoerslist, sp) { - if (!sp->modified) - (void) unlink(sp->tpath); - else - (void) install_sudoers(sp, oldperms); - } - - exit(0); -} - -/* - * Edit each sudoers file. - * Returns TRUE on success, else FALSE. - */ -static int -edit_sudoers(sp, editor, args, lineno) - struct sudoersfile *sp; - char *editor, *args; - int lineno; -{ - int tfd; /* sudoers temp file descriptor */ - int modified; /* was the file modified? */ - int ac; /* argument count */ - char **av; /* argument vector for run_command */ - char *cp; /* scratch char pointer */ - char buf[PATH_MAX*2]; /* buffer used for copying files */ - char linestr[64]; /* string version of lineno */ - struct timeval tv, tv1, tv2; /* time before and after edit */ - struct timeval orig_mtim; /* starting mtime of sudoers file */ - off_t orig_size; /* starting size of sudoers file */ - ssize_t nread; /* number of bytes read */ - struct stat sb; /* stat buffer */ - -#ifdef HAVE_FSTAT - if (fstat(sp->fd, &sb) == -1) -#else - if (stat(sp->path, &sb) == -1) -#endif - error(1, "can't stat %s", sp->path); - orig_size = sb.st_size; - mtim_get(&sb, &orig_mtim); - - /* Create the temp file if needed and set timestamp. */ - if (sp->tpath == NULL) { - easprintf(&sp->tpath, "%s.tmp", sp->path); - tfd = open(sp->tpath, O_WRONLY | O_CREAT | O_TRUNC, 0600); - if (tfd < 0) - error(1, "%s", sp->tpath); - - /* Copy sp->path -> sp->tpath and reset the mtime. */ - if (orig_size != 0) { - (void) lseek(sp->fd, (off_t)0, SEEK_SET); - while ((nread = read(sp->fd, buf, sizeof(buf))) > 0) - if (write(tfd, buf, nread) != nread) - error(1, "write error"); - - /* Add missing newline at EOF if needed. */ - if (nread > 0 && buf[nread - 1] != '\n') { - buf[0] = '\n'; - write(tfd, buf, 1); - } - } - (void) close(tfd); - } - (void) touch(-1, sp->tpath, &orig_mtim); - - /* Find the length of the argument vector */ - ac = 3 + (lineno > 0); - if (args) { - int wasblank; - - ac++; - for (wasblank = FALSE, cp = args; *cp; cp++) { - if (isblank((unsigned char) *cp)) - wasblank = TRUE; - else if (wasblank) { - wasblank = FALSE; - ac++; - } - } - } - - /* Build up argument vector for the command */ - av = emalloc2(ac, sizeof(char *)); - if ((av[0] = strrchr(editor, '/')) != NULL) - av[0]++; - else - av[0] = editor; - ac = 1; - if (lineno > 0) { - (void) snprintf(linestr, sizeof(linestr), "+%d", lineno); - av[ac++] = linestr; - } - if (args) { - for ((cp = strtok(args, " \t")); cp; (cp = strtok(NULL, " \t"))) - av[ac++] = cp; - } - av[ac++] = sp->tpath; - av[ac++] = NULL; - - /* - * Do the edit: - * We cannot check the editor's exit value against 0 since - * XPG4 specifies that vi's exit value is a function of the - * number of errors during editing (?!?!). - */ - gettime(&tv1); - if (run_command(editor, av) != -1) { - gettime(&tv2); - /* - * Sanity checks. - */ - if (stat(sp->tpath, &sb) < 0) { - warningx("cannot stat temporary file (%s), %s unchanged", - sp->tpath, sp->path); - return(FALSE); - } - if (sb.st_size == 0 && orig_size != 0) { - warningx("zero length temporary file (%s), %s unchanged", - sp->tpath, sp->path); - sp->modified = TRUE; - return(FALSE); - } - } else { - warningx("editor (%s) failed, %s unchanged", editor, sp->path); - return(FALSE); - } - - /* Set modified bit if use changed the file. */ - modified = TRUE; - mtim_get(&sb, &tv); - if (orig_size == sb.st_size && timevalcmp(&orig_mtim, &tv, ==)) { - /* - * If mtime and size match but the user spent no measurable - * time in the editor we can't tell if the file was changed. - */ - timevalsub(&tv1, &tv2); - if (timevalisset(&tv2)) - modified = FALSE; - } - - /* - * If modified in this edit session, mark as modified. - */ - if (modified) - sp->modified = modified; - else - warningx("%s unchanged", sp->tpath); - - return(TRUE); -} - -/* - * Parse sudoers after editing and re-edit any ones that caused a parse error. - * Returns TRUE on success, else FALSE. - */ -static int -reparse_sudoers(editor, args, strict, quiet) - char *editor, *args; - int strict, quiet; -{ - struct sudoersfile *sp, *last; - FILE *fp; - int ch; - - /* - * Parse the edited sudoers files and do sanity checking - */ - do { - sp = tq_first(&sudoerslist); - last = tq_last(&sudoerslist); - fp = fopen(sp->tpath, "r+"); - if (fp == NULL) - errorx(1, "can't re-open temporary file (%s), %s unchanged.", - sp->tpath, sp->path); - - /* Clean slate for each parse */ - init_defaults(); - init_parser(sp->path, quiet); - - /* Parse the sudoers temp file */ - yyrestart(fp); - if (yyparse() && !parse_error) { - warningx("unabled to parse temporary file (%s), unknown error", - sp->tpath); - parse_error = TRUE; - errorfile = sp->path; - } - fclose(yyin); - if (!parse_error) { - if (!update_defaults(SETDEF_GENERIC|SETDEF_HOST|SETDEF_USER) || - check_aliases(strict, quiet) != 0) { - parse_error = TRUE; - errorfile = sp->path; - } - } - - /* - * Got an error, prompt the user for what to do now - */ - if (parse_error) { - switch (whatnow()) { - case 'Q' : parse_error = FALSE; /* ignore parse error */ - break; - case 'x' : cleanup(0); - exit(0); - break; - } - } - if (parse_error) { - /* Edit file with the parse error */ - tq_foreach_fwd(&sudoerslist, sp) { - if (errorfile == NULL || strcmp(sp->path, errorfile) == 0) { - edit_sudoers(sp, editor, args, errorlineno); - break; - } - } - if (sp == NULL) - errorx(1, "internal error, can't find %s in list!", sudoers); - } - - /* If any new #include directives were added, edit them too. */ - for (sp = last->next; sp != NULL; sp = sp->next) { - printf("press return to edit %s: ", sp->path); - while ((ch = getchar()) != EOF && ch != '\n') - continue; - edit_sudoers(sp, editor, args, errorlineno); - } - } while (parse_error); - - return(TRUE); -} - -/* - * Set the owner and mode on a sudoers temp file and - * move it into place. Returns TRUE on success, else FALSE. - */ -static int -install_sudoers(sp, oldperms) - struct sudoersfile *sp; - int oldperms; -{ - struct stat sb; - - /* - * Change mode and ownership of temp file so when - * we move it to sp->path things are kosher. - */ - if (oldperms) { - /* Use perms of the existing file. */ -#ifdef HAVE_FSTAT - if (fstat(sp->fd, &sb) == -1) -#else - if (stat(sp->path, &sb) == -1) -#endif - error(1, "can't stat %s", sp->path); - (void) chown(sp->tpath, sb.st_uid, sb.st_gid); - (void) chmod(sp->tpath, sb.st_mode & 0777); - } else { - if (chown(sp->tpath, SUDOERS_UID, SUDOERS_GID) != 0) { - warning("unable to set (uid, gid) of %s to (%d, %d)", - sp->tpath, SUDOERS_UID, SUDOERS_GID); - return(FALSE); - } - if (chmod(sp->tpath, SUDOERS_MODE) != 0) { - warning("unable to change mode of %s to 0%o", sp->tpath, - SUDOERS_MODE); - return(FALSE); - } - } - - /* - * Now that sp->tpath is sane (parses ok) it needs to be - * rename(2)'d to sp->path. If the rename(2) fails we try using - * mv(1) in case sp->tpath and sp->path are on different file systems. - */ - if (rename(sp->tpath, sp->path) == 0) { - efree(sp->tpath); - sp->tpath = NULL; - } else { - if (errno == EXDEV) { - char *av[4]; - warningx("%s and %s not on the same file system, using mv to rename", - sp->tpath, sp->path); - - /* Build up argument vector for the command */ - if ((av[0] = strrchr(_PATH_MV, '/')) != NULL) - av[0]++; - else - av[0] = _PATH_MV; - av[1] = sp->tpath; - av[2] = sp->path; - av[3] = NULL; - - /* And run it... */ - if (run_command(_PATH_MV, av)) { - warningx("command failed: '%s %s %s', %s unchanged", - _PATH_MV, sp->tpath, sp->path, sp->path); - (void) unlink(sp->tpath); - efree(sp->tpath); - sp->tpath = NULL; - return(FALSE); - } - efree(sp->tpath); - sp->tpath = NULL; - } else { - warning("error renaming %s, %s unchanged", sp->tpath, sp->path); - (void) unlink(sp->tpath); - return(FALSE); - } - } - return(TRUE); -} - -/* STUB */ -void -set_fqdn() -{ - return; -} - -/* STUB */ -void -init_envtables() -{ - return; -} - -/* STUB */ -int -user_is_exempt() -{ - return(FALSE); -} - -/* STUB */ -void -sudo_setspent() -{ - return; -} - -/* STUB */ -void -sudo_endspent() -{ - return; -} - -char * -sudo_getepw(pw) - const struct passwd *pw; -{ - return (pw->pw_passwd); -} - -/* - * Assuming a parse error occurred, prompt the user for what they want - * to do now. Returns the first letter of their choice. - */ -static char -whatnow() -{ - int choice, c; - - for (;;) { - (void) fputs("What now? ", stdout); - choice = getchar(); - for (c = choice; c != '\n' && c != EOF;) - c = getchar(); - - switch (choice) { - case EOF: - choice = 'x'; - /* FALLTHROUGH */ - case 'e': - case 'x': - case 'Q': - return(choice); - default: - (void) puts("Options are:"); - (void) puts(" (e)dit sudoers file again"); - (void) puts(" e(x)it without saving changes to sudoers file"); - (void) puts(" (Q)uit and save changes to sudoers file (DANGER!)\n"); - } - } -} - -/* - * Install signal handlers for visudo. - */ -static void -setup_signals() -{ - sigaction_t sa; - - /* - * Setup signal handlers to cleanup nicely. - */ - zero_bytes(&sa, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = quit; - (void) sigaction(SIGTERM, &sa, NULL); - (void) sigaction(SIGHUP, &sa, NULL); - (void) sigaction(SIGINT, &sa, NULL); - (void) sigaction(SIGQUIT, &sa, NULL); -} - -static int -run_command(path, argv) - char *path; - char **argv; -{ - int status; - pid_t pid, rv; - - switch (pid = fork()) { - case -1: - error(1, "unable to run %s", path); - break; /* NOTREACHED */ - case 0: - sudo_endpwent(); - sudo_endgrent(); - closefrom(STDERR_FILENO + 1); - execv(path, argv); - warning("unable to run %s", path); - _exit(127); - break; /* NOTREACHED */ - } - - do { -#ifdef sudo_waitpid - rv = sudo_waitpid(pid, &status, 0); -#else - rv = wait(&status); -#endif - } while (rv == -1 && errno == EINTR); - - if (rv == -1 || !WIFEXITED(status)) - return(-1); - return(WEXITSTATUS(status)); -} - -static int -check_syntax(sudoers_path, quiet, strict) - char *sudoers_path; - int quiet; - int strict; -{ - struct stat sb; - int error; - - if ((yyin = fopen(sudoers_path, "r")) == NULL) { - if (!quiet) - warning("unable to open %s", sudoers_path); - exit(1); - } - init_parser(sudoers_path, quiet); - if (yyparse() && !parse_error) { - if (!quiet) - warningx("failed to parse %s file, unknown error", sudoers_path); - parse_error = TRUE; - errorfile = sudoers_path; - } - if (!parse_error && check_aliases(strict, quiet) != 0) { - parse_error = TRUE; - errorfile = sudoers_path; - } - error = parse_error; - if (!quiet) { - if (parse_error) { - if (errorlineno != -1) - (void) printf("parse error in %s near line %d\n", errorfile, - errorlineno); - else - (void) printf("parse error in %s\n", errorfile); - } else { - (void) printf("%s: parsed OK\n", sudoers_path); - } - } - /* Check mode and owner in strict mode. */ -#ifdef HAVE_FSTAT - if (strict && fstat(fileno(yyin), &sb) == 0) -#else - if (strict && stat(sudoers_path, &sb) == 0) -#endif - { - if (sb.st_uid != SUDOERS_UID || sb.st_gid != SUDOERS_GID) { - error = TRUE; - if (!quiet) { - fprintf(stderr, "%s: wrong owner (uid, gid) should be (%d, %d)\n", - sudoers_path, SUDOERS_UID, SUDOERS_GID); - } - } - if ((sb.st_mode & 07777) != SUDOERS_MODE) { - error = TRUE; - if (!quiet) { - fprintf(stderr, "%s: bad permissions, should be mode 0%o\n", - sudoers_path, SUDOERS_MODE); - } - } - } - - return(error); -} - -/* - * Used to open (and lock) the initial sudoers file and to also open - * any subsequent files #included via a callback from the parser. - */ -FILE * -open_sudoers(path, doedit, keepopen) - const char *path; - int doedit; - int *keepopen; -{ - struct sudoersfile *entry; - FILE *fp; - - /* Check for existing entry */ - tq_foreach_fwd(&sudoerslist, entry) { - if (strcmp(path, entry->path) == 0) - break; - } - if (entry == NULL) { - entry = emalloc(sizeof(*entry)); - entry->path = estrdup(path); - entry->modified = 0; - entry->prev = entry; - entry->next = NULL; - entry->fd = open(entry->path, O_RDWR | O_CREAT, SUDOERS_MODE); - entry->tpath = NULL; - entry->doedit = doedit; - if (entry->fd == -1) { - warning("%s", entry->path); - efree(entry); - return(NULL); - } - if (!lock_file(entry->fd, SUDO_TLOCK)) - errorx(1, "%s busy, try again later", entry->path); - if ((fp = fdopen(entry->fd, "r")) == NULL) - error(1, "%s", entry->path); - tq_append(&sudoerslist, entry); - } else { - /* Already exists, open .tmp version if there is one. */ - if (entry->tpath != NULL) { - if ((fp = fopen(entry->tpath, "r")) == NULL) - error(1, "%s", entry->tpath); - } else { - if ((fp = fdopen(entry->fd, "r")) == NULL) - error(1, "%s", entry->path); - rewind(fp); - } - } - if (keepopen != NULL) - *keepopen = TRUE; - return(fp); -} - -static char * -get_editor(args) - char **args; -{ - char *Editor, *EditorArgs, *EditorPath, *UserEditor, *UserEditorArgs; - - /* - * Check VISUAL and EDITOR environment variables to see which editor - * the user wants to use (we may not end up using it though). - * If the path is not fully-qualified, make it so and check that - * the specified executable actually exists. - */ - UserEditorArgs = NULL; - if ((UserEditor = getenv("VISUAL")) == NULL || *UserEditor == '\0') - UserEditor = getenv("EDITOR"); - if (UserEditor && *UserEditor == '\0') - UserEditor = NULL; - else if (UserEditor) { - UserEditorArgs = get_args(UserEditor); - if (find_path(UserEditor, &Editor, NULL, getenv("PATH"), 0) == FOUND) { - UserEditor = Editor; - } else { - if (def_env_editor) { - /* If we are honoring $EDITOR this is a fatal error. */ - errorx(1, "specified editor (%s) doesn't exist!", UserEditor); - } else { - /* Otherwise, just ignore $EDITOR. */ - UserEditor = NULL; - } - } - } - - /* - * See if we can use the user's choice of editors either because - * we allow any $EDITOR or because $EDITOR is in the allowable list. - */ - Editor = EditorArgs = EditorPath = NULL; - if (def_env_editor && UserEditor) { - Editor = UserEditor; - EditorArgs = UserEditorArgs; - } else if (UserEditor) { - struct stat editor_sb; - struct stat user_editor_sb; - char *base, *userbase; - - if (stat(UserEditor, &user_editor_sb) != 0) { - /* Should never happen since we already checked above. */ - error(1, "unable to stat editor (%s)", UserEditor); - } - EditorPath = estrdup(def_editor); - Editor = strtok(EditorPath, ":"); - do { - EditorArgs = get_args(Editor); - /* - * Both Editor and UserEditor should be fully qualified but - * check anyway... - */ - if ((base = strrchr(Editor, '/')) == NULL) - continue; - if ((userbase = strrchr(UserEditor, '/')) == NULL) { - Editor = NULL; - break; - } - base++, userbase++; - - /* - * We compare the basenames first and then use stat to match - * for sure. - */ - if (strcmp(base, userbase) == 0) { - if (stat(Editor, &editor_sb) == 0 && S_ISREG(editor_sb.st_mode) - && (editor_sb.st_mode & 0000111) && - editor_sb.st_dev == user_editor_sb.st_dev && - editor_sb.st_ino == user_editor_sb.st_ino) - break; - } - } while ((Editor = strtok(NULL, ":"))); - } - - /* - * Can't use $EDITOR, try each element of def_editor until we - * find one that exists, is regular, and is executable. - */ - if (Editor == NULL || *Editor == '\0') { - efree(EditorPath); - EditorPath = estrdup(def_editor); - Editor = strtok(EditorPath, ":"); - do { - EditorArgs = get_args(Editor); - if (sudo_goodpath(Editor, NULL)) - break; - } while ((Editor = strtok(NULL, ":"))); - - /* Bleah, none of the editors existed! */ - if (Editor == NULL || *Editor == '\0') - errorx(1, "no editor found (editor path = %s)", def_editor); - } - *args = EditorArgs; - return(Editor); -} - -/* - * Split out any command line arguments and return them. - */ -static char * -get_args(cmnd) - char *cmnd; -{ - char *args; - - args = cmnd; - while (*args && !isblank((unsigned char) *args)) - args++; - if (*args) { - *args++ = '\0'; - while (*args && isblank((unsigned char) *args)) - args++; - } - return(*args ? args : NULL); -} - -/* - * Look up the hostname and set user_host and user_shost. - */ -static void -get_hostname() -{ - char *p, thost[MAXHOSTNAMELEN + 1]; - - if (gethostname(thost, sizeof(thost)) != 0) { - user_host = user_shost = "localhost"; - return; - } - thost[sizeof(thost) - 1] = '\0'; - user_host = estrdup(thost); - - if ((p = strchr(user_host, '.'))) { - *p = '\0'; - user_shost = estrdup(user_host); - *p = '.'; - } else { - user_shost = user_host; - } -} - -static int -alias_remove_recursive(name, type, strict, quiet) - char *name; - int type; - int strict; - int quiet; -{ - struct member *m; - struct alias *a; - int error = 0; - - if ((a = alias_find(name, type)) != NULL) { - tq_foreach_fwd(&a->members, m) { - if (m->type == ALIAS) { - if (strcmp(name, m->name) == 0) { - print_selfref(m->name, type, strict, quiet); - error = 1; - } else { - if (!alias_remove_recursive(m->name, type, strict, quiet)) - error = 1; - } - } - } - } - alias_seqno++; - a = alias_remove(name, type); - if (a) - rbinsert(alias_freelist, a); - return(error); -} - -/* - * Iterate through the sudoers datastructures looking for undefined - * aliases or unused aliases. - */ -static int -check_aliases(strict, quiet) - int strict; - int quiet; -{ - struct cmndspec *cs; - struct member *m, *binding; - struct privilege *priv; - struct userspec *us; - struct defaults *d; - int atype, error = 0; - - alias_freelist = rbcreate(alias_compare); - - /* Forward check. */ - tq_foreach_fwd(&userspecs, us) { - tq_foreach_fwd(&us->users, m) { - if (m->type == ALIAS) { - alias_seqno++; - if (alias_find(m->name, USERALIAS) == NULL) { - print_undefined(m->name, USERALIAS, strict, quiet); - error++; - } - } - } - tq_foreach_fwd(&us->privileges, priv) { - tq_foreach_fwd(&priv->hostlist, m) { - if (m->type == ALIAS) { - alias_seqno++; - if (alias_find(m->name, HOSTALIAS) == NULL) { - print_undefined(m->name, HOSTALIAS, strict, quiet); - error++; - } - } - } - tq_foreach_fwd(&priv->cmndlist, cs) { - tq_foreach_fwd(&cs->runasuserlist, m) { - if (m->type == ALIAS) { - alias_seqno++; - if (alias_find(m->name, RUNASALIAS) == NULL) { - print_undefined(m->name, RUNASALIAS, strict, quiet); - error++; - } - } - } - if ((m = cs->cmnd)->type == ALIAS) { - alias_seqno++; - if (alias_find(m->name, CMNDALIAS) == NULL) { - print_undefined(m->name, CMNDALIAS, strict, quiet); - error++; - } - } - } - } - } - - /* Reverse check (destructive) */ - tq_foreach_fwd(&userspecs, us) { - tq_foreach_fwd(&us->users, m) { - if (m->type == ALIAS) { - if (!alias_remove_recursive(m->name, USERALIAS, strict, quiet)) - error++; - } - } - tq_foreach_fwd(&us->privileges, priv) { - tq_foreach_fwd(&priv->hostlist, m) { - if (m->type == ALIAS) - if (!alias_remove_recursive(m->name, HOSTALIAS, strict, - quiet)) - error++; - } - tq_foreach_fwd(&priv->cmndlist, cs) { - tq_foreach_fwd(&cs->runasuserlist, m) { - if (m->type == ALIAS) - if (!alias_remove_recursive(m->name, RUNASALIAS, - strict, quiet)) - error++; - } - if ((m = cs->cmnd)->type == ALIAS) - if (!alias_remove_recursive(m->name, CMNDALIAS, strict, - quiet)) - error++; - } - } - } - tq_foreach_fwd(&defaults, d) { - switch (d->type) { - case DEFAULTS_HOST: - atype = HOSTALIAS; - break; - case DEFAULTS_USER: - atype = USERALIAS; - break; - case DEFAULTS_RUNAS: - atype = RUNASALIAS; - break; - case DEFAULTS_CMND: - atype = CMNDALIAS; - break; - default: - continue; /* not an alias */ - } - tq_foreach_fwd(&d->binding, binding) { - for (m = binding; m != NULL; m = m->next) { - if (m->type == ALIAS) - if (!alias_remove_recursive(m->name, atype, strict, quiet)) - error++; - } - } - } - rbdestroy(alias_freelist, alias_free); - - /* If all aliases were referenced we will have an empty tree. */ - if (!no_aliases() && !quiet) - alias_apply(print_unused, strict ? "Error" : "Warning"); - - return (strict ? error : 0); -} - -static void -print_undefined(name, type, strict, quiet) - char *name; - int type; - int strict; - int quiet; -{ - if (!quiet) { - warningx("%s: %s_Alias `%s' referenced but not defined", - strict ? "Error" : "Warning", - type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" : - type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : - "Unknown", name); - } -} - -static void -print_selfref(name, type, strict, quiet) - char *name; - int type; - int strict; - int quiet; -{ - if (!quiet) { - warningx("%s: %s_Alias `%s' references self", - strict ? "Error" : "Warning", - type == HOSTALIAS ? "Host" : type == CMNDALIAS ? "Cmnd" : - type == USERALIAS ? "User" : type == RUNASALIAS ? "Runas" : - "Unknown", name); - } -} - -static int -print_unused(v1, v2) - void *v1; - void *v2; -{ - struct alias *a = (struct alias *)v1; - char *prefix = (char *)v2; - - warningx("%s: unused %s_Alias %s", prefix, - a->type == HOSTALIAS ? "Host" : a->type == CMNDALIAS ? "Cmnd" : - a->type == USERALIAS ? "User" : a->type == RUNASALIAS ? "Runas" : - "Unknown", a->name); - return(0); -} - -/* - * Unlink any sudoers temp files that remain. - */ -void -cleanup(gotsignal) - int gotsignal; -{ - struct sudoersfile *sp; - - tq_foreach_fwd(&sudoerslist, sp) { - if (sp->tpath != NULL) - (void) unlink(sp->tpath); - } - if (!gotsignal) { - sudo_endpwent(); - sudo_endgrent(); - } -} - -/* - * Unlink sudoers temp files (if any) and exit. - */ -static RETSIGTYPE -quit(signo) - int signo; -{ - cleanup(signo); -#define emsg " exiting due to signal.\n" - write(STDERR_FILENO, getprogname(), strlen(getprogname())); - write(STDERR_FILENO, emsg, sizeof(emsg) - 1); - _exit(signo); -} - -static void -usage() -{ - (void) fprintf(stderr, "usage: %s [-c] [-q] [-s] [-V] [-f sudoers]\n", - getprogname()); - exit(1); -} diff --git a/visudo.cat b/visudo.cat deleted file mode 100644 index c99374f..0000000 --- a/visudo.cat +++ /dev/null @@ -1,198 +0,0 @@ - - - -VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) - - -NNAAMMEE - visudo - edit the sudoers file - -SSYYNNOOPPSSIISS - vviissuuddoo [--cc] [--qq] [--ss] [--VV] [--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). - vviissuuddoo locks the _s_u_d_o_e_r_s file against multiple simultaneous edits, - provides basic sanity checks, and checks for parse errors. If the - _s_u_d_o_e_r_s file is currently being edited you will receive a message to - try again later. - - There is a hard-coded list of one or more editors that vviissuuddoo will use - set at compile-time that may be overridden via the _e_d_i_t_o_r _s_u_d_o_e_r_s - Default variable. This list defaults to "vi". Normally, vviissuuddoo does - not honor the VISUAL or EDITOR environment variables unless they - contain an editor in the aforementioned editors list. However, if - vviissuuddoo is configured with the _-_-_w_i_t_h_-_e_n_v_-_e_d_i_t_o_r option or the - _e_n_v___e_d_i_t_o_r Default variable is set in _s_u_d_o_e_r_s, vviissuuddoo will use any the - editor defines by VISUAL or EDITOR. Note that this can be a security - hole since it allows the user to execute any program they wish simply - by setting VISUAL or EDITOR. - - vviissuuddoo parses the _s_u_d_o_e_r_s file after the edit and will not save the - changes if there is a syntax error. Upon finding an error, vviissuuddoo will - print a message stating the line number(s) where the error occurred and - the user will receive the "What now?" prompt. At this point the user - may enter "e" to re-edit the _s_u_d_o_e_r_s file, "x" to exit without saving - the changes, or "Q" to quit and save changes. The "Q" option should be - used with extreme care because if vviissuuddoo believes there to be a parse - error, so will ssuuddoo and no one will be able to ssuuddoo again until the - error is fixed. If "e" is typed to edit the _s_u_d_o_e_r_s file after a - parse error has been detected, the cursor will be placed on the line - where the error occurred (if the editor supports this feature). - -OOPPTTIIOONNSS - vviissuuddoo accepts the following command line options: - - -c Enable cchheecckk--oonnllyy mode. The existing _s_u_d_o_e_r_s file will be - checked for syntax and a message will be printed to the - standard output detailing the status of _s_u_d_o_e_r_s. If the - syntax check completes successfully, vviissuuddoo will exit with - a value of 0. If a syntax error is encountered, vviissuuddoo - will exit with a value of 1. - - -f _s_u_d_o_e_r_s Specify and alternate _s_u_d_o_e_r_s file location. With this - 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. - - -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 - - - - - -VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) - - - combined with the --cc option. - - -s Enable ssttrriicctt checking of the _s_u_d_o_e_r_s file. If an alias is - used before it is defined, vviissuuddoo will consider this a - parse error. Note that it is not possible to differentiate - between an alias and a host name or user name that consists - solely of uppercase letters, digits, and the underscore - ('_') character. - - -V The --VV (version) option causes vviissuuddoo to print its version - number and exit. - -EENNVVIIRROONNMMEENNTT - The following environment variables may be consulted depending on the - value of the _e_d_i_t_o_r and _e_n_v___e_d_i_t_o_r _s_u_d_o_e_r_s variables: - - VISUAL Invoked by visudo as the editor to use - - EDITOR Used by visudo if VISUAL is not set - -FFIILLEESS - _/_e_t_c_/_s_u_d_o_e_r_s List of who can run what - - _/_e_t_c_/_s_u_d_o_e_r_s_._t_m_p Lock file for visudo - -DDIIAAGGNNOOSSTTIICCSS - sudoers file busy, try again later. - Someone else is currently editing the _s_u_d_o_e_r_s file. - - /etc/sudoers.tmp: Permission denied - You didn't run vviissuuddoo as root. - - Can't find you in the passwd database - Your userid does not appear in the system passwd file. - - Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined - Either you are trying to use an undeclare - {User,Runas,Host,Cmnd}_Alias or you have a user or host name listed - that consists solely of uppercase letters, digits, and the - underscore ('_') character. In the latter case, you can ignore the - warnings (ssuuddoo will not complain). In --ss (strict) mode these are - errors, not warnings. - - Warning: unused {User,Runas,Host,Cmnd}_Alias - The specified {User,Runas,Host,Cmnd}_Alias was defined but never - used. You may wish to comment out or remove the unused alias. In - --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 - - - - - -VISUDO(1m) MAINTENANCE COMMANDS VISUDO(1m) - - - Todd Miller - - See the HISTORY file in the sudo distribution or visit - http://www.sudo.ws/sudo/history.html for more details. - -CCAAVVEEAATTSS - There is no easy way to prevent a user from gaining a root shell if the - editor used by vviissuuddoo allows shell escapes. - -BBUUGGSS - If you feel you have found a bug in vviissuuddoo, please submit a bug report - at http://www.sudo.ws/sudo/bugs/ - -SSUUPPPPOORRTT - Limited free support is available via the sudo-users mailing list, see - http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search - the archives. - -DDIISSCCLLAAIIMMEERR - vviissuuddoo is provided ``AS IS'' and any express or implied warranties, - including, but not limited to, the implied warranties of - merchantability and fitness for a particular purpose are disclaimed. - See the LICENSE file distributed with ssuuddoo or - http://www.sudo.ws/sudo/license.html for complete details. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -1.7.4 July 14, 2010 3 - - diff --git a/visudo.man.in b/visudo.man.in deleted file mode 100644 index 563fd3b..0000000 --- a/visudo.man.in +++ /dev/null @@ -1,301 +0,0 @@ -.\" Copyright (c) 1996,1998-2005, 2007-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. -.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" Sponsored in part by the Defense Advanced Research Projects -.\" Agency (DARPA) and Air Force Research Laboratory, Air Force -.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. -.\" -.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.07) -.\" -.\" Standard preamble: -.\" ======================================================================== -.de Sp \" Vertical space (when we can't use .PP) -.if t .sp .5v -.if n .sp -.. -.de Vb \" Begin verbatim text -.ft CW -.nf -.ne \\$1 -.. -.de Ve \" End verbatim text -.ft R -.fi -.. -.\" Set up some character translations and predefined strings. \*(-- will -.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left -.\" double quote, and \*(R" will give a right double quote. \*(C+ will -.\" give a nicer C++. Capital omega is used to do unbreakable dashes and -.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, -.\" nothing in troff, for use with C<>. -.tr \(*W- -.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' -.ie n \{\ -. ds -- \(*W- -. ds PI pi -. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch -. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch -. ds L" "" -. ds R" "" -. ds C` -. ds C' -'br\} -.el\{\ -. ds -- \|\(em\| -. ds PI \(*p -. ds L" `` -. ds R" '' -'br\} -.\" -.\" Escape single quotes in literal strings from groff's Unicode transform. -.ie \n(.g .ds Aq \(aq -.el .ds Aq ' -.\" -.\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index -.\" entries marked with X<> in POD. Of course, you'll have to process the -.\" output yourself in some meaningful fashion. -.ie \nF \{\ -. de IX -. tm Index:\\$1\t\\n%\t"\\$2" -.. -. nr % 0 -. rr F -.\} -.el \{\ -. de IX -.. -.\} -.\" -.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). -.\" Fear. Run. Save yourself. No user-serviceable parts. -. \" fudge factors for nroff and troff -.if n \{\ -. ds #H 0 -. ds #V .8m -. ds #F .3m -. ds #[ \f1 -. ds #] \fP -.\} -.if t \{\ -. ds #H ((1u-(\\\\n(.fu%2u))*.13m) -. ds #V .6m -. ds #F 0 -. ds #[ \& -. ds #] \& -.\} -. \" simple accents for nroff and troff -.if n \{\ -. ds ' \& -. ds ` \& -. ds ^ \& -. ds , \& -. ds ~ ~ -. ds / -.\} -.if t \{\ -. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" -. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' -. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' -. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' -. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' -. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' -.\} -. \" troff and (daisy-wheel) nroff accents -.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' -.ds 8 \h'\*(#H'\(*b\h'-\*(#H' -.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] -.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' -.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' -.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] -.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] -.ds ae a\h'-(\w'a'u*4/10)'e -.ds Ae A\h'-(\w'A'u*4/10)'E -. \" corrections for vroff -.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' -.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' -. \" for low resolution devices (crt and lpr) -.if \n(.H>23 .if \n(.V>19 \ -\{\ -. ds : e -. ds 8 ss -. ds o a -. ds d- d\h'-1'\(ga -. ds D- D\h'-1'\(hy -. ds th \o'bp' -. ds Th \o'LP' -. ds ae ae -. ds Ae AE -.\} -.rm #[ #] #H #V #F C -.\" ======================================================================== -.\" -.IX Title "VISUDO @mansectsu@" -.TH VISUDO @mansectsu@ "July 14, 2010" "1.7.4" "MAINTENANCE COMMANDS" -.\" For nroff, turn off justification. Always turn off hyphenation; it makes -.\" way too many mistakes in technical documents. -.if n .ad l -.nh -.SH "NAME" -visudo \- edit the sudoers file -.SH "SYNOPSIS" -.IX Header "SYNOPSIS" -\&\fBvisudo\fR [\fB\-c\fR] [\fB\-q\fR] [\fB\-s\fR] [\fB\-V\fR] [\fB\-f\fR \fIsudoers\fR] -.SH "DESCRIPTION" -.IX Header "DESCRIPTION" -\&\fBvisudo\fR edits the \fIsudoers\fR file in a safe fashion, analogous to -\&\fIvipw\fR\|(@mansectsu@). \fBvisudo\fR locks the \fIsudoers\fR file against multiple -simultaneous edits, provides basic sanity checks, and checks -for parse errors. If the \fIsudoers\fR file is currently being -edited you will receive a message to try again later. -.PP -There is a hard-coded list of one or more editors that \fBvisudo\fR will -use set at compile-time that may be overridden via the \fIeditor\fR \fIsudoers\fR -\&\f(CW\*(C`Default\*(C'\fR variable. This list defaults to \f(CW"@editor@"\fR. Normally, -\&\fBvisudo\fR does not honor the \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR environment -variables unless they contain an editor in the aforementioned editors -list. However, if \fBvisudo\fR is configured with the \fI\-\-with\-env\-editor\fR -option or the \fIenv_editor\fR \f(CW\*(C`Default\*(C'\fR variable is set in \fIsudoers\fR, -\&\fBvisudo\fR will use any the editor defines by \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR. -Note that this can be a security hole since it allows the user to -execute any program they wish simply by setting \f(CW\*(C`VISUAL\*(C'\fR or \f(CW\*(C`EDITOR\*(C'\fR. -.PP -\&\fBvisudo\fR parses the \fIsudoers\fR file after the edit and will -not save the changes if there is a syntax error. Upon finding -an error, \fBvisudo\fR will print a message stating the line number(s) -where the error occurred and the user will receive the -\&\*(L"What now?\*(R" prompt. At this point the user may enter \*(L"e\*(R" -to re-edit the \fIsudoers\fR file, \*(L"x\*(R" to exit without -saving the changes, or \*(L"Q\*(R" to quit and save changes. The -\&\*(L"Q\*(R" option should be used with extreme care because if \fBvisudo\fR -believes there to be a parse error, so will \fBsudo\fR and no one -will be able to \fBsudo\fR again until the error is fixed. -If \*(L"e\*(R" is typed to edit the \fIsudoers\fR file after a parse error -has been detected, the cursor will be placed on the line where the -error occurred (if the editor supports this feature). -.SH "OPTIONS" -.IX Header "OPTIONS" -\&\fBvisudo\fR accepts the following command line options: -.IP "\-c" 12 -.IX Item "-c" -Enable \fBcheck-only\fR mode. The existing \fIsudoers\fR file will be -checked for syntax and a message will be printed to the -standard output detailing the status of \fIsudoers\fR. -If the syntax check completes successfully, \fBvisudo\fR will -exit with a value of 0. If a syntax error is encountered, -\&\fBvisudo\fR will exit with a value of 1. -.IP "\-f \fIsudoers\fR" 12 -.IX Item "-f sudoers" -Specify and alternate \fIsudoers\fR file location. With this option -\&\fBvisudo\fR will edit (or check) the \fIsudoers\fR file of your choice, -instead of the default, \fI@sysconfdir@/sudoers\fR. The lock file used -is the specified \fIsudoers\fR file with \*(L".tmp\*(R" appended to it. -.IP "\-q" 12 -.IX Item "-q" -Enable \fBquiet\fR mode. In this mode details about syntax errors -are not printed. This option is only useful when combined with -the \fB\-c\fR option. -.IP "\-s" 12 -.IX Item "-s" -Enable \fBstrict\fR checking of the \fIsudoers\fR file. If an alias is -used before it is defined, \fBvisudo\fR will consider this a parse -error. Note that it is not possible to differentiate between an -alias and a host name or user name that consists solely of uppercase -letters, digits, and the underscore ('_') character. -.IP "\-V" 12 -.IX Item "-V" -The \fB\-V\fR (version) option causes \fBvisudo\fR to print its version number -and exit. -.SH "ENVIRONMENT" -.IX Header "ENVIRONMENT" -The following environment variables may be consulted depending on -the value of the \fIeditor\fR and \fIenv_editor\fR \fIsudoers\fR variables: -.ie n .IP "\*(C`VISUAL\*(C'" 16 -.el .IP "\f(CW\*(C`VISUAL\*(C'\fR" 16 -.IX Item "VISUAL" -Invoked by visudo as the editor to use -.ie n .IP "\*(C`EDITOR\*(C'" 16 -.el .IP "\f(CW\*(C`EDITOR\*(C'\fR" 16 -.IX Item "EDITOR" -Used by visudo if \s-1VISUAL\s0 is not set -.SH "FILES" -.IX Header "FILES" -.ie n .IP "\fI@sysconfdir@/sudoers\fR" 24 -.el .IP "\fI@sysconfdir@/sudoers\fR" 24 -.IX Item "@sysconfdir@/sudoers" -List of who can run what -.ie n .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24 -.el .IP "\fI@sysconfdir@/sudoers.tmp\fR" 24 -.IX Item "@sysconfdir@/sudoers.tmp" -Lock file for visudo -.SH "DIAGNOSTICS" -.IX Header "DIAGNOSTICS" -.IP "sudoers file busy, try again later." 4 -.IX Item "sudoers file busy, try again later." -Someone else is currently editing the \fIsudoers\fR file. -.ie n .IP "@sysconfdir@/sudoers.tmp: Permission denied" 4 -.el .IP "\f(CW@sysconfdir\fR@/sudoers.tmp: Permission denied" 4 -.IX Item "@sysconfdir@/sudoers.tmp: Permission denied" -You didn't run \fBvisudo\fR as root. -.IP "Can't find you in the passwd database" 4 -.IX Item "Can't find you in the passwd database" -Your userid does not appear in the system passwd file. -.IP "Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined" 4 -.IX Item "Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined" -Either you are trying to use an undeclare {User,Runas,Host,Cmnd}_Alias -or you have a user or host name listed that consists solely of -uppercase letters, digits, and the underscore ('_') character. In -the latter case, you can ignore the warnings (\fBsudo\fR will not -complain). In \fB\-s\fR (strict) mode these are errors, not warnings. -.IP "Warning: unused {User,Runas,Host,Cmnd}_Alias" 4 -.IX Item "Warning: unused {User,Runas,Host,Cmnd}_Alias" -The specified {User,Runas,Host,Cmnd}_Alias was defined but never -used. You may wish to comment out or remove the unused alias. In -\&\fB\-s\fR (strict) mode this is an error, not a warning. -.SH "SEE ALSO" -.IX Header "SEE ALSO" -\&\fIvi\fR\|(1), \fIsudoers\fR\|(@mansectform@), \fIsudo\fR\|(@mansectsu@), \fIvipw\fR\|(8) -.SH "AUTHOR" -.IX Header "AUTHOR" -Many people have worked on \fIsudo\fR over the years; this version of -\&\fBvisudo\fR was written by: -.PP -.Vb 1 -\& Todd Miller -.Ve -.PP -See the \s-1HISTORY\s0 file in the sudo distribution or visit -http://www.sudo.ws/sudo/history.html for more details. -.SH "CAVEATS" -.IX Header "CAVEATS" -There is no easy way to prevent a user from gaining a root shell if -the editor used by \fBvisudo\fR allows shell escapes. -.SH "BUGS" -.IX Header "BUGS" -If you feel you have found a bug in \fBvisudo\fR, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ -.SH "SUPPORT" -.IX Header "SUPPORT" -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo\-users to subscribe or -search the archives. -.SH "DISCLAIMER" -.IX Header "DISCLAIMER" -\&\fBvisudo\fR is provided ``\s-1AS\s0 \s-1IS\s0'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the \s-1LICENSE\s0 -file distributed with \fBsudo\fR or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/visudo.pod b/visudo.pod deleted file mode 100644 index ccc5c00..0000000 --- a/visudo.pod +++ /dev/null @@ -1,206 +0,0 @@ -Copyright (c) 1996,1998-2005, 2007-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. -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Sponsored in part by the Defense Advanced Research Projects -Agency (DARPA) and Air Force Research Laboratory, Air Force -Materiel Command, USAF, under agreement number F39502-99-1-0512. - -=pod - -=head1 NAME - -visudo - edit the sudoers file - -=head1 SYNOPSIS - -B [B<-c>] [B<-q>] [B<-s>] [B<-V>] [B<-f> I] - -=head1 DESCRIPTION - -B edits the I file in a safe fashion, analogous to -L. B locks the I file against multiple -simultaneous edits, provides basic sanity checks, and checks -for parse errors. If the I file is currently being -edited you will receive a message to try again later. - -There is a hard-coded list of one or more editors that B will -use set at compile-time that may be overridden via the I I -C variable. This list defaults to C<"@editor@">. Normally, -B does not honor the C or C environment -variables unless they contain an editor in the aforementioned editors -list. However, if B is configured with the I<--with-env-editor> -option or the I C variable is set in I, -B will use any the editor defines by C or C. -Note that this can be a security hole since it allows the user to -execute any program they wish simply by setting C or C. - -B parses the I file after the edit and will -not save the changes if there is a syntax error. Upon finding -an error, B will print a message stating the line number(s) -where the error occurred and the user will receive the -"What now?" prompt. At this point the user may enter "e" -to re-edit the I file, "x" to exit without -saving the changes, or "Q" to quit and save changes. The -"Q" option should be used with extreme care because if B -believes there to be a parse error, so will B and no one -will be able to B again until the error is fixed. -If "e" is typed to edit the I file after a parse error -has been detected, the cursor will be placed on the line where the -error occurred (if the editor supports this feature). - -=head1 OPTIONS - -B accepts the following command line options: - -=over 12 - -=item -c - -Enable B mode. The existing I file will be -checked for syntax and a message will be printed to the -standard output detailing the status of I. -If the syntax check completes successfully, B will -exit with a value of 0. If a syntax error is encountered, -B will exit with a value of 1. - -=item -f I - -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. - -=item -q - -Enable B mode. In this mode details about syntax errors -are not printed. This option is only useful when combined with -the B<-c> option. - -=item -s - -Enable B checking of the I file. If an alias is -used before it is defined, B will consider this a parse -error. Note that it is not possible to differentiate between an -alias and a host name or user name that consists solely of uppercase -letters, digits, and the underscore ('_') character. - -=item -V - -The B<-V> (version) option causes B to print its version number -and exit. - -=back - -=head1 ENVIRONMENT - -The following environment variables may be consulted depending on -the value of the I and I I variables: - -=over 16 - -=item C - -Invoked by visudo as the editor to use - -=item C - -Used by visudo if VISUAL is not set - -=back - -=head1 FILES - -=over 24 - -=item F<@sysconfdir@/sudoers> - -List of who can run what - -=item F<@sysconfdir@/sudoers.tmp> - -Lock file for visudo - -=back - -=head1 DIAGNOSTICS - -=over 4 - -=item sudoers file busy, try again later. - -Someone else is currently editing the I file. - -=item @sysconfdir@/sudoers.tmp: Permission denied - -You didn't run B as root. - -=item Can't find you in the passwd database - -Your userid does not appear in the system passwd file. - -=item Warning: {User,Runas,Host,Cmnd}_Alias referenced but not defined - -Either you are trying to use an undeclare {User,Runas,Host,Cmnd}_Alias -or you have a user or host name listed that consists solely of -uppercase letters, digits, and the underscore ('_') character. In -the latter case, you can ignore the warnings (B will not -complain). In B<-s> (strict) mode these are errors, not warnings. - -=item Warning: unused {User,Runas,Host,Cmnd}_Alias - -The specified {User,Runas,Host,Cmnd}_Alias was defined but never -used. You may wish to comment out or remove the unused alias. In -B<-s> (strict) mode this is an error, not a warning. - -=back - -=head1 SEE ALSO - -L, L, L, L - -=head1 AUTHOR - -Many people have worked on I over the years; this version of -B was written by: - - Todd Miller - -See the HISTORY file in the sudo distribution or visit -http://www.sudo.ws/sudo/history.html for more details. - -=head1 CAVEATS - -There is no easy way to prevent a user from gaining a root shell if -the editor used by B allows shell escapes. - -=head1 BUGS - -If you feel you have found a bug in B, please submit a bug report -at http://www.sudo.ws/sudo/bugs/ - -=head1 SUPPORT - -Limited free support is available via the sudo-users mailing list, -see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or -search the archives. - -=head1 DISCLAIMER - -B is provided ``AS IS'' and any express or implied warranties, -including, but not limited to, the implied warranties of merchantability -and fitness for a particular purpose are disclaimed. See the LICENSE -file distributed with B or http://www.sudo.ws/sudo/license.html -for complete details. diff --git a/zero_bytes.c b/zero_bytes.c deleted file mode 100644 index 7391780..0000000 --- a/zero_bytes.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2003-2005, 2007 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. - */ - -#include - -#include -#include - -/* - * Like bzero(3) but with a volatile pointer. The hope is that - * the compiler will not be able to optimize away this function. - */ -void -zero_bytes(v, n) - volatile void *v; - size_t n; -{ - volatile char *p, *ep; - - for (p = v, ep = p + n; p < ep; p++) - *p = 0; - return; -} diff --git a/zlib/Makefile.in b/zlib/Makefile.in new file mode 100644 index 0000000..10faf0b --- /dev/null +++ b/zlib/Makefile.in @@ -0,0 +1,132 @@ +# +# 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. +# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# @configure_input@ +# + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Compiler & tools to use +CC = @CC@ +LIBTOOL = @LIBTOOL@ + +# C preprocessor flags +CPPFLAGS = -I. -I$(srcdir) + +# Usually -O and/or -g +CFLAGS = @CFLAGS@ + +# OS dependent defines +DEFS = @OSDEFS@ + +#### End of system configuration section. #### + +SHELL = @SHELL@ + +LTOBJS = adler32.lo compress.lo crc32.lo deflate.lo gzclose.lo gzlib.lo \ + gzread.lo gzwrite.lo infback.lo inffast.lo inflate.lo inftrees.lo \ + trees.lo uncompr.lo zutil.lo + +all: libz.la + +Makefile: $(srcdir)/Makefile.in + (cd $(top_builddir) && ./config.status --file zlib/Makefile) + +.SUFFIXES: .c .h .lo + +.c.lo: + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $< + +libz.la: $(LTOBJS) + $(LIBTOOL) --mode=link $(CC) -o $@ $(LTOBJS) -no-install + +pre-install: + +install: + +install-dirs: + +install-binaries: + +install-includes: + +install-doc: + +install-plugin: + +uninstall: + +check: + +clean: + -$(LIBTOOL) --mode=clean rm -f *.lo *.o *.la *.a stamp-* core *.core core.* + +mostlyclean: clean + +distclean: clean + -rm -rf Makefile .libs zconf.h + +clobber: distclean + +realclean: distclean + rm -f TAGS tags + +cleandir: realclean + +# Autogenerated dependencies, do not modify +adler32.lo: $(srcdir)/adler32.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/adler32.c +compress.lo: $(srcdir)/compress.c $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/compress.c +crc32.lo: $(srcdir)/crc32.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h \ + $(srcdir)/crc32.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/crc32.c +deflate.lo: $(srcdir)/deflate.c $(srcdir)/deflate.h $(srcdir)/zutil.h \ + $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/deflate.c +gzclose.lo: $(srcdir)/gzclose.c $(srcdir)/gzguts.h $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzclose.c +gzlib.lo: $(srcdir)/gzlib.c $(srcdir)/gzguts.h $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzlib.c +gzread.lo: $(srcdir)/gzread.c $(srcdir)/gzguts.h $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzread.c +gzwrite.lo: $(srcdir)/gzwrite.c $(srcdir)/gzguts.h $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/gzwrite.c +infback.lo: $(srcdir)/infback.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h \ + $(srcdir)/inftrees.h $(srcdir)/inflate.h $(srcdir)/inffast.h \ + $(srcdir)/inffixed.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/infback.c +inffast.lo: $(srcdir)/inffast.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h \ + $(srcdir)/inftrees.h $(srcdir)/inflate.h $(srcdir)/inffast.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/inffast.c +inflate.lo: $(srcdir)/inflate.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h \ + $(srcdir)/inftrees.h $(srcdir)/inflate.h $(srcdir)/inffast.h \ + $(srcdir)/inffixed.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/inflate.c +inftrees.lo: $(srcdir)/inftrees.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h \ + $(srcdir)/inftrees.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/inftrees.c +trees.lo: $(srcdir)/trees.c $(srcdir)/deflate.h $(srcdir)/zutil.h \ + $(srcdir)/zlib.h ./zconf.h $(srcdir)/trees.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/trees.c +uncompr.lo: $(srcdir)/uncompr.c $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/uncompr.c +zutil.lo: $(srcdir)/zutil.c $(srcdir)/zutil.h $(srcdir)/zlib.h ./zconf.h + $(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(DEFS) $(srcdir)/zutil.c diff --git a/zlib/adler32.c b/zlib/adler32.c new file mode 100644 index 0000000..a868f07 --- /dev/null +++ b/zlib/adler32.c @@ -0,0 +1,179 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 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_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521 /* 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 -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(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; + MOD28(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; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + 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..49598c0 --- /dev/null +++ b/zlib/crc32.c @@ -0,0 +1,447 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011 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(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#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 + typedef u4 crc_table_t; +# 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 + typedef unsigned long crc_table_t; +# 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_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local crc_table_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const crc_table_t 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() +{ + crc_table_t c; + int n, k; + crc_table_t 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 = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (crc_table_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (crc_table_t)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 crc_table_t 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 crc_table_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(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 *)(void 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..c3e7171 --- /dev/null +++ b/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const crc_table_t 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..8bd480e --- /dev/null +++ b/zlib/deflate.c @@ -0,0 +1,1965 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2012 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://tools.ietf.org/html/rfc1951 + * + * 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.6 Copyright 1995-2012 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 + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * 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) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#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 str, n; + int wrap; + unsigned avail; + unsigned char *next; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep (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); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +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 deflatePending (strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + deflate_state *s; + int put; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + 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; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->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 && RANK(flush) <= RANK(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; + s->insert = 0; + } + } + } + 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((voidpf)dest, (voidpf)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((voidpf)ds, (voidpf)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((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)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; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + 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->insert = 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; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + 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) break; + + /* 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 + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* 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; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* =========================================================================== + * 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); + } + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if ((long)s->strstart > s->block_start) + FLUSH_BLOCK(s, 0); + return 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); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return 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; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return 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 run, plus one for the unrolled loop. + */ + 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; + } + Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* 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); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return 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); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/zlib/deflate.h b/zlib/deflate.h new file mode 100644 index 0000000..fbac44d --- /dev/null +++ b/zlib/deflate.h @@ -0,0 +1,346 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2012 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 Buf_size 16 +/* size of bit buffer in bi_buf */ + +#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 suppress 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 */ + uInt insert; /* bytes at end of window left to insert */ + +#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_flush_bits OF((deflate_state *s)); +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..968ba7f --- /dev/null +++ b/zlib/gzguts.h @@ -0,0 +1,190 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010, 2011, 2012 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 __TURBOC__ +# include +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#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 + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# 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 ) +# include +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#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 memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#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 { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + 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) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* 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..7aedab8 --- /dev/null +++ b/zlib/gzlib.c @@ -0,0 +1,564 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004, 2010, 2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#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; +{ + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.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; + + /* check input */ + if (path == NULL) + return NULL; + + /* 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; + state->direct = 0; + 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; + case 'T': + state->direct = 1; + 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; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* 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 < 2) + size = 2; /* need two bytes to check magic header */ + 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 && state->err != Z_BUF_ERROR)) + 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 && state->err != Z_BUF_ERROR) + 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->x.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->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.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->x.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->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.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->x.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->past : 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; + state->past = 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; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* 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..46d40e0 --- /dev/null +++ b/zlib/gzread.c @@ -0,0 +1,584 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010, 2011 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_look OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_fetch 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. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(state) + gz_statep state; +{ + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) + memmove(state->in, strm->next_in, strm->avail_in); + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + 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. 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 will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + /* 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 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, 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->x.next = state->out; + if (strm->avail_in) { + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.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. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret = Z_OK; + unsigned had; + 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_BUF_ERROR, "unexpected end of file"); + break; + } + + /* 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 */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 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 to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + 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->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.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_fetch(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 (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + 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_DATA_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->x.have) { + n = state->x.have > len ? len : state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && strm->avail_in == 0) { + state->past = 1; /* tried to read past end */ + 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_fetch(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->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.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 (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gzread() */ + ret = gzread(file, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +#undef gzgetc +int ZEXPORT gzgetc(file) +gzFile file; +{ + return gzgetc_(file); +} + +/* -- 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 (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + 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->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; + 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 (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + 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->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + 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; + + /* 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->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret, err; + 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); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/zlib/gzwrite.c b/zlib/gzwrite.c new file mode 100644 index 0000000..caa35b6 --- /dev/null +++ b/zlib/gzwrite.c @@ -0,0 +1,593 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004, 2005, 2010, 2011, 2012 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 buffer */ + state->in = malloc(state->want); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = malloc(state->want); + if (state->out == 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, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + 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 if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.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. If gz->direct + is true, then simply write to the output file without compressing, and + ignore flush. */ +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; + + /* write directly if requested */ + if (state->direct) { + got = write(state->fd, strm->next_in, strm->avail_in); + if (got < 0 || (unsigned)got != strm->avail_in) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in = 0; + return 0; + } + + /* 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->x.next); + if (have && ((got = write(state->fd, state->x.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->x.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->x.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_DATA_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->x.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->x.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->x.pos++; + return c & 0xff; + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = c; + if (gzwrite(file, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- 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; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#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->x.pos += len; + return len; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- 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 can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return 0; + + /* 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->x.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 = Z_OK; + 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; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} + +/* used by zlibVersion() to get the vsnprintf story from the horse's mouth */ +unsigned long ZEXPORT gzflags() +{ + unsigned long flags = 0; +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# 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; +} diff --git a/zlib/infback.c b/zlib/infback.c new file mode 100644 index 0000000..981aff1 --- /dev/null +++ b/zlib/infback.c @@ -0,0 +1,640 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2011 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) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + 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) { + 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..d628327 --- /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 this 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..cc89517 --- /dev/null +++ b/zlib/inflate.c @@ -0,0 +1,1501 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2011 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 inflateResetKeep(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; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + 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 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; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +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) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + 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}", (low & 127) == 99 ? 64 : 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) { + 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 || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + 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; + unsigned char *next; + unsigned avail; + int ret; + + /* 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 using updatewindow(), which will amend the + existing dictionary if appropriate */ + next = strm->next_out; + avail = strm->avail_out; + strm->next_out = (Bytef *)dictionary + dictLength; + strm->avail_out = 0; + ret = updatewindow(strm, dictLength); + strm->avail_out = avail; + strm->next_out = next; + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + 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((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)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..60bbd58 --- /dev/null +++ b/zlib/inftrees.c @@ -0,0 +1,306 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2012 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.6 Copyright 1995-2012 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, 203, 69}; + 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 remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* 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..8c32b21 --- /dev/null +++ b/zlib/trees.c @@ -0,0 +1,1224 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2012 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. + */ + +/* =========================================================================== + * 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; +#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 */ +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +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); +} + +/* =========================================================================== + * 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); +} + +/* =========================================================================== + * 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 */ + + 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..b7f54d6 --- /dev/null +++ b/zlib/zconf.h.in @@ -0,0 +1,474 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2011 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 */ +# define Z_PREFIX_SET + +/* 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 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# 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 deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# 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 +# ifndef Z_SOLO +# 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 gzflags z_gzflags +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# 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 +# endif +# 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 inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# 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 +# ifndef Z_SOLO +# define gzFile z_gzFile +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# endif +# 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 */ +# ifndef Z_SOLO +# define gz_header_s z_gz_header_s +# endif +# 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 + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#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 + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(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 HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#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(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define Z_LARGE +#endif + +#if (defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE)) && !defined(Z_SOLO) +# 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 + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# 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(_WIN32) && (defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0) +# define z_off64_t off64_t +#else +# if defined(_WIN32) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +#endif +#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..79142d1 --- /dev/null +++ b/zlib/zlib.h @@ -0,0 +1,1732 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.6, January 29th, 2012 + + Copyright (C) 1995-2012 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://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.6" +#define ZLIB_VERNUM 0x1260 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 6 +#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 { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number 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 number of bytes output so far */ + + z_const 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). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and 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 not required to perform an + inflation in one step. However it may be used to inform inflate that a + faster approach can be used for the single inflate() call. Z_FINISH also + informs inflate to not maintain a sliding window if the stream completes, + which reduces inflate's memory footprint. + + 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 effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 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. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip 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. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. 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 not at a block boundary for raw deflate). 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(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +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, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, 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 at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. 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 possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible 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 parameters 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) + */ + +#ifndef Z_SOLO + + /* 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. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* 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 struct gzFile_s *gzFile; /* semi-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.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "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. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + 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. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + 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. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + 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 is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + 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 Z_ARG((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. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +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. + + 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(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +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, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, 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. +*/ + +#endif /* !Z_SOLO */ + + /* 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. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +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, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); +#define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc_(g)) + +/* 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 +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef _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 + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* 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)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#ifndef Z_SOLO + ZEXTERN unsigned long ZEXPORT gzflags OF((void)); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/zlib/zutil.c b/zlib/zutil.c new file mode 100644 index 0000000..8a1d242 --- /dev/null +++ b/zlib/zutil.c @@ -0,0 +1,301 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005, 2010, 2011 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 Z_SOLO + return flags; +#else + return flags + gzflags(); +#endif +} + +#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 + +#ifndef Z_SOLO + +#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 */ + +#endif /* !Z_SOLO */ diff --git a/zlib/zutil.h b/zlib/zutil.h new file mode 100644 index 0000000..dff1112 --- /dev/null +++ b/zlib/zutil.h @@ -0,0 +1,248 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2011 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" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#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 +# ifndef Z_SOLO +# 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 +#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 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# ifndef Z_SOLO +# 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 +#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__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && (!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(pyr) || defined(Z_SOLO) +# 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 + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#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 */