diff --git a/lib/libpam/libpam/security/pam_mod_misc.h b/lib/libpam/libpam/security/pam_mod_misc.h --- a/lib/libpam/libpam/security/pam_mod_misc.h +++ b/lib/libpam/libpam/security/pam_mod_misc.h @@ -35,7 +35,6 @@ * Common option names */ #define PAM_OPT_NULLOK "nullok" -#define PAM_OPT_EMPTYOK "emptyok" #define PAM_OPT_AUTH_AS_SELF "auth_as_self" #define PAM_OPT_ECHO_PASS "echo_pass" #define PAM_OPT_DEBUG "debug" diff --git a/lib/libpam/modules/pam_unix/pam_unix.8 b/lib/libpam/modules/pam_unix/pam_unix.8 --- a/lib/libpam/modules/pam_unix/pam_unix.8 +++ b/lib/libpam/modules/pam_unix/pam_unix.8 @@ -32,7 +32,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 3, 2020 +.Dd November 24, 2023 .Dt PAM_UNIX 8 .Os .Sh NAME @@ -101,29 +101,11 @@ sufficient. .It Cm nullok If the password database has no password for the entity being -authenticated, then this option will forgo password prompting, and -silently allow authentication to succeed. -.Pp -.Sy NOTE: -If -.Nm -is invoked by a process that does not have the privileges required to -access the password database (in most cases, this means root -privileges), the -.Cm nullok -option may cause -.Nm -to allow any user to log in with any password. -.It Cm emptyok -If the password database contains the password for the entity being -authenticated, but the password matches an empty string, -then this option will forgo password prompting, and -silently allow authentication to succeed. -.Pp -The difference between this and -.Cm nullok -is that it avoids prompting for password when the password is set -to an empty string, as opposed to not being set. +authenticated, or a password matching the empty string, then this +option will forgo password prompting, and silently allow authentication +to succeed. +Without this option, any attempt to authenticate with an empty password +is rejected. .It Cm local_pass Use only the local password database, even if NIS is in use. This will cause an authentication failure if the system is configured @@ -182,6 +164,8 @@ suppress warning messages to the user. These messages include reasons why the user's authentication attempt was declined. +.It Cm nullok +allows unprivileged users to set an empty new password. .It Cm local_pass forces the password module to change a local password in favour of a NIS one. diff --git a/lib/libpam/modules/pam_unix/pam_unix.c b/lib/libpam/modules/pam_unix/pam_unix.c --- a/lib/libpam/modules/pam_unix/pam_unix.c +++ b/lib/libpam/modules/pam_unix/pam_unix.c @@ -108,22 +108,19 @@ if (pwd != NULL) { PAM_LOG("Doing real authentication"); realpw = pwd->pw_passwd; - if (realpw[0] == '\0') { + /* + * An empty password can be stored as an empty saved password + * hash or as a hash generated from an empty password, make + * sure to check both cases here. + */ + if (realpw[0] == '\0' || + strcmp(crypt(emptypasswd, realpw), realpw) == 0) { if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) && openpam_get_option(pamh, PAM_OPT_NULLOK)) return (PAM_SUCCESS); PAM_LOG("Password is empty, using fake password"); realpw = "*"; } - /* - * Check whether the saved password hash matches the one - * generated from an empty password - as opposed to empty - * saved password hash, which is handled above. - */ - if (!(flags & PAM_DISALLOW_NULL_AUTHTOK) && - openpam_get_option(pamh, PAM_OPT_EMPTYOK) && - strcmp(crypt(emptypasswd, realpw), realpw) == 0) - return (PAM_SUCCESS); lc = login_getpwclass(pwd); } else { PAM_LOG("Doing dummy authentication");