7575#include <sys/stat.h>
7676#include <pwd.h>
7777#include <grp.h>
78+ #ifdef HAVE_CRYPT_R
79+ #include <crypt.h>
80+ #endif
7881#include <errno.h>
7982#include <fcntl.h>
8083#include <unistd.h>
@@ -808,6 +811,13 @@ static int ExtractSalt(char* hash, char** salt, int saltSz)
808811#endif
809812
810813#if defined(WOLFSSH_HAVE_LIBCRYPT ) || defined(WOLFSSH_HAVE_LIBLOGIN )
814+ #ifdef HAVE_CRYPT_R
815+ /* the result lives in data, which the caller wipes */
816+ #define WSSHD_CRYPT (in , salt , data ) crypt_r((in), (salt), (data))
817+ #else
818+ #define WSSHD_CRYPT (in , salt , data ) crypt((in), (salt))
819+ #endif
820+
811821#ifdef WOLFSSHD_UNIT_TEST
812822int CheckPasswordHashUnix (const char * input , const char * stored )
813823#else
@@ -830,6 +840,12 @@ static int CheckPasswordHashUnix(const char* input, const char* stored)
830840 int locked = 0 ;
831841 char * hashedInput = NULL ;
832842 word32 hashedInputSz = 0 , storedSz = 0 ;
843+ #ifdef HAVE_CRYPT_R
844+ /* ~128 KB on glibc, ~32 KB on libxcrypt, so not on the stack */
845+ struct crypt_data * cryptData = NULL ;
846+ #else
847+ void * cryptData = NULL ;
848+ #endif
833849
834850 if (input == NULL || stored == NULL ) {
835851 ret = WS_BAD_ARGUMENT ;
@@ -843,6 +859,20 @@ static int CheckPasswordHashUnix(const char* input, const char* stored)
843859 return ret ;
844860 }
845861
862+ #ifdef HAVE_CRYPT_R
863+ if (ret == WSSHD_AUTH_SUCCESS ) {
864+ cryptData = (struct crypt_data * )WMALLOC (sizeof (* cryptData ), NULL ,
865+ DYNTYPE_SSHD );
866+ if (cryptData == NULL ) {
867+ ret = WS_MEMORY_E ;
868+ }
869+ else {
870+ /* zeroed, as crypt_r() requires of a fresh crypt_data */
871+ WMEMSET (cryptData , 0 , sizeof (* cryptData ));
872+ }
873+ }
874+ #endif
875+
846876 if (ret == WSSHD_AUTH_SUCCESS ) {
847877 const char * salt = stored ;
848878
@@ -870,7 +900,7 @@ static int CheckPasswordHashUnix(const char* input, const char* stored)
870900 }
871901 }
872902
873- hashedInput = crypt (input , salt );
903+ hashedInput = WSSHD_CRYPT (input , salt , cryptData );
874904 /* glibc signals an unsupported salt with a "*"-prefixed sentinel,
875905 * not NULL; check both so the fallback engages on every libc. */
876906 if (locked ) {
@@ -880,7 +910,7 @@ static int CheckPasswordHashUnix(const char* input, const char* stored)
880910 && (hashedInput == NULL || hashedInput [0 ] == '*' );
881911 fbIdx ++ ) {
882912 salt = fakeHashFallbacks [fbIdx ];
883- hashedInput = crypt (input , salt );
913+ hashedInput = WSSHD_CRYPT (input , salt , cryptData );
884914 }
885915 }
886916
@@ -896,10 +926,18 @@ static int CheckPasswordHashUnix(const char* input, const char* stored)
896926 (const byte * )stored , storedSz ) != 0 ) {
897927 ret = WSSHD_AUTH_FAILURE ;
898928 }
899- /* crypt() leaves the result in static storage */
929+ /* the result is in crypt()'s static storage or in cryptData */
900930 WS_FORCEZERO (hashedInput , hashedInputSz );
901931 }
902932 }
933+ #ifdef HAVE_CRYPT_R
934+ if (cryptData != NULL ) {
935+ WS_FORCEZERO (cryptData , sizeof (* cryptData ));
936+ WFREE (cryptData , NULL , DYNTYPE_SSHD );
937+ }
938+ #else
939+ WOLFSSH_UNUSED (cryptData );
940+ #endif
903941 return ret ;
904942}
905943#endif /* WOLFSSH_HAVE_LIBCRYPT || WOLFSSH_HAVE_LIBLOGIN */
0 commit comments