summaryrefslogtreecommitdiff
path: root/modules/pam_unix
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_unix')
-rw-r--r--modules/pam_unix/Makefile.am8
-rw-r--r--modules/pam_unix/Makefile.in42
-rw-r--r--modules/pam_unix/README6
-rw-r--r--modules/pam_unix/bigcrypt.c10
-rw-r--r--modules/pam_unix/lckpwdf.-c10
-rw-r--r--modules/pam_unix/md5.c40
-rw-r--r--modules/pam_unix/md5.h10
-rw-r--r--modules/pam_unix/pam_unix.810
-rw-r--r--modules/pam_unix/pam_unix.8.xml6
-rw-r--r--modules/pam_unix/pam_unix_acct.c6
-rw-r--r--modules/pam_unix/pam_unix_passwd.c2
-rw-r--r--modules/pam_unix/passverify.c173
-rw-r--r--modules/pam_unix/passverify.h4
-rw-r--r--modules/pam_unix/support.c48
-rw-r--r--modules/pam_unix/unix_chkpwd.84
-rw-r--r--modules/pam_unix/unix_chkpwd.c9
-rw-r--r--modules/pam_unix/unix_update.84
-rw-r--r--modules/pam_unix/unix_update.c13
18 files changed, 187 insertions, 218 deletions
diff --git a/modules/pam_unix/Makefile.am b/modules/pam_unix/Makefile.am
index 6463872a..1658735b 100644
--- a/modules/pam_unix/Makefile.am
+++ b/modules/pam_unix/Makefile.am
@@ -47,14 +47,14 @@ bigcrypt_LDADD = @LIBCRYPT@
unix_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c \
passverify.c
-unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_chkpwd\"
-unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@
+unix_chkpwd_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@ -DHELPER_COMPILE=\"unix_chkpwd\"
+unix_chkpwd_LDFLAGS = @EXE_LDFLAGS@
unix_chkpwd_LDADD = @LIBCRYPT@ @LIBSELINUX@ @LIBAUDIT@
unix_update_SOURCES = unix_update.c md5_good.c md5_broken.c bigcrypt.c \
passverify.c
-unix_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_update\"
-unix_update_LDFLAGS = @PIE_LDFLAGS@
+unix_update_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@ -DHELPER_COMPILE=\"unix_update\"
+unix_update_LDFLAGS = @EXE_LDFLAGS@
unix_update_LDADD = @LIBCRYPT@ @LIBSELINUX@
if ENABLE_REGENERATE_MAN
diff --git a/modules/pam_unix/Makefile.in b/modules/pam_unix/Makefile.in
index bfc1a252..4dcfdf64 100644
--- a/modules/pam_unix/Makefile.in
+++ b/modules/pam_unix/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -100,18 +100,21 @@ sbin_PROGRAMS = unix_chkpwd$(EXEEXT) unix_update$(EXEEXT)
noinst_PROGRAMS = bigcrypt$(EXEEXT)
subdir = modules/pam_unix
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \
- $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
- $(top_srcdir)/m4/japhar_grep_cflags.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 \
$(top_srcdir)/m4/jh_path_xml_catalog.m4 \
$(top_srcdir)/m4/ld-O1.m4 $(top_srcdir)/m4/ld-as-needed.m4 \
- $(top_srcdir)/m4/ld-no-undefined.m4 $(top_srcdir)/m4/lib-ld.m4 \
+ $(top_srcdir)/m4/ld-no-undefined.m4 \
+ $(top_srcdir)/m4/ld-z-now.m4 $(top_srcdir)/m4/lib-ld.m4 \
$(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \
$(top_srcdir)/m4/libprelude.m4 $(top_srcdir)/m4/libtool.m4 \
$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
$(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
- $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/warn_lang_flags.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(dist_check_SCRIPTS) \
@@ -431,6 +434,7 @@ am__set_TESTS_bases = \
bases='$(TEST_LOGS)'; \
bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
RECHECK_LOGS = $(TEST_LOGS)
AM_RECURSIVE_TARGETS = check recheck
TEST_SUITE_LOG = test-suite.log
@@ -475,6 +479,9 @@ CC_FOR_BUILD = @CC_FOR_BUILD@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
+CRYPTO_LIBS = @CRYPTO_LIBS@
+CRYPT_CFLAGS = @CRYPT_CFLAGS@
+CRYPT_LIBS = @CRYPT_LIBS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
@@ -488,6 +495,8 @@ ECONF_CFLAGS = @ECONF_CFLAGS@
ECONF_LIBS = @ECONF_LIBS@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
+EXE_CFLAGS = @EXE_CFLAGS@
+EXE_LDFLAGS = @EXE_LDFLAGS@
FGREP = @FGREP@
FO2PDF = @FO2PDF@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
@@ -507,7 +516,6 @@ LEX = @LEX@
LEXLIB = @LEXLIB@
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LIBAUDIT = @LIBAUDIT@
-LIBCRACK = @LIBCRACK@
LIBCRYPT = @LIBCRYPT@
LIBDB = @LIBDB@
LIBDL = @LIBDL@
@@ -554,8 +562,6 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
-PIE_CFLAGS = @PIE_CFLAGS@
-PIE_LDFLAGS = @PIE_LDFLAGS@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
@@ -566,6 +572,7 @@ SECUREDIR = @SECUREDIR@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
+STRINGPARAM_HMAC = @STRINGPARAM_HMAC@
STRINGPARAM_VENDORDIR = @STRINGPARAM_VENDORDIR@
STRIP = @STRIP@
TIRPC_CFLAGS = @TIRPC_CFLAGS@
@@ -615,7 +622,6 @@ htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
-libc_cv_fpie = @libc_cv_fpie@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
@@ -623,9 +629,6 @@ localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
-pam_cv_ld_O1 = @pam_cv_ld_O1@
-pam_cv_ld_as_needed = @pam_cv_ld_as_needed@
-pam_cv_ld_no_undefined = @pam_cv_ld_no_undefined@
pam_xauth_path = @pam_xauth_path@
pdfdir = @pdfdir@
prefix = @prefix@
@@ -635,6 +638,7 @@ sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
+systemdunitdir = @systemdunitdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
@@ -670,14 +674,14 @@ bigcrypt_LDADD = @LIBCRYPT@
unix_chkpwd_SOURCES = unix_chkpwd.c md5_good.c md5_broken.c bigcrypt.c \
passverify.c
-unix_chkpwd_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_chkpwd\"
-unix_chkpwd_LDFLAGS = @PIE_LDFLAGS@
+unix_chkpwd_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@ -DHELPER_COMPILE=\"unix_chkpwd\"
+unix_chkpwd_LDFLAGS = @EXE_LDFLAGS@
unix_chkpwd_LDADD = @LIBCRYPT@ @LIBSELINUX@ @LIBAUDIT@
unix_update_SOURCES = unix_update.c md5_good.c md5_broken.c bigcrypt.c \
passverify.c
-unix_update_CFLAGS = $(AM_CFLAGS) @PIE_CFLAGS@ -DHELPER_COMPILE=\"unix_update\"
-unix_update_LDFLAGS = @PIE_LDFLAGS@
+unix_update_CFLAGS = $(AM_CFLAGS) @EXE_CFLAGS@ -DHELPER_COMPILE=\"unix_update\"
+unix_update_LDFLAGS = @EXE_LDFLAGS@
unix_update_LDADD = @LIBCRYPT@ @LIBSELINUX@
@ENABLE_REGENERATE_MAN_TRUE@dist_noinst_DATA = README
all: all-am
@@ -1254,7 +1258,7 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
fi; \
echo "$${col}$$br$${std}"; \
- echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
echo "$${col}$$br$${std}"; \
create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \
diff --git a/modules/pam_unix/README b/modules/pam_unix/README
index a87f34a5..67a2d215 100644
--- a/modules/pam_unix/README
+++ b/modules/pam_unix/README
@@ -99,7 +99,7 @@ use_authtok
When password changing enforce the module to set the new password to the
one provided by a previously stacked password module (this is used in the
- example of the stacking of the pam_cracklib module documented below).
+ example of the stacking of the pam_passwdqc module documented below).
authtok_type=type
@@ -194,8 +194,8 @@ auth required pam_unix.so
# Ensure users account and password are still active
account required pam_unix.so
# Change the user's password, but at first check the strength
-# with pam_cracklib(8)
-password required pam_cracklib.so retry=3 minlen=6 difok=3
+# with pam_passwdqc(8)
+password required pam_passwdqc.so config=/etc/passwdqc.conf
password required pam_unix.so use_authtok nullok yescrypt
session required pam_unix.so
diff --git a/modules/pam_unix/bigcrypt.c b/modules/pam_unix/bigcrypt.c
index e08e4098..d8d61a4b 100644
--- a/modules/pam_unix/bigcrypt.c
+++ b/modules/pam_unix/bigcrypt.c
@@ -29,9 +29,7 @@
#include <string.h>
#include <stdlib.h>
#include <security/_pam_macros.h>
-#ifdef HAVE_LIBXCRYPT
-#include <xcrypt.h>
-#elif defined(HAVE_CRYPT_H)
+#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
@@ -111,6 +109,9 @@ char *bigcrypt(const char *key, const char *salt)
#endif
if (tmp_ptr == NULL) {
free(dec_c2_cryptbuf);
+#ifdef HAVE_CRYPT_R
+ free(cdata);
+#endif
return NULL;
}
/* and place in the static area */
@@ -137,6 +138,9 @@ char *bigcrypt(const char *key, const char *salt)
if (tmp_ptr == NULL) {
_pam_overwrite(dec_c2_cryptbuf);
free(dec_c2_cryptbuf);
+#ifdef HAVE_CRYPT_R
+ free(cdata);
+#endif
return NULL;
}
diff --git a/modules/pam_unix/lckpwdf.-c b/modules/pam_unix/lckpwdf.-c
index 7145617e..c3e63155 100644
--- a/modules/pam_unix/lckpwdf.-c
+++ b/modules/pam_unix/lckpwdf.-c
@@ -73,17 +73,17 @@ static int lckpwdf(void)
lockfd = open(LOCKFILE, O_WRONLY);
if(lockfd == -1 && errno == ENOENT)
{
- security_context_t create_context;
+ char *create_context_raw;
int rc;
- if(getfilecon("/etc/passwd", &create_context))
+ if(getfilecon_raw("/etc/passwd", &create_context_raw))
return -1;
- rc = setfscreatecon(create_context);
- freecon(create_context);
+ rc = setfscreatecon_raw(create_context_raw);
+ freecon(create_context_raw);
if(rc)
return -1;
lockfd = open(LOCKFILE, O_CREAT | O_WRONLY, 0600);
- if(setfscreatecon(NULL))
+ if(setfscreatecon_raw(NULL))
return -1;
}
}
diff --git a/modules/pam_unix/md5.c b/modules/pam_unix/md5.c
index 9954536f..593d6dc3 100644
--- a/modules/pam_unix/md5.c
+++ b/modules/pam_unix/md5.c
@@ -52,10 +52,10 @@ static void byteReverse(uint8_aligned *buf, unsigned longs)
*/
void MD5Name(MD5Init)(struct MD5Context *ctx)
{
- ctx->buf[0] = 0x67452301U;
- ctx->buf[1] = 0xefcdab89U;
- ctx->buf[2] = 0x98badcfeU;
- ctx->buf[3] = 0x10325476U;
+ ctx->buf.i[0] = 0x67452301U;
+ ctx->buf.i[1] = 0xefcdab89U;
+ ctx->buf.i[2] = 0x98badcfeU;
+ ctx->buf.i[3] = 0x10325476U;
ctx->bits[0] = 0;
ctx->bits[1] = 0;
@@ -81,7 +81,7 @@ void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsign
/* Handle any leading odd-sized chunks */
if (t) {
- unsigned char *p = (unsigned char *) ctx->in + t;
+ unsigned char *p = ctx->in.c + t;
t = 64 - t;
if (len < t) {
@@ -89,24 +89,24 @@ void MD5Name(MD5Update)(struct MD5Context *ctx, unsigned const char *buf, unsign
return;
}
memcpy(p, buf, t);
- byteReverse(ctx->in, 16);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ byteReverse(ctx->in.c, 16);
+ MD5Name(MD5Transform)(ctx->buf.i, ctx->in.i);
buf += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64) {
- memcpy(ctx->in, buf, 64);
- byteReverse(ctx->in, 16);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ memcpy(ctx->in.c, buf, 64);
+ byteReverse(ctx->in.c, 16);
+ MD5Name(MD5Transform)(ctx->buf.i, ctx->in.i);
buf += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
- memcpy(ctx->in, buf, len);
+ memcpy(ctx->in.c, buf, len);
}
/*
@@ -123,7 +123,7 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
- p = ctx->in + count;
+ p = ctx->in.c + count;
*p++ = 0x80;
/* Bytes of padding needed to make 64 bytes */
@@ -133,23 +133,23 @@ void MD5Name(MD5Final)(unsigned char digest[16], struct MD5Context *ctx)
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
memset(p, 0, count);
- byteReverse(ctx->in, 16);
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
+ byteReverse(ctx->in.c, 16);
+ MD5Name(MD5Transform)(ctx->buf.i, ctx->in.i);
/* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
+ memset(ctx->in.c, 0, 56);
} else {
/* Pad block to 56 bytes */
memset(p, 0, count - 8);
}
- byteReverse(ctx->in, 14);
+ byteReverse(ctx->in.c, 14);
/* Append length in bits and transform */
- memcpy((uint32 *)ctx->in + 14, ctx->bits, 2*sizeof(uint32));
+ memcpy(ctx->in.i + 14, ctx->bits, 2*sizeof(uint32));
- MD5Name(MD5Transform)(ctx->buf, (uint32 *) ctx->in);
- byteReverse((unsigned char *) ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
+ MD5Name(MD5Transform)(ctx->buf.i, ctx->in.i);
+ byteReverse(ctx->buf.c, 4);
+ memcpy(digest, ctx->buf.c, 16);
memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
}
diff --git a/modules/pam_unix/md5.h b/modules/pam_unix/md5.h
index d9186b7f..3dc54bd2 100644
--- a/modules/pam_unix/md5.h
+++ b/modules/pam_unix/md5.h
@@ -7,9 +7,15 @@
typedef unsigned int uint32;
struct MD5Context {
- uint32 buf[4];
+ union {
+ uint32 i[4];
+ unsigned char c[16] PAM_ATTRIBUTE_ALIGNED(4);
+ } buf;
uint32 bits[2];
- unsigned char in[64] PAM_ATTRIBUTE_ALIGNED(4);
+ union {
+ uint32 i[16];
+ unsigned char c[64] PAM_ATTRIBUTE_ALIGNED(4);
+ } in;
};
void GoodMD5Init(struct MD5Context *);
diff --git a/modules/pam_unix/pam_unix.8 b/modules/pam_unix/pam_unix.8
index b396b66c..d9cdea5a 100644
--- a/modules/pam_unix/pam_unix.8
+++ b/modules/pam_unix/pam_unix.8
@@ -2,12 +2,12 @@
.\" Title: pam_unix
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 06/08/2020
+.\" Date: 09/03/2021
.\" Manual: Linux-PAM Manual
.\" Source: Linux-PAM Manual
.\" Language: English
.\"
-.TH "PAM_UNIX" "8" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "PAM_UNIX" "8" "09/03/2021" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -126,7 +126,7 @@ This argument can be used to discourage the authentication component from reques
When password changing enforce the module to set the new password to the one provided by a previously stacked
\fBpassword\fR
module (this is used in the example of the stacking of the
-\fBpam_cracklib\fR
+\fBpam_passwdqc\fR
module documented below)\&.
.RE
.PP
@@ -264,8 +264,8 @@ auth required pam_unix\&.so
# Ensure users account and password are still active
account required pam_unix\&.so
# Change the user\*(Aqs password, but at first check the strength
-# with pam_cracklib(8)
-password required pam_cracklib\&.so retry=3 minlen=6 difok=3
+# with pam_passwdqc(8)
+password required pam_passwdqc\&.so config=/etc/passwdqc\&.conf
password required pam_unix\&.so use_authtok nullok yescrypt
session required pam_unix\&.so
diff --git a/modules/pam_unix/pam_unix.8.xml b/modules/pam_unix/pam_unix.8.xml
index fa02c3a6..9f9c8185 100644
--- a/modules/pam_unix/pam_unix.8.xml
+++ b/modules/pam_unix/pam_unix.8.xml
@@ -223,7 +223,7 @@
When password changing enforce the module to set the new
password to the one provided by a previously stacked
<option>password</option> module (this is used in the
- example of the stacking of the <command>pam_cracklib</command>
+ example of the stacking of the <command>pam_passwdqc</command>
module documented below).
</para>
</listitem>
@@ -465,8 +465,8 @@ auth required pam_unix.so
# Ensure users account and password are still active
account required pam_unix.so
# Change the user's password, but at first check the strength
-# with pam_cracklib(8)
-password required pam_cracklib.so retry=3 minlen=6 difok=3
+# with pam_passwdqc(8)
+password required pam_passwdqc.so config=/etc/passwdqc.conf
password required pam_unix.so use_authtok nullok yescrypt
session required pam_unix.so
</programlisting>
diff --git a/modules/pam_unix/pam_unix_acct.c b/modules/pam_unix/pam_unix_acct.c
index de8d65c1..8f5ed3e0 100644
--- a/modules/pam_unix/pam_unix_acct.c
+++ b/modules/pam_unix/pam_unix_acct.c
@@ -189,7 +189,7 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
unsigned long long ctrl;
const void *void_uname;
const char *uname;
- int retval, daysleft;
+ int retval, daysleft = -1;
char buf[256];
D(("called."));
@@ -252,6 +252,10 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
_("Your account has expired; please contact your system administrator."));
break;
case PAM_AUTHTOK_ERR:
+ /*
+ * We ignore "password changed too early" error
+ * as it is relevant only for password change.
+ */
retval = PAM_SUCCESS;
/* fallthrough */
case PAM_SUCCESS:
diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c
index e988b2e3..a20e919e 100644
--- a/modules/pam_unix/pam_unix_passwd.c
+++ b/modules/pam_unix/pam_unix_passwd.c
@@ -577,7 +577,7 @@ static int _pam_unix_approve_pass(pam_handle_t * pamh
}
}
- if (strlen(pass_new) > MAXPASS) {
+ if (strlen(pass_new) > PAM_MAX_RESP_SIZE) {
remark = _("You must choose a shorter password.");
D(("length exceeded [%s]", remark));
} else if (off(UNIX__IAMROOT, ctrl)) {
diff --git a/modules/pam_unix/passverify.c b/modules/pam_unix/passverify.c
index a571b4f7..f2474a5b 100644
--- a/modules/pam_unix/passverify.c
+++ b/modules/pam_unix/passverify.c
@@ -19,9 +19,7 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
-#ifdef HAVE_LIBXCRYPT
-#include <xcrypt.h>
-#elif defined(HAVE_CRYPT_H)
+#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
@@ -243,12 +241,15 @@ PAMH_ARG_DECL(int get_account_info,
* ...and shadow password file entry for this user,
* if shadowing is enabled
*/
+ *spwdent = pam_modutil_getspnam(pamh, name);
+ if (*spwdent == NULL) {
#ifndef HELPER_COMPILE
- if (geteuid() || SELINUX_ENABLED)
+ /* still a chance the user can authenticate */
return PAM_UNIX_RUN_HELPER;
#endif
- *spwdent = pam_modutil_getspnam(pamh, name);
- if (*spwdent == NULL || (*spwdent)->sp_pwdp == NULL)
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ if ((*spwdent)->sp_pwdp == NULL)
return PAM_AUTHINFO_UNAVAIL;
}
} else {
@@ -289,13 +290,7 @@ PAMH_ARG_DECL(int check_shadow_expiry,
D(("account expired"));
return PAM_ACCT_EXPIRED;
}
-#if defined(CRYPT_CHECKSALT_AVAILABLE) && CRYPT_CHECKSALT_AVAILABLE
- if (spent->sp_lstchg == 0 ||
- crypt_checksalt(spent->sp_pwdp) == CRYPT_SALT_METHOD_LEGACY ||
- crypt_checksalt(spent->sp_pwdp) == CRYPT_SALT_TOO_CHEAP) {
-#else
if (spent->sp_lstchg == 0) {
-#endif
D(("need a new password"));
*daysleft = 0;
return PAM_NEW_AUTHTOK_REQD;
@@ -452,7 +447,7 @@ PAMH_ARG_DECL(char * create_password_hash,
algoid = "$6$";
} else { /* must be crypt/bigcrypt */
char tmppass[9];
- char *crypted;
+ char *hashed;
crypt_make_salt(salt, 2);
if (off(UNIX_BIGCRYPT, ctrl) && strlen(password) > 8) {
@@ -460,10 +455,10 @@ PAMH_ARG_DECL(char * create_password_hash,
tmppass[sizeof(tmppass)-1] = '\0';
password = tmppass;
}
- crypted = bigcrypt(password, salt);
+ hashed = bigcrypt(password, salt);
memset(tmppass, '\0', sizeof(tmppass));
password = NULL;
- return crypted;
+ return hashed;
}
#if defined(CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY) && CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY
@@ -473,23 +468,11 @@ PAMH_ARG_DECL(char * create_password_hash,
*/
sp = crypt_gensalt_rn(algoid, rounds, NULL, 0, salt, sizeof(salt));
#else
-#ifdef HAVE_CRYPT_GENSALT_R
- if (on(UNIX_BLOWFISH_PASS, ctrl)) {
- char entropy[17];
- crypt_make_salt(entropy, sizeof(entropy) - 1);
- sp = crypt_gensalt_r (algoid, rounds,
- entropy, sizeof(entropy),
- salt, sizeof(salt));
- } else {
-#endif
- sp = stpcpy(salt, algoid);
- if (on(UNIX_ALGO_ROUNDS, ctrl)) {
- sp += snprintf(sp, sizeof(salt) - (16 + 1 + (sp - salt)), "rounds=%u$", rounds);
- }
- crypt_make_salt(sp, 16);
-#ifdef HAVE_CRYPT_GENSALT_R
+ sp = stpcpy(salt, algoid);
+ if (on(UNIX_ALGO_ROUNDS, ctrl)) {
+ sp += snprintf(sp, sizeof(salt) - (16 + 1 + (sp - salt)), "rounds=%u$", rounds);
}
-#endif
+ crypt_make_salt(sp, 16);
#endif /* CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY */
#ifdef HAVE_CRYPT_R
sp = NULL;
@@ -650,7 +633,7 @@ save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
struct stat st;
size_t len = strlen(forwho);
#ifdef WITH_SELINUX
- security_context_t prev_context=NULL;
+ char *prev_context_raw = NULL;
#endif
if (howmany < 0) {
@@ -665,20 +648,20 @@ save_old_password(pam_handle_t *pamh, const char *forwho, const char *oldpass,
#ifdef WITH_SELINUX
if (SELINUX_ENABLED) {
- security_context_t passwd_context=NULL;
- if (getfilecon("/etc/passwd",&passwd_context)<0) {
+ char *passwd_context_raw = NULL;
+ if (getfilecon_raw("/etc/passwd",&passwd_context_raw)<0) {
return PAM_AUTHTOK_ERR;
};
- if (getfscreatecon(&prev_context)<0) {
- freecon(passwd_context);
+ if (getfscreatecon_raw(&prev_context_raw)<0) {
+ freecon(passwd_context_raw);
return PAM_AUTHTOK_ERR;
}
- if (setfscreatecon(passwd_context)) {
- freecon(passwd_context);
- freecon(prev_context);
+ if (setfscreatecon_raw(passwd_context_raw)) {
+ freecon(passwd_context_raw);
+ freecon(prev_context_raw);
return PAM_AUTHTOK_ERR;
}
- freecon(passwd_context);
+ freecon(passwd_context_raw);
}
#endif
pwfile = fopen(OPW_TMPFILE, "w");
@@ -796,12 +779,12 @@ done:
}
#ifdef WITH_SELINUX
if (SELINUX_ENABLED) {
- if (setfscreatecon(prev_context)) {
+ if (setfscreatecon_raw(prev_context_raw)) {
err = 1;
}
- if (prev_context)
- freecon(prev_context);
- prev_context=NULL;
+ if (prev_context_raw)
+ freecon(prev_context_raw);
+ prev_context_raw = NULL;
}
#endif
if (!err) {
@@ -821,26 +804,26 @@ PAMH_ARG_DECL(int unix_update_passwd,
int err = 1;
int oldmask;
#ifdef WITH_SELINUX
- security_context_t prev_context=NULL;
+ char *prev_context_raw = NULL;
#endif
oldmask = umask(077);
#ifdef WITH_SELINUX
if (SELINUX_ENABLED) {
- security_context_t passwd_context=NULL;
- if (getfilecon("/etc/passwd",&passwd_context)<0) {
+ char *passwd_context_raw = NULL;
+ if (getfilecon_raw("/etc/passwd",&passwd_context_raw)<0) {
return PAM_AUTHTOK_ERR;
};
- if (getfscreatecon(&prev_context)<0) {
- freecon(passwd_context);
+ if (getfscreatecon_raw(&prev_context_raw)<0) {
+ freecon(passwd_context_raw);
return PAM_AUTHTOK_ERR;
}
- if (setfscreatecon(passwd_context)) {
- freecon(passwd_context);
- freecon(prev_context);
+ if (setfscreatecon_raw(passwd_context_raw)) {
+ freecon(passwd_context_raw);
+ freecon(prev_context_raw);
return PAM_AUTHTOK_ERR;
}
- freecon(passwd_context);
+ freecon(passwd_context_raw);
}
#endif
pwfile = fopen(PW_TMPFILE, "w");
@@ -919,12 +902,12 @@ done:
}
#ifdef WITH_SELINUX
if (SELINUX_ENABLED) {
- if (setfscreatecon(prev_context)) {
+ if (setfscreatecon_raw(prev_context_raw)) {
err = 1;
}
- if (prev_context)
- freecon(prev_context);
- prev_context=NULL;
+ if (prev_context_raw)
+ freecon(prev_context_raw);
+ prev_context_raw = NULL;
}
#endif
if (!err) {
@@ -945,27 +928,27 @@ PAMH_ARG_DECL(int unix_update_shadow,
int oldmask;
int wroteentry = 0;
#ifdef WITH_SELINUX
- security_context_t prev_context=NULL;
+ char *prev_context_raw = NULL;
#endif
oldmask = umask(077);
#ifdef WITH_SELINUX
if (SELINUX_ENABLED) {
- security_context_t shadow_context=NULL;
- if (getfilecon("/etc/shadow",&shadow_context)<0) {
+ char *shadow_context_raw = NULL;
+ if (getfilecon_raw("/etc/shadow",&shadow_context_raw)<0) {
return PAM_AUTHTOK_ERR;
};
- if (getfscreatecon(&prev_context)<0) {
- freecon(shadow_context);
+ if (getfscreatecon_raw(&prev_context_raw)<0) {
+ freecon(shadow_context_raw);
return PAM_AUTHTOK_ERR;
}
- if (setfscreatecon(shadow_context)) {
- freecon(shadow_context);
- freecon(prev_context);
+ if (setfscreatecon_raw(shadow_context_raw)) {
+ freecon(shadow_context_raw);
+ freecon(prev_context_raw);
return PAM_AUTHTOK_ERR;
}
- freecon(shadow_context);
+ freecon(shadow_context_raw);
}
#endif
pwfile = fopen(SH_TMPFILE, "w");
@@ -1065,12 +1048,12 @@ PAMH_ARG_DECL(int unix_update_shadow,
#ifdef WITH_SELINUX
if (SELINUX_ENABLED) {
- if (setfscreatecon(prev_context)) {
+ if (setfscreatecon_raw(prev_context_raw)) {
err = 1;
}
- if (prev_context)
- freecon(prev_context);
- prev_context=NULL;
+ if (prev_context_raw)
+ freecon(prev_context_raw);
+ prev_context_raw = NULL;
}
#endif
@@ -1096,6 +1079,12 @@ helper_verify_password(const char *name, const char *p, int nullok)
if (pwd == NULL || hash == NULL) {
helper_log_err(LOG_NOTICE, "check pass; user unknown");
retval = PAM_USER_UNKNOWN;
+ } else if (p[0] == '\0' && nullok) {
+ if (hash[0] == '\0') {
+ retval = PAM_SUCCESS;
+ } else {
+ retval = PAM_AUTH_ERR;
+ }
} else {
retval = verify_pwd_hash(p, hash, nullok);
}
@@ -1111,6 +1100,7 @@ helper_verify_password(const char *name, const char *p, int nullok)
}
void
+PAM_FORMAT((printf, 2, 3))
helper_log_err(int err, const char *format, ...)
{
va_list args;
@@ -1180,49 +1170,6 @@ getuidname(uid_t uid)
return username;
}
-int
-read_passwords(int fd, int npass, char **passwords)
-{
- /* The passwords array must contain npass preallocated
- * buffers of length MAXPASS + 1
- */
- int rbytes = 0;
- int offset = 0;
- int i = 0;
- char *pptr;
- while (npass > 0) {
- rbytes = read(fd, passwords[i]+offset, MAXPASS+1-offset);
-
- if (rbytes < 0) {
- if (errno == EINTR) continue;
- break;
- }
- if (rbytes == 0)
- break;
-
- while (npass > 0 && (pptr=memchr(passwords[i]+offset, '\0', rbytes))
- != NULL) {
- rbytes -= pptr - (passwords[i]+offset) + 1;
- i++;
- offset = 0;
- npass--;
- if (rbytes > 0) {
- if (npass > 0)
- memcpy(passwords[i], pptr+1, rbytes);
- memset(pptr+1, '\0', rbytes);
- }
- }
- offset += rbytes;
- }
-
- /* clear up */
- if (offset > 0 && npass > 0) {
- memset(passwords[i], '\0', offset);
- }
-
- return i;
-}
-
#endif
/* ****************************************************************** *
* Copyright (c) Jan Rękorajski 1999.
diff --git a/modules/pam_unix/passverify.h b/modules/pam_unix/passverify.h
index e9a88fbf..c07037d2 100644
--- a/modules/pam_unix/passverify.h
+++ b/modules/pam_unix/passverify.h
@@ -8,8 +8,6 @@
#define PAM_UNIX_RUN_HELPER PAM_CRED_INSUFFICIENT
-#define MAXPASS PAM_MAX_RESP_SIZE /* the maximum length of a password */
-
#define OLD_PASSWORDS_FILE "/etc/security/opasswd"
int
@@ -50,8 +48,6 @@ setup_signals(void);
char *
getuidname(uid_t uid);
-int
-read_passwords(int fd, int npass, char **passwords);
#endif
#ifdef HELPER_COMPILE
diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c
index 41db1f04..27ca7127 100644
--- a/modules/pam_unix/support.c
+++ b/modules/pam_unix/support.c
@@ -601,6 +601,9 @@ _unix_blankpasswd (pam_handle_t *pamh, unsigned long long ctrl, const char *name
char *salt = NULL;
int daysleft;
int retval;
+ int blank = 0;
+ int execloop;
+ int nonexistent_check = 1;
D(("called"));
@@ -624,32 +627,35 @@ _unix_blankpasswd (pam_handle_t *pamh, unsigned long long ctrl, const char *name
/* UNIX passwords area */
- retval = get_pwd_hash(pamh, name, &pwd, &salt);
-
- if (retval == PAM_UNIX_RUN_HELPER) {
- /* salt will not be set here so we can return immediately */
- if (_unix_run_helper_binary(pamh, NULL, ctrl, name) == PAM_SUCCESS)
- return 1;
- else
- return 0;
- }
+ /*
+ * Execute this loop twice: one checking the password hash of an existing
+ * user and another one for a non-existing user. This way the runtimes
+ * are equal, making it more difficult to differentiate existing from
+ * non-existing users.
+ */
+ for (execloop = 0; execloop < 2; ++execloop) {
+ retval = get_pwd_hash(pamh, name, &pwd, &salt);
- /* Does this user have a password? */
- if (salt == NULL) {
- retval = 0;
- } else {
- if (strlen(salt) == 0)
- retval = 1;
- else
- retval = 0;
+ if (retval == PAM_UNIX_RUN_HELPER) {
+ if (_unix_run_helper_binary(pamh, NULL, ctrl, name) == PAM_SUCCESS)
+ blank = nonexistent_check;
+ } else if (retval == PAM_USER_UNKNOWN) {
+ name = "root";
+ nonexistent_check = 0;
+ continue;
+ } else if (salt != NULL) {
+ if (strlen(salt) == 0)
+ blank = nonexistent_check;
+ }
+ name = "pam_unix_non_existent:";
+ /* non-existent user check will not affect the blank value */
}
/* tidy up */
-
if (salt)
_pam_delete(salt);
- return retval;
+ return blank;
}
int _unix_verify_password(pam_handle_t * pamh, const char *name
@@ -658,7 +664,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
struct passwd *pwd = NULL;
char *salt = NULL;
char *data_name;
- char pw[MAXPASS + 1];
+ char pw[PAM_MAX_RESP_SIZE + 1];
int retval;
@@ -685,7 +691,7 @@ int _unix_verify_password(pam_handle_t * pamh, const char *name
strcpy(data_name + sizeof(FAIL_PREFIX) - 1, name);
}
- if (p != NULL && strlen(p) > MAXPASS) {
+ if (p != NULL && strlen(p) > PAM_MAX_RESP_SIZE) {
memset(pw, 0, sizeof(pw));
p = strncpy(pw, p, sizeof(pw) - 1);
}
diff --git a/modules/pam_unix/unix_chkpwd.8 b/modules/pam_unix/unix_chkpwd.8
index e5d40ad3..93c95bd6 100644
--- a/modules/pam_unix/unix_chkpwd.8
+++ b/modules/pam_unix/unix_chkpwd.8
@@ -2,12 +2,12 @@
.\" Title: unix_chkpwd
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 06/08/2020
+.\" Date: 09/03/2021
.\" Manual: Linux-PAM Manual
.\" Source: Linux-PAM Manual
.\" Language: English
.\"
-.TH "UNIX_CHKPWD" "8" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "UNIX_CHKPWD" "8" "09/03/2021" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/modules/pam_unix/unix_chkpwd.c b/modules/pam_unix/unix_chkpwd.c
index 88647e58..3931bab2 100644
--- a/modules/pam_unix/unix_chkpwd.c
+++ b/modules/pam_unix/unix_chkpwd.c
@@ -33,6 +33,7 @@
#include <security/_pam_macros.h>
#include "passverify.h"
+#include "pam_inline.h"
static int _check_expiry(const char *uname)
{
@@ -89,7 +90,7 @@ static int _audit_log(int type, const char *uname, int rc)
int main(int argc, char *argv[])
{
- char pass[MAXPASS + 1];
+ char pass[PAM_MAX_RESP_SIZE + 1];
char *option;
int npass, nullok;
int blankpass = 0;
@@ -136,7 +137,7 @@ int main(int argc, char *argv[])
user = getuidname(getuid());
/* if the caller specifies the username, verify that user
matches it */
- if (strcmp(user, argv[1])) {
+ if (user == NULL || strcmp(user, argv[1])) {
user = argv[1];
/* no match -> permanently change to the real user and proceed */
if (setuid(getuid()) != 0)
@@ -162,7 +163,7 @@ int main(int argc, char *argv[])
}
/* read the password from stdin (a pipe from the pam_unix module) */
- npass = read_passwords(STDIN_FILENO, 1, passwords);
+ npass = pam_read_passwords(STDIN_FILENO, 1, passwords);
if (npass != 1) { /* is it a valid password? */
helper_log_err(LOG_DEBUG, "no password supplied");
@@ -175,7 +176,7 @@ int main(int argc, char *argv[])
retval = helper_verify_password(user, pass, nullok);
- memset(pass, '\0', MAXPASS); /* clear memory of the password */
+ memset(pass, '\0', PAM_MAX_RESP_SIZE); /* clear memory of the password */
/* return pass or fail */
diff --git a/modules/pam_unix/unix_update.8 b/modules/pam_unix/unix_update.8
index 4a7a3d1b..b1f5ac71 100644
--- a/modules/pam_unix/unix_update.8
+++ b/modules/pam_unix/unix_update.8
@@ -2,12 +2,12 @@
.\" Title: unix_update
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
-.\" Date: 06/08/2020
+.\" Date: 09/03/2021
.\" Manual: Linux-PAM Manual
.\" Source: Linux-PAM Manual
.\" Language: English
.\"
-.TH "UNIX_UPDATE" "8" "06/08/2020" "Linux-PAM Manual" "Linux\-PAM Manual"
+.TH "UNIX_UPDATE" "8" "09/03/2021" "Linux-PAM Manual" "Linux\-PAM Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
diff --git a/modules/pam_unix/unix_update.c b/modules/pam_unix/unix_update.c
index 6ea7ea51..3559972b 100644
--- a/modules/pam_unix/unix_update.c
+++ b/modules/pam_unix/unix_update.c
@@ -32,14 +32,15 @@
#include <security/_pam_macros.h>
#include "passverify.h"
+#include "pam_inline.h"
static int
set_password(const char *forwho, const char *shadow, const char *remember)
{
struct passwd *pwd = NULL;
int retval;
- char pass[MAXPASS + 1];
- char towhat[MAXPASS + 1];
+ char pass[PAM_MAX_RESP_SIZE + 1];
+ char towhat[PAM_MAX_RESP_SIZE + 1];
int npass = 0;
/* we don't care about number format errors because the helper
should be called internally only */
@@ -49,12 +50,12 @@ set_password(const char *forwho, const char *shadow, const char *remember)
/* read the password from stdin (a pipe from the pam_unix module) */
- npass = read_passwords(STDIN_FILENO, 2, passwords);
+ npass = pam_read_passwords(STDIN_FILENO, 2, passwords);
if (npass != 2) { /* is it a valid password? */
if (npass == 1) {
helper_log_err(LOG_DEBUG, "no new password supplied");
- memset(pass, '\0', MAXPASS);
+ memset(pass, '\0', PAM_MAX_RESP_SIZE);
} else {
helper_log_err(LOG_DEBUG, "no valid passwords supplied");
}
@@ -97,8 +98,8 @@ set_password(const char *forwho, const char *shadow, const char *remember)
}
done:
- memset(pass, '\0', MAXPASS);
- memset(towhat, '\0', MAXPASS);
+ memset(pass, '\0', PAM_MAX_RESP_SIZE);
+ memset(towhat, '\0', PAM_MAX_RESP_SIZE);
unlock_pwdf();