summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2020-07-01 14:35:39 +1200
committerKarolin Seeger <kseeger@samba.org>2020-07-06 13:57:23 +0000
commite52f51990912e08b4c25f53ceeab54e6220ac613 (patch)
tree62ce7881d47ec5bf66677e4d6b62e9b484479cf3
parentf0e3089a5a75f02a3a4398c66fda4d2950a89c93 (diff)
downloadsamba-e52f51990912e08b4c25f53ceeab54e6220ac613.tar.gz
dsdb: Allow "password hash userPassword schemes = CryptSHA256" to work on RHEL7
On RHEL7 crypt_r() will set errno. This is a problem because the implementation of crypt_r() in RHEL8 and elsewhere in libcrypt will return non-NULL but set errno on failure. The workaround is to use crypt_rn(), provided only by libcrypt, which will return NULL on failure, and so avoid checking errno in the non-failure case. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14424 Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Alexander Bokovoy <ab@samba.org> (cherry picked from commit 91453f110fa72062291eb59ad9d95fab0f423557)
-rw-r--r--lib/replace/wscript1
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c37
2 files changed, 31 insertions, 7 deletions
diff --git a/lib/replace/wscript b/lib/replace/wscript
index 56e2a22de49..d5651f1bdc0 100644
--- a/lib/replace/wscript
+++ b/lib/replace/wscript
@@ -649,6 +649,7 @@ def configure(conf):
conf.CHECK_FUNCS_IN('crypt', 'crypt', checklibc=True)
conf.CHECK_FUNCS_IN('crypt_r', 'crypt', checklibc=True)
+ conf.CHECK_FUNCS_IN('crypt_rn', 'crypt', checklibc=True)
conf.CHECK_VARIABLE('rl_event_hook', define='HAVE_DECL_RL_EVENT_HOOK', always=True,
headers='readline.h readline/readline.h readline/history.h')
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index 006e35c46d5..f5a6bdc43d6 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -1507,8 +1507,10 @@ static int setup_primary_userPassword_hash(
int rounds = 0; /* The number of hash rounds */
DATA_BLOB *hash_blob = NULL;
TALLOC_CTX *frame = talloc_stackframe();
-#ifdef HAVE_CRYPT_R
- struct crypt_data crypt_data; /* working storage used by crypt */
+#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT_RN)
+ struct crypt_data crypt_data = {
+ .initialized = 0 /* working storage used by crypt */
+ };
#endif
/* Genrate a random password salt */
@@ -1549,8 +1551,32 @@ static int setup_primary_userPassword_hash(
* Relies on the assertion that cleartext_utf8->data is a zero
* terminated UTF-8 string
*/
+
+ /*
+ * crypt_r() and crypt() may return a null pointer upon error
+ * depending on how libcrypt was configured, so we prefer
+ * crypt_rn() from libcrypt / libxcrypt which always returns
+ * NULL on error.
+ *
+ * POSIX specifies returning a null pointer and setting
+ * errno.
+ *
+ * RHEL 7 (which does not use libcrypt / libxcrypt) returns a
+ * non-NULL pointer from crypt_r() on success but (always?)
+ * sets errno during internal processing in the NSS crypto
+ * subsystem.
+ *
+ * By preferring crypt_rn we avoid the 'return non-NULL but
+ * set-errno' that we otherwise cannot tell apart from the
+ * RHEL 7 behaviour.
+ */
errno = 0;
-#ifdef HAVE_CRYPT_R
+#ifdef HAVE_CRYPT_RN
+ hash = crypt_rn((char *)io->n.cleartext_utf8->data,
+ cmd,
+ &crypt_data,
+ sizeof(crypt_data));
+#elif HAVE_CRYPT_R
hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
#else
/*
@@ -1559,10 +1585,7 @@ static int setup_primary_userPassword_hash(
*/
hash = crypt((char *)io->n.cleartext_utf8->data, cmd);
#endif
- /* crypt_r and crypt may return a null pointer upon error depending on
- * how libcrypt was configured. POSIX specifies returning a null
- * pointer and setting errno. */
- if (hash == NULL || errno != 0) {
+ if (hash == NULL) {
char buf[1024];
int err = strerror_r(errno, buf, sizeof(buf));
if (err != 0) {