]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared/libcrypt-util: add fallback for crypt_ra()
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 10 Sep 2020 16:30:22 +0000 (18:30 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 15 Sep 2020 09:52:30 +0000 (11:52 +0200)
Following the style in missing_syscall.h, we use a non-conflicting name
for the function and use a macro to map to the real name to the replacement.

src/shared/libcrypt-util.c

index de0cfced6d91a897e217b6dd83a644d02c128f8e..66f345ee5f7cb228e8279ce081ed168cc12176dd 100644 (file)
@@ -69,6 +69,8 @@ int make_salt(char **ret) {
 
         assert_cc(sizeof(table) == 64U + 1U);
 
+        log_debug("Generating fallback salt for hash prefix: $6$");
+
         /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */
         r = genuine_random_bytes(raw, sizeof(raw), RANDOM_BLOCK);
         if (r < 0)
@@ -90,6 +92,47 @@ int make_salt(char **ret) {
 #endif
 }
 
+#if HAVE_CRYPT_RA
+#  define CRYPT_RA_NAME "crypt_ra"
+#else
+#  define CRYPT_RA_NAME "crypt_r"
+
+/* Provide a poor man's fallback that uses a fixed size buffer. */
+
+static char* systemd_crypt_ra(const char *phrase, const char *setting, void **data, int *size) {
+        assert(data);
+        assert(size);
+
+        /* We allocate the buffer because crypt(3) says: struct crypt_data may be quite large (32kB in this
+         * implementation of libcrypt; over 128kB in some other implementations). This is large enough that
+         * it may be unwise to allocate it on the stack. */
+
+        if (!*data) {
+                *data = new0(struct crypt_data, 1);
+                if (!*data) {
+                        errno = -ENOMEM;
+                        return NULL;
+                }
+
+                *size = (int) (sizeof(struct crypt_data));
+        }
+
+        char *t = crypt_r(phrase, setting, *data);
+        if (!t)
+                return NULL;
+
+        /* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on
+         * error, so let's just return that. */
+        if (t[0] == '*')
+                return NULL;
+
+        return t;
+}
+
+#define crypt_ra systemd_crypt_ra
+
+#endif
+
 int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) {
         _cleanup_free_ char *salt = NULL;
         _cleanup_(erase_and_freep) void *_cd_data = NULL;
@@ -106,7 +149,7 @@ int hash_password_full(const char *password, void **cd_data, int *cd_size, char
         p = crypt_ra(password, salt, cd_data ?: &_cd_data, cd_size ?: &_cd_size);
         if (!p)
                 return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)),
-                                       "crypt_ra() failed: %m");
+                                       CRYPT_RA_NAME "() failed: %m");
 
         p = strdup(p);
         if (!p)