From: Andrew Bartlett Date: Wed, 1 Jul 2020 02:35:39 +0000 (+1200) Subject: dsdb: Allow "password hash userPassword schemes = CryptSHA256" to work on RHEL7 X-Git-Tag: samba-4.11.12~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e52f51990912e08b4c25f53ceeab54e6220ac613;p=thirdparty%2Fsamba.git 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 Reviewed-by: Alexander Bokovoy (cherry picked from commit 91453f110fa72062291eb59ad9d95fab0f423557) --- 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) {