From 64a15de957481e17fc4f555adaa269c01fcd1dc3 Mon Sep 17 00:00:00 2001 From: Colin James Date: Tue, 6 Aug 2024 10:56:54 +0100 Subject: [PATCH] CP-50518: Add stub for crypt_r to ocaml/auth This change adds a binding stub for the crypt_r ("re-entrant crypt") function. The introduced external function is of type: crypt_r : key:string -> salt:string -> string option The arguments are labelled to avoid mixup. In the case of failure, None is returned (no explicit error). Otherwise, the result is Some h, where h is the string containing the computed hash. The usage pattern that most are familiar with is: h = crypt_r(k, s) h' = crypt_r(k', s) equal = h == h' However, the following is also a valid way of expressing the same, and doesn't require extracting the salt (which is embedded in the resultant hash string): h = crypt_r(k, s) h' = crypt_r(k', h) equal = h == h' There is potential for more error handling, but the largest potential for error is in supplying well formed inputs. Different implementations support different errnos, which complicates how accurate any attempt at error reporting would be. The difficulty with over-specifying the requirements of this function at the API level is that different implementations may have different behaviour. To this end, any unit testis exercising this binding will need to explicitly test invariants we expect our specific implementation to have. The precise implementation of the function installed on the host is up to the shared library we link against (which, in practice, I've found to differ in behaviour from what is installed on my host Linux machine). Signed-off-by: Colin James --- ocaml/auth/pam.ml | 3 +++ ocaml/auth/xa_auth_stubs.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ocaml/auth/pam.ml b/ocaml/auth/pam.ml index b2049580b59..a68719d4bf8 100644 --- a/ocaml/auth/pam.ml +++ b/ocaml/auth/pam.ml @@ -15,3 +15,6 @@ external authenticate : string -> string -> unit = "stub_XA_mh_authorize" external change_password : string -> string -> unit = "stub_XA_mh_chpasswd" + +external crypt_r : key:string -> salt:string -> string option + = "stub_XA_crypt_r" diff --git a/ocaml/auth/xa_auth_stubs.c b/ocaml/auth/xa_auth_stubs.c index 6c6c7a5b915..914fdcd8ce6 100644 --- a/ocaml/auth/xa_auth_stubs.c +++ b/ocaml/auth/xa_auth_stubs.c @@ -95,6 +95,25 @@ void __attribute__((constructor)) stub_XA_workaround(void) crypt_r("", "$6$", &data); } +/* key:string -> salt:string -> string option */ +CAMLprim value stub_XA_crypt_r(value key, value salt) { + CAMLparam2(key, salt); + CAMLlocal1(result); + + struct crypt_data cd = {0}; + + caml_enter_blocking_section(); + const char* const hashed = + crypt_r(String_val(key), String_val(salt), &cd); + caml_leave_blocking_section(); + + if (!hashed || *hashed == '*') + CAMLreturn(Val_none); + + result = caml_copy_string(hashed); + CAMLreturn(caml_alloc_some(result)); +} + /* * Local variables: * mode: C