41 Commits

Author SHA1 Message Date
da60bddb3e Release 1.90.9 2021-01-13 13:23:24 +01:00
506d99e90c tests: Check that two consecutive runs work 2021-01-11 12:59:06 +00:00
e7f47e28d7 tests: Add finger and connection sharing for virtual image
This allows testing some more conditions (e.g. forcing VerifyStop to run
into a cancellation).
2021-01-11 12:59:06 +00:00
938c1aac5a device: Add common stoppable_action_completed function
The stoppable actions (Verify/Enroll) have the same logic during
completion. Create a common function to share this logic instead of
copying it in each of the handlers.

Fixes: #97
2021-01-11 12:59:06 +00:00
fd02922608 pam: Pick the device with more enrolled finger prints
When multiple devices are available PAM module will just pick the first
one, even if it has not enrolled fingers.

Since this can't be user configured (yet) we can be a bit smarter and
select the device that has more fingerprints configured for the user.
2021-01-05 12:16:09 +00:00
195f7eaf5f tests/fprintd: Check that fingers deletion will remove user print
But will keep state dir where it is
2021-01-05 13:07:19 +01:00
48ea3b89c9 file_storage: Cleanup the user storage path when removing prints
Try to remove user and devices directories if they are empty.
2021-01-05 13:07:19 +01:00
4cfa6b5b37 file_storage: Remove debug leftovers and add actual debug statements 2021-01-05 13:07:19 +01:00
c685f0d34c file_storage: Don't return an error if the print doesn't exist
We may just try to remove something isn't there so it's not an actual
error from our POV.
2021-01-05 13:07:19 +01:00
eece834231 file_storage: Do not remove the finger path two times
Return the actual operation error instead
2021-01-05 13:07:19 +01:00
3faaa81257 file_storage: Do not ignore STATE_DIRECTORY if it's set to an actual path 2021-01-05 13:07:19 +01:00
b9cdb58a1a device: Load the current finger print and not always the first print
In the garbage collection code we always ended up to load the first
enrolled print, and this may lead to removing from device storage prints
that are actually in use.
2021-01-05 12:57:55 +01:00
ab8dcfaa61 treewide: fix typos 2021-01-04 11:04:13 +01:00
25a97c8276 tests: Add disconnect tests for enroll/verify/identify
We test both the scenario where VerifyStop/EnrollStop is not called
while the operation is still ongoing or when the operation is already
finished.
2021-01-04 11:00:18 +01:00
8057e49d31 tests: Allow claiming in secondary bus helper
This saves an extra step when creating tests that disconnect.
2021-01-04 11:00:18 +01:00
f75e800d5c tests: Allow enrolling from different device
This simplfies disconnect tests as we can do the enroll from the client
that will disconnect later on.
2021-01-04 11:00:18 +01:00
6ae4f5e939 tests: Add get_secondary_bus_and_device helper
It returns a new bus object and the device on that bus. This allows
testing what happens if a client disconnects from the bus.
2021-01-04 11:00:18 +01:00
7c9a04c2ae device: Fix race when client vanishes from bus
We have a condition where a client vanishing instead of cleaning up the
operation using VerifyStop would cause fprintd to hang. This only
happens if the underlying enroll/verify/identify operation has already
finished when the client vanishes.

Fix this by correctly interpreting current_cancellable as a flag for
these operations.

Fixes: #97
2021-01-04 11:00:18 +01:00
7b7aa6e99d device: Fix typos 2021-01-04 09:49:24 +08:00
b624f8c8c7 manager: Do not use unnecessary volatile qualifier on GQuark
As per new GLib in CI image fprintd doesn't build anymore, since
g_once_init_enter now warns about using a volatile value, as this has
never been supposed to be the case, despite its signature [1].

Related to: https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1719

[1] https://gitlab.gnome.org/GNOME/glib/-/issues/600
2020-12-19 22:34:12 +01:00
3e81179eca device: Add auto-cleanup function to unset the current action
This is useful in the functions where we have to unset the device's
current action but we may use early-return to handle multiple conditions
such as in open, close and delete functions.
The latest also currently is a bit buggy as it won't reset the state on
some failures.
2020-12-17 16:33:58 +01:00
c6647ba875 tests: Add test that enforces a verify/identify operation restart
In the usual test we cancel the operation immediately by calling
VerifyStop. This (often) tests the case where we don't end up restarting
the Verify operation internally.

We can easily force fprintd to have restarted already internally, so add
a test that does so by sleeping a bit. This should give us a slightly
higher branch coverage in the verify_cb/identify_cb tests.
2020-12-16 14:44:23 +01:00
988ee01f66 tests: Add retry test for PAM 2020-12-16 14:12:37 +01:00
32ee94c8a0 Add compatibility defines to allow compiling with older glib
We need at least the GFlagsClass autoptr, but just pull in most of the
definitions from libfprint.
2020-12-14 11:30:45 +01:00
7d22a2b5b9 Release 1.90.8 2020-12-11 16:00:28 +01:00
de725a91e4 verify: Print message about verification start from callback
It seems that GLib may process multiple DBus signals in one mainloop
iteration. This could cause messages to be re-ordered, which in turn
caused a race condition in the CI that could trigger random failures.
2020-12-11 16:00:28 +01:00
18392cba54 manager: Export the object manager in /net/reactivated/Fprint
Given we're going to use an object manager it can just stay at the root
of the project, while it will be just used to manage the devices
2020-12-11 15:30:26 +01:00
783d82f359 device: Expose method name when logging authorization steps 2020-12-11 14:03:37 +00:00
c00a3375d1 device: Use standard names for local errors and remove unused one 2020-12-11 14:03:37 +00:00
5aa61adabc build: make systemd dependency optional
The systemd dependency is only used to install some systemd service
files. This can easily be made optional.
2020-12-11 15:01:24 +01:00
1fc10f15ee pam: Stop authorization if we couldn't parse signals
This really should never ever happen. If it does, don't continue but
stop instead.
2020-12-11 10:34:51 +01:00
c24badfd68 pam: Move NameOwnerChanged registration after initialization
We must ignore NameOwnerChanged that happen due to automatic startup.
The easy way to do so is to just register it only when we get to the
point that a name owner change has security implications.

While add it, change it to always log at a warning level.

Fixes: #94
2020-12-11 10:34:51 +01:00
4612c1f3ed Release 1.90.7 2020-12-09 13:16:12 +01:00
ca216a32af test_pam_fprintd: Add test verifying the case in which we've no devices 2020-12-08 21:14:24 +01:00
944493e472 pam_fprintd: Protect usage of strdup for NULL values
It's not smart as g_strdup, so need to ensure we don't use it for NULL
strings.

This is a regression caused by commit bf223662
2020-12-08 21:14:01 +01:00
34f24cbe19 ci: Move build jobs to build phase 2020-12-07 18:42:24 +01:00
9314069a88 ci: Add check-source stage where we check syntax 2020-12-07 18:42:24 +01:00
66e21eac8f .git-blame-ignore-revs: Ignore formatting commit and add hint how to use it 2020-12-07 18:42:22 +01:00
f73429f062 fprintd: Reindent the source code following uncrustify rules 2020-12-07 18:41:45 +01:00
c18ebaf9da scripts: Add uncrustify scripts for reformatting fprintd source code
We follow libfprint here, using GNOME format
2020-12-07 18:41:45 +01:00
4a80bfacec fingerprint-strings: Make the finger_str_to_msg loop clearer
Just continue earlier instead of using a long if check
2020-12-07 18:41:45 +01:00
24 changed files with 4158 additions and 3248 deletions

7
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,7 @@
# The commits that did automated reformatting. You can ignore them
# during git-blame with `--ignore-rev` or `--ignore-revs-file`.
#
# $ git config --add 'blame.ignoreRevsFile' '.git-blame-ignore-revs'
#
f73429f06226f5423c92b1c504313657c9b6f9b5

View File

@ -29,6 +29,11 @@ variables:
image: "$FEDORA_IMAGE"
stages:
- check-source
- build
- test
.fprintd_build_preconditions:
except:
variables:
@ -47,8 +52,17 @@ image: "$FEDORA_IMAGE"
# So we don't get error about this libfprint file
- echo "libfprint/demo/gtk-libfprint-test.ui" >> po/POTFILES.skip
test_indent:
stage: check-source
extends: .fprintd_build_preconditions
script:
- scripts/uncrustify.sh
- git diff
- "! git status -s | grep -q ."
build_stable:
extends: .fprintd_build_preconditions
stage: build
script:
- meson _build
- ninja -C _build -v
@ -58,6 +72,7 @@ build_dev:
extends:
- .fprintd_build_preconditions
- .install_libfprint_dev
stage: build
script:
- meson _build --werror -Dgtk_doc=true
- ninja -C _build -v

30
NEWS
View File

@ -1,6 +1,36 @@
This file lists notable changes in each release. For the full history of all
changes, see ChangeLog.
Version 1.90.9:
Highlights:
- Fix multiple daemon lockup issues (#97)
- Fix print garbage collection to not delete used prints
- pam: Use the device with the most prints
Version 1.90.8:
It seems that we are finally reaching the end of the tunnel with regard
to regressions. One more issue that cropped up was that a pam_fprintd fix
to avoid a possible authentication bypass caused issues when fprintd was
just started on demand.
Highlights:
- pam: Only listen to NameOwnerChanged after fprintd is known to run (#94)
- Place new ObjectManager DBus API at /net/reactivated/Fprint
Version 1.90.7:
While 1.90.6 fixed a number of issues, we did have a bad regression due
causing pam_fprintd to crash when there are no fingerprint devices
installed.
Highlights:
- pam: Guard strdup calls against NULL pointers
Version 1.90.6:
The 1.90.5 release was unusable due to a number of inter-related issues

View File

@ -11,15 +11,17 @@ configure_file(
install_dir: dbus_service_dir,
)
configure_file(
configuration: configuration_data({
'libexecdir': fprintd_installdir,
}),
input: 'fprintd.service.in',
output: 'fprintd.service',
install: true,
install_dir: systemd_unit_dir,
)
if get_option('systemd')
configure_file(
configuration: configuration_data({
'libexecdir': fprintd_installdir,
}),
input: 'fprintd.service.in',
output: 'fprintd.service',
install: true,
install_dir: systemd_unit_dir,
)
endif
polkit_policy = 'net.reactivated.fprint.device.policy'
polkit_policy_target = i18n.merge_file(polkit_policy,

View File

@ -1,5 +1,5 @@
project('fprintd', 'c',
version: '1.90.6',
version: '1.90.9',
license: 'GPLv2+',
default_options: [
'buildtype=debugoptimized',
@ -94,13 +94,17 @@ pod2man = find_program('pod2man', required: get_option('man'))
xsltproc = find_program('xsltproc', required: get_option('gtk_doc'))
# StateDirectory was introduced in systemd 235
systemd_dep = dependency('systemd', version: '>= 235')
systemd_dep = dependency('systemd', version: '>= 235', required: false)
systemd_unit_dir = get_option('systemd_system_unit_dir')
if systemd_unit_dir == ''
if systemd_unit_dir == '' and systemd_dep.found()
systemd_unit_dir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir')
endif
if get_option('systemd') and systemd_unit_dir == ''
error('systemd development files or systemd_system_unit_dir is needed for systemd support.')
endif
dbus_service_dir = get_option('dbus_service_dir')
dbus_data_dir = datadir
dbus_interfaces_dir = ''

View File

@ -6,6 +6,10 @@ option('man',
description: 'Generate the man files',
type: 'boolean',
value: true)
option('systemd',
description: 'Install system service files',
type: 'boolean',
value: true)
option('systemd_system_unit_dir',
description: 'Directory for systemd service files',
type: 'string')

View File

@ -1,7 +1,7 @@
/*
* Helper functions to translate statuses and actions to strings
* Copyright (C) 2008 Bastien Nocera <hadess@hadess.net>
*
*
* Experimental code. This will be moved out of fprintd into it's own
* package once the system has matured.
*
@ -9,12 +9,12 @@
* 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.
@ -28,115 +28,128 @@
#define GNUC_UNUSED __attribute__((__unused__))
static bool str_equal (const char *a, const char *b)
static bool
str_equal (const char *a, const char *b)
{
if (a == NULL && b == NULL)
return true;
if (a == NULL || b == NULL)
return false;
return (strcmp (a, b) == 0);
if (a == NULL && b == NULL)
return true;
if (a == NULL || b == NULL)
return false;
return strcmp (a, b) == 0;
}
struct {
const char *dbus_name;
const char *place_str_generic;
const char *place_str_specific;
const char *swipe_str_generic;
const char *swipe_str_specific;
struct
{
const char *dbus_name;
const char *place_str_generic;
const char *place_str_specific;
const char *swipe_str_generic;
const char *swipe_str_specific;
} fingers[] = {
{ "any",
N_("Place your finger on the fingerprint reader"),
N_("Place your finger on %s"),
N_("Swipe your finger across the fingerprint reader"),
N_("Swipe your finger across %s") },
{ "left-thumb",
N_("Place your left thumb on the fingerprint reader"),
N_("Place your left thumb on %s"),
N_("Swipe your left thumb across the fingerprint reader"),
N_("Swipe your left thumb across %s") },
{ "left-index-finger",
N_("Place your left index finger on the fingerprint reader"),
N_("Place your left index finger on %s"),
N_("Swipe your left index finger across the fingerprint reader"),
N_("Swipe your left index finger across %s") },
{ "left-middle-finger",
N_("Place your left middle finger on the fingerprint reader"),
N_("Place your left middle finger on %s"),
N_("Swipe your left middle finger across the fingerprint reader"),
N_("Swipe your left middle finger across %s") },
{ "left-ring-finger",
N_("Place your left ring finger on the fingerprint reader"),
N_("Place your left ring finger on %s"),
N_("Swipe your left ring finger across the fingerprint reader"),
N_("Swipe your left ring finger across %s") },
{ "left-little-finger",
N_("Place your left little finger on the fingerprint reader"),
N_("Place your left little finger on %s"),
N_("Swipe your left little finger across the fingerprint reader"),
N_("Swipe your left little finger across %s") },
{ "right-thumb",
N_("Place your right thumb on the fingerprint reader"),
N_("Place your right thumb on %s"),
N_("Swipe your right thumb across the fingerprint reader"),
N_("Swipe your right thumb across %s") },
{ "right-index-finger",
N_("Place your right index finger on the fingerprint reader"),
N_("Place your right index finger on %s"),
N_("Swipe your right index finger across the fingerprint reader"),
N_("Swipe your right index finger across %s") },
{ "right-middle-finger",
N_("Place your right middle finger on the fingerprint reader"),
N_("Place your right middle finger on %s"),
N_("Swipe your right middle finger across the fingerprint reader"),
N_("Swipe your right middle finger across %s") },
{ "right-ring-finger",
N_("Place your right ring finger on the fingerprint reader"),
N_("Place your right ring finger on %s"),
N_("Swipe your right ring finger across the fingerprint reader"),
N_("Swipe your right ring finger across %s") },
{ "right-little-finger",
N_("Place your right little finger on the fingerprint reader"),
N_("Place your right little finger on %s"),
N_("Swipe your right little finger across the fingerprint reader"),
N_("Swipe your right little finger across %s") },
{ NULL, NULL, NULL, NULL, NULL }
{ "any",
N_("Place your finger on the fingerprint reader"),
N_("Place your finger on %s"),
N_("Swipe your finger across the fingerprint reader"),
N_("Swipe your finger across %s") },
{ "left-thumb",
N_("Place your left thumb on the fingerprint reader"),
N_("Place your left thumb on %s"),
N_("Swipe your left thumb across the fingerprint reader"),
N_("Swipe your left thumb across %s") },
{ "left-index-finger",
N_("Place your left index finger on the fingerprint reader"),
N_("Place your left index finger on %s"),
N_("Swipe your left index finger across the fingerprint reader"),
N_("Swipe your left index finger across %s") },
{ "left-middle-finger",
N_("Place your left middle finger on the fingerprint reader"),
N_("Place your left middle finger on %s"),
N_("Swipe your left middle finger across the fingerprint reader"),
N_("Swipe your left middle finger across %s") },
{ "left-ring-finger",
N_("Place your left ring finger on the fingerprint reader"),
N_("Place your left ring finger on %s"),
N_("Swipe your left ring finger across the fingerprint reader"),
N_("Swipe your left ring finger across %s") },
{ "left-little-finger",
N_("Place your left little finger on the fingerprint reader"),
N_("Place your left little finger on %s"),
N_("Swipe your left little finger across the fingerprint reader"),
N_("Swipe your left little finger across %s") },
{ "right-thumb",
N_("Place your right thumb on the fingerprint reader"),
N_("Place your right thumb on %s"),
N_("Swipe your right thumb across the fingerprint reader"),
N_("Swipe your right thumb across %s") },
{ "right-index-finger",
N_("Place your right index finger on the fingerprint reader"),
N_("Place your right index finger on %s"),
N_("Swipe your right index finger across the fingerprint reader"),
N_("Swipe your right index finger across %s") },
{ "right-middle-finger",
N_("Place your right middle finger on the fingerprint reader"),
N_("Place your right middle finger on %s"),
N_("Swipe your right middle finger across the fingerprint reader"),
N_("Swipe your right middle finger across %s") },
{ "right-ring-finger",
N_("Place your right ring finger on the fingerprint reader"),
N_("Place your right ring finger on %s"),
N_("Swipe your right ring finger across the fingerprint reader"),
N_("Swipe your right ring finger across %s") },
{ "right-little-finger",
N_("Place your right little finger on the fingerprint reader"),
N_("Place your right little finger on %s"),
N_("Swipe your right little finger across the fingerprint reader"),
N_("Swipe your right little finger across %s") },
{ NULL, NULL, NULL, NULL, NULL }
};
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
GNUC_UNUSED static char *finger_str_to_msg(const char *finger_name, const char *driver_name, bool is_swipe)
GNUC_UNUSED static char *
finger_str_to_msg (const char *finger_name, const char *driver_name, bool is_swipe)
{
int i;
int i;
if (finger_name == NULL)
return NULL;
if (finger_name == NULL)
return NULL;
for (i = 0; fingers[i].dbus_name != NULL; i++) {
if (str_equal (fingers[i].dbus_name, finger_name)) {
if (is_swipe == false) {
if (driver_name) {
char *s;
int ret;
ret = asprintf (&s, TR (fingers[i].place_str_specific), driver_name);
return ret >= 0 ? s : NULL;
} else {
return strdup (TR (fingers[i].place_str_generic));
}
} else {
if (driver_name) {
char *s;
int ret;
ret = asprintf (&s, TR (fingers[i].swipe_str_specific), driver_name);
return ret >= 0 ? s : NULL;
} else {
return strdup (TR (fingers[i].swipe_str_generic));
}
}
}
}
for (i = 0; fingers[i].dbus_name != NULL; i++)
{
if (!str_equal (fingers[i].dbus_name, finger_name))
continue;
if (is_swipe == false)
{
if (driver_name)
{
char *s;
int ret;
ret = asprintf (&s, TR (fingers[i].place_str_specific), driver_name);
return ret >= 0 ? s : NULL;
}
else
{
return strdup (TR (fingers[i].place_str_generic));
}
}
else
{
if (driver_name)
{
char *s;
int ret;
ret = asprintf (&s, TR (fingers[i].swipe_str_specific), driver_name);
return ret >= 0 ? s : NULL;
}
else
{
return strdup (TR (fingers[i].swipe_str_generic));
}
}
}
return NULL;
return NULL;
}
#pragma GCC diagnostic pop
@ -146,25 +159,27 @@ GNUC_UNUSED static char *finger_str_to_msg(const char *finger_name, const char *
* verify-match
* verify-unknown-error
*/
GNUC_UNUSED static const char *verify_result_str_to_msg(const char *result, bool is_swipe)
GNUC_UNUSED static const char *
verify_result_str_to_msg (const char *result, bool is_swipe)
{
if (result == NULL)
return NULL;
if (result == NULL)
return NULL;
if (strcmp (result, "verify-retry-scan") == 0) {
if (is_swipe == false)
return TR (N_("Place your finger on the reader again"));
else
return TR (N_("Swipe your finger again"));
}
if (strcmp (result, "verify-swipe-too-short") == 0)
return TR (N_("Swipe was too short, try again"));
if (strcmp (result, "verify-finger-not-centered") == 0)
return TR (N_("Your finger was not centered, try swiping your finger again"));
if (strcmp (result, "verify-remove-and-retry") == 0)
return TR (N_("Remove your finger, and try swiping your finger again"));
if (strcmp (result, "verify-retry-scan") == 0)
{
if (is_swipe == false)
return TR (N_("Place your finger on the reader again"));
else
return TR (N_("Swipe your finger again"));
}
if (strcmp (result, "verify-swipe-too-short") == 0)
return TR (N_("Swipe was too short, try again"));
if (strcmp (result, "verify-finger-not-centered") == 0)
return TR (N_("Your finger was not centered, try swiping your finger again"));
if (strcmp (result, "verify-remove-and-retry") == 0)
return TR (N_("Remove your finger, and try swiping your finger again"));
return NULL;
return NULL;
}
/* Cases not handled:
@ -172,24 +187,25 @@ GNUC_UNUSED static const char *verify_result_str_to_msg(const char *result, bool
* enroll-failed
* enroll-unknown-error
*/
GNUC_UNUSED static const char *enroll_result_str_to_msg(const char *result, bool is_swipe)
GNUC_UNUSED static const char *
enroll_result_str_to_msg (const char *result, bool is_swipe)
{
if (result == NULL)
return NULL;
if (result == NULL)
return NULL;
if (strcmp (result, "enroll-retry-scan") == 0 || strcmp (result, "enroll-stage-passed") == 0) {
if (is_swipe == false)
return TR (N_("Place your finger on the reader again"));
else
return TR (N_("Swipe your finger again"));
}
if (strcmp (result, "enroll-swipe-too-short") == 0)
return TR (N_("Swipe was too short, try again"));
if (strcmp (result, "enroll-finger-not-centered") == 0)
return TR (N_("Your finger was not centered, try swiping your finger again"));
if (strcmp (result, "enroll-remove-and-retry") == 0)
return TR (N_("Remove your finger, and try swiping your finger again"));
if (strcmp (result, "enroll-retry-scan") == 0 || strcmp (result, "enroll-stage-passed") == 0)
{
if (is_swipe == false)
return TR (N_("Place your finger on the reader again"));
else
return TR (N_("Swipe your finger again"));
}
if (strcmp (result, "enroll-swipe-too-short") == 0)
return TR (N_("Swipe was too short, try again"));
if (strcmp (result, "enroll-finger-not-centered") == 0)
return TR (N_("Your finger was not centered, try swiping your finger again"));
if (strcmp (result, "enroll-remove-and-retry") == 0)
return TR (N_("Remove your finger, and try swiping your finger again"));
return NULL;
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -23,35 +23,36 @@
/* Define auto-pointers functions, based on GLib Macros */
#define _CLEANUP_FUNC(func) __attribute__((cleanup(func)))
#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_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); }
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 __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;
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)
_CLEANUP_FUNC (_PF_AUTOPTR_FUNC_NAME (TypeName)) \
_PF_AUTOPTR_TYPENAME (TypeName)
#define pf_auto(TypeName) \
_CLEANUP_FUNC (_PF_AUTOPTR_FUNC_NAME (TypeName)) 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)

137
scripts/uncrustify.cfg Normal file
View File

@ -0,0 +1,137 @@
newlines lf
input_tab_size 8
output_tab_size 8
string_escape_char 92
string_escape_char2 0
# indenting
indent_columns 2
indent_with_tabs 0
indent_align_string True
indent_brace 2
indent_braces false
indent_braces_no_func True
indent_func_call_param false
indent_func_def_param false
indent_func_proto_param false
indent_switch_case 0
indent_case_brace 2
indent_paren_close 1
# spacing
sp_arith Add
sp_assign Add
sp_enum_assign Add
sp_bool Add
sp_compare Add
sp_inside_paren Remove
sp_inside_fparens Remove
sp_func_def_paren Force
sp_func_proto_paren Force
sp_paren_paren Remove
sp_balance_nested_parens False
sp_paren_brace Remove
sp_before_square Remove
sp_before_squares Remove
sp_inside_square Remove
sp_before_ptr_star Add
sp_between_ptr_star Remove
sp_after_comma Add
sp_before_comma Remove
sp_after_cast Add
sp_sizeof_paren Add
sp_not Remove
sp_inv Remove
sp_addr Remove
sp_member Remove
sp_deref Remove
sp_sign Remove
sp_incdec Remove
sp_attribute_paren remove
sp_macro Force
sp_func_call_paren Force
sp_func_call_user_paren Remove
set func_call_user _ N_ C_ g_autoptr g_auto
sp_brace_typedef add
sp_cond_colon add
sp_cond_question add
sp_defined_paren remove
# alignment
align_keep_tabs False
align_with_tabs False
align_on_tabstop False
align_number_right False
align_func_params True
align_var_def_span 0
align_var_def_amp_style 1
align_var_def_colon true
align_enum_equ_span 0
align_var_struct_span 2
align_var_def_star_style 2
align_var_def_amp_style 2
align_typedef_span 2
align_typedef_func 0
align_typedef_star_style 2
align_typedef_amp_style 2
# newlines
nl_assign_leave_one_liners True
nl_enum_leave_one_liners False
nl_func_leave_one_liners False
nl_if_leave_one_liners False
nl_end_of_file Add
nl_assign_brace Remove
nl_func_var_def_blk 1
nl_fcall_brace Add
nl_enum_brace Remove
nl_struct_brace Force
nl_union_brace Force
nl_if_brace Force
nl_brace_else Force
nl_elseif_brace Force
nl_else_brace Add
nl_for_brace Force
nl_while_brace Force
nl_do_brace Force
nl_brace_while Force
nl_switch_brace Force
nl_before_case True
nl_after_case False
nl_func_type_name Force
nl_func_proto_type_name Remove
nl_func_paren Remove
nl_func_decl_start Remove
nl_func_decl_args Force
nl_func_decl_end Remove
nl_fdef_brace Force
nl_after_return False
nl_define_macro False
nl_create_if_one_liner False
nl_create_for_one_liner False
nl_create_while_one_liner False
nl_after_semicolon True
nl_multi_line_cond true
# mod
# I'd like these to be remove, but that removes brackets in if { if { foo } }, which i dislike
# Not clear what to do about that...
mod_full_brace_for Remove
mod_full_brace_if Remove
mod_full_brace_if_chain True
mod_full_brace_while Remove
mod_full_brace_do Remove
mod_full_brace_nl 3
mod_paren_on_return Remove
# line splitting
#code_width = 78
ls_for_split_full True
ls_func_split_full True
# positioning
pos_bool Trail
pos_conditional Trail

19
scripts/uncrustify.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/bash
SRCROOT=`git rev-parse --show-toplevel`
CFG="$SRCROOT/scripts/uncrustify.cfg"
echo "srcroot: $SRCROOT"
case "$1" in
-c|--check)
OPTS="--check"
;;
*)
OPTS="--replace --no-backup"
;;
esac
pushd "$SRCROOT"
uncrustify -c "$CFG" $OPTS `git ls-tree --name-only -r HEAD | grep -E '.*\.[ch]$' | grep -v build/`
RES=$?
popd
exit $RES

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,12 @@
* 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.
@ -44,271 +44,317 @@
static char *storage_path = NULL;
static const char *get_storage_path(void)
static const char *
get_storage_path (void)
{
const char *path = NULL;
const char *path = NULL;
if (storage_path != NULL)
return storage_path;
if (storage_path != NULL)
return storage_path;
/* set by systemd >= 240 to an absolute path
* taking into account the StateDirectory
* unit file setting */
path = g_getenv ("STATE_DIRECTORY");
if (path != NULL) {
/* If multiple directories are set, then in the environment variable
* the paths are concatenated with colon (":"). */
if (strchr (path, ':')) {
g_auto(GStrv) elems = NULL;
elems = g_strsplit (path, ":", -1);
storage_path = g_strdup (elems[0]);
}
}
/* set by systemd >= 240 to an absolute path
* taking into account the StateDirectory
* unit file setting */
path = g_getenv ("STATE_DIRECTORY");
if (path != NULL)
{
/* If multiple directories are set, then in the environment variable
* the paths are concatenated with colon (":"). */
if (strchr (path, ':'))
{
g_auto(GStrv) elems = NULL;
elems = g_strsplit (path, ":", -1);
storage_path = g_strdup (elems[0]);
}
else if (*path)
{
storage_path = g_strdup (path);
}
}
if (storage_path == NULL)
storage_path = g_strdup (FILE_STORAGE_PATH);
if (storage_path == NULL)
storage_path = g_strdup (FILE_STORAGE_PATH);
return storage_path;
return storage_path;
}
static char *get_path_to_storedir(const char *driver, const char * device_id, char *base_store)
static char *
get_path_to_storedir (const char *driver, const char * device_id, char *base_store)
{
return g_build_filename(base_store, driver, device_id, NULL);
return g_build_filename (base_store, driver, device_id, NULL);
}
static char *__get_path_to_print(const char *driver, const char * device_id,
FpFinger finger, char *base_store)
static char *
__get_path_to_print (const char *driver, const char * device_id,
FpFinger finger, char *base_store)
{
g_autofree char *dirpath = NULL;
char *path;
char fingername[2];
g_autofree char *dirpath = NULL;
char *path;
char fingername[2];
g_snprintf(fingername, 2, "%x", finger);
g_snprintf (fingername, 2, "%x", finger);
dirpath = get_path_to_storedir(driver, device_id, base_store);
path = g_build_filename(dirpath, fingername, NULL);
return path;
dirpath = get_path_to_storedir (driver, device_id, base_store);
path = g_build_filename (dirpath, fingername, NULL);
return path;
}
static char *get_path_to_print(FpDevice *dev, FpFinger finger, char *base_store)
static char *
get_path_to_print (FpDevice *dev, FpFinger finger, char *base_store)
{
return __get_path_to_print(fp_device_get_driver (dev),
fp_device_get_device_id(dev),
finger,
base_store);
return __get_path_to_print (fp_device_get_driver (dev),
fp_device_get_device_id (dev),
finger,
base_store);
}
static char *get_path_to_print_dscv(FpDevice *dev, FpFinger finger, char *base_store)
static char *
get_path_to_print_dscv (FpDevice *dev, FpFinger finger, char *base_store)
{
return __get_path_to_print(fp_device_get_driver (dev),
fp_device_get_device_id(dev),
finger,
base_store);
return __get_path_to_print (fp_device_get_driver (dev),
fp_device_get_device_id (dev),
finger,
base_store);
}
static char *file_storage_get_basestore_for_username(const char *username)
static char *
file_storage_get_basestore_for_username (const char *username)
{
return g_build_filename(get_storage_path(), username, NULL);
return g_build_filename (get_storage_path (), username, NULL);
}
int file_storage_print_data_save(FpPrint *print)
int
file_storage_print_data_save (FpPrint *print)
{
g_autoptr(GError) err = NULL;
g_autofree char *path = NULL;
g_autofree char *dirpath = NULL;
g_autofree char *base_store = NULL;
g_autofree char *buf = NULL;
gsize len;
int r;
g_autoptr(GError) err = NULL;
g_autofree char *path = NULL;
g_autofree char *dirpath = NULL;
g_autofree char *base_store = NULL;
g_autofree char *buf = NULL;
gsize len;
int r;
base_store = file_storage_get_basestore_for_username(fp_print_get_username (print));
base_store = file_storage_get_basestore_for_username (fp_print_get_username (print));
if (!fp_print_serialize (print, (guchar **) &buf, &len, &err)) {
g_warning ("Error serializing data: %s", err->message);
return -ENOMEM;
}
if (!fp_print_serialize (print, (guchar **) &buf, &len, &err))
{
g_warning ("Error serializing data: %s", err->message);
return -ENOMEM;
}
path = __get_path_to_print(fp_print_get_driver (print),
fp_print_get_device_id (print),
fp_print_get_finger (print),
base_store);
dirpath = g_path_get_dirname(path);
r = g_mkdir_with_parents(dirpath, DIR_PERMS);
if (r < 0) {
g_debug("file_storage_print_data_save(): could not mkdir(\"%s\"): %s",
dirpath, g_strerror(r));
return r;
}
path = __get_path_to_print (fp_print_get_driver (print),
fp_print_get_device_id (print),
fp_print_get_finger (print),
base_store);
dirpath = g_path_get_dirname (path);
r = g_mkdir_with_parents (dirpath, DIR_PERMS);
if (r < 0)
{
g_debug ("file_storage_print_data_save(): could not mkdir(\"%s\"): %s",
dirpath, g_strerror (r));
return r;
}
//fp_dbg("saving to %s", path);
g_file_set_contents(path, buf, len, &err);
if (err) {
g_debug("file_storage_print_data_save(): could not save '%s': %s",
path, err->message);
/* FIXME interpret error codes */
return err->code;
}
g_file_set_contents (path, buf, len, &err);
if (err)
{
g_debug ("file_storage_print_data_save(): could not save '%s': %s",
path, err->message);
/* FIXME interpret error codes */
return err->code;
}
return 0;
g_debug ("file_storage_print_data_save(): print saved to %s", path);
return 0;
}
static int load_from_file(char *path, FpPrint **print)
static int
load_from_file (char *path, FpPrint **print)
{
g_autoptr(GError) err = NULL;
gsize length;
g_autofree char *contents = NULL;
FpPrint *new;
g_autoptr(GError) err = NULL;
gsize length;
g_autofree char *contents = NULL;
FpPrint *new;
//fp_dbg("from %s", path);
g_file_get_contents(path, &contents, &length, &err);
if (err) {
int r = err->code;
/* FIXME interpret more error codes */
if (r == G_FILE_ERROR_NOENT)
return -ENOENT;
else
return r;
}
g_file_get_contents (path, &contents, &length, &err);
if (err)
{
int r = err->code;
/* FIXME interpret more error codes */
if (r == G_FILE_ERROR_NOENT)
return -ENOENT;
else
return r;
}
new = fp_print_deserialize ((guchar *) contents, length, &err);
if (!new) {
g_print ("Error deserializing data: %s", err->message);
return -EIO;
}
new = fp_print_deserialize ((guchar *) contents, length, &err);
if (!new)
{
g_print ("Error deserializing data: %s", err->message);
return -EIO;
}
*print = new;
return 0;
*print = new;
return 0;
}
int file_storage_print_data_load(FpDevice *dev,
FpFinger finger,
const char *username,
FpPrint **print)
int
file_storage_print_data_load (FpDevice *dev,
FpFinger finger,
const char *username,
FpPrint **print)
{
g_autofree gchar *path = NULL;
g_autofree gchar *base_store = NULL;
g_autoptr(FpPrint) new = NULL;
int r;
g_autofree gchar *path = NULL;
g_autofree gchar *base_store = NULL;
base_store = file_storage_get_basestore_for_username(username);
g_autoptr(FpPrint) new = NULL;
int r;
path = get_path_to_print(dev, finger, base_store);
r = load_from_file(path, &new);
g_debug ("file_storage_print_data_load(): loaded '%s' %s",
path, g_strerror(r));
if (r)
return r;
base_store = file_storage_get_basestore_for_username (username);
if (!fp_print_compatible (new, dev)) {
return -EINVAL;
}
path = get_path_to_print (dev, finger, base_store);
r = load_from_file (path, &new);
g_debug ("file_storage_print_data_load(): loaded '%s' %s",
path, g_strerror (r));
if (r)
return r;
*print = g_steal_pointer (&new);
return 0;
if (!fp_print_compatible (new, dev))
return -EINVAL;
*print = g_steal_pointer (&new);
return 0;
}
int file_storage_print_data_delete(FpDevice *dev, FpFinger finger, const char *username)
int
file_storage_print_data_delete (FpDevice *dev, FpFinger finger, const char *username)
{
g_autofree gchar *base_store = NULL;
g_autofree gchar *path = NULL;
int r;
g_autoptr(GSList) prints = NULL;
g_autofree gchar *base_store = NULL;
g_autofree gchar *path = NULL;
int r;
base_store = file_storage_get_basestore_for_username(username);
base_store = file_storage_get_basestore_for_username (username);
path = get_path_to_print_dscv(dev, finger, base_store);
path = get_path_to_print_dscv (dev, finger, base_store);
r = g_unlink(path);
g_debug("file_storage_print_data_delete(): unlink(\"%s\") %s",
path, g_strerror(r));
if (!g_file_test (path, G_FILE_TEST_EXISTS))
return 0;
/* FIXME: cleanup empty directory */
return g_unlink(path);
r = g_unlink (path);
g_debug ("file_storage_print_data_delete(): unlink(\"%s\") %s",
path, g_strerror (r));
prints = file_storage_discover_prints (dev, username);
if (!prints)
{
g_autofree char *dir = g_steal_pointer (&path);
do
{
g_autofree char *tmp = g_steal_pointer (&dir);
dir = g_path_get_dirname (tmp);
}
while (g_str_has_prefix (dir, base_store) && g_rmdir (dir) == 0);
}
return r;
}
static GSList *scan_dev_storedir(char *devpath,
GSList *list)
static GSList *
scan_dev_storedir (char *devpath,
GSList *list)
{
g_autoptr(GError) err = NULL;
const gchar *ent;
g_autoptr(GError) err = NULL;
const gchar *ent;
GDir *dir = g_dir_open(devpath, 0, &err);
if (!dir) {
g_debug("scan_dev_storedir(): opendir(\"%s\") failed: %s", devpath, err->message);
return list;
}
GDir *dir = g_dir_open (devpath, 0, &err);
while ((ent = g_dir_read_name(dir))) {
/* ent is an 1 hex character fp_finger code */
guint64 val;
gchar *endptr;
if (!dir)
{
g_debug ("scan_dev_storedir(): opendir(\"%s\") failed: %s", devpath, err->message);
return list;
}
if (*ent == 0 || strlen(ent) != 1)
continue;
while ((ent = g_dir_read_name (dir)))
{
/* ent is an 1 hex character fp_finger code */
guint64 val;
gchar *endptr;
val = g_ascii_strtoull(ent, &endptr, 16);
if (endptr == ent || !FP_FINGER_IS_VALID(val)) {
g_debug("scan_dev_storedir(): skipping print file '%s'", ent);
continue;
}
if (*ent == 0 || strlen (ent) != 1)
continue;
list = g_slist_prepend (list, GUINT_TO_POINTER (val));
}
val = g_ascii_strtoull (ent, &endptr, 16);
if (endptr == ent || !FP_FINGER_IS_VALID (val))
{
g_debug ("scan_dev_storedir(): skipping print file '%s'", ent);
continue;
}
g_dir_close(dir);
return list;
list = g_slist_prepend (list, GUINT_TO_POINTER (val));
}
g_dir_close (dir);
return list;
}
GSList *file_storage_discover_prints(FpDevice *dev, const char *username)
GSList *
file_storage_discover_prints (FpDevice *dev, const char *username)
{
GSList *list = NULL;
g_autofree gchar *base_store = NULL;
g_autofree gchar *storedir = NULL;
GSList *list = NULL;
g_autofree gchar *base_store = NULL;
g_autofree gchar *storedir = NULL;
base_store = file_storage_get_basestore_for_username(username);
base_store = file_storage_get_basestore_for_username (username);
storedir = get_path_to_storedir(fp_device_get_driver (dev),
fp_device_get_device_id (dev),
base_store);
storedir = get_path_to_storedir (fp_device_get_driver (dev),
fp_device_get_device_id (dev),
base_store);
g_debug ("file_storage_discover_prints() for user '%s' in '%s'",
username, storedir);
g_debug ("file_storage_discover_prints() for user '%s' in '%s'",
username, storedir);
list = scan_dev_storedir(storedir, list);
list = scan_dev_storedir (storedir, list);
return list;
return list;
}
GSList *file_storage_discover_users(void)
GSList *
file_storage_discover_users (void)
{
g_autoptr(GError) err = NULL;
GSList *list = NULL;
const gchar *ent;
GDir *dir = g_dir_open(get_storage_path(), 0, &err);
g_autoptr(GError) err = NULL;
GSList *list = NULL;
const gchar *ent;
GDir *dir = g_dir_open (get_storage_path (), 0, &err);
if (!dir) {
return list;
}
if (!dir)
return list;
while ((ent = g_dir_read_name(dir))) {
/* ent is a username */
if (*ent == 0)
continue;
while ((ent = g_dir_read_name (dir)))
{
/* ent is a username */
if (*ent == 0)
continue;
list = g_slist_prepend(list, g_strdup (ent));
}
list = g_slist_prepend (list, g_strdup (ent));
}
g_dir_close(dir);
return list;
g_dir_close (dir);
return list;
}
int file_storage_init(void)
int
file_storage_init (void)
{
/* Nothing to do */
return 0;
/* Nothing to do */
return 0;
}
int file_storage_deinit(void)
int
file_storage_deinit (void)
{
g_clear_pointer (&storage_path, g_free);
return 0;
g_clear_pointer (&storage_path, g_free);
return 0;
}

View File

@ -6,12 +6,12 @@
* 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.
@ -20,20 +20,21 @@
#pragma once
int file_storage_print_data_save(FpPrint *print);
int file_storage_print_data_save (FpPrint *print);
int file_storage_print_data_load(FpDevice *dev,
FpFinger finger,
const char *username,
FpPrint **print);
int file_storage_print_data_load (FpDevice *dev,
FpFinger finger,
const char *username,
FpPrint **print);
int file_storage_print_data_delete(FpDevice *dev,
FpFinger finger,
const char *username);
int file_storage_print_data_delete (FpDevice *dev,
FpFinger finger,
const char *username);
int file_storage_init(void);
int file_storage_init (void);
int file_storage_deinit(void);
int file_storage_deinit (void);
GSList *file_storage_discover_prints(FpDevice *dev, const char *username);
GSList *file_storage_discover_users(void);
GSList *file_storage_discover_prints (FpDevice *dev,
const char *username);
GSList *file_storage_discover_users (void);

View File

@ -6,12 +6,12 @@
* 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.
@ -31,60 +31,78 @@
#define FPRINT_SERVICE_PATH "/net/reactivated/Fprint"
/* Errors */
GQuark fprint_error_quark(void);
GQuark fprint_error_quark (void);
#define FPRINT_ERROR fprint_error_quark()
#define FPRINT_ERROR fprint_error_quark ()
typedef enum {
/* developer didn't claim the device */
FPRINT_ERROR_CLAIM_DEVICE, /*< nick=net.reactivated.Fprint.Error.ClaimDevice >*/
/* device is already claimed by somebody else */
FPRINT_ERROR_ALREADY_IN_USE, /*< nick=net.reactivated.Fprint.Error.AlreadyInUse >*/
/* internal error occurred */
FPRINT_ERROR_INTERNAL, /*< nick=net.reactivated.Fprint.Error.Internal >*/
/* PolicyKit refused the action */
FPRINT_ERROR_PERMISSION_DENIED, /*< nick=net.reactivated.Fprint.Error.PermissionDenied >*/
/* No prints are enrolled */
FPRINT_ERROR_NO_ENROLLED_PRINTS, /*< nick=net.reactivated.Fprint.Error.NoEnrolledPrints >*/
/* No actions currently in progress */
FPRINT_ERROR_NO_ACTION_IN_PROGRESS, /*< nick=net.reactivated.Fprint.Error.NoActionInProgress >*/
/* the finger name passed was invalid */
FPRINT_ERROR_INVALID_FINGERNAME, /*< nick=net.reactivated.Fprint.Error.InvalidFingername >*/
/* device does not exist */
FPRINT_ERROR_NO_SUCH_DEVICE, /*< nick=net.reactivated.Fprint.Error.NoSuchDevice >*/
/* developer didn't claim the device */
FPRINT_ERROR_CLAIM_DEVICE, /*< nick=net.reactivated.Fprint.Error.ClaimDevice >*/
/* device is already claimed by somebody else */
FPRINT_ERROR_ALREADY_IN_USE, /*< nick=net.reactivated.Fprint.Error.AlreadyInUse >*/
/* internal error occurred */
FPRINT_ERROR_INTERNAL, /*< nick=net.reactivated.Fprint.Error.Internal >*/
/* PolicyKit refused the action */
FPRINT_ERROR_PERMISSION_DENIED, /*< nick=net.reactivated.Fprint.Error.PermissionDenied >*/
/* No prints are enrolled */
FPRINT_ERROR_NO_ENROLLED_PRINTS, /*< nick=net.reactivated.Fprint.Error.NoEnrolledPrints >*/
/* No actions currently in progress */
FPRINT_ERROR_NO_ACTION_IN_PROGRESS, /*< nick=net.reactivated.Fprint.Error.NoActionInProgress >*/
/* the finger name passed was invalid */
FPRINT_ERROR_INVALID_FINGERNAME, /*< nick=net.reactivated.Fprint.Error.InvalidFingername >*/
/* device does not exist */
FPRINT_ERROR_NO_SUCH_DEVICE, /*< nick=net.reactivated.Fprint.Error.NoSuchDevice >*/
} 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.
accepted: the lowest the value, the more priority it has.
- Nick must match the relative polkit rule.
*/
*/
typedef enum {
FPRINT_DEVICE_PERMISSION_NONE = 0,
FPRINT_DEVICE_PERMISSION_VERIFY = (1 << 0), /*< nick=net.reactivated.fprint.device.verify >*/
FPRINT_DEVICE_PERMISSION_ENROLL = (1 << 1), /*< nick=net.reactivated.fprint.device.enroll >*/
FPRINT_DEVICE_PERMISSION_SETUSERNAME = (1 << 2), /*< nick=net.reactivated.fprint.device.setusername >*/
FPRINT_DEVICE_PERMISSION_NONE = 0,
FPRINT_DEVICE_PERMISSION_VERIFY = (1 << 0), /*< nick=net.reactivated.fprint.device.verify >*/
FPRINT_DEVICE_PERMISSION_ENROLL = (1 << 1), /*< nick=net.reactivated.fprint.device.enroll >*/
FPRINT_DEVICE_PERMISSION_SETUSERNAME = (1 << 2), /*< nick=net.reactivated.fprint.device.setusername >*/
} FprintDevicePermission;
/* Manager */
#define FPRINT_TYPE_MANAGER (fprint_manager_get_type())
#define FPRINT_TYPE_MANAGER (fprint_manager_get_type ())
G_DECLARE_FINAL_TYPE (FprintManager, fprint_manager, FPRINT, MANAGER, GObject)
struct _FprintManager {
GObject parent;
struct _FprintManager
{
GObject parent;
};
FprintManager *fprint_manager_new (GDBusConnection *connection, gboolean no_timeout);
FprintManager *fprint_manager_new (GDBusConnection *connection,
gboolean no_timeout);
/* Device */
#define FPRINT_TYPE_DEVICE (fprint_device_get_type())
#define FPRINT_TYPE_DEVICE (fprint_device_get_type ())
G_DECLARE_FINAL_TYPE (FprintDevice, fprint_device, FPRINT, DEVICE,
FprintDBusDeviceSkeleton)
FprintDBusDeviceSkeleton)
struct _FprintDevice {
FprintDBusDeviceSkeleton parent;
struct _FprintDevice
{
FprintDBusDeviceSkeleton parent;
};
FprintDevice *fprint_device_new(FpDevice *dev);
guint32 _fprint_device_get_id(FprintDevice *rdev);
FprintDevice *fprint_device_new (FpDevice *dev);
guint32 _fprint_device_get_id (FprintDevice *rdev);
/* Print */
/* TODO */
/* Some compatibility definitions for older GLib. Copied from from libfprint. */
#if !GLIB_CHECK_VERSION (2, 57, 0)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
#else
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
* the version we depend on currently. */
#undef G_SOURCE_FUNC
#endif
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))

View File

@ -7,12 +7,12 @@
* 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.
@ -44,171 +44,179 @@ static gboolean g_fatal_warnings = FALSE;
static void
set_storage_file (void)
{
store.init = &file_storage_init;
store.deinit = &file_storage_deinit;
store.print_data_save = &file_storage_print_data_save;
store.print_data_load = &file_storage_print_data_load;
store.print_data_delete = &file_storage_print_data_delete;
store.discover_prints = &file_storage_discover_prints;
store.discover_users = &file_storage_discover_users;
store.init = &file_storage_init;
store.deinit = &file_storage_deinit;
store.print_data_save = &file_storage_print_data_save;
store.print_data_load = &file_storage_print_data_load;
store.print_data_delete = &file_storage_print_data_delete;
store.discover_prints = &file_storage_discover_prints;
store.discover_users = &file_storage_discover_users;
}
static gboolean
load_storage_module (const char *module_name)
{
GModule *module;
g_autofree char *filename = NULL;
GModule *module;
g_autofree char *filename = NULL;
filename = g_module_build_path (PLUGINDIR, module_name);
module = g_module_open (filename, 0);
if (module == NULL)
return FALSE;
filename = g_module_build_path (PLUGINDIR, module_name);
module = g_module_open (filename, 0);
if (module == NULL)
return FALSE;
if (!g_module_symbol (module, "init", (gpointer *) &store.init) ||
!g_module_symbol (module, "deinit", (gpointer *) &store.deinit) ||
!g_module_symbol (module, "print_data_save", (gpointer *) &store.print_data_save) ||
!g_module_symbol (module, "print_data_load", (gpointer *) &store.print_data_load) ||
!g_module_symbol (module, "print_data_delete", (gpointer *) &store.print_data_delete) ||
!g_module_symbol (module, "discover_prints", (gpointer *) &store.discover_prints)) {
g_module_close (module);
return FALSE;
}
if (!g_module_symbol (module, "init", (gpointer *) &store.init) ||
!g_module_symbol (module, "deinit", (gpointer *) &store.deinit) ||
!g_module_symbol (module, "print_data_save", (gpointer *) &store.print_data_save) ||
!g_module_symbol (module, "print_data_load", (gpointer *) &store.print_data_load) ||
!g_module_symbol (module, "print_data_delete", (gpointer *) &store.print_data_delete) ||
!g_module_symbol (module, "discover_prints", (gpointer *) &store.discover_prints))
{
g_module_close (module);
return FALSE;
}
g_module_make_resident (module);
g_module_make_resident (module);
return TRUE;
return TRUE;
}
static gboolean
load_conf (void)
{
g_autofree char *filename = NULL;
g_autofree char *module_name = NULL;
g_autoptr(GKeyFile) file = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *filename = NULL;
g_autofree char *module_name = NULL;
filename = g_build_filename (SYSCONFDIR, "fprintd.conf", NULL);
file = g_key_file_new ();
g_debug("About to load configuration file '%s'", filename);
if (!g_key_file_load_from_file (file, filename, G_KEY_FILE_NONE, &error)) {
g_warning ("Could not open \"%s\": %s\n", filename, error->message);
return FALSE;
}
g_autoptr(GKeyFile) file = NULL;
g_autoptr(GError) error = NULL;
module_name = g_key_file_get_string (file, "storage", "type", &error);
if (module_name == NULL)
return FALSE;
filename = g_build_filename (SYSCONFDIR, "fprintd.conf", NULL);
file = g_key_file_new ();
g_debug ("About to load configuration file '%s'", filename);
if (!g_key_file_load_from_file (file, filename, G_KEY_FILE_NONE, &error))
{
g_warning ("Could not open \"%s\": %s\n", filename, error->message);
return FALSE;
}
if (g_str_equal (module_name, "file")) {
set_storage_file ();
return TRUE;
}
module_name = g_key_file_get_string (file, "storage", "type", &error);
if (module_name == NULL)
return FALSE;
return load_storage_module (module_name);
if (g_str_equal (module_name, "file"))
{
set_storage_file ();
return TRUE;
}
return load_storage_module (module_name);
}
static const GOptionEntry entries[] = {
{"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL},
{"no-timeout", 't', 0, G_OPTION_ARG_NONE, &no_timeout, "Do not exit after unused for a while", NULL},
{ NULL }
{"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL},
{"no-timeout", 't', 0, G_OPTION_ARG_NONE, &no_timeout, "Do not exit after unused for a while", NULL},
{ NULL }
};
static gboolean sigterm_callback(gpointer data)
static gboolean
sigterm_callback (gpointer data)
{
GMainLoop *loop = data;
GMainLoop *loop = data;
g_main_loop_quit (loop);
return FALSE;
g_main_loop_quit (loop);
return FALSE;
}
static void
on_name_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
const char *name,
gpointer user_data)
{
g_debug ("D-Bus service launched with name: %s", name);
g_debug ("D-Bus service launched with name: %s", name);
}
static void
on_name_lost (GDBusConnection *connection,
const char *name,
gpointer user_data)
const char *name,
gpointer user_data)
{
GMainLoop *loop = user_data;
GMainLoop *loop = user_data;
g_warning ("Failed to get name: %s", name);
g_warning ("Failed to get name: %s", name);
g_main_loop_quit (loop);
g_main_loop_quit (loop);
}
int main(int argc, char **argv)
int
main (int argc, char **argv)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GMainLoop) loop = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(FprintManager) manager = NULL;
g_autoptr(GDBusConnection) connection = NULL;
guint32 request_name_ret;
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GMainLoop) loop = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(FprintManager) manager = NULL;
g_autoptr(GDBusConnection) connection = NULL;
guint32 request_name_ret;
setlocale (LC_ALL, "");
setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
context = g_option_context_new ("Fingerprint handler daemon");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
context = g_option_context_new ("Fingerprint handler daemon");
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
g_warning ("couldn't parse command-line options: %s\n", error->message);
return 1;
}
if (g_option_context_parse (context, &argc, &argv, &error) == FALSE)
{
g_warning ("couldn't parse command-line options: %s\n", error->message);
return 1;
}
if (g_fatal_warnings) {
GLogLevelFlags fatal_mask;
if (g_fatal_warnings)
{
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
/* Obtain a connection to the system bus */
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (!G_IS_DBUS_CONNECTION (connection)) {
g_warning("Failed to open connection to bus: %s", error->message);
return 1;
}
/* Obtain a connection to the system bus */
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (!G_IS_DBUS_CONNECTION (connection))
{
g_warning ("Failed to open connection to bus: %s", error->message);
return 1;
}
/* Load the configuration file,
* and the default storage plugin */
if (!load_conf())
set_storage_file ();
store.init ();
/* Load the configuration file,
* and the default storage plugin */
if (!load_conf ())
set_storage_file ();
store.init ();
loop = g_main_loop_new(NULL, FALSE);
g_unix_signal_add (SIGTERM, sigterm_callback, loop);
loop = g_main_loop_new (NULL, FALSE);
g_unix_signal_add (SIGTERM, sigterm_callback, loop);
g_debug("Launching FprintObject");
g_debug ("Launching FprintObject");
/* create the one instance of the Manager object to be shared between
* all fprintd users. This blocks until all the devices are enumerated */
manager = fprint_manager_new (connection, no_timeout);
/* create the one instance of the Manager object to be shared between
* all fprintd users. This blocks until all the devices are enumerated */
manager = fprint_manager_new (connection, no_timeout);
/* Obtain the well-known name after the manager has been initialized.
* Otherwise a client immediately enumerating the devices will not see
* any. */
request_name_ret = g_bus_own_name_on_connection (connection,
FPRINT_SERVICE_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
on_name_acquired,
on_name_lost,
loop, NULL);
/* Obtain the well-known name after the manager has been initialized.
* Otherwise a client immediately enumerating the devices will not see
* any. */
request_name_ret = g_bus_own_name_on_connection (connection,
FPRINT_SERVICE_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
on_name_acquired,
on_name_lost,
loop, NULL);
g_debug("entering main loop");
g_main_loop_run(loop);
g_bus_unown_name (request_name_ret);
g_debug("main loop completed");
g_debug ("entering main loop");
g_main_loop_run (loop);
g_bus_unown_name (request_name_ret);
g_debug ("main loop completed");
return 0;
return 0;
}

View File

@ -7,12 +7,12 @@
* 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.
@ -28,294 +28,316 @@
#include "fprintd.h"
static void fprint_manager_constructed (GObject *object);
static gboolean fprint_manager_get_devices(FprintManager *manager,
GPtrArray **devices, GError **error);
static gboolean fprint_manager_get_default_device(FprintManager *manager,
const char **device, GError **error);
static gboolean fprint_manager_get_devices (FprintManager *manager,
GPtrArray **devices,
GError **error);
static gboolean fprint_manager_get_default_device (FprintManager *manager,
const char **device,
GError **error);
typedef struct
{
GDBusConnection *connection;
GDBusObjectManager *object_manager;
FprintDBusManager *dbus_manager;
FpContext *context;
gboolean no_timeout;
guint timeout_id;
GDBusConnection *connection;
GDBusObjectManager *object_manager;
FprintDBusManager *dbus_manager;
FpContext *context;
gboolean no_timeout;
guint timeout_id;
} FprintManagerPrivate;
G_DEFINE_TYPE_WITH_CODE(FprintManager, fprint_manager, G_TYPE_OBJECT, G_ADD_PRIVATE (FprintManager))
G_DEFINE_TYPE_WITH_CODE (FprintManager, fprint_manager, G_TYPE_OBJECT, G_ADD_PRIVATE (FprintManager))
enum {
PROP_0,
FPRINT_MANAGER_CONNECTION,
N_PROPS
PROP_0,
FPRINT_MANAGER_CONNECTION,
N_PROPS
};
static GParamSpec *properties[N_PROPS];
static void fprint_manager_finalize(GObject *object)
static void
fprint_manager_finalize (GObject *object)
{
FprintManagerPrivate *priv = fprint_manager_get_instance_private (FPRINT_MANAGER (object));
FprintManagerPrivate *priv = fprint_manager_get_instance_private (FPRINT_MANAGER (object));
g_clear_object (&priv->object_manager);
g_clear_object (&priv->dbus_manager);
g_clear_object (&priv->connection);
g_clear_object (&priv->context);
g_clear_object (&priv->object_manager);
g_clear_object (&priv->dbus_manager);
g_clear_object (&priv->connection);
g_clear_object (&priv->context);
G_OBJECT_CLASS(fprint_manager_parent_class)->finalize(object);
G_OBJECT_CLASS (fprint_manager_parent_class)->finalize (object);
}
static FprintDevice *
fprint_dbus_object_skeleton_get_device (FprintDBusObjectSkeleton *object) {
FprintDevice *rdev;
fprint_dbus_object_skeleton_get_device (FprintDBusObjectSkeleton *object)
{
FprintDevice *rdev;
g_object_get (object, "device", &rdev, NULL);
return rdev;
g_object_get (object, "device", &rdev, NULL);
return rdev;
}
static void fprint_manager_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
static void
fprint_manager_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
FprintManager *self = FPRINT_MANAGER (object);
FprintManagerPrivate *priv = fprint_manager_get_instance_private (self);
FprintManager *self = FPRINT_MANAGER (object);
FprintManagerPrivate *priv = fprint_manager_get_instance_private (self);
switch (property_id) {
case FPRINT_MANAGER_CONNECTION:
priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
switch (property_id)
{
case FPRINT_MANAGER_CONNECTION:
priv->connection = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void fprint_manager_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
static void
fprint_manager_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
FprintManager *self = FPRINT_MANAGER (object);
FprintManagerPrivate *priv = fprint_manager_get_instance_private (self);
FprintManager *self = FPRINT_MANAGER (object);
FprintManagerPrivate *priv = fprint_manager_get_instance_private (self);
switch (property_id) {
case FPRINT_MANAGER_CONNECTION:
g_value_set_object (value, priv->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
switch (property_id)
{
case FPRINT_MANAGER_CONNECTION:
g_value_set_object (value, priv->connection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void fprint_manager_class_init(FprintManagerClass *klass)
static void
fprint_manager_class_init (FprintManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = fprint_manager_constructed;
object_class->set_property = fprint_manager_set_property;
object_class->get_property = fprint_manager_get_property;
object_class->finalize = fprint_manager_finalize;
object_class->constructed = fprint_manager_constructed;
object_class->set_property = fprint_manager_set_property;
object_class->get_property = fprint_manager_get_property;
object_class->finalize = fprint_manager_finalize;
properties[FPRINT_MANAGER_CONNECTION] =
g_param_spec_object ("connection",
"Connection",
"Set GDBus connection property",
G_TYPE_DBUS_CONNECTION,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE);
properties[FPRINT_MANAGER_CONNECTION] =
g_param_spec_object ("connection",
"Connection",
"Set GDBus connection property",
G_TYPE_DBUS_CONNECTION,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPS, properties);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static gchar *get_device_path(FprintDevice *rdev)
static gchar *
get_device_path (FprintDevice *rdev)
{
return g_strdup_printf (FPRINT_SERVICE_PATH "/Device/%d",
_fprint_device_get_id(rdev));
return g_strdup_printf (FPRINT_SERVICE_PATH "/Device/%d",
_fprint_device_get_id (rdev));
}
static gboolean
fprint_manager_timeout_cb (FprintManager *manager)
{
//FIXME kill all the devices
exit(0);
return FALSE;
//FIXME kill all the devices
exit (0);
return FALSE;
}
static void
fprint_manager_in_use_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager)
{
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
guint num_devices_used = 0;
g_autolist(GDBusObject) devices = NULL;
GList *l;
gboolean in_use;
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
guint num_devices_used = 0;
if (priv->timeout_id > 0) {
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
}
if (priv->no_timeout)
return;
g_autolist (GDBusObject) devices = NULL;
GList *l;
gboolean in_use;
devices = g_dbus_object_manager_get_objects (priv->object_manager);
if (priv->timeout_id > 0)
{
g_source_remove (priv->timeout_id);
priv->timeout_id = 0;
}
if (priv->no_timeout)
return;
for (l = devices; l != NULL; l = l->next) {
g_autoptr(FprintDevice) dev = NULL;
FprintDBusObjectSkeleton *object = l->data;
devices = g_dbus_object_manager_get_objects (priv->object_manager);
dev = fprint_dbus_object_skeleton_get_device (object);
g_object_get (G_OBJECT(dev), "in-use", &in_use, NULL);
if (in_use != FALSE)
num_devices_used++;
}
for (l = devices; l != NULL; l = l->next)
{
g_autoptr(FprintDevice) dev = NULL;
FprintDBusObjectSkeleton *object = l->data;
if (num_devices_used == 0)
priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager);
dev = fprint_dbus_object_skeleton_get_device (object);
g_object_get (G_OBJECT (dev), "in-use", &in_use, NULL);
if (in_use != FALSE)
num_devices_used++;
}
if (num_devices_used == 0)
priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager);
}
static gboolean
handle_get_devices (FprintManager *manager, GDBusMethodInvocation *invocation,
FprintDBusManager *skeleton)
FprintDBusManager *skeleton)
{
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GPtrArray) devices = NULL;
g_autoptr(GError) error = NULL;
if (!fprint_manager_get_devices (manager, &devices, &error)) {
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
if (!fprint_manager_get_devices (manager, &devices, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
fprint_dbus_manager_complete_get_devices (skeleton, invocation,
(const gchar *const *)
devices->pdata);
fprint_dbus_manager_complete_get_devices (skeleton, invocation,
(const gchar *const *)
devices->pdata);
return TRUE;
return TRUE;
}
static gboolean
handle_get_default_device (FprintManager *manager,
GDBusMethodInvocation *invocation,
FprintDBusManager *skeleton)
handle_get_default_device (FprintManager *manager,
GDBusMethodInvocation *invocation,
FprintDBusManager *skeleton)
{
const gchar *device;
g_autoptr(GError) error = NULL;
const gchar *device;
if (!fprint_manager_get_default_device (manager, &device, &error)) {
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
g_autoptr(GError) error = NULL;
fprint_dbus_manager_complete_get_default_device (skeleton, invocation,
device);
if (!fprint_manager_get_default_device (manager, &device, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
return TRUE;
fprint_dbus_manager_complete_get_default_device (skeleton, invocation,
device);
return TRUE;
}
static void
device_added_cb (FprintManager *manager, FpDevice *device, FpContext *context)
{
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
g_autoptr(FprintDBusObjectSkeleton) object = NULL;
g_autoptr(FprintDevice) rdev = NULL;
g_autofree gchar *path = NULL;
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
rdev = fprint_device_new(device);
g_autoptr(FprintDBusObjectSkeleton) object = NULL;
g_autoptr(FprintDevice) rdev = NULL;
g_autofree gchar *path = NULL;
g_signal_connect (G_OBJECT(rdev), "notify::in-use",
G_CALLBACK (fprint_manager_in_use_notified), manager);
rdev = fprint_device_new (device);
path = get_device_path (rdev);
g_signal_connect (G_OBJECT (rdev), "notify::in-use",
G_CALLBACK (fprint_manager_in_use_notified), manager);
object = fprint_dbus_object_skeleton_new (path);
fprint_dbus_object_skeleton_set_device (object,
FPRINT_DBUS_DEVICE (rdev));
g_dbus_object_manager_server_export (
G_DBUS_OBJECT_MANAGER_SERVER (priv->object_manager),
G_DBUS_OBJECT_SKELETON (object));
path = get_device_path (rdev);
object = fprint_dbus_object_skeleton_new (path);
fprint_dbus_object_skeleton_set_device (object,
FPRINT_DBUS_DEVICE (rdev));
g_dbus_object_manager_server_export (
G_DBUS_OBJECT_MANAGER_SERVER (priv->object_manager),
G_DBUS_OBJECT_SKELETON (object));
}
static void
device_removed_cb (FprintManager *manager, FpDevice *device, FpContext *context)
{
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
GList *item;
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
objects = g_dbus_object_manager_get_objects (priv->object_manager);
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
GList *item;
for (item = objects; item; item = item->next) {
g_autoptr(FprintDevice) rdev = NULL;
g_autoptr(FpDevice) dev = NULL;
FprintDBusObjectSkeleton *object = item->data;
objects = g_dbus_object_manager_get_objects (priv->object_manager);
rdev = fprint_dbus_object_skeleton_get_device (object);
g_object_get (rdev, "dev", &dev, NULL);
if (dev != device)
continue;
for (item = objects; item; item = item->next)
{
g_autoptr(FprintDevice) rdev = NULL;
g_autoptr(FpDevice) dev = NULL;
FprintDBusObjectSkeleton *object = item->data;
g_dbus_object_manager_server_unexport (
G_DBUS_OBJECT_MANAGER_SERVER (priv->object_manager),
g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (rdev)));
rdev = fprint_dbus_object_skeleton_get_device (object);
g_object_get (rdev, "dev", &dev, NULL);
if (dev != device)
continue;
g_signal_handlers_disconnect_by_data (rdev, manager);
g_dbus_object_manager_server_unexport (
G_DBUS_OBJECT_MANAGER_SERVER (priv->object_manager),
g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (rdev)));
/* We cannot continue to iterate at this point, but we don't need to either */
break;
}
g_signal_handlers_disconnect_by_data (rdev, manager);
/* The device that disappeared might have been in-use.
* Do we need to do anything else in this case to clean up more gracefully? */
fprint_manager_in_use_notified (NULL, NULL, manager);
/* We cannot continue to iterate at this point, but we don't need to either */
break;
}
/* The device that disappeared might have been in-use.
* Do we need to do anything else in this case to clean up more gracefully? */
fprint_manager_in_use_notified (NULL, NULL, manager);
}
static void fprint_manager_constructed (GObject *object)
static void
fprint_manager_constructed (GObject *object)
{
FprintManager *manager = FPRINT_MANAGER (object);
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
GDBusObjectManagerServer *object_manager_server;
FprintManager *manager = FPRINT_MANAGER (object);
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
GDBusObjectManagerServer *object_manager_server;
object_manager_server =
g_dbus_object_manager_server_new (FPRINT_SERVICE_PATH "/Device");
object_manager_server =
g_dbus_object_manager_server_new (FPRINT_SERVICE_PATH);
priv->object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
priv->dbus_manager = fprint_dbus_manager_skeleton_new ();
priv->context = fp_context_new ();
priv->object_manager = G_DBUS_OBJECT_MANAGER (object_manager_server);
priv->dbus_manager = fprint_dbus_manager_skeleton_new ();
priv->context = fp_context_new ();
g_signal_connect_object (priv->dbus_manager,
"handle-get-devices",
G_CALLBACK (handle_get_devices),
manager,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->dbus_manager,
"handle-get-default-device",
G_CALLBACK (handle_get_default_device),
manager,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->dbus_manager,
"handle-get-devices",
G_CALLBACK (handle_get_devices),
manager,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->dbus_manager,
"handle-get-default-device",
G_CALLBACK (handle_get_default_device),
manager,
G_CONNECT_SWAPPED);
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_manager),
priv->connection,
FPRINT_SERVICE_PATH "/Manager", NULL);
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_manager),
priv->connection,
FPRINT_SERVICE_PATH "/Manager", NULL);
g_dbus_object_manager_server_set_connection (object_manager_server,
priv->connection);
g_dbus_object_manager_server_set_connection (object_manager_server,
priv->connection);
/* And register the signals for initial enumeration and hotplug. */
g_signal_connect_object (priv->context,
"device-added",
(GCallback) device_added_cb,
manager,
G_CONNECT_SWAPPED);
/* And register the signals for initial enumeration and hotplug. */
g_signal_connect_object (priv->context,
"device-added",
(GCallback) device_added_cb,
manager,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->context,
"device-removed",
(GCallback) device_removed_cb,
manager,
G_CONNECT_SWAPPED);
g_signal_connect_object (priv->context,
"device-removed",
(GCallback) device_removed_cb,
manager,
G_CONNECT_SWAPPED);
/* Prepare everything by enumerating all devices.
* This blocks the main loop until the existing devices are enumerated
*/
fp_context_enumerate (priv->context);
/* Prepare everything by enumerating all devices.
* This blocks the main loop until the existing devices are enumerated
*/
fp_context_enumerate (priv->context);
G_OBJECT_CLASS (fprint_manager_parent_class)->constructed (object);
G_OBJECT_CLASS (fprint_manager_parent_class)->constructed (object);
}
static void
@ -323,99 +345,113 @@ fprint_manager_init (FprintManager *manager)
{
}
FprintManager *fprint_manager_new (GDBusConnection *connection, gboolean no_timeout)
FprintManager *
fprint_manager_new (GDBusConnection *connection, gboolean no_timeout)
{
FprintManagerPrivate *priv;
GObject *object;
FprintManagerPrivate *priv;
GObject *object;
object = g_object_new (FPRINT_TYPE_MANAGER, "connection", connection, NULL);
priv = fprint_manager_get_instance_private (FPRINT_MANAGER (object));
priv->no_timeout = no_timeout;
object = g_object_new (FPRINT_TYPE_MANAGER, "connection", connection, NULL);
priv = fprint_manager_get_instance_private (FPRINT_MANAGER (object));
priv->no_timeout = no_timeout;
if (!priv->no_timeout)
priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, object);
if (!priv->no_timeout)
priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, object);
return FPRINT_MANAGER (object);
return FPRINT_MANAGER (object);
}
static gboolean fprint_manager_get_devices(FprintManager *manager,
GPtrArray **devices, GError **error)
static gboolean
fprint_manager_get_devices (FprintManager *manager,
GPtrArray **devices, GError **error)
{
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
GList *l;
int num_open;
GPtrArray *devs;
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
objects = g_dbus_object_manager_get_objects (priv->object_manager);
objects = g_list_reverse (objects);
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
GList *l;
int num_open;
GPtrArray *devs;
num_open = g_list_length (objects);
devs = g_ptr_array_sized_new(num_open);
objects = g_dbus_object_manager_get_objects (priv->object_manager);
objects = g_list_reverse (objects);
if (num_open > 0) {
for (l = objects; l != NULL; l = l->next) {
g_autoptr(FprintDevice) rdev = NULL;
FprintDBusObjectSkeleton *object = l->data;
const char *path;
num_open = g_list_length (objects);
devs = g_ptr_array_sized_new (num_open);
rdev = fprint_dbus_object_skeleton_get_device (object);
path = g_dbus_interface_skeleton_get_object_path (
G_DBUS_INTERFACE_SKELETON (rdev));
g_ptr_array_add (devs, (char *) path);
}
}
g_ptr_array_add (devs, NULL);
if (num_open > 0)
{
for (l = objects; l != NULL; l = l->next)
{
g_autoptr(FprintDevice) rdev = NULL;
FprintDBusObjectSkeleton *object = l->data;
const char *path;
*devices = devs;
return TRUE;
rdev = fprint_dbus_object_skeleton_get_device (object);
path = g_dbus_interface_skeleton_get_object_path (
G_DBUS_INTERFACE_SKELETON (rdev));
g_ptr_array_add (devs, (char *) path);
}
}
g_ptr_array_add (devs, NULL);
*devices = devs;
return TRUE;
}
static gboolean fprint_manager_get_default_device(FprintManager *manager,
const char **device, GError **error)
static gboolean
fprint_manager_get_default_device (FprintManager *manager,
const char **device, GError **error)
{
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
int num_open;
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
objects = g_dbus_object_manager_get_objects (priv->object_manager);
num_open = g_list_length (objects);
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
int num_open;
if (num_open > 0) {
g_autoptr(FprintDevice) rdev = NULL;
FprintDBusObjectSkeleton *object = g_list_last (objects)->data;
objects = g_dbus_object_manager_get_objects (priv->object_manager);
num_open = g_list_length (objects);
rdev = fprint_dbus_object_skeleton_get_device (object);
*device = g_dbus_interface_skeleton_get_object_path (
G_DBUS_INTERFACE_SKELETON (rdev));
return TRUE;
} else {
g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_DEVICE,
"No devices available");
*device = NULL;
return FALSE;
}
if (num_open > 0)
{
g_autoptr(FprintDevice) rdev = NULL;
FprintDBusObjectSkeleton *object = g_list_last (objects)->data;
rdev = fprint_dbus_object_skeleton_get_device (object);
*device = g_dbus_interface_skeleton_get_object_path (
G_DBUS_INTERFACE_SKELETON (rdev));
return TRUE;
}
else
{
g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_DEVICE,
"No devices available");
*device = NULL;
return FALSE;
}
}
GQuark fprint_error_quark (void)
GQuark
fprint_error_quark (void)
{
static volatile gsize quark = 0;
if (g_once_init_enter (&quark)) {
g_autoptr(GEnumClass) errors_enum = NULL;
GQuark domain;
unsigned i;
static gsize quark = 0;
domain = g_quark_from_static_string ("fprintd-error-quark");
errors_enum = g_type_class_ref (FPRINT_TYPE_ERROR);
if (g_once_init_enter (&quark))
{
g_autoptr(GEnumClass) errors_enum = NULL;
GQuark domain;
unsigned i;
for (i = 0; i < errors_enum->n_values; ++i) {
GEnumValue *value = &errors_enum->values[i];
domain = g_quark_from_static_string ("fprintd-error-quark");
errors_enum = g_type_class_ref (FPRINT_TYPE_ERROR);
g_dbus_error_register_error (domain, value->value,
value->value_nick);
}
for (i = 0; i < errors_enum->n_values; ++i)
{
GEnumValue *value = &errors_enum->values[i];
g_once_init_leave (&quark, domain);
}
return (GQuark) quark;
g_dbus_error_register_error (domain, value->value,
value->value_nick);
}
g_once_init_leave (&quark, domain);
}
return (GQuark) quark;
}

View File

@ -6,12 +6,12 @@
* 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.
@ -28,19 +28,21 @@ typedef int (*storage_print_data_load)(FpDevice *dev,
typedef int (*storage_print_data_delete)(FpDevice *dev,
FpFinger finger,
const char *username);
typedef GSList *(*storage_discover_prints)(FpDevice *dev, const char *username);
typedef GSList *(*storage_discover_prints)(FpDevice *dev,
const char *username);
typedef GSList *(*storage_discover_users)(void);
typedef int (*storage_init)(void);
typedef int (*storage_deinit)(void);
struct storage {
storage_init init;
storage_deinit deinit;
storage_print_data_save print_data_save;
storage_print_data_load print_data_load;
storage_print_data_delete print_data_delete;
storage_discover_prints discover_prints;
storage_discover_users discover_users;
struct storage
{
storage_init init;
storage_deinit deinit;
storage_print_data_save print_data_save;
storage_print_data_load print_data_load;
storage_print_data_delete print_data_delete;
storage_discover_prints discover_prints;
storage_discover_users discover_users;
};
typedef struct storage fp_storage;

View File

@ -296,24 +296,36 @@ class FPrintdTest(dbusmock.DBusTestCase):
'.*net\.reactivated\.Fprint\.Error\.{}.*'.format(fprint_error))
# From libfprint tests
def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT):
with Connection(self.sockaddr) as con:
def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT, con=None):
if con:
con.sendall(struct.pack('ii', -1, retry_error))
return
with Connection(self.sockaddr) as con:
self.send_retry(retry_error, con)
# From libfprint tests
def send_error(self, error=FPrint.DeviceError.GENERAL):
with Connection(self.sockaddr) as con:
def send_error(self, error=FPrint.DeviceError.GENERAL, con=None):
if con:
con.sendall(struct.pack('ii', -2, error))
return
with Connection(self.sockaddr) as con:
self.send_error(error, con)
# From libfprint tests
def send_remove(self):
with Connection(self.sockaddr) as con:
def send_remove(self, con=None):
if con:
con.sendall(struct.pack('ii', -5, 0))
return
with Connection(self.sockaddr) as con:
self.send_remove(con=con)
# From libfprint tests
def send_image(self, image):
img = self.prints[image]
with Connection(self.sockaddr) as con:
def send_image(self, image, con=None):
if con:
img = self.prints[image]
mem = img.get_data()
mem = mem.tobytes()
self.assertEqual(len(mem), img.get_width() * img.get_height())
@ -322,6 +334,28 @@ class FPrintdTest(dbusmock.DBusTestCase):
encoded_img += mem
con.sendall(encoded_img)
return
with Connection(self.sockaddr) as con:
self.send_image(image, con)
def send_finger_automatic(self, automatic, con=None):
# Set whether finger on/off is reported around images
if con:
con.sendall(struct.pack('ii', -3, 1 if automatic else 0))
return
with Connection(self.sockaddr) as con:
self.send_finger_automatic(automatic, con=con)
def send_finger_report(self, has_finger, con=None):
# Send finger on/off
if con:
con.sendall(struct.pack('ii', -4, 1 if has_finger else 0))
return
with Connection(self.sockaddr) as con:
self.send_finger_report(has_finger, con=con)
def call_device_method_async(self, method, *args):
""" add cancellable... """
@ -429,10 +463,12 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
if expected is not None:
self.assertEqual(self._last_result, expected)
def enroll_image(self, img, finger='right-index-finger', expected_result='enroll-completed'):
self.device.EnrollStart('(s)', finger)
def enroll_image(self, img, device=None, finger='right-index-finger', expected_result='enroll-completed'):
if device is None:
device = self.device
device.EnrollStart('(s)', finger)
stages = self.device.get_cached_property('num-enroll-stages').unpack()
stages = device.get_cached_property('num-enroll-stages').unpack()
for stage in range(stages):
self.send_image(img)
if stage < stages - 1:
@ -440,7 +476,7 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
else:
self.wait_for_result(expected_result)
self.device.EnrollStop()
device.EnrollStop()
self.assertEqual(self._last_result, expected_result)
def enroll_multiple_images(self, images_override={}, return_index=-1):
@ -462,6 +498,29 @@ class FPrintdVirtualDeviceBaseTest(FPrintdTest):
return (enrolled, enroll_map)
def get_secondary_bus_and_device(self, claim=None):
addr = os.environ['DBUS_SYSTEM_BUS_ADDRESS']
# Get a separate bus connection
bus = Gio.DBusConnection.new_for_address_sync(addr,
Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION |
Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT, None, None)
assert bus.is_closed() == False
dev_path = self.device.get_object_path()
dev = Gio.DBusProxy.new_sync(bus,
Gio.DBusProxyFlags.DO_NOT_AUTO_START,
None,
'net.reactivated.Fprint',
dev_path,
'net.reactivated.Fprint.Device',
None)
if claim is not None:
dev.Claim('(s)', claim)
return bus, dev
class FPrintdManagerTests(FPrintdVirtualDeviceBaseTest):
@ -700,23 +759,7 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
self.device.Release()
def test_claim_disconnect(self):
addr = os.environ['DBUS_SYSTEM_BUS_ADDRESS']
# Get a separat bus connection
dbus = Gio.DBusConnection.new_for_address_sync(addr,
Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION |
Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT, None, None)
assert dbus.is_closed() == False
dev_path = self.device.get_object_path()
dev = Gio.DBusProxy.new_sync(dbus,
Gio.DBusProxyFlags.DO_NOT_AUTO_START,
None,
'net.reactivated.Fprint',
dev_path,
'net.reactivated.Fprint.Device',
None)
bus, dev = self.get_secondary_bus_and_device()
def call_done(obj, result, user_data):
# Ignore the callback (should be an error)
@ -726,8 +769,91 @@ class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
dev.Claim('(s)', 'testuser', result_handler=call_done)
# Ensure the call is on the wire, then close immediately
dbus.flush_sync()
dbus.close_sync()
bus.flush_sync()
bus.close_sync()
time.sleep(1)
def test_enroll_running_disconnect(self):
bus, dev = self.get_secondary_bus_and_device(claim='testuser')
# Start an enroll and disconnect, without finishing/cancelling
dev.EnrollStart('(s)', 'left-index-finger')
# Ensure the call is on the wire, then close immediately
bus.flush_sync()
bus.close_sync()
time.sleep(1)
def test_enroll_done_disconnect(self):
bus, dev = self.get_secondary_bus_and_device(claim='testuser')
# Start an enroll and disconnect, without finishing/cancelling
dev.EnrollStart('(s)', 'left-index-finger')
# This works because we also receive the signals on the main connection
stages = dev.get_cached_property('num-enroll-stages').unpack()
for stage in range(stages):
self.send_image('whorl')
if stage < stages - 1:
self.wait_for_result('enroll-stage-passed')
else:
self.wait_for_result('enroll-completed')
bus.close_sync()
time.sleep(1)
def test_verify_running_disconnect(self):
bus, dev = self.get_secondary_bus_and_device(claim='testuser')
self.enroll_image('whorl', device=dev)
# Start an enroll and disconnect, without finishing/cancelling
dev.VerifyStart('(s)', 'right-index-finger')
bus.close_sync()
time.sleep(1)
def test_verify_done_disconnect(self):
bus, dev = self.get_secondary_bus_and_device(claim='testuser')
self.enroll_image('whorl', device=dev)
# Start an enroll and disconnect, without finishing/cancelling
dev.VerifyStart('(s)', 'right-index-finger')
self.send_image('whorl')
# Wait for match and sleep a bit to give fprintd time to wrap up
self.wait_for_result('verify-match')
time.sleep(1)
bus.close_sync()
time.sleep(1)
def test_identify_running_disconnect(self):
bus, dev = self.get_secondary_bus_and_device(claim='testuser')
self.enroll_image('whorl', device=dev)
# Start an enroll and disconnect, without finishing/cancelling
dev.VerifyStart('(s)', 'any')
bus.close_sync()
time.sleep(1)
def test_identify_done_disconnect(self):
bus, dev = self.get_secondary_bus_and_device(claim='testuser')
self.enroll_image('whorl', device=dev)
# Start an enroll and disconnect, without finishing/cancelling
dev.VerifyStart('(s)', 'any')
self.send_image('whorl')
# Wait for match and sleep a bit to give fprintd time to wrap up
self.wait_for_result('verify-match')
time.sleep(1)
bus.close_sync()
time.sleep(1)
@ -843,9 +969,11 @@ class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
self.device.DeleteEnrolledFingers2()
self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser')))
self.assertTrue(os.path.exists(self.state_dir))
def test_enroll_invalid_storage_dir(self):
# Directory wil not exist yet
# Directory will not exist yet
os.makedirs(self.state_dir, mode=0o500)
self.addCleanup(os.chmod, self.state_dir, mode=0o700)
@ -1214,6 +1342,12 @@ class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
def test_verify_retry_general(self):
self.assertVerifyRetry(FPrint.DeviceRetry.GENERAL, 'verify-retry-scan')
def test_verify_retry_general_restarted(self):
self.assertVerifyRetry(FPrint.DeviceRetry.GENERAL, 'verify-retry-scan')
# Give fprintd time to re-start the request. We can't force the other
# case (cancellation before restart happened), but we can force this one.
time.sleep(1)
def test_verify_retry_too_short(self):
self.assertVerifyRetry(FPrint.DeviceRetry.TOO_SHORT, 'verify-swipe-too-short')
@ -1250,6 +1384,38 @@ class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
def test_verify_error_data_full(self):
self.assertVerifyError(FPrint.DeviceError.DATA_FULL, 'verify-unknown-error')
def test_multiple_verify(self):
self.send_image('tented_arch')
self.wait_for_result()
self.assertTrue(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-no-match')
self.device.VerifyStop()
self.device.VerifyStart('(s)', self.verify_finger)
self.send_image('whorl')
self.wait_for_result()
self.assertTrue(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-match')
def test_multiple_verify_cancelled(self):
with Connection(self.sockaddr) as con:
self.send_finger_automatic(False, con=con)
self.send_finger_report(True, con=con)
self.send_image('tented_arch', con=con)
self.wait_for_result()
self.assertTrue(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-no-match')
self.device.VerifyStop()
# We'll be cancelled at this point, so con is invalid
self.device.VerifyStart('(s)', self.verify_finger)
self.send_finger_report(False)
self.send_image('whorl')
self.wait_for_result()
self.assertTrue(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-match')
def test_verify_start_during_verify(self):
with self.assertFprintError('AlreadyInUse'):
self.device.VerifyStart('(s)', self.verify_finger)

44
tests/pam/test_pam_fprintd.py Executable file → Normal file
View File

@ -86,6 +86,10 @@ class TestPamFprintd(dbusmock.DBusTestCase):
self.device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
self.device_mock.SetEnrolledFingers('toto', ['left-little-finger', 'right-little-finger'])
def test_pam_no_device(self):
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_identify_error(self):
self.setup_device()
script = [
@ -150,6 +154,21 @@ class TestPamFprintd(dbusmock.DBusTestCase):
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
def test_pam_fprintd_retry(self):
self.setup_device()
script = [
( 'verify-swipe-too-short', False, 1 ),
( 'verify-finger-not-centered', False, 1 ),
( 'verify-match', True, 1 )
]
self.device_mock.SetVerifyScript(script)
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
self.assertRegex(res.errors[0], r'Swipe was too short, try again')
self.assertRegex(res.errors[1], r'Your finger was not centered, try swiping your finger again')
def test_pam_fprintd_no_fingers_while_verifying(self):
self.setup_device()
script = [
@ -217,6 +236,31 @@ class TestPamFprintd(dbusmock.DBusTestCase):
self.assertRegex(res.info[0], r'Place your left middle finger on FDO Sandpaper Reader')
self.assertEqual(len(res.errors), 0)
def test_pam_fprintd_multi_reader_not_all_enrolled(self):
# Add a 1st device with actual enrolled prints
device_path = self.obj_fprintd_mock.AddDevice('FDO Empty reader', 3, 'press')
empty_reader = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
empty_reader.SetEnrolledFingers('toto', dbus.Array(set([]), signature='s'))
# Add a 2nd device with actual enrolled prints
device_path = self.obj_fprintd_mock.AddDevice('FDO Most Used Reader', 3, 'press')
sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
sandpaper_device_mock.SetEnrolledFingers('toto', ['left-middle-finger', 'right-middle-finger'])
script = [
( 'verify-match', True, 2 )
]
sandpaper_device_mock.SetVerifyScript(script)
# Add a 3rd device, with only one enrolled finger
self.setup_device()
self.device_mock.SetEnrolledFingers('toto', ['left-middle-finger'])
tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
self.assertRegex(res.info[0], r'Place your left middle finger on FDO Most Used Reader')
self.assertEqual(len(res.errors), 0)
def test_pam_fprintd_last_try_auth(self):
self.setup_device()
script = [

View File

@ -7,12 +7,12 @@
* 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.
@ -26,126 +26,146 @@
static FprintDBusManager *manager = NULL;
static GDBusConnection *connection = NULL;
static void create_manager(void)
static void
create_manager (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(GError) error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL) {
g_print("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL)
{
g_print ("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL) {
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL)
{
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
}
static void delete_fingerprints (FprintDBusDevice *dev, const char *username)
static void
delete_fingerprints (FprintDBusDevice *dev, const char *username)
{
g_autoptr(GError) error = NULL;
g_autoptr(GError) error = NULL;
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error)) {
g_print("failed to claim device: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error))
{
g_print ("failed to claim device: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_delete_enrolled_fingers2_sync (dev, NULL,
&error)) {
gboolean ignore_error = FALSE;
if (g_dbus_error_is_remote_error (error)) {
g_autofree char *dbus_error =
g_dbus_error_get_remote_error (error);
if (g_str_equal (dbus_error,
"net.reactivated.Fprint.Error.NoEnrolledPrints")) {
g_print ("No fingerprints to delete on %s\n",
fprint_dbus_device_get_name (dev));
ignore_error = TRUE;
}
}
if (!ignore_error) {
g_print("ListEnrolledFingers failed: %s\n",
error->message);
exit (1);
} else {
g_print ("No fingerprints to delete on %s\n",
fprint_dbus_device_get_name (dev));
}
} else {
g_print ("Fingerprints deleted on %s\n",
fprint_dbus_device_get_name (dev));
}
g_clear_error (&error);
if (!fprint_dbus_device_call_delete_enrolled_fingers2_sync (dev, NULL,
&error))
{
gboolean ignore_error = FALSE;
if (g_dbus_error_is_remote_error (error))
{
g_autofree char *dbus_error =
g_dbus_error_get_remote_error (error);
if (g_str_equal (dbus_error,
"net.reactivated.Fprint.Error.NoEnrolledPrints"))
{
g_print ("No fingerprints to delete on %s\n",
fprint_dbus_device_get_name (dev));
ignore_error = TRUE;
}
}
if (!ignore_error)
{
g_print ("ListEnrolledFingers failed: %s\n",
error->message);
exit (1);
}
else
{
g_print ("No fingerprints to delete on %s\n",
fprint_dbus_device_get_name (dev));
}
}
else
{
g_print ("Fingerprints deleted on %s\n",
fprint_dbus_device_get_name (dev));
}
g_clear_error (&error);
if (!fprint_dbus_device_call_release_sync (dev, NULL, &error)) {
g_print("ReleaseDevice failed: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_release_sync (dev, NULL, &error))
{
g_print ("ReleaseDevice failed: %s\n", error->message);
exit (1);
}
}
static void process_devices(char **argv)
static void
process_devices (char **argv)
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) devices = NULL;
char *path;
guint num_devices;
guint i;
g_autoptr(GError) error = NULL;
g_auto(GStrv) devices = NULL;
char *path;
guint num_devices;
guint i;
if (!fprint_dbus_manager_call_get_devices_sync (manager, &devices,
NULL, &error)) {
g_print("Impossible to get devices: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_manager_call_get_devices_sync (manager, &devices,
NULL, &error))
{
g_print ("Impossible to get devices: %s\n", error->message);
exit (1);
}
num_devices = g_strv_length (devices);
if (num_devices == 0) {
g_print("No devices available\n");
exit(1);
}
num_devices = g_strv_length (devices);
if (num_devices == 0)
{
g_print ("No devices available\n");
exit (1);
}
g_print ("found %u devices\n", num_devices);
for (i = 0; devices[i] != NULL; i++) {
path = devices[i];
g_print("Device at %s\n", path);
}
g_print ("found %u devices\n", num_devices);
for (i = 0; devices[i] != NULL; i++)
{
path = devices[i];
g_print ("Device at %s\n", path);
}
for (i = 0; devices[i] != NULL; i++) {
g_autoptr(FprintDBusDevice) dev = NULL;
guint j;
for (i = 0; devices[i] != NULL; i++)
{
g_autoptr(FprintDBusDevice) dev = NULL;
guint j;
path = devices[i];
g_print("Using device %s\n", path);
path = devices[i];
g_print ("Using device %s\n", path);
/* NOTE: We should handle error cases! */
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, NULL);
/* NOTE: We should handle error cases! */
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, NULL);
for (j = 1; argv[j] != NULL; j++)
delete_fingerprints (dev, argv[j]);
}
for (j = 1; argv[j] != NULL; j++)
delete_fingerprints (dev, argv[j]);
}
}
int main(int argc, char **argv)
int
main (int argc, char **argv)
{
setlocale (LC_ALL, "");
setlocale (LC_ALL, "");
create_manager();
create_manager ();
if (argc < 2) {
g_print ("Usage: %s <username> [usernames...]\n", argv[0]);
return 1;
}
if (argc < 2)
{
g_print ("Usage: %s <username> [usernames...]\n", argv[0]);
return 1;
}
process_devices (argv);
process_devices (argv);
return 0;
return 0;
}

View File

@ -7,12 +7,12 @@
* 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.
@ -33,171 +33,193 @@ static GDBusConnection *connection = NULL;
static char *finger_name = NULL;
static char **usernames = NULL;
static void create_manager(void)
static void
create_manager (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(GError) error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL) {
g_print("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL)
{
g_print ("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL) {
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL)
{
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
}
static FprintDBusDevice *open_device (const char *username)
static FprintDBusDevice *
open_device (const char *username)
{
g_autoptr(FprintDBusDevice) dev = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *path = NULL;
g_autoptr(FprintDBusDevice) dev = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *path = NULL;
if (!fprint_dbus_manager_call_get_default_device_sync (manager, &path,
NULL, &error)) {
g_print("Impossible to enroll: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_manager_call_get_default_device_sync (manager, &path,
NULL, &error))
{
g_print ("Impossible to enroll: %s\n", error->message);
exit (1);
}
g_print("Using device %s\n", path);
g_print ("Using device %s\n", path);
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, &error);
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, &error);
if (error) {
g_print ("failed to connect to device: %s\n", error->message);
exit (1);
}
if (error)
{
g_print ("failed to connect to device: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error)) {
g_print("failed to claim device: %s\n", error->message);
exit (1);
}
return g_steal_pointer (&dev);
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error))
{
g_print ("failed to claim device: %s\n", error->message);
exit (1);
}
return g_steal_pointer (&dev);
}
static void enroll_result(GObject *object, const char *result, gboolean done, void *user_data)
static void
enroll_result (GObject *object, const char *result, gboolean done, void *user_data)
{
gboolean *enroll_completed = user_data;
g_print("Enroll result: %s\n", result);
if (done != FALSE)
*enroll_completed = TRUE;
gboolean *enroll_completed = user_data;
g_print ("Enroll result: %s\n", result);
if (done != FALSE)
*enroll_completed = TRUE;
}
static void proxy_signal_cb (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
static void
proxy_signal_cb (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
if (g_str_equal (signal_name, "EnrollStatus")) {
const gchar *result;
gboolean done;
if (g_str_equal (signal_name, "EnrollStatus"))
{
const gchar *result;
gboolean done;
g_variant_get (parameters, "(&sb)", &result, &done);
enroll_result (G_OBJECT (proxy), result, done, user_data);
}
g_variant_get (parameters, "(&sb)", &result, &done);
enroll_result (G_OBJECT (proxy), result, done, user_data);
}
}
static void do_enroll (FprintDBusDevice *dev)
static void
do_enroll (FprintDBusDevice *dev)
{
g_autoptr(GError) error = NULL;
gboolean enroll_completed = FALSE;
gboolean found;
guint i;
g_autoptr(GError) error = NULL;
gboolean enroll_completed = FALSE;
gboolean found;
guint i;
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
&enroll_completed);
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
&enroll_completed);
found = FALSE;
for (i = 0; fingers[i].dbus_name != NULL; i++) {
if (g_strcmp0 (fingers[i].dbus_name, finger_name) == 0) {
found = TRUE;
break;
}
}
if (!found) {
g_autoptr(GString) s = NULL;
found = FALSE;
for (i = 0; fingers[i].dbus_name != NULL; i++)
{
if (g_strcmp0 (fingers[i].dbus_name, finger_name) == 0)
{
found = TRUE;
break;
}
}
if (!found)
{
g_autoptr(GString) s = NULL;
s = g_string_new (NULL);
g_string_append_printf (s, "Invalid finger name '%s'. Name must be one of ", finger_name);
for (i = 0; fingers[i].dbus_name != NULL; i++) {
g_string_append_printf (s, "%s", fingers[i].dbus_name);
if (fingers[i + 1].dbus_name != NULL)
g_string_append (s, ", ");
}
g_warning ("%s", s->str);
exit (1);
}
s = g_string_new (NULL);
g_string_append_printf (s, "Invalid finger name '%s'. Name must be one of ", finger_name);
for (i = 0; fingers[i].dbus_name != NULL; i++)
{
g_string_append_printf (s, "%s", fingers[i].dbus_name);
if (fingers[i + 1].dbus_name != NULL)
g_string_append (s, ", ");
}
g_warning ("%s", s->str);
exit (1);
}
g_print("Enrolling %s finger.\n", finger_name);
if (!fprint_dbus_device_call_enroll_start_sync (dev, finger_name, NULL,
&error)) {
g_print("EnrollStart failed: %s\n", error->message);
exit (1);
}
g_print ("Enrolling %s finger.\n", finger_name);
if (!fprint_dbus_device_call_enroll_start_sync (dev, finger_name, NULL,
&error))
{
g_print ("EnrollStart failed: %s\n", error->message);
exit (1);
}
while (!enroll_completed)
g_main_context_iteration(NULL, TRUE);
while (!enroll_completed)
g_main_context_iteration (NULL, TRUE);
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb, &enroll_result);
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb, &enroll_result);
if (!fprint_dbus_device_call_enroll_stop_sync (dev, NULL, &error)) {
g_print("VerifyStop failed: %s\n", error->message);
exit(1);
}
if (!fprint_dbus_device_call_enroll_stop_sync (dev, NULL, &error))
{
g_print ("VerifyStop failed: %s\n", error->message);
exit (1);
}
}
static void release_device (FprintDBusDevice *dev)
static void
release_device (FprintDBusDevice *dev)
{
g_autoptr(GError) error = NULL;
if (!fprint_dbus_device_call_release_sync (dev, NULL, &error)) {
g_print("ReleaseDevice failed: %s\n", error->message);
exit (1);
}
g_autoptr(GError) error = NULL;
if (!fprint_dbus_device_call_release_sync (dev, NULL, &error))
{
g_print ("ReleaseDevice failed: %s\n", error->message);
exit (1);
}
}
static const GOptionEntry entries[] = {
{ "finger", 'f', 0, G_OPTION_ARG_STRING, &finger_name, "Finger selected to verify (default is automatic)", NULL },
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &usernames, NULL, "[username]" },
{ NULL }
{ "finger", 'f', 0, G_OPTION_ARG_STRING, &finger_name, "Finger selected to verify (default is automatic)", NULL },
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &usernames, NULL, "[username]" },
{ NULL }
};
int main(int argc, char **argv)
int
main (int argc, char **argv)
{
g_autoptr(FprintDBusDevice) dev = NULL;
GOptionContext *context;
g_autoptr(GError) err = NULL;
g_autoptr(FprintDBusDevice) dev = NULL;
GOptionContext *context;
setlocale (LC_ALL, "");
g_autoptr(GError) err = NULL;
context = g_option_context_new ("Enroll a fingerprint");
g_option_context_add_main_entries (context, entries, NULL);
setlocale (LC_ALL, "");
if (g_option_context_parse (context, &argc, &argv, &err) == FALSE) {
g_print ("couldn't parse command-line options: %s\n", err->message);
return 1;
}
context = g_option_context_new ("Enroll a fingerprint");
g_option_context_add_main_entries (context, entries, NULL);
if (finger_name == NULL)
finger_name = g_strdup("right-index-finger");
if (g_option_context_parse (context, &argc, &argv, &err) == FALSE)
{
g_print ("couldn't parse command-line options: %s\n", err->message);
return 1;
}
create_manager();
if (finger_name == NULL)
finger_name = g_strdup ("right-index-finger");
dev = open_device (usernames ? usernames[0] : "");
do_enroll(dev);
release_device(dev);
g_free(finger_name);
g_strfreev(usernames);
return 0;
create_manager ();
dev = open_device (usernames ? usernames[0] : "");
do_enroll (dev);
release_device (dev);
g_free (finger_name);
g_strfreev (usernames);
return 0;
}

View File

@ -7,12 +7,12 @@
* 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.
@ -26,125 +26,137 @@
static FprintDBusManager *manager = NULL;
static GDBusConnection *connection = NULL;
static void create_manager(void)
static void
create_manager (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(GError) error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL) {
g_print("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL)
{
g_print ("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL) {
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL)
{
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
}
static void list_fingerprints (FprintDBusDevice *dev, const char *username)
static void
list_fingerprints (FprintDBusDevice *dev, const char *username)
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) fingers = NULL;
guint i;
g_autoptr(GError) error = NULL;
g_auto(GStrv) fingers = NULL;
guint i;
if (!fprint_dbus_device_call_list_enrolled_fingers_sync (dev, username,
&fingers, NULL,
&error)) {
gboolean ignore_error = FALSE;
if (g_dbus_error_is_remote_error (error)) {
g_autofree char *dbus_error =
g_dbus_error_get_remote_error (error);
if (g_str_equal (dbus_error,
"net.reactivated.Fprint.Error.NoEnrolledPrints")) {
ignore_error = TRUE;
}
}
if (!fprint_dbus_device_call_list_enrolled_fingers_sync (dev, username,
&fingers, NULL,
&error))
{
gboolean ignore_error = FALSE;
if (g_dbus_error_is_remote_error (error))
{
g_autofree char *dbus_error =
g_dbus_error_get_remote_error (error);
if (g_str_equal (dbus_error,
"net.reactivated.Fprint.Error.NoEnrolledPrints"))
ignore_error = TRUE;
}
if (!ignore_error) {
g_print("ListEnrolledFingers failed: %s\n", error->message);
exit (1);
}
}
if (!ignore_error)
{
g_print ("ListEnrolledFingers failed: %s\n", error->message);
exit (1);
}
}
if (fingers == NULL || g_strv_length (fingers) == 0) {
g_print ("User %s has no fingers enrolled for %s.\n", username,
fprint_dbus_device_get_name (dev));
return;
}
if (fingers == NULL || g_strv_length (fingers) == 0)
{
g_print ("User %s has no fingers enrolled for %s.\n", username,
fprint_dbus_device_get_name (dev));
return;
}
g_print("Fingerprints for user %s on %s (%s):\n",
username,
fprint_dbus_device_get_name (dev),
fprint_dbus_device_get_scan_type (dev));
g_print ("Fingerprints for user %s on %s (%s):\n",
username,
fprint_dbus_device_get_name (dev),
fprint_dbus_device_get_scan_type (dev));
for (i = 0; fingers[i] != NULL; i++) {
g_print(" - #%d: %s\n", i, fingers[i]);
}
for (i = 0; fingers[i] != NULL; i++)
g_print (" - #%d: %s\n", i, fingers[i]);
}
static void process_devices(char **argv)
static void
process_devices (char **argv)
{
g_auto(GStrv) devices = NULL;
g_autoptr(GError) error = NULL;
char *path;
guint num_devices;
guint i;
g_auto(GStrv) devices = NULL;
g_autoptr(GError) error = NULL;
char *path;
guint num_devices;
guint i;
if (!fprint_dbus_manager_call_get_devices_sync (manager, &devices, NULL,
&error)) {
g_print("Impossible to get devices: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_manager_call_get_devices_sync (manager, &devices, NULL,
&error))
{
g_print ("Impossible to get devices: %s\n", error->message);
exit (1);
}
num_devices = g_strv_length (devices);
if (num_devices == 0) {
g_print("No devices available\n");
exit(1);
}
num_devices = g_strv_length (devices);
if (num_devices == 0)
{
g_print ("No devices available\n");
exit (1);
}
g_print ("found %u devices\n", num_devices);
for (i = 0; devices[i] != NULL; i++) {
path = devices[i];
g_print("Device at %s\n", path);
}
g_print ("found %u devices\n", num_devices);
for (i = 0; devices[i] != NULL; i++)
{
path = devices[i];
g_print ("Device at %s\n", path);
}
for (i = 0; devices[i] != NULL; i++) {
g_autoptr(FprintDBusDevice) dev = NULL;
guint j;
for (i = 0; devices[i] != NULL; i++)
{
g_autoptr(FprintDBusDevice) dev = NULL;
guint j;
path = devices[i];
g_print("Using device %s\n", path);
path = devices[i];
g_print ("Using device %s\n", path);
/* NOTE: We should handle error cases! */
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, NULL);
/* NOTE: We should handle error cases! */
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, NULL);
for (j = 1; argv[j] != NULL; j++)
list_fingerprints (dev, argv[j]);
}
for (j = 1; argv[j] != NULL; j++)
list_fingerprints (dev, argv[j]);
}
}
int main(int argc, char **argv)
int
main (int argc, char **argv)
{
setlocale (LC_ALL, "");
setlocale (LC_ALL, "");
create_manager();
create_manager ();
if (argc < 2) {
g_print ("Usage: %s <username> [usernames...]\n", argv[0]);
return 1;
}
if (argc < 2)
{
g_print ("Usage: %s <username> [usernames...]\n", argv[0]);
return 1;
}
process_devices (argv);
process_devices (argv);
return 0;
return 0;
}

View File

@ -7,12 +7,12 @@
* 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.
@ -31,250 +31,276 @@ static char *finger_name = NULL;
static gboolean g_fatal_warnings = FALSE;
static char **usernames = NULL;
static void create_manager(void)
static void
create_manager (void)
{
g_autoptr(GError) error = NULL;
g_autoptr(GError) error = NULL;
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL) {
g_print("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
if (connection == NULL)
{
g_print ("Failed to connect to session bus: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL) {
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
manager = fprint_dbus_manager_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
"/net/reactivated/Fprint/Manager",
NULL, &error);
if (manager == NULL)
{
g_print ("Failed to get Fprintd manager: %s\n", error->message);
exit (1);
}
}
static FprintDBusDevice *open_device (const char *username)
static FprintDBusDevice *
open_device (const char *username)
{
g_autoptr(FprintDBusDevice) dev = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *path = NULL;
g_autoptr(FprintDBusDevice) dev = NULL;
g_autoptr(GError) error = NULL;
g_autofree char *path = NULL;
if (!fprint_dbus_manager_call_get_default_device_sync (manager, &path,
NULL, &error)) {
g_print("Impossible to verify: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_manager_call_get_default_device_sync (manager, &path,
NULL, &error))
{
g_print ("Impossible to verify: %s\n", error->message);
exit (1);
}
g_print("Using device %s\n", path);
g_print ("Using device %s\n", path);
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, &error);
dev = fprint_dbus_device_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
"net.reactivated.Fprint",
path, NULL, &error);
if (error) {
g_print ("failed to connect to device: %s\n", error->message);
exit (1);
}
if (error)
{
g_print ("failed to connect to device: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error)) {
g_print("failed to claim device: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error))
{
g_print ("failed to claim device: %s\n", error->message);
exit (1);
}
return g_steal_pointer (&dev);
return g_steal_pointer (&dev);
}
static void find_finger (FprintDBusDevice *dev, const char *username)
static void
find_finger (FprintDBusDevice *dev, const char *username)
{
g_autoptr(GError) error = NULL;
g_auto(GStrv) fingers = NULL;
guint i;
g_autoptr(GError) error = NULL;
g_auto(GStrv) fingers = NULL;
guint i;
if (!fprint_dbus_device_call_list_enrolled_fingers_sync (dev, username,
&fingers,
NULL, &error)) {
g_print("ListEnrolledFingers failed: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_list_enrolled_fingers_sync (dev, username,
&fingers,
NULL, &error))
{
g_print ("ListEnrolledFingers failed: %s\n", error->message);
exit (1);
}
if (fingers == NULL || g_strv_length (fingers) == 0) {
g_print("No fingers enrolled for this device.\n");
exit(1);
}
if (fingers == NULL || g_strv_length (fingers) == 0)
{
g_print ("No fingers enrolled for this device.\n");
exit (1);
}
g_print("Listing enrolled fingers:\n");
for (i = 0; fingers[i] != NULL; i++) {
g_print(" - #%d: %s\n", i, fingers[i]);
}
g_print ("Listing enrolled fingers:\n");
for (i = 0; fingers[i] != NULL; i++)
g_print (" - #%d: %s\n", i, fingers[i]);
if (finger_name && !g_str_equal (finger_name, "any") &&
!g_strv_contains ((const char **) fingers, finger_name)) {
g_print("Finger '%s' not enrolled for user %s.\n", finger_name,
username);
g_free (finger_name);
exit(1);
}
if (finger_name && !g_str_equal (finger_name, "any") &&
!g_strv_contains ((const char **) fingers, finger_name))
{
g_print ("Finger '%s' not enrolled for user %s.\n", finger_name,
username);
g_free (finger_name);
exit (1);
}
if (finger_name == NULL) {
finger_name = g_strdup (fingers[0]);
}
if (finger_name == NULL)
finger_name = g_strdup (fingers[0]);
}
struct VerifyState {
GError *error;
gboolean started;
gboolean completed;
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)
{
struct VerifyState *verify_state = user_data;
g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done");
if (done != FALSE)
verify_state->completed = TRUE;
struct VerifyState *verify_state = user_data;
g_print ("Verify result: %s (%s)\n", result, done ? "done" : "not done");
if (done != FALSE)
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)
{
g_print("Verifying: %s\n", name);
g_print ("Verifying: %s\n", name);
}
static void verify_started_cb (GObject *obj,
GAsyncResult *res,
gpointer user_data)
static void
verify_started_cb (GObject *obj,
GAsyncResult *res,
gpointer user_data)
{
struct VerifyState *verify_state = user_data;
struct VerifyState *verify_state = user_data;
if (fprint_dbus_device_call_verify_start_finish (FPRINT_DBUS_DEVICE (obj), res, &verify_state->error))
verify_state->started = TRUE;
if (fprint_dbus_device_call_verify_start_finish (FPRINT_DBUS_DEVICE (obj), res, &verify_state->error))
{
g_print ("Verify started!\n");
verify_state->started = TRUE;
}
}
static void proxy_signal_cb (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
static void
proxy_signal_cb (GDBusProxy *proxy,
const gchar *sender_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
struct VerifyState *verify_state = user_data;
struct VerifyState *verify_state = user_data;
if (!verify_state->started)
return;
if (!verify_state->started)
return;
if (g_str_equal (signal_name, "VerifyStatus")) {
const gchar *result;
gboolean done;
if (g_str_equal (signal_name, "VerifyStatus"))
{
const gchar *result;
gboolean done;
g_variant_get (parameters, "(&sb)", &result, &done);
verify_result (G_OBJECT (proxy), result, done, user_data);
} else if (g_str_equal (signal_name, "VerifyFingerSelected")) {
const gchar *name;
g_variant_get (parameters, "(&sb)", &result, &done);
verify_result (G_OBJECT (proxy), result, done, user_data);
}
else if (g_str_equal (signal_name, "VerifyFingerSelected"))
{
const gchar *name;
g_variant_get (parameters, "(&s)", &name);
verify_finger_selected (G_OBJECT (proxy), name, user_data);
}
g_variant_get (parameters, "(&s)", &name);
verify_finger_selected (G_OBJECT (proxy), name, user_data);
}
}
static void do_verify (FprintDBusDevice *dev)
static void
do_verify (FprintDBusDevice *dev)
{
g_autoptr(GError) error = NULL;
struct VerifyState verify_state = { 0 };
g_autoptr(GError) error = NULL;
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.
*/
/* 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),
&verify_state);
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
&verify_state);
fprint_dbus_device_call_verify_start (dev, finger_name, NULL,
verify_started_cb,
&verify_state);
fprint_dbus_device_call_verify_start (dev, finger_name, NULL,
verify_started_cb,
&verify_state);
/* Wait for verify start while discarding any VerifyStatus signals */
while (!verify_state.started && !verify_state.error)
g_main_context_iteration(NULL, TRUE);
/* 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);
}
g_print("Verify started!\n");
if (verify_state.error)
{
g_print ("VerifyStart failed: %s\n", verify_state.error->message);
g_clear_error (&verify_state.error);
exit (1);
}
/* VerifyStatus signals are processing, wait for completion. */
while (!verify_state.completed)
g_main_context_iteration(NULL, TRUE);
/* VerifyStatus signals are processing, wait for completion. */
while (!verify_state.completed)
g_main_context_iteration (NULL, TRUE);
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb,
&verify_state);
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb,
&verify_state);
if (!fprint_dbus_device_call_verify_stop_sync (dev, NULL, &error)) {
g_print("VerifyStop failed: %s\n", error->message);
exit (1);
}
if (!fprint_dbus_device_call_verify_stop_sync (dev, NULL, &error))
{
g_print ("VerifyStop failed: %s\n", error->message);
exit (1);
}
}
static void release_device (FprintDBusDevice *dev)
static void
release_device (FprintDBusDevice *dev)
{
g_autoptr(GError) error = NULL;
if (!fprint_dbus_device_call_release_sync (dev, NULL, &error)) {
g_print("ReleaseDevice failed: %s\n", error->message);
exit (1);
}
g_autoptr(GError) error = NULL;
if (!fprint_dbus_device_call_release_sync (dev, NULL, &error))
{
g_print ("ReleaseDevice failed: %s\n", error->message);
exit (1);
}
}
static const GOptionEntry entries[] = {
{ "finger", 'f', 0, G_OPTION_ARG_STRING, &finger_name, "Finger selected to verify (default is automatic)", NULL },
{"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL},
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &usernames, NULL, "[username]" },
{ NULL }
{ "finger", 'f', 0, G_OPTION_ARG_STRING, &finger_name, "Finger selected to verify (default is automatic)", NULL },
{"g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL},
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &usernames, NULL, "[username]" },
{ NULL }
};
int main(int argc, char **argv)
int
main (int argc, char **argv)
{
g_autoptr(FprintDBusDevice) dev = NULL;
g_autoptr(GError) err = NULL;
GOptionContext *context;
const char *username = NULL;
g_autoptr(FprintDBusDevice) dev = NULL;
g_autoptr(GError) err = NULL;
GOptionContext *context;
const char *username = NULL;
setlocale (LC_ALL, "");
setlocale (LC_ALL, "");
context = g_option_context_new ("Verify a fingerprint");
g_option_context_add_main_entries (context, entries, NULL);
context = g_option_context_new ("Verify a fingerprint");
g_option_context_add_main_entries (context, entries, NULL);
if (g_option_context_parse (context, &argc, &argv, &err) == FALSE) {
g_print ("couldn't parse command-line options: %s\n", err->message);
return 1;
}
if (g_option_context_parse (context, &argc, &argv, &err) == FALSE)
{
g_print ("couldn't parse command-line options: %s\n", err->message);
return 1;
}
if (usernames == NULL) {
username = "";
} else {
username = usernames[0];
}
if (usernames == NULL)
username = "";
else
username = usernames[0];
if (g_fatal_warnings) {
GLogLevelFlags fatal_mask;
if (g_fatal_warnings)
{
GLogLevelFlags fatal_mask;
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
g_log_set_always_fatal (fatal_mask);
}
create_manager();
create_manager ();
dev = open_device(username);
find_finger(dev, username);
do_verify(dev);
release_device(dev);
return 0;
dev = open_device (username);
find_finger (dev, username);
do_verify (dev);
release_device (dev);
return 0;
}