mirror of
https://gitlab.com/mishakmak/pam-fprint-grosshack.git
synced 2026-04-09 04:13:33 +02:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da60bddb3e | |||
| 506d99e90c | |||
| e7f47e28d7 | |||
| 938c1aac5a | |||
| fd02922608 | |||
| 195f7eaf5f | |||
| 48ea3b89c9 | |||
| 4cfa6b5b37 | |||
| c685f0d34c | |||
| eece834231 | |||
| 3faaa81257 | |||
| b9cdb58a1a | |||
| ab8dcfaa61 | |||
| 25a97c8276 | |||
| 8057e49d31 | |||
| f75e800d5c | |||
| 6ae4f5e939 | |||
| 7c9a04c2ae | |||
| 7b7aa6e99d | |||
| b624f8c8c7 | |||
| 3e81179eca | |||
| c6647ba875 | |||
| 988ee01f66 | |||
| 32ee94c8a0 | |||
| 7d22a2b5b9 | |||
| de725a91e4 | |||
| 18392cba54 | |||
| 783d82f359 | |||
| c00a3375d1 | |||
| 5aa61adabc | |||
| 1fc10f15ee | |||
| c24badfd68 |
20
NEWS
20
NEWS
@ -1,6 +1,26 @@
|
||||
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
|
||||
to regressions. One more issue that cropped up was that a pam_fprintd fix
|
||||
to avoid a possible authentication bypass caused issues when fprintd was
|
||||
just started on demand.
|
||||
|
||||
Highlights:
|
||||
- pam: Only listen to NameOwnerChanged after fprintd is known to run (#94)
|
||||
- Place new ObjectManager DBus API at /net/reactivated/Fprint
|
||||
|
||||
|
||||
Version 1.90.7:
|
||||
|
||||
While 1.90.6 fixed a number of issues, we did have a bad regression due
|
||||
|
||||
@ -11,15 +11,17 @@ configure_file(
|
||||
install_dir: dbus_service_dir,
|
||||
)
|
||||
|
||||
configure_file(
|
||||
configuration: configuration_data({
|
||||
'libexecdir': fprintd_installdir,
|
||||
}),
|
||||
input: 'fprintd.service.in',
|
||||
output: 'fprintd.service',
|
||||
install: true,
|
||||
install_dir: systemd_unit_dir,
|
||||
)
|
||||
if get_option('systemd')
|
||||
configure_file(
|
||||
configuration: configuration_data({
|
||||
'libexecdir': fprintd_installdir,
|
||||
}),
|
||||
input: 'fprintd.service.in',
|
||||
output: 'fprintd.service',
|
||||
install: true,
|
||||
install_dir: systemd_unit_dir,
|
||||
)
|
||||
endif
|
||||
|
||||
polkit_policy = 'net.reactivated.fprint.device.policy'
|
||||
polkit_policy_target = i18n.merge_file(polkit_policy,
|
||||
|
||||
10
meson.build
10
meson.build
@ -1,5 +1,5 @@
|
||||
project('fprintd', 'c',
|
||||
version: '1.90.7',
|
||||
version: '1.90.9',
|
||||
license: 'GPLv2+',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
@ -94,13 +94,17 @@ pod2man = find_program('pod2man', required: get_option('man'))
|
||||
xsltproc = find_program('xsltproc', required: get_option('gtk_doc'))
|
||||
|
||||
# StateDirectory was introduced in systemd 235
|
||||
systemd_dep = dependency('systemd', version: '>= 235')
|
||||
systemd_dep = dependency('systemd', version: '>= 235', required: false)
|
||||
systemd_unit_dir = get_option('systemd_system_unit_dir')
|
||||
|
||||
if systemd_unit_dir == ''
|
||||
if systemd_unit_dir == '' and systemd_dep.found()
|
||||
systemd_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
|
||||
endif
|
||||
|
||||
if get_option('systemd') and systemd_unit_dir == ''
|
||||
error('systemd development files or systemd_system_unit_dir is needed for systemd support.')
|
||||
endif
|
||||
|
||||
dbus_service_dir = get_option('dbus_service_dir')
|
||||
dbus_data_dir = datadir
|
||||
dbus_interfaces_dir = ''
|
||||
|
||||
@ -6,6 +6,10 @@ option('man',
|
||||
description: 'Generate the man files',
|
||||
type: 'boolean',
|
||||
value: true)
|
||||
option('systemd',
|
||||
description: 'Install system service files',
|
||||
type: 'boolean',
|
||||
value: true)
|
||||
option('systemd_system_unit_dir',
|
||||
description: 'Directory for systemd service files',
|
||||
type: 'string')
|
||||
|
||||
@ -60,6 +60,11 @@ static unsigned timeout = DEFAULT_TIMEOUT;
|
||||
#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 @@ send_err_msg (pam_handle_t *pamh, const char *msg)
|
||||
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 @@ open_device (pam_handle_t *pamh,
|
||||
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);
|
||||
@ -208,6 +226,7 @@ verify_result (sd_bus_message *m,
|
||||
if ((r = sd_bus_message_read (m, "sb", &result, &done)) < 0)
|
||||
{
|
||||
pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyResult signal: %d", r);
|
||||
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -255,6 +274,7 @@ verify_finger_selected (sd_bus_message *m,
|
||||
if (sd_bus_message_read_basic (m, 's', &finger_name) < 0)
|
||||
{
|
||||
pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyFingerSelected signal: %d", errno);
|
||||
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -526,11 +546,11 @@ do_verify (sd_bus *bus,
|
||||
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;
|
||||
@ -555,21 +575,21 @@ user_has_prints (pam_handle_t *pamh,
|
||||
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
|
||||
@ -630,6 +650,7 @@ name_owner_changed (sd_bus_message *m,
|
||||
if (sd_bus_message_read (m, "sss", &name, &old_owner, &new_owner) < 0)
|
||||
{
|
||||
pam_syslog (data->pamh, LOG_ERR, "Failed to parse NameOwnerChanged signal: %d", errno);
|
||||
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -640,8 +661,7 @@ name_owner_changed (sd_bus_message *m,
|
||||
* to events from a new name owner otherwise. */
|
||||
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||
|
||||
if (debug)
|
||||
pam_syslog (data->pamh, LOG_ERR, "fprintd name owner changed during operation!\n");
|
||||
pam_syslog (data->pamh, LOG_WARNING, "fprintd name owner changed during operation!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -649,8 +669,6 @@ name_owner_changed (sd_bus_message *m,
|
||||
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;
|
||||
@ -665,6 +683,13 @@ do_auth (pam_handle_t *pamh, const char *username)
|
||||
return PAM_AUTHINFO_UNAVAIL;
|
||||
}
|
||||
|
||||
data->dev = open_device (pamh, bus, username, &data->has_multiple_devices);
|
||||
if (data->dev == NULL)
|
||||
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.
|
||||
*/
|
||||
name_owner_changed_slot = NULL;
|
||||
sd_bus_match_signal (bus,
|
||||
&name_owner_changed_slot,
|
||||
@ -675,17 +700,6 @@ do_auth (pam_handle_t *pamh, const char *username)
|
||||
name_owner_changed,
|
||||
data);
|
||||
|
||||
data->dev = open_device (pamh, bus, &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;
|
||||
|
||||
if (claim_device (pamh, bus, data->dev, username))
|
||||
{
|
||||
int ret = do_verify (bus, data);
|
||||
|
||||
164
src/device.c
164
src/device.c
@ -210,6 +210,16 @@ session_data_set_new (FprintDevicePrivate *priv, gchar *sender, gchar *username)
|
||||
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)
|
||||
{
|
||||
@ -717,7 +727,7 @@ _fprint_device_check_for_username (FprintDevice *rdev,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GVariant) ret = NULL;
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
GDBusConnection *connection;
|
||||
const char *sender;
|
||||
struct passwd *user;
|
||||
@ -734,15 +744,13 @@ _fprint_device_check_for_username (FprintDevice *rdev,
|
||||
"GetConnectionUnixUser",
|
||||
g_variant_new ("(s)", sender),
|
||||
NULL, G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
NULL, &err);
|
||||
NULL, &local_error);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
g_autoptr(GError) e = NULL;
|
||||
|
||||
g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
|
||||
"Could not get conection unix user ID: %s",
|
||||
err->message);
|
||||
"Could not get connection unix user ID: %s",
|
||||
local_error->message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -786,15 +794,30 @@ _fprint_device_client_vanished (GDBusConnection *connection,
|
||||
if (session != NULL &&
|
||||
g_strcmp0 (session->sender, name) == 0)
|
||||
{
|
||||
while (priv->current_action != ACTION_NONE)
|
||||
{
|
||||
/* OPEN/CLOSE are not cancellable, we just need to wait */
|
||||
if (priv->current_cancellable)
|
||||
g_cancellable_cancel (priv->current_cancellable);
|
||||
g_cancellable_cancel (priv->current_cancellable);
|
||||
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
if (!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;
|
||||
|
||||
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);
|
||||
@ -840,11 +863,12 @@ dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
|
||||
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;
|
||||
@ -941,12 +965,13 @@ dev_close_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
|
||||
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;
|
||||
@ -1054,7 +1079,7 @@ can_start_action (FprintDevice *rdev, GError **error)
|
||||
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:
|
||||
@ -1085,6 +1110,47 @@ can_start_action (FprintDevice *rdev, GError **error)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
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,
|
||||
@ -1111,10 +1177,8 @@ static void
|
||||
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;
|
||||
@ -1123,8 +1187,6 @@ verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
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 */
|
||||
@ -1150,21 +1212,7 @@ verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1175,7 +1223,6 @@ identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
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;
|
||||
|
||||
@ -1208,22 +1255,7 @@ identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1446,7 +1478,7 @@ try_delete_print (FprintDevice *rdev)
|
||||
guint index;
|
||||
|
||||
store.print_data_load (priv->dev,
|
||||
GPOINTER_TO_UINT (fingers->data),
|
||||
GPOINTER_TO_UINT (finger->data),
|
||||
username,
|
||||
&print);
|
||||
|
||||
@ -1520,7 +1552,6 @@ enroll_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
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;
|
||||
@ -1568,18 +1599,7 @@ enroll_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -1824,6 +1844,7 @@ fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
|
||||
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;
|
||||
@ -1841,6 +1862,7 @@ fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
|
||||
}
|
||||
|
||||
priv->current_action = ACTION_DELETE;
|
||||
action_unset = rdev;
|
||||
|
||||
if (!_fprint_device_check_claimed (rdev, invocation, &error))
|
||||
{
|
||||
@ -1874,8 +1896,6 @@ fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
|
||||
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;
|
||||
@ -1890,6 +1910,7 @@ fprint_device_delete_enrolled_fingers2 (FprintDBusDevice *dbus_dev,
|
||||
|
||||
g_autoptr(SessionData) session = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
|
||||
|
||||
if (!_fprint_device_check_claimed (rdev, invocation, &error))
|
||||
{
|
||||
@ -1904,13 +1925,12 @@ fprint_device_delete_enrolled_fingers2 (FprintDBusDevice *dbus_dev,
|
||||
}
|
||||
|
||||
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;
|
||||
@ -1925,8 +1945,9 @@ handle_unauthorized_access (FprintDevice *rdev,
|
||||
|
||||
g_assert (error);
|
||||
|
||||
g_warning ("Client %s not authorized for device %s: %s",
|
||||
g_warning ("Client %s not authorized to call method '%s' for device %s: %s",
|
||||
g_dbus_method_invocation_get_sender (invocation),
|
||||
g_dbus_method_invocation_get_method_name (invocation),
|
||||
fp_device_get_name (priv->dev),
|
||||
error->message);
|
||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||
@ -1980,8 +2001,9 @@ action_authorization_handler (GDBusInterfaceSkeleton *interface,
|
||||
&error))
|
||||
return handle_unauthorized_access (rdev, invocation, error);
|
||||
|
||||
g_debug ("Authorization granted to %s for device %s!",
|
||||
g_debug ("Authorization granted to %s to call method '%s' for device %s!",
|
||||
fp_device_get_name (priv->dev),
|
||||
g_dbus_method_invocation_get_method_name (invocation),
|
||||
g_dbus_method_invocation_get_sender (invocation));
|
||||
|
||||
return TRUE;
|
||||
|
||||
@ -66,6 +66,10 @@ get_storage_path (void)
|
||||
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 @@ file_storage_print_data_save (FpPrint *print)
|
||||
return r;
|
||||
}
|
||||
|
||||
//fp_dbg("saving to %s", path);
|
||||
g_file_set_contents (path, buf, len, &err);
|
||||
if (err)
|
||||
{
|
||||
@ -161,6 +164,8 @@ file_storage_print_data_save (FpPrint *print)
|
||||
return err->code;
|
||||
}
|
||||
|
||||
g_debug ("file_storage_print_data_save(): print saved to %s", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -172,7 +177,6 @@ load_from_file (char *path, FpPrint **print)
|
||||
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 @@ file_storage_print_data_load (FpDevice *dev,
|
||||
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 @@ file_storage_print_data_delete (FpDevice *dev, FpFinger finger, const char *user
|
||||
|
||||
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 *
|
||||
|
||||
@ -55,7 +55,7 @@ typedef enum {
|
||||
|
||||
/* 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 @@ FprintDevice *fprint_device_new (FpDevice *dev);
|
||||
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))
|
||||
|
||||
@ -295,7 +295,7 @@ fprint_manager_constructed (GObject *object)
|
||||
GDBusObjectManagerServer *object_manager_server;
|
||||
|
||||
object_manager_server =
|
||||
g_dbus_object_manager_server_new (FPRINT_SERVICE_PATH "/Device");
|
||||
g_dbus_object_manager_server_new (FPRINT_SERVICE_PATH);
|
||||
|
||||
priv->object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||
priv->dbus_manager = fprint_dbus_manager_skeleton_new ();
|
||||
@ -432,7 +432,7 @@ fprint_manager_get_default_device (FprintManager *manager,
|
||||
GQuark
|
||||
fprint_error_quark (void)
|
||||
{
|
||||
static volatile gsize quark = 0;
|
||||
static gsize quark = 0;
|
||||
|
||||
if (g_once_init_enter (&quark))
|
||||
{
|
||||
|
||||
232
tests/fprintd.py
232
tests/fprintd.py
@ -296,24 +296,36 @@ class FPrintdTest(dbusmock.DBusTestCase):
|
||||
'.*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
|
||||
|
||||
with Connection(self.sockaddr) as con:
|
||||
self.send_retry(retry_error, con)
|
||||
|
||||
# From libfprint tests
|
||||
def send_error(self, error=FPrint.DeviceError.GENERAL):
|
||||
with Connection(self.sockaddr) as con:
|
||||
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:
|
||||
self.send_error(error, con)
|
||||
|
||||
# From libfprint tests
|
||||
def send_remove(self):
|
||||
with Connection(self.sockaddr) as con:
|
||||
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):
|
||||
img = self.prints[image]
|
||||
with Connection(self.sockaddr) as con:
|
||||
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 @@ class FPrintdTest(dbusmock.DBusTestCase):
|
||||
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 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
|
||||
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 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
|
||||
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 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
|
||||
|
||||
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 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
||||
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 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
||||
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 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
|
||||
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 @@ class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
|
||||
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 @@ class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
|
||||
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)
|
||||
|
||||
40
tests/pam/test_pam_fprintd.py
Executable file → Normal file
40
tests/pam/test_pam_fprintd.py
Executable file → Normal file
@ -154,6 +154,21 @@ class TestPamFprintd(dbusmock.DBusTestCase):
|
||||
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 @@ class TestPamFprintd(dbusmock.DBusTestCase):
|
||||
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 = [
|
||||
|
||||
@ -160,7 +160,10 @@ verify_started_cb (GObject *obj,
|
||||
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;
|
||||
{
|
||||
g_print ("Verify started!\n");
|
||||
verify_state->started = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -226,7 +229,6 @@ do_verify (FprintDBusDevice *dev)
|
||||
g_clear_error (&verify_state.error);
|
||||
exit (1);
|
||||
}
|
||||
g_print ("Verify started!\n");
|
||||
|
||||
/* VerifyStatus signals are processing, wait for completion. */
|
||||
while (!verify_state.completed)
|
||||
|
||||
Reference in New Issue
Block a user