]>
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" | |
7 | #include "libcrypt-util.h" | |
8 | #include "log.h" | |
9 | #include "macro.h" | |
10 | #include "missing_stdlib.h" | |
11 | #include "random-util.h" | |
12 | #include "string-util.h" | |
13 | #include "strv.h" | |
14 | ||
15 | int make_salt(char **ret) { | |
16 | ||
17 | #ifdef XCRYPT_VERSION_MAJOR | |
18 | const char *e; | |
19 | char *salt; | |
20 | ||
21 | /* If we have libxcrypt we default to the "preferred method" (i.e. usually yescrypt), and generate it | |
22 | * with crypt_gensalt_ra(). */ | |
23 | ||
24 | e = secure_getenv("SYSTEMD_CRYPT_PREFIX"); | |
25 | if (!e) | |
26 | e = crypt_preferred_method(); | |
27 | ||
28 | log_debug("Generating salt for hash prefix: %s", e); | |
29 | ||
30 | salt = crypt_gensalt_ra(e, 0, NULL, 0); | |
31 | if (!salt) | |
32 | return -errno; | |
33 | ||
34 | *ret = salt; | |
35 | return 0; | |
36 | #else | |
37 | /* If libxcrypt is not used, we use SHA512 and generate the salt on our own since crypt_gensalt_ra() | |
38 | * is not available. */ | |
39 | ||
40 | static const char table[] = | |
41 | "abcdefghijklmnopqrstuvwxyz" | |
42 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
43 | "0123456789" | |
44 | "./"; | |
45 | ||
46 | uint8_t raw[16]; | |
47 | char *salt, *j; | |
48 | size_t i; | |
49 | int r; | |
50 | ||
51 | /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but | |
52 | * SHA512, i.e. is legacy-free and minimizes our deps. */ | |
53 | ||
54 | assert_cc(sizeof(table) == 64U + 1U); | |
55 | ||
56 | /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */ | |
57 | r = genuine_random_bytes(raw, sizeof(raw), RANDOM_BLOCK); | |
58 | if (r < 0) | |
59 | return r; | |
60 | ||
61 | salt = new(char, 3+sizeof(raw)+1+1); | |
62 | if (!salt) | |
63 | return -ENOMEM; | |
64 | ||
65 | /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */ | |
66 | j = stpcpy(salt, "$6$"); | |
67 | for (i = 0; i < sizeof(raw); i++) | |
68 | j[i] = table[raw[i] & 63]; | |
69 | j[i++] = '$'; | |
70 | j[i] = 0; | |
71 | ||
72 | *ret = salt; | |
73 | return 0; | |
74 | #endif | |
75 | } | |
64aa2622 LP |
76 | |
77 | bool hashed_password_valid(const char *s) { | |
78 | ||
79 | /* Returns true if the specified string is a 'valid' hashed UNIX password, i.e. if starts with '$' or | |
80 | * with '!$' (the latter being a valid, yet locked password). */ | |
81 | ||
82 | if (isempty(s)) | |
83 | return false; | |
84 | ||
85 | return STARTSWITH_SET(s, "$", "!$"); | |
86 | } |