diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 14ac25326a..82f7aad14f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,25 +16,36 @@ on: paths: - '**.c' - '**.h' +permissions: {} jobs: Fuzzing: runs-on: ubuntu-latest + permissions: + security-events: write steps: - name: Build Fuzzers id: build uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'sudoers' - dry-run: false + language: c - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'sudoers' + language: c fuzz-seconds: 600 - dry-run: false + output-sarif: true - name: Upload Crash - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v3 if: failure() && steps.build.outcome == 'success' with: name: artifacts path: ./out/artifacts + - name: Upload Sarif + if: always() && steps.build.outcome == 'success' + uses: github/codeql-action/upload-sarif@v2 + with: + # Path to SARIF file relative to the root of the repository + sarif_file: cifuzz-sarif/results.sarif + checkout_path: cifuzz-sarif diff --git a/INSTALL.md b/INSTALL.md index fe2366be0c..a448b57ad0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -728,12 +728,12 @@ Defaults are listed in brackets after the description. By default, sudo requires the user to authenticate via a password or similar means. This options causes sudo to **not** require authentication. It is possible to turn - authentication back on in sudoers via the PASSWD attribute. + authentication back on in sudoers via the PASSWD attribute. Sudoers option: !authenticate --disable-env-reset Disable environment resetting. This sets the default value - of the "env_reset" Defaults option in sudoers to false. + of the "env_reset" Defaults option in sudoers to false. Sudoers option: !env_reset --disable-path-info @@ -742,43 +742,43 @@ Defaults are listed in brackets after the description. 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, sudo will tell - the user that they are not allowed to run it, which can be confusing. + the user that they are not allowed to run it, which can be confusing. Sudoers option: path_info --disable-root-sudo Don't let root run sudo. This can be used to prevent people from "chaining" sudo commands to get a root shell by doing something - like `sudo sudo /bin/sh`. + like `sudo sudo /bin/sh`. Sudoers option: !root_sudo --disable-zlib Disable the use of the zlib compress library when storing - I/O log files. + I/O log files. Sudoers option: !compress_io --enable-log-host - Log the hostname in the log file. + Log the hostname in the log file. Sudoers option: log_host --enable-noargs-shell If sudo is invoked with no arguments it acts as if the "-s" flag had been given. That is, it runs a shell as root (the shell is determined by the SHELL environment variable, falling back on the shell listed - in the invoking user's `/etc/passwd` entry). + in the invoking user's `/etc/passwd` entry). Sudoers option: shell_noargs --enable-shell-sets-home If sudo is invoked with the "-s" flag the HOME environment variable will be set to the home directory of the target user (which is root unless the "-u" option is used). This option effectively makes the - "-s" flag imply "-H". + "-s" flag imply "-H". Sudoers option: set_home --enable-timestamp-type=TYPE Set the default time stamp record type. The TYPE may be "global" (a single record per user), "ppid" (a single record for process with the same parent process), or "tty" (a separate record for - each login session). The default is "tty". + each login session). The default is "tty". Sudoers option: timestamp_type --with-all-insults @@ -796,13 +796,13 @@ Defaults are listed in brackets after the description. --with-badpass-message="MESSAGE" Message that is displayed if a user enters an incorrect password. - The default is "Sorry, try again." unless insults are turned on. + The default is "Sorry, try again." unless insults are turned on. Sudoers option: badpass_message --with-badpri=PRIORITY Determines which syslog priority to log unauthenticated commands and errors. The following priorities are supported: - alert, crit, debug, emerg, err, info, notice, and warning. + alert, crit, debug, emerg, err, info, notice, and warning. Sudoers option: syslog_badpri --with-classic-insults @@ -823,7 +823,7 @@ Defaults are listed in brackets after the description. single path name or a colon-separated list of editors. In the latter case, visudo will choose the editor that matches the user's SUDO_EDITOR, VISUAL or EDITOR environment variable, or the first editor in the list - that exists. The default is the path to vi on your system. + that exists. The default is the path to vi on your system. Sudoers option: editor --with-env-editor=no, --without-env-editor @@ -834,14 +834,14 @@ Defaults are listed in brackets after the description. commands as root without logging. Some sites may with to disable this and use a colon-separated list of "safe" editors with the --with-editor option. visudo will then only use the SUDO_EDITOR, VISUAL, or EDITOR - variables if they match a value specified via --with-editor. + variables if they match a value specified via --with-editor. Sudoers option: env_editor --with-exempt=GROUP Users in the specified group don't need to enter a password when running sudo. This may be useful for sites that don't want their "core" sysadmins to have to enter a password but where Jr. sysadmins - need to. You should probably use NOPASSWD in sudoers instead. + need to. You should probably use NOPASSWD in sudoers instead. Sudoers option: exempt_group --with-fqdn @@ -852,13 +852,13 @@ Defaults are listed in brackets after the description. sudo unusable if your DNS is totally hosed. 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. + way to get all aliases from DNS. Sudoers option: fqdn --with-goodpri=PRIORITY Determines which syslog priority to log successfully authenticated commands. The following priorities are supported: alert, crit, debug, - emerg, err, info, notice, and warning. + emerg, err, info, notice, and warning. Sudoers option: syslog_goodpri --with-python-insults @@ -878,7 +878,7 @@ Defaults are listed in brackets after the description. --with-ignore-dot If set, sudo will ignore "." or "" (current dir) in $PATH. - The $PATH itself is not modified. + The $PATH itself is not modified. Sudoers option: ignore_dot --with-insults @@ -900,11 +900,11 @@ Defaults are listed in brackets after the description. --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. + I/O logs will be stored in the indicated directory instead. Sudoers option: iolog_dir --with-lecture=no, --without-lecture - Don't print the lecture the first time a user runs sudo. + Don't print the lecture the first time a user runs sudo. Sudoers option: !lecture --with-logfac=FACILITY @@ -913,83 +913,83 @@ Defaults are listed in brackets after the description. this for ancient syslogs but it will have no effect. The following facilities are supported: authpriv (if your OS supports it), auth, daemon, user, local0, local1, local2, - local3, local4, local5, local6, and local7. + local3, local4, local5, local6, and local7. Sudoers option: syslog --with-logging=TYPE How you want to do your logging. You may choose "syslog", "file", or "both". Setting this to "syslog" is nice because you can keep all of your sudo logs in one place (see the - example syslog.conf file). The default is "syslog". + example syslog.conf file). The default is "syslog". Sudoers options: syslog and logfile --with-loglen=NUMBER Number of characters per line for the file log. This is only used if you are to "file" or "both". This value is used to decide when to wrap lines for nicer log files. The default is 80. Setting this to 0 - will disable the wrapping. + will disable the wrapping. Sudoers options: loglinelen --with-logpath=PATH Override the default location of the sudo log file and use "path" instead. By default will use /var/log/sudo.log if there is a /var/log dir, falling back to /var/adm/sudo.log - or /usr/adm/sudo.log if not. + or /usr/adm/sudo.log if not. Sudoers option: logfile --with-long-otp-prompt When validating with a One Time Password scheme (S/Key or OPIE), a two-line prompt is used to make it easier to cut and paste the challenge to a local window. It's not as - pretty as the default but some people find it more convenient. + pretty as the default but some people find it more convenient. Sudoers option: long_otp_prompt --with-mail-if-no-user=no, --without-mail-if-no-user Normally, sudo will mail to the "alertmail" user if the user invoking - sudo is not in the sudoers file. This option disables that behavior. + sudo is not in the sudoers file. This option disables that behavior. Sudoers option: mail_no_user --with-mail-if-no-host Send mail to the "alermail" user if the user exists in the sudoers - file, but is not allowed to run commands on the current host. + file, but is not allowed to run commands on the current host. Sudoers option: mail_no_host --with-mail-if-noperms Send mail to the "alermail" user if the user is allowed to use sudo but - the command they are trying is not listed in their sudoers file entry. + the command they are trying is not listed in their sudoers file entry. Sudoers option: mail_no_perms --with-mailsubject="SUBJECT" Subject of the mail sent to the "mailto" user. The token "%h" will expand to the hostname of the machine. - The default value is "*** SECURITY information for %h ***". + The default value is "*** SECURITY information for %h ***". Sudoers option: mailsub --with-mailto=USER|MAIL_ALIAS User (or mail alias) that mail from sudo is sent to. - This should go to a sysadmin at your site. The default value is "root". + This should go to a sysadmin at your site. The default value is "root". Sudoers option: mailto --with-passprompt="PROMPT" Default prompt to use when asking for a password; can be overridden via the -p option and the SUDO_PROMPT environment variable. Supports the "%H", "%h", "%U", and "%u" escapes as documented in the sudo - manual page. The default value is "Password:". + manual page. The default value is "Password:". Sudoers option: passprompt --with-password-timeout=NUMBER Number of minutes before the sudo password prompt times out. - The default is 5, set this to 0 for no password timeout. + The default is 5, set this to 0 for no password timeout. Sudoers option: passwd_timeout --with-passwd-tries=NUMBER Number of tries a user gets to enter his/her password before sudo logs - the failure and exits. The default is 3. + the failure and exits. The default is 3. Sudoers option: passwd_tries --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". + on the command line. This defaults to "root". Sudoers option: runas_default --with-secure-path[=PATH] @@ -1000,23 +1000,25 @@ Defaults are listed in brackets after the description. path for your site. This is not applied to users in the group specified by --with-exemptgroup. If you do not specify a path, "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - is used. + is used. Sudoers option: secure_path --with-secure-path-value[=PATH] Sets the value of "secure_path" that is substituted into - the default sudoers file. This option is intended to be - used by package maintainers who wish to set "secure_path" - to a system-specific value in the default sudoers file. - It does not actually enable "secure-path". + the default sudoers file. A value of "no" will cause the + "secure_path" line in the default sudoers file to be commented + out. This option is intended to be used by package maintainers + who wish to set "secure_path" to a system-specific value + in the default sudoers file. It does not actually enable + "secure-path" in the sudoers plugin itself. --with-sendmail=PATH - Override configure's guess as to the location of sendmail. + Override configure's guess as to the location of sendmail. Sudoers option: mailerpath --with-sendmail=no, --without-sendmail Do not use sendmail to mail messages to the "mailto" user. - Use only if you don't run sendmail or the equivalent. + Use only if you don't run sendmail or the equivalent. Sudoers options: !mailerpath or !mailto --with-sudoers-mode=MODE @@ -1037,21 +1039,21 @@ Defaults are listed in brackets after the description. --with-timeout=NUMBER Number of minutes that can elapse before sudo will ask for a passwd - again. The default is 5, set it to 0 to always prompt for a password. + again. The default is 5, set it to 0 to always prompt for a password. Sudoers option: timestamp_timeout --with-umask=MASK - Umask to use when running the root command. The default is 0022. + Umask to use when running the root command. The default is 0022. Sudoers option: umask --with-umask=no, --without-umask - Preserves the umask of the user invoking sudo. + Preserves the umask of the user invoking sudo. Sudoers option: !umask --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. + user's umask and the umask specified in sudoers. Sudoers option: umask_override ## OS dependent notes diff --git a/LICENSE.md b/LICENSE.md index b1a81239df..0aa321defd 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -247,9 +247,9 @@ The file inet_pton.c bears the following license: The file arc4random.c bears the following license: - Copyright (c) 1996, David Mazieres - Copyright (c) 2008, Damien Miller - Copyright (c) 2013, Markus Friedl + Copyright (c) 1996, David Mazieres + Copyright (c) 2008, Damien Miller + Copyright (c) 2013, Markus Friedl Copyright (c) 2014, Theo de Raadt Permission to use, copy, modify, and distribute this software for any @@ -282,7 +282,7 @@ The file arc4random_uniform.c bears the following license: The file getentropy.c bears the following license: - Copyright (c) 2014 Theo de Raadt + Copyright (c) 2014 Theo de Raadt Copyright (c) 2014 Bob Beck Permission to use, copy, modify, and distribute this software for any diff --git a/NEWS b/NEWS index 775d2d1c85..41cf250239 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,30 @@ +What's new in Sudo 1.9.16p1 + + * Fixed the test for cross-compiling when checking for C99 snprintf(). + The changes made to the test in sudo 1.9.16 resulted in a different + problem. GitHub issue #386. + + * Fixed the date used by the exit record in sudo-format log files. + This was a regression introduced in sudo 1.9.16 and only affected + file-based logs, not syslog. GitHub issue #405. + + * Fixed the root cause of the "unable to find terminal name for + device" message when running sudo on AIX when no terminal is + present. In sudo 1.9.16 this was turned from a debug message + into a warning. GitHub issue #408 + + * When a duplicate alias is found in the sudoers file, the warning + message now includes the file and line number of the previous + definition. + + * Added support for the --with-secure-path-value=no configure + option to allow packagers to ship the default sudoers file with + the secure path line commented out. + + * Sudo no longer sends mail when a user runs "sudo -nv" or "sudo -nl", + even if "mail_badpass" or "mail_always" are set. Sudo already + avoids logging to a file or syslog in this case. Bug #1072. + What's new in Sudo 1.9.16 * Added the "cmddenial_message" sudoers option to provide additional @@ -263,7 +290,7 @@ What's new in Sudo 1.9.14 The sudoers plugin will now change the root directory id needed before performing command matching. Previously, the root directory was simply prepended to the path that was being processed. - + * When NETGROUP_BASE is set in the ldap.conf file, sudo will now perform its own netgroup lookups of the host name instead of using the system innetgr(3) function. This guarantees that user @@ -273,7 +300,7 @@ What's new in Sudo 1.9.14 * Fixed a bug introduced in sudo 1.9.13 that resulted in a missing " ; " separator between environment variables and the command in log entries. - + * The visudo utility now displays a warning when it ignores a file in an include dir such as /etc/sudoers.d. @@ -442,7 +469,7 @@ What's new in Sudo 1.9.13 * Sudo no longer checks the ownership and mode of the plugins that it loads. Plugins are configured via either the sudo.conf or sudoers file which are trusted configuration files. These checks - suffered from time-of-check vs. time-of-use race conditions and + suffered from time-of-check versus time-of-use race conditions and complicate loading plugins that are not simple paths. Ownership and mode checks are still performed when loading the sudo.conf and sudoers files, which do not suffer from race conditions. @@ -531,7 +558,7 @@ What's new in Sudo 1.9.12 security policy. The new "intercept_verify" sudoers setting can be used to control this behavior. - * Fixed running commands with a relative path (e.g. ./foo) in + * Fixed running commands with a relative path (e.g., ./foo) in intercept mode. Previously, this would fail if sudo's current working directory was different from that of the command. @@ -596,7 +623,7 @@ What's new in Sudo 1.9.12 from the EDITOR environment variable. GitHub issue #179. * The sudo Python plugin now implements the "find_spec" method instead - of the the deprecated "find_module". This fixes a test failure when + of the deprecated "find_module". This fixes a test failure when a newer version of setuptools that doesn't include "find_module" is found on the system. @@ -831,7 +858,7 @@ What's new in Sudo 1.9.9 * visudo now only warns about an undefined alias or a cycle in an alias once for each alias. - + * The sudoRole cn was truncated by a single character in warning messages. GitHub issue #115. @@ -997,7 +1024,7 @@ What's new in Sudo 1.9.8 * The new "log_exit_status" sudoers setting can be used to log the exit status commands run via sudo. This is also a corresponding "log_exit" setting in the sudo_logsrvd.conf eventlog stanza. - + * Support for logging sudo_logsrvd errors via syslog or to a file. Previously, most sudo_logsrvd errors were only visible in the debug log. @@ -1042,7 +1069,7 @@ What's new in Sudo 1.9.7p2 to load a plugin with a name that conflicts with a Python module installed in the system location. - * Sudo no longer sets the the open files resource limit to "unlimited" + * Sudo no longer sets the open files resource limit to "unlimited" while it runs. This avoids a problem where sudo's closefrom() emulation would need to close a very large number of descriptors on systems without a way to determine which ones are actually open. @@ -1089,7 +1116,7 @@ What's new in Sudo 1.9.7 * The "fuzz" Makefile target now runs all the fuzzers for 8192 passes (can be overridden via the FUZZ_RUNS variable). This makes it easier to run the fuzzers in-tree. To run a fuzzer indefinitely, - set FUZZ_RUNS=-1, e.g. "make FUZZ_RUNS=-1 fuzz". + set FUZZ_RUNS=-1, e.g., "make FUZZ_RUNS=-1 fuzz". * Fixed fuzzing on FreeBSD where the ld.lld linker returns an error by default when a symbol is multiply-defined. @@ -1719,7 +1746,7 @@ What's new in Sudo 1.9.0 * Fixed an issue where PAM session modules could be called with the wrong user name when multiple users in the passwd database - share the the same user-ID. Debian bug #734752. + share the same user-ID. Debian bug #734752. * Sudo command line options that take a value may only be specified once. This is to help guard against problems caused by poorly @@ -1766,7 +1793,7 @@ What's new in Sudo 1.8.30 * Sudo now treats an attempt to run "sudo sudoedit" as simply "sudoedit". If the sudoers file contains a fully-qualified path to sudoedit, sudo will now treat it simply as "sudoedit" (with - no path). Visudo will will now treat a fully-qualified path + no path). Visudo will now treat a fully-qualified path to sudoedit as an error. Bug #871. * Fixed a bug introduced in sudo 1.8.28 where sudo would warn about @@ -2826,7 +2853,7 @@ What's new in Sudo 1.8.15 * When the command sudo is running dies due to a signal, sudo will now send itself that same signal with the default signal handler installed instead of exiting. The bash shell appears to ignore - some signals, e.g. SIGINT, unless the command being run is killed + some signals, e.g., SIGINT, unless the command being run is killed by that signal. This makes the behavior of commands run under sudo the same as without sudo when bash is the shell. Bug #722 @@ -3620,7 +3647,7 @@ What's new in Sudo 1.8.6p1? What's new in Sudo 1.8.6? - * Sudo is now built with the -fstack-protector flag if the the + * Sudo is now built with the -fstack-protector flag if the compiler supports it. Also, the -zrelro linker flag is used if supported. The --disable-hardening configure option can be used to build sudo without stack smashing protection. @@ -3758,7 +3785,7 @@ What's new in Sudo 1.8.5? * 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. + 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 @@ -3766,7 +3793,7 @@ What's new in Sudo 1.8.5? 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). + 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. @@ -3877,19 +3904,19 @@ What's new in Sudo 1.8.4? * 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 + 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 + 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" + 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 @@ -4076,7 +4103,7 @@ What's new in Sudo 1.8.1? 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" + 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. @@ -4377,7 +4404,7 @@ What's new in Sudo 1.7.3? now taken into account when looking up users and groups. Sudo now applies the correct the user and group ids when running a command as a user whose account details come from a different - source (e.g. LDAP or DCE vs. local files). + source (e.g., LDAP or DCE versus local files). * Support for multiple 'sudoers_base' and 'uri' entries in ldap.conf. When multiple entries are listed, sudo will try each one in the diff --git a/README.LDAP.md b/README.LDAP.md index bccda62f5b..7eb4da0b96 100644 --- a/README.LDAP.md +++ b/README.LDAP.md @@ -60,7 +60,7 @@ can store sudoers content. For OpenLDAP, there are two options, depending on how slapd is configured. The first option is to copy the file schema.OpenLDAP to the schema -directory (e.g. /etc/openldap/schema). You must then edit your +directory (e.g., /etc/openldap/schema). You must then edit your slapd.conf and add an include line the new schema, for example: # Sudo LDAP schema diff --git a/configure b/configure index 18eb2bdf27..135adec9be 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for sudo 1.9.16. +# Generated by GNU Autoconf 2.72 for sudo 1.9.16p1. # # Report bugs to . # @@ -614,8 +614,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sudo' PACKAGE_TARNAME='sudo' -PACKAGE_VERSION='1.9.16' -PACKAGE_STRING='sudo 1.9.16' +PACKAGE_VERSION='1.9.16p1' +PACKAGE_STRING='sudo 1.9.16p1' PACKAGE_BUGREPORT='https://bugzilla.sudo.ws/' PACKAGE_URL='' @@ -734,6 +734,7 @@ pam_login_service pam_session editor secure_path_status +secure_path_config secure_path netsvc_conf nsswitch_conf @@ -1644,7 +1645,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.9.16 to adapt to many kinds of systems. +'configure' configures sudo 1.9.16p1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1710,7 +1711,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of sudo 1.9.16:";; + short | recursive ) echo "Configuration of sudo 1.9.16p1:";; esac cat <<\_ACEOF @@ -1885,7 +1886,8 @@ Optional Packages: --with-ldap-conf-file path to LDAP configuration file --with-ldap-secret-file path to LDAP secret password file --with-secure-path-value - value of secure_path in the default sudoers file + value of secure_path in the default sudoers file, or + "no" to comment out by default --with-secure-path override the user's path with a built-in one --without-interfaces don't try to read the ip addr of network interfaces --with-askpass=PATH Fully qualified pathname of askpass helper @@ -2004,7 +2006,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -sudo configure 1.9.16 +sudo configure 1.9.16p1 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -2824,7 +2826,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by sudo $as_me 1.9.16, which was +It was created by sudo $as_me 1.9.16p1, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3685,6 +3687,7 @@ sudoers_path='$(sysconfdir)/sudoers' + # @@ -3733,6 +3736,7 @@ sesh_file="$libexecdir/sudo/sesh" visudo="$sbindir/visudo" nsswitch_conf=/etc/nsswitch.conf secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +secure_path_config= secure_path_status="disabled" pam_session=on pam_login_service=sudo @@ -6314,7 +6318,9 @@ EOF if test ${with_secure_path_value+y} then : withval=$with_secure_path_value; case $with_secure_path_value in - yes|no) as_fn_error $? "must give --secure-path-value an argument." "$LINENO" 5 + yes) as_fn_error $? "must give --with-secure-path-value an argument." "$LINENO" 5 + ;; + no) secure_path_config="# " ;; *) secure_path="$with_secure_path_value" ;; @@ -24790,7 +24796,31 @@ esac COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }mktemp_test" fi -ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" +if test X"$ac_cv_build_prog_cc_c99" != X"no" -a X"$cross_compiling" = X"yes" +then : + + # If we have a C99 compiler and are cross-compiling, assume + # C99-compliant v?snprintf(). + ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" +if test "x$ac_cv_func_snprintf" = xyes +then : + printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h + +fi +ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" +if test "x$ac_cv_func_vsnprintf" = xyes +then : + printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h + +fi + + ac_cv_have_working_snprintf="$ac_cv_func_snprintf" + ac_cv_have_working_vsnprintf="$ac_cv_func_vsnprintf" + +else case e in #( + e) + # Check for C99-compliant v?snprintf(). + ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h @@ -24919,19 +24949,8 @@ printf "%s\n" "$as_me: WARNING: Replacing missing/broken (v)snprintf() with sudo printf "%s\n" "#define PREFER_PORTABLE_SNPRINTF 1" >>confdefs.h fi -if test X"$ac_cv_build_prog_cc_c99" != X"no" -then : - - # If we have a C99 compiler and are cross-compiling, assume - # C99-compliant v?snprintf(). - if test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"crosscross" -then : - - ac_cv_have_working_snprintf=yes - ac_cv_have_working_vsnprintf=yes - -fi - + ;; +esac fi if test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"yesyes" then : @@ -36755,7 +36774,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by sudo $as_me 1.9.16, which was +This file was extended by sudo $as_me 1.9.16p1, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -36823,7 +36842,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -sudo config.status 1.9.16 +sudo config.status 1.9.16p1 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 28b63ef0d8..15a4047d36 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ dnl ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. dnl AC_PREREQ([2.69]) -AC_INIT([sudo], [1.9.16], [https://bugzilla.sudo.ws/], [sudo]) +AC_INIT([sudo], [1.9.16p1], [https://bugzilla.sudo.ws/], [sudo]) AC_CONFIG_HEADERS([config.h pathnames.h]) AC_CONFIG_SRCDIR([src/sudo.c]) AC_CONFIG_AUX_DIR([scripts]) @@ -177,6 +177,7 @@ AC_SUBST([sssd_lib]) AC_SUBST([nsswitch_conf]) AC_SUBST([netsvc_conf]) AC_SUBST([secure_path]) +AC_SUBST([secure_path_config]) AC_SUBST([secure_path_status]) AC_SUBST([editor]) AC_SUBST([pam_session]) @@ -230,6 +231,7 @@ sesh_file="$libexecdir/sudo/sesh" visudo="$sbindir/visudo" nsswitch_conf=/etc/nsswitch.conf secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +secure_path_config= secure_path_status="disabled" pam_session=on pam_login_service=sudo @@ -1068,9 +1070,11 @@ AC_ARG_WITH(ldap-secret-file, [AS_HELP_STRING([--with-ldap-secret-file], [path t test -n "$with_ldap_secret_file" && ldap_secret="$with_ldap_secret_file" SUDO_DEFINE_UNQUOTED(_PATH_LDAP_SECRET, "$ldap_secret", [Path to the ldap.secret file]) -AC_ARG_WITH(secure-path-value, [AS_HELP_STRING([--with-secure-path-value], [value of secure_path in the default sudoers file])], +AC_ARG_WITH(secure-path-value, [AS_HELP_STRING([--with-secure-path-value], [value of secure_path in the default sudoers file, or "no" to comment out by default])], [case $with_secure_path_value in - yes|no) AC_MSG_ERROR([must give --secure-path-value an argument.]) + yes) AC_MSG_ERROR([must give --with-secure-path-value an argument.]) + ;; + no) secure_path_config="# " ;; *) secure_path="$with_secure_path_value" ;; @@ -3060,14 +3064,15 @@ AS_IF([test X"$sudo_mktemp" = X"yes"], [ SUDO_APPEND_COMPAT_EXP(sudo_mkdtemp sudo_mkdtempat sudo_mkostempsat sudo_mkstemp sudo_mkstemps) COMPAT_TEST_PROGS="${COMPAT_TEST_PROGS}${COMPAT_TEST_PROGS+ }mktemp_test" ]) -AX_FUNC_SNPRINTF -AS_IF([test X"$ac_cv_prog_cc_c99" != X"no"], [ +AS_IF([test X"$ac_cv_prog_cc_c99" != X"no" -a X"$cross_compiling" = X"yes"], [ # If we have a C99 compiler and are cross-compiling, assume # C99-compliant v?snprintf(). - AS_IF([test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"crosscross"], [ - ac_cv_have_working_snprintf=yes - ac_cv_have_working_vsnprintf=yes - ]) + AC_CHECK_FUNCS(snprintf vsnprintf) + ac_cv_have_working_snprintf="$ac_cv_func_snprintf" + ac_cv_have_working_vsnprintf="$ac_cv_func_vsnprintf" +], [ + # Check for C99-compliant v?snprintf(). + AX_FUNC_SNPRINTF ]) AS_IF([test X"$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf" = X"yesyes"], [ # System has a C99-compliant v?snprintf(), check for v?asprintf() diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 415ca4165c..726a06d843 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -36,7 +36,7 @@ work flows: * clone the [sudo repo](https://github.com/sudo-project/sudo), make your changes, and submit a Pull Request (PR). - + * send a diff with your changes to the [sudo-workers@sudo.ws mailing list](https://www.sudo.ws/mailman/listinfo/sudo-workers) to start a discussion. diff --git a/docs/Makefile.in b/docs/Makefile.in index b9ba1bb4cf..ed67bb70b6 100644 --- a/docs/Makefile.in +++ b/docs/Makefile.in @@ -102,18 +102,20 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ all: $(DEVDOCS) $(DOCS) -igor: all - @if [ "$(mantype)" != "mdoc" ]; then \ - echo "make igor only supported for mdoc manuals" 1>&2; \ - exit 1; \ - else \ - rval=0; \ - for m in $(DOCS); do \ - echo $(IGOR) -D $$m; \ - $(IGOR) -D $$m || rval=`expr $$rval + $$?`; \ - done; \ - exit $$rval; \ - fi +igor: + @rval=0; \ + for f in *.mdoc.in; do \ + echo $(IGOR) -D $$f; \ + $(IGOR) -D $$f || rval=`expr $$rval + $$?`; \ + done; \ + for f in $(OTHER_DOCS) $(OTHER_DOCS_LDAP); do \ + case `basename $$f` in \ + [A-Z][A-Z]*) \ + echo $(IGOR) -abrw $$f; \ + $(IGOR) -abrw $$f || rval=`expr $$rval + $$?`;; \ + esac; \ + done; \ + exit $$rval lint: all @if [ "$(mantype)" != "mdoc" ]; then \ diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 1bb2680f7e..953ebfbd9d 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -13,7 +13,7 @@ We try to respond to security issues in a timely manner but understand that Sudo Include as much of the following information as possible to help us better understand the nature and scope of the potential issue: - * Type of issue (e.g. buffer overflow, privilege escalation, etc.) + * Type of issue (e.g., buffer overflow, privilege escalation, etc.) * Full paths of source file(s) related to the issue * The location of the affected source code (tag/branch/commit or direct URL) * Any special configuration required to reproduce the issue diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 2d3b72173e..216ed11690 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -95,10 +95,10 @@ It just says "Sorry, try again." three times and exits. > 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 (e.g.: touch /var/log/sudo). +> to it (e.g., `touch /var/log/sudo`). -> The facility (e.g. 'auth.debug') must be separated from -> the destination (e.g. '/var/log/auth' or '@loghost') by tabs, +> 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. #### Sudo won't accept my password, even when entered correctly @@ -137,9 +137,9 @@ It just says "Sorry, try again." three times and exits. > site you may be interested in sudo's LDAP sudoers support, see > [README.LDAP.md](../README.LDAP.md) and the sudoers.ldap manual. -#### I don't run sendmail, does this mean that I cannot use sudo? +#### I don't run sendmail, can I still use sudo? -> No, you just need to disable mailing with a line like: +> Yes, you just need to disable mailing with a line like: Defaults !mailerpath diff --git a/docs/UPGRADE.md b/docs/UPGRADE.md index 83df1f44cc..81f7285edc 100644 --- a/docs/UPGRADE.md +++ b/docs/UPGRADE.md @@ -35,7 +35,7 @@ Notes on upgrading from an older release Defaults !use_pty * Upgrading from a version prior to 1.9.13: - + Sudo now builds AIX-style shared libraries and dynamic shared objects by default instead of svr4-style. This means that the default sudo plugins are now .a (archive) files that contain a @@ -294,8 +294,8 @@ Notes on upgrading from an older release important that the time stamp files not persist when the system reboots. For this reason, the default location for the time stamp files has changed back to a directory located in `/var/run`. - Systems that do not have `/var/run` (e.g. AIX) or that do not clear - it on boot (e.g. HP-UX) will need to clear the time stamp + Systems that do not have `/var/run` (e.g., AIX) or that do not clear + it on boot (e.g., HP-UX) will need to clear the time stamp directory via a start up script. Such a script is installed by default on AIX and HP-UX systems. @@ -504,7 +504,7 @@ Notes on upgrading from an older release When sudo is build with LDAP support the `/etc/nsswitch.conf` file is now used to determine the sudoers sea ch 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.: + This can be changed with an nsswitch.conf line, for example: sudoers: ldap files @@ -548,7 +548,7 @@ Notes on upgrading from an older release 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 + 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. diff --git a/docs/sudoers.man.in b/docs/sudoers.man.in index 3e19c0ed3a..34da19e412 100644 --- a/docs/sudoers.man.in +++ b/docs/sudoers.man.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.TH "SUDOERS" "@mansectform@" "July 14, 2024" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDOERS" "@mansectform@" "November 11, 2024" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -3838,7 +3838,7 @@ This flag is \fIon\fR by default. .sp -This setting is only supported by version 1.8.16 or higher. +This setting is only supported by version 1.9.16 or higher. .TP 18n passprompt_override If set, the prompt specified by @@ -5570,11 +5570,16 @@ The \fIrestricted_env_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 +Entries in this file should be assignments in the form \(oqVARIABLE=value\(cq or -\(oqexport VARIABLE=value\(cq. +\(oqexport VARIABLE=value\(cq, +separated by newline characters. The value may optionally be enclosed in single or double quotes. +Shell-style variable substitution is not supported. +Empty lines and comments starting with a pound sign +(\(oq#\(cq) +are ignored. Variables in this file are only added if the variable does not already exist in the environment. Unlike diff --git a/docs/sudoers.mdoc.in b/docs/sudoers.mdoc.in index 180f147e33..810a407705 100644 --- a/docs/sudoers.mdoc.in +++ b/docs/sudoers.mdoc.in @@ -25,7 +25,7 @@ .nr BA @BAMAN@ .nr LC @LCMAN@ .nr PS @PSMAN@ -.Dd July 14, 2024 +.Dd November 11, 2024 .Dt SUDOERS @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -3637,7 +3637,7 @@ This flag is .Em on by default. .Pp -This setting is only supported by version 1.8.16 or higher. +This setting is only supported by version 1.9.16 or higher. .It passprompt_override If set, the prompt specified by .Em passprompt @@ -5220,11 +5220,16 @@ The .Em restricted_env_file 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 +Entries in this file should be assignments in the form .Ql VARIABLE=value or -.Ql export VARIABLE=value . +.Ql export VARIABLE=value , +separated by newline characters. The value may optionally be enclosed in single or double quotes. +Shell-style variable substitution is not supported. +Empty lines and comments starting with a pound sign +.Pq Ql # +are ignored. Variables in this file are only added if the variable does not already exist in the environment. Unlike diff --git a/lib/eventlog/eventlog.c b/lib/eventlog/eventlog.c index 5d4a832623..5a32824645 100644 --- a/lib/eventlog/eventlog.c +++ b/lib/eventlog/eventlog.c @@ -1453,6 +1453,7 @@ eventlog_exit(const struct eventlog *evlog, int flags) bool ret = true; debug_decl(eventlog_exit, SUDO_DEBUG_UTIL); + /* We expect evlog->event_time to be the command start time. */ if (sudo_timespecisset(&evlog->run_time)) { sudo_timespecadd(&evlog->event_time, &evlog->run_time, &exit_time); args.event_time = &exit_time; diff --git a/logsrvd/logsrvd_local.c b/logsrvd/logsrvd_local.c index 024ae7cfa3..f863e5a237 100644 --- a/logsrvd/logsrvd_local.c +++ b/logsrvd/logsrvd_local.c @@ -423,7 +423,7 @@ store_exit_local(ExitMessage *msg, uint8_t *buf, size_t len, "command exited with %d", msg->exit_value); } if (logsrvd_conf_log_exit()) { - if (!eventlog_exit(closure->evlog, flags)) { + if (!eventlog_exit(evlog, flags)) { closure->errstr = _("error logging exit event"); debug_return_bool(false); } diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c index 3b678bf4d4..973d67bce5 100644 --- a/plugins/sudoers/auth/pam.c +++ b/plugins/sudoers/auth/pam.c @@ -297,25 +297,26 @@ int sudo_pam_verify(const struct sudoers_context *ctx, struct passwd *pw, const char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback) { - const char *envccname; - const char *s; - int *pam_status = (int *)auth->data; + const char *envccname, *pam_user; + int rc, *pam_status = (int *)auth->data; debug_decl(sudo_pam_verify, SUDOERS_DEBUG_AUTH); def_prompt = prompt; /* for converse */ getpass_error = false; /* set by converse if user presses ^C */ pam_closure.callback = callback; /* passed to conversation function */ - /* Set KRB5CCNAME from the user environment if not set to propagate this - * information to PAM modules that may use it to authentication. */ - envccname = sudo_getenv("KRB5CCNAME"); - if (envccname == NULL && ctx->user.ccname != NULL) { - if (sudo_setenv("KRB5CCNAME", ctx->user.ccname, true) != 0) { - sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, - "unable to set KRB5CCNAME"); - debug_return_int(AUTH_FAILURE); - } + /* + * Set KRB5CCNAME from the user environment if not set to propagate this + * information to PAM modules that may use it to authentication. + */ + envccname = sudo_getenv("KRB5CCNAME"); + if (envccname == NULL && ctx->user.ccname != NULL) { + if (sudo_setenv("KRB5CCNAME", ctx->user.ccname, true) != 0) { + sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, + "unable to set KRB5CCNAME"); + debug_return_int(AUTH_FAILURE); } + } /* PAM_SILENT prevents the authentication service from generating output. */ *pam_status = pam_authenticate(pamh, def_pam_silent ? PAM_SILENT : 0); @@ -323,31 +324,41 @@ sudo_pam_verify(const struct sudoers_context *ctx, struct passwd *pw, /* Restore def_prompt, the passed-in prompt may be freed later. */ def_prompt = PASSPROMPT; - /* Restore KRB5CCNAME to its original value. */ - if (envccname == NULL && sudo_unsetenv("KRB5CCNAME") != 0) { - sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, - "unable to restore KRB5CCNAME"); - debug_return_int(AUTH_FAILURE); - } + /* Restore KRB5CCNAME to its original value. */ + if (envccname == NULL && sudo_unsetenv("KRB5CCNAME") != 0) { + sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, + "unable to restore KRB5CCNAME"); + debug_return_int(AUTH_FAILURE); + } if (getpass_error) { /* error or ^C from tgetpass() or running non-interactive */ debug_return_int(noninteractive ? AUTH_NONINTERACTIVE : AUTH_INTR); } + switch (*pam_status) { - case PAM_SUCCESS: - debug_return_int(AUTH_SUCCESS); - case PAM_AUTH_ERR: - case PAM_AUTHINFO_UNAVAIL: - case PAM_MAXTRIES: - case PAM_PERM_DENIED: + case PAM_SUCCESS: + /* Verify user did not change during PAM transaction. */ + rc = pam_get_item(pamh, PAM_USER, (PAM_CONST void **)&pam_user); + if (rc == PAM_SUCCESS && + (pam_user == NULL || strcmp(pam_user, pw->pw_name) != 0)) { sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, - "pam_authenticate: %d", *pam_status); + "unable to authenticate '%s' as user '%s'", + pw->pw_name, pam_user); debug_return_int(AUTH_FAILURE); - default: - s = sudo_pam_strerror(pamh, *pam_status); - log_warningx(ctx, 0, N_("PAM authentication error: %s"), s); - debug_return_int(AUTH_ERROR); + } + debug_return_int(AUTH_SUCCESS); + case PAM_AUTH_ERR: + case PAM_AUTHINFO_UNAVAIL: + case PAM_MAXTRIES: + case PAM_PERM_DENIED: + sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_LINENO, + "pam_authenticate: %d", *pam_status); + debug_return_int(AUTH_FAILURE); + default: + log_warningx(ctx, 0, N_("PAM authentication error: %s"), + sudo_pam_strerror(pamh, *pam_status)); + debug_return_int(AUTH_ERROR); } } @@ -363,59 +374,59 @@ sudo_pam_approval(const struct sudoers_context *ctx, struct passwd *pw, if (def_pam_acct_mgmt) { rc = pam_acct_mgmt(pamh, PAM_SILENT); switch (rc) { - case PAM_SUCCESS: - break; - case PAM_AUTH_ERR: - log_warningx(ctx, 0, N_("account validation failure, " - "is your account locked?")); - status = AUTH_ERROR; - break; - case PAM_NEW_AUTHTOK_REQD: - /* Ignore if user is exempt from password restrictions. */ - if (exempt) { - rc = *pam_status; - break; - } - /* New password required, try to change it. */ - log_warningx(ctx, 0, N_("Account or password is " - "expired, reset your password and try again")); - rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); - if (rc == PAM_SUCCESS) - break; - s = pam_strerror(pamh, rc); - log_warningx(ctx, 0, - N_("unable to change expired password: %s"), s); - status = AUTH_FAILURE; - break; - case PAM_AUTHTOK_EXPIRED: - /* Ignore if user is exempt from password restrictions. */ - if (exempt) { - rc = *pam_status; - break; - } - /* Password expired, cannot be updated by user. */ - log_warningx(ctx, 0, - N_("Password expired, contact your system administrator")); - status = AUTH_ERROR; - break; - case PAM_ACCT_EXPIRED: - log_warningx(ctx, 0, - N_("Account expired or PAM config lacks an \"account\" " - "section for sudo, contact your system administrator")); - status = AUTH_ERROR; + case PAM_SUCCESS: + break; + case PAM_AUTH_ERR: + log_warningx(ctx, 0, N_("account validation failure, " + "is your account locked?")); + status = AUTH_ERROR; + break; + case PAM_NEW_AUTHTOK_REQD: + /* Ignore if user is exempt from password restrictions. */ + if (exempt) { + rc = *pam_status; break; - case PAM_AUTHINFO_UNAVAIL: - case PAM_MAXTRIES: - case PAM_PERM_DENIED: - s = sudo_pam_strerror(pamh, rc); - log_warningx(ctx, 0, N_("PAM account management error: %s"), s); - status = AUTH_FAILURE; + } + /* New password required, try to change it. */ + log_warningx(ctx, 0, N_("Account or password is " + "expired, reset your password and try again")); + rc = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); + if (rc == PAM_SUCCESS) break; - default: - s = sudo_pam_strerror(pamh, rc); - log_warningx(ctx, 0, N_("PAM account management error: %s"), s); - status = AUTH_ERROR; + s = pam_strerror(pamh, rc); + log_warningx(ctx, 0, + N_("unable to change expired password: %s"), s); + status = AUTH_FAILURE; + break; + case PAM_AUTHTOK_EXPIRED: + /* Ignore if user is exempt from password restrictions. */ + if (exempt) { + rc = *pam_status; break; + } + /* Password expired, cannot be updated by user. */ + log_warningx(ctx, 0, + N_("Password expired, contact your system administrator")); + status = AUTH_ERROR; + break; + case PAM_ACCT_EXPIRED: + log_warningx(ctx, 0, + N_("Account expired or PAM config lacks an \"account\" " + "section for sudo, contact your system administrator")); + status = AUTH_ERROR; + break; + case PAM_AUTHINFO_UNAVAIL: + case PAM_MAXTRIES: + case PAM_PERM_DENIED: + s = sudo_pam_strerror(pamh, rc); + log_warningx(ctx, 0, N_("PAM account management error: %s"), s); + status = AUTH_FAILURE; + break; + default: + s = sudo_pam_strerror(pamh, rc); + log_warningx(ctx, 0, N_("PAM account management error: %s"), s); + status = AUTH_ERROR; + break; } *pam_status = rc; } @@ -706,53 +717,53 @@ converse(int num_msg, PAM_CONST struct pam_message **msg, 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: - /* Error out if the last password read was interrupted. */ - if (getpass_error) - goto bad; - - /* Treat non-interactive mode as a getpass error. */ - if (noninteractive) { - getpass_error = true; - goto bad; - } + case PAM_PROMPT_ECHO_ON: + type = SUDO_CONV_PROMPT_ECHO_ON; + FALLTHROUGH; + case PAM_PROMPT_ECHO_OFF: + /* Error out if the last password read was interrupted. */ + if (getpass_error) + goto bad; - /* Choose either the sudo prompt or the PAM one. */ - prompt = use_pam_prompt(pm->msg) ? pm->msg : def_prompt; + /* Treat non-interactive mode as a getpass error. */ + if (noninteractive) { + getpass_error = true; + goto bad; + } - /* Read the password unless interrupted. */ - pass = auth_getpass(prompt, type, callback); - if (pass == NULL) { - /* Error (or ^C) reading password, don't try again. */ - getpass_error = true; - goto bad; - } - if (strlen(pass) >= PAM_MAX_RESP_SIZE) { - sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "password longer than %d", PAM_MAX_RESP_SIZE); - freezero(pass, strlen(pass)); - pass = NULL; - goto bad; - } - reply[n].resp = pass; /* auth_getpass() malloc's a copy */ - break; - case PAM_TEXT_INFO: - if (pm->msg != NULL && !is_filtered(pm->msg)) - sudo_printf(SUDO_CONV_INFO_MSG|SUDO_CONV_PREFER_TTY, - "%s\n", pm->msg); - break; - case PAM_ERROR_MSG: - if (pm->msg != NULL) - sudo_printf(SUDO_CONV_ERROR_MSG|SUDO_CONV_PREFER_TTY, - "%s\n", pm->msg); - break; - default: + /* Choose either the sudo prompt or the PAM one. */ + prompt = use_pam_prompt(pm->msg) ? pm->msg : def_prompt; + + /* Read the password unless interrupted. */ + pass = auth_getpass(prompt, type, callback); + if (pass == NULL) { + /* Error (or ^C) reading password, don't try again. */ + getpass_error = true; + goto bad; + } + if (strlen(pass) >= PAM_MAX_RESP_SIZE) { sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, - "unsupported message style: %d", pm->msg_style); + "password longer than %d", PAM_MAX_RESP_SIZE); + freezero(pass, strlen(pass)); + pass = NULL; goto bad; + } + reply[n].resp = pass; /* auth_getpass() malloc's a copy */ + break; + case PAM_TEXT_INFO: + if (pm->msg != NULL && !is_filtered(pm->msg)) + sudo_printf(SUDO_CONV_INFO_MSG|SUDO_CONV_PREFER_TTY, + "%s\n", pm->msg); + break; + case PAM_ERROR_MSG: + if (pm->msg != NULL) + sudo_printf(SUDO_CONV_ERROR_MSG|SUDO_CONV_PREFER_TTY, + "%s\n", pm->msg); + break; + default: + sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO, + "unsupported message style: %d", pm->msg_style); + goto bad; } } diff --git a/plugins/sudoers/gram.c b/plugins/sudoers/gram.c index 668c35ec8f..82cd49e9fe 100644 --- a/plugins/sudoers/gram.c +++ b/plugins/sudoers/gram.c @@ -167,7 +167,7 @@ static struct defaults *new_default(char *, char *, short); static struct member *new_member(char *, short); static struct sudo_command *new_command(char *, char *); static struct command_digest *new_digest(unsigned int, char *); -static void alias_error(const char *name, int errnum); +static void alias_error(const char *name, short type, int errnum); #line 167 "gram.c" @@ -2927,7 +2927,7 @@ yyparse (void) { if (!alias_add(&parsed_policy, (yyvsp[-3].string), HOSTALIAS, sudoers, alias_line, alias_column, (yyvsp[0].member))) { - alias_error((yyvsp[-3].string), errno); + alias_error((yyvsp[-3].string), HOSTALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, (yyvsp[-3].string)); @@ -2960,7 +2960,7 @@ yyparse (void) { if (!alias_add(&parsed_policy, (yyvsp[-3].string), CMNDALIAS, sudoers, alias_line, alias_column, (yyvsp[0].member))) { - alias_error((yyvsp[-3].string), errno); + alias_error((yyvsp[-3].string), CMNDALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, (yyvsp[-3].string)); @@ -2993,7 +2993,7 @@ yyparse (void) { if (!alias_add(&parsed_policy, (yyvsp[-3].string), RUNASALIAS, sudoers, alias_line, alias_column, (yyvsp[0].member))) { - alias_error((yyvsp[-3].string), errno); + alias_error((yyvsp[-3].string), RUNASALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, (yyvsp[-3].string)); @@ -3016,7 +3016,7 @@ yyparse (void) { if (!alias_add(&parsed_policy, (yyvsp[-3].string), USERALIAS, sudoers, alias_line, alias_column, (yyvsp[0].member))) { - alias_error((yyvsp[-3].string), errno); + alias_error((yyvsp[-3].string), USERALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, (yyvsp[-3].string)); @@ -3475,12 +3475,27 @@ sudoerserror(const char *s) } static void -alias_error(const char *name, int errnum) +alias_error(const char *name, short type, int errnum) { - if (errnum == EEXIST) - sudoerserrorf(U_("Alias \"%s\" already defined"), name); - else + if (errnum == EEXIST) { + struct alias *a = alias_get(&parsed_policy, name, type); + if (a != NULL) { + sudoerserrorf( + U_("duplicate %s \"%s\", previously defined at %s:%d:%d"), + alias_type_to_string(type), name, a->file, a->line, a->column); + alias_put(a); + } else { + if (errno == ELOOP) { + sudoerserrorf(U_("cycle in %s \"%s\""), + alias_type_to_string(type), name); + } else { + sudoerserrorf(U_("duplicate %s \"%s\""), + alias_type_to_string(type), name); + } + } + } else { sudoerserror(N_("unable to allocate memory")); + } } static struct defaults * diff --git a/plugins/sudoers/gram.y b/plugins/sudoers/gram.y index 5356cce761..67b0af8591 100644 --- a/plugins/sudoers/gram.y +++ b/plugins/sudoers/gram.y @@ -84,7 +84,7 @@ static struct defaults *new_default(char *, char *, short); static struct member *new_member(char *, short); static struct sudo_command *new_command(char *, char *); static struct command_digest *new_digest(unsigned int, char *); -static void alias_error(const char *name, int errnum); +static void alias_error(const char *name, short type, int errnum); %} %union { @@ -1012,7 +1012,7 @@ hostalias : ALIAS { } '=' hostlist { if (!alias_add(&parsed_policy, $1, HOSTALIAS, sudoers, alias_line, alias_column, $4)) { - alias_error($1, errno); + alias_error($1, HOSTALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, $1); @@ -1039,7 +1039,7 @@ cmndalias : ALIAS { } '=' cmndlist { if (!alias_add(&parsed_policy, $1, CMNDALIAS, sudoers, alias_line, alias_column, $4)) { - alias_error($1, errno); + alias_error($1, CMNDALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, $1); @@ -1066,7 +1066,7 @@ runasalias : ALIAS { } '=' userlist { if (!alias_add(&parsed_policy, $1, RUNASALIAS, sudoers, alias_line, alias_column, $4)) { - alias_error($1, errno); + alias_error($1, RUNASALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, $1); @@ -1085,7 +1085,7 @@ useralias : ALIAS { } '=' userlist { if (!alias_add(&parsed_policy, $1, USERALIAS, sudoers, alias_line, alias_column, $4)) { - alias_error($1, errno); + alias_error($1, USERALIAS, errno); YYERROR; } parser_leak_remove(LEAK_PTR, $1); @@ -1292,12 +1292,27 @@ sudoerserror(const char *s) } static void -alias_error(const char *name, int errnum) +alias_error(const char *name, short type, int errnum) { - if (errnum == EEXIST) - sudoerserrorf(U_("Alias \"%s\" already defined"), name); - else + if (errnum == EEXIST) { + struct alias *a = alias_get(&parsed_policy, name, type); + if (a != NULL) { + sudoerserrorf( + U_("duplicate %s \"%s\", previously defined at %s:%d:%d"), + alias_type_to_string(type), name, a->file, a->line, a->column); + alias_put(a); + } else { + if (errno == ELOOP) { + sudoerserrorf(U_("cycle in %s \"%s\""), + alias_type_to_string(type), name); + } else { + sudoerserrorf(U_("duplicate %s \"%s\""), + alias_type_to_string(type), name); + } + } + } else { sudoerserror(N_("unable to allocate memory")); + } } static struct defaults * diff --git a/plugins/sudoers/logging.c b/plugins/sudoers/logging.c index e6d9b7afea..07a34d135a 100644 --- a/plugins/sudoers/logging.c +++ b/plugins/sudoers/logging.c @@ -507,15 +507,6 @@ log_auth_failure(const struct sudoers_context *ctx, unsigned int status, /* Do auditing first (audit_failure() handles the locale itself). */ audit_failure(ctx, ctx->runas.argv, "%s", N_("authentication failure")); - if (ISSET(status, FLAG_NO_USER_INPUT)) { - /* For "sudo -n", only log the entry if an actual command was run. */ - if (ISSET(ctx->mode, MODE_LIST|MODE_VALIDATE)) - logit = false; - } else if (!ISSET(status, FLAG_BAD_PASSWORD)) { - /* Authenticated OK, sudoers denials are logged separately. */ - logit = false; - } - /* * Do we need to send mail? * We want to avoid sending multiple messages for the same command @@ -536,6 +527,18 @@ log_auth_failure(const struct sudoers_context *ctx, unsigned int status, logit = false; } + /* Special case overrides for logging and mailing. */ + if (ISSET(status, FLAG_NO_USER_INPUT)) { + /* For "sudo -n", only log the entry if an actual command was run. */ + if (ISSET(ctx->mode, MODE_LIST|MODE_VALIDATE)) { + logit = false; + mailit = false; + } + } else if (!ISSET(status, FLAG_BAD_PASSWORD)) { + /* Authenticated OK, sudoers denials are logged separately. */ + logit = false; + } + if (logit || mailit) { /* Log and mail messages should be in the sudoers locale. */ sudoers_setlocale(SUDOERS_LOCALE_SUDOERS, &oldlocale); @@ -655,6 +658,11 @@ log_exit_status(const struct sudoers_context *ctx, int status) if (!def_log_exit_status) SET(evl_flags, EVLOG_MAIL_ONLY); } + /* + * eventlog_exit() expects event_time to be the command start time, + * not the current time as set by sudoers_to_eventlog(). + */ + sudo_timespecsub(&evlog.event_time, &run_time, &evlog.event_time); evlog.run_time = run_time; evlog.exit_value = exit_value; evlog.signal_name = signal_name; diff --git a/plugins/sudoers/strvec_join.c b/plugins/sudoers/strvec_join.c index bee2e44fec..962e2c289f 100644 --- a/plugins/sudoers/strvec_join.c +++ b/plugins/sudoers/strvec_join.c @@ -40,7 +40,7 @@ * char. If non-NULL, the copy function must have strlcpy-like semantics. */ char * -strvec_join(char *const argv[], char sep, size_t (*cpy)(char *, const char *, size_t)) +strvec_join(char *const argv[], char sep, size_t (*cpy)(char * restrict, const char * restrict, size_t)) { char *dst, *result = NULL; char *const *av; diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 93c77667cb..106a1e8c2c 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -496,10 +496,10 @@ void canon_path_free(char *resolved); void canon_path_free_cache(void); /* strlcpy_unesc.c */ -size_t strlcpy_unescape(char *restrict dst, const char *restrict src, size_t size); +size_t strlcpy_unescape(char * restrict dst, const char * restrict src, size_t size); /* strvec_join.c */ -char *strvec_join(char *const argv[], char sep, size_t (*cpy)(char *, const char *, size_t)); +char *strvec_join(char *const argv[], char sep, size_t (*cpy)(char * restrict, const char * restrict, size_t)); /* unesc_str.c */ void unescape_string(char *str); diff --git a/plugins/sudoers/sudoers.in b/plugins/sudoers/sudoers.in index b0d464160f..b5ed1f10fd 100644 --- a/plugins/sudoers/sudoers.in +++ b/plugins/sudoers/sudoers.in @@ -47,8 +47,8 @@ Defaults!@visudo@ env_keep += "SUDO_EDITOR EDITOR VISUAL" ## ## Use a hard-coded PATH instead of the user's to find commands. ## This also helps prevent poorly written scripts from running -## artbitrary commands under sudo. -Defaults secure_path="@secure_path@" +## arbitrary commands under sudo. +@secure_path_config@Defaults secure_path="@secure_path@" ## ## You may wish to keep some of the following environment variables ## when running commands via sudo. @@ -107,6 +107,10 @@ Defaults secure_path="@secure_path@" ## Some package scripts run a huge number of commands, which is made ## slower by these options and also can clutter up the logs. # Defaults!PKGMAN !intercept, !log_subcmds +## +## Uncomment to disable PAM silent mode. Otherwise messages by PAM +## modules such as pam_faillock will not be printed. +# Defaults !pam_silent ## ## Runas alias specification diff --git a/src/exec_ptrace.c b/src/exec_ptrace.c index 3d44b82e2a..a313ab530e 100644 --- a/src/exec_ptrace.c +++ b/src/exec_ptrace.c @@ -1386,7 +1386,7 @@ script_matches(const char *script, const char *execpath, int argc, /* Match interpreter. */ if (!pathname_matches(execpath, interp, true)) { /* It is possible for the interpreter to be a script too. */ - if (argv > 0 && strcmp(interp, argv[1]) == 0) { + if (argc > 0 && strcmp(interp, argv[1]) == 0) { /* Interpreter args must match for *this* interpreter. */ if (interp_args == NULL || (argc > 1 && strcmp(interp_args, argv[2]) == 0)) { diff --git a/src/ttyname.c b/src/ttyname.c index ae8bc9789b..a36b6da2fa 100644 --- a/src/ttyname.c +++ b/src/ttyname.c @@ -1,7 +1,7 @@ /* * SPDX-License-Identifier: ISC * - * Copyright (c) 2012-2023 Todd C. Miller + * Copyright (c) 2012-2024 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,7 +23,7 @@ #include -/* Large files not supported by procfs.h on Solaris. */ +/* Large files may not be supported by procfs.h on Solaris. */ #if defined(HAVE_STRUCT_PSINFO_PR_TTYDEV) # undef _FILE_OFFSET_BITS # undef _LARGE_FILES @@ -175,7 +175,8 @@ get_process_ttyname(char *name, size_t namelen) if ((psinfo.pr_ttydev & DEVNO64) && sizeof(dev_t) == 4) ttydev = makedev(major64(psinfo.pr_ttydev), minor64(psinfo.pr_ttydev)); #endif - if (ttydev != (dev_t)-1) { + /* On AIX, pr_ttydev is 0 (not -1) when no terminal is present. */ + if (ttydev != 0 && ttydev != (dev_t)-1) { errno = serrno; if (sudo_ttyname_dev(ttydev, name, namelen) == NULL) { sudo_warnx( @@ -185,6 +186,7 @@ get_process_ttyname(char *name, size_t namelen) } goto done; } + ttydev = (dev_t)-1; } } else { struct stat sb;