]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
util: add a crypt wrapper, derived from dsdb:password_hash
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Thu, 5 Dec 2024 03:35:51 +0000 (16:35 +1300)
committerAndreas Schneider <asn@cryptomilk.org>
Fri, 20 Dec 2024 07:04:31 +0000 (07:04 +0000)
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 <asn@samba.org>
lib/util/util_crypt.c [new file with mode: 0644]
lib/util/util_crypt.h [new file with mode: 0644]
lib/util/wscript_build

diff --git a/lib/util/util_crypt.c b/lib/util/util_crypt.c
new file mode 100644 (file)
index 0000000..0f7b2d0
--- /dev/null
@@ -0,0 +1,90 @@
+#include <replace.h>
+#include "data_blob.h"
+#include <talloc.h>
+#include <crypt.h>
+#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 (file)
index 0000000..8c289e4
--- /dev/null
@@ -0,0 +1,5 @@
+
+int talloc_crypt_blob(TALLOC_CTX *mem_ctx,
+                     const char *phrase,
+                     const char *cmd,
+                     DATA_BLOB *blob);
index b4fcfeaba07c576fcc2eee7a0f0762ab594fae0f..7de9c0b7b172d7a9a6f2c34d5c5af1968f1a8e87 100644 (file)
@@ -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',