diff --git a/ocaml/auth/dune b/ocaml/auth/dune index 8d6774ab817..f963fbb591b 100644 --- a/ocaml/auth/dune +++ b/ocaml/auth/dune @@ -4,7 +4,7 @@ (names xa_auth xa_auth_stubs) ) (name pam) - (c_library_flags -lpam) + (c_library_flags -lpam -lcrypt) (wrapped false) ) diff --git a/ocaml/auth/xa_auth_stubs.c b/ocaml/auth/xa_auth_stubs.c index 78dfb131eaf..6c6c7a5b915 100644 --- a/ocaml/auth/xa_auth_stubs.c +++ b/ocaml/auth/xa_auth_stubs.c @@ -11,8 +11,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. */ -/* - */ + +/* must be at the beginning, it affects defines in other headers that cannot be reenabled later */ +#define _GNU_SOURCE #include #include @@ -70,6 +71,30 @@ CAMLprim value stub_XA_mh_chpasswd(value username, value new_password){ CAMLreturn(ret); } +#include +/* 'constructor' attribute will ensure this function gets call early during program startup. */ +void __attribute__((constructor)) stub_XA_workaround(void) +{ + struct crypt_data data; + memset(&data, 0, sizeof(data)); + + /* Initialize and load crypt library used for password hashing. + This library is loaded and initialized at [pam_authenticate] time and not at [pam_start]. + If it detects a race condition (multiple threads with their own PAM contexts trying to call 'crypt_r'), + then it does [sleep 1] as can be seen in this call trace: + [pam_authenticate -> crypt_r -> __sha512_crypt_r -> freebl_InitVector -> freebl_RunLoaderOnce -> sleep]. + + As a workaround link with 'libcrypt' and call 'crypt_r' with a setting that will make it take tha sha512 route + to ensure that the library gets initialized while we're still single-threaded and stays loaded and initialized. + + '$6$' is the setting for sha512 according to crypt(5). + + Upstream has switched to using libxcrypt instead which doesn't have these problems, when we switch then + this workaround can be dropped. + */ + crypt_r("", "$6$", &data); +} + /* * Local variables: * mode: C