mirror of
https://gitlab.com/mishakmak/pam-fprint-grosshack.git
synced 2026-04-08 20:03:34 +02:00
utils: Fix race in verify accepting unrelated signals
Signals like VerifyResult may be received from unrelated Verify operations. To avoid races, we need to ignore any VerifyResult that happenes before the DBus method returns. The only way to do this race-free is to use the async version of the VerifyStart method.
This commit is contained in:
@ -62,6 +62,7 @@ common_cflags = cc.get_supported_arguments([
|
|||||||
add_project_arguments(common_cflags, language: 'c')
|
add_project_arguments(common_cflags, language: 'c')
|
||||||
|
|
||||||
host_system = host_machine.system()
|
host_system = host_machine.system()
|
||||||
|
# NOTE: Bump gdbus-codegen min version once we can depend on 2.64!
|
||||||
glib_min_version = '2.56'
|
glib_min_version = '2.56'
|
||||||
libfprint_min_version = '1.90.1'
|
libfprint_min_version = '1.90.1'
|
||||||
|
|
||||||
|
|||||||
@ -120,12 +120,18 @@ static void find_finger (FprintDBusDevice *dev, const char *username)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VerifyState {
|
||||||
|
GError *error;
|
||||||
|
gboolean started;
|
||||||
|
gboolean completed;
|
||||||
|
};
|
||||||
|
|
||||||
static void verify_result(GObject *object, const char *result, gboolean done, void *user_data)
|
static void verify_result(GObject *object, const char *result, gboolean done, void *user_data)
|
||||||
{
|
{
|
||||||
gboolean *verify_completed = user_data;
|
struct VerifyState *verify_state = user_data;
|
||||||
g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done");
|
g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done");
|
||||||
if (done != FALSE)
|
if (done != FALSE)
|
||||||
*verify_completed = TRUE;
|
verify_state->completed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_finger_selected(GObject *object, const char *name, void *user_data)
|
static void verify_finger_selected(GObject *object, const char *name, void *user_data)
|
||||||
@ -133,12 +139,27 @@ static void verify_finger_selected(GObject *object, const char *name, void *user
|
|||||||
g_print("Verifying: %s\n", name);
|
g_print("Verifying: %s\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void verify_started_cb (GObject *obj,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct VerifyState *verify_state = user_data;
|
||||||
|
|
||||||
|
if (fprint_dbus_device_call_verify_start_finish (FPRINT_DBUS_DEVICE (obj), res, &verify_state->error))
|
||||||
|
verify_state->started = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void proxy_signal_cb (GDBusProxy *proxy,
|
static void proxy_signal_cb (GDBusProxy *proxy,
|
||||||
const gchar *sender_name,
|
const gchar *sender_name,
|
||||||
const gchar *signal_name,
|
const gchar *signal_name,
|
||||||
GVariant *parameters,
|
GVariant *parameters,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
|
struct VerifyState *verify_state = user_data;
|
||||||
|
|
||||||
|
if (!verify_state->started)
|
||||||
|
return;
|
||||||
|
|
||||||
if (g_str_equal (signal_name, "VerifyStatus")) {
|
if (g_str_equal (signal_name, "VerifyStatus")) {
|
||||||
const gchar *result;
|
const gchar *result;
|
||||||
gboolean done;
|
gboolean done;
|
||||||
@ -156,23 +177,43 @@ static void proxy_signal_cb (GDBusProxy *proxy,
|
|||||||
static void do_verify (FprintDBusDevice *dev)
|
static void do_verify (FprintDBusDevice *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
gboolean verify_completed = FALSE;
|
struct VerifyState verify_state = { 0 };
|
||||||
|
|
||||||
|
/* This one is funny. We connect to the signal immediately to avoid
|
||||||
|
* race conditions. However, we must ignore any authentication results
|
||||||
|
* that happen before our start call returns.
|
||||||
|
* This is because the verify call itself may internally try to verify
|
||||||
|
* against fprintd (possibly using a separate account).
|
||||||
|
*
|
||||||
|
* To do so, we *must* use the async version of the verify call, as the
|
||||||
|
* sync version would cause the signals to be queued and only processed
|
||||||
|
* after it returns.
|
||||||
|
*/
|
||||||
|
|
||||||
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
|
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
|
||||||
&verify_completed);
|
&verify_state);
|
||||||
|
|
||||||
if (!fprint_dbus_device_call_verify_start_sync (dev, finger_name, NULL,
|
fprint_dbus_device_call_verify_start (dev, finger_name, NULL,
|
||||||
&error)) {
|
verify_started_cb,
|
||||||
g_print("VerifyStart failed: %s\n", error->message);
|
&verify_state);
|
||||||
|
|
||||||
|
/* Wait for verify start while discarding any VerifyStatus signals */
|
||||||
|
while (!verify_state.started && !verify_state.error)
|
||||||
|
g_main_context_iteration(NULL, TRUE);
|
||||||
|
|
||||||
|
if (verify_state.error) {
|
||||||
|
g_print("VerifyStart failed: %s\n", verify_state.error->message);
|
||||||
|
g_clear_error (&verify_state.error);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!verify_completed)
|
/* VerifyStatus signals are processing, wait for completion. */
|
||||||
|
while (!verify_state.completed)
|
||||||
g_main_context_iteration(NULL, TRUE);
|
g_main_context_iteration(NULL, TRUE);
|
||||||
|
|
||||||
|
|
||||||
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb,
|
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb,
|
||||||
&verify_completed);
|
&verify_state);
|
||||||
|
|
||||||
if (!fprint_dbus_device_call_verify_stop_sync (dev, NULL, &error)) {
|
if (!fprint_dbus_device_call_verify_stop_sync (dev, NULL, &error)) {
|
||||||
g_print("VerifyStop failed: %s\n", error->message);
|
g_print("VerifyStop failed: %s\n", error->message);
|
||||||
|
|||||||
Reference in New Issue
Block a user