From 47751548b28e6d8492b8be9d164325d45b9335ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Fri, 4 Dec 2020 21:47:49 +0100 Subject: [PATCH] pam_fprintd: Ignore any verify signal if we didn't complete VerifyStart In case fprintd is emitting a verify signal for another request that is still going on while we're about to start a new verification, we'd just accept such signal, so potentially allowing a log-in because another concurrent request succeeded. To avoid this, use async call to VerifyStart and open a verify window (during which we accept the verification related signals) that is kept open just once the VerifyStart call has been completed and before stopping the verification again. As that's the only moment in which we can be sure that we've control of the daemon events for such device. Thanks to Benjamin to find out the race. Fixes: #47 --- pam/pam_fprintd.c | 83 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 16 deletions(-) diff --git a/pam/pam_fprintd.c b/pam/pam_fprintd.c index eb43c34..036e2f5 100644 --- a/pam/pam_fprintd.c +++ b/pam/pam_fprintd.c @@ -164,6 +164,8 @@ typedef struct { char *result; bool timed_out; bool is_swipe; + bool verify_started; + int verify_ret; pam_handle_t *pamh; char *driver; @@ -193,6 +195,11 @@ verify_result (sd_bus_message *m, return 0; } + if (!data->verify_started) { + pam_syslog (data->pamh, LOG_ERR, "Unexpected VerifyResult '%s', %"PRIu64" signal", result, done); + return 0; + } + if (debug) pam_syslog (data->pamh, LOG_DEBUG, "Verify result: %s (done: %d)", result, done ? 1 : 0); @@ -225,6 +232,11 @@ verify_finger_selected (sd_bus_message *m, return 0; } + if (!data->verify_started) { + pam_syslog (data->pamh, LOG_ERR, "Unexpected VerifyFingerSelected %s signal", finger_name); + return 0; + } + msg = finger_str_to_msg(finger_name, data->driver, data->is_swipe); if (debug) pam_syslog (data->pamh, LOG_DEBUG, "verify_finger_selected %s", msg); @@ -278,6 +290,35 @@ fail: return sd_bus_error_set_errno(error, r); } + +static int verify_started_cb (sd_bus_message *m, + void *userdata, + sd_bus_error *ret_error) { + const sd_bus_error *error = sd_bus_message_get_error (m); + verify_data *data = userdata; + + if (error) { + if (sd_bus_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints")) { + pam_syslog (data->pamh, LOG_DEBUG, "No prints enrolled"); + data->verify_ret = PAM_USER_UNKNOWN; + } else { + data->verify_ret = PAM_AUTH_ERR; + } + + if (debug) + pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart failed: %s", error->message); + + return 1; + } + + if (debug) + pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart completed successfully"); + + data->verify_started = true; + + return 1; +} + static int do_verify (pam_handle_t *pamh, sd_bus *bus, @@ -348,28 +389,28 @@ do_verify (pam_handle_t *pamh, while (ret == PAM_AUTH_ERR && data->max_tries > 0) { uint64_t verification_end = now () + (timeout * USEC_PER_SEC); - sd_bus_message *m = NULL; - sd_bus_error error = SD_BUS_ERROR_NULL; data->timed_out = false; + data->verify_started = false; + data->verify_ret = PAM_INCOMPLETE; - r = sd_bus_call_method (bus, - "net.reactivated.Fprint", - dev, - "net.reactivated.Fprint.Device", - "VerifyStart", - &error, - &m, - "s", - "any"); + if (debug) + pam_syslog (data->pamh, LOG_DEBUG, "About to call VerifyStart"); + + r = sd_bus_call_method_async (bus, + NULL, + "net.reactivated.Fprint", + dev, + "net.reactivated.Fprint.Device", + "VerifyStart", + verify_started_cb, + data, + "s", + "any"); if (r < 0) { - if (sd_bus_error_has_name (&error, "net.reactivated.Fprint.Error.NoEnrolledPrints")) - ret = PAM_USER_UNKNOWN; - if (debug) - pam_syslog (pamh, LOG_DEBUG, "VerifyStart failed: %s", error.message); - sd_bus_error_free (&error); + pam_syslog (pamh, LOG_DEBUG, "VerifyStart call failed: %d", r); break; } @@ -383,6 +424,10 @@ do_verify (pam_handle_t *pamh, r = sd_bus_process (bus, NULL); if (r < 0) break; + if (data->verify_ret != PAM_INCOMPLETE) + break; + if (!data->verify_started) + continue; if (data->result != NULL) break; if (r == 0) { @@ -397,12 +442,18 @@ do_verify (pam_handle_t *pamh, } } + if (data->verify_ret != PAM_INCOMPLETE) { + ret = data->verify_ret; + break; + } + if (now () >= verification_end) { data->timed_out = true; send_info_msg (data->pamh, _("Verification timed out")); } /* Ignore errors from VerifyStop */ + data->verify_started = false; sd_bus_call_method (bus, "net.reactivated.Fprint", dev,