s3/mdssvc: add option "elasticsearch:force_substring_search = yes | no" (default...
[samba.git] / lib / util / util_crypt.c
blob9ac6e1cfd0e5e41d44ab3e7f8bd3b696cc71ada5
1 #include <replace.h>
2 #include "data_blob.h"
3 #include "discard.h"
4 #include <talloc.h>
5 #include <crypt.h>
6 #include "util_crypt.h"
9 static int crypt_as_best_we_can(TALLOC_CTX *mem_ctx,
10 const char *phrase,
11 const char *setting,
12 const char **hashp)
14 int ret = 0;
15 const char *hash = NULL;
17 #if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT_RN)
18 struct crypt_data crypt_data = {
19 .initialized = 0 /* working storage used by crypt */
21 #endif
24 * crypt_r() and crypt() may return a null pointer upon error
25 * depending on how libcrypt was configured, so we prefer
26 * crypt_rn() from libcrypt / libxcrypt which always returns
27 * NULL on error.
29 * POSIX specifies returning a null pointer and setting
30 * errno.
32 * RHEL 7 (which does not use libcrypt / libxcrypt) returns a
33 * non-NULL pointer from crypt_r() on success but (always?)
34 * sets errno during internal processing in the NSS crypto
35 * subsystem.
37 * By preferring crypt_rn we avoid the 'return non-NULL but
38 * set-errno' that we otherwise cannot tell apart from the
39 * RHEL 7 behaviour.
41 errno = 0;
43 #ifdef HAVE_CRYPT_RN
44 hash = crypt_rn(phrase, setting,
45 &crypt_data,
46 sizeof(crypt_data));
47 #elif HAVE_CRYPT_R
48 hash = crypt_r(phrase, setting, &crypt_data);
49 #else
51 * No crypt_r falling back to crypt, which is NOT thread safe
52 * Thread safety MT-Unsafe race:crypt
54 hash = crypt(phrase, setting);
55 #endif
57 * On error, crypt() and crypt_r() may return a null pointer,
58 * or a pointer to an invalid hash beginning with a '*'.
60 ret = errno;
61 errno = 0;
62 if (hash == NULL || hash[0] == '*') {
63 if (ret == 0) {
64 /* this is annoying */
65 ret = ENOTRECOVERABLE;
68 if (ret != 0) {
69 return ret;
72 *hashp = talloc_strdup(mem_ctx, hash);
73 if (*hashp == NULL) {
74 ret = -1;
76 return ret;
80 int talloc_crypt_blob(TALLOC_CTX *mem_ctx,
81 const char *phrase,
82 const char *setting,
83 DATA_BLOB *blob)
85 const char *hash = NULL;
86 int ret = crypt_as_best_we_can(mem_ctx, phrase, setting, &hash);
87 if (ret != 0) {
88 blob->data = NULL;
89 blob->length = 0;
90 return ret;
92 blob->length = strlen(hash);
93 blob->data = discard_const_p(uint8_t, hash);
94 if (blob->data == NULL) {
95 return ENOMEM;
97 return 0;
101 char *talloc_crypt_errstring(TALLOC_CTX *mem_ctx, int error)
103 char buf[1024];
104 int err;
105 if (error == ERANGE) {
106 return talloc_strdup(
107 mem_ctx,
108 "Password exceeds maximum length allowed for crypt() hashing");
110 if (error == ENOTRECOVERABLE) {
111 /* probably weird RHEL7 crypt, see crypt_as_best_we_can() */
112 goto unknown;
115 err = strerror_r(error, buf, sizeof(buf));
116 if (err != 0) {
117 goto unknown;
119 return talloc_strndup(mem_ctx, buf, sizeof(buf));
120 unknown:
121 return talloc_strdup(mem_ctx, "Unknown error");