mirror of
https://gitlab.com/mishakmak/pam-fprint-grosshack.git
synced 2026-04-09 12:23:34 +02:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52058c1ea0 | |||
| 22cdc0a7ea | |||
| 043fcaafec | |||
| bf2236620e | |||
| 0122d351f9 | |||
| 4435706d20 | |||
| c5877bbc12 | |||
| a170a3a09f | |||
| a76af6ce71 | |||
| 34a24eac77 | |||
| 47751548b2 | |||
| a30c45629e | |||
| 3242b99410 | |||
| 5ccb9ba0ec | |||
| f4eaacd0ec | |||
| 34b21fa917 | |||
| 2d98d4543f | |||
| 8c46fddd03 | |||
| 3a00643d5b | |||
| eb73e024e1 | |||
| a4b06c2219 | |||
| 5ccaa094a0 | |||
| fc7e4d0e5c | |||
| 583cd870d8 | |||
| 2ca2d5e62c | |||
| c5c81a2ea8 | |||
| c0ad5880a4 | |||
| 2dc3a4e2c5 | |||
| 3b0d93bcc2 | |||
| eac171ab0f | |||
| 7533f63a06 | |||
| a38917ab26 | |||
| a92b8e5f60 | |||
| 29f34cf23c | |||
| a10f0dc22d |
18
NEWS
18
NEWS
@ -1,6 +1,24 @@
|
|||||||
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.6:
|
||||||
|
|
||||||
|
The 1.90.5 release was unusable due to a number of inter-related issues
|
||||||
|
with the DBus interface and authorization. We also found a number of
|
||||||
|
problems with possible security implications.
|
||||||
|
|
||||||
|
Currently fprintd will do interactive authorization even if this was not
|
||||||
|
requested using the correct DBus method call flag. All API users MUST be
|
||||||
|
updated to set the flag as it will be enabled in the future!
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
- Fix fprintd DBus configuration
|
||||||
|
- Change details of what requires authorization
|
||||||
|
- Fix various race conditions in pam_fprintd
|
||||||
|
- Permit interactive authorization from fprintd utilities
|
||||||
|
- Do not allow deletion while another operation is ongoing
|
||||||
|
|
||||||
|
|
||||||
Version 1.90.5:
|
Version 1.90.5:
|
||||||
|
|
||||||
The 1.90.4 release contained some bad errors, this release addresses those.
|
The 1.90.4 release contained some bad errors, this release addresses those.
|
||||||
|
|||||||
@ -13,7 +13,9 @@
|
|||||||
<!-- Anyone can talk to the service -->
|
<!-- Anyone can talk to the service -->
|
||||||
<policy context="default">
|
<policy context="default">
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
<allow send_destination="net.reactivated.Fprint"
|
||||||
send_interface="net.reactivated.Fprint"/>
|
send_interface="net.reactivated.Fprint.Manager"/>
|
||||||
|
<allow send_destination="net.reactivated.Fprint"
|
||||||
|
send_interface="net.reactivated.Fprint.Device"/>
|
||||||
|
|
||||||
<!-- Basic D-Bus API stuff -->
|
<!-- Basic D-Bus API stuff -->
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
<allow send_destination="net.reactivated.Fprint"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
project('fprintd', 'c',
|
project('fprintd', 'c',
|
||||||
version: '1.90.5',
|
version: '1.90.6',
|
||||||
license: 'GPLv2+',
|
license: 'GPLv2+',
|
||||||
default_options: [
|
default_options: [
|
||||||
'buildtype=debugoptimized',
|
'buildtype=debugoptimized',
|
||||||
@ -62,6 +62,7 @@ common_cflags = cc.get_supported_arguments([
|
|||||||
add_project_arguments(common_cflags, language: 'c')
|
add_project_arguments(common_cflags, language: 'c')
|
||||||
|
|
||||||
host_system = host_machine.system()
|
host_system = host_machine.system()
|
||||||
|
# NOTE: Bump gdbus-codegen min version once we can depend on 2.64!
|
||||||
glib_min_version = '2.56'
|
glib_min_version = '2.56'
|
||||||
libfprint_min_version = '1.90.1'
|
libfprint_min_version = '1.90.1'
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,7 @@
|
|||||||
#define N_(s) (s)
|
#define N_(s) (s)
|
||||||
|
|
||||||
#include "fingerprint-strings.h"
|
#include "fingerprint-strings.h"
|
||||||
|
#include "pam_fprintd_autoptrs.h"
|
||||||
|
|
||||||
#define DEFAULT_MAX_TRIES 3
|
#define DEFAULT_MAX_TRIES 3
|
||||||
#define DEFAULT_TIMEOUT 30
|
#define DEFAULT_TIMEOUT 30
|
||||||
@ -83,10 +84,8 @@ static bool send_msg(pam_handle_t *pamh, const char *msg, int style)
|
|||||||
const struct pam_message *msgp = &mymsg;
|
const struct pam_message *msgp = &mymsg;
|
||||||
const struct pam_conv *pc;
|
const struct pam_conv *pc;
|
||||||
struct pam_response *resp;
|
struct pam_response *resp;
|
||||||
int r;
|
|
||||||
|
|
||||||
r = pam_get_item(pamh, PAM_CONV, (const void **) &pc);
|
if (pam_get_item(pamh, PAM_CONV, (const void **) &pc) != PAM_SUCCESS)
|
||||||
if (r != PAM_SUCCESS)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!pc || !pc->conv)
|
if (!pc || !pc->conv)
|
||||||
@ -110,39 +109,35 @@ open_device (pam_handle_t *pamh,
|
|||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
bool *has_multiple_devices)
|
bool *has_multiple_devices)
|
||||||
{
|
{
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
pf_auto(sd_bus_error) error = SD_BUS_ERROR_NULL;
|
||||||
sd_bus_message *m = NULL;
|
pf_autoptr(sd_bus_message) m = NULL;
|
||||||
size_t num_devices;
|
size_t num_devices;
|
||||||
const char *path = NULL;
|
const char *path = NULL;
|
||||||
char *ret;
|
|
||||||
const char *s;
|
const char *s;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
*has_multiple_devices = false;
|
*has_multiple_devices = false;
|
||||||
|
|
||||||
r = sd_bus_call_method (bus,
|
if (sd_bus_call_method (bus,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
"/net/reactivated/Fprint/Manager",
|
"/net/reactivated/Fprint/Manager",
|
||||||
"net.reactivated.Fprint.Manager",
|
"net.reactivated.Fprint.Manager",
|
||||||
"GetDevices",
|
"GetDevices",
|
||||||
&error,
|
&error,
|
||||||
&m,
|
&m,
|
||||||
NULL);
|
NULL) < 0) {
|
||||||
if (r < 0) {
|
|
||||||
pam_syslog (pamh, LOG_ERR, "GetDevices failed: %s", error.message);
|
pam_syslog (pamh, LOG_ERR, "GetDevices failed: %s", error.message);
|
||||||
sd_bus_error_free (&error);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_bus_message_enter_container (m, 'a', "o");
|
r = sd_bus_message_enter_container (m, 'a', "o");
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
pam_syslog (pamh, LOG_ERR, "Failed to parse answer from GetDevices(): %d", r);
|
pam_syslog (pamh, LOG_ERR, "Failed to parse answer from GetDevices(): %d", r);
|
||||||
goto out;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_bus_message_read_basic (m, 'o', &path);
|
if (sd_bus_message_read_basic (m, 'o', &path) < 0)
|
||||||
if (r < 0)
|
return NULL;
|
||||||
goto out;
|
|
||||||
|
|
||||||
num_devices = 1;
|
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)
|
||||||
@ -153,22 +148,35 @@ open_device (pam_handle_t *pamh,
|
|||||||
|
|
||||||
sd_bus_message_exit_container (m);
|
sd_bus_message_exit_container (m);
|
||||||
|
|
||||||
out:
|
return strdup (path);
|
||||||
ret = path ? strdup (path) : NULL;
|
|
||||||
sd_bus_message_unref (m);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
char *dev;
|
||||||
|
bool has_multiple_devices;
|
||||||
|
|
||||||
unsigned max_tries;
|
unsigned max_tries;
|
||||||
char *result;
|
char *result;
|
||||||
bool timed_out;
|
bool timed_out;
|
||||||
bool is_swipe;
|
bool is_swipe;
|
||||||
|
bool verify_started;
|
||||||
|
int verify_ret;
|
||||||
pam_handle_t *pamh;
|
pam_handle_t *pamh;
|
||||||
|
|
||||||
char *driver;
|
char *driver;
|
||||||
} verify_data;
|
} verify_data;
|
||||||
|
|
||||||
|
static void
|
||||||
|
verify_data_free (verify_data *data)
|
||||||
|
{
|
||||||
|
free (data->result);
|
||||||
|
free (data->driver);
|
||||||
|
free (data->dev);
|
||||||
|
free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
PF_DEFINE_AUTOPTR_CLEANUP_FUNC (verify_data, verify_data_free)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
verify_result (sd_bus_message *m,
|
verify_result (sd_bus_message *m,
|
||||||
void *userdata,
|
void *userdata,
|
||||||
@ -193,15 +201,29 @@ verify_result (sd_bus_message *m,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data->verify_started) {
|
||||||
|
pam_syslog (data->pamh, LOG_ERR, "Unexpected VerifyResult '%s', %"PRIu64" signal", result, done);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (data->pamh, LOG_DEBUG, "Verify result: %s (done: %d)", result, done ? 1 : 0);
|
pam_syslog (data->pamh, LOG_DEBUG, "Verify result: %s (done: %d)", result, done ? 1 : 0);
|
||||||
|
|
||||||
|
if (data->result) {
|
||||||
|
free (data->result);
|
||||||
|
data->result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
data->result = strdup (result);
|
data->result = strdup (result);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = verify_result_str_to_msg (result, data->is_swipe);
|
msg = verify_result_str_to_msg (result, data->is_swipe);
|
||||||
|
if (!msg) {
|
||||||
|
data->result = strdup ("Protocol error with fprintd!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
send_err_msg (data->pamh, msg);
|
send_err_msg (data->pamh, msg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -214,18 +236,26 @@ verify_finger_selected (sd_bus_message *m,
|
|||||||
{
|
{
|
||||||
verify_data *data = userdata;
|
verify_data *data = userdata;
|
||||||
const char *finger_name = NULL;
|
const char *finger_name = NULL;
|
||||||
char *msg;
|
pf_autofree char *msg = NULL;
|
||||||
|
|
||||||
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);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!data->verify_started) {
|
||||||
|
pam_syslog (data->pamh, LOG_ERR, "Unexpected VerifyFingerSelected %s signal", finger_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
msg = finger_str_to_msg(finger_name, data->driver, data->is_swipe);
|
msg = finger_str_to_msg(finger_name, data->driver, data->is_swipe);
|
||||||
|
if (!msg) {
|
||||||
|
data->result = strdup ("Protocol error with fprintd!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (data->pamh, LOG_DEBUG, "verify_finger_selected %s", msg);
|
pam_syslog (data->pamh, LOG_DEBUG, "verify_finger_selected %s", msg);
|
||||||
send_info_msg (data->pamh, msg);
|
send_info_msg (data->pamh, msg);
|
||||||
free (msg);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -240,7 +270,7 @@ get_property_string (sd_bus *bus,
|
|||||||
sd_bus_error *error,
|
sd_bus_error *error,
|
||||||
char **ret) {
|
char **ret) {
|
||||||
|
|
||||||
sd_bus_message *reply = NULL;
|
pf_autoptr(sd_bus_message) reply = NULL;
|
||||||
const char *s;
|
const char *s;
|
||||||
char *n;
|
char *n;
|
||||||
int r;
|
int r;
|
||||||
@ -251,121 +281,133 @@ get_property_string (sd_bus *bus,
|
|||||||
|
|
||||||
r = sd_bus_message_enter_container(reply, 'v', "s");
|
r = sd_bus_message_enter_container(reply, 'v', "s");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
return sd_bus_error_set_errno(error, r);
|
||||||
|
|
||||||
r = sd_bus_message_read_basic(reply, 's', &s);
|
r = sd_bus_message_read_basic(reply, 's', &s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
return sd_bus_error_set_errno(error, r);
|
||||||
|
|
||||||
n = strdup(s);
|
n = strdup(s);
|
||||||
if (!n) {
|
if (!n) {
|
||||||
r = -ENOMEM;
|
return sd_bus_error_set_errno(error, -ENOMEM);
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sd_bus_message_unref (reply);
|
|
||||||
|
|
||||||
*ret = n;
|
*ret = n;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
fail:
|
|
||||||
if (reply != NULL)
|
static int verify_started_cb (sd_bus_message *m,
|
||||||
sd_bus_message_unref (reply);
|
void *userdata,
|
||||||
return sd_bus_error_set_errno(error, r);
|
sd_bus_error *ret_error) {
|
||||||
|
const sd_bus_error *error = sd_bus_message_get_error (m);
|
||||||
|
verify_data *data = userdata;
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
if (sd_bus_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints")) {
|
||||||
|
pam_syslog (data->pamh, LOG_DEBUG, "No prints enrolled");
|
||||||
|
data->verify_ret = PAM_USER_UNKNOWN;
|
||||||
|
} else {
|
||||||
|
data->verify_ret = PAM_AUTH_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart failed: %s", error->message);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart completed successfully");
|
||||||
|
|
||||||
|
data->verify_started = true;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
do_verify (pam_handle_t *pamh,
|
do_verify (sd_bus *bus,
|
||||||
sd_bus *bus,
|
verify_data *data)
|
||||||
const char *dev,
|
|
||||||
bool has_multiple_devices)
|
|
||||||
{
|
{
|
||||||
verify_data *data;
|
pf_autoptr(sd_bus_slot) verify_status_slot = NULL;
|
||||||
sd_bus_slot *verify_status_slot, *verify_finger_selected_slot;
|
pf_autoptr(sd_bus_slot) verify_finger_selected_slot = NULL;
|
||||||
char *scan_type = NULL;
|
pf_autofree char *scan_type = NULL;
|
||||||
int ret;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
data = calloc (1, sizeof(verify_data));
|
|
||||||
data->max_tries = max_tries;
|
|
||||||
data->pamh = pamh;
|
|
||||||
|
|
||||||
/* Get some properties for the device */
|
/* Get some properties for the device */
|
||||||
r = get_property_string (bus,
|
r = get_property_string (bus,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
data->dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
"scan-type",
|
"scan-type",
|
||||||
NULL,
|
NULL,
|
||||||
&scan_type);
|
&scan_type);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
pam_syslog (data->pamh, LOG_ERR, "Failed to get scan-type for %s: %d", dev, r);
|
pam_syslog (data->pamh, LOG_ERR, "Failed to get scan-type for %s: %d", data->dev, r);
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (data->pamh, LOG_DEBUG, "scan-type for %s: %s", dev, scan_type);
|
pam_syslog (data->pamh, LOG_DEBUG, "scan-type for %s: %s", data->dev, scan_type);
|
||||||
if (str_equal (scan_type, "swipe"))
|
if (str_equal (scan_type, "swipe"))
|
||||||
data->is_swipe = true;
|
data->is_swipe = true;
|
||||||
free (scan_type);
|
|
||||||
|
|
||||||
if (has_multiple_devices) {
|
if (data->has_multiple_devices) {
|
||||||
get_property_string (bus,
|
get_property_string (bus,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
data->dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
"name",
|
"name",
|
||||||
NULL,
|
NULL,
|
||||||
&data->driver);
|
&data->driver);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
pam_syslog (data->pamh, LOG_ERR, "Failed to get driver name for %s: %d", dev, r);
|
pam_syslog (data->pamh, LOG_ERR, "Failed to get driver name for %s: %d", data->dev, r);
|
||||||
if (debug && r == 0)
|
if (debug && r == 0)
|
||||||
pam_syslog (data->pamh, LOG_DEBUG, "driver name for %s: %s", dev, data->driver);
|
pam_syslog (data->pamh, LOG_DEBUG, "driver name for %s: %s", data->dev, data->driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_status_slot = NULL;
|
|
||||||
sd_bus_match_signal (bus,
|
sd_bus_match_signal (bus,
|
||||||
&verify_status_slot,
|
&verify_status_slot,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
data->dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
"VerifyStatus",
|
"VerifyStatus",
|
||||||
verify_result,
|
verify_result,
|
||||||
data);
|
data);
|
||||||
|
|
||||||
verify_finger_selected_slot = NULL;
|
|
||||||
sd_bus_match_signal (bus,
|
sd_bus_match_signal (bus,
|
||||||
&verify_finger_selected_slot,
|
&verify_finger_selected_slot,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
data->dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
"VerifyFingerSelected",
|
"VerifyFingerSelected",
|
||||||
verify_finger_selected,
|
verify_finger_selected,
|
||||||
data);
|
data);
|
||||||
|
|
||||||
ret = PAM_AUTH_ERR;
|
while (data->max_tries > 0) {
|
||||||
|
|
||||||
while (ret == PAM_AUTH_ERR && data->max_tries > 0) {
|
|
||||||
uint64_t verification_end = now () + (timeout * USEC_PER_SEC);
|
uint64_t verification_end = now () + (timeout * USEC_PER_SEC);
|
||||||
sd_bus_message *m = NULL;
|
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
||||||
|
|
||||||
data->timed_out = false;
|
data->timed_out = false;
|
||||||
|
data->verify_started = false;
|
||||||
|
data->verify_ret = PAM_INCOMPLETE;
|
||||||
|
|
||||||
r = sd_bus_call_method (bus,
|
free (data->result);
|
||||||
|
data->result = NULL;
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
pam_syslog (data->pamh, LOG_DEBUG, "About to call VerifyStart");
|
||||||
|
|
||||||
|
r = sd_bus_call_method_async (bus,
|
||||||
|
NULL,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
data->dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
"VerifyStart",
|
"VerifyStart",
|
||||||
&error,
|
verify_started_cb,
|
||||||
&m,
|
data,
|
||||||
"s",
|
"s",
|
||||||
"any");
|
"any");
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (sd_bus_error_has_name (&error, "net.reactivated.Fprint.Error.NoEnrolledPrints"))
|
|
||||||
ret = PAM_USER_UNKNOWN;
|
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (pamh, LOG_DEBUG, "VerifyStart failed: %s", error.message);
|
pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart call failed: %d", r);
|
||||||
sd_bus_error_free (&error);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,29 +421,38 @@ do_verify (pam_handle_t *pamh,
|
|||||||
r = sd_bus_process (bus, NULL);
|
r = sd_bus_process (bus, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
break;
|
break;
|
||||||
|
if (data->verify_ret != PAM_INCOMPLETE)
|
||||||
|
break;
|
||||||
|
if (!data->verify_started)
|
||||||
|
continue;
|
||||||
if (data->result != NULL)
|
if (data->result != NULL)
|
||||||
break;
|
break;
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
pam_syslog(pamh, LOG_DEBUG, "Waiting for %"PRId64" seconds (%"PRId64" usecs)",
|
pam_syslog(data->pamh, LOG_DEBUG,
|
||||||
|
"Waiting for %"PRId64" seconds (%"PRId64" usecs)",
|
||||||
wait_time / USEC_PER_SEC,
|
wait_time / USEC_PER_SEC,
|
||||||
wait_time);
|
wait_time);
|
||||||
}
|
}
|
||||||
r = sd_bus_wait (bus, wait_time);
|
if (sd_bus_wait (bus, wait_time) < 0)
|
||||||
if (r < 0)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->verify_ret != PAM_INCOMPLETE) {
|
||||||
|
return data->verify_ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (now () >= verification_end) {
|
if (now () >= verification_end) {
|
||||||
data->timed_out = true;
|
data->timed_out = true;
|
||||||
send_info_msg (data->pamh, _("Verification timed out"));
|
send_info_msg (data->pamh, _("Verification timed out"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore errors from VerifyStop */
|
/* Ignore errors from VerifyStop */
|
||||||
|
data->verify_started = false;
|
||||||
sd_bus_call_method (bus,
|
sd_bus_call_method (bus,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
data->dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
"VerifyStop",
|
"VerifyStop",
|
||||||
NULL,
|
NULL,
|
||||||
@ -410,43 +461,28 @@ do_verify (pam_handle_t *pamh,
|
|||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
if (data->timed_out) {
|
if (data->timed_out) {
|
||||||
ret = PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
if (str_equal (data->result, "verify-no-match")) {
|
if (str_equal (data->result, "verify-no-match")) {
|
||||||
send_err_msg (data->pamh, "Failed to match fingerprint");
|
send_err_msg (data->pamh, "Failed to match fingerprint");
|
||||||
ret = PAM_AUTH_ERR;
|
|
||||||
} else if (str_equal (data->result, "verify-match")) {
|
} else if (str_equal (data->result, "verify-match")) {
|
||||||
ret = PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
break;
|
|
||||||
} else if (str_equal (data->result, "verify-unknown-error")) {
|
} else if (str_equal (data->result, "verify-unknown-error")) {
|
||||||
ret = PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
} else if (str_equal (data->result, "verify-disconnected")) {
|
} else if (str_equal (data->result, "verify-disconnected")) {
|
||||||
ret = PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
break;
|
|
||||||
} else {
|
} else {
|
||||||
send_err_msg (data->pamh, _("An unknown error occurred"));
|
send_err_msg (data->pamh, _("An unknown error occurred"));
|
||||||
ret = PAM_AUTH_ERR;
|
return PAM_AUTH_ERR;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
free (data->result);
|
|
||||||
data->result = NULL;
|
|
||||||
}
|
}
|
||||||
data->max_tries--;
|
data->max_tries--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->max_tries == 0)
|
if (data->max_tries == 0)
|
||||||
ret = PAM_MAXTRIES;
|
return PAM_MAXTRIES;
|
||||||
|
|
||||||
sd_bus_slot_unref (verify_status_slot);
|
return PAM_AUTH_ERR;
|
||||||
sd_bus_slot_unref (verify_finger_selected_slot);
|
|
||||||
|
|
||||||
if (data->result)
|
|
||||||
free (data->result);
|
|
||||||
free (data->driver);
|
|
||||||
free (data);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -455,8 +491,8 @@ user_has_prints (pam_handle_t *pamh,
|
|||||||
const char *dev,
|
const char *dev,
|
||||||
const char *username)
|
const char *username)
|
||||||
{
|
{
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
pf_auto(sd_bus_error) error = SD_BUS_ERROR_NULL;
|
||||||
sd_bus_message *m = NULL;
|
pf_autoptr(sd_bus_message) m = NULL;
|
||||||
size_t num_fingers = 0;
|
size_t num_fingers = 0;
|
||||||
const char *s;
|
const char *s;
|
||||||
int r;
|
int r;
|
||||||
@ -478,23 +514,19 @@ user_has_prints (pam_handle_t *pamh,
|
|||||||
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);
|
||||||
}
|
}
|
||||||
sd_bus_error_free (&error);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
goto out;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_fingers = 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);
|
||||||
|
|
||||||
out:
|
|
||||||
sd_bus_message_unref (m);
|
|
||||||
return (num_fingers > 0);
|
return (num_fingers > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,10 +535,9 @@ release_device (pam_handle_t *pamh,
|
|||||||
sd_bus *bus,
|
sd_bus *bus,
|
||||||
const char *dev)
|
const char *dev)
|
||||||
{
|
{
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
pf_auto(sd_bus_error) error = SD_BUS_ERROR_NULL;
|
||||||
int r;
|
|
||||||
|
|
||||||
r = sd_bus_call_method (bus,
|
if (sd_bus_call_method (bus,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
@ -514,10 +545,8 @@ release_device (pam_handle_t *pamh,
|
|||||||
&error,
|
&error,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL) < 0) {
|
||||||
if (r < 0) {
|
|
||||||
pam_syslog (pamh, LOG_ERR, "ReleaseDevice failed: %s", error.message);
|
pam_syslog (pamh, LOG_ERR, "ReleaseDevice failed: %s", error.message);
|
||||||
sd_bus_error_free (&error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,10 +556,9 @@ claim_device (pam_handle_t *pamh,
|
|||||||
const char *dev,
|
const char *dev,
|
||||||
const char *username)
|
const char *username)
|
||||||
{
|
{
|
||||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
pf_auto(sd_bus_error) error = SD_BUS_ERROR_NULL;
|
||||||
int r;
|
|
||||||
|
|
||||||
r = sd_bus_call_method (bus,
|
if (sd_bus_call_method (bus,
|
||||||
"net.reactivated.Fprint",
|
"net.reactivated.Fprint",
|
||||||
dev,
|
dev,
|
||||||
"net.reactivated.Fprint.Device",
|
"net.reactivated.Fprint.Device",
|
||||||
@ -538,53 +566,88 @@ claim_device (pam_handle_t *pamh,
|
|||||||
&error,
|
&error,
|
||||||
NULL,
|
NULL,
|
||||||
"s",
|
"s",
|
||||||
username);
|
username) < 0) {
|
||||||
if (r < 0) {
|
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (pamh, LOG_DEBUG, "failed to claim device %s", error.message);
|
pam_syslog (pamh, LOG_DEBUG, "failed to claim device %s", error.message);
|
||||||
sd_bus_error_free (&error);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
name_owner_changed (sd_bus_message *m,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *ret_error)
|
||||||
|
{
|
||||||
|
verify_data *data = userdata;
|
||||||
|
const char *name = NULL;
|
||||||
|
const char *old_owner = NULL;
|
||||||
|
const char *new_owner = NULL;
|
||||||
|
|
||||||
|
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);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp (name, "net.reactivated.Fprint") != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Name owner for fprintd changed, give up as we might start listening
|
||||||
|
* 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");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_auth(pam_handle_t *pamh, const char *username)
|
static int do_auth(pam_handle_t *pamh, const char *username)
|
||||||
{
|
{
|
||||||
char *dev;
|
|
||||||
bool have_prints;
|
bool have_prints;
|
||||||
bool has_multiple_devices;
|
pf_autoptr(verify_data) data = NULL;
|
||||||
int ret = PAM_AUTHINFO_UNAVAIL;
|
pf_autoptr(sd_bus) bus = NULL;
|
||||||
sd_bus *bus = NULL;
|
pf_autoptr(sd_bus_slot) name_owner_changed_slot = NULL;
|
||||||
|
|
||||||
|
data = calloc (1, sizeof(verify_data));
|
||||||
|
data->max_tries = max_tries;
|
||||||
|
data->pamh = pamh;
|
||||||
|
|
||||||
if (sd_bus_open_system (&bus) < 0) {
|
if (sd_bus_open_system (&bus) < 0) {
|
||||||
pam_syslog (pamh, LOG_ERR, "Error with getting the bus: %d", errno);
|
pam_syslog (pamh, LOG_ERR, "Error with getting the bus: %d", errno);
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = open_device (pamh, bus, &has_multiple_devices);
|
name_owner_changed_slot = NULL;
|
||||||
if (dev == NULL) {
|
sd_bus_match_signal (bus,
|
||||||
sd_bus_unref (bus);
|
&name_owner_changed_slot,
|
||||||
|
"org.freedesktop.DBus",
|
||||||
|
"/org/freedesktop/DBus",
|
||||||
|
"org.freedesktop.DBus",
|
||||||
|
"NameOwnerChanged",
|
||||||
|
name_owner_changed,
|
||||||
|
data);
|
||||||
|
|
||||||
|
data->dev = open_device (pamh, bus, &data->has_multiple_devices);
|
||||||
|
if (data->dev == NULL) {
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
have_prints = user_has_prints (pamh, bus, dev, username);
|
have_prints = user_has_prints (pamh, bus, data->dev, username);
|
||||||
if (debug)
|
if (debug)
|
||||||
pam_syslog (pamh, LOG_DEBUG, "prints registered: %s\n", have_prints ? "yes" : "no");
|
pam_syslog (pamh, LOG_DEBUG, "prints registered: %s\n", have_prints ? "yes" : "no");
|
||||||
|
|
||||||
if (!have_prints)
|
if (!have_prints)
|
||||||
goto out;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
|
|
||||||
if (claim_device (pamh, bus, dev, username)) {
|
if (claim_device (pamh, bus, data->dev, username)) {
|
||||||
ret = do_verify (pamh, bus, dev, has_multiple_devices);
|
int ret = do_verify (bus, data);
|
||||||
release_device (pamh, bus, dev);
|
release_device (pamh, bus, data->dev);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
free (dev);
|
|
||||||
sd_bus_unref (bus);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -614,7 +677,6 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
|
|||||||
{
|
{
|
||||||
const char *username;
|
const char *username;
|
||||||
int i;
|
int i;
|
||||||
int r;
|
|
||||||
|
|
||||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||||
@ -622,8 +684,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
|
|||||||
if (is_remote (pamh))
|
if (is_remote (pamh))
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
|
|
||||||
r = pam_get_user(pamh, &username, NULL);
|
if (pam_get_user(pamh, &username, NULL) != PAM_SUCCESS)
|
||||||
if (r != PAM_SUCCESS)
|
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
|
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
@ -674,9 +735,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = do_auth(pamh, username);
|
return do_auth(pamh, username);
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
|
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
|
||||||
|
|||||||
60
pam/pam_fprintd_autoptrs.h
Normal file
60
pam/pam_fprintd_autoptrs.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* pam_fprint: PAM module for fingerprint authentication through fprintd
|
||||||
|
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Define auto-pointers functions, based on GLib Macros */
|
||||||
|
|
||||||
|
#define _CLEANUP_FUNC(func) __attribute__((cleanup(func)))
|
||||||
|
|
||||||
|
#define _PF_AUTOPTR_FUNC_NAME(TypeName) pf_autoptr_cleanup_##TypeName
|
||||||
|
#define _PF_AUTOPTR_TYPENAME(TypeName) TypeName##_pf_autoptr
|
||||||
|
|
||||||
|
#define PF_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, cleanup) \
|
||||||
|
typedef TypeName *_PF_AUTOPTR_TYPENAME (TypeName); \
|
||||||
|
static __attribute__((__unused__)) inline void \
|
||||||
|
_PF_AUTOPTR_FUNC_NAME (TypeName) (TypeName **_ptr) \
|
||||||
|
{ if (_ptr) (cleanup) (*_ptr); }
|
||||||
|
|
||||||
|
#define PF_DEFINE_AUTO_CLEAN_FUNC(TypeName, cleanup) \
|
||||||
|
static __attribute__((__unused__)) inline void \
|
||||||
|
_PF_AUTOPTR_FUNC_NAME (TypeName) (TypeName *_ptr) \
|
||||||
|
{ cleanup (_ptr); }
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
autoptr_cleanup_generic_free (void *p)
|
||||||
|
{
|
||||||
|
void **pp = (void**)p;
|
||||||
|
free (*pp);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define pf_autofree _CLEANUP_FUNC (autoptr_cleanup_generic_free)
|
||||||
|
#define pf_autoptr(TypeName) \
|
||||||
|
_CLEANUP_FUNC (_PF_AUTOPTR_FUNC_NAME (TypeName)) \
|
||||||
|
_PF_AUTOPTR_TYPENAME (TypeName)
|
||||||
|
#define pf_auto(TypeName) \
|
||||||
|
_CLEANUP_FUNC (_PF_AUTOPTR_FUNC_NAME (TypeName)) TypeName
|
||||||
|
|
||||||
|
PF_DEFINE_AUTOPTR_CLEANUP_FUNC (sd_bus, sd_bus_unref)
|
||||||
|
PF_DEFINE_AUTOPTR_CLEANUP_FUNC (sd_bus_message, sd_bus_message_unref)
|
||||||
|
PF_DEFINE_AUTOPTR_CLEANUP_FUNC (sd_bus_slot, sd_bus_slot_unref)
|
||||||
|
|
||||||
|
PF_DEFINE_AUTO_CLEAN_FUNC (sd_bus_error, sd_bus_error_free)
|
||||||
110
src/dbus-interactive-auth.patch
Normal file
110
src/dbus-interactive-auth.patch
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
--- a/src/fprintd-dbus.c 2020-12-04 16:38:28.527712626 +0100
|
||||||
|
+++ b/src/fprintd-dbus.c 2020-12-04 16:40:03.561692619 +0100
|
||||||
|
@@ -1149,7 +1149,7 @@
|
||||||
|
"ListEnrolledFingers",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_username),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
callback,
|
||||||
|
@@ -1213,7 +1213,7 @@
|
||||||
|
"ListEnrolledFingers",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_username),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
@@ -1253,7 +1253,7 @@
|
||||||
|
"DeleteEnrolledFingers",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_username),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
callback,
|
||||||
|
@@ -1312,7 +1312,7 @@
|
||||||
|
"DeleteEnrolledFingers",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_username),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
@@ -1348,7 +1348,7 @@
|
||||||
|
g_dbus_proxy_call (G_DBUS_PROXY (proxy),
|
||||||
|
"DeleteEnrolledFingers2",
|
||||||
|
g_variant_new ("()"),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
callback,
|
||||||
|
@@ -1404,7 +1404,7 @@
|
||||||
|
_ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
|
||||||
|
"DeleteEnrolledFingers2",
|
||||||
|
g_variant_new ("()"),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
@@ -1443,7 +1443,7 @@
|
||||||
|
"Claim",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_username),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
callback,
|
||||||
|
@@ -1502,7 +1502,7 @@
|
||||||
|
"Claim",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_username),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
@@ -1633,7 +1633,7 @@
|
||||||
|
"VerifyStart",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_finger_name),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
callback,
|
||||||
|
@@ -1692,7 +1692,7 @@
|
||||||
|
"VerifyStart",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_finger_name),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
|
@@ -1823,7 +1823,7 @@
|
||||||
|
"EnrollStart",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_finger_name),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
callback,
|
||||||
|
@@ -1882,7 +1882,7 @@
|
||||||
|
"EnrollStart",
|
||||||
|
g_variant_new ("(s)",
|
||||||
|
arg_finger_name),
|
||||||
|
- G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
+ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
|
||||||
|
-1,
|
||||||
|
cancellable,
|
||||||
|
error);
|
||||||
342
src/device.c
342
src/device.c
@ -34,16 +34,16 @@
|
|||||||
|
|
||||||
static const char *FINGERS_NAMES[] = {
|
static const char *FINGERS_NAMES[] = {
|
||||||
[FP_FINGER_UNKNOWN] = "unknown",
|
[FP_FINGER_UNKNOWN] = "unknown",
|
||||||
"left-thumb",
|
[FP_FINGER_LEFT_THUMB] = "left-thumb",
|
||||||
"left-index-finger",
|
[FP_FINGER_LEFT_INDEX] = "left-index-finger",
|
||||||
"left-middle-finger",
|
[FP_FINGER_LEFT_MIDDLE] = "left-middle-finger",
|
||||||
"left-ring-finger",
|
[FP_FINGER_LEFT_RING] = "left-ring-finger",
|
||||||
"left-little-finger",
|
[FP_FINGER_LEFT_LITTLE] = "left-little-finger",
|
||||||
"right-thumb",
|
[FP_FINGER_RIGHT_THUMB] = "right-thumb",
|
||||||
"right-index-finger",
|
[FP_FINGER_RIGHT_INDEX] = "right-index-finger",
|
||||||
"right-middle-finger",
|
[FP_FINGER_RIGHT_MIDDLE] = "right-middle-finger",
|
||||||
"right-ring-finger",
|
[FP_FINGER_RIGHT_RING] = "right-ring-finger",
|
||||||
"right-little-finger"
|
[FP_FINGER_RIGHT_LITTLE] = "right-little-finger"
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fprint_device_dbus_skeleton_iface_init (FprintDBusDeviceIface *);
|
static void fprint_device_dbus_skeleton_iface_init (FprintDBusDeviceIface *);
|
||||||
@ -60,12 +60,14 @@ typedef enum {
|
|||||||
ACTION_ENROLL,
|
ACTION_ENROLL,
|
||||||
ACTION_OPEN,
|
ACTION_OPEN,
|
||||||
ACTION_CLOSE,
|
ACTION_CLOSE,
|
||||||
|
ACTION_DELETE,
|
||||||
} FprintDeviceAction;
|
} FprintDeviceAction;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
STATE_CLAIMED,
|
STATE_CLAIMED,
|
||||||
STATE_UNCLAIMED,
|
STATE_UNCLAIMED,
|
||||||
STATE_IGNORED,
|
STATE_AUTO_CLAIM,
|
||||||
|
STATE_ANYTIME,
|
||||||
} FprintDeviceClaimState;
|
} FprintDeviceClaimState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -366,22 +368,22 @@ guint32 _fprint_device_get_id(FprintDevice *rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
finger_num_to_name (int finger_num)
|
fp_finger_to_name (FpFinger finger)
|
||||||
{
|
{
|
||||||
if (finger_num == -1)
|
if (finger == FP_FINGER_UNKNOWN)
|
||||||
return "any";
|
return "any";
|
||||||
if (!FP_FINGER_IS_VALID (finger_num))
|
if (!FP_FINGER_IS_VALID (finger))
|
||||||
return NULL;
|
return NULL;
|
||||||
return FINGERS_NAMES[finger_num];
|
return FINGERS_NAMES[finger];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static FpFinger
|
||||||
finger_name_to_num (const char *finger_name)
|
finger_name_to_fp_finger (const char *finger_name)
|
||||||
{
|
{
|
||||||
guint i;
|
FpFinger i;
|
||||||
|
|
||||||
if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any"))
|
if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any"))
|
||||||
return -1;
|
return FP_FINGER_UNKNOWN;
|
||||||
|
|
||||||
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++) {
|
for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++) {
|
||||||
if (g_str_equal (finger_name, FINGERS_NAMES[i]))
|
if (g_str_equal (finger_name, FINGERS_NAMES[i]))
|
||||||
@ -389,7 +391,7 @@ finger_name_to_num (const char *finger_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Invalid, let's try that */
|
/* Invalid, let's try that */
|
||||||
return -1;
|
return FP_FINGER_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
@ -464,21 +466,78 @@ enroll_result_to_name (gboolean completed, gboolean enrolled, GError *error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FprintDevicePermission
|
||||||
|
get_permissions_for_invocation (GDBusMethodInvocation *invocation)
|
||||||
|
{
|
||||||
|
FprintDevicePermission required_perms;
|
||||||
|
const char *method_name;
|
||||||
|
|
||||||
|
required_perms = FPRINT_DEVICE_PERMISSION_NONE;
|
||||||
|
method_name = g_dbus_method_invocation_get_method_name (invocation);
|
||||||
|
|
||||||
|
if (g_str_equal (method_name, "Claim")) {
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
||||||
|
} else if (g_str_equal (method_name, "DeleteEnrolledFingers")) {
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
||||||
|
} else if (g_str_equal (method_name, "DeleteEnrolledFingers2")) {
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
||||||
|
} else if (g_str_equal (method_name, "EnrollStart")) {
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
||||||
|
} else if (g_str_equal (method_name, "ListEnrolledFingers")) {
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
||||||
|
} else if (g_str_equal (method_name, "VerifyStart")) {
|
||||||
|
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
||||||
|
} else if (g_str_equal (method_name, "Release")) {
|
||||||
|
} else if (g_str_equal (method_name, "EnrollStop")) {
|
||||||
|
} else if (g_str_equal (method_name, "VerifyStop")) {
|
||||||
|
/* Don't require permissiong for for release/stop operations.
|
||||||
|
* We are authenticated already if we could start, and we don't
|
||||||
|
* want to end up authorizing interactively again.
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return required_perms;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FprintDeviceClaimState
|
||||||
|
get_claim_state_for_invocation (GDBusMethodInvocation *invocation)
|
||||||
|
{
|
||||||
|
const char *method_name;
|
||||||
|
|
||||||
|
method_name = g_dbus_method_invocation_get_method_name (invocation);
|
||||||
|
|
||||||
|
if (g_str_equal (method_name, "Claim")) {
|
||||||
|
return STATE_UNCLAIMED;
|
||||||
|
} else if (g_str_equal (method_name, "DeleteEnrolledFingers")) {
|
||||||
|
return STATE_AUTO_CLAIM;
|
||||||
|
} else if (g_str_equal (method_name, "ListEnrolledFingers")) {
|
||||||
|
return STATE_ANYTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATE_CLAIMED;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
_fprint_device_check_claimed (FprintDevice *rdev,
|
_fprint_device_check_claimed (FprintDevice *rdev,
|
||||||
GDBusMethodInvocation *invocation,
|
GDBusMethodInvocation *invocation,
|
||||||
FprintDeviceClaimState requested_state,
|
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
||||||
g_autoptr(SessionData) session = NULL;
|
g_autoptr(SessionData) session = NULL;
|
||||||
|
FprintDeviceClaimState requested_state;
|
||||||
const char *sender;
|
const char *sender;
|
||||||
gboolean retval;
|
|
||||||
|
|
||||||
if (requested_state == STATE_IGNORED)
|
requested_state = get_claim_state_for_invocation (invocation);
|
||||||
|
|
||||||
|
if (requested_state == STATE_ANYTIME)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
session = session_data_get (priv);
|
session = session_data_get (priv);
|
||||||
|
if (requested_state == STATE_AUTO_CLAIM)
|
||||||
|
requested_state = session ? STATE_CLAIMED : STATE_UNCLAIMED;
|
||||||
|
|
||||||
if (requested_state == STATE_UNCLAIMED) {
|
if (requested_state == STATE_UNCLAIMED) {
|
||||||
/* Is it already claimed? */
|
/* Is it already claimed? */
|
||||||
@ -501,14 +560,14 @@ _fprint_device_check_claimed (FprintDevice *rdev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sender = g_dbus_method_invocation_get_sender (invocation);
|
sender = g_dbus_method_invocation_get_sender (invocation);
|
||||||
retval = g_str_equal (sender, session->sender);
|
|
||||||
|
|
||||||
if (retval == FALSE || session->invocation != NULL) {
|
if (!g_str_equal (sender, session->sender) || session->invocation != NULL) {
|
||||||
g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
_("Device already in use by another user"));
|
_("Device already in use by another user"));
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@ -519,7 +578,7 @@ _fprint_device_check_polkit_for_action (FprintDevice *rdev,
|
|||||||
{
|
{
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
||||||
const char *sender;
|
const char *sender;
|
||||||
g_autoptr(GError) _error = NULL;
|
g_autoptr(GError) local_error = NULL;
|
||||||
g_autoptr(PolkitAuthorizationResult) result = NULL;
|
g_autoptr(PolkitAuthorizationResult) result = NULL;
|
||||||
g_autoptr(PolkitSubject) subject = NULL;
|
g_autoptr(PolkitSubject) subject = NULL;
|
||||||
|
|
||||||
@ -532,11 +591,11 @@ _fprint_device_check_polkit_for_action (FprintDevice *rdev,
|
|||||||
action,
|
action,
|
||||||
NULL,
|
NULL,
|
||||||
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
|
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
|
||||||
NULL, &_error);
|
NULL, &local_error);
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
g_set_error (error, FPRINT_ERROR,
|
g_set_error (error, FPRINT_ERROR,
|
||||||
FPRINT_ERROR_PERMISSION_DENIED,
|
FPRINT_ERROR_PERMISSION_DENIED,
|
||||||
"Not Authorized: %s", _error->message);
|
"Not Authorized: %s", local_error->message);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -779,13 +838,14 @@ static gboolean fprint_device_claim (FprintDBusDevice *dbus_dev,
|
|||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
char *sender, *user;
|
char *sender, *user;
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_UNCLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
user = g_object_steal_qdata (G_OBJECT (invocation), quark_auth_user);
|
user = g_object_steal_qdata (G_OBJECT (invocation), quark_auth_user);
|
||||||
g_assert (user);
|
g_assert (user);
|
||||||
|
g_assert (g_str_equal (username, "") || g_str_equal (user, username));
|
||||||
|
|
||||||
sender = g_strdup (g_dbus_method_invocation_get_sender (invocation));
|
sender = g_strdup (g_dbus_method_invocation_get_sender (invocation));
|
||||||
_fprint_device_add_client (rdev, sender);
|
_fprint_device_add_client (rdev, sender);
|
||||||
@ -838,7 +898,7 @@ static gboolean fprint_device_release (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);
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -849,6 +909,8 @@ static gboolean fprint_device_release (FprintDBusDevice *dbus_dev,
|
|||||||
} else if (priv->current_action == ACTION_IDENTIFY ||
|
} else if (priv->current_action == ACTION_IDENTIFY ||
|
||||||
priv->current_action == ACTION_VERIFY) {
|
priv->current_action == ACTION_VERIFY) {
|
||||||
g_warning("Verification was in progress, stopping it");
|
g_warning("Verification was in progress, stopping it");
|
||||||
|
} else if (priv->current_action == ACTION_DELETE) {
|
||||||
|
g_warning("Deletion was in progress, stopping it");
|
||||||
}
|
}
|
||||||
|
|
||||||
g_cancellable_cancel (priv->current_cancellable);
|
g_cancellable_cancel (priv->current_cancellable);
|
||||||
@ -893,6 +955,48 @@ static void report_verify_status (FprintDevice *rdev,
|
|||||||
session->verify_status_reported = TRUE;
|
session->verify_status_reported = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean can_start_action(FprintDevice *rdev, GError **error) {
|
||||||
|
FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
|
||||||
|
|
||||||
|
switch (priv->current_action) {
|
||||||
|
case ACTION_NONE:
|
||||||
|
return TRUE;
|
||||||
|
case ACTION_ENROLL:
|
||||||
|
g_set_error (error,
|
||||||
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
|
"Enrollment already in progress");
|
||||||
|
break;
|
||||||
|
case ACTION_IDENTIFY:
|
||||||
|
case ACTION_VERIFY:
|
||||||
|
g_set_error (error,
|
||||||
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
|
"Enrollment already in progress");
|
||||||
|
break;
|
||||||
|
case ACTION_OPEN:
|
||||||
|
g_set_error (error,
|
||||||
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
|
"Claim already in progress");
|
||||||
|
break;
|
||||||
|
case ACTION_CLOSE:
|
||||||
|
g_set_error (error,
|
||||||
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
|
"Release already in progress");
|
||||||
|
break;
|
||||||
|
case ACTION_DELETE:
|
||||||
|
g_set_error (error,
|
||||||
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
|
"Delete already in progress");
|
||||||
|
break;
|
||||||
|
default: /* Fallback only. */
|
||||||
|
g_assert_not_reached();
|
||||||
|
g_set_error (error,
|
||||||
|
FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
|
"Another operation is already in progress");
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void match_cb (FpDevice *device,
|
static void match_cb (FpDevice *device,
|
||||||
FpPrint *match,
|
FpPrint *match,
|
||||||
FpPrint *print,
|
FpPrint *print,
|
||||||
@ -1030,28 +1134,21 @@ static gboolean fprint_device_verify_start (FprintDBusDevice *dbus_dev,
|
|||||||
g_autoptr(FpPrint) print = NULL;
|
g_autoptr(FpPrint) print = NULL;
|
||||||
g_autoptr(SessionData) session = NULL;
|
g_autoptr(SessionData) session = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
int finger_num = finger_name_to_num (finger_name);
|
FpFinger finger = finger_name_to_fp_finger (finger_name);
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
session = session_data_get (priv);
|
session = session_data_get (priv);
|
||||||
|
|
||||||
if (priv->current_action != ACTION_NONE) {
|
if (!can_start_action (rdev, &error)) {
|
||||||
if (priv->current_action == ACTION_ENROLL) {
|
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
|
||||||
"Enrollment in progress");
|
|
||||||
} else {
|
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
|
||||||
"Verification already in progress");
|
|
||||||
}
|
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finger_num == -1) {
|
if (finger == FP_FINGER_UNKNOWN) {
|
||||||
g_autoptr(GSList) prints = NULL;
|
g_autoptr(GSList) prints = NULL;
|
||||||
|
|
||||||
prints = store.discover_prints(priv->dev, session->username);
|
prints = store.discover_prints(priv->dev, session->username);
|
||||||
@ -1067,19 +1164,19 @@ static gboolean fprint_device_verify_start (FprintDBusDevice *dbus_dev,
|
|||||||
gallery = g_ptr_array_new_with_free_func (g_object_unref);
|
gallery = g_ptr_array_new_with_free_func (g_object_unref);
|
||||||
|
|
||||||
for (l = prints; l != NULL; l = l->next) {
|
for (l = prints; l != NULL; l = l->next) {
|
||||||
g_debug ("adding finger %d to the gallery", GPOINTER_TO_INT (l->data));
|
g_debug ("adding finger %u to the gallery", GPOINTER_TO_UINT (l->data));
|
||||||
store.print_data_load(priv->dev, GPOINTER_TO_INT (l->data),
|
store.print_data_load(priv->dev, GPOINTER_TO_UINT (l->data),
|
||||||
session->username, &print);
|
session->username, &print);
|
||||||
|
|
||||||
if (print)
|
if (print)
|
||||||
g_ptr_array_add (gallery, g_steal_pointer (&print));
|
g_ptr_array_add (gallery, g_steal_pointer (&print));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
finger_num = GPOINTER_TO_INT (prints->data);
|
finger = GPOINTER_TO_UINT (prints->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fp_device_supports_identify (priv->dev) && finger_num == -1) {
|
if (fp_device_supports_identify (priv->dev) && finger == FP_FINGER_UNKNOWN) {
|
||||||
if (gallery->len == 0) {
|
if (gallery->len == 0) {
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
|
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
|
||||||
"No fingerprints on that device");
|
"No fingerprints on that device");
|
||||||
@ -1097,14 +1194,14 @@ static gboolean fprint_device_verify_start (FprintDBusDevice *dbus_dev,
|
|||||||
} else {
|
} else {
|
||||||
priv->current_action = ACTION_VERIFY;
|
priv->current_action = ACTION_VERIFY;
|
||||||
|
|
||||||
g_debug("start verification device %d finger %d", priv->id, finger_num);
|
g_debug("start verification device %d finger %d", priv->id, finger);
|
||||||
|
|
||||||
store.print_data_load(priv->dev, finger_num,
|
store.print_data_load(priv->dev, finger,
|
||||||
session->username, &print);
|
session->username, &print);
|
||||||
|
|
||||||
if (!print) {
|
if (!print) {
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
|
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
|
||||||
"No such print %d", finger_num);
|
"No such print %d", finger);
|
||||||
g_dbus_method_invocation_return_gerror (invocation,
|
g_dbus_method_invocation_return_gerror (invocation,
|
||||||
error);
|
error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -1117,12 +1214,12 @@ static gboolean fprint_device_verify_start (FprintDBusDevice *dbus_dev,
|
|||||||
(GAsyncReadyCallback) verify_cb, rdev);
|
(GAsyncReadyCallback) verify_cb, rdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprint_dbus_device_complete_verify_start (dbus_dev, invocation);
|
||||||
|
|
||||||
/* Emit VerifyFingerSelected telling the front-end which finger
|
/* Emit VerifyFingerSelected telling the front-end which finger
|
||||||
* we selected for auth */
|
* we selected for auth */
|
||||||
g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
|
g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
|
||||||
0, finger_num_to_name (finger_num));
|
0, fp_finger_to_name (finger));
|
||||||
|
|
||||||
fprint_dbus_device_complete_verify_start (dbus_dev, invocation);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -1135,22 +1232,26 @@ static gboolean fprint_device_verify_stop (FprintDBusDevice *dbus_dev,
|
|||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->current_action == ACTION_NONE) {
|
switch (priv->current_action) {
|
||||||
g_dbus_method_invocation_return_error_literal (invocation,
|
case ACTION_VERIFY:
|
||||||
FPRINT_ERROR,
|
case ACTION_IDENTIFY:
|
||||||
|
break;
|
||||||
|
case ACTION_NONE:
|
||||||
|
g_dbus_method_invocation_return_error_literal (
|
||||||
|
invocation, FPRINT_ERROR,
|
||||||
FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
|
FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
|
||||||
"No verification in progress");
|
"No verification in progress");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else if (priv->current_action == ACTION_ENROLL) {
|
default:
|
||||||
g_dbus_method_invocation_return_error_literal (invocation,
|
g_dbus_method_invocation_return_error_literal (
|
||||||
FPRINT_ERROR,
|
invocation, FPRINT_ERROR,
|
||||||
FPRINT_ERROR_ALREADY_IN_USE,
|
FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
"Enrollment in progress");
|
"Another operation is already in progress");
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1213,7 +1314,7 @@ static gboolean try_delete_print(FprintDevice *rdev)
|
|||||||
guint index;
|
guint index;
|
||||||
|
|
||||||
store.print_data_load (priv->dev,
|
store.print_data_load (priv->dev,
|
||||||
GPOINTER_TO_INT (fingers->data),
|
GPOINTER_TO_UINT (fingers->data),
|
||||||
username,
|
username,
|
||||||
&print);
|
&print);
|
||||||
|
|
||||||
@ -1257,7 +1358,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static FpPrint*
|
static FpPrint*
|
||||||
fprint_device_create_enroll_template(FprintDevice *rdev, gint finger_num)
|
fprint_device_create_enroll_template(FprintDevice *rdev, FpFinger finger)
|
||||||
{
|
{
|
||||||
g_autoptr(SessionData) session = NULL;
|
g_autoptr(SessionData) session = NULL;
|
||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
||||||
@ -1269,7 +1370,7 @@ fprint_device_create_enroll_template(FprintDevice *rdev, gint finger_num)
|
|||||||
session = session_data_get (priv);
|
session = session_data_get (priv);
|
||||||
|
|
||||||
template = fp_print_new (priv->dev);
|
template = fp_print_new (priv->dev);
|
||||||
fp_print_set_finger (template, finger_num);
|
fp_print_set_finger (template, finger);
|
||||||
fp_print_set_username (template, session->username);
|
fp_print_set_username (template, session->username);
|
||||||
datetime = g_date_time_new_now_local ();
|
datetime = g_date_time_new_now_local ();
|
||||||
g_date_time_get_ymd (datetime, &year, &month, &day);
|
g_date_time_get_ymd (datetime, &year, &month, &day);
|
||||||
@ -1347,36 +1448,29 @@ static gboolean fprint_device_enroll_start (FprintDBusDevice *dbus_dev,
|
|||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
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);
|
||||||
int finger_num = finger_name_to_num (finger_name);
|
FpFinger finger = finger_name_to_fp_finger (finger_name);
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (finger_num == -1) {
|
if (finger == FP_FINGER_UNKNOWN) {
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
|
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
|
||||||
"Invalid finger name");
|
"Invalid finger name");
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->current_action != ACTION_NONE) {
|
if (!can_start_action (rdev, &error)) {
|
||||||
if (priv->current_action == ACTION_ENROLL) {
|
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
|
||||||
"Enrollment already in progress");
|
|
||||||
} else {
|
|
||||||
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
|
||||||
"Verification in progress");
|
|
||||||
}
|
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_debug("start enrollment device %d finger %d", priv->id, finger_num);
|
g_debug("start enrollment device %d finger %d", priv->id, finger);
|
||||||
|
|
||||||
priv->current_cancellable = g_cancellable_new ();
|
priv->current_cancellable = g_cancellable_new ();
|
||||||
priv->enroll_data = finger_num;
|
priv->enroll_data = finger;
|
||||||
fp_device_enroll (priv->dev,
|
fp_device_enroll (priv->dev,
|
||||||
fprint_device_create_enroll_template (rdev, priv->enroll_data),
|
fprint_device_create_enroll_template (rdev, priv->enroll_data),
|
||||||
priv->current_cancellable,
|
priv->current_cancellable,
|
||||||
@ -1400,24 +1494,25 @@ static gboolean fprint_device_enroll_stop (FprintDBusDevice *dbus_dev,
|
|||||||
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->current_action != ACTION_ENROLL) {
|
switch (priv->current_action) {
|
||||||
if (priv->current_action == ACTION_NONE) {
|
case ACTION_ENROLL:
|
||||||
g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
|
break;
|
||||||
|
case ACTION_NONE:
|
||||||
|
g_dbus_method_invocation_return_error_literal (
|
||||||
|
invocation, FPRINT_ERROR,
|
||||||
|
FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
|
||||||
"No enrollment in progress");
|
"No enrollment in progress");
|
||||||
} else if (priv->current_action == ACTION_VERIFY) {
|
return TRUE;
|
||||||
g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
default:
|
||||||
"Verification in progress");
|
g_dbus_method_invocation_return_error_literal (
|
||||||
} else if (priv->current_action == ACTION_IDENTIFY) {
|
invocation, FPRINT_ERROR,
|
||||||
g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
|
FPRINT_ERROR_ALREADY_IN_USE,
|
||||||
"Identification in progress");
|
"Another operation is already in progress");
|
||||||
} else
|
|
||||||
g_assert_not_reached ();
|
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1461,8 +1556,8 @@ static gboolean fprint_device_list_enrolled_fingers (FprintDBusDevice *dbus_dev,
|
|||||||
|
|
||||||
ret = g_ptr_array_new ();
|
ret = g_ptr_array_new ();
|
||||||
for (item = prints; item; item = item->next) {
|
for (item = prints; item; item = item->next) {
|
||||||
int finger_num = GPOINTER_TO_INT (item->data);
|
FpFinger finger = GPOINTER_TO_UINT (item->data);
|
||||||
g_ptr_array_add (ret, (char *) finger_num_to_name (finger_num));
|
g_ptr_array_add (ret, (char *) fp_finger_to_name (finger));
|
||||||
}
|
}
|
||||||
g_ptr_array_add (ret, NULL);
|
g_ptr_array_add (ret, NULL);
|
||||||
|
|
||||||
@ -1491,7 +1586,7 @@ static void delete_enrolled_fingers(FprintDevice *rdev, const char *user)
|
|||||||
g_autoptr(FpPrint) print = NULL;
|
g_autoptr(FpPrint) print = NULL;
|
||||||
|
|
||||||
store.print_data_load(priv->dev,
|
store.print_data_load(priv->dev,
|
||||||
GPOINTER_TO_INT (l->data),
|
GPOINTER_TO_UINT (l->data),
|
||||||
user,
|
user,
|
||||||
&print);
|
&print);
|
||||||
|
|
||||||
@ -1570,11 +1665,14 @@ static gboolean fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_de
|
|||||||
log_offending_client (invocation);
|
log_offending_client (invocation);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
user = g_object_steal_qdata (G_OBJECT (invocation), quark_auth_user);
|
if (!can_start_action(rdev, &error)) {
|
||||||
g_assert (user);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED,
|
priv->current_action = ACTION_DELETE;
|
||||||
&error)) {
|
|
||||||
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
/* Return error for anything but FPRINT_ERROR_CLAIM_DEVICE */
|
/* Return error for anything but FPRINT_ERROR_CLAIM_DEVICE */
|
||||||
if (!g_error_matches (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE)) {
|
if (!g_error_matches (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation,
|
g_dbus_method_invocation_return_gerror (invocation,
|
||||||
@ -1593,11 +1691,17 @@ static gboolean fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_de
|
|||||||
if (!opened && fp_device_has_storage (priv->dev))
|
if (!opened && fp_device_has_storage (priv->dev))
|
||||||
fp_device_open_sync (priv->dev, NULL, NULL);
|
fp_device_open_sync (priv->dev, NULL, NULL);
|
||||||
|
|
||||||
|
user = g_object_steal_qdata (G_OBJECT (invocation), quark_auth_user);
|
||||||
|
g_assert (user);
|
||||||
|
g_assert (g_str_equal (username, "") || g_str_equal (user, username));
|
||||||
|
|
||||||
delete_enrolled_fingers (rdev, user);
|
delete_enrolled_fingers (rdev, user);
|
||||||
|
|
||||||
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;
|
||||||
@ -1611,14 +1715,24 @@ static gboolean fprint_device_delete_enrolled_fingers2 (FprintDBusDevice *dbus_d
|
|||||||
g_autoptr(SessionData) session = NULL;
|
g_autoptr(SessionData) session = NULL;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, STATE_CLAIMED, &error)) {
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!can_start_action(rdev, &error)) {
|
||||||
|
g_dbus_method_invocation_return_gerror (invocation, error);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->current_action = ACTION_DELETE;
|
||||||
|
|
||||||
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;
|
||||||
@ -1650,8 +1764,7 @@ action_authorization_handler (GDBusInterfaceSkeleton *interface,
|
|||||||
FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (interface);
|
FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (interface);
|
||||||
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);
|
||||||
FprintDeviceClaimState required_state = STATE_IGNORED;
|
FprintDevicePermission required_perms;
|
||||||
FprintDevicePermission required_perms = FPRINT_DEVICE_PERMISSION_NONE;
|
|
||||||
gboolean needs_user_auth = FALSE;
|
gboolean needs_user_auth = FALSE;
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
const gchar *method_name;
|
const gchar *method_name;
|
||||||
@ -1664,43 +1777,16 @@ action_authorization_handler (GDBusInterfaceSkeleton *interface,
|
|||||||
|
|
||||||
if (g_str_equal (method_name, "Claim")) {
|
if (g_str_equal (method_name, "Claim")) {
|
||||||
needs_user_auth = TRUE;
|
needs_user_auth = TRUE;
|
||||||
required_state = STATE_UNCLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
|
||||||
} else if (g_str_equal (method_name, "DeleteEnrolledFingers")) {
|
} else if (g_str_equal (method_name, "DeleteEnrolledFingers")) {
|
||||||
needs_user_auth = TRUE;
|
needs_user_auth = TRUE;
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
|
||||||
} else if (g_str_equal (method_name, "DeleteEnrolledFingers2")) {
|
|
||||||
required_state = STATE_CLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
|
||||||
} else if (g_str_equal (method_name, "EnrollStart")) {
|
|
||||||
required_state = STATE_CLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
|
||||||
} else if (g_str_equal (method_name, "EnrollStop")) {
|
|
||||||
required_state = STATE_CLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
|
||||||
} else if (g_str_equal (method_name, "ListEnrolledFingers")) {
|
} else if (g_str_equal (method_name, "ListEnrolledFingers")) {
|
||||||
needs_user_auth = TRUE;
|
needs_user_auth = TRUE;
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
|
||||||
} else if (g_str_equal (method_name, "Release")) {
|
|
||||||
required_state = STATE_CLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
|
|
||||||
} else if (g_str_equal (method_name, "VerifyStart")) {
|
|
||||||
required_state = STATE_CLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
|
||||||
} else if (g_str_equal (method_name, "VerifyStop")) {
|
|
||||||
required_state = STATE_CLAIMED;
|
|
||||||
required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
|
|
||||||
} else {
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is just a quick check in order to avoid authentication if
|
/* This is just a quick check in order to avoid authentication if
|
||||||
* the user cannot make the call at this time anyway.
|
* the user cannot make the call at this time anyway.
|
||||||
* The method handler itself is required to check again! */
|
* The method handler itself is required to check again! */
|
||||||
if (!_fprint_device_check_claimed (rdev, invocation, required_state,
|
if (!_fprint_device_check_claimed (rdev, invocation, &error)) {
|
||||||
&error)) {
|
|
||||||
return handle_unauthorized_access (rdev, invocation, error);
|
return handle_unauthorized_access (rdev, invocation, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1709,6 +1795,8 @@ action_authorization_handler (GDBusInterfaceSkeleton *interface,
|
|||||||
return handle_unauthorized_access (rdev, invocation, error);
|
return handle_unauthorized_access (rdev, invocation, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
required_perms = get_permissions_for_invocation (invocation);
|
||||||
|
|
||||||
/* This may possibly block the invocation till the user has not
|
/* This may possibly block the invocation till the user has not
|
||||||
* provided an authentication method, so other calls could arrive */
|
* provided an authentication method, so other calls could arrive */
|
||||||
if (!fprint_device_check_polkit_for_permissions (rdev, invocation,
|
if (!fprint_device_check_polkit_for_permissions (rdev, invocation,
|
||||||
|
|||||||
@ -251,7 +251,7 @@ static GSList *scan_dev_storedir(char *devpath,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
list = g_slist_prepend(list, GINT_TO_POINTER(val));
|
list = g_slist_prepend (list, GUINT_TO_POINTER (val));
|
||||||
}
|
}
|
||||||
|
|
||||||
g_dir_close(dir);
|
g_dir_close(dir);
|
||||||
|
|||||||
@ -53,11 +53,16 @@ typedef enum {
|
|||||||
FPRINT_ERROR_NO_SUCH_DEVICE, /*< nick=net.reactivated.Fprint.Error.NoSuchDevice >*/
|
FPRINT_ERROR_NO_SUCH_DEVICE, /*< nick=net.reactivated.Fprint.Error.NoSuchDevice >*/
|
||||||
} FprintError;
|
} FprintError;
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
- Nick must match the relative polkit rule.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FPRINT_DEVICE_PERMISSION_NONE = 0,
|
FPRINT_DEVICE_PERMISSION_NONE = 0,
|
||||||
FPRINT_DEVICE_PERMISSION_ENROLL = (1 << 0), /*< nick=net.reactivated.fprint.device.enroll >*/
|
FPRINT_DEVICE_PERMISSION_VERIFY = (1 << 0), /*< nick=net.reactivated.fprint.device.verify >*/
|
||||||
FPRINT_DEVICE_PERMISSION_SETUSERNAME = (1 << 1), /*< nick=net.reactivated.fprint.device.setusername >*/
|
FPRINT_DEVICE_PERMISSION_ENROLL = (1 << 1), /*< nick=net.reactivated.fprint.device.enroll >*/
|
||||||
FPRINT_DEVICE_PERMISSION_VERIFY = (1 << 2), /*< nick=net.reactivated.fprint.device.verify >*/
|
FPRINT_DEVICE_PERMISSION_SETUSERNAME = (1 << 2), /*< nick=net.reactivated.fprint.device.setusername >*/
|
||||||
} FprintDevicePermission;
|
} FprintDevicePermission;
|
||||||
|
|
||||||
/* Manager */
|
/* Manager */
|
||||||
|
|||||||
@ -14,7 +14,8 @@ foreach interface_name: dbus_interfaces
|
|||||||
)
|
)
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
fprintd_dbus_sources = gnome.gdbus_codegen('fprintd-dbus',
|
# NOTE: We should pass "--glib-min-required 2.64" but cannot
|
||||||
|
fprintd_dbus_sources_base = gnome.gdbus_codegen('fprintd-dbus',
|
||||||
sources: dbus_interfaces_files,
|
sources: dbus_interfaces_files,
|
||||||
autocleanup: 'all',
|
autocleanup: 'all',
|
||||||
interface_prefix: 'net.reactivated.Fprint.',
|
interface_prefix: 'net.reactivated.Fprint.',
|
||||||
@ -22,6 +23,23 @@ fprintd_dbus_sources = gnome.gdbus_codegen('fprintd-dbus',
|
|||||||
object_manager: true,
|
object_manager: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# FIXME: remove this and just use fprintd_dbus_sources when we're on glib 2.64
|
||||||
|
fprintd_dbus_sources = [
|
||||||
|
fprintd_dbus_sources_base[1] # header file
|
||||||
|
]
|
||||||
|
|
||||||
|
fprintd_dbus_sources += custom_target('fprintd-dbus-interactive',
|
||||||
|
input: fprintd_dbus_sources_base[0], # c file,
|
||||||
|
output: 'fprintd-dbus-interactive.c',
|
||||||
|
command: [
|
||||||
|
find_program('patch'),
|
||||||
|
'-p1',
|
||||||
|
'--merge',
|
||||||
|
'@INPUT@',
|
||||||
|
files('dbus-interactive-auth.patch'),
|
||||||
|
'-o', '@OUTPUT@',
|
||||||
|
])
|
||||||
|
|
||||||
fprintd_enum_files = gnome.mkenums_simple('fprintd-enums',
|
fprintd_enum_files = gnome.mkenums_simple('fprintd-enums',
|
||||||
sources: 'fprintd.h',
|
sources: 'fprintd.h',
|
||||||
)
|
)
|
||||||
|
|||||||
@ -18,6 +18,8 @@ __email__ = 'hadess@hadess.net'
|
|||||||
__copyright__ = '(c) 2020 Red Hat Inc.'
|
__copyright__ = '(c) 2020 Red Hat Inc.'
|
||||||
__license__ = 'LGPL 3+'
|
__license__ = 'LGPL 3+'
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from gi.repository import GLib
|
||||||
import dbus
|
import dbus
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
@ -213,9 +215,22 @@ def can_verify_finger(device, finger_name):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def send_verify_script(device, script):
|
def glib_sleep(timeout):
|
||||||
for [result, done, timeout] in device.verify_script:
|
waiting = True
|
||||||
await asyncio.sleep(timeout)
|
|
||||||
|
def done_waiting():
|
||||||
|
nonlocal waiting
|
||||||
|
waiting = False
|
||||||
|
|
||||||
|
GLib.timeout_add(timeout, done_waiting)
|
||||||
|
while (waiting):
|
||||||
|
GLib.main_context_default().iteration(True)
|
||||||
|
|
||||||
|
def device_run_script(device, result, done):
|
||||||
|
if result == 'MOCK: quit':
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Emit signal
|
||||||
device.EmitSignal(DEVICE_IFACE, 'VerifyStatus', 'sb', [
|
device.EmitSignal(DEVICE_IFACE, 'VerifyStatus', 'sb', [
|
||||||
result,
|
result,
|
||||||
done
|
done
|
||||||
@ -249,13 +264,44 @@ def VerifyStart(device, finger_name):
|
|||||||
if finger_name == 'any' and not device.has_identification:
|
if finger_name == 'any' and not device.has_identification:
|
||||||
finger_name = device.fingers[device.claimed_user][0]
|
finger_name = device.fingers[device.claimed_user][0]
|
||||||
device.selected_finger = finger_name
|
device.selected_finger = finger_name
|
||||||
device.EmitSignal(DEVICE_IFACE, 'VerifyFingerSelected', 's', [
|
# Needs to happen after method return
|
||||||
finger_name
|
GLib.idle_add(device.EmitSignal,
|
||||||
|
DEVICE_IFACE, 'VerifyFingerSelected', 's', [
|
||||||
|
device.selected_finger
|
||||||
])
|
])
|
||||||
|
|
||||||
if device.verify_script is not None and len(device.verify_script) > 0:
|
error = None
|
||||||
asyncio.run(send_verify_script(device, device.verify_script))
|
base_delay = 0
|
||||||
|
while device.verify_script is not None and len(device.verify_script) > 0:
|
||||||
|
result, done, timeout = device.verify_script.pop(0)
|
||||||
|
|
||||||
|
# We stop when "timeout >= 0 and done"
|
||||||
|
if result == 'MOCK: no-prints':
|
||||||
|
# Special case to change return value of DBus call, ignores timeout
|
||||||
|
error = dbus.exceptions.DBusException(
|
||||||
|
'No enrolled prints for user \'%s\'' % device.claimed_user,
|
||||||
|
name='net.reactivated.Fprint.Error.NoEnrolledPrints')
|
||||||
|
|
||||||
|
elif timeout < 0:
|
||||||
|
# Negative timeouts mean emitting before the DBus call returns
|
||||||
|
device_run_script(device, result, done)
|
||||||
|
glib_sleep(-timeout)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Positive or zero means emitting afterwards the given timeout
|
||||||
|
base_delay += timeout
|
||||||
|
GLib.timeout_add(base_delay,
|
||||||
|
device_run_script,
|
||||||
|
device,
|
||||||
|
result,
|
||||||
|
done)
|
||||||
|
|
||||||
|
# Stop processing commands when the done flag is set
|
||||||
|
if done:
|
||||||
|
break
|
||||||
|
|
||||||
|
if error:
|
||||||
|
raise error
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_MOCK_IFACE,
|
@dbus.service.method(DEVICE_MOCK_IFACE,
|
||||||
in_signature='sb', out_signature='')
|
in_signature='sb', out_signature='')
|
||||||
@ -383,3 +429,11 @@ def SetVerifyScript(device, script):
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
device.verify_script = script
|
device.verify_script = script
|
||||||
|
|
||||||
|
@dbus.service.method(DEVICE_MOCK_IFACE,
|
||||||
|
in_signature='s', out_signature='')
|
||||||
|
def SetClaimed(device, user):
|
||||||
|
if user == '':
|
||||||
|
device.claimed_user = None
|
||||||
|
else:
|
||||||
|
device.claimed_user = user
|
||||||
|
|||||||
@ -493,32 +493,55 @@ class FPrintdManagerPreStartTests(FPrintdTest):
|
|||||||
self.manager.GetDefaultDevice()
|
self.manager.GetDefaultDevice()
|
||||||
|
|
||||||
def test_manager_get_devices_on_name_appeared(self):
|
def test_manager_get_devices_on_name_appeared(self):
|
||||||
self._appeared_res = []
|
self._appeared_name = None
|
||||||
|
|
||||||
def on_name_appeared(connection, name, name_owner):
|
def on_name_appeared(connection, name, name_owner):
|
||||||
self._appeared_res.append(connection.call_sync('net.reactivated.Fprint',
|
self._appeared_name = name
|
||||||
'/net/reactivated/Fprint/Manager',
|
|
||||||
'net.reactivated.Fprint.Manager',
|
def on_name_vanished(connection, name):
|
||||||
'GetDefaultDevice', None, None,
|
self._appeared_name = 'NAME_VANISHED'
|
||||||
Gio.DBusCallFlags.NO_AUTO_START, 500, None))
|
|
||||||
|
|
||||||
id = Gio.bus_watch_name_on_connection(self.dbus,
|
id = Gio.bus_watch_name_on_connection(self.dbus,
|
||||||
'net.reactivated.Fprint', Gio.BusNameWatcherFlags.NONE,
|
'net.reactivated.Fprint', Gio.BusNameWatcherFlags.NONE,
|
||||||
on_name_appeared, None)
|
on_name_appeared, on_name_vanished)
|
||||||
|
self.addCleanup(Gio.bus_unwatch_name, id)
|
||||||
|
|
||||||
self.daemon_start()
|
self.daemon_start()
|
||||||
while not self._appeared_res:
|
while not self._appeared_name:
|
||||||
ctx.iteration(True)
|
ctx.iteration(True)
|
||||||
|
|
||||||
self.assertIsNotNone(self._appeared_res[0])
|
self.assertEqual(self._appeared_name, 'net.reactivated.Fprint')
|
||||||
dev_path = self._appeared_res[0][0]
|
|
||||||
self.assertTrue(dev_path.startswith('/net/reactivated/Fprint/Device/'))
|
|
||||||
|
|
||||||
Gio.bus_unwatch_name(id)
|
try:
|
||||||
|
appeared_device = self.dbus.call_sync(
|
||||||
|
'net.reactivated.Fprint',
|
||||||
|
'/net/reactivated/Fprint/Manager',
|
||||||
|
'net.reactivated.Fprint.Manager',
|
||||||
|
'GetDefaultDevice', None, None,
|
||||||
|
Gio.DBusCallFlags.NO_AUTO_START, 500, None)
|
||||||
|
except GLib.GError as e:
|
||||||
|
if 'net.reactivated.Fprint.Error.NoSuchDevice' in e.message:
|
||||||
|
self.skipTest("Need virtual_image device to run the test")
|
||||||
|
raise(e)
|
||||||
|
|
||||||
|
self.assertIsNotNone(appeared_device)
|
||||||
|
[dev_path] = appeared_device
|
||||||
|
self.assertTrue(dev_path.startswith('/net/reactivated/Fprint/Device/'))
|
||||||
|
|
||||||
|
|
||||||
class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
||||||
|
|
||||||
|
def test_name_property(self):
|
||||||
|
self.assertEqual(self.device.get_cached_property('name').unpack(),
|
||||||
|
'Virtual image device for debugging')
|
||||||
|
|
||||||
|
def test_enroll_stages_property(self):
|
||||||
|
self.assertEqual(self.device.get_cached_property('num-enroll-stages').unpack(), 5)
|
||||||
|
|
||||||
|
def test_scan_type(self):
|
||||||
|
self.assertEqual(self.device.get_cached_property('scan-type').unpack(),
|
||||||
|
'swipe')
|
||||||
|
|
||||||
def test_allowed_claim_release_enroll(self):
|
def test_allowed_claim_release_enroll(self):
|
||||||
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername',
|
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername',
|
||||||
'net.reactivated.fprint.device.enroll'])
|
'net.reactivated.fprint.device.enroll'])
|
||||||
@ -580,6 +603,34 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
with self.assertFprintError('PermissionDenied'):
|
with self.assertFprintError('PermissionDenied'):
|
||||||
self.device.Claim('(s)', 'testuser')
|
self.device.Claim('(s)', 'testuser')
|
||||||
|
|
||||||
|
def test_unallowed_enroll_with_verify_claim(self):
|
||||||
|
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
|
||||||
|
self.device.Claim('(s)', '')
|
||||||
|
|
||||||
|
with self.assertFprintError('PermissionDenied'):
|
||||||
|
self.enroll_image('whorl', finger='right-thumb')
|
||||||
|
|
||||||
|
def test_unallowed_delete_with_verify_claim(self):
|
||||||
|
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
|
||||||
|
self.device.Claim('(s)', '')
|
||||||
|
|
||||||
|
with self.assertFprintError('PermissionDenied'):
|
||||||
|
self.device.DeleteEnrolledFingers('(s)', 'testuser')
|
||||||
|
|
||||||
|
def test_unallowed_delete2_with_verify_claim(self):
|
||||||
|
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
|
||||||
|
self.device.Claim('(s)', '')
|
||||||
|
|
||||||
|
with self.assertFprintError('PermissionDenied'):
|
||||||
|
self.device.DeleteEnrolledFingers2()
|
||||||
|
|
||||||
|
def test_unallowed_verify_with_enroll_claim(self):
|
||||||
|
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
|
||||||
|
self.device.Claim('(s)', '')
|
||||||
|
|
||||||
|
with self.assertFprintError('PermissionDenied'):
|
||||||
|
self.device.VerifyStart('(s)', 'any')
|
||||||
|
|
||||||
def test_unallowed_claim_current_user(self):
|
def test_unallowed_claim_current_user(self):
|
||||||
self._polkitd_obj.SetAllowed([''])
|
self._polkitd_obj.SetAllowed([''])
|
||||||
|
|
||||||
@ -597,20 +648,11 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
|
|
||||||
self.device.Release()
|
self.device.Release()
|
||||||
|
|
||||||
def test_unallowed_release(self):
|
def test_always_allowed_release(self):
|
||||||
self.device.Claim('(s)', 'testuser')
|
self.device.Claim('(s)', 'testuser')
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed([''])
|
self._polkitd_obj.SetAllowed([''])
|
||||||
|
|
||||||
with self.assertFprintError('PermissionDenied'):
|
|
||||||
self.device.Release()
|
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername'])
|
|
||||||
|
|
||||||
with self.assertFprintError('PermissionDenied'):
|
|
||||||
self.device.Release()
|
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
|
|
||||||
self.device.Release()
|
self.device.Release()
|
||||||
|
|
||||||
def test_unclaimed_release(self):
|
def test_unclaimed_release(self):
|
||||||
@ -780,6 +822,7 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
self.wait_for_result()
|
self.wait_for_result()
|
||||||
self.assertTrue(self._verify_stopped)
|
self.assertTrue(self._verify_stopped)
|
||||||
self.assertEqual(self._last_result, 'verify-match')
|
self.assertEqual(self._last_result, 'verify-match')
|
||||||
|
self.device.VerifyStop()
|
||||||
|
|
||||||
self.assertEqual(self.device.ListEnrolledFingers('(s)', 'testuser'), ['right-index-finger'])
|
self.assertEqual(self.device.ListEnrolledFingers('(s)', 'testuser'), ['right-index-finger'])
|
||||||
|
|
||||||
@ -959,15 +1002,11 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
|
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
|
||||||
self.enroll_image('whorl')
|
self.enroll_image('whorl')
|
||||||
|
|
||||||
def test_unallowed_enroll_stop(self):
|
def test_always_allowed_enroll_stop(self):
|
||||||
self.device.EnrollStart('(s)', 'right-index-finger')
|
self.device.EnrollStart('(s)', 'right-index-finger')
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed([''])
|
self._polkitd_obj.SetAllowed([''])
|
||||||
|
|
||||||
with self.assertFprintError('PermissionDenied'):
|
|
||||||
self.device.EnrollStop()
|
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
|
|
||||||
self.device.EnrollStop()
|
self.device.EnrollStop()
|
||||||
|
|
||||||
def test_unallowed_verify_start(self):
|
def test_unallowed_verify_start(self):
|
||||||
@ -976,15 +1015,11 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
|
|||||||
with self.assertFprintError('PermissionDenied'):
|
with self.assertFprintError('PermissionDenied'):
|
||||||
self.device.VerifyStart('(s)', 'any')
|
self.device.VerifyStart('(s)', 'any')
|
||||||
|
|
||||||
def test_unallowed_verify_stop(self):
|
def test_always_allowed_verify_stop(self):
|
||||||
self.enroll_image('whorl')
|
self.enroll_image('whorl')
|
||||||
self.device.VerifyStart('(s)', 'any')
|
self.device.VerifyStart('(s)', 'any')
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed([''])
|
self._polkitd_obj.SetAllowed([''])
|
||||||
with self.assertFprintError('PermissionDenied'):
|
|
||||||
self.device.VerifyStop()
|
|
||||||
|
|
||||||
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
|
|
||||||
self.device.VerifyStop()
|
self.device.VerifyStop()
|
||||||
|
|
||||||
def test_list_enrolled_fingers_current_user(self):
|
def test_list_enrolled_fingers_current_user(self):
|
||||||
|
|||||||
148
tests/output_checker.py
Normal file
148
tests/output_checker.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
# Copyright © 2020, RedHat Inc.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU Lesser General Public
|
||||||
|
# License as published by the Free Software Foundation; either
|
||||||
|
# version 2.1 of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public
|
||||||
|
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
# Authors:
|
||||||
|
# Benjamin Berg <bberg@redhat.com>
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import fcntl
|
||||||
|
import io
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
class OutputChecker(object):
|
||||||
|
|
||||||
|
def __init__(self, out=sys.stdout):
|
||||||
|
self._output = out
|
||||||
|
self._pipe_fd_r, self._pipe_fd_w = os.pipe()
|
||||||
|
self._partial_buf = b''
|
||||||
|
self._lines_sem = threading.Semaphore()
|
||||||
|
self._lines = []
|
||||||
|
self._reader_io = io.StringIO()
|
||||||
|
|
||||||
|
# Just to be sure, shouldn't be a problem even if we didn't set it
|
||||||
|
fcntl.fcntl(self._pipe_fd_r, fcntl.F_SETFL,
|
||||||
|
fcntl.fcntl(self._pipe_fd_r, fcntl.F_GETFL) | os.O_CLOEXEC)
|
||||||
|
fcntl.fcntl(self._pipe_fd_w, fcntl.F_SETFL,
|
||||||
|
fcntl.fcntl(self._pipe_fd_w, fcntl.F_GETFL) | os.O_CLOEXEC)
|
||||||
|
|
||||||
|
# Start copier thread
|
||||||
|
self._thread = threading.Thread(target=self._copy)
|
||||||
|
self._thread.start()
|
||||||
|
|
||||||
|
def _copy(self):
|
||||||
|
while True:
|
||||||
|
r = os.read(self._pipe_fd_r, 1024)
|
||||||
|
if not r:
|
||||||
|
return
|
||||||
|
|
||||||
|
l = r.split(b'\n')
|
||||||
|
l[0] = self._partial_buf + l[0]
|
||||||
|
self._lines.extend(l[:-1])
|
||||||
|
self._partial_buf = l[-1]
|
||||||
|
|
||||||
|
self._lines_sem.release()
|
||||||
|
|
||||||
|
os.write(self._output.fileno(), r)
|
||||||
|
|
||||||
|
def check_line_re(self, needle_re, timeout=0, failmsg=None):
|
||||||
|
deadline = time.time() + timeout
|
||||||
|
|
||||||
|
if isinstance(needle_re, str):
|
||||||
|
needle_re = needle_re.encode('ascii')
|
||||||
|
|
||||||
|
r = re.compile(needle_re)
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
l = self._lines.pop(0)
|
||||||
|
except IndexError:
|
||||||
|
# Check if should wake up
|
||||||
|
if not self._lines_sem.acquire(timeout = deadline - time.time()):
|
||||||
|
if failmsg:
|
||||||
|
raise AssertionError(failmsg)
|
||||||
|
else:
|
||||||
|
raise AssertionError('Timed out waiting for needle %s (timeout: %0.2f)' % (str(needle_re), timeout))
|
||||||
|
continue
|
||||||
|
|
||||||
|
ret.append(l)
|
||||||
|
if r.search(l):
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def check_line(self, needle, timeout=0, failmsg=None):
|
||||||
|
if isinstance(needle, str):
|
||||||
|
needle = needle.encode('ascii')
|
||||||
|
|
||||||
|
needle_re = re.escape(needle)
|
||||||
|
|
||||||
|
return self.check_line_re(needle_re, timeout=timeout, failmsg=failmsg)
|
||||||
|
|
||||||
|
def check_no_line_re(self, needle_re, wait=0, failmsg=None):
|
||||||
|
deadline = time.time() + wait
|
||||||
|
|
||||||
|
if isinstance(needle_re, str):
|
||||||
|
needle_re = needle_re.encode('ascii')
|
||||||
|
|
||||||
|
r = re.compile(needle_re)
|
||||||
|
ret = []
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
l = self._lines.pop(0)
|
||||||
|
except IndexError:
|
||||||
|
# Check if should wake up
|
||||||
|
if not self._lines_sem.acquire(timeout = deadline - time.time()):
|
||||||
|
# Timed out, so everything is good
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
|
||||||
|
ret.append(l)
|
||||||
|
if r.search(l):
|
||||||
|
if failmsg:
|
||||||
|
raise AssertionError(failmsg)
|
||||||
|
else:
|
||||||
|
raise AssertionError('Found needle %s but shouldn\'t have been there (timeout: %0.2f)' % (str(needle_re), timeout))
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def check_no_line(self, needle, wait=0, failmsg=None):
|
||||||
|
if isinstance(needle, str):
|
||||||
|
needle = needle.encode('ascii')
|
||||||
|
|
||||||
|
needle_re = re.escape(needle)
|
||||||
|
|
||||||
|
return self.check_no_line_re(needle_re, wait=wait, failmsg=failmsg)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
ret = self._lines
|
||||||
|
self._lines = []
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def assert_closed(self, timeout=1):
|
||||||
|
self._thread.join(timeout)
|
||||||
|
if self._thread.is_alive() != False:
|
||||||
|
raise AssertionError("OutputCheck: Write side has not been closed yet!")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fd(self):
|
||||||
|
return self._pipe_fd_w
|
||||||
|
|
||||||
|
def writer_attached(self):
|
||||||
|
os.close(self._pipe_fd_w)
|
||||||
|
self._pipe_fd_w = -1
|
||||||
|
|
||||||
@ -17,7 +17,6 @@ import sys
|
|||||||
import subprocess
|
import subprocess
|
||||||
import dbus
|
import dbus
|
||||||
import dbusmock
|
import dbusmock
|
||||||
import fcntl
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@ -75,10 +74,7 @@ class TestPamFprintd(dbusmock.DBusTestCase):
|
|||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
|
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
|
||||||
self.template_name, {}, stdout=subprocess.PIPE)
|
self.template_name, {})
|
||||||
# set log to nonblocking
|
|
||||||
flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
|
|
||||||
fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
|
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@ -143,6 +139,66 @@ class TestPamFprintd(dbusmock.DBusTestCase):
|
|||||||
self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
|
self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
|
||||||
self.assertEqual(len(res.errors), 0)
|
self.assertEqual(len(res.errors), 0)
|
||||||
|
|
||||||
|
def test_pam_fprintd_no_fingers(self):
|
||||||
|
self.setup_device()
|
||||||
|
self.device_mock.SetEnrolledFingers('toto', dbus.Array(set([]), signature='s'))
|
||||||
|
script = [
|
||||||
|
( 'verify-match', True, 1 )
|
||||||
|
]
|
||||||
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
|
||||||
|
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_no_fingers_while_verifying(self):
|
||||||
|
self.setup_device()
|
||||||
|
script = [
|
||||||
|
( 'MOCK: no-prints', True, 1),
|
||||||
|
( 'verify-match', True, 1 )
|
||||||
|
]
|
||||||
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
|
||||||
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_USER_UNKNOWN)
|
||||||
|
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
||||||
|
|
||||||
|
def test_pam_fprintd_blocks_unexpected_auth(self):
|
||||||
|
self.setup_device()
|
||||||
|
script = [
|
||||||
|
( 'verify-match', True, -500 ), # This one is sent before VerifyStart has completed
|
||||||
|
( 'verify-no-match', True, 1 ),
|
||||||
|
( 'verify-no-match', True, 1 ),
|
||||||
|
( 'verify-no-match', True, 1 ),
|
||||||
|
]
|
||||||
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
|
||||||
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
|
||||||
|
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.assertEqual(len(res.errors), 3)
|
||||||
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
||||||
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
||||||
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
||||||
|
|
||||||
|
def test_pam_fprintd_blocks_unexpected_auth2(self):
|
||||||
|
self.setup_device()
|
||||||
|
script = [
|
||||||
|
( 'verify-no-match', True, 1 ),
|
||||||
|
( 'verify-match', True, -500 ), # This one is sent before VerifyStart has completed
|
||||||
|
( 'verify-no-match', True, 1 ),
|
||||||
|
( 'verify-no-match', True, 1 ),
|
||||||
|
]
|
||||||
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
|
||||||
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
|
||||||
|
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.assertEqual(len(res.errors), 3)
|
||||||
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
||||||
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
||||||
|
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
||||||
|
|
||||||
def test_pam_fprintd_dual_reader_auth(self):
|
def test_pam_fprintd_dual_reader_auth(self):
|
||||||
device_path = self.obj_fprintd_mock.AddDevice('FDO Sandpaper Reader', 3, 'press')
|
device_path = self.obj_fprintd_mock.AddDevice('FDO Sandpaper Reader', 3, 'press')
|
||||||
sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
|
sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
|
||||||
@ -196,6 +252,20 @@ class TestPamFprintd(dbusmock.DBusTestCase):
|
|||||||
self.assertRegex(res.errors[1], r'Failed to match fingerprint')
|
self.assertRegex(res.errors[1], r'Failed to match fingerprint')
|
||||||
self.assertRegex(res.errors[2], r'Failed to match fingerprint')
|
self.assertRegex(res.errors[2], r'Failed to match fingerprint')
|
||||||
|
|
||||||
|
def test_pam_already_claimed(self):
|
||||||
|
self.setup_device()
|
||||||
|
script = [
|
||||||
|
( 'verify-match', True, 2 )
|
||||||
|
]
|
||||||
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
self.device_mock.SetClaimed('toto')
|
||||||
|
|
||||||
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
|
||||||
|
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
||||||
|
|
||||||
|
self.assertEqual(len(res.info), 0)
|
||||||
|
self.assertEqual(len(res.errors), 0)
|
||||||
|
|
||||||
def test_pam_timeout(self):
|
def test_pam_timeout(self):
|
||||||
self.setup_device()
|
self.setup_device()
|
||||||
|
|
||||||
@ -203,6 +273,19 @@ class TestPamFprintd(dbusmock.DBusTestCase):
|
|||||||
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
||||||
self.assertRegex(res.info[1], r'Verification timed out')
|
self.assertRegex(res.info[1], r'Verification timed out')
|
||||||
|
|
||||||
|
def test_pam_notices_fprintd_disappearing(self):
|
||||||
|
self.setup_device()
|
||||||
|
|
||||||
|
script = [
|
||||||
|
( 'MOCK: quit', True, 0 ),
|
||||||
|
]
|
||||||
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
|
||||||
|
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
|
||||||
|
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
|
||||||
|
self.assertEqual(len(res.errors), 0)
|
||||||
|
self.assertEqual(len(res.info), 0)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if 'PAM_WRAPPER_SERVICE_DIR' not in os.environ:
|
if 'PAM_WRAPPER_SERVICE_DIR' not in os.environ:
|
||||||
print('Cannot run test without environment set correctly, run "meson test" instead')
|
print('Cannot run test without environment set correctly, run "meson test" instead')
|
||||||
|
|||||||
@ -18,9 +18,9 @@ import subprocess
|
|||||||
import dbus
|
import dbus
|
||||||
import dbus.mainloop.glib
|
import dbus.mainloop.glib
|
||||||
import dbusmock
|
import dbusmock
|
||||||
import fcntl
|
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
from output_checker import OutputChecker
|
||||||
|
|
||||||
|
|
||||||
VALID_FINGER_NAMES = [
|
VALID_FINGER_NAMES = [
|
||||||
@ -77,10 +77,8 @@ class TestFprintdUtilsBase(dbusmock.DBusTestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
|
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
|
||||||
self.template_name, {}, stdout=subprocess.PIPE)
|
self.template_name, {})
|
||||||
# set log to nonblocking
|
# set log to nonblocking
|
||||||
flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
|
|
||||||
fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
|
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@ -102,22 +100,21 @@ class TestFprintdUtilsBase(dbusmock.DBusTestCase):
|
|||||||
|
|
||||||
def start_utility_process(self, utility_name, args=[], sleep=True):
|
def start_utility_process(self, utility_name, args=[], sleep=True):
|
||||||
utility = [ os.path.join(self.tools_prefix, 'fprintd-{}'.format(utility_name)) ]
|
utility = [ os.path.join(self.tools_prefix, 'fprintd-{}'.format(utility_name)) ]
|
||||||
|
output = OutputChecker()
|
||||||
process = subprocess.Popen(self.wrapper_args + utility + args,
|
process = subprocess.Popen(self.wrapper_args + utility + args,
|
||||||
stdout=subprocess.PIPE,
|
stdout=output.fd,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT)
|
||||||
universal_newlines=True)
|
output.writer_attached()
|
||||||
flags = fcntl.fcntl(process.stdout, fcntl.F_GETFL)
|
|
||||||
fcntl.fcntl(process.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
|
|
||||||
|
|
||||||
|
self.addCleanup(output.assert_closed)
|
||||||
self.addCleanup(self.try_stop_utility_process, process)
|
self.addCleanup(self.try_stop_utility_process, process)
|
||||||
|
|
||||||
if sleep:
|
if sleep:
|
||||||
time.sleep(self.sleep_time)
|
time.sleep(self.sleep_time)
|
||||||
|
|
||||||
return process
|
return process, output
|
||||||
|
|
||||||
def stop_utility_process(self, process):
|
def stop_utility_process(self, process):
|
||||||
print(process.stdout.read())
|
|
||||||
process.terminate()
|
process.terminate()
|
||||||
process.wait()
|
process.wait()
|
||||||
|
|
||||||
@ -127,17 +124,12 @@ class TestFprintdUtilsBase(dbusmock.DBusTestCase):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_process_output(self, process):
|
|
||||||
out = process.stdout.read()
|
|
||||||
self.addCleanup(print, out)
|
|
||||||
return out
|
|
||||||
|
|
||||||
def run_utility_process(self, utility_name, args=[], sleep=True, timeout=None):
|
def run_utility_process(self, utility_name, args=[], sleep=True, timeout=None):
|
||||||
proc = self.start_utility_process(utility_name, args=args, sleep=sleep)
|
proc, output = self.start_utility_process(utility_name, args=args, sleep=sleep)
|
||||||
ret = proc.wait(timeout=timeout if timeout is not None else self.sleep_time * 4)
|
ret = proc.wait(timeout=timeout if timeout is not None else self.sleep_time * 4)
|
||||||
self.assertLessEqual(ret, 128)
|
self.assertLessEqual(ret, 128)
|
||||||
|
|
||||||
return self.get_process_output(proc), ret
|
return b''.join(output.clear()), ret
|
||||||
|
|
||||||
|
|
||||||
class TestFprintdUtils(TestFprintdUtilsBase):
|
class TestFprintdUtils(TestFprintdUtilsBase):
|
||||||
@ -146,65 +138,62 @@ class TestFprintdUtils(TestFprintdUtilsBase):
|
|||||||
self.setup_device()
|
self.setup_device()
|
||||||
|
|
||||||
def test_fprintd_enroll(self):
|
def test_fprintd_enroll(self):
|
||||||
process = self.start_utility_process('enroll', ['-f', 'right-index-finger', 'toto'])
|
process, out = self.start_utility_process('enroll', ['-f', 'right-index-finger', 'toto'])
|
||||||
|
|
||||||
out = self.get_process_output(process)
|
out.check_line(rb'right-index-finger', 0)
|
||||||
self.assertRegex(out, r'right-index-finger')
|
|
||||||
|
|
||||||
self.device_mock.EmitEnrollStatus('enroll-completed', True)
|
self.device_mock.EmitEnrollStatus('enroll-completed', True)
|
||||||
time.sleep(self.sleep_time)
|
|
||||||
|
|
||||||
out = self.get_process_output(process)
|
out.check_line(rb'Enroll result: enroll-completed', self.sleep_time)
|
||||||
self.assertRegex(out, 'Enroll result: enroll-completed')
|
|
||||||
|
|
||||||
def test_fprintd_list(self):
|
def test_fprintd_list(self):
|
||||||
# Rick has no fingerprints enrolled
|
# Rick has no fingerprints enrolled
|
||||||
out, ret = self.run_utility_process('list', ['rick'])
|
out, ret = self.run_utility_process('list', ['rick'])
|
||||||
self.assertRegex(out, r'has no fingers enrolled for')
|
self.assertRegex(out, rb'has no fingers enrolled for')
|
||||||
self.assertEqual(ret, 0)
|
self.assertEqual(ret, 0)
|
||||||
|
|
||||||
# Toto does
|
# Toto does
|
||||||
out, ret = self.run_utility_process('list', ['toto'])
|
out, ret = self.run_utility_process('list', ['toto'])
|
||||||
self.assertRegex(out, r'right-little-finger')
|
self.assertRegex(out, rb'right-little-finger')
|
||||||
self.assertEqual(ret, 0)
|
self.assertEqual(ret, 0)
|
||||||
|
|
||||||
def test_fprintd_delete(self):
|
def test_fprintd_delete(self):
|
||||||
# Has fingerprints enrolled
|
# Has fingerprints enrolled
|
||||||
out, ret = self.run_utility_process('list', ['toto'])
|
out, ret = self.run_utility_process('list', ['toto'])
|
||||||
self.assertRegex(out, r'left-little-finger')
|
self.assertRegex(out, rb'left-little-finger')
|
||||||
self.assertEqual(ret, 0)
|
self.assertEqual(ret, 0)
|
||||||
self.assertRegex(out, r'right-little-finger')
|
self.assertRegex(out, rb'right-little-finger')
|
||||||
|
|
||||||
# Delete fingerprints
|
# Delete fingerprints
|
||||||
out, ret = self.run_utility_process('delete', ['toto'])
|
out, ret = self.run_utility_process('delete', ['toto'])
|
||||||
self.assertRegex(out, r'Fingerprints deleted')
|
self.assertRegex(out, rb'Fingerprints deleted')
|
||||||
self.assertEqual(ret, 0)
|
self.assertEqual(ret, 0)
|
||||||
|
|
||||||
# Doesn't have fingerprints
|
# Doesn't have fingerprints
|
||||||
out, ret = self.run_utility_process('list', ['toto'])
|
out, ret = self.run_utility_process('list', ['toto'])
|
||||||
self.assertRegex(out, r'has no fingers enrolled for')
|
self.assertRegex(out, rb'has no fingers enrolled for')
|
||||||
self.assertEqual(ret, 0)
|
self.assertEqual(ret, 0)
|
||||||
|
|
||||||
|
|
||||||
class TestFprintdUtilsNoDeviceTests(TestFprintdUtilsBase):
|
class TestFprintdUtilsNoDeviceTests(TestFprintdUtilsBase):
|
||||||
def test_fprintd_enroll(self):
|
def test_fprintd_enroll(self):
|
||||||
out, ret = self.run_utility_process('enroll', ['toto'])
|
out, ret = self.run_utility_process('enroll', ['toto'])
|
||||||
self.assertIn('No devices available', out)
|
self.assertIn(b'No devices available', out)
|
||||||
self.assertEqual(ret, 1)
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
def test_fprintd_list(self):
|
def test_fprintd_list(self):
|
||||||
out, ret = self.run_utility_process('list', ['toto'])
|
out, ret = self.run_utility_process('list', ['toto'])
|
||||||
self.assertIn('No devices available', out)
|
self.assertIn(b'No devices available', out)
|
||||||
self.assertEqual(ret, 1)
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
def test_fprintd_delete(self):
|
def test_fprintd_delete(self):
|
||||||
out, ret = self.run_utility_process('delete', ['toto'])
|
out, ret = self.run_utility_process('delete', ['toto'])
|
||||||
self.assertIn('No devices available', out)
|
self.assertIn(b'No devices available', out)
|
||||||
self.assertEqual(ret, 1)
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
def test_fprintd_verify(self):
|
def test_fprintd_verify(self):
|
||||||
out, ret = self.run_utility_process('verify', ['toto'])
|
out, ret = self.run_utility_process('verify', ['toto'])
|
||||||
self.assertIn('No devices available', out)
|
self.assertIn(b'No devices available', out)
|
||||||
self.assertEqual(ret, 1)
|
self.assertEqual(ret, 1)
|
||||||
|
|
||||||
|
|
||||||
@ -213,24 +202,20 @@ class TestFprintdUtilsVerify(TestFprintdUtilsBase):
|
|||||||
super().setUp()
|
super().setUp()
|
||||||
self.setup_device()
|
self.setup_device()
|
||||||
|
|
||||||
def start_verify_process(self, user='toto', finger=None, checkEnrolled=True):
|
def start_verify_process(self, user='toto', finger=None, nowait=False):
|
||||||
args = [user]
|
args = [user]
|
||||||
if finger:
|
if finger:
|
||||||
args += ['-f', finger]
|
args += ['-f', finger]
|
||||||
|
|
||||||
self.process = self.start_utility_process('verify', args)
|
self.process, self.output = self.start_utility_process('verify', args)
|
||||||
out = self.get_process_output(self.process)
|
if nowait:
|
||||||
|
return
|
||||||
|
|
||||||
self.assertNotRegex(out, r'Device already in use by [A-z]+')
|
preamble = self.output.check_line(b'Verify started!')
|
||||||
self.assertNotIn('Verify result:', out)
|
|
||||||
|
|
||||||
if checkEnrolled and finger:
|
out = b''.join(preamble)
|
||||||
self.assertNotIn('''Finger '{}' not enrolled for user {}'''.format(
|
|
||||||
finger, user), out)
|
|
||||||
|
|
||||||
if checkEnrolled:
|
self.assertNotIn(b'Verify result:', out)
|
||||||
for f in self.enrolled_fingers:
|
|
||||||
self.assertIn(f, out)
|
|
||||||
|
|
||||||
if finger:
|
if finger:
|
||||||
expected_finger = finger
|
expected_finger = finger
|
||||||
@ -239,9 +224,8 @@ class TestFprintdUtilsVerify(TestFprintdUtilsBase):
|
|||||||
self.assertEqual(self.device_mock.GetSelectedFinger(), expected_finger)
|
self.assertEqual(self.device_mock.GetSelectedFinger(), expected_finger)
|
||||||
|
|
||||||
def assertVerifyMatch(self, match):
|
def assertVerifyMatch(self, match):
|
||||||
self.assertIn('Verify result: {} (done)'.format(
|
self.output.check_line(r'Verify result: {} (done)'.format(
|
||||||
'verify-match' if match else 'verify-no-match'),
|
'verify-match' if match else 'verify-no-match'))
|
||||||
self.get_process_output(self.process))
|
|
||||||
|
|
||||||
def test_fprintd_verify(self):
|
def test_fprintd_verify(self):
|
||||||
self.start_verify_process()
|
self.start_verify_process()
|
||||||
@ -280,14 +264,16 @@ class TestFprintdUtilsVerify(TestFprintdUtilsBase):
|
|||||||
|
|
||||||
def test_fprintd_verify_not_enrolled_fingers(self):
|
def test_fprintd_verify_not_enrolled_fingers(self):
|
||||||
for finger in [f for f in VALID_FINGER_NAMES if f not in self.enrolled_fingers]:
|
for finger in [f for f in VALID_FINGER_NAMES if f not in self.enrolled_fingers]:
|
||||||
|
self.start_verify_process(finger=finger, nowait=True)
|
||||||
regex = r'Finger \'{}\' not enrolled'.format(finger)
|
regex = r'Finger \'{}\' not enrolled'.format(finger)
|
||||||
with self.assertRaisesRegex(AssertionError, regex):
|
self.output.check_line_re(regex, timeout=self.sleep_time)
|
||||||
self.start_verify_process(finger=finger)
|
|
||||||
self.device_mock.Release()
|
self.device_mock.Release()
|
||||||
|
|
||||||
def test_fprintd_verify_no_enrolled_fingers(self):
|
def test_fprintd_verify_no_enrolled_fingers(self):
|
||||||
self.set_enrolled_fingers([])
|
self.set_enrolled_fingers([])
|
||||||
self.start_verify_process()
|
self.start_verify_process(nowait=True)
|
||||||
|
self.output.check_line(b'No fingers enrolled for this device.', timeout=self.sleep_time)
|
||||||
self.assertEqual(self.process.poll(), 1)
|
self.assertEqual(self.process.poll(), 1)
|
||||||
|
|
||||||
def test_fprintd_list_all_fingers(self):
|
def test_fprintd_list_all_fingers(self):
|
||||||
@ -299,16 +285,17 @@ class TestFprintdUtilsVerify(TestFprintdUtilsBase):
|
|||||||
( 'verify-match', True, 2 )
|
( 'verify-match', True, 2 )
|
||||||
]
|
]
|
||||||
self.device_mock.SetVerifyScript(script)
|
self.device_mock.SetVerifyScript(script)
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
self.start_verify_process()
|
self.start_verify_process()
|
||||||
time.sleep(self.sleep_time * 4)
|
time.sleep(2 + self.sleep_time)
|
||||||
self.assertVerifyMatch(True)
|
self.assertVerifyMatch(True)
|
||||||
|
|
||||||
def test_fprintd_multiple_verify_fails(self):
|
def test_fprintd_multiple_verify_fails(self):
|
||||||
self.start_verify_process()
|
self.start_verify_process()
|
||||||
|
|
||||||
with self.assertRaisesRegex(AssertionError, r'Device already in use'):
|
self.start_verify_process(nowait=True)
|
||||||
self.start_verify_process()
|
self.output.check_line_re(rb'Device already in use by [A-z]+', timeout=self.sleep_time)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# avoid writing to stderr
|
# avoid writing to stderr
|
||||||
|
|||||||
@ -120,12 +120,18 @@ static void find_finger (FprintDBusDevice *dev, const char *username)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VerifyState {
|
||||||
|
GError *error;
|
||||||
|
gboolean started;
|
||||||
|
gboolean completed;
|
||||||
|
};
|
||||||
|
|
||||||
static void verify_result(GObject *object, const char *result, gboolean done, void *user_data)
|
static void verify_result(GObject *object, const char *result, gboolean done, void *user_data)
|
||||||
{
|
{
|
||||||
gboolean *verify_completed = user_data;
|
struct VerifyState *verify_state = user_data;
|
||||||
g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done");
|
g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done");
|
||||||
if (done != FALSE)
|
if (done != FALSE)
|
||||||
*verify_completed = TRUE;
|
verify_state->completed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void verify_finger_selected(GObject *object, const char *name, void *user_data)
|
static void verify_finger_selected(GObject *object, const char *name, void *user_data)
|
||||||
@ -133,12 +139,27 @@ static void verify_finger_selected(GObject *object, const char *name, void *user
|
|||||||
g_print("Verifying: %s\n", name);
|
g_print("Verifying: %s\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void verify_started_cb (GObject *obj,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
struct VerifyState *verify_state = user_data;
|
||||||
|
|
||||||
|
if (fprint_dbus_device_call_verify_start_finish (FPRINT_DBUS_DEVICE (obj), res, &verify_state->error))
|
||||||
|
verify_state->started = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void proxy_signal_cb (GDBusProxy *proxy,
|
static void proxy_signal_cb (GDBusProxy *proxy,
|
||||||
const gchar *sender_name,
|
const gchar *sender_name,
|
||||||
const gchar *signal_name,
|
const gchar *signal_name,
|
||||||
GVariant *parameters,
|
GVariant *parameters,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
|
struct VerifyState *verify_state = user_data;
|
||||||
|
|
||||||
|
if (!verify_state->started)
|
||||||
|
return;
|
||||||
|
|
||||||
if (g_str_equal (signal_name, "VerifyStatus")) {
|
if (g_str_equal (signal_name, "VerifyStatus")) {
|
||||||
const gchar *result;
|
const gchar *result;
|
||||||
gboolean done;
|
gboolean done;
|
||||||
@ -156,23 +177,44 @@ static void proxy_signal_cb (GDBusProxy *proxy,
|
|||||||
static void do_verify (FprintDBusDevice *dev)
|
static void do_verify (FprintDBusDevice *dev)
|
||||||
{
|
{
|
||||||
g_autoptr(GError) error = NULL;
|
g_autoptr(GError) error = NULL;
|
||||||
gboolean verify_completed = FALSE;
|
struct VerifyState verify_state = { 0 };
|
||||||
|
|
||||||
|
/* This one is funny. We connect to the signal immediately to avoid
|
||||||
|
* race conditions. However, we must ignore any authentication results
|
||||||
|
* that happen before our start call returns.
|
||||||
|
* This is because the verify call itself may internally try to verify
|
||||||
|
* against fprintd (possibly using a separate account).
|
||||||
|
*
|
||||||
|
* To do so, we *must* use the async version of the verify call, as the
|
||||||
|
* sync version would cause the signals to be queued and only processed
|
||||||
|
* after it returns.
|
||||||
|
*/
|
||||||
|
|
||||||
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
|
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
|
||||||
&verify_completed);
|
&verify_state);
|
||||||
|
|
||||||
if (!fprint_dbus_device_call_verify_start_sync (dev, finger_name, NULL,
|
fprint_dbus_device_call_verify_start (dev, finger_name, NULL,
|
||||||
&error)) {
|
verify_started_cb,
|
||||||
g_print("VerifyStart failed: %s\n", error->message);
|
&verify_state);
|
||||||
|
|
||||||
|
/* Wait for verify start while discarding any VerifyStatus signals */
|
||||||
|
while (!verify_state.started && !verify_state.error)
|
||||||
|
g_main_context_iteration(NULL, TRUE);
|
||||||
|
|
||||||
|
if (verify_state.error) {
|
||||||
|
g_print("VerifyStart failed: %s\n", verify_state.error->message);
|
||||||
|
g_clear_error (&verify_state.error);
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
g_print("Verify started!\n");
|
||||||
|
|
||||||
while (!verify_completed)
|
/* VerifyStatus signals are processing, wait for completion. */
|
||||||
|
while (!verify_state.completed)
|
||||||
g_main_context_iteration(NULL, TRUE);
|
g_main_context_iteration(NULL, TRUE);
|
||||||
|
|
||||||
|
|
||||||
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb,
|
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb,
|
||||||
&verify_completed);
|
&verify_state);
|
||||||
|
|
||||||
if (!fprint_dbus_device_call_verify_stop_sync (dev, NULL, &error)) {
|
if (!fprint_dbus_device_call_verify_stop_sync (dev, NULL, &error)) {
|
||||||
g_print("VerifyStop failed: %s\n", error->message);
|
g_print("VerifyStop failed: %s\n", error->message);
|
||||||
|
|||||||
Reference in New Issue
Block a user