Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package fprintd for openSUSE:Factory checked in at 2021-01-18 11:28:34 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fprintd (Old) and /work/SRC/openSUSE:Factory/.fprintd.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fprintd" Mon Jan 18 11:28:34 2021 rev:13 rq:863644 version:1.90.9 Changes: -------- --- /work/SRC/openSUSE:Factory/fprintd/fprintd.changes 2020-12-21 10:27:03.232227251 +0100 +++ /work/SRC/openSUSE:Factory/.fprintd.new.28504/fprintd.changes 2021-01-18 11:32:24.888688164 +0100 @@ -1,0 +2,8 @@ +Fri Jan 15 19:42:37 UTC 2021 - Martin Hauke <[email protected]> + +- Update to version 1.90.9 + * Fix multiple daemon lockup issues (#97) + * Fix print garbage collection to not delete used prints + * pam: Use the device with the most prints + +------------------------------------------------------------------- Old: ---- fprintd-1.90.8.tar.bz2 New: ---- fprintd-1.90.9.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fprintd.spec ++++++ --- /var/tmp/diff_new_pack.1xDsYM/_old 2021-01-18 11:32:25.480688748 +0100 +++ /var/tmp/diff_new_pack.1xDsYM/_new 2021-01-18 11:32:25.480688748 +0100 @@ -1,7 +1,7 @@ # # spec file for package fprintd # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -16,10 +16,10 @@ # -%define gitlabhash 7d22a2b5b9d323638bb213aefb8627d897c8e482 +%define gitlabhash da60bddb3e5be024c6c1958437cb13e0ce0ffac8 Name: fprintd -Version: 1.90.8 +Version: 1.90.9 Release: 0 Summary: D-Bus service for Fingerprint reader access License: GPL-2.0-or-later ++++++ fprintd-1.90.8.tar.bz2 -> fprintd-1.90.9.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/NEWS new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/NEWS --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/NEWS 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/NEWS 2021-01-13 13:23:24.000000000 +0100 @@ -1,6 +1,14 @@ This file lists notable changes in each release. For the full history of all changes, see ChangeLog. +Version 1.90.9: + +Highlights: + - Fix multiple daemon lockup issues (#97) + - Fix print garbage collection to not delete used prints + - pam: Use the device with the most prints + + Version 1.90.8: It seems that we are finally reaching the end of the tunnel with regard diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/meson.build new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/meson.build --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/meson.build 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/meson.build 2021-01-13 13:23:24.000000000 +0100 @@ -1,5 +1,5 @@ project('fprintd', 'c', - version: '1.90.8', + version: '1.90.9', license: 'GPLv2+', default_options: [ 'buildtype=debugoptimized', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/pam/pam_fprintd.c new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/pam/pam_fprintd.c --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/pam/pam_fprintd.c 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/pam/pam_fprintd.c 2021-01-13 13:23:24.000000000 +0100 @@ -60,6 +60,11 @@ #define USEC_PER_SEC ((uint64_t) 1000000ULL) #define NSEC_PER_USEC ((uint64_t) 1000ULL) +static size_t user_enrolled_prints_num (pam_handle_t *pamh, + sd_bus *bus, + const char *dev, + const char *username); + static uint64_t now (void) { @@ -112,11 +117,13 @@ static char * open_device (pam_handle_t *pamh, sd_bus *bus, + const char *username, bool *has_multiple_devices) { pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL; pf_autoptr (sd_bus_message) m = NULL; size_t num_devices; + size_t max_prints; const char *path = NULL; const char *s; int r; @@ -143,12 +150,23 @@ return NULL; } - if (sd_bus_message_read_basic (m, 'o', &path) < 0) - return NULL; - - num_devices = 1; + num_devices = 0; + max_prints = 0; while ((r = sd_bus_message_read_basic (m, 'o', &s)) > 0) - num_devices++; + { + size_t enrolled_prints = user_enrolled_prints_num (pamh, bus, s, username); + + if (debug) + pam_syslog (pamh, LOG_DEBUG, "%s prints registered: %" PRIu64, s, enrolled_prints); + + if (enrolled_prints > max_prints) + { + max_prints = enrolled_prints; + path = s; + } + + num_devices++; + } *has_multiple_devices = (num_devices > 1); if (debug) pam_syslog (pamh, LOG_DEBUG, "Using device %s (out of %ld devices)", path, num_devices); @@ -528,11 +546,11 @@ return PAM_AUTH_ERR; } -static bool -user_has_prints (pam_handle_t *pamh, - sd_bus *bus, - const char *dev, - const char *username) +static size_t +user_enrolled_prints_num (pam_handle_t *pamh, + sd_bus *bus, + const char *dev, + const char *username) { pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL; pf_autoptr (sd_bus_message) m = NULL; @@ -557,21 +575,21 @@ if (debug) pam_syslog (pamh, LOG_DEBUG, "ListEnrolledFingers failed for %s: %s", username, error.message); - return false; + return 0; } r = sd_bus_message_enter_container (m, 'a', "s"); if (r < 0) { pam_syslog (pamh, LOG_ERR, "Failed to parse answer from ListEnrolledFingers(): %d", r); - return false; + return 0; } while ((r = sd_bus_message_read_basic (m, 's', &s)) > 0) num_fingers++; sd_bus_message_exit_container (m); - return num_fingers > 0; + return num_fingers; } static void @@ -651,8 +669,6 @@ static int do_auth (pam_handle_t *pamh, const char *username) { - bool have_prints; - pf_autoptr (verify_data) data = NULL; pf_autoptr (sd_bus) bus = NULL; pf_autoptr (sd_bus_slot) name_owner_changed_slot = NULL; @@ -667,17 +683,10 @@ return PAM_AUTHINFO_UNAVAIL; } - data->dev = open_device (pamh, bus, &data->has_multiple_devices); + data->dev = open_device (pamh, bus, username, &data->has_multiple_devices); if (data->dev == NULL) return PAM_AUTHINFO_UNAVAIL; - have_prints = user_has_prints (pamh, bus, data->dev, username); - if (debug) - pam_syslog (pamh, LOG_DEBUG, "prints registered: %s\n", have_prints ? "yes" : "no"); - - if (!have_prints) - return PAM_AUTHINFO_UNAVAIL; - /* Only connect to NameOwnerChanged when needed. In case of automatic startup * we rely on the fact that we never see those signals. */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/device.c new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/device.c --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/device.c 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/device.c 2021-01-13 13:23:24.000000000 +0100 @@ -210,6 +210,16 @@ return new; } +typedef FprintDevice FprintDeviceActionUnset; +static void +auto_device_action_unset (FprintDeviceActionUnset *self) +{ + FprintDevicePrivate *priv = fprint_device_get_instance_private (self); + + priv->current_action = ACTION_NONE; +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FprintDeviceActionUnset, auto_device_action_unset); + static void fprint_device_dispose (GObject *object) { @@ -739,7 +749,7 @@ if (!ret) { g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL, - "Could not get conection unix user ID: %s", + "Could not get connection unix user ID: %s", local_error->message); return NULL; } @@ -784,15 +794,30 @@ if (session != NULL && g_strcmp0 (session->sender, name) == 0) { - while (priv->current_action != ACTION_NONE) + g_cancellable_cancel (priv->current_cancellable); + + if (!priv->current_cancellable) { - /* OPEN/CLOSE are not cancellable, we just need to wait */ - if (priv->current_cancellable) - g_cancellable_cancel (priv->current_cancellable); + /* This isn't optimal, but for verify/identify/enroll we expect the stop + * command. And we use current_cancellable as a flag to know that the + * underlying operation has finished already. + * If it has finished, unset the current_action. */ + switch (priv->current_action) + { + case ACTION_VERIFY: + case ACTION_IDENTIFY: + case ACTION_ENROLL: + priv->current_action = ACTION_NONE; + break; - g_main_context_iteration (NULL, TRUE); + default: + break; + } } + while (priv->current_action != ACTION_NONE) + g_main_context_iteration (NULL, TRUE); + /* The session may have disappeared at this point if the device * was already closing. */ g_clear_pointer (&session, session_data_unref); @@ -838,11 +863,12 @@ g_autoptr(SessionData) session = NULL; g_autoptr(GDBusMethodInvocation) invocation = NULL; + g_autoptr(FprintDeviceActionUnset) action_unset = NULL; + action_unset = rdev; session = session_data_get (priv); invocation = g_steal_pointer (&session->invocation); - priv->current_action = ACTION_NONE; if (!fp_device_open_finish (dev, res, &error)) { g_autoptr(GError) dbus_error = NULL; @@ -939,12 +965,13 @@ g_autoptr(SessionData) session = NULL; g_autoptr(GDBusMethodInvocation) invocation = NULL; + g_autoptr(FprintDeviceActionUnset) action_unset = NULL; session = session_data_get (priv); session_data_set_new (priv, NULL, NULL); invocation = g_steal_pointer (&session->invocation); + action_unset = rdev; - priv->current_action = ACTION_NONE; if (!fp_device_close_finish (dev, res, &error)) { g_autoptr(GError) dbus_error = NULL; @@ -1052,7 +1079,7 @@ case ACTION_VERIFY: g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE, - "Enrollment already in progress"); + "Verification already in progress"); break; case ACTION_OPEN: @@ -1084,6 +1111,47 @@ } static void +stoppable_action_completed (FprintDevice *rdev) +{ + g_autoptr(SessionData) session = NULL; + FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev); + FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev); + + session = session_data_get (priv); + + /* Return the cancellation or reset action right away if vanished. */ + if (priv->current_cancel_invocation) + { + switch (priv->current_action) + { + case ACTION_VERIFY: + case ACTION_IDENTIFY: + fprint_dbus_device_complete_verify_stop (dbus_dev, + g_steal_pointer (&priv->current_cancel_invocation)); + break; + + case ACTION_ENROLL: + fprint_dbus_device_complete_enroll_stop (dbus_dev, + g_steal_pointer (&priv->current_cancel_invocation)); + break; + + default: + g_assert_not_reached (); + } + + priv->current_action = ACTION_NONE; + session->verify_status_reported = FALSE; + } + else if (g_cancellable_is_cancelled (priv->current_cancellable)) + { + priv->current_action = ACTION_NONE; + session->verify_status_reported = FALSE; + } + + g_clear_object (&priv->current_cancellable); +} + +static void match_cb (FpDevice *device, FpPrint *match, FpPrint *print, @@ -1109,10 +1177,8 @@ verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data) { g_autoptr(GError) error = NULL; - g_autoptr(SessionData) session = NULL; FprintDevice *rdev = user_data; FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev); - FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev); gboolean success; const char *name; gboolean match; @@ -1121,8 +1187,6 @@ g_assert (!!success == !error); name = verify_result_to_name (match, error); - session = session_data_get (priv); - g_debug ("verify_cb: result %s", name); /* Automatically restart the operation for retry failures */ @@ -1148,21 +1212,7 @@ error->message); } - /* Return the cancellation or reset action right away if vanished. */ - if (priv->current_cancel_invocation) - { - fprint_dbus_device_complete_verify_stop (dbus_dev, - g_steal_pointer (&priv->current_cancel_invocation)); - priv->current_action = ACTION_NONE; - session->verify_status_reported = FALSE; - } - else if (g_cancellable_is_cancelled (priv->current_cancellable)) - { - priv->current_action = ACTION_NONE; - session->verify_status_reported = FALSE; - } - - g_clear_object (&priv->current_cancellable); + stoppable_action_completed (rdev); } } @@ -1173,7 +1223,6 @@ g_autoptr(FpPrint) match = NULL; FprintDevice *rdev = user_data; FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev); - FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev); const char *name; gboolean success; @@ -1206,22 +1255,7 @@ error->message); } - /* Return the cancellation or reset action right away if vanished. */ - if (priv->current_cancel_invocation) - { - fprint_dbus_device_complete_verify_stop (dbus_dev, - g_steal_pointer (&priv->current_cancel_invocation)); - priv->current_action = ACTION_NONE; - } - else if (g_cancellable_is_cancelled (priv->current_cancellable)) - { - g_autoptr(SessionData) session = NULL; - session = session_data_get (priv); - priv->current_action = ACTION_NONE; - session->verify_status_reported = FALSE; - } - - g_clear_object (&priv->current_cancellable); + stoppable_action_completed (rdev); } } @@ -1444,7 +1478,7 @@ guint index; store.print_data_load (priv->dev, - GPOINTER_TO_UINT (fingers->data), + GPOINTER_TO_UINT (finger->data), username, &print); @@ -1518,7 +1552,6 @@ g_autoptr(GError) error = NULL; FprintDevice *rdev = user_data; FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev); - FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev); g_autoptr(FpPrint) print = NULL; const char *name; @@ -1566,18 +1599,7 @@ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) g_warning ("Device reported an error during enroll: %s", error->message); - /* Return the cancellation or reset action right away if vanished. */ - if (priv->current_cancel_invocation) - { - fprint_dbus_device_complete_enroll_stop (dbus_dev, - g_steal_pointer (&priv->current_cancel_invocation)); - priv->current_action = ACTION_NONE; - } - else if (g_cancellable_is_cancelled (priv->current_cancellable)) - { - priv->current_action = ACTION_NONE; - } - g_clear_object (&priv->current_cancellable); + stoppable_action_completed (rdev); } @@ -1822,6 +1844,7 @@ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev); FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev); + g_autoptr(FprintDeviceActionUnset) action_unset = NULL; g_autoptr(GError) error = NULL; g_autofree char *user = NULL; const char *sender; @@ -1839,6 +1862,7 @@ } priv->current_action = ACTION_DELETE; + action_unset = rdev; if (!_fprint_device_check_claimed (rdev, invocation, &error)) { @@ -1872,8 +1896,6 @@ if (!opened && fp_device_has_storage (priv->dev)) fp_device_close_sync (priv->dev, NULL, NULL); - priv->current_action = ACTION_NONE; - fprint_dbus_device_complete_delete_enrolled_fingers (dbus_dev, invocation); return TRUE; @@ -1888,6 +1910,7 @@ g_autoptr(SessionData) session = NULL; g_autoptr(GError) error = NULL; + g_autoptr(FprintDeviceActionUnset) action_unset = NULL; if (!_fprint_device_check_claimed (rdev, invocation, &error)) { @@ -1902,13 +1925,12 @@ } priv->current_action = ACTION_DELETE; + action_unset = rdev; session = session_data_get (priv); delete_enrolled_fingers (rdev, session->username); - priv->current_action = ACTION_NONE; - fprint_dbus_device_complete_delete_enrolled_fingers2 (dbus_dev, invocation); return TRUE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/file_storage.c new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/file_storage.c --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/file_storage.c 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/file_storage.c 2021-01-13 13:23:24.000000000 +0100 @@ -66,6 +66,10 @@ elems = g_strsplit (path, ":", -1); storage_path = g_strdup (elems[0]); } + else if (*path) + { + storage_path = g_strdup (path); + } } if (storage_path == NULL) @@ -151,7 +155,6 @@ return r; } - //fp_dbg("saving to %s", path); g_file_set_contents (path, buf, len, &err); if (err) { @@ -161,6 +164,8 @@ return err->code; } + g_debug ("file_storage_print_data_save(): print saved to %s", path); + return 0; } @@ -172,7 +177,6 @@ g_autofree char *contents = NULL; FpPrint *new; - //fp_dbg("from %s", path); g_file_get_contents (path, &contents, &length, &err); if (err) { @@ -226,6 +230,7 @@ int file_storage_print_data_delete (FpDevice *dev, FpFinger finger, const char *username) { + g_autoptr(GSList) prints = NULL; g_autofree gchar *base_store = NULL; g_autofree gchar *path = NULL; int r; @@ -234,12 +239,27 @@ path = get_path_to_print_dscv (dev, finger, base_store); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + return 0; + r = g_unlink (path); g_debug ("file_storage_print_data_delete(): unlink(\"%s\") %s", path, g_strerror (r)); - /* FIXME: cleanup empty directory */ - return g_unlink (path); + prints = file_storage_discover_prints (dev, username); + if (!prints) + { + g_autofree char *dir = g_steal_pointer (&path); + + do + { + g_autofree char *tmp = g_steal_pointer (&dir); + dir = g_path_get_dirname (tmp); + } + while (g_str_has_prefix (dir, base_store) && g_rmdir (dir) == 0); + } + + return r; } static GSList * diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/fprintd.h new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/fprintd.h --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/fprintd.h 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/fprintd.h 2021-01-13 13:23:24.000000000 +0100 @@ -55,7 +55,7 @@ /* Enum of possible permissions, orders and nick matter here: - The order controls the priority of a required permission when various are - accepted: the lowest the value, the more priorty it has. + accepted: the lowest the value, the more priority it has. - Nick must match the relative polkit rule. */ typedef enum { @@ -91,3 +91,18 @@ guint32 _fprint_device_get_id (FprintDevice *rdev); /* Print */ /* TODO */ + + +/* Some compatibility definitions for older GLib. Copied from from libfprint. */ +#if !GLIB_CHECK_VERSION (2, 57, 0) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref); +G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref); +#else +/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with + * the version we depend on currently. */ +#undef G_SOURCE_FUNC +#endif + +#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/manager.c new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/manager.c --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/src/manager.c 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/src/manager.c 2021-01-13 13:23:24.000000000 +0100 @@ -432,7 +432,7 @@ GQuark fprint_error_quark (void) { - static volatile gsize quark = 0; + static gsize quark = 0; if (g_once_init_enter (&quark)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/tests/fprintd.py new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/tests/fprintd.py --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/tests/fprintd.py 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/tests/fprintd.py 2021-01-13 13:23:24.000000000 +0100 @@ -296,24 +296,36 @@ '.*net\.reactivated\.Fprint\.Error\.{}.*'.format(fprint_error)) # From libfprint tests - def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT): - with Connection(self.sockaddr) as con: + def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT, con=None): + if con: con.sendall(struct.pack('ii', -1, retry_error)) + return - # From libfprint tests - def send_error(self, error=FPrint.DeviceError.GENERAL): with Connection(self.sockaddr) as con: - con.sendall(struct.pack('ii', -2, error)) + self.send_retry(retry_error, con) # From libfprint tests - def send_remove(self): + def send_error(self, error=FPrint.DeviceError.GENERAL, con=None): + if con: + con.sendall(struct.pack('ii', -2, error)) + return + with Connection(self.sockaddr) as con: - con.sendall(struct.pack('ii', -5, 0)) + self.send_error(error, con) # From libfprint tests - def send_image(self, image): - img = self.prints[image] + def send_remove(self, con=None): + if con: + con.sendall(struct.pack('ii', -5, 0)) + return + with Connection(self.sockaddr) as con: + self.send_remove(con=con) + + # From libfprint tests + def send_image(self, image, con=None): + if con: + img = self.prints[image] mem = img.get_data() mem = mem.tobytes() self.assertEqual(len(mem), img.get_width() * img.get_height()) @@ -322,6 +334,28 @@ encoded_img += mem con.sendall(encoded_img) + return + + with Connection(self.sockaddr) as con: + self.send_image(image, con) + + def send_finger_automatic(self, automatic, con=None): + # Set whether finger on/off is reported around images + if con: + con.sendall(struct.pack('ii', -3, 1 if automatic else 0)) + return + + with Connection(self.sockaddr) as con: + self.send_finger_automatic(automatic, con=con) + + def send_finger_report(self, has_finger, con=None): + # Send finger on/off + if con: + con.sendall(struct.pack('ii', -4, 1 if has_finger else 0)) + return + + with Connection(self.sockaddr) as con: + self.send_finger_report(has_finger, con=con) def call_device_method_async(self, method, *args): """ add cancellable... """ @@ -429,10 +463,12 @@ if expected is not None: self.assertEqual(self._last_result, expected) - def enroll_image(self, img, finger='right-index-finger', expected_result='enroll-completed'): - self.device.EnrollStart('(s)', finger) + def enroll_image(self, img, device=None, finger='right-index-finger', expected_result='enroll-completed'): + if device is None: + device = self.device + device.EnrollStart('(s)', finger) - stages = self.device.get_cached_property('num-enroll-stages').unpack() + stages = device.get_cached_property('num-enroll-stages').unpack() for stage in range(stages): self.send_image(img) if stage < stages - 1: @@ -440,7 +476,7 @@ else: self.wait_for_result(expected_result) - self.device.EnrollStop() + device.EnrollStop() self.assertEqual(self._last_result, expected_result) def enroll_multiple_images(self, images_override={}, return_index=-1): @@ -462,6 +498,29 @@ return (enrolled, enroll_map) + def get_secondary_bus_and_device(self, claim=None): + addr = os.environ['DBUS_SYSTEM_BUS_ADDRESS'] + + # Get a separate bus connection + bus = Gio.DBusConnection.new_for_address_sync(addr, + Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION | + Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT, None, None) + assert bus.is_closed() == False + + dev_path = self.device.get_object_path() + dev = Gio.DBusProxy.new_sync(bus, + Gio.DBusProxyFlags.DO_NOT_AUTO_START, + None, + 'net.reactivated.Fprint', + dev_path, + 'net.reactivated.Fprint.Device', + None) + + if claim is not None: + dev.Claim('(s)', claim) + + return bus, dev + class FPrintdManagerTests(FPrintdVirtualDeviceBaseTest): @@ -700,23 +759,7 @@ self.device.Release() def test_claim_disconnect(self): - addr = os.environ['DBUS_SYSTEM_BUS_ADDRESS'] - - # Get a separat bus connection - dbus = Gio.DBusConnection.new_for_address_sync(addr, - Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION | - Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT, None, None) - assert dbus.is_closed() == False - - - dev_path = self.device.get_object_path() - dev = Gio.DBusProxy.new_sync(dbus, - Gio.DBusProxyFlags.DO_NOT_AUTO_START, - None, - 'net.reactivated.Fprint', - dev_path, - 'net.reactivated.Fprint.Device', - None) + bus, dev = self.get_secondary_bus_and_device() def call_done(obj, result, user_data): # Ignore the callback (should be an error) @@ -726,8 +769,91 @@ dev.Claim('(s)', 'testuser', result_handler=call_done) # Ensure the call is on the wire, then close immediately - dbus.flush_sync() - dbus.close_sync() + bus.flush_sync() + bus.close_sync() + + time.sleep(1) + + def test_enroll_running_disconnect(self): + bus, dev = self.get_secondary_bus_and_device(claim='testuser') + + # Start an enroll and disconnect, without finishing/cancelling + dev.EnrollStart('(s)', 'left-index-finger') + + # Ensure the call is on the wire, then close immediately + bus.flush_sync() + bus.close_sync() + + time.sleep(1) + + def test_enroll_done_disconnect(self): + bus, dev = self.get_secondary_bus_and_device(claim='testuser') + + # Start an enroll and disconnect, without finishing/cancelling + dev.EnrollStart('(s)', 'left-index-finger') + + # This works because we also receive the signals on the main connection + stages = dev.get_cached_property('num-enroll-stages').unpack() + for stage in range(stages): + self.send_image('whorl') + if stage < stages - 1: + self.wait_for_result('enroll-stage-passed') + else: + self.wait_for_result('enroll-completed') + + bus.close_sync() + + time.sleep(1) + + def test_verify_running_disconnect(self): + bus, dev = self.get_secondary_bus_and_device(claim='testuser') + self.enroll_image('whorl', device=dev) + + # Start an enroll and disconnect, without finishing/cancelling + dev.VerifyStart('(s)', 'right-index-finger') + + bus.close_sync() + + time.sleep(1) + + def test_verify_done_disconnect(self): + bus, dev = self.get_secondary_bus_and_device(claim='testuser') + self.enroll_image('whorl', device=dev) + + # Start an enroll and disconnect, without finishing/cancelling + dev.VerifyStart('(s)', 'right-index-finger') + self.send_image('whorl') + # Wait for match and sleep a bit to give fprintd time to wrap up + self.wait_for_result('verify-match') + time.sleep(1) + + bus.close_sync() + + time.sleep(1) + + def test_identify_running_disconnect(self): + bus, dev = self.get_secondary_bus_and_device(claim='testuser') + self.enroll_image('whorl', device=dev) + + # Start an enroll and disconnect, without finishing/cancelling + dev.VerifyStart('(s)', 'any') + + bus.close_sync() + + time.sleep(1) + + def test_identify_done_disconnect(self): + bus, dev = self.get_secondary_bus_and_device(claim='testuser') + self.enroll_image('whorl', device=dev) + + # Start an enroll and disconnect, without finishing/cancelling + dev.VerifyStart('(s)', 'any') + self.send_image('whorl') + # Wait for match and sleep a bit to give fprintd time to wrap up + self.wait_for_result('verify-match') + time.sleep(1) + + bus.close_sync() time.sleep(1) @@ -843,9 +969,11 @@ self.device.DeleteEnrolledFingers2() self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7'))) + self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser'))) + self.assertTrue(os.path.exists(self.state_dir)) def test_enroll_invalid_storage_dir(self): - # Directory wil not exist yet + # Directory will not exist yet os.makedirs(self.state_dir, mode=0o500) self.addCleanup(os.chmod, self.state_dir, mode=0o700) @@ -1214,6 +1342,12 @@ def test_verify_retry_general(self): self.assertVerifyRetry(FPrint.DeviceRetry.GENERAL, 'verify-retry-scan') + def test_verify_retry_general_restarted(self): + self.assertVerifyRetry(FPrint.DeviceRetry.GENERAL, 'verify-retry-scan') + # Give fprintd time to re-start the request. We can't force the other + # case (cancellation before restart happened), but we can force this one. + time.sleep(1) + def test_verify_retry_too_short(self): self.assertVerifyRetry(FPrint.DeviceRetry.TOO_SHORT, 'verify-swipe-too-short') @@ -1250,6 +1384,38 @@ def test_verify_error_data_full(self): self.assertVerifyError(FPrint.DeviceError.DATA_FULL, 'verify-unknown-error') + def test_multiple_verify(self): + self.send_image('tented_arch') + self.wait_for_result() + self.assertTrue(self._verify_stopped) + self.assertEqual(self._last_result, 'verify-no-match') + self.device.VerifyStop() + + self.device.VerifyStart('(s)', self.verify_finger) + self.send_image('whorl') + self.wait_for_result() + self.assertTrue(self._verify_stopped) + self.assertEqual(self._last_result, 'verify-match') + + def test_multiple_verify_cancelled(self): + with Connection(self.sockaddr) as con: + self.send_finger_automatic(False, con=con) + self.send_finger_report(True, con=con) + self.send_image('tented_arch', con=con) + self.wait_for_result() + self.assertTrue(self._verify_stopped) + self.assertEqual(self._last_result, 'verify-no-match') + self.device.VerifyStop() + + # We'll be cancelled at this point, so con is invalid + + self.device.VerifyStart('(s)', self.verify_finger) + self.send_finger_report(False) + self.send_image('whorl') + self.wait_for_result() + self.assertTrue(self._verify_stopped) + self.assertEqual(self._last_result, 'verify-match') + def test_verify_start_during_verify(self): with self.assertFprintError('AlreadyInUse'): self.device.VerifyStart('(s)', self.verify_finger) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/tests/pam/test_pam_fprintd.py new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/tests/pam/test_pam_fprintd.py --- old/fprintd-v1.90.8-7d22a2b5b9d323638bb213aefb8627d897c8e482/tests/pam/test_pam_fprintd.py 2020-12-11 16:00:28.000000000 +0100 +++ new/fprintd-v1.90.9-da60bddb3e5be024c6c1958437cb13e0ce0ffac8/tests/pam/test_pam_fprintd.py 2021-01-13 13:23:24.000000000 +0100 @@ -154,6 +154,21 @@ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL) res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ]) + def test_pam_fprintd_retry(self): + self.setup_device() + script = [ + ( 'verify-swipe-too-short', False, 1 ), + ( 'verify-finger-not-centered', False, 1 ), + ( 'verify-match', True, 1 ) + ] + self.device_mock.SetVerifyScript(script) + + tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS) + res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ]) + self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader') + self.assertRegex(res.errors[0], r'Swipe was too short, try again') + self.assertRegex(res.errors[1], r'Your finger was not centered, try swiping your finger again') + def test_pam_fprintd_no_fingers_while_verifying(self): self.setup_device() script = [ @@ -221,6 +236,31 @@ self.assertRegex(res.info[0], r'Place your left middle finger on FDO Sandpaper Reader') self.assertEqual(len(res.errors), 0) + def test_pam_fprintd_multi_reader_not_all_enrolled(self): + # Add a 1st device with actual enrolled prints + device_path = self.obj_fprintd_mock.AddDevice('FDO Empty reader', 3, 'press') + empty_reader = self.dbus_con.get_object('net.reactivated.Fprint', device_path) + empty_reader.SetEnrolledFingers('toto', dbus.Array(set([]), signature='s')) + + # Add a 2nd device with actual enrolled prints + device_path = self.obj_fprintd_mock.AddDevice('FDO Most Used Reader', 3, 'press') + sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path) + sandpaper_device_mock.SetEnrolledFingers('toto', ['left-middle-finger', 'right-middle-finger']) + script = [ + ( 'verify-match', True, 2 ) + ] + sandpaper_device_mock.SetVerifyScript(script) + + # Add a 3rd device, with only one enrolled finger + self.setup_device() + self.device_mock.SetEnrolledFingers('toto', ['left-middle-finger']) + + tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS) + res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ]) + + self.assertRegex(res.info[0], r'Place your left middle finger on FDO Most Used Reader') + self.assertEqual(len(res.errors), 0) + def test_pam_fprintd_last_try_auth(self): self.setup_device() script = [
