From: Douglas Bagnall Date: Thu, 5 Dec 2024 03:35:51 +0000 (+1300) Subject: util: add a crypt wrapper, derived from dsdb:password_hash X-Git-Tag: tdb-1.4.13~259 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=833455c7f9f71583d567e3a53e854567cd8c3b0b;p=thirdparty%2Fsamba.git util: add a crypt wrapper, derived from dsdb:password_hash This is going to be used by the dsdb password_hash module, and exposed to Python via pyglue. We're doing this because Python 3.13 has dropped crypt from the Python standard library. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15756 Reviewed-by: Andreas Schneider --- diff --git a/lib/util/util_crypt.c b/lib/util/util_crypt.c new file mode 100644 index 00000000000..0f7b2d0fd31 --- /dev/null +++ b/lib/util/util_crypt.c @@ -0,0 +1,90 @@ +#include +#include "data_blob.h" +#include +#include +#include "util_crypt.h" + + +static int crypt_as_best_we_can(const char *phrase, + const char *setting, + const char **hashp) +{ + int ret = 0; + const char *hash = NULL; + +#if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT_RN) + struct crypt_data crypt_data = { + .initialized = 0 /* working storage used by crypt */ + }; +#endif + + /* + * 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_RN + hash = crypt_rn(phrase, setting, + &crypt_data, + sizeof(crypt_data)); +#elif HAVE_CRYPT_R + hash = crypt_r(phrase, setting, &crypt_data); +#else + /* + * No crypt_r falling back to crypt, which is NOT thread safe + * Thread safety MT-Unsafe race:crypt + */ + hash = crypt(phrase, setting); +#endif + /* + * On error, crypt() and crypt_r() may return a null pointer, + * or a pointer to an invalid hash beginning with a '*'. + */ + ret = errno; + errno = 0; + if (hash == NULL || hash[0] == '*') { + if (ret == 0) { + /* this is annoying */ + ret = ENOTRECOVERABLE; + } + } + + *hashp = hash; + return ret; +} + + +int talloc_crypt_blob(TALLOC_CTX *mem_ctx, + const char *phrase, + const char *setting, + DATA_BLOB *blob) +{ + const char *hash = NULL; + int ret = crypt_as_best_we_can(phrase, setting, &hash); + if (ret != 0) { + blob->data = NULL; + blob->length = 0; + return ret; + } + blob->length = strlen(hash); + blob->data = talloc_memdup(mem_ctx, hash, blob->length); + if (blob->data == NULL) { + return ENOMEM; + } + return 0; +} diff --git a/lib/util/util_crypt.h b/lib/util/util_crypt.h new file mode 100644 index 00000000000..8c289e489e8 --- /dev/null +++ b/lib/util/util_crypt.h @@ -0,0 +1,5 @@ + +int talloc_crypt_blob(TALLOC_CTX *mem_ctx, + const char *phrase, + const char *cmd, + DATA_BLOB *blob); diff --git a/lib/util/wscript_build b/lib/util/wscript_build index b4fcfeaba07..7de9c0b7b17 100644 --- a/lib/util/wscript_build +++ b/lib/util/wscript_build @@ -253,6 +253,12 @@ else: private_library=True, local_include=False) + bld.SAMBA_LIBRARY('util_crypt', + source='util_crypt.c', + deps='talloc crypt', + private_library=True, + local_include=False) + bld.SAMBA_SUBSYSTEM('UNIX_PRIVS', source='unix_privs.c',