]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
dsdb: Allow "password hash userPassword schemes = CryptSHA256" to work on RHEL7
authorAndrew Bartlett <abartlet@samba.org>
Wed, 1 Jul 2020 02:35:39 +0000 (14:35 +1200)
committerKarolin Seeger <kseeger@samba.org>
Mon, 6 Jul 2020 09:50:31 +0000 (09:50 +0000)
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)

lib/replace/wscript
source4/dsdb/samdb/ldb_modules/password_hash.c

index ab2b3c043afeafb67f3ed96db8cd1085ed8d6779..55c8903f1c89c250cc4d3128682bdd2febcbe86c 100644 (file)
@@ -661,6 +661,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')
index ffd48da616e40363dc03dd2a00a56d5ceaafa878..c321678e8139f63b5b553e817aa3e1990d3c5a6d 100644 (file)
@@ -1472,8 +1472,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 */
@@ -1514,8 +1516,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
        /*
@@ -1524,10 +1550,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) {