]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/libcrypt-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 /* libxcrypt is a replacement for glibc's libcrypt, and libcrypt might be
5 * removed from glibc at some point. As part of the removal, defines for
6 * crypt(3) are dropped from unistd.h, and we must include crypt.h instead.
8 * Newer versions of glibc (v2.0+) already ship crypt.h with a definition
9 * of crypt(3) as well, so we simply include it if it is present. MariaDB,
10 * MySQL, PostgreSQL, Perl and some other wide-spread packages do it the
11 * same way since ages without any problems.
21 #include "alloc-util.h"
22 #include "errno-util.h"
23 #include "libcrypt-util.h"
26 #include "memory-util.h"
27 #include "missing_stdlib.h"
28 #include "random-util.h"
29 #include "string-util.h"
32 int make_salt(char **ret
) {
34 #if HAVE_CRYPT_GENSALT_RA
38 /* If we have crypt_gensalt_ra() we default to the "preferred method" (i.e. usually yescrypt).
39 * crypt_gensalt_ra() is usually provided by libxcrypt. */
41 e
= secure_getenv("SYSTEMD_CRYPT_PREFIX");
43 #if HAVE_CRYPT_PREFERRED_METHOD
44 e
= crypt_preferred_method();
49 log_debug("Generating salt for hash prefix: %s", e
);
51 salt
= crypt_gensalt_ra(e
, 0, NULL
, 0);
58 /* If crypt_gensalt_ra() is not available, we use SHA512 and generate the salt on our own. */
60 static const char table
[] =
61 "abcdefghijklmnopqrstuvwxyz"
62 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
71 /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but
72 * SHA512, i.e. is legacy-free and minimizes our deps. */
74 assert_cc(sizeof(table
) == 64U + 1U);
76 log_debug("Generating fallback salt for hash prefix: $6$");
78 /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */
79 r
= crypto_random_bytes(raw
, sizeof(raw
));
83 salt
= new(char, 3+sizeof(raw
)+1+1);
87 /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
88 j
= stpcpy(salt
, "$6$");
89 for (i
= 0; i
< sizeof(raw
); i
++)
90 j
[i
] = table
[raw
[i
] & 63];
100 # define CRYPT_RA_NAME "crypt_ra"
102 # define CRYPT_RA_NAME "crypt_r"
104 /* Provide a poor man's fallback that uses a fixed size buffer. */
106 static char* systemd_crypt_ra(const char *phrase
, const char *setting
, void **data
, int *size
) {
110 /* We allocate the buffer because crypt(3) says: struct crypt_data may be quite large (32kB in this
111 * implementation of libcrypt; over 128kB in some other implementations). This is large enough that
112 * it may be unwise to allocate it on the stack. */
115 *data
= new0(struct crypt_data
, 1);
121 *size
= (int) (sizeof(struct crypt_data
));
124 char *t
= crypt_r(phrase
, setting
, *data
);
128 /* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on
129 * error, so let's just return that. */
136 #define crypt_ra systemd_crypt_ra
140 int hash_password_full(const char *password
, void **cd_data
, int *cd_size
, char **ret
) {
141 _cleanup_free_
char *salt
= NULL
;
142 _cleanup_(erase_and_freep
) void *_cd_data
= NULL
;
146 assert(!!cd_data
== !!cd_size
);
148 r
= make_salt(&salt
);
150 return log_debug_errno(r
, "Failed to generate salt: %m");
153 p
= crypt_ra(password
, salt
, cd_data
?: &_cd_data
, cd_size
?: &_cd_size
);
155 return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL
)),
156 CRYPT_RA_NAME
"() failed: %m");
158 return strdup_to(ret
, p
);
161 bool looks_like_hashed_password(const char *s
) {
162 /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists
163 * various hashing methods. We only reject (return false) strings which are documented to have
164 * different meanings.
166 * In particular, we allow locked passwords, i.e. strings starting with "!", including just "!",
167 * i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e.
172 s
+= strspn(s
, "!"); /* Skip (possibly duplicated) locking prefix */
174 return !STR_IN_SET(s
, "x", "*");
177 int test_password_one(const char *hashed_password
, const char *password
) {
178 _cleanup_(erase_and_freep
) void *cd_data
= NULL
;
183 k
= crypt_ra(password
, hashed_password
, &cd_data
, &cd_size
);
187 /* Unknown or unavailable hashing method or string too short */
191 return streq(k
, hashed_password
);
194 int test_password_many(char **hashed_password
, const char *password
) {
197 STRV_FOREACH(hpw
, hashed_password
) {
198 r
= test_password_one(*hpw
, password
);