]> 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 13:57:23 +0000 (13:57 +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 56e2a22de4977ec3c0134ab10e2ea2babd54c928..d5651f1bdc0e13d72ba95408a809e8f408a1ff11 100644 (file)
@@ -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')
index 006e35c46d573311dbbf22fcae4651f6988bbbfa..f5a6bdc43d6a74fcf2c9612e5636a8fdc7311ffe 100644 (file)
@@ -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) {