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
|
This file lists notable changes in each release. For the full history of all
|
||||||
changes, see ChangeLog.
|
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:
|
Version 1.90.7:
|
||||||
|
|
||||||
While 1.90.6 fixed a number of issues, we did have a bad regression due
|
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,
|
install_dir: dbus_service_dir,
|
||||||
)
|
)
|
||||||
|
|
||||||
configure_file(
|
if get_option('systemd')
|
||||||
configuration: configuration_data({
|
configure_file(
|
||||||
'libexecdir': fprintd_installdir,
|
configuration: configuration_data({
|
||||||
}),
|
'libexecdir': fprintd_installdir,
|
||||||
input: 'fprintd.service.in',
|
}),
|
||||||
output: 'fprintd.service',
|
input: 'fprintd.service.in',
|
||||||
install: true,
|
output: 'fprintd.service',
|
||||||
install_dir: systemd_unit_dir,
|
install: true,
|
||||||
)
|
install_dir: systemd_unit_dir,
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
polkit_policy = 'net.reactivated.fprint.device.policy'
|
polkit_policy = 'net.reactivated.fprint.device.policy'
|
||||||
polkit_policy_target = i18n.merge_file(polkit_policy,
|
polkit_policy_target = i18n.merge_file(polkit_policy,
|
||||||
|
|||||||
10
meson.build
10
meson.build
@ -1,5 +1,5 @@
|
|||||||
project('fprintd', 'c',
|
project('fprintd', 'c',
|
||||||
version: '1.90.7',
|
version: '1.90.9',
|
||||||
license: 'GPLv2+',
|
license: 'GPLv2+',
|
||||||
default_options: [
|
default_options: [
|
||||||
'buildtype=debugoptimized',
|
'buildtype=debugoptimized',
|
||||||
@ -94,13 +94,17 @@ pod2man = find_program('pod2man', required: get_option('man'))
|
|||||||
xsltproc = find_program('xsltproc', required: get_option('gtk_doc'))
|
xsltproc = find_program('xsltproc', required: get_option('gtk_doc'))
|
||||||
|
|
||||||
# StateDirectory was introduced in systemd 235
|
# 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')
|
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')
|
systemd_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
|
||||||
endif
|
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_service_dir = get_option('dbus_service_dir')
|
||||||
dbus_data_dir = datadir
|
dbus_data_dir = datadir
|
||||||
dbus_interfaces_dir = ''
|
dbus_interfaces_dir = ''
|
||||||
|
|||||||
@ -6,6 +6,10 @@ option('man',
|
|||||||
description: 'Generate the man files',
|
description: 'Generate the man files',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
value: true)
|
value: true)
|
||||||
|
option('systemd',
|
||||||
|
description: 'Install system service files',
|
||||||
|
type: 'boolean',
|
||||||
|
value: true)
|
||||||
option('systemd_system_unit_dir',
|
option('systemd_system_unit_dir',
|
||||||
description: 'Directory for systemd service files',
|
description: 'Directory for systemd service files',
|
||||||
type: 'string')
|
type: 'string')
|
||||||
|
|||||||
@ -60,6 +60,11 @@ static unsigned timeout = DEFAULT_TIMEOUT;
|
|||||||
#define USEC_PER_SEC ((uint64_t) 1000000ULL)
|
#define USEC_PER_SEC ((uint64_t) 1000000ULL)
|
||||||
#define NSEC_PER_USEC ((uint64_t) 1000ULL)
|
#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
|
static uint64_t
|
||||||
now (void)
|
now (void)
|
||||||
{
|
{
|
||||||
@ -112,11 +117,13 @@ send_err_msg (pam_handle_t *pamh, const char *msg)
|
|||||||
static char *
|
static char *
|
||||||
open_device (pam_handle_t *pamh,
|
open_device (pam_handle_t *pamh,
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
|
const char *username,
|
||||||
bool *has_multiple_devices)
|
bool *has_multiple_devices)
|
||||||
{
|
{
|
||||||
pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
|
pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
|
||||||
pf_autoptr (sd_bus_message) m = NULL;
|
pf_autoptr (sd_bus_message) m = NULL;
|
||||||
size_t num_devices;
|
size_t num_devices;
|
||||||
|
size_t max_prints;
|
||||||
const char *path = NULL;
|
const char *path = NULL;
|
||||||
const char *s;
|
const char *s;
|
||||||
int r;
|
int r;
|
||||||
@ -143,12 +150,23 @@ open_device (pam_handle_t *pamh,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sd_bus_message_read_basic (m, 'o', &path) < 0)
|
num_devices = 0;
|
||||||
return NULL;
|
max_prints = 0;
|
||||||
|
|
||||||
num_devices = 1;
|
|
||||||
while ((r = sd_bus_message_read_basic (m, 'o', &s)) > 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);
|
*has_multiple_devices = (num_devices > 1);
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (pamh, LOG_DEBUG, "Using device %s (out of %ld devices)", path, num_devices);
|
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)
|
if ((r = sd_bus_message_read (m, "sb", &result, &done)) < 0)
|
||||||
{
|
{
|
||||||
pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyResult signal: %d", r);
|
pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyResult signal: %d", r);
|
||||||
|
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +274,7 @@ verify_finger_selected (sd_bus_message *m,
|
|||||||
if (sd_bus_message_read_basic (m, 's', &finger_name) < 0)
|
if (sd_bus_message_read_basic (m, 's', &finger_name) < 0)
|
||||||
{
|
{
|
||||||
pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyFingerSelected signal: %d", errno);
|
pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyFingerSelected signal: %d", errno);
|
||||||
|
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,11 +546,11 @@ do_verify (sd_bus *bus,
|
|||||||
return PAM_AUTH_ERR;
|
return PAM_AUTH_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static size_t
|
||||||
user_has_prints (pam_handle_t *pamh,
|
user_enrolled_prints_num (pam_handle_t *pamh,
|
||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *dev,
|
const char *dev,
|
||||||
const char *username)
|
const char *username)
|
||||||
{
|
{
|
||||||
pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
|
pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
|
||||||
pf_autoptr (sd_bus_message) m = NULL;
|
pf_autoptr (sd_bus_message) m = NULL;
|
||||||
@ -555,21 +575,21 @@ user_has_prints (pam_handle_t *pamh,
|
|||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (pamh, LOG_DEBUG, "ListEnrolledFingers failed for %s: %s",
|
pam_syslog (pamh, LOG_DEBUG, "ListEnrolledFingers failed for %s: %s",
|
||||||
username, error.message);
|
username, error.message);
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_bus_message_enter_container (m, 'a', "s");
|
r = sd_bus_message_enter_container (m, 'a', "s");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
{
|
{
|
||||||
pam_syslog (pamh, LOG_ERR, "Failed to parse answer from ListEnrolledFingers(): %d", r);
|
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)
|
while ((r = sd_bus_message_read_basic (m, 's', &s)) > 0)
|
||||||
num_fingers++;
|
num_fingers++;
|
||||||
sd_bus_message_exit_container (m);
|
sd_bus_message_exit_container (m);
|
||||||
|
|
||||||
return num_fingers > 0;
|
return num_fingers;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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)
|
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);
|
pam_syslog (data->pamh, LOG_ERR, "Failed to parse NameOwnerChanged signal: %d", errno);
|
||||||
|
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,8 +661,7 @@ name_owner_changed (sd_bus_message *m,
|
|||||||
* to events from a new name owner otherwise. */
|
* to events from a new name owner otherwise. */
|
||||||
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
data->verify_ret = PAM_AUTHINFO_UNAVAIL;
|
||||||
|
|
||||||
if (debug)
|
pam_syslog (data->pamh, LOG_WARNING, "fprintd name owner changed during operation!");
|
||||||
pam_syslog (data->pamh, LOG_ERR, "fprintd name owner changed during operation!\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -649,8 +669,6 @@ name_owner_changed (sd_bus_message *m,
|
|||||||
static int
|
static int
|
||||||
do_auth (pam_handle_t *pamh, const char *username)
|
do_auth (pam_handle_t *pamh, const char *username)
|
||||||
{
|
{
|
||||||
bool have_prints;
|
|
||||||
|
|
||||||
pf_autoptr (verify_data) data = NULL;
|
pf_autoptr (verify_data) data = NULL;
|
||||||
pf_autoptr (sd_bus) bus = NULL;
|
pf_autoptr (sd_bus) bus = NULL;
|
||||||
pf_autoptr (sd_bus_slot) name_owner_changed_slot = 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;
|
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;
|
name_owner_changed_slot = NULL;
|
||||||
sd_bus_match_signal (bus,
|
sd_bus_match_signal (bus,
|
||||||
&name_owner_changed_slot,
|
&name_owner_changed_slot,
|
||||||
@ -675,17 +700,6 @@ do_auth (pam_handle_t *pamh, const char *username)
|
|||||||
name_owner_changed,
|
name_owner_changed,
|
||||||
data);
|
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))
|
if (claim_device (pamh, bus, data->dev, username))
|
||||||
{
|
{
|
||||||
int ret = do_verify (bus, data);
|
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;
|
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
|
static void
|
||||||
fprint_device_dispose (GObject *object)
|
fprint_device_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
@ -717,7 +727,7 @@ _fprint_device_check_for_username (FprintDevice *rdev,
|
|||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_autoptr(GVariant) ret = NULL;
|
g_autoptr(GVariant) ret = NULL;
|
||||||
g_autoptr(GError) err = NULL;
|
g_autoptr(GError) local_error = NULL;
|
||||||
GDBusConnection *connection;
|
GDBusConnection *connection;
|
||||||
const char *sender;
|
const char *sender;
|
||||||
struct passwd *user;
|
struct passwd *user;
|
||||||
@ -734,15 +744,13 @@ _fprint_device_check_for_username (FprintDevice *rdev,
|
|||||||
"GetConnectionUnixUser",
|
"GetConnectionUnixUser",
|
||||||
g_variant_new ("(s)", sender),
|
g_variant_new ("(s)", sender),
|
||||||
NULL, G_DBUS_CALL_FLAGS_NONE, -1,
|
NULL, G_DBUS_CALL_FLAGS_NONE, -1,
|
||||||
NULL, &err);
|
NULL, &local_error);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) e = NULL;
|
|
||||||
|
|
||||||
g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
|
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",
|
||||||
err->message);
|
local_error->message);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -786,15 +794,30 @@ _fprint_device_client_vanished (GDBusConnection *connection,
|
|||||||
if (session != NULL &&
|
if (session != NULL &&
|
||||||
g_strcmp0 (session->sender, name) == 0)
|
g_strcmp0 (session->sender, name) == 0)
|
||||||
{
|
{
|
||||||
while (priv->current_action != ACTION_NONE)
|
g_cancellable_cancel (priv->current_cancellable);
|
||||||
{
|
|
||||||
/* OPEN/CLOSE are not cancellable, we just need to wait */
|
|
||||||
if (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
|
/* The session may have disappeared at this point if the device
|
||||||
* was already closing. */
|
* was already closing. */
|
||||||
g_clear_pointer (&session, session_data_unref);
|
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(SessionData) session = NULL;
|
||||||
g_autoptr(GDBusMethodInvocation) invocation = NULL;
|
g_autoptr(GDBusMethodInvocation) invocation = NULL;
|
||||||
|
g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
|
||||||
|
|
||||||
|
action_unset = rdev;
|
||||||
session = session_data_get (priv);
|
session = session_data_get (priv);
|
||||||
invocation = g_steal_pointer (&session->invocation);
|
invocation = g_steal_pointer (&session->invocation);
|
||||||
|
|
||||||
priv->current_action = ACTION_NONE;
|
|
||||||
if (!fp_device_open_finish (dev, res, &error))
|
if (!fp_device_open_finish (dev, res, &error))
|
||||||
{
|
{
|
||||||
g_autoptr(GError) dbus_error = NULL;
|
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(SessionData) session = NULL;
|
||||||
g_autoptr(GDBusMethodInvocation) invocation = NULL;
|
g_autoptr(GDBusMethodInvocation) invocation = NULL;
|
||||||
|
g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
|
||||||
|
|
||||||
session = session_data_get (priv);
|
session = session_data_get (priv);
|
||||||
session_data_set_new (priv, NULL, NULL);
|
session_data_set_new (priv, NULL, NULL);
|
||||||
invocation = g_steal_pointer (&session->invocation);
|
invocation = g_steal_pointer (&session->invocation);
|
||||||
|
action_unset = rdev;
|
||||||
|
|
||||||
priv->current_action = ACTION_NONE;
|
|
||||||
if (!fp_device_close_finish (dev, res, &error))
|
if (!fp_device_close_finish (dev, res, &error))
|
||||||
{
|
{
|
||||||
g_autoptr(GError) dbus_error = NULL;
|
g_autoptr(GError) dbus_error = NULL;
|
||||||
@ -1054,7 +1079,7 @@ can_start_action (FprintDevice *rdev, GError **error)
|
|||||||
case ACTION_VERIFY:
|
case ACTION_VERIFY:
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
"Enrollment already in progress");
|
"Verification already in progress");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACTION_OPEN:
|
case ACTION_OPEN:
|
||||||
@ -1085,6 +1110,47 @@ can_start_action (FprintDevice *rdev, GError **error)
|
|||||||
return FALSE;
|
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
|
static void
|
||||||
match_cb (FpDevice *device,
|
match_cb (FpDevice *device,
|
||||||
FpPrint *match,
|
FpPrint *match,
|
||||||
@ -1111,10 +1177,8 @@ static void
|
|||||||
verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
g_autoptr(SessionData) session = NULL;
|
|
||||||
FprintDevice *rdev = user_data;
|
FprintDevice *rdev = user_data;
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||||
FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev);
|
|
||||||
gboolean success;
|
gboolean success;
|
||||||
const char *name;
|
const char *name;
|
||||||
gboolean match;
|
gboolean match;
|
||||||
@ -1123,8 +1187,6 @@ verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|||||||
g_assert (!!success == !error);
|
g_assert (!!success == !error);
|
||||||
name = verify_result_to_name (match, error);
|
name = verify_result_to_name (match, error);
|
||||||
|
|
||||||
session = session_data_get (priv);
|
|
||||||
|
|
||||||
g_debug ("verify_cb: result %s", name);
|
g_debug ("verify_cb: result %s", name);
|
||||||
|
|
||||||
/* Automatically restart the operation for retry failures */
|
/* Automatically restart the operation for retry failures */
|
||||||
@ -1150,21 +1212,7 @@ verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|||||||
error->message);
|
error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the cancellation or reset action right away if vanished. */
|
stoppable_action_completed (rdev);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1175,7 +1223,6 @@ identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|||||||
g_autoptr(FpPrint) match = NULL;
|
g_autoptr(FpPrint) match = NULL;
|
||||||
FprintDevice *rdev = user_data;
|
FprintDevice *rdev = user_data;
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||||
FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev);
|
|
||||||
const char *name;
|
const char *name;
|
||||||
gboolean success;
|
gboolean success;
|
||||||
|
|
||||||
@ -1208,22 +1255,7 @@ identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|||||||
error->message);
|
error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the cancellation or reset action right away if vanished. */
|
stoppable_action_completed (rdev);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1446,7 +1478,7 @@ try_delete_print (FprintDevice *rdev)
|
|||||||
guint index;
|
guint index;
|
||||||
|
|
||||||
store.print_data_load (priv->dev,
|
store.print_data_load (priv->dev,
|
||||||
GPOINTER_TO_UINT (fingers->data),
|
GPOINTER_TO_UINT (finger->data),
|
||||||
username,
|
username,
|
||||||
&print);
|
&print);
|
||||||
|
|
||||||
@ -1520,7 +1552,6 @@ enroll_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
FprintDevice *rdev = user_data;
|
FprintDevice *rdev = user_data;
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||||
FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev);
|
|
||||||
|
|
||||||
g_autoptr(FpPrint) print = NULL;
|
g_autoptr(FpPrint) print = NULL;
|
||||||
const char *name;
|
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))
|
if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
g_warning ("Device reported an error during enroll: %s", error->message);
|
g_warning ("Device reported an error during enroll: %s", error->message);
|
||||||
|
|
||||||
/* Return the cancellation or reset action right away if vanished. */
|
stoppable_action_completed (rdev);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1824,6 +1844,7 @@ fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
|
|||||||
FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
|
FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||||
|
|
||||||
|
g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
g_autofree char *user = NULL;
|
g_autofree char *user = NULL;
|
||||||
const char *sender;
|
const char *sender;
|
||||||
@ -1841,6 +1862,7 @@ fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
priv->current_action = ACTION_DELETE;
|
priv->current_action = ACTION_DELETE;
|
||||||
|
action_unset = rdev;
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, &error))
|
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))
|
if (!opened && fp_device_has_storage (priv->dev))
|
||||||
fp_device_close_sync (priv->dev, NULL, NULL);
|
fp_device_close_sync (priv->dev, NULL, NULL);
|
||||||
|
|
||||||
priv->current_action = ACTION_NONE;
|
|
||||||
|
|
||||||
fprint_dbus_device_complete_delete_enrolled_fingers (dbus_dev,
|
fprint_dbus_device_complete_delete_enrolled_fingers (dbus_dev,
|
||||||
invocation);
|
invocation);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1890,6 +1910,7 @@ fprint_device_delete_enrolled_fingers2 (FprintDBusDevice *dbus_dev,
|
|||||||
|
|
||||||
g_autoptr(SessionData) session = NULL;
|
g_autoptr(SessionData) session = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, &error))
|
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;
|
priv->current_action = ACTION_DELETE;
|
||||||
|
action_unset = rdev;
|
||||||
|
|
||||||
session = session_data_get (priv);
|
session = session_data_get (priv);
|
||||||
|
|
||||||
delete_enrolled_fingers (rdev, session->username);
|
delete_enrolled_fingers (rdev, session->username);
|
||||||
|
|
||||||
priv->current_action = ACTION_NONE;
|
|
||||||
|
|
||||||
fprint_dbus_device_complete_delete_enrolled_fingers2 (dbus_dev,
|
fprint_dbus_device_complete_delete_enrolled_fingers2 (dbus_dev,
|
||||||
invocation);
|
invocation);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1925,8 +1945,9 @@ handle_unauthorized_access (FprintDevice *rdev,
|
|||||||
|
|
||||||
g_assert (error);
|
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_sender (invocation),
|
||||||
|
g_dbus_method_invocation_get_method_name (invocation),
|
||||||
fp_device_get_name (priv->dev),
|
fp_device_get_name (priv->dev),
|
||||||
error->message);
|
error->message);
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
@ -1980,8 +2001,9 @@ action_authorization_handler (GDBusInterfaceSkeleton *interface,
|
|||||||
&error))
|
&error))
|
||||||
return handle_unauthorized_access (rdev, invocation, 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),
|
fp_device_get_name (priv->dev),
|
||||||
|
g_dbus_method_invocation_get_method_name (invocation),
|
||||||
g_dbus_method_invocation_get_sender (invocation));
|
g_dbus_method_invocation_get_sender (invocation));
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|||||||
@ -66,6 +66,10 @@ get_storage_path (void)
|
|||||||
elems = g_strsplit (path, ":", -1);
|
elems = g_strsplit (path, ":", -1);
|
||||||
storage_path = g_strdup (elems[0]);
|
storage_path = g_strdup (elems[0]);
|
||||||
}
|
}
|
||||||
|
else if (*path)
|
||||||
|
{
|
||||||
|
storage_path = g_strdup (path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (storage_path == NULL)
|
if (storage_path == NULL)
|
||||||
@ -151,7 +155,6 @@ file_storage_print_data_save (FpPrint *print)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
//fp_dbg("saving to %s", path);
|
|
||||||
g_file_set_contents (path, buf, len, &err);
|
g_file_set_contents (path, buf, len, &err);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -161,6 +164,8 @@ file_storage_print_data_save (FpPrint *print)
|
|||||||
return err->code;
|
return err->code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_debug ("file_storage_print_data_save(): print saved to %s", path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +177,6 @@ load_from_file (char *path, FpPrint **print)
|
|||||||
g_autofree char *contents = NULL;
|
g_autofree char *contents = NULL;
|
||||||
FpPrint *new;
|
FpPrint *new;
|
||||||
|
|
||||||
//fp_dbg("from %s", path);
|
|
||||||
g_file_get_contents (path, &contents, &length, &err);
|
g_file_get_contents (path, &contents, &length, &err);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -226,6 +230,7 @@ file_storage_print_data_load (FpDevice *dev,
|
|||||||
int
|
int
|
||||||
file_storage_print_data_delete (FpDevice *dev, FpFinger finger, const char *username)
|
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 *base_store = NULL;
|
||||||
g_autofree gchar *path = NULL;
|
g_autofree gchar *path = NULL;
|
||||||
int r;
|
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);
|
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);
|
r = g_unlink (path);
|
||||||
g_debug ("file_storage_print_data_delete(): unlink(\"%s\") %s",
|
g_debug ("file_storage_print_data_delete(): unlink(\"%s\") %s",
|
||||||
path, g_strerror (r));
|
path, g_strerror (r));
|
||||||
|
|
||||||
/* FIXME: cleanup empty directory */
|
prints = file_storage_discover_prints (dev, username);
|
||||||
return g_unlink (path);
|
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 *
|
static GSList *
|
||||||
|
|||||||
@ -55,7 +55,7 @@ typedef enum {
|
|||||||
|
|
||||||
/* Enum of possible permissions, orders and nick matter here:
|
/* Enum of possible permissions, orders and nick matter here:
|
||||||
- The order controls the priority of a required permission when various are
|
- 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.
|
- Nick must match the relative polkit rule.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -91,3 +91,18 @@ FprintDevice *fprint_device_new (FpDevice *dev);
|
|||||||
guint32 _fprint_device_get_id (FprintDevice *rdev);
|
guint32 _fprint_device_get_id (FprintDevice *rdev);
|
||||||
/* Print */
|
/* Print */
|
||||||
/* TODO */
|
/* 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;
|
GDBusObjectManagerServer *object_manager_server;
|
||||||
|
|
||||||
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->object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
|
||||||
priv->dbus_manager = fprint_dbus_manager_skeleton_new ();
|
priv->dbus_manager = fprint_dbus_manager_skeleton_new ();
|
||||||
@ -432,7 +432,7 @@ fprint_manager_get_default_device (FprintManager *manager,
|
|||||||
GQuark
|
GQuark
|
||||||
fprint_error_quark (void)
|
fprint_error_quark (void)
|
||||||
{
|
{
|
||||||
static volatile gsize quark = 0;
|
static gsize quark = 0;
|
||||||
|
|
||||||
if (g_once_init_enter (&quark))
|
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))
|
'.*net\.reactivated\.Fprint\.Error\.{}.*'.format(fprint_error))
|
||||||
|
|
||||||
# From libfprint tests
|
# From libfprint tests
|
||||||
def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT):
|
def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT, con=None):
|
||||||
with Connection(self.sockaddr) as con:
|
if con:
|
||||||
con.sendall(struct.pack('ii', -1, retry_error))
|
con.sendall(struct.pack('ii', -1, retry_error))
|
||||||
|
return
|
||||||
|
|
||||||
|
with Connection(self.sockaddr) as con:
|
||||||
|
self.send_retry(retry_error, con)
|
||||||
|
|
||||||
# From libfprint tests
|
# From libfprint tests
|
||||||
def send_error(self, error=FPrint.DeviceError.GENERAL):
|
def send_error(self, error=FPrint.DeviceError.GENERAL, con=None):
|
||||||
with Connection(self.sockaddr) as con:
|
if con:
|
||||||
con.sendall(struct.pack('ii', -2, error))
|
con.sendall(struct.pack('ii', -2, error))
|
||||||
|
return
|
||||||
|
|
||||||
|
with Connection(self.sockaddr) as con:
|
||||||
|
self.send_error(error, con)
|
||||||
|
|
||||||
# From libfprint tests
|
# From libfprint tests
|
||||||
def send_remove(self):
|
def send_remove(self, con=None):
|
||||||
with Connection(self.sockaddr) as con:
|
if con:
|
||||||
con.sendall(struct.pack('ii', -5, 0))
|
con.sendall(struct.pack('ii', -5, 0))
|
||||||
|
return
|
||||||
|
|
||||||
|
with Connection(self.sockaddr) as con:
|
||||||
|
self.send_remove(con=con)
|
||||||
|
|
||||||
# From libfprint tests
|
# From libfprint tests
|
||||||
def send_image(self, image):
|
def send_image(self, image, con=None):
|
||||||
img = self.prints[image]
|
if con:
|
||||||
with Connection(self.sockaddr) as con:
|
img = self.prints[image]
|
||||||
mem = img.get_data()
|
mem = img.get_data()
|
||||||
mem = mem.tobytes()
|
mem = mem.tobytes()
|
||||||
self.assertEqual(len(mem), img.get_width() * img.get_height())
|
self.assertEqual(len(mem), img.get_width() * img.get_height())
|
||||||
@ -322,6 +334,28 @@ class FPrintdTest(dbusmock.DBusTestCase):
|
|||||||
encoded_img += mem
|
encoded_img += mem
|
||||||
|
|
||||||
con.sendall(encoded_img)
|
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):
|
def call_device_method_async(self, method, *args):
|
||||||
""" add cancellable... """
|
""" add cancellable... """
|
||||||
@ -429,10 +463,12 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
|
|||||||
if expected is not None:
|
if expected is not None:
|
||||||
self.assertEqual(self._last_result, expected)
|
self.assertEqual(self._last_result, expected)
|
||||||
|
|
||||||
def enroll_image(self, img, finger='right-index-finger', expected_result='enroll-completed'):
|
def enroll_image(self, img, device=None, finger='right-index-finger', expected_result='enroll-completed'):
|
||||||
self.device.EnrollStart('(s)', finger)
|
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):
|
for stage in range(stages):
|
||||||
self.send_image(img)
|
self.send_image(img)
|
||||||
if stage < stages - 1:
|
if stage < stages - 1:
|
||||||
@ -440,7 +476,7 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
|
|||||||
else:
|
else:
|
||||||
self.wait_for_result(expected_result)
|
self.wait_for_result(expected_result)
|
||||||
|
|
||||||
self.device.EnrollStop()
|
device.EnrollStop()
|
||||||
self.assertEqual(self._last_result, expected_result)
|
self.assertEqual(self._last_result, expected_result)
|
||||||
|
|
||||||
def enroll_multiple_images(self, images_override={}, return_index=-1):
|
def enroll_multiple_images(self, images_override={}, return_index=-1):
|
||||||
@ -462,6 +498,29 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
|
|||||||
|
|
||||||
return (enrolled, enroll_map)
|
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):
|
class FPrintdManagerTests(FPrintdVirtualDeviceBaseTest):
|
||||||
|
|
||||||
@ -700,23 +759,7 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
self.device.Release()
|
self.device.Release()
|
||||||
|
|
||||||
def test_claim_disconnect(self):
|
def test_claim_disconnect(self):
|
||||||
addr = os.environ['DBUS_SYSTEM_BUS_ADDRESS']
|
bus, dev = self.get_secondary_bus_and_device()
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
def call_done(obj, result, user_data):
|
def call_done(obj, result, user_data):
|
||||||
# Ignore the callback (should be an error)
|
# Ignore the callback (should be an error)
|
||||||
@ -726,8 +769,91 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
dev.Claim('(s)', 'testuser', result_handler=call_done)
|
dev.Claim('(s)', 'testuser', result_handler=call_done)
|
||||||
|
|
||||||
# Ensure the call is on the wire, then close immediately
|
# Ensure the call is on the wire, then close immediately
|
||||||
dbus.flush_sync()
|
bus.flush_sync()
|
||||||
dbus.close_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)
|
time.sleep(1)
|
||||||
|
|
||||||
@ -843,9 +969,11 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
self.device.DeleteEnrolledFingers2()
|
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/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):
|
def test_enroll_invalid_storage_dir(self):
|
||||||
# Directory wil not exist yet
|
# Directory will not exist yet
|
||||||
os.makedirs(self.state_dir, mode=0o500)
|
os.makedirs(self.state_dir, mode=0o500)
|
||||||
self.addCleanup(os.chmod, self.state_dir, mode=0o700)
|
self.addCleanup(os.chmod, self.state_dir, mode=0o700)
|
||||||
|
|
||||||
@ -1214,6 +1342,12 @@ class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
|
|||||||
def test_verify_retry_general(self):
|
def test_verify_retry_general(self):
|
||||||
self.assertVerifyRetry(FPrint.DeviceRetry.GENERAL, 'verify-retry-scan')
|
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):
|
def test_verify_retry_too_short(self):
|
||||||
self.assertVerifyRetry(FPrint.DeviceRetry.TOO_SHORT, 'verify-swipe-too-short')
|
self.assertVerifyRetry(FPrint.DeviceRetry.TOO_SHORT, 'verify-swipe-too-short')
|
||||||
|
|
||||||
@ -1250,6 +1384,38 @@ class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
|
|||||||
def test_verify_error_data_full(self):
|
def test_verify_error_data_full(self):
|
||||||
self.assertVerifyError(FPrint.DeviceError.DATA_FULL, 'verify-unknown-error')
|
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):
|
def test_verify_start_during_verify(self):
|
||||||
with self.assertFprintError('AlreadyInUse'):
|
with self.assertFprintError('AlreadyInUse'):
|
||||||
self.device.VerifyStart('(s)', self.verify_finger)
|
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)
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
|
||||||
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
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):
|
def test_pam_fprintd_no_fingers_while_verifying(self):
|
||||||
self.setup_device()
|
self.setup_device()
|
||||||
script = [
|
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.assertRegex(res.info[0], r'Place your left middle finger on FDO Sandpaper Reader')
|
||||||
self.assertEqual(len(res.errors), 0)
|
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):
|
def test_pam_fprintd_last_try_auth(self):
|
||||||
self.setup_device()
|
self.setup_device()
|
||||||
script = [
|
script = [
|
||||||
|
|||||||
@ -160,7 +160,10 @@ verify_started_cb (GObject *obj,
|
|||||||
struct VerifyState *verify_state = user_data;
|
struct VerifyState *verify_state = user_data;
|
||||||
|
|
||||||
if (fprint_dbus_device_call_verify_start_finish (FPRINT_DBUS_DEVICE (obj), res, &verify_state->error))
|
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
|
static void
|
||||||
@ -226,7 +229,6 @@ do_verify (FprintDBusDevice *dev)
|
|||||||
g_clear_error (&verify_state.error);
|
g_clear_error (&verify_state.error);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
g_print ("Verify started!\n");
|
|
||||||
|
|
||||||
/* VerifyStatus signals are processing, wait for completion. */
|
/* VerifyStatus signals are processing, wait for completion. */
|
||||||
while (!verify_state.completed)
|
while (!verify_state.completed)
|
||||||
|
|||||||
Reference in New Issue
Block a user