]>
Commit | Line | Data |
---|---|---|
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 | ||
16 | int 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 |
78 | int 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 |
102 | bool 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 | } |