]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/libcrypt-util.c
Add a helper function that does make_salt+crypt_r
[thirdparty/systemd.git] / src / shared / libcrypt-util.c
CommitLineData
42f3b2f9
LP
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno.h>
4#include <stdlib.h>
5
6#include "alloc-util.h"
0e98d17e 7#include "errno-util.h"
42f3b2f9
LP
8#include "libcrypt-util.h"
9#include "log.h"
10#include "macro.h"
11#include "missing_stdlib.h"
12#include "random-util.h"
13#include "string-util.h"
14#include "strv.h"
15
16int make_salt(char **ret) {
17
18#ifdef XCRYPT_VERSION_MAJOR
19 const char *e;
20 char *salt;
21
22 /* If we have libxcrypt we default to the "preferred method" (i.e. usually yescrypt), and generate it
23 * with crypt_gensalt_ra(). */
24
25 e = secure_getenv("SYSTEMD_CRYPT_PREFIX");
26 if (!e)
27 e = crypt_preferred_method();
28
29 log_debug("Generating salt for hash prefix: %s", e);
30
31 salt = crypt_gensalt_ra(e, 0, NULL, 0);
32 if (!salt)
33 return -errno;
34
35 *ret = salt;
36 return 0;
37#else
38 /* If libxcrypt is not used, we use SHA512 and generate the salt on our own since crypt_gensalt_ra()
39 * is not available. */
40
41 static const char table[] =
42 "abcdefghijklmnopqrstuvwxyz"
43 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
44 "0123456789"
45 "./";
46
47 uint8_t raw[16];
48 char *salt, *j;
49 size_t i;
50 int r;
51
52 /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but
53 * SHA512, i.e. is legacy-free and minimizes our deps. */
54
55 assert_cc(sizeof(table) == 64U + 1U);
56
57 /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */
58 r = genuine_random_bytes(raw, sizeof(raw), RANDOM_BLOCK);
59 if (r < 0)
60 return r;
61
62 salt = new(char, 3+sizeof(raw)+1+1);
63 if (!salt)
64 return -ENOMEM;
65
66 /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
67 j = stpcpy(salt, "$6$");
68 for (i = 0; i < sizeof(raw); i++)
69 j[i] = table[raw[i] & 63];
70 j[i++] = '$';
71 j[i] = 0;
72
73 *ret = salt;
74 return 0;
75#endif
76}
64aa2622 77
0e98d17e
ZJS
78int hash_password(const char *password, char **ret) {
79 _cleanup_free_ char *salt = NULL;
80 char *p;
81 struct crypt_data cd = {};
82 int r;
83
84 r = make_salt(&salt);
85 if (r < 0)
86 return log_debug_errno(r, "Failed to generate salt: %m");
87
88 errno = 0;
89 p = crypt_r(password, salt, &cd);
90 if (!p)
91 return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)),
92 "crypt_r() failed: %m");
93
94 p = strdup(p);
95 if (!p)
96 return -ENOMEM;
97
98 *ret = p;
99 return 0;
100}
101
8f796e40
ZJS
102bool looks_like_hashed_password(const char *s) {
103 /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists
104 * various hashing methods. We only reject (return false) strings which are documented to have
105 * different meanings.
106 *
107 * In particular, we allow locked passwords, i.e. strings starting with "!", including just "!",
108 * i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e.
109 */
110 if (!s)
64aa2622
LP
111 return false;
112
8f796e40
ZJS
113 s += strspn(s, "!"); /* Skip (possibly duplicated) locking prefix */
114
115 return !STR_IN_SET(s, "x", "*");
64aa2622 116}