]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
42f3b2f9 | 2 | |
83764f8d ZJS |
3 | #if HAVE_CRYPT_H |
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. | |
7 | * | |
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. | |
12 | */ | |
13 | # include <crypt.h> | |
14 | #else | |
15 | # include <unistd.h> | |
16 | #endif | |
17 | ||
42f3b2f9 LP |
18 | #include <stdlib.h> |
19 | ||
20 | #include "alloc-util.h" | |
0e98d17e | 21 | #include "errno-util.h" |
42f3b2f9 LP |
22 | #include "libcrypt-util.h" |
23 | #include "log.h" | |
14dc330c | 24 | #include "random-util.h" |
42f3b2f9 LP |
25 | #include "string-util.h" |
26 | #include "strv.h" | |
27 | ||
28 | int make_salt(char **ret) { | |
29 | ||
2b49f0ca | 30 | #if HAVE_CRYPT_GENSALT_RA |
42f3b2f9 LP |
31 | const char *e; |
32 | char *salt; | |
33 | ||
2b49f0ca ZJS |
34 | /* If we have crypt_gensalt_ra() we default to the "preferred method" (i.e. usually yescrypt). |
35 | * crypt_gensalt_ra() is usually provided by libxcrypt. */ | |
42f3b2f9 LP |
36 | |
37 | e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); | |
38 | if (!e) | |
feee7f62 | 39 | #if HAVE_CRYPT_PREFERRED_METHOD |
42f3b2f9 | 40 | e = crypt_preferred_method(); |
feee7f62 LB |
41 | #else |
42 | e = "$6$"; | |
43 | #endif | |
42f3b2f9 LP |
44 | |
45 | log_debug("Generating salt for hash prefix: %s", e); | |
46 | ||
47 | salt = crypt_gensalt_ra(e, 0, NULL, 0); | |
48 | if (!salt) | |
49 | return -errno; | |
50 | ||
51 | *ret = salt; | |
52 | return 0; | |
53 | #else | |
2b49f0ca | 54 | /* If crypt_gensalt_ra() is not available, we use SHA512 and generate the salt on our own. */ |
42f3b2f9 LP |
55 | |
56 | static const char table[] = | |
57 | "abcdefghijklmnopqrstuvwxyz" | |
58 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
59 | "0123456789" | |
60 | "./"; | |
61 | ||
62 | uint8_t raw[16]; | |
63 | char *salt, *j; | |
64 | size_t i; | |
65 | int r; | |
66 | ||
67 | /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but | |
68 | * SHA512, i.e. is legacy-free and minimizes our deps. */ | |
69 | ||
70 | assert_cc(sizeof(table) == 64U + 1U); | |
71 | ||
9de324c3 ZJS |
72 | log_debug("Generating fallback salt for hash prefix: $6$"); |
73 | ||
42f3b2f9 | 74 | /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ |
87cb1ab6 | 75 | r = crypto_random_bytes(raw, sizeof(raw)); |
42f3b2f9 LP |
76 | if (r < 0) |
77 | return r; | |
78 | ||
79 | salt = new(char, 3+sizeof(raw)+1+1); | |
80 | if (!salt) | |
81 | return -ENOMEM; | |
82 | ||
83 | /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ | |
84 | j = stpcpy(salt, "$6$"); | |
85 | for (i = 0; i < sizeof(raw); i++) | |
86 | j[i] = table[raw[i] & 63]; | |
87 | j[i++] = '$'; | |
88 | j[i] = 0; | |
89 | ||
90 | *ret = salt; | |
91 | return 0; | |
92 | #endif | |
93 | } | |
64aa2622 | 94 | |
9de324c3 ZJS |
95 | #if HAVE_CRYPT_RA |
96 | # define CRYPT_RA_NAME "crypt_ra" | |
97 | #else | |
98 | # define CRYPT_RA_NAME "crypt_r" | |
99 | ||
100 | /* Provide a poor man's fallback that uses a fixed size buffer. */ | |
101 | ||
102 | static char* systemd_crypt_ra(const char *phrase, const char *setting, void **data, int *size) { | |
103 | assert(data); | |
104 | assert(size); | |
105 | ||
106 | /* We allocate the buffer because crypt(3) says: struct crypt_data may be quite large (32kB in this | |
107 | * implementation of libcrypt; over 128kB in some other implementations). This is large enough that | |
108 | * it may be unwise to allocate it on the stack. */ | |
109 | ||
110 | if (!*data) { | |
111 | *data = new0(struct crypt_data, 1); | |
112 | if (!*data) { | |
a937fa96 | 113 | errno = ENOMEM; |
9de324c3 ZJS |
114 | return NULL; |
115 | } | |
116 | ||
117 | *size = (int) (sizeof(struct crypt_data)); | |
118 | } | |
119 | ||
120 | char *t = crypt_r(phrase, setting, *data); | |
121 | if (!t) | |
122 | return NULL; | |
123 | ||
124 | /* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on | |
125 | * error, so let's just return that. */ | |
126 | if (t[0] == '*') | |
127 | return NULL; | |
128 | ||
129 | return t; | |
130 | } | |
131 | ||
132 | #define crypt_ra systemd_crypt_ra | |
133 | ||
134 | #endif | |
135 | ||
a937ce2d | 136 | int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) { |
0e98d17e | 137 | _cleanup_free_ char *salt = NULL; |
a937ce2d | 138 | _cleanup_(erase_and_freep) void *_cd_data = NULL; |
454318d3 | 139 | const char *p; |
a937ce2d ZJS |
140 | int r, _cd_size = 0; |
141 | ||
142 | assert(!!cd_data == !!cd_size); | |
0e98d17e ZJS |
143 | |
144 | r = make_salt(&salt); | |
145 | if (r < 0) | |
146 | return log_debug_errno(r, "Failed to generate salt: %m"); | |
147 | ||
148 | errno = 0; | |
a937ce2d | 149 | p = crypt_ra(password, salt, cd_data ?: &_cd_data, cd_size ?: &_cd_size); |
0e98d17e ZJS |
150 | if (!p) |
151 | return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), | |
9de324c3 | 152 | CRYPT_RA_NAME "() failed: %m"); |
0e98d17e | 153 | |
454318d3 | 154 | return strdup_to(ret, p); |
0e98d17e ZJS |
155 | } |
156 | ||
8f796e40 ZJS |
157 | bool looks_like_hashed_password(const char *s) { |
158 | /* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists | |
159 | * various hashing methods. We only reject (return false) strings which are documented to have | |
160 | * different meanings. | |
161 | * | |
162 | * In particular, we allow locked passwords, i.e. strings starting with "!", including just "!", | |
163 | * i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e. | |
164 | */ | |
165 | if (!s) | |
64aa2622 LP |
166 | return false; |
167 | ||
8f796e40 ZJS |
168 | s += strspn(s, "!"); /* Skip (possibly duplicated) locking prefix */ |
169 | ||
170 | return !STR_IN_SET(s, "x", "*"); | |
64aa2622 | 171 | } |
2ae297fe ZJS |
172 | |
173 | int test_password_one(const char *hashed_password, const char *password) { | |
999b49c8 ZJS |
174 | _cleanup_(erase_and_freep) void *cd_data = NULL; |
175 | int cd_size = 0; | |
2ae297fe | 176 | const char *k; |
2ae297fe ZJS |
177 | |
178 | errno = 0; | |
999b49c8 | 179 | k = crypt_ra(password, hashed_password, &cd_data, &cd_size); |
35e22827 ZJS |
180 | if (!k) { |
181 | if (errno == ENOMEM) | |
182 | return -ENOMEM; | |
183 | /* Unknown or unavailable hashing method or string too short */ | |
184 | return 0; | |
185 | } | |
2ae297fe | 186 | |
999b49c8 | 187 | return streq(k, hashed_password); |
2ae297fe ZJS |
188 | } |
189 | ||
190 | int test_password_many(char **hashed_password, const char *password) { | |
2ae297fe ZJS |
191 | int r; |
192 | ||
193 | STRV_FOREACH(hpw, hashed_password) { | |
194 | r = test_password_one(*hpw, password); | |
195 | if (r < 0) | |
196 | return r; | |
197 | if (r > 0) | |
198 | return true; | |
199 | } | |
200 | ||
201 | return false; | |
202 | } |