From 125b262675217084e0c59014b4a98f724f1c4fb3 Mon Sep 17 00:00:00 2001 From: David Karoly Date: Wed, 8 Feb 2023 22:16:08 +0100 Subject: [PATCH] libroot: introduce crypt_r Change-Id: Ieacd1b383ac078a440227c7954f5531a36fbbd62 Reviewed-on: https://review.haiku-os.org/c/haiku/+/5827 Tested-by: Commit checker robot Reviewed-by: Adrien Destugues --- headers/compatibility/gnu/crypt.h | 46 +++++++++++++++++ src/libs/gnu/Jamfile | 2 + src/libs/gnu/crypt.cpp | 16 ++++++ src/system/libroot/posix/crypt/Jamfile | 2 + src/system/libroot/posix/crypt/crypt.cpp | 50 ++++++++++++------- src/system/libroot/posix/crypt/crypt_legacy.h | 2 +- .../libroot/posix/crypt/crypt_legacy_util.c | 24 ++++----- src/tests/system/libroot/posix/CryptTest.cpp | 20 ++++++++ src/tests/system/libroot/posix/CryptTest.h | 1 + src/tests/system/libroot/posix/Jamfile | 4 +- 10 files changed, 132 insertions(+), 35 deletions(-) create mode 100644 headers/compatibility/gnu/crypt.h create mode 100644 src/libs/gnu/crypt.cpp diff --git a/headers/compatibility/gnu/crypt.h b/headers/compatibility/gnu/crypt.h new file mode 100644 index 0000000000..da60429965 --- /dev/null +++ b/headers/compatibility/gnu/crypt.h @@ -0,0 +1,46 @@ +/* + * Copyright 2023, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _GNU_CRYPT_H_ +#define _GNU_CRYPT_H_ + + +#include + + +#ifdef _DEFAULT_SOURCE + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +struct crypt_data { + int initialized; + char buf[512]; +}; + + +char *crypt_rn(const char *key, const char *salt, struct crypt_data *data, size_t size); + + +static inline char * +crypt_r(const char *key, const char *salt, struct crypt_data *data) +{ + return crypt_rn(key, salt, data, sizeof(struct crypt_data)); +} + + +#ifdef __cplusplus +} +#endif + + +#endif + + +#endif /* _GNU_CRYPT_H_ */ diff --git a/src/libs/gnu/Jamfile b/src/libs/gnu/Jamfile index 0a2544a82f..bb7d90d4dc 100644 --- a/src/libs/gnu/Jamfile +++ b/src/libs/gnu/Jamfile @@ -1,5 +1,6 @@ SubDir HAIKU_TOP src libs gnu ; +UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility gnu ] : true ; UsePrivateHeaders shared ; @@ -10,6 +11,7 @@ local architectureObject ; for architectureObject in [ MultiArchSubDirSetup ] { on $(architectureObject) { SharedLibrary [ MultiArchDefaultGristFiles libgnu.so ] : + crypt.cpp memmem.c qsort.c xattr.cpp diff --git a/src/libs/gnu/crypt.cpp b/src/libs/gnu/crypt.cpp new file mode 100644 index 0000000000..24df745803 --- /dev/null +++ b/src/libs/gnu/crypt.cpp @@ -0,0 +1,16 @@ +/* + * Copyright 2023 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#include + + +/* move this to libroot_private.h ??? */ +extern "C" char *_crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size); + + +char * +crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size) +{ + return _crypt_rn(key, setting, data, size); +} diff --git a/src/system/libroot/posix/crypt/Jamfile b/src/system/libroot/posix/crypt/Jamfile index 8331fb7320..3c8d33a0a6 100644 --- a/src/system/libroot/posix/crypt/Jamfile +++ b/src/system/libroot/posix/crypt/Jamfile @@ -2,6 +2,8 @@ SubDir HAIKU_TOP src system libroot posix crypt ; UsePrivateHeaders libroot ; UsePrivateSystemHeaders ; +SubDirSysHdrs $(HAIKU_TOP) headers compatibility bsd ; +SubDirSysHdrs $(HAIKU_TOP) headers compatibility gnu ; local architectureObject ; for architectureObject in [ MultiArchSubDirSetup ] { diff --git a/src/system/libroot/posix/crypt/crypt.cpp b/src/system/libroot/posix/crypt/crypt.cpp index c932565fd4..e9346b1cbf 100644 --- a/src/system/libroot/posix/crypt/crypt.cpp +++ b/src/system/libroot/posix/crypt/crypt.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -24,8 +25,8 @@ #define SALT_STR_BYTES (SALT_BYTES * 2 + 1) #define DEFAULT_N_LOG2 14 -// $s$99$ salt $ hash \0 #define CRYPT_OUTPUT_BYTES (6 + 64 + 1 + 64 + 1) +#define SALT_OUTPUT_BYTES (6 + 64 + 1 + 1) static const char* kHexAlphabet = "0123456789abcdef"; static const int8 kHexLookup[] = { @@ -97,17 +98,16 @@ fromHex(const char* hex, uint8* outBuffer, size_t outBufferLength) //! Generate a new salt appropriate for crypt(). -static char* -crypt_gensalt() +static int +crypt_gensalt_rn(char *outbuf, size_t bufsize) { - static char result[CRYPT_OUTPUT_BYTES]; uint8 salt[SALT_BYTES]; char saltString[SALT_STR_BYTES]; size_t totalBytesRead = 0; int fd = open("/dev/random", O_RDONLY, 0); if (fd < 0) - return NULL; + return -1; while (totalBytesRead < sizeof(salt)) { const ssize_t bytesRead = read(fd, @@ -115,7 +115,7 @@ crypt_gensalt() sizeof(salt) - totalBytesRead); if (bytesRead <= 0) { close(fd); - return NULL; + return -1; } totalBytesRead += bytesRead; @@ -123,34 +123,38 @@ crypt_gensalt() close(fd); assert(toHex(salt, sizeof(salt), saltString, sizeof(saltString)) == 0); - snprintf(result, sizeof(result), "$s$%d$%s$", DEFAULT_N_LOG2, saltString); - return result; + snprintf(outbuf, bufsize, "$s$%d$%s$", DEFAULT_N_LOG2, saltString); + return 0; } -char * -crypt(const char* key, const char* setting) +extern "C" char * +_crypt_rn(const char* key, const char* setting, struct crypt_data* data, size_t size) { - static char outBuffer[CRYPT_OUTPUT_BYTES]; uint8 saltBinary[SALT_BYTES]; char saltString[SALT_STR_BYTES]; + char gensaltResult[SALT_OUTPUT_BYTES]; uint8 resultBuffer[32]; char hexResultBuffer[64 + 1]; int nLog2 = DEFAULT_N_LOG2; if (setting == NULL) { - setting = crypt_gensalt(); - if (setting == NULL) { - // crypt_gensalt should set errno itself. + int res = crypt_gensalt_rn(gensaltResult, sizeof(gensaltResult)); + + // crypt_gensalt_r should set errno itself. + if (res < 0) return NULL; - } + + setting = gensaltResult; } // Some idioms existed where the password was also used as the salt. // As a crude heuristic, use the old crypt algorithm if the salt is // shortish. - if (strlen(setting) < 16) - return crypt_legacy(key, setting); + if (strlen(setting) < 16) { + crypt_legacy(key, setting, data->buf); + return data->buf; + } // We don't want to fall into the old algorithm by accident somehow, so // if our salt is kind of like our salt, but not exactly, return an @@ -183,10 +187,18 @@ crypt(const char* key, const char* setting) assert(toHex(resultBuffer, sizeof(resultBuffer), hexResultBuffer, sizeof(hexResultBuffer)) == 0); - snprintf(outBuffer, sizeof(outBuffer), "$s$%d$%s$%s", nLog2, saltString, + snprintf(data->buf, size - sizeof(int), "$s$%d$%s$%s", nLog2, saltString, hexResultBuffer); - return outBuffer; + return data->buf; +} + + +char * +crypt(const char* key, const char* salt) +{ + static struct crypt_data data; + return _crypt_rn(key, salt, &data, sizeof(struct crypt_data)); } diff --git a/src/system/libroot/posix/crypt/crypt_legacy.h b/src/system/libroot/posix/crypt/crypt_legacy.h index 62774a47f2..16e08077f1 100644 --- a/src/system/libroot/posix/crypt/crypt_legacy.h +++ b/src/system/libroot/posix/crypt/crypt_legacy.h @@ -5,7 +5,7 @@ extern "C" { #endif -char *crypt_legacy(const char *key, const char *salt); +void crypt_legacy(const char *key, const char *salt, char *outbuf); #ifdef __cplusplus } diff --git a/src/system/libroot/posix/crypt/crypt_legacy_util.c b/src/system/libroot/posix/crypt/crypt_legacy_util.c index 734bbc3507..192bb85230 100644 --- a/src/system/libroot/posix/crypt/crypt_legacy_util.c +++ b/src/system/libroot/posix/crypt/crypt_legacy_util.c @@ -694,10 +694,8 @@ ufc_long *_ufc_dofinalperm(l1, l2, r1, r2) * prefixing with the salt */ -STATIC char *output_conversion(v1, v2, salt) - ufc_long v1, v2; - char *salt; - { static char outbuf[14]; +STATIC void output_conversion_r(ufc_long v1, ufc_long v2, const char *salt, char *outbuf) +{ int i, s, shf; outbuf[0] = salt[0]; @@ -718,9 +716,7 @@ STATIC char *output_conversion(v1, v2, salt) outbuf[12] = bin_to_ascii(s); outbuf[13] = 0; - - return outbuf; - } +} ufc_long *_ufc_doit(); @@ -728,9 +724,9 @@ ufc_long *_ufc_doit(); * UNIX crypt function */ -char *crypt_legacy(key, salt) - const char *key, *salt; - { ufc_long *s; +void crypt_legacy(const char *key, const char *salt, char *outbuf) +{ + ufc_long *s; char ktab[9]; /* @@ -758,8 +754,8 @@ char *crypt_legacy(key, salt) /* * And convert back to 6 bit ASCII */ - return output_conversion(s[0], s[1], salt); - } + output_conversion_r(s[0], s[1], salt, outbuf); +} /* * UNIX encrypt function. Takes a bitvector @@ -901,7 +897,7 @@ char *crypt16(key, salt) /* * And convert back to 6 bit ASCII */ - strcpy (res, output_conversion(s[0], s[1], salt)); + output_conversion_r(s[0], s[1], salt, res); clearmem(ttab, sizeof ttab); if (strlen (key) > 8) (void)strncpy(ttab, key+8, 8); @@ -915,7 +911,7 @@ char *crypt16(key, salt) /* * And convert back to 6 bit ASCII */ - strcpy (q, output_conversion(t[0], t[1], salt)); + output_conversion_r(t[0], t[1], salt, q); strcpy (res+13, q+2); clearmem(ktab, sizeof ktab); diff --git a/src/tests/system/libroot/posix/CryptTest.cpp b/src/tests/system/libroot/posix/CryptTest.cpp index c290757c27..8dffbd7e0e 100644 --- a/src/tests/system/libroot/posix/CryptTest.cpp +++ b/src/tests/system/libroot/posix/CryptTest.cpp @@ -7,6 +7,7 @@ */ +#include #include #include #include @@ -87,6 +88,22 @@ CryptTest::TestBadSalt() } +void +CryptTest::TestCryptR() +{ + char tmp[200]; + + struct crypt_data data; + data.initialized = 0; + + char* buf = crypt_r(PASSWORD, NULL, &data); + CPPUNIT_ASSERT(buf != NULL); + strlcpy(tmp, buf, sizeof(tmp)); + buf = crypt(PASSWORD, tmp); + CPPUNIT_ASSERT(strcmp(buf, tmp) == 0); +} + + void CryptTest::AddTests(BTestSuite& parent) { @@ -103,5 +120,8 @@ CryptTest::AddTests(BTestSuite& parent) suite.addTest(new CppUnit::TestCaller( "CryptTest::TestBadSalt", &CryptTest::TestBadSalt)); + suite.addTest(new CppUnit::TestCaller( + "CryptTest::TestCryptR", + &CryptTest::TestCryptR)); parent.addTest("CryptTest", &suite); } diff --git a/src/tests/system/libroot/posix/CryptTest.h b/src/tests/system/libroot/posix/CryptTest.h index ee208adf65..244e84a3ec 100644 --- a/src/tests/system/libroot/posix/CryptTest.h +++ b/src/tests/system/libroot/posix/CryptTest.h @@ -27,6 +27,7 @@ public: void TestCustomSalt(); void TestSaltGeneration(); void TestBadSalt(); + void TestCryptR(); static void AddTests(BTestSuite& suite); }; diff --git a/src/tests/system/libroot/posix/Jamfile b/src/tests/system/libroot/posix/Jamfile index 68b4cb1e2c..fd5bbf1b54 100644 --- a/src/tests/system/libroot/posix/Jamfile +++ b/src/tests/system/libroot/posix/Jamfile @@ -1,6 +1,8 @@ SubDir HAIKU_TOP src tests system libroot posix ; UsePrivateHeaders libroot system ; +SubDirSysHdrs $(HAIKU_TOP) headers compatibility bsd ; +SubDirSysHdrs $(HAIKU_TOP) headers compatibility gnu ; # filter warnings about strftime()-formats in locale_test TARGET_WARNING_C++FLAGS_$(TARGET_PACKAGING_ARCH) @@ -87,7 +89,7 @@ UnitTestLib librootposixtest.so : CryptTest.cpp - : be [ TargetLibstdc++ ] [ TargetLibsupc++ ] + : be libgnu.so [ TargetLibstdc++ ] [ TargetLibsupc++ ] ; SubInclude HAIKU_TOP src tests system libroot posix math ;