diff options
author | Andrew Bartlett <abartlet@samba.org> | 2020-07-01 14:35:39 +1200 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2020-07-06 13:57:23 +0000 |
commit | e52f51990912e08b4c25f53ceeab54e6220ac613 (patch) | |
tree | 62ce7881d47ec5bf66677e4d6b62e9b484479cf3 | |
parent | f0e3089a5a75f02a3a4398c66fda4d2950a89c93 (diff) | |
download | samba-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/wscript | 1 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/password_hash.c | 37 |
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) { |