diff -Nru fprintd-1.90.1/config.h.in fprintd-1.90.9/config.h.in
--- fprintd-1.90.1/config.h.in 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/config.h.in 2021-01-13 12:23:24.000000000 +0000
@@ -9,3 +9,6 @@
/* Define to the version of this package. */
#mesondefine VERSION
+
+/* Whether current polkit version supports autopointers */
+#mesondefine POLKIT_HAS_AUTOPOINTERS
diff -Nru fprintd-1.90.1/data/meson.build fprintd-1.90.9/data/meson.build
--- fprintd-1.90.1/data/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/data/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -11,15 +11,17 @@
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,
diff -Nru fprintd-1.90.1/data/net.reactivated.Fprint.conf fprintd-1.90.9/data/net.reactivated.Fprint.conf
--- fprintd-1.90.1/data/net.reactivated.Fprint.conf 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/data/net.reactivated.Fprint.conf 2021-01-13 12:23:24.000000000 +0000
@@ -12,8 +12,18 @@
-
-
+
+
+
+
+
+
+
diff -Nru fprintd-1.90.1/data/net.reactivated.fprint.device.policy.in fprintd-1.90.9/data/net.reactivated.fprint.device.policy.in
--- fprintd-1.90.1/data/net.reactivated.fprint.device.policy.in 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/data/net.reactivated.fprint.device.policy.in 2021-01-13 12:23:24.000000000 +0000
@@ -25,7 +25,7 @@
no
no
- yes
+ auth_self_keep
diff -Nru fprintd-1.90.1/debian/changelog fprintd-1.90.9/debian/changelog
--- fprintd-1.90.1/debian/changelog 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/changelog 2021-02-22 15:00:47.000000000 +0000
@@ -1,3 +1,128 @@
+fprintd (1.90.9-1~ubuntu20.04.1) focal; urgency=medium
+
+ * Backport to focal (LP: #1908119)
+
+ -- Marco Trevisan (Treviño) Mon, 22 Feb 2021 16:00:47 +0100
+
+fprintd (1.90.9-1) unstable; urgency=medium
+
+ [ Marco Trevisan (Treviño) ]
+ * New upstream release:
+ - Fix multiple daemon lockup issues (#97)
+ - Fix print garbage collection to not delete used prints
+ - pam: Use the device with the most prints
+ * debian/control: Mark fprintd-doc as Multi-Arch: foreign
+
+ [ Helmut Grohne ]
+ * Fix nocheck FTFBS: Drop from non-optional dependencies.
+ (Closes: #977395)
+
+ -- Marco Trevisan (Treviño) Thu, 21 Jan 2021 21:29:07 +0100
+
+fprintd (1.90.8-1~ubuntu20.04.1) focal; urgency=medium
+
+ * Backport to focal (LP: #1908119)
+ * debian/{control,gbp.conf}: Prepare for ubuntu focal branching
+ * debian/{control, rules}: Do not use debhelper 13 features
+ * debian/rules: Use meson test directly to handle timeouts
+ * debian/patches: Drop all the patches applied upstream
+
+ -- Marco Trevisan (Treviño) Mon, 22 Feb 2021 15:53:20 +0100
+
+fprintd (1.90.8-1) unstable; urgency=medium
+
+ * New upstream release
+ - pam: Only listen to NameOwnerChanged after fprintd is known to run
+ - Place new ObjectManager DBus API at /net/reactivated/Fprint
+ * debian/patches: Remove all patches, applied upstream or not needed anymore
+ * debian/control: Depend on systemd 235, but only in linux
+ * debian/rules: Require systemd and set unit path only on linux
+ * debian/fprintd.install: Use dh-exec to filter linux-only files
+
+ -- Marco Trevisan (Treviño) Mon, 14 Dec 2020 21:32:29 +0100
+
+fprintd (1.90.7-1) unstable; urgency=medium
+
+ * New upstream release
+ - Fix fprintd DBus configuration (Closes: #976990)
+ - Change details of what requires authorization
+ - Fix various race conditions in pam_fprintd
+ - Permit interactive authorization from fprintd utilities
+ - Do not allow deletion while another operation is ongoing
+ - pam: Guard strdup calls against NULL pointers
+ * debian/patches:
+ - Refresh
+ - Ignore NameOwnerChanged until fprintd is running
+
+ -- Marco Trevisan (Treviño) Fri, 11 Dec 2020 00:03:27 +0100
+
+fprintd (1.90.5-2) unstable; urgency=medium
+
+ * debian/patches: Make tests run with actual required libfprint version
+ * debian/control: Remove test-only dependency on libfprint 1.90.4.
+ Tests are now working with older libfprint versions too
+ * debian/control: Add myself to Uploaders
+ * debian/gbp.conf: Include suggested settings by GNOME team.
+ Even if fprintd is not part of GNOME I think these settings are good
+ practice anyways.
+
+ -- Marco Trevisan (Treviño) Thu, 03 Dec 2020 15:57:19 +0100
+
+fprintd (1.90.5-1) unstable; urgency=medium
+
+ * New upstream release:
+ - Permit building with polkit older than 0.114
+ - Fix possible issues with PAM test
+ - Fix incorrect DBus policy
+ - Fix build so that CFLAGS environment is correctly used
+ - Skip hotplug test with older libfprint (which times out otherwise)
+ * debian/patches: Drop patches applied upstream
+
+ -- Marco Trevisan (Treviño) Wed, 02 Dec 2020 05:35:33 +0100
+
+fprintd (1.90.4-1) unstable; urgency=medium
+
+ * Team upload.
+ [ Marco Trevisan (Treviño) ]
+ * New upstream release:
+ - Use GDBus and async Polkit checks
+ - Authentication is now required to enroll a new print (LP: #1532264,
+ Closes: #719004)
+ - Add support for the libfprint early reporting mechanism
+ - Proper hotplug support together with libfprint 1.90.4
+ - Handle STATE_DIRECTORY containing multiple paths
+ - Various memory fixes (LP: #1888495)
+ * debian/control:
+ - Remove build dependency on dbus-glib (Closes: #955893)
+ - Mark as the packages required only for testing
+ - Use debhelper 13
+ - Bump libfprint-2 dependency on 1.90.4 on test case
+ * debian/rules:
+ - remove unneeded override to force --fail-missing (as per dh 13)
+ - Increase tests timeout multiplier
+ * debian/patches:
+ - Refresh
+ - Define auto-pointers functions if not defined:
+ Fixes a build failure with debian polkit version.
+ - Cleanup pam-wrapper temporary dir when running tests
+ - Fix dbus-policy file to address lintian
+ - Ensure we generate debug symbols in debian builds
+
+ [ Laurent Bigonville ]
+ * debian/control: Bump Standards-Version to 4.5.1 (no further changes)
+
+ -- Laurent Bigonville Tue, 01 Dec 2020 13:06:59 +0100
+
+fprintd (1.90.1-2) unstable; urgency=low
+
+ * Team upload.
+ * Simplify the installation of the pam-config, do not install one
+ configuration file per architecture
+ * debian/NEWS: Add an news entry explaining that the user will have to
+ re-enroll their fingerprints upon update to 1.90.1.
+
+ -- Laurent Bigonville Sun, 15 Nov 2020 16:22:57 +0100
+
fprintd (1.90.1-1ubuntu1) focal; urgency=medium
* d/p/device-Cancel-the-ongoing-operation-when-releasing-the-de.patch,
diff -Nru fprintd-1.90.1/debian/control fprintd-1.90.9/debian/control
--- fprintd-1.90.1/debian/control 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/control 2021-02-22 15:00:47.000000000 +0000
@@ -1,33 +1,33 @@
Source: fprintd
Section: misc
Priority: optional
-Maintainer: FingerForce Team
-Uploaders: Didier Raboud
+Maintainer: Ubuntu Developers
+XSBC-Original-Maintainer: FingerForce Team
+Uploaders: Marco Trevisan
Build-Depends: debhelper-compat (= 12),
- libdbus-1-dev,
- libdbus-glib-1-dev,
- libfprint-2-dev (>= 1:1.90.0),
+ dh-exec,
+ libfprint-2-dev (>= 1:1.90.1),
libglib2.0-dev (>= 2.56),
libpam0g-dev,
libpolkit-gobject-1-dev,
- libsystemd-dev,
+ libsystemd-dev (>= 235) [linux-any],
meson (>= 0.50.0),
policykit-1,
- rename,
-# Needed for the test suite
python3,
- python3-cairo-dev,
+ python3-cairo,
python3-dbus,
python3-dbusmock,
- python3-gi,
+ python3-gi ,
python3-pypamtest,
libpam-wrapper,
- libxml2-utils
+ libxml2-utils
Build-Depends-Indep: gtk-doc-tools , xsltproc
-Standards-Version: 4.5.0
+Standards-Version: 4.5.1
Homepage: https://www.freedesktop.org/wiki/Software/fprint/fprintd
-Vcs-Git: https://salsa.debian.org/debian/fprintd.git
-Vcs-Browser: https://salsa.debian.org/debian/fprintd
+XS-Debian-Vcs-Git: https://salsa.debian.org/debian/fprintd.git
+XS-Debian-Vcs-Browser: https://salsa.debian.org/debian/fprintd
+Vcs-Git: https://salsa.debian.org/debian/fprintd.git -b focal
+Vcs-Browser: https://salsa.debian.org/debian/fprintd/tree/focal
Package: fprintd
Architecture: any
@@ -63,6 +63,7 @@
Depends: ${misc:Depends}
Suggests: fprintd (>= ${source:Version}), libpam-fprintd (>= ${source:Version})
Build-Profiles:
+Multi-Arch: foreign
Description: development documentation for fprintd
fprintd is a D-Bus daemon that offers libfprint functionality over the
D-Bus interprocess communication bus. By adding this daemon layer above
diff -Nru fprintd-1.90.1/debian/fprintd.install fprintd-1.90.9/debian/fprintd.install
--- fprintd-1.90.1/debian/fprintd.install 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/fprintd.install 2021-02-22 15:00:47.000000000 +0000
@@ -1,5 +1,7 @@
+#!/usr/bin/dh-exec
+
etc/fprintd.conf
-lib/systemd/system/fprintd.service
+[linux-any] lib/systemd/system/fprintd.service
usr/bin/fprintd-delete
usr/bin/fprintd-enroll
usr/bin/fprintd-list
diff -Nru fprintd-1.90.1/debian/gbp.conf fprintd-1.90.9/debian/gbp.conf
--- fprintd-1.90.1/debian/gbp.conf 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/gbp.conf 2021-02-22 15:00:47.000000000 +0000
@@ -1,4 +1,18 @@
[DEFAULT]
pristine-tar = True
-debian-branch = debian
-upstream-vcs-tag = V_%(version%.%_)s
+debian-branch = focal
+debian-tag=ubuntu/%(version)s
+upstream-vcs-tag = v%(version)s
+
+[buildpackage]
+sign-tags = True
+
+[dch]
+multimaint-merge = True
+
+[import-orig]
+postimport = dch -v%(version)s New upstream release; git add debian/changelog; debcommit
+
+[pq]
+patch-numbers = False
+
diff -Nru fprintd-1.90.1/debian/libpam-fprintd.prerm fprintd-1.90.9/debian/libpam-fprintd.prerm
--- fprintd-1.90.1/debian/libpam-fprintd.prerm 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/libpam-fprintd.prerm 2021-02-22 15:00:47.000000000 +0000
@@ -2,8 +2,8 @@
set -e
-if [ "$1" = remove ]; then
- pam-auth-update --package --remove fprintd.#DEB_HOST_ARCH#
+if [ "$1" = remove ] && [ "${DPKG_MAINTSCRIPT_PACKAGE_REFCOUNT:-1}" = 1 ]; then
+ pam-auth-update --package --remove fprintd
fi
#DEBHELPER#
diff -Nru fprintd-1.90.1/debian/NEWS fprintd-1.90.9/debian/NEWS
--- fprintd-1.90.1/debian/NEWS 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/debian/NEWS 2021-02-22 15:00:47.000000000 +0000
@@ -0,0 +1,9 @@
+fprintd (1.90.1-1) experimental; urgency=medium
+
+ Since version 1.90.1, the format of the fingerprints database changed.
+
+ That means that each users will have to re-enroll their fingerprints either
+ using fprintd-enroll(1) or the desktop environment specific way (ie. via
+ gnome-control-center if you are using GNOME).
+
+ -- Laurent Bigonville Sun, 15 Nov 2020 15:47:25 +0100
diff -Nru fprintd-1.90.1/debian/patches/device-Cancel-the-ongoing-operation-when-releasing-the-de.patch fprintd-1.90.9/debian/patches/device-Cancel-the-ongoing-operation-when-releasing-the-de.patch
--- fprintd-1.90.1/debian/patches/device-Cancel-the-ongoing-operation-when-releasing-the-de.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Cancel-the-ongoing-operation-when-releasing-the-de.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,65 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Thu, 6 Feb 2020 21:34:39 +0100
-Subject: device: Cancel the ongoing operation when releasing the device
-
-If a device is currently verifying, identifying or enrolling we may want the
-user to stop the operation before we actually release the device.
-
-Otherwise we may end-up in trying to close (failing) the internal device,
-while fprintd is still considering the device active, causing a dead-lock
-(the device can't be released, but neither claimed again or stop the current
-action).
-
-In fact calling Claim() -> EnrollStart() -> Release(), we would fail with
-the error
-
- net.reactivated.Fprint.Error.Internal:
- Release failed with error: The device is still busy with another
- operation, please try again later. (36)"
-
-However, if we try to call VerifyStop, after this error, we'd fail because
-for the fprintd logic, the device is not claimed anymore, but actually
-closed, and we'd need to claim it again, but... That would still cause an
-internal error.
-
-To avoid this, in case Relase() is called cancel the ongoing operation,
-and wait until it's done before completing the release call.
-
-Origin: https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/e7f804e9
----
- src/device.c | 15 ++++++++++++++-
- 1 file changed, 14 insertions(+), 1 deletion(-)
-
-diff --git a/src/device.c b/src/device.c
-index b13d317..6508563 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -563,7 +563,7 @@ _fprint_device_client_vanished (GDBusConnection *connection,
- }
-
- if (!fp_device_close_sync (priv->dev, NULL, &error))
-- g_warning ("Error closing device after disconnect: %s", error->message);
-+ g_debug ("Error closing device after disconnect: %s", error->message);
-
- g_clear_pointer(&priv->session, session_data_free);
- }
-@@ -717,6 +717,19 @@ static void fprint_device_release(FprintDevice *rdev,
- return;
- }
-
-+ if (priv->current_cancellable) {
-+ if (priv->current_action == ACTION_ENROLL) {
-+ g_warning("Enrollment was in progress, stopping it");
-+ } else if (priv->current_action == ACTION_IDENTIFY ||
-+ priv->current_action == ACTION_VERIFY) {
-+ g_warning("Verification was in progress, stopping it");
-+ }
-+
-+ g_cancellable_cancel (priv->current_cancellable);
-+ while (priv->current_action != ACTION_NONE)
-+ g_main_context_iteration (NULL, TRUE);
-+ }
-+
- priv->session->context = context;
- fp_device_close (priv->dev, NULL, (GAsyncReadyCallback) dev_close_cb, rdev);
- }
diff -Nru fprintd-1.90.1/debian/patches/device-Fix-retry-enroll-error-names.patch fprintd-1.90.9/debian/patches/device-Fix-retry-enroll-error-names.patch
--- fprintd-1.90.1/debian/patches/device-Fix-retry-enroll-error-names.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Fix-retry-enroll-error-names.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,28 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Fri, 7 Feb 2020 21:28:58 +0100
-Subject: device: Fix retry enroll error names
-
-Use proper names for enroll retry errors, fixing a copy/paste error from the
-verify code.
-
-Origin: https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/efac52d9
----
- src/device.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/device.c b/src/device.c
-index 6508563..b206b22 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -371,9 +371,9 @@ enroll_result_to_name (gboolean completed, gboolean enrolled, GError *error)
- case FP_DEVICE_RETRY_CENTER_FINGER:
- return "enroll-finger-not-centered";
- case FP_DEVICE_RETRY_REMOVE_FINGER:
-- return "verify-remove-and-retry";
-- default:
- return "enroll-remove-and-retry";
-+ default:
-+ return "enroll-retry-scan";
- }
- } else {
- /* Which errors should be mapped to disconnection?
diff -Nru fprintd-1.90.1/debian/patches/device-Fix-verify-disconnected-state-name.patch fprintd-1.90.9/debian/patches/device-Fix-verify-disconnected-state-name.patch
--- fprintd-1.90.1/debian/patches/device-Fix-verify-disconnected-state-name.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Fix-verify-disconnected-state-name.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,24 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Tue, 11 Feb 2020 23:00:25 +0100
-Subject: device: Fix verify-disconnected state name
-
-Respect protocol, and use proper name
-
-Origin: https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/5e9624be
----
- src/device.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/device.c b/src/device.c
-index b206b22..82c8e3d 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -344,7 +344,7 @@ verify_result_to_name (gboolean match, GError *error)
- * Are drivers/libfprint/fprintd really in agreement here?
- */
- if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO))
-- return "verify-disconnect";
-+ return "verify-disconnected";
- else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- return "verify-no-match";
-
diff -Nru fprintd-1.90.1/debian/patches/device-Return-enroll-failed-on-cancelled-enrollment.patch fprintd-1.90.9/debian/patches/device-Return-enroll-failed-on-cancelled-enrollment.patch
--- fprintd-1.90.1/debian/patches/device-Return-enroll-failed-on-cancelled-enrollment.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Return-enroll-failed-on-cancelled-enrollment.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,44 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Mon, 10 Feb 2020 17:22:50 +0100
-Subject: device: Return 'enroll-failed' on cancelled enrollment
-
-We were returning an 'enroll-unknown-error' while we actually know what
-happened, so better to return a soft operation failure.
-
-Origin: https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/b312a5e54098
----
- src/device.c | 2 ++
- tests/fprintd.py | 7 +++++++
- 2 files changed, 9 insertions(+)
-
-diff --git a/src/device.c b/src/device.c
-index 2902851..b13d317 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -383,6 +383,8 @@ enroll_result_to_name (gboolean completed, gboolean enrolled, GError *error)
- return "enroll-disconnected";
- else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_FULL))
- return "enroll-data-full";
-+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-+ return "enroll-failed";
-
- return "enroll-unknown-error";
- }
-diff --git a/tests/fprintd.py b/tests/fprintd.py
-index eeb632a..9b8baaf 100755
---- a/tests/fprintd.py
-+++ b/tests/fprintd.py
-@@ -521,6 +521,13 @@ class FPrintdVirtualDeviceTest(FPrintdTest):
-
- self.device.Release()
-
-+ def test_enroll_stop_cancels(self):
-+ self.device.Claim('(s)', 'testuser')
-+ self.device.EnrollStart('(s)', 'left-index-finger')
-+ self.device.EnrollStop()
-+ self.wait_for_result(expected='enroll-failed')
-+
-+
- if __name__ == '__main__':
- if len(sys.argv) == 2 and sys.argv[1] == "list-tests":
- for machine, human in list_tests():
diff -Nru fprintd-1.90.1/debian/patches/device-Return-verify-no-match-on-cancelled-verification-1.patch fprintd-1.90.9/debian/patches/device-Return-verify-no-match-on-cancelled-verification-1.patch
--- fprintd-1.90.1/debian/patches/device-Return-verify-no-match-on-cancelled-verification-1.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Return-verify-no-match-on-cancelled-verification-1.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,36 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Mon, 10 Feb 2020 17:23:19 +0100
-Subject: device: Return 'verify-no-match' on cancelled verification
-
-We were returning a 'verify-unknown-error' while we actually know what
-happened, so better to return a soft operation failure.
-
-https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/0e993d92
----
- tests/fprintd.py | 13 +++++++++++++
- 1 file changed, 13 insertions(+)
-
-diff --git a/tests/fprintd.py b/tests/fprintd.py
-index 9b8baaf..613c096 100755
---- a/tests/fprintd.py
-+++ b/tests/fprintd.py
-@@ -527,6 +527,19 @@ class FPrintdVirtualDeviceTest(FPrintdTest):
- self.device.EnrollStop()
- self.wait_for_result(expected='enroll-failed')
-
-+ def test_verify_stop_cancels(self):
-+ self.device.Claim('(s)', 'testuser')
-+ self.enroll_image('whorl')
-+ self.device.VerifyStart('(s)', 'any')
-+ self.device.VerifyStop()
-+ self.wait_for_result(expected='verify-no-match')
-+
-+ def test_verify_finger_stop_cancels(self):
-+ self.device.Claim('(s)', 'testuser')
-+ self.enroll_image('whorl', finger='left-thumb')
-+ self.device.VerifyStart('(s)', 'left-thumb')
-+ self.device.VerifyStop()
-+
-
- if __name__ == '__main__':
- if len(sys.argv) == 2 and sys.argv[1] == "list-tests":
diff -Nru fprintd-1.90.1/debian/patches/device-Return-verify-no-match-on-cancelled-verification.patch fprintd-1.90.9/debian/patches/device-Return-verify-no-match-on-cancelled-verification.patch
--- fprintd-1.90.1/debian/patches/device-Return-verify-no-match-on-cancelled-verification.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Return-verify-no-match-on-cancelled-verification.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,25 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Mon, 10 Feb 2020 17:23:19 +0100
-Subject: device: Return 'verify-no-match' on cancelled verification
-
-We were returning a 'verify-unknown-error' while we actually know what
-happened, so better to return a soft operation failure.
-
-Origin: https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/0e993d92e2c8
----
- src/device.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/src/device.c b/src/device.c
-index e4f7b1d..2902851 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -345,6 +345,8 @@ verify_result_to_name (gboolean match, GError *error)
- */
- if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO))
- return "verify-disconnect";
-+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-+ return "verify-no-match";
-
- return "verify-unknown-error";
- }
diff -Nru fprintd-1.90.1/debian/patches/device-Throw-NoEnrolledPrints-on-missing-finger-in-galler.patch fprintd-1.90.9/debian/patches/device-Throw-NoEnrolledPrints-on-missing-finger-in-galler.patch
--- fprintd-1.90.1/debian/patches/device-Throw-NoEnrolledPrints-on-missing-finger-in-galler.patch 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/device-Throw-NoEnrolledPrints-on-missing-finger-in-galler.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,25 +0,0 @@
-From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?=
-Date: Tue, 11 Feb 2020 02:29:13 +0100
-Subject: device: Throw NoEnrolledPrints on missing finger in gallery
-
-Throw a NoEnrolledPrints error if the requested finger isn't present
-in the gallery.
-
-Origin: https://gitlab.freedesktop.org/libfprint/fprintd/-/commit/f4ee2f86
----
- src/device.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/device.c b/src/device.c
-index 82c8e3d..c753e9a 100644
---- a/src/device.c
-+++ b/src/device.c
-@@ -915,7 +915,7 @@ static void fprint_device_verify_start(FprintDevice *rdev,
- priv->session->username, &print);
-
- if (!print) {
-- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
-+ g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
- "No such print %d", finger_num);
- dbus_g_method_return_error(context, error);
- return;
diff -Nru fprintd-1.90.1/debian/patches/remove_unneeded_systemd_check.patch fprintd-1.90.9/debian/patches/remove_unneeded_systemd_check.patch
--- fprintd-1.90.1/debian/patches/remove_unneeded_systemd_check.patch 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/patches/remove_unneeded_systemd_check.patch 1970-01-01 00:00:00.000000000 +0000
@@ -1,15 +0,0 @@
-Description: Remove unneeded check against systemd version
-Author: Laurent Bigonville
-Forwarded: not-needed
-
---- a/meson.build
-+++ b/meson.build
-@@ -84,8 +84,6 @@ pam_dep = cc.find_library('pam',
- 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_unit_dir = get_option('systemd_system_unit_dir')
-
- if systemd_unit_dir == ''
diff -Nru fprintd-1.90.1/debian/patches/series fprintd-1.90.9/debian/patches/series
--- fprintd-1.90.1/debian/patches/series 2020-04-16 07:01:27.000000000 +0000
+++ fprintd-1.90.9/debian/patches/series 1970-01-01 00:00:00.000000000 +0000
@@ -1,8 +0,0 @@
-remove_unneeded_systemd_check.patch
-device-Return-verify-no-match-on-cancelled-verification.patch
-device-Return-enroll-failed-on-cancelled-enrollment.patch
-device-Return-verify-no-match-on-cancelled-verification-1.patch
-device-Cancel-the-ongoing-operation-when-releasing-the-de.patch
-device-Fix-retry-enroll-error-names.patch
-device-Fix-verify-disconnected-state-name.patch
-device-Throw-NoEnrolledPrints-on-missing-finger-in-galler.patch
diff -Nru fprintd-1.90.1/debian/rules fprintd-1.90.9/debian/rules
--- fprintd-1.90.1/debian/rules 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/rules 2021-02-22 15:00:47.000000000 +0000
@@ -6,7 +6,14 @@
dh $@
# Configuration arguments
-CONFIG_ARGS = -Dpam=true -Dsystemd_system_unit_dir=/lib/systemd/system
+CONFIG_ARGS = -Dpam=true
+BUILDDIR = $(CURDIR)/obj-$(DEB_HOST_GNU_TYPE)
+
+ifeq ($(DEB_HOST_ARCH_OS),linux)
+ CONFIG_ARGS += -Dsystemd_system_unit_dir=/lib/systemd/system
+else
+ CONFIG_ARGS += -Dsystemd=false
+endif
ifneq (,$(filter fprintd-doc,$(shell dh_listpackages)))
CONFIG_ARGS += -Dgtk_doc=true
@@ -15,15 +22,8 @@
override_dh_auto_configure:
dh_auto_configure -- $(CONFIG_ARGS)
-override_dh_install-arch:
- dh_install -a
- # Arch-qualify pam-configs
- rename 's|(.*)/(.*)$$|$$1/$$2.$(DEB_HOST_ARCH)|' debian/libpam-fprintd/usr/share/pam-configs/*
- sed -e 's/#DEB_HOST_ARCH#/$(DEB_HOST_ARCH)/g' debian/libpam-fprintd.prerm > debian/libpam-fprintd.prerm.$(DEB_HOST_ARCH)
-
override_dh_missing:
dh_missing --fail-missing
-override_dh_clean:
- rm -f debian/libpam-fprintd.prerm.*
- dh_clean
+override_dh_auto_test:
+ meson test -C $(BUILDDIR) --verbose --timeout-multiplier 5
diff -Nru fprintd-1.90.1/debian/watch fprintd-1.90.9/debian/watch
--- fprintd-1.90.1/debian/watch 2020-02-19 13:01:10.000000000 +0000
+++ fprintd-1.90.9/debian/watch 2021-02-22 15:00:47.000000000 +0000
@@ -1,4 +1,5 @@
version=4
-https://gitlab.freedesktop.org/libfprint/fprintd/tags \
- /libfprint/fprintd/uploads/(?:.*)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@
+opts=versionmangle=s/_/./g \
+ https://gitlab.freedesktop.org/libfprint/@PACKAGE@/tags \
+ .*\/archive\/[Vv]_?([\d_\+\.]+)\/@PACKAGE@-.*@ARCHIVE_EXT@
diff -Nru fprintd-1.90.1/doc/dbus/meson.build fprintd-1.90.9/doc/dbus/meson.build
--- fprintd-1.90.1/doc/dbus/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/doc/dbus/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -2,8 +2,8 @@
output: 'docbook-xml-header.xml',
command: [
'echo', '-n',
- '',
- '',
+ '\n',
+ '\n',
],
capture: true,
)
diff -Nru fprintd-1.90.1/.git-blame-ignore-revs fprintd-1.90.9/.git-blame-ignore-revs
--- fprintd-1.90.1/.git-blame-ignore-revs 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/.git-blame-ignore-revs 2021-01-13 12:23:24.000000000 +0000
@@ -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
diff -Nru fprintd-1.90.1/.gitignore fprintd-1.90.9/.gitignore
--- fprintd-1.90.1/.gitignore 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/.gitignore 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,11 @@
+/*.bak
+/*.o
+/*.orig
+/*.rej
+/*.tab.c
+/*~
+/.*.sw[nop]
+/.dirstamp
+/.gitignore
+/_build
+/tags
diff -Nru fprintd-1.90.1/.gitlab-ci.yml fprintd-1.90.9/.gitlab-ci.yml
--- fprintd-1.90.1/.gitlab-ci.yml 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/.gitlab-ci.yml 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,127 @@
+include:
+ - project: 'libfprint/libfprint'
+ ref: master
+ file: '/.gitlab-ci/libfprint-templates.yaml'
+ - project: 'wayland/ci-templates'
+ ref: master
+ file: '/templates/fedora.yml'
+
+variables:
+ extends: .libfprint_common_variables
+ FDO_DISTRIBUTION_TAG: latest
+ FDO_DISTRIBUTION_VERSION: rawhide
+ FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FDO_DISTRIBUTION_VERSION:$FDO_DISTRIBUTION_TAG"
+ DEPENDENCIES: dbus-glib-devel
+ gcc
+ gcovr
+ gettext
+ git
+ glibc-devel
+ gtk-doc
+ libasan
+ libfprint-devel
+ meson
+ pam-devel
+ polkit-devel
+ python3-dbusmock
+ python3-libpamtest
+ systemd-devel
+
+image: "$FEDORA_IMAGE"
+
+stages:
+ - check-source
+ - build
+ - test
+
+.fprintd_build_preconditions:
+ except:
+ variables:
+ - $FPRINT_CRON_TASK == "BUILD_CI_IMAGES"
+
+.install_libfprint_dev:
+ before_script:
+ # Make sure we don't build or link against the system libfprint
+ - dnf remove -y libfprint-devel
+ - git clone https://gitlab.freedesktop.org/libfprint/libfprint.git
+ - cd libfprint
+ - meson . _build --prefix=/usr -Ddrivers=virtual_image -Ddoc=false
+ - ninja -C _build
+ - ninja -C _build install
+ - cd ..
+ # 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
+ - ninja -C _build -v install
+
+build_dev:
+ extends:
+ - .fprintd_build_preconditions
+ - .install_libfprint_dev
+ stage: build
+ script:
+ - meson _build --werror -Dgtk_doc=true
+ - ninja -C _build -v
+ - ninja -C _build -v install
+ artifacts:
+ name: log
+ when: on_failure
+ paths:
+ - _build/meson-logs/*.txt
+
+test_dev:
+ extends:
+ - .fprintd_build_preconditions
+ - .install_libfprint_dev
+ stage: test
+ script:
+ - meson _build -Db_coverage=true
+ - meson test -C _build --verbose --no-stdsplit --timeout-multiplier 3
+ - ninja -C _build coverage
+ - cat _build/meson-logs/coverage.txt
+ artifacts:
+ name: log-and-coverage
+ when: always
+ paths:
+ - _build/meson-logs
+
+test_dev_with_sanitizer:
+ extends:
+ - .fprintd_build_preconditions
+ - .install_libfprint_dev
+ stage: test
+ script:
+ - meson _build -Db_sanitize=address
+ - meson test -C _build --verbose --no-stdsplit --timeout-multiplier 5
+ artifacts:
+ name: meson-logs
+ when: on_failure
+ paths:
+ - _build/meson-logs
+
+# CONTAINERS creation stage
+container_fedora_build:
+ extends: .fdo.container-build@fedora
+ only:
+ variables:
+ - $FPRINT_CRON_TASK == "BUILD_CI_IMAGES"
+ variables:
+ GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
+ # a list of packages to install
+ FDO_DISTRIBUTION_PACKAGES:
+ $DEPENDENCIES
+ $LIBFPRINT_DEPENDENCIES
diff -Nru fprintd-1.90.1/meson.build fprintd-1.90.9/meson.build
--- fprintd-1.90.1/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -1,9 +1,9 @@
project('fprintd', 'c',
- version: '1.90.1',
+ version: '1.90.9',
license: 'GPLv2+',
default_options: [
'buildtype=debugoptimized',
- 'warning_level=1',
+ 'warning_level=3',
'c_std=gnu99',
],
meson_version: '>= 0.50.0')
@@ -12,23 +12,8 @@
i18n = import('i18n')
cc = meson.get_compiler('c')
-host_system = host_machine.system()
-glib_min_version = '2.56'
-libfprint_min_version = '1.90.0'
-
-fprintd_installdir = get_option('prefix') / get_option('libexecdir')
-fprintd_plugindir = get_option('prefix') / get_option('libdir') / meson.project_name() / 'modules'
-storage_path = get_option('prefix') / get_option('localstatedir') / 'lib/fprint'
-localedir = get_option('prefix') / get_option('localedir')
-datadir = get_option('prefix') / get_option('datadir')
-sysconfdir = get_option('sysconfdir')
-if get_option('prefix') != '/usr'
- sysconfdir = get_option('prefix') / sysconfdir
-endif
-
common_cflags = cc.get_supported_arguments([
'-fno-strict-aliasing',
- '-Wall',
'-Wcast-align',
'-Werror=address',
'-Werror=array-bounds',
@@ -67,14 +52,38 @@
])
add_project_arguments(common_cflags, language: 'c')
+common_cflags = cc.get_supported_arguments([
+ # The stub passes a lot of params that we do not use, maybe a good idea to
+ # mark it appropriately, but this works well for now.
+ '-Wno-unused-parameter',
+ # We use g_signal_handlers_disconnect_* which is not compatible with -Wpedantic
+ '-Wno-pedantic',
+])
+add_project_arguments(common_cflags, language: 'c')
+
+host_system = host_machine.system()
+# NOTE: Bump gdbus-codegen min version once we can depend on 2.64!
+glib_min_version = '2.56'
+libfprint_min_version = '1.90.1'
+
+fprintd_installdir = get_option('prefix') / get_option('libexecdir')
+fprintd_plugindir = get_option('prefix') / get_option('libdir') / meson.project_name() / 'modules'
+storage_path = get_option('prefix') / get_option('localstatedir') / 'lib/fprint'
+localedir = get_option('prefix') / get_option('localedir')
+datadir = get_option('prefix') / get_option('datadir')
+sysconfdir = get_option('sysconfdir')
+if get_option('prefix') != '/usr'
+ sysconfdir = get_option('prefix') / sysconfdir
+endif
+
# Dependencies
glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version)
gio_dep = dependency('gio-2.0', version: '>=' + glib_min_version)
+gio_unix_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version)
gmodule_dep = dependency('gmodule-2.0', version: '>=' + glib_min_version)
libfprint_dep = dependency('libfprint-2', version: '>=' + libfprint_min_version)
polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.91')
dbus_dep = dependency('dbus-1', required: false)
-dbus_glib_dep = dependency('dbus-glib-1')
libsystemd_dep = dependency('libsystemd', required: get_option('pam'))
pam_dep = cc.find_library('pam',
required: get_option('pam'),
@@ -85,13 +94,17 @@
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 = ''
@@ -125,6 +138,7 @@
'dbus': true,
'dbusmock': true,
'gi': true,
+ 'gi.repository.FPrint': true,
'pypamtest': get_option('pam'),
}
python3_available_modules = []
@@ -140,6 +154,7 @@
cdata.set_quoted('PACKAGE_VERSION', meson.project_version())
cdata.set_quoted('VERSION', meson.project_version())
cdata.set_quoted('SYSCONFDIR', sysconfdir)
+cdata.set('POLKIT_HAS_AUTOPOINTERS', polkit_gobject_dep.version().version_compare('>= 0.114'))
config_h = configure_file(
input: 'config.h.in',
@@ -178,5 +193,7 @@
output += ' Manuals: ' + get_option('man').to_string()
output += ' GTK Doc: ' + get_option('gtk_doc').to_string()
output += ' XML Linter ' + xmllint.found().to_string()
+output += '\nTest setup:\n'
+output += ' With address sanitizer: ' + address_sanitizer.to_string()
message('\n'+'\n'.join(output)+'\n')
diff -Nru fprintd-1.90.1/meson_options.txt fprintd-1.90.9/meson_options.txt
--- fprintd-1.90.1/meson_options.txt 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/meson_options.txt 2021-01-13 12:23:24.000000000 +0000
@@ -6,6 +6,10 @@
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')
diff -Nru fprintd-1.90.1/NEWS fprintd-1.90.9/NEWS
--- fprintd-1.90.1/NEWS 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/NEWS 2021-01-13 12:23:24.000000000 +0000
@@ -1,6 +1,77 @@
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
+with the DBus interface and authorization. We also found a number of
+problems with possible security implications.
+
+Currently fprintd will do interactive authorization even if this was not
+requested using the correct DBus method call flag. All API users MUST be
+updated to set the flag as it will be enabled in the future!
+
+Highlights:
+ - Fix fprintd DBus configuration
+ - Change details of what requires authorization
+ - Fix various race conditions in pam_fprintd
+ - Permit interactive authorization from fprintd utilities
+ - Do not allow deletion while another operation is ongoing
+
+
+Version 1.90.5:
+
+The 1.90.4 release contained some bad errors, this release addresses those.
+
+Highlights:
+ - Permit building with polkit older than 0.114
+ - Fix possible issues with PAM test
+ - Fix incorrect DBus policy
+ - Fix build so that CFLAGS enviroment is correctly used
+ - Skip hotplug test with older libfprint (which times out otherwise)
+
+Version 1.90.4:
+
+This fprintd release contains major core reworkings and improved testing.
+As such, only the most important changes are listed here, focusing on
+changes relevant to distributors.
+
+Highlights:
+ - Authentication is now required to enroll a new print (#5)
+ - Add support for the libfprint early reporting mechanism
+ - Proper hotplug support together with libfprint 1.90.4
+ - Handle STATE_DIRECTORY containing multiple paths
+
version 1.90.1:
- Add support for prints saved on the fingerprint device itself
- Add integration tests using the virtual image driver, and further
diff -Nru fprintd-1.90.1/pam/fingerprint-strings.h fprintd-1.90.9/pam/fingerprint-strings.h
--- fprintd-1.90.1/pam/fingerprint-strings.h 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/pam/fingerprint-strings.h 2021-01-13 12:23:24.000000000 +0000
@@ -1,7 +1,7 @@
/*
* Helper functions to translate statuses and actions to strings
* Copyright (C) 2008 Bastien Nocera
- *
+ *
* 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 @@
* 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 N_("Place your finger on the reader again");
- else
- return N_("Swipe your finger again");
- }
- if (strcmp (result, "verify-swipe-too-short") == 0)
- return N_("Swipe was too short, try again");
- if (strcmp (result, "verify-finger-not-centered") == 0)
- return N_("Your finger was not centered, try swiping your finger again");
- if (strcmp (result, "verify-remove-and-retry") == 0)
- return 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 @@
* 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 N_("Place your finger on the reader again");
- else
- return N_("Swipe your finger again");
- }
- if (strcmp (result, "enroll-swipe-too-short") == 0)
- return N_("Swipe was too short, try again");
- if (strcmp (result, "enroll-finger-not-centered") == 0)
- return N_("Your finger was not centered, try swiping your finger again");
- if (strcmp (result, "enroll-remove-and-retry") == 0)
- return 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;
}
-
diff -Nru fprintd-1.90.1/pam/pam_fprintd_autoptrs.h fprintd-1.90.9/pam/pam_fprintd_autoptrs.h
--- fprintd-1.90.1/pam/pam_fprintd_autoptrs.h 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/pam/pam_fprintd_autoptrs.h 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,61 @@
+/*
+ * pam_fprint: PAM module for fingerprint authentication through fprintd
+ * Copyright (C) 2020 Marco Trevisan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+#include
+
+/* Define auto-pointers functions, based on GLib Macros */
+
+#define _CLEANUP_FUNC(func) __attribute__((cleanup (func)))
+
+#define _PF_AUTOPTR_FUNC_NAME(TypeName) pf_autoptr_cleanup_ ## TypeName
+#define _PF_AUTOPTR_TYPENAME(TypeName) TypeName ## _pf_autoptr
+
+#define PF_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, cleanup) \
+ typedef TypeName *_PF_AUTOPTR_TYPENAME (TypeName); \
+ static __attribute__((__unused__)) inline void \
+ _PF_AUTOPTR_FUNC_NAME (TypeName) (TypeName **_ptr) \
+ { if (_ptr) (cleanup) (*_ptr); }
+
+#define PF_DEFINE_AUTO_CLEAN_FUNC(TypeName, cleanup) \
+ static __attribute__((__unused__)) inline void \
+ _PF_AUTOPTR_FUNC_NAME (TypeName) (TypeName *_ptr) \
+ { cleanup (_ptr); }
+
+static inline void
+autoptr_cleanup_generic_free (void *p)
+{
+ void **pp = (void **) p;
+
+ free (*pp);
+}
+
+#define pf_autofree _CLEANUP_FUNC (autoptr_cleanup_generic_free)
+#define pf_autoptr(TypeName) \
+ _CLEANUP_FUNC (_PF_AUTOPTR_FUNC_NAME (TypeName)) \
+ _PF_AUTOPTR_TYPENAME (TypeName)
+#define pf_auto(TypeName) \
+ _CLEANUP_FUNC (_PF_AUTOPTR_FUNC_NAME (TypeName)) TypeName
+
+PF_DEFINE_AUTOPTR_CLEANUP_FUNC (sd_bus, sd_bus_unref)
+PF_DEFINE_AUTOPTR_CLEANUP_FUNC (sd_bus_message, sd_bus_message_unref)
+PF_DEFINE_AUTOPTR_CLEANUP_FUNC (sd_bus_slot, sd_bus_slot_unref)
+
+PF_DEFINE_AUTO_CLEAN_FUNC (sd_bus_error, sd_bus_error_free)
diff -Nru fprintd-1.90.1/pam/pam_fprintd.c fprintd-1.90.9/pam/pam_fprintd.c
--- fprintd-1.90.1/pam/pam_fprintd.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/pam/pam_fprintd.c 2021-01-13 12:23:24.000000000 +0000
@@ -39,10 +39,11 @@
#include
#define _(s) ((char *) dgettext (GETTEXT_PACKAGE, s))
-#define TR(s) dgettext(GETTEXT_PACKAGE, s)
+#define TR(s) dgettext (GETTEXT_PACKAGE, s)
#define N_(s) (s)
#include "fingerprint-strings.h"
+#include "pam_fprintd_autoptrs.h"
#define DEFAULT_MAX_TRIES 3
#define DEFAULT_TIMEOUT 30
@@ -59,637 +60,770 @@
#define USEC_PER_SEC ((uint64_t) 1000000ULL)
#define NSEC_PER_USEC ((uint64_t) 1000ULL)
+static size_t user_enrolled_prints_num (pam_handle_t *pamh,
+ sd_bus *bus,
+ const char *dev,
+ const char *username);
+
static uint64_t
now (void)
{
- struct timespec ts;
- clock_gettime (CLOCK_MONOTONIC, &ts);
- return (uint64_t) ts.tv_sec * USEC_PER_SEC + (uint64_t) ts.tv_nsec / NSEC_PER_USEC;
+ struct timespec ts;
+
+ clock_gettime (CLOCK_MONOTONIC, &ts);
+ return (uint64_t) ts.tv_sec * USEC_PER_SEC + (uint64_t) ts.tv_nsec / NSEC_PER_USEC;
}
-static bool str_has_prefix (const char *s, const char *prefix)
+static bool
+str_has_prefix (const char *s, const char *prefix)
{
- if (s == NULL || prefix == NULL)
- return false;
- return (strncmp (s, prefix, strlen (prefix)) == 0);
+ if (s == NULL || prefix == NULL)
+ return false;
+ return strncmp (s, prefix, strlen (prefix)) == 0;
}
-static bool send_msg(pam_handle_t *pamh, const char *msg, int style)
+static bool
+send_msg (pam_handle_t *pamh, const char *msg, int style)
{
- const struct pam_message mymsg = {
- .msg_style = style,
- .msg = msg,
- };
- const struct pam_message *msgp = &mymsg;
- const struct pam_conv *pc;
- struct pam_response *resp;
- int r;
+ const struct pam_message mymsg = {
+ .msg_style = style,
+ .msg = msg,
+ };
+ const struct pam_message *msgp = &mymsg;
+ const struct pam_conv *pc;
+ struct pam_response *resp;
- r = pam_get_item(pamh, PAM_CONV, (const void **) &pc);
- if (r != PAM_SUCCESS)
- return false;
+ if (pam_get_item (pamh, PAM_CONV, (const void **) &pc) != PAM_SUCCESS)
+ return false;
- if (!pc || !pc->conv)
- return false;
+ if (!pc || !pc->conv)
+ return false;
- return (pc->conv(1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS);
+ return pc->conv (1, &msgp, &resp, pc->appdata_ptr) == PAM_SUCCESS;
}
-static bool send_info_msg(pam_handle_t *pamh, const char *msg)
+static bool
+send_info_msg (pam_handle_t *pamh, const char *msg)
{
- return send_msg(pamh, msg, PAM_TEXT_INFO);
+ return send_msg (pamh, msg, PAM_TEXT_INFO);
}
-static bool send_err_msg(pam_handle_t *pamh, const char *msg)
+static bool
+send_err_msg (pam_handle_t *pamh, const char *msg)
{
- return send_msg(pamh, msg, PAM_ERROR_MSG);
+ return send_msg (pamh, msg, PAM_ERROR_MSG);
}
static char *
-open_device (pam_handle_t *pamh,
- sd_bus *bus,
- bool *has_multiple_devices)
-{
- sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *m = NULL;
- size_t num_devices;
- const char *path = NULL;
- char *ret;
- const char *s;
- int r;
-
- *has_multiple_devices = false;
-
- r = sd_bus_call_method (bus,
- "net.reactivated.Fprint",
- "/net/reactivated/Fprint/Manager",
- "net.reactivated.Fprint.Manager",
- "GetDevices",
- &error,
- &m,
- NULL);
- if (r < 0) {
- pam_syslog (pamh, LOG_ERR, "GetDevices failed: %s", error.message);
- sd_bus_error_free (&error);
- return NULL;
- }
-
- r = sd_bus_message_enter_container (m, 'a', "o");
- if (r < 0) {
- pam_syslog (pamh, LOG_ERR, "Failed to parse answer from GetDevices(): %d", r);
- goto out;
- }
-
- r = sd_bus_message_read_basic (m, 'o', &path);
- if (r < 0)
- goto out;
-
- num_devices = 1;
- while ((r = sd_bus_message_read_basic(m, 'o', &s)) > 0)
- num_devices++;
- *has_multiple_devices = (num_devices > 1);
- if (debug)
- pam_syslog(pamh, LOG_DEBUG, "Using device %s (out of %ld devices)", path, num_devices);
-
- sd_bus_message_exit_container (m);
-
-out:
- ret = path ? strdup (path) : NULL;
- sd_bus_message_unref (m);
- return ret;
-}
-
-typedef struct {
- unsigned max_tries;
- char *result;
- bool timed_out;
- bool is_swipe;
- pam_handle_t *pamh;
+open_device (pam_handle_t *pamh,
+ sd_bus *bus,
+ const char *username,
+ bool *has_multiple_devices)
+{
+ pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
+ pf_autoptr (sd_bus_message) m = NULL;
+ size_t num_devices;
+ size_t max_prints;
+ const char *path = NULL;
+ const char *s;
+ int r;
+
+ *has_multiple_devices = false;
+
+ if (sd_bus_call_method (bus,
+ "net.reactivated.Fprint",
+ "/net/reactivated/Fprint/Manager",
+ "net.reactivated.Fprint.Manager",
+ "GetDevices",
+ &error,
+ &m,
+ NULL) < 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "GetDevices failed: %s", error.message);
+ return NULL;
+ }
+
+ r = sd_bus_message_enter_container (m, 'a', "o");
+ if (r < 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "Failed to parse answer from GetDevices(): %d", r);
+ return NULL;
+ }
+
+ num_devices = 0;
+ max_prints = 0;
+ while ((r = sd_bus_message_read_basic (m, 'o', &s)) > 0)
+ {
+ size_t enrolled_prints = user_enrolled_prints_num (pamh, bus, s, username);
+
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "%s prints registered: %" PRIu64, s, enrolled_prints);
+
+ if (enrolled_prints > max_prints)
+ {
+ max_prints = enrolled_prints;
+ path = s;
+ }
+
+ num_devices++;
+ }
+ *has_multiple_devices = (num_devices > 1);
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "Using device %s (out of %ld devices)", path, num_devices);
+
+ sd_bus_message_exit_container (m);
+
+ return path ? strdup (path) : NULL;
+}
+
+typedef struct
+{
+ char *dev;
+ bool has_multiple_devices;
+
+ unsigned max_tries;
+ char *result;
+ bool timed_out;
+ bool is_swipe;
+ bool verify_started;
+ int verify_ret;
+ pam_handle_t *pamh;
- char *driver;
+ char *driver;
} verify_data;
+static void
+verify_data_free (verify_data *data)
+{
+ free (data->result);
+ free (data->driver);
+ free (data->dev);
+ free (data);
+}
+
+PF_DEFINE_AUTOPTR_CLEANUP_FUNC (verify_data, verify_data_free)
+
static int
verify_result (sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
+ void *userdata,
+ sd_bus_error *ret_error)
{
- verify_data *data = userdata;
- const char *msg;
- const char *result = NULL;
- /* see https://github.com/systemd/systemd/issues/14643 */
- uint64_t done = false;
- int r;
-
- if (!sd_bus_message_is_signal(m, "net.reactivated.Fprint.Device", "VerifyStatus")) {
- pam_syslog (data->pamh, LOG_ERR, "Not the signal we expected (iface: %s, member: %s)",
- sd_bus_message_get_interface (m),
- sd_bus_message_get_member (m));
- return 0;
- }
-
- if ((r = sd_bus_message_read (m, "sb", &result, &done)) < 0) {
- pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyResult signal: %d", r);
- return 0;
- }
-
- if (debug)
- pam_syslog (data->pamh, LOG_DEBUG, "Verify result: %s (done: %d)", result, done ? 1 : 0);
-
- if (done) {
- data->result = strdup (result);
- return 0;
- }
+ verify_data *data = userdata;
+ const char *msg;
+ const char *result = NULL;
+ /* see https://github.com/systemd/systemd/issues/14643 */
+ uint64_t done = false;
+ int r;
+
+ if (!sd_bus_message_is_signal (m, "net.reactivated.Fprint.Device", "VerifyStatus"))
+ {
+ pam_syslog (data->pamh, LOG_ERR, "Not the signal we expected (iface: %s, member: %s)",
+ sd_bus_message_get_interface (m),
+ sd_bus_message_get_member (m));
+ return 0;
+ }
+
+ if ((r = sd_bus_message_read (m, "sb", &result, &done)) < 0)
+ {
+ pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyResult signal: %d", r);
+ data->verify_ret = PAM_AUTHINFO_UNAVAIL;
+ return 0;
+ }
+
+ if (!data->verify_started)
+ {
+ pam_syslog (data->pamh, LOG_ERR, "Unexpected VerifyResult '%s', %" PRIu64 " signal", result, done);
+ return 0;
+ }
+
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "Verify result: %s (done: %d)", result, done ? 1 : 0);
+
+ if (data->result)
+ {
+ free (data->result);
+ data->result = NULL;
+ }
+
+ if (done && result)
+ {
+ data->result = strdup (result);
+ return 0;
+ }
+
+ msg = verify_result_str_to_msg (result, data->is_swipe);
+ if (!msg)
+ {
+ data->result = strdup ("Protocol error with fprintd!");
+ return 0;
+ }
+ send_err_msg (data->pamh, msg);
- msg = _(verify_result_str_to_msg (result, data->is_swipe));
- send_err_msg (data->pamh, msg);
-
- return 0;
+ return 0;
}
static int
verify_finger_selected (sd_bus_message *m,
- void *userdata,
- sd_bus_error *ret_error)
+ void *userdata,
+ sd_bus_error *ret_error)
{
- verify_data *data = userdata;
- const char *finger_name = NULL;
- char *msg;
-
- if (sd_bus_message_read_basic (m, 's', &finger_name) < 0) {
- pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyFingerSelected signal: %m");
- return 0;
- }
-
- msg = finger_str_to_msg(finger_name, data->driver, data->is_swipe);
- if (debug)
- pam_syslog (data->pamh, LOG_DEBUG, "verify_finger_selected %s", msg);
- send_info_msg (data->pamh, msg);
- free (msg);
+ verify_data *data = userdata;
+ const char *finger_name = NULL;
+ pf_autofree char *msg = NULL;
+
+ if (sd_bus_message_read_basic (m, 's', &finger_name) < 0)
+ {
+ pam_syslog (data->pamh, LOG_ERR, "Failed to parse VerifyFingerSelected signal: %d", errno);
+ data->verify_ret = PAM_AUTHINFO_UNAVAIL;
+ return 0;
+ }
+
+ if (!data->verify_started)
+ {
+ pam_syslog (data->pamh, LOG_ERR, "Unexpected VerifyFingerSelected %s signal", finger_name);
+ return 0;
+ }
+
+ msg = finger_str_to_msg (finger_name, data->driver, data->is_swipe);
+ if (!msg)
+ {
+ data->result = strdup ("Protocol error with fprintd!");
+ return 0;
+ }
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "verify_finger_selected %s", msg);
+ send_info_msg (data->pamh, msg);
- return 0;
+ return 0;
}
/* See https://github.com/systemd/systemd/issues/14636 */
static int
-get_property_string (sd_bus *bus,
- const char *destination,
- const char *path,
- const char *interface,
- const char *member,
- sd_bus_error *error,
- char **ret) {
-
- sd_bus_message *reply = NULL;
- const char *s;
- char *n;
- int r;
-
- r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", interface, member);
- if (r < 0)
- return r;
-
- r = sd_bus_message_enter_container(reply, 'v', "s");
- if (r < 0)
- goto fail;
-
- r = sd_bus_message_read_basic(reply, 's', &s);
- if (r < 0)
- goto fail;
-
- n = strdup(s);
- if (!n) {
- r = -ENOMEM;
- goto fail;
- }
-
- sd_bus_message_unref (reply);
-
- *ret = n;
- return 0;
-
-fail:
- if (reply != NULL)
- sd_bus_message_unref (reply);
- return sd_bus_error_set_errno(error, r);
+get_property_string (sd_bus *bus,
+ const char *destination,
+ const char *path,
+ const char *interface,
+ const char *member,
+ sd_bus_error *error,
+ char **ret)
+{
+
+ pf_autoptr (sd_bus_message) reply = NULL;
+ const char *s;
+ char *n;
+ int r;
+
+ r = sd_bus_call_method (bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", interface, member);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_enter_container (reply, 'v', "s");
+ if (r < 0)
+ return sd_bus_error_set_errno (error, r);
+
+ r = sd_bus_message_read_basic (reply, 's', &s);
+ if (r < 0)
+ return sd_bus_error_set_errno (error, r);
+
+ n = strdup (s);
+ if (!n)
+ return sd_bus_error_set_errno (error, -ENOMEM);
+
+ *ret = n;
+ return 0;
}
+
static int
-do_verify (pam_handle_t *pamh,
- sd_bus *bus,
- const char *dev,
- bool has_multiple_devices)
-{
- verify_data *data;
- sd_bus_slot *verify_status_slot, *verify_finger_selected_slot;
- char *scan_type = NULL;
- int ret;
- int r;
-
- data = calloc (1, sizeof(verify_data));
- data->max_tries = max_tries;
- data->pamh = pamh;
-
- /* Get some properties for the device */
- r = get_property_string (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "scan-type",
- NULL,
- &scan_type);
- if (r < 0)
- pam_syslog (data->pamh, LOG_ERR, "Failed to get scan-type for %s: %d", dev, r);
- if (debug)
- pam_syslog (data->pamh, LOG_DEBUG, "scan-type for %s: %s", dev, scan_type);
- if (str_equal (scan_type, "swipe"))
- data->is_swipe = true;
- free (scan_type);
-
- if (has_multiple_devices) {
- get_property_string (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "name",
- NULL,
- &data->driver);
- if (r < 0)
- pam_syslog (data->pamh, LOG_ERR, "Failed to get driver name for %s: %d", dev, r);
- if (debug && r == 0)
- pam_syslog (data->pamh, LOG_DEBUG, "driver name for %s: %s", dev, data->driver);
- }
-
- verify_status_slot = NULL;
- sd_bus_match_signal (bus,
- &verify_status_slot,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "VerifyStatus",
- verify_result,
- data);
-
- verify_finger_selected_slot = NULL;
- sd_bus_match_signal (bus,
- &verify_finger_selected_slot,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "VerifyFingerSelected",
- verify_finger_selected,
- data);
-
- ret = PAM_AUTH_ERR;
-
- while (ret == PAM_AUTH_ERR && data->max_tries > 0) {
- uint64_t verification_end = now () + (timeout * USEC_PER_SEC);
- sd_bus_message *m = NULL;
- sd_bus_error error = SD_BUS_ERROR_NULL;
-
- data->timed_out = false;
-
- r = sd_bus_call_method (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "VerifyStart",
- &error,
- &m,
- "s",
- "any");
-
- if (r < 0) {
- if (sd_bus_error_has_name (&error, "net.reactivated.Fprint.Error.NoEnrolledPrints"))
- ret = PAM_USER_UNKNOWN;
-
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "VerifyStart failed: %s", error.message);
- sd_bus_error_free (&error);
- break;
- }
-
- for (;;) {
- int64_t wait_time;
-
- wait_time = verification_end - now();
- if (wait_time <= 0)
- break;
-
- r = sd_bus_process (bus, NULL);
- if (r < 0)
- break;
- if (data->result != NULL)
- break;
- if (r == 0) {
- if (debug) {
- pam_syslog(pamh, LOG_DEBUG, "Waiting for %"PRId64" seconds (%"PRId64" usecs)",
- wait_time / USEC_PER_SEC,
- wait_time);
- }
- r = sd_bus_wait (bus, wait_time);
- if (r < 0)
- break;
- }
- }
-
- if (now () >= verification_end) {
- data->timed_out = true;
- send_info_msg (data->pamh, _("Verification timed out"));
- }
-
- /* Ignore errors from VerifyStop */
- sd_bus_call_method (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "VerifyStop",
- NULL,
- NULL,
- NULL,
- NULL);
-
- if (data->timed_out) {
- ret = PAM_AUTHINFO_UNAVAIL;
- break;
- } else {
- if (str_equal (data->result, "verify-no-match")) {
- send_err_msg (data->pamh, "Failed to match fingerprint");
- ret = PAM_AUTH_ERR;
- } else if (str_equal (data->result, "verify-match")) {
- ret = PAM_SUCCESS;
- break;
- } else if (str_equal (data->result, "verify-unknown-error")) {
- ret = PAM_AUTHINFO_UNAVAIL;
- } else if (str_equal (data->result, "verify-disconnected")) {
- ret = PAM_AUTHINFO_UNAVAIL;
- free (data->result);
- break;
- } else {
- send_info_msg (data->pamh, _("An unknown error occurred"));
- ret = PAM_AUTH_ERR;
- free (data->result);
- break;
- }
- free (data->result);
- data->result = NULL;
- }
- data->max_tries--;
- }
-
- if (data->max_tries == 0)
- ret = PAM_MAXTRIES;
-
- sd_bus_slot_unref (verify_status_slot);
- sd_bus_slot_unref (verify_finger_selected_slot);
-
- if (data->result)
- free (data->result);
- free (data->driver);
- free (data);
+verify_started_cb (sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error)
+{
+ const sd_bus_error *error = sd_bus_message_get_error (m);
+ verify_data *data = userdata;
+
+ if (error)
+ {
+ if (sd_bus_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints"))
+ {
+ pam_syslog (data->pamh, LOG_DEBUG, "No prints enrolled");
+ data->verify_ret = PAM_USER_UNKNOWN;
+ }
+ else
+ {
+ data->verify_ret = PAM_AUTH_ERR;
+ }
+
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart failed: %s", error->message);
+
+ return 1;
+ }
+
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart completed successfully");
- return ret;
+ data->verify_started = true;
+
+ return 1;
}
-static bool
-user_has_prints (pam_handle_t *pamh,
- sd_bus *bus,
- const char *dev,
- const char *username)
-{
- sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *m = NULL;
- size_t num_fingers = 0;
- const char *s;
- int r;
-
- r = sd_bus_call_method (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "ListEnrolledFingers",
- &error,
- &m,
- "s",
- username);
- if (r < 0) {
- /* If ListEnrolledFingers fails then verification should
- * also fail (both use the same underlying call), so we
- * report false here and bail out early. */
- if (debug) {
- pam_syslog (pamh, LOG_DEBUG, "ListEnrolledFingers failed for %s: %s",
- username, error.message);
- }
- sd_bus_error_free (&error);
- return false;
- }
-
- r = sd_bus_message_enter_container (m, 'a', "s");
- if (r < 0) {
- pam_syslog (pamh, LOG_ERR, "Failed to parse answer from ListEnrolledFingers(): %d", r);
- goto out;
- }
-
- num_fingers = 0;
- while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0)
- num_fingers++;
- sd_bus_message_exit_container (m);
-
-out:
- sd_bus_message_unref (m);
- return (num_fingers > 0);
+static int
+do_verify (sd_bus *bus,
+ verify_data *data)
+{
+ pf_autoptr (sd_bus_slot) verify_status_slot = NULL;
+ pf_autoptr (sd_bus_slot) verify_finger_selected_slot = NULL;
+ pf_autofree char *scan_type = NULL;
+ int r;
+
+ /* Get some properties for the device */
+ r = get_property_string (bus,
+ "net.reactivated.Fprint",
+ data->dev,
+ "net.reactivated.Fprint.Device",
+ "scan-type",
+ NULL,
+ &scan_type);
+ if (r < 0)
+ pam_syslog (data->pamh, LOG_ERR, "Failed to get scan-type for %s: %d", data->dev, r);
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "scan-type for %s: %s", data->dev, scan_type);
+ if (str_equal (scan_type, "swipe"))
+ data->is_swipe = true;
+
+ if (data->has_multiple_devices)
+ {
+ get_property_string (bus,
+ "net.reactivated.Fprint",
+ data->dev,
+ "net.reactivated.Fprint.Device",
+ "name",
+ NULL,
+ &data->driver);
+ if (r < 0)
+ pam_syslog (data->pamh, LOG_ERR, "Failed to get driver name for %s: %d", data->dev, r);
+ if (debug && r == 0)
+ pam_syslog (data->pamh, LOG_DEBUG, "driver name for %s: %s", data->dev, data->driver);
+ }
+
+ sd_bus_match_signal (bus,
+ &verify_status_slot,
+ "net.reactivated.Fprint",
+ data->dev,
+ "net.reactivated.Fprint.Device",
+ "VerifyStatus",
+ verify_result,
+ data);
+
+ sd_bus_match_signal (bus,
+ &verify_finger_selected_slot,
+ "net.reactivated.Fprint",
+ data->dev,
+ "net.reactivated.Fprint.Device",
+ "VerifyFingerSelected",
+ verify_finger_selected,
+ data);
+
+ while (data->max_tries > 0)
+ {
+ uint64_t verification_end = now () + (timeout * USEC_PER_SEC);
+
+ data->timed_out = false;
+ data->verify_started = false;
+ data->verify_ret = PAM_INCOMPLETE;
+
+ free (data->result);
+ data->result = NULL;
+
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "About to call VerifyStart");
+
+ r = sd_bus_call_method_async (bus,
+ NULL,
+ "net.reactivated.Fprint",
+ data->dev,
+ "net.reactivated.Fprint.Device",
+ "VerifyStart",
+ verify_started_cb,
+ data,
+ "s",
+ "any");
+
+ if (r < 0)
+ {
+ if (debug)
+ pam_syslog (data->pamh, LOG_DEBUG, "VerifyStart call failed: %d", r);
+ break;
+ }
+
+ for (;;)
+ {
+ int64_t wait_time;
+
+ wait_time = verification_end - now ();
+ if (wait_time <= 0)
+ break;
+
+ r = sd_bus_process (bus, NULL);
+ if (r < 0)
+ break;
+ if (data->verify_ret != PAM_INCOMPLETE)
+ break;
+ if (!data->verify_started)
+ continue;
+ if (data->result != NULL)
+ break;
+ if (r == 0)
+ {
+ if (debug)
+ {
+ pam_syslog (data->pamh, LOG_DEBUG,
+ "Waiting for %" PRId64 " seconds (%" PRId64 " usecs)",
+ wait_time / USEC_PER_SEC,
+ wait_time);
+ }
+ if (sd_bus_wait (bus, wait_time) < 0)
+ break;
+ }
+ }
+
+ if (data->verify_ret != PAM_INCOMPLETE)
+ return data->verify_ret;
+
+ if (now () >= verification_end)
+ {
+ data->timed_out = true;
+ send_info_msg (data->pamh, _("Verification timed out"));
+ }
+
+ /* Ignore errors from VerifyStop */
+ data->verify_started = false;
+ sd_bus_call_method (bus,
+ "net.reactivated.Fprint",
+ data->dev,
+ "net.reactivated.Fprint.Device",
+ "VerifyStop",
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (data->timed_out)
+ {
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ else
+ {
+ if (str_equal (data->result, "verify-no-match"))
+ {
+ send_err_msg (data->pamh, "Failed to match fingerprint");
+ }
+ else if (str_equal (data->result, "verify-match"))
+ {
+ return PAM_SUCCESS;
+ }
+ else if (str_equal (data->result, "verify-unknown-error"))
+ {
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ else if (str_equal (data->result, "verify-disconnected"))
+ {
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+ else
+ {
+ send_err_msg (data->pamh, _("An unknown error occurred"));
+ return PAM_AUTH_ERR;
+ }
+ }
+ data->max_tries--;
+ }
+
+ if (data->max_tries == 0)
+ return PAM_MAXTRIES;
+
+ return PAM_AUTH_ERR;
+}
+
+static size_t
+user_enrolled_prints_num (pam_handle_t *pamh,
+ sd_bus *bus,
+ const char *dev,
+ const char *username)
+{
+ pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
+ pf_autoptr (sd_bus_message) m = NULL;
+ size_t num_fingers = 0;
+ const char *s;
+ int r;
+
+ r = sd_bus_call_method (bus,
+ "net.reactivated.Fprint",
+ dev,
+ "net.reactivated.Fprint.Device",
+ "ListEnrolledFingers",
+ &error,
+ &m,
+ "s",
+ username);
+ if (r < 0)
+ {
+ /* If ListEnrolledFingers fails then verification should
+ * also fail (both use the same underlying call), so we
+ * report false here and bail out early. */
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "ListEnrolledFingers failed for %s: %s",
+ username, error.message);
+ return 0;
+ }
+
+ r = sd_bus_message_enter_container (m, 'a', "s");
+ if (r < 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "Failed to parse answer from ListEnrolledFingers(): %d", r);
+ return 0;
+ }
+
+ while ((r = sd_bus_message_read_basic (m, 's', &s)) > 0)
+ num_fingers++;
+ sd_bus_message_exit_container (m);
+
+ return num_fingers;
}
static void
release_device (pam_handle_t *pamh,
- sd_bus *bus,
- const char *dev)
+ sd_bus *bus,
+ const char *dev)
{
- sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
+ pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
- r = sd_bus_call_method (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "Release",
- &error,
- NULL,
- NULL,
- NULL);
- if (r < 0) {
- pam_syslog (pamh, LOG_ERR, "ReleaseDevice failed: %s", error.message);
- sd_bus_error_free (&error);
- }
+ if (sd_bus_call_method (bus,
+ "net.reactivated.Fprint",
+ dev,
+ "net.reactivated.Fprint.Device",
+ "Release",
+ &error,
+ NULL,
+ NULL,
+ NULL) < 0)
+ pam_syslog (pamh, LOG_ERR, "ReleaseDevice failed: %s", error.message);
}
static bool
claim_device (pam_handle_t *pamh,
- sd_bus *bus,
- const char *dev,
- const char *username)
-{
- sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- r = sd_bus_call_method (bus,
- "net.reactivated.Fprint",
- dev,
- "net.reactivated.Fprint.Device",
- "Claim",
- &error,
- NULL,
- "s",
- username);
- if (r < 0) {
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "failed to claim device %s", error.message);
- sd_bus_error_free (&error);
- return false;
- }
-
- return true;
-}
-
-static int do_auth(pam_handle_t *pamh, const char *username)
-{
- char *dev;
- bool have_prints;
- bool has_multiple_devices;
- int ret = PAM_AUTHINFO_UNAVAIL;
- sd_bus *bus = NULL;
-
- if (sd_bus_open_system (&bus) < 0) {
- pam_syslog (pamh, LOG_ERR, "Error with getting the bus: %m");
- return PAM_AUTHINFO_UNAVAIL;
- }
-
- dev = open_device (pamh, bus, &has_multiple_devices);
- if (dev == NULL) {
- sd_bus_unref (bus);
- return PAM_AUTHINFO_UNAVAIL;
- }
-
- have_prints = user_has_prints (pamh, bus, dev, username);
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "prints registered: %s\n", have_prints ? "yes" : "no");
-
- if (!have_prints)
- goto out;
-
- if (claim_device (pamh, bus, dev, username)) {
- ret = do_verify (pamh, bus, dev, has_multiple_devices);
- release_device (pamh, bus, dev);
- }
-
-out:
- free (dev);
- sd_bus_unref (bus);
+ sd_bus *bus,
+ const char *dev,
+ const char *username)
+{
+ pf_auto (sd_bus_error) error = SD_BUS_ERROR_NULL;
+
+ if (sd_bus_call_method (bus,
+ "net.reactivated.Fprint",
+ dev,
+ "net.reactivated.Fprint.Device",
+ "Claim",
+ &error,
+ NULL,
+ "s",
+ username) < 0)
+ {
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "failed to claim device %s", error.message);
+ return false;
+ }
- return ret;
+ return true;
}
-static bool
-is_remote (pam_handle_t *pamh)
-{
- const char *rhost = NULL;
+static int
+name_owner_changed (sd_bus_message *m,
+ void *userdata,
+ sd_bus_error *ret_error)
+{
+ verify_data *data = userdata;
+ const char *name = NULL;
+ const char *old_owner = NULL;
+ const char *new_owner = NULL;
+
+ if (sd_bus_message_read (m, "sss", &name, &old_owner, &new_owner) < 0)
+ {
+ pam_syslog (data->pamh, LOG_ERR, "Failed to parse NameOwnerChanged signal: %d", errno);
+ data->verify_ret = PAM_AUTHINFO_UNAVAIL;
+ return 0;
+ }
+
+ if (strcmp (name, "net.reactivated.Fprint") != 0)
+ return 0;
+
+ /* Name owner for fprintd changed, give up as we might start listening
+ * to events from a new name owner otherwise. */
+ data->verify_ret = PAM_AUTHINFO_UNAVAIL;
- pam_get_item(pamh, PAM_RHOST, (const void **)(const void*) &rhost);
+ pam_syslog (data->pamh, LOG_WARNING, "fprintd name owner changed during operation!");
- /* NULL or empty rhost if the host information is not available or set.
- * "localhost" if the host is local.
- * We want to not run for known remote hosts */
- if (rhost != NULL &&
- *rhost != '\0' &&
- strcmp (rhost, "localhost") != 0) {
- return true;
- }
-
- if (sd_session_is_remote (NULL) > 0)
- return true;
-
- return false;
-}
-
-PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
- const char **argv)
-{
- const char *username;
- unsigned i;
- int r;
-
- bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-
- if (is_remote (pamh))
- return PAM_AUTHINFO_UNAVAIL;
-
- r = pam_get_user(pamh, &username, NULL);
- if (r != PAM_SUCCESS)
- return PAM_AUTHINFO_UNAVAIL;
-
- for (i = 0; i < argc; i++) {
- if (argv[i] != NULL) {
- if (str_equal (argv[i], "debug")) {
- pam_syslog (pamh, LOG_DEBUG, "debug on");
- debug = true;
- } else if (str_has_prefix (argv[i], DEBUG_MATCH)) {
- pam_syslog (pamh, LOG_DEBUG, "debug on");
- const char *value;
-
- value = argv[i] + strlen (DEBUG_MATCH);
- if (str_equal (value, "on") ||
- str_equal (value, "true") ||
- str_equal (value, "1")) {
- pam_syslog (pamh, LOG_DEBUG, "debug on");
- debug = true;
- } else if (str_equal (value, "off") ||
- str_equal (value, "false") ||
- str_equal (value, "0")) {
- debug = false;
- } else {
- pam_syslog (pamh, LOG_DEBUG, "invalid debug value '%s', disabling", value);
- }
- } else if (str_has_prefix (argv[i], MAX_TRIES_MATCH) && strlen(argv[i]) == strlen (MAX_TRIES_MATCH) + 1) {
- max_tries = atoi (argv[i] + strlen (MAX_TRIES_MATCH));
- if (max_tries < 1) {
- if (debug) {
- pam_syslog (pamh, LOG_DEBUG, "invalid max tries '%s', using %d",
- argv[i] + strlen (MAX_TRIES_MATCH), DEFAULT_MAX_TRIES);
- }
- max_tries = DEFAULT_MAX_TRIES;
- }
- if (debug)
- pam_syslog (pamh, LOG_DEBUG, "max_tries specified as: %d", max_tries);
- } else if (str_has_prefix (argv[i], TIMEOUT_MATCH) && strlen(argv[i]) <= strlen (TIMEOUT_MATCH) + 2) {
- timeout = atoi (argv[i] + strlen (TIMEOUT_MATCH));
- if (timeout < MIN_TIMEOUT) {
- if (debug) {
- pam_syslog (pamh, LOG_DEBUG, "timeout %d secs too low, using %d",
- timeout, MIN_TIMEOUT);
- }
- timeout = MIN_TIMEOUT;
- } else if (debug) {
- pam_syslog (pamh, LOG_DEBUG, "timeout specified as: %d secs", timeout);
- }
- }
- }
- }
-
- r = do_auth(pamh, username);
-
- return r;
-}
-
-PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
- const char **argv)
-{
- return PAM_SUCCESS;
+ return 0;
}
-PAM_EXTERN int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
- const char **argv)
+static int
+do_auth (pam_handle_t *pamh, const char *username)
{
- return PAM_SUCCESS;
+ pf_autoptr (verify_data) data = NULL;
+ pf_autoptr (sd_bus) bus = NULL;
+ pf_autoptr (sd_bus_slot) name_owner_changed_slot = NULL;
+
+ data = calloc (1, sizeof (verify_data));
+ data->max_tries = max_tries;
+ data->pamh = pamh;
+
+ if (sd_bus_open_system (&bus) < 0)
+ {
+ pam_syslog (pamh, LOG_ERR, "Error with getting the bus: %d", errno);
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ data->dev = open_device (pamh, bus, username, &data->has_multiple_devices);
+ if (data->dev == NULL)
+ return PAM_AUTHINFO_UNAVAIL;
+
+ /* Only connect to NameOwnerChanged when needed. In case of automatic startup
+ * we rely on the fact that we never see those signals.
+ */
+ name_owner_changed_slot = NULL;
+ sd_bus_match_signal (bus,
+ &name_owner_changed_slot,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameOwnerChanged",
+ name_owner_changed,
+ data);
+
+ if (claim_device (pamh, bus, data->dev, username))
+ {
+ int ret = do_verify (bus, data);
+ release_device (pamh, bus, data->dev);
+ return ret;
+ }
+
+ return PAM_AUTHINFO_UNAVAIL;
}
+static bool
+is_remote (pam_handle_t *pamh)
+{
+ const char *rhost = NULL;
+
+ pam_get_item (pamh, PAM_RHOST, (const void **) (const void *) &rhost);
+
+ /* NULL or empty rhost if the host information is not available or set.
+ * "localhost" if the host is local.
+ * We want to not run for known remote hosts */
+ if (rhost != NULL &&
+ *rhost != '\0' &&
+ strcmp (rhost, "localhost") != 0)
+ return true;
+
+ if (sd_session_is_remote (NULL) > 0)
+ return true;
+
+ return false;
+}
+
+PAM_EXTERN int
+pam_sm_authenticate (pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ const char *username;
+ int i;
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+
+ if (is_remote (pamh))
+ return PAM_AUTHINFO_UNAVAIL;
+
+ if (pam_get_user (pamh, &username, NULL) != PAM_SUCCESS)
+ return PAM_AUTHINFO_UNAVAIL;
+
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i] != NULL)
+ {
+ if (str_equal (argv[i], "debug"))
+ {
+ pam_syslog (pamh, LOG_DEBUG, "debug on");
+ debug = true;
+ }
+ else if (str_has_prefix (argv[i], DEBUG_MATCH))
+ {
+ pam_syslog (pamh, LOG_DEBUG, "debug on");
+ const char *value;
+
+ value = argv[i] + strlen (DEBUG_MATCH);
+ if (str_equal (value, "on") ||
+ str_equal (value, "true") ||
+ str_equal (value, "1"))
+ {
+ pam_syslog (pamh, LOG_DEBUG, "debug on");
+ debug = true;
+ }
+ else if (str_equal (value, "off") ||
+ str_equal (value, "false") ||
+ str_equal (value, "0"))
+ {
+ debug = false;
+ }
+ else
+ {
+ pam_syslog (pamh, LOG_DEBUG, "invalid debug value '%s', disabling", value);
+ }
+ }
+ else if (str_has_prefix (argv[i], MAX_TRIES_MATCH) && strlen (argv[i]) == strlen (MAX_TRIES_MATCH) + 1)
+ {
+ max_tries = atoi (argv[i] + strlen (MAX_TRIES_MATCH));
+ if (max_tries < 1)
+ {
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "invalid max tries '%s', using %d",
+ argv[i] + strlen (MAX_TRIES_MATCH), DEFAULT_MAX_TRIES);
+ max_tries = DEFAULT_MAX_TRIES;
+ }
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "max_tries specified as: %d", max_tries);
+ }
+ else if (str_has_prefix (argv[i], TIMEOUT_MATCH) && strlen (argv[i]) <= strlen (TIMEOUT_MATCH) + 2)
+ {
+ timeout = atoi (argv[i] + strlen (TIMEOUT_MATCH));
+ if (timeout < MIN_TIMEOUT)
+ {
+ if (debug)
+ pam_syslog (pamh, LOG_DEBUG, "timeout %d secs too low, using %d",
+ timeout, MIN_TIMEOUT);
+ timeout = MIN_TIMEOUT;
+ }
+ else if (debug)
+ {
+ pam_syslog (pamh, LOG_DEBUG, "timeout specified as: %d secs", timeout);
+ }
+ }
+ }
+ }
+
+ return do_auth (pamh, username);
+}
+
+PAM_EXTERN int
+pam_sm_setcred (pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return PAM_SUCCESS;
+}
+
+PAM_EXTERN int
+pam_sm_chauthtok (pam_handle_t *pamh, int flags, int argc,
+ const char **argv)
+{
+ return PAM_SUCCESS;
+}
diff -Nru fprintd-1.90.1/scripts/uncrustify.cfg fprintd-1.90.9/scripts/uncrustify.cfg
--- fprintd-1.90.1/scripts/uncrustify.cfg 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/scripts/uncrustify.cfg 2021-01-13 12:23:24.000000000 +0000
@@ -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
+
diff -Nru fprintd-1.90.1/scripts/uncrustify.sh fprintd-1.90.9/scripts/uncrustify.sh
--- fprintd-1.90.1/scripts/uncrustify.sh 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/scripts/uncrustify.sh 2021-01-13 12:23:24.000000000 +0000
@@ -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
diff -Nru fprintd-1.90.1/src/dbus-interactive-auth.patch fprintd-1.90.9/src/dbus-interactive-auth.patch
--- fprintd-1.90.1/src/dbus-interactive-auth.patch 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/src/dbus-interactive-auth.patch 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,110 @@
+--- a/src/fprintd-dbus.c 2020-12-04 16:38:28.527712626 +0100
++++ b/src/fprintd-dbus.c 2020-12-04 16:40:03.561692619 +0100
+@@ -1149,7 +1149,7 @@
+ "ListEnrolledFingers",
+ g_variant_new ("(s)",
+ arg_username),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ callback,
+@@ -1213,7 +1213,7 @@
+ "ListEnrolledFingers",
+ g_variant_new ("(s)",
+ arg_username),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ error);
+@@ -1253,7 +1253,7 @@
+ "DeleteEnrolledFingers",
+ g_variant_new ("(s)",
+ arg_username),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ callback,
+@@ -1312,7 +1312,7 @@
+ "DeleteEnrolledFingers",
+ g_variant_new ("(s)",
+ arg_username),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ error);
+@@ -1348,7 +1348,7 @@
+ g_dbus_proxy_call (G_DBUS_PROXY (proxy),
+ "DeleteEnrolledFingers2",
+ g_variant_new ("()"),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ callback,
+@@ -1404,7 +1404,7 @@
+ _ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
+ "DeleteEnrolledFingers2",
+ g_variant_new ("()"),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ error);
+@@ -1443,7 +1443,7 @@
+ "Claim",
+ g_variant_new ("(s)",
+ arg_username),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ callback,
+@@ -1502,7 +1502,7 @@
+ "Claim",
+ g_variant_new ("(s)",
+ arg_username),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ error);
+@@ -1633,7 +1633,7 @@
+ "VerifyStart",
+ g_variant_new ("(s)",
+ arg_finger_name),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ callback,
+@@ -1692,7 +1692,7 @@
+ "VerifyStart",
+ g_variant_new ("(s)",
+ arg_finger_name),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ error);
+@@ -1823,7 +1823,7 @@
+ "EnrollStart",
+ g_variant_new ("(s)",
+ arg_finger_name),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ callback,
+@@ -1882,7 +1882,7 @@
+ "EnrollStart",
+ g_variant_new ("(s)",
+ arg_finger_name),
+- G_DBUS_CALL_FLAGS_NONE,
++ G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION,
+ -1,
+ cancellable,
+ error);
diff -Nru fprintd-1.90.1/src/device.c fprintd-1.90.9/src/device.c
--- fprintd-1.90.1/src/device.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/device.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* /net/reactivated/Fprint/Device/foo object implementation
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -19,8 +20,6 @@
#include "config.h"
-#include
-#include
#include
#include
#include
@@ -30,1401 +29,1996 @@
#include
#include
-#include "fprintd-marshal.h"
#include "fprintd.h"
#include "storage.h"
static const char *FINGERS_NAMES[] = {
- [FP_FINGER_UNKNOWN] = "unknown",
- "left-thumb",
- "left-index-finger",
- "left-middle-finger",
- "left-ring-finger",
- "left-little-finger",
- "right-thumb",
- "right-index-finger",
- "right-middle-finger",
- "right-ring-finger",
- "right-little-finger"
+ [FP_FINGER_UNKNOWN] = "unknown",
+ [FP_FINGER_LEFT_THUMB] = "left-thumb",
+ [FP_FINGER_LEFT_INDEX] = "left-index-finger",
+ [FP_FINGER_LEFT_MIDDLE] = "left-middle-finger",
+ [FP_FINGER_LEFT_RING] = "left-ring-finger",
+ [FP_FINGER_LEFT_LITTLE] = "left-little-finger",
+ [FP_FINGER_RIGHT_THUMB] = "right-thumb",
+ [FP_FINGER_RIGHT_INDEX] = "right-index-finger",
+ [FP_FINGER_RIGHT_MIDDLE] = "right-middle-finger",
+ [FP_FINGER_RIGHT_RING] = "right-ring-finger",
+ [FP_FINGER_RIGHT_LITTLE] = "right-little-finger"
};
-extern DBusGConnection *fprintd_dbus_conn;
+static void fprint_device_dbus_skeleton_iface_init (FprintDBusDeviceIface *);
+static gboolean action_authorization_handler (GDBusInterfaceSkeleton *,
+ GDBusMethodInvocation *,
+ gpointer user_data);
-static void fprint_device_claim(FprintDevice *rdev,
- const char *username,
- DBusGMethodInvocation *context);
-static void fprint_device_release(FprintDevice *rdev,
- DBusGMethodInvocation *context);
-static void fprint_device_verify_start(FprintDevice *rdev,
- const char *finger_name, DBusGMethodInvocation *context);
-static void fprint_device_verify_stop(FprintDevice *rdev,
- DBusGMethodInvocation *context);
-static void fprint_device_enroll_start(FprintDevice *rdev,
- const char *finger_name, DBusGMethodInvocation *context);
-static void fprint_device_enroll_stop(FprintDevice *rdev,
- DBusGMethodInvocation *context);
-static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
- const char *username,
- DBusGMethodInvocation *context);
-static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
- const char *username,
- DBusGMethodInvocation *context);
-static void fprint_device_delete_enrolled_fingers2(FprintDevice *rdev,
- DBusGMethodInvocation *context);
-
-#include "device-dbus-glue.h"
+static GQuark quark_auth_user = 0;
typedef enum {
- ACTION_NONE = 0,
- ACTION_IDENTIFY,
- ACTION_VERIFY,
- ACTION_ENROLL
+ ACTION_NONE = 0,
+ ACTION_IDENTIFY,
+ ACTION_VERIFY,
+ ACTION_ENROLL,
+ ACTION_OPEN,
+ ACTION_CLOSE,
+ ACTION_DELETE,
} FprintDeviceAction;
-typedef struct {
- /* current method invocation */
- DBusGMethodInvocation *context;
-
- /* The current user of the device, if claimed */
- char *sender;
-
- /* The current user of the device, or if allowed,
- * what was passed as a username argument */
- char *username;
+typedef enum {
+ STATE_CLAIMED,
+ STATE_UNCLAIMED,
+ STATE_AUTO_CLAIM,
+ STATE_ANYTIME,
+} FprintDeviceClaimState;
+
+typedef struct
+{
+ volatile gint _refcount;
+
+ /* current method invocation */
+ GDBusMethodInvocation *invocation;
+
+ /* The current user of the device, if claimed */
+ const char * const sender;
+
+ /* The current user of the device, or if allowed,
+ * what was passed as a username argument */
+ const char * const username;
+
+ gboolean verify_status_reported;
} SessionData;
-typedef struct {
- guint32 id;
- FpDevice *dev;
- SessionData *session;
-
- PolkitAuthority *auth;
-
- /* Hashtable of connected clients */
- GHashTable *clients;
-
- /* Required to restart the operation on a retry failure. */
- FpPrint *verify_data;
- GPtrArray *identify_data;
- int enroll_data;
-
- /* whether we're running an identify, or a verify */
- FprintDeviceAction current_action;
- GCancellable *current_cancellable;
- DBusGMethodInvocation *current_cancel_context;
- /* Whether the device was disconnected */
- gboolean disconnected;
+typedef struct
+{
+ guint32 id;
+ FpDevice *dev;
+ SessionData *_session;
+
+ PolkitAuthority *auth;
+
+ /* Hashtable of connected clients */
+ GHashTable *clients;
+
+ /* Required to restart the operation on a retry failure. */
+ FpPrint *verify_data;
+ GPtrArray *identify_data;
+ int enroll_data;
+
+ /* whether we're running an identify, or a verify */
+ FprintDeviceAction current_action;
+ GCancellable *current_cancellable;
+ GDBusMethodInvocation *current_cancel_invocation;
} FprintDevicePrivate;
-G_DEFINE_TYPE_WITH_CODE(FprintDevice, fprint_device, G_TYPE_OBJECT, G_ADD_PRIVATE (FprintDevice));
+G_DEFINE_TYPE_WITH_CODE (FprintDevice, fprint_device,
+ FPRINT_DBUS_TYPE_DEVICE_SKELETON,
+ G_ADD_PRIVATE (FprintDevice)
+ G_IMPLEMENT_INTERFACE (FPRINT_DBUS_TYPE_DEVICE,
+ fprint_device_dbus_skeleton_iface_init));
enum fprint_device_properties {
- FPRINT_DEVICE_CONSTRUCT_DEV = 1,
- FPRINT_DEVICE_IN_USE,
- FPRINT_DEVICE_NAME,
- FPRINT_DEVICE_NUM_ENROLL,
- FPRINT_DEVICE_SCAN_TYPE
+ FPRINT_DEVICE_CONSTRUCT_DEV = 1,
+ FPRINT_DEVICE_IN_USE,
+ FPRINT_DEVICE_NAME,
+ FPRINT_DEVICE_NUM_ENROLL,
+ FPRINT_DEVICE_SCAN_TYPE
};
enum fprint_device_signals {
- SIGNAL_VERIFY_STATUS,
- SIGNAL_VERIFY_FINGER_SELECTED,
- SIGNAL_ENROLL_STATUS,
- NUM_SIGNALS,
+ SIGNAL_VERIFY_STATUS,
+ SIGNAL_VERIFY_FINGER_SELECTED,
+ SIGNAL_ENROLL_STATUS,
+ NUM_SIGNALS,
};
static guint32 last_id = ~0;
static guint signals[NUM_SIGNALS] = { 0, };
-static void session_data_free(SessionData *session)
+#ifndef POLKIT_HAS_AUTOPOINTERS
+/* FIXME: Remove this once we're fine to depend on polkit 0.114 */
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (PolkitAuthorizationResult, g_object_unref)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (PolkitSubject, g_object_unref)
+#endif
+
+static void
+session_data_unref (SessionData *session)
+{
+ if (g_atomic_int_dec_and_test (&session->_refcount))
+ {
+ g_clear_pointer ((char **) &session->sender, g_free);
+ g_clear_pointer ((char **) &session->username, g_free);
+ g_clear_object (&session->invocation);
+ g_free (session);
+ }
+}
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (SessionData, session_data_unref);
+
+static SessionData *
+session_data_get (FprintDevicePrivate *priv)
+{
+ SessionData *invalid = (SessionData *) &priv->_session;
+ SessionData *cur;
+
+ /* Get the current pointer and mark the pointer as "busy". */
+ do
+ {
+ cur = priv->_session;
+ /* Swap if cur is valid, otherwise busy loop. */
+ }
+ while (cur == invalid || !g_atomic_pointer_compare_and_exchange (&priv->_session, cur, invalid));
+
+ /* We can safely increase the reference count now. */
+ if (cur)
+ g_atomic_int_inc (&cur->_refcount);
+
+ /* Swap back, this must succeed. */
+ if (!g_atomic_pointer_compare_and_exchange (&priv->_session, invalid, cur))
+ g_assert_not_reached ();
+
+ return cur;
+}
+
+/* Pass NULL sender and username to unset session data. */
+static SessionData *
+session_data_set_new (FprintDevicePrivate *priv, gchar *sender, gchar *username)
+{
+ SessionData *invalid = (SessionData *) &priv->_session;
+ SessionData *new = NULL;
+ SessionData *old;
+
+ g_assert ((!sender && !username) || (sender && username));
+ if (sender)
+ {
+ new = g_new0 (SessionData, 1);
+ /* Internal reference of the pointer and returned reference. */
+ new->_refcount = 2;
+ *(char **) &new->sender = sender;
+ *(char **) &new->username = username;
+ }
+
+ /* Get the current (but not if it is busy) and put the new one in place. */
+ do
+ {
+ old = priv->_session;
+ /* Swap if old is valid, otherwise busy loop as someone is ref'ing it currently. */
+ }
+ while (old == invalid || !g_atomic_pointer_compare_and_exchange (&priv->_session, old, new));
+
+ /* We can safely drop the our internal reference now. */
+ if (old)
+ session_data_unref (old);
+
+ return new;
+}
+
+typedef FprintDevice FprintDeviceActionUnset;
+static void
+auto_device_action_unset (FprintDeviceActionUnset *self)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (self);
+
+ priv->current_action = ACTION_NONE;
+}
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (FprintDeviceActionUnset, auto_device_action_unset);
+
+static void
+fprint_device_dispose (GObject *object)
+{
+ FprintDevice *self = (FprintDevice *) object;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (self);
+
+ g_hash_table_remove_all (priv->clients);
+
+ G_OBJECT_CLASS (fprint_device_parent_class)->dispose (object);
+}
+
+static void
+fprint_device_finalize (GObject *object)
+{
+ FprintDevice *self = (FprintDevice *) object;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (self);
+
+ g_hash_table_destroy (priv->clients);
+ session_data_set_new (priv, NULL, NULL);
+ g_clear_object (&priv->auth);
+ g_clear_object (&priv->dev);
+
+ if (priv->current_action != ACTION_NONE ||
+ priv->_session ||
+ priv->verify_data ||
+ priv->identify_data ||
+ priv->current_cancellable ||
+ priv->current_cancel_invocation)
+ g_critical ("Device was not cleaned up properly before being finalized.");
+
+ G_OBJECT_CLASS (fprint_device_parent_class)->finalize (object);
+}
+
+static void
+fprint_device_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ FprintDevice *self = (FprintDevice *) object;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (self);
+
+ switch (property_id)
+ {
+ case FPRINT_DEVICE_CONSTRUCT_DEV:
+ priv->dev = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+fprint_device_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ FprintDevice *self = (FprintDevice *) object;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (self);
+
+ switch (property_id)
+ {
+ case FPRINT_DEVICE_CONSTRUCT_DEV:
+ g_value_set_object (value, priv->dev);
+ break;
+
+ case FPRINT_DEVICE_IN_USE:
+ g_value_set_boolean (value, g_hash_table_size (priv->clients) != 0);
+ break;
+
+ case FPRINT_DEVICE_NAME:
+ g_value_set_static_string (value, fp_device_get_name (priv->dev));
+ break;
+
+ case FPRINT_DEVICE_NUM_ENROLL:
+ if (priv->dev)
+ g_value_set_int (value, fp_device_get_nr_enroll_stages (priv->dev));
+ else
+ g_value_set_int (value, -1);
+ break;
+
+ case FPRINT_DEVICE_SCAN_TYPE: {
+ const char *type;
+
+ if (fp_device_get_scan_type (priv->dev) == FP_SCAN_TYPE_PRESS)
+ type = "press";
+ else
+ type = "swipe";
+
+ g_value_set_static_string (value, type);
+ break;
+ }
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+fprint_device_class_init (FprintDeviceClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ gobject_class->dispose = fprint_device_dispose;
+ gobject_class->finalize = fprint_device_finalize;
+ gobject_class->set_property = fprint_device_set_property;
+ gobject_class->get_property = fprint_device_get_property;
+
+ pspec = g_param_spec_object ("dev", "Device",
+ "Set device construction property",
+ FP_TYPE_DEVICE,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE);
+ g_object_class_install_property (gobject_class,
+ FPRINT_DEVICE_CONSTRUCT_DEV, pspec);
+
+ pspec = g_param_spec_boolean ("in-use", "In use",
+ "Whether the device is currently in use", FALSE,
+ G_PARAM_READABLE);
+ g_object_class_install_property (gobject_class,
+ FPRINT_DEVICE_IN_USE, pspec);
+
+ g_object_class_override_property (gobject_class,
+ FPRINT_DEVICE_NAME,
+ "name");
+
+ g_object_class_override_property (gobject_class,
+ FPRINT_DEVICE_SCAN_TYPE,
+ "scan-type");
+
+ g_object_class_override_property (gobject_class,
+ FPRINT_DEVICE_NUM_ENROLL,
+ "num-enroll-stages");
+
+ signals[SIGNAL_VERIFY_STATUS] =
+ g_signal_lookup ("verify-status", FPRINT_TYPE_DEVICE);
+ signals[SIGNAL_ENROLL_STATUS] =
+ g_signal_lookup ("enroll-status", FPRINT_TYPE_DEVICE);
+ signals[SIGNAL_VERIFY_FINGER_SELECTED] =
+ g_signal_lookup ("verify-finger-selected", FPRINT_TYPE_DEVICE);
+
+ quark_auth_user = g_quark_from_static_string ("authorized-user");
+}
+
+static void
+_unwatch_name (gpointer id)
{
- g_clear_pointer(&session->sender, g_free);
- g_clear_pointer(&session->username, g_free);
- g_nullify_pointer((gpointer *) &session->context);
- g_free(session);
-}
-G_DEFINE_AUTOPTR_CLEANUP_FUNC(SessionData, session_data_free);
-
-static void fprint_device_finalize(GObject *object)
-{
- FprintDevice *self = (FprintDevice *) object;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(self);
-
- g_hash_table_destroy (priv->clients);
- g_clear_pointer(&priv->session, session_data_free);
- /* FIXME close and stuff */
-
- G_OBJECT_CLASS(fprint_device_parent_class)->finalize(object);
-}
-
-static void fprint_device_set_property(GObject *object, guint property_id,
- const GValue *value, GParamSpec *pspec)
-{
- FprintDevice *self = (FprintDevice *) object;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(self);
-
- switch (property_id) {
- case FPRINT_DEVICE_CONSTRUCT_DEV:
- priv->dev = g_value_dup_object(value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
- break;
- }
-}
-
-static void fprint_device_get_property(GObject *object, guint property_id,
- GValue *value, GParamSpec *pspec)
-{
- FprintDevice *self = (FprintDevice *) object;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(self);
-
- switch (property_id) {
- case FPRINT_DEVICE_CONSTRUCT_DEV:
- g_value_set_object(value, priv->dev);
- break;
- case FPRINT_DEVICE_IN_USE:
- g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0);
- break;
- case FPRINT_DEVICE_NAME:
- g_value_set_static_string (value, fp_device_get_name (priv->dev));
- break;
- case FPRINT_DEVICE_NUM_ENROLL:
- if (priv->dev)
- g_value_set_int (value, fp_device_get_nr_enroll_stages (priv->dev));
- else
- g_value_set_int (value, -1);
- break;
- case FPRINT_DEVICE_SCAN_TYPE: {
- const char *type;
-
- if (fp_device_get_scan_type (priv->dev) == FP_SCAN_TYPE_PRESS)
- type = "press";
- else
- type = "swipe";
-
- g_value_set_static_string (value, type);
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
- break;
- }
-}
-
-static void fprint_device_class_init(FprintDeviceClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
- GParamSpec *pspec;
-
- dbus_g_object_type_install_info(FPRINT_TYPE_DEVICE,
- &dbus_glib_fprint_device_object_info);
-
- gobject_class->finalize = fprint_device_finalize;
- gobject_class->set_property = fprint_device_set_property;
- gobject_class->get_property = fprint_device_get_property;
-
- pspec = g_param_spec_object("dev", "Device",
- "Set device construction property",
- FP_TYPE_DEVICE,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE);
- g_object_class_install_property(gobject_class,
- FPRINT_DEVICE_CONSTRUCT_DEV, pspec);
-
- pspec = g_param_spec_boolean("in-use", "In use",
- "Whether the device is currently in use", FALSE,
- G_PARAM_READABLE);
- g_object_class_install_property(gobject_class,
- FPRINT_DEVICE_IN_USE, pspec);
-
- pspec = g_param_spec_string("name", "Name",
- "The product name of the device", NULL,
- G_PARAM_READABLE);
- g_object_class_install_property(gobject_class,
- FPRINT_DEVICE_NAME, pspec);
-
- pspec = g_param_spec_string("scan-type", "Scan Type",
- "The scan type of the device", "press",
- G_PARAM_READABLE);
- g_object_class_install_property(gobject_class,
- FPRINT_DEVICE_SCAN_TYPE, pspec);
-
- pspec = g_param_spec_int("num-enroll-stages", "Number of enrollments stages",
- "Number of enrollment stages for the device.",
- -1, G_MAXINT, -1, G_PARAM_READABLE);
- g_object_class_install_property(gobject_class,
- FPRINT_DEVICE_NUM_ENROLL, pspec);
-
- signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status",
- G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
- fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
- signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status",
- G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
- fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
- signals[SIGNAL_VERIFY_FINGER_SELECTED] = g_signal_new("verify-finger-selected",
- G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
- g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
-}
-
-static void fprint_device_init(FprintDevice *device)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(device);
- priv->id = ++last_id;
-
- /* Setup PolicyKit */
- priv->auth = polkit_authority_get_sync (NULL, NULL);
- priv->clients = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- NULL);
-}
-
-FprintDevice *fprint_device_new(FpDevice *dev)
+ g_bus_unwatch_name (GPOINTER_TO_INT (id));
+}
+
+static void
+fprint_device_init (FprintDevice *device)
{
- return g_object_new(FPRINT_TYPE_DEVICE, "dev", dev, NULL);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (device);
+
+ priv->id = ++last_id;
+
+ /* Setup PolicyKit */
+ priv->auth = polkit_authority_get_sync (NULL, NULL);
+ priv->clients = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ _unwatch_name);
+
+ g_signal_connect (device, "g-authorize-method",
+ G_CALLBACK (action_authorization_handler),
+ NULL);
}
-guint32 _fprint_device_get_id(FprintDevice *rdev)
+FprintDevice *
+fprint_device_new (FpDevice *dev)
{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
+ return g_object_new (FPRINT_TYPE_DEVICE, "dev", dev, NULL);
+}
+
+guint32
+_fprint_device_get_id (FprintDevice *rdev)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
- return priv->id;
+ return priv->id;
}
static const char *
-finger_num_to_name (int finger_num)
+fp_finger_to_name (FpFinger finger)
{
- if (finger_num == -1)
- return "any";
- if (!FP_FINGER_IS_VALID (finger_num))
- return NULL;
- return FINGERS_NAMES[finger_num];
+ if (finger == FP_FINGER_UNKNOWN)
+ return "any";
+ if (!FP_FINGER_IS_VALID (finger))
+ return NULL;
+ return FINGERS_NAMES[finger];
}
-static int
-finger_name_to_num (const char *finger_name)
+static FpFinger
+finger_name_to_fp_finger (const char *finger_name)
{
- guint i;
+ FpFinger i;
- if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any"))
- return -1;
+ if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any"))
+ return FP_FINGER_UNKNOWN;
- for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++) {
- if (g_str_equal (finger_name, FINGERS_NAMES[i]))
- return i;
- }
+ for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++)
+ if (g_str_equal (finger_name, FINGERS_NAMES[i]))
+ return i;
- /* Invalid, let's try that */
- return -1;
+ /* Invalid, let's try that */
+ return FP_FINGER_UNKNOWN;
}
static const char *
verify_result_to_name (gboolean match, GError *error)
{
- if (!error) {
- if (match)
- return "verify-match";
- else
- return "verify-no-match";
- }
-
- if (error->domain == FP_DEVICE_RETRY) {
- switch (error->code) {
- case FP_DEVICE_RETRY_TOO_SHORT:
- return "verify-swipe-too-short";
- case FP_DEVICE_RETRY_CENTER_FINGER:
- return "verify-finger-not-centered";
- case FP_DEVICE_RETRY_REMOVE_FINGER:
- return "verify-remove-and-retry";
- default:
- return "verify-retry-scan";
- }
- } else {
- /* Which errors should be mapped to disconnection?
- * Are drivers/libfprint/fprintd really in agreement here?
- */
- if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO))
- return "verify-disconnect";
+ if (!error)
+ {
+ if (match)
+ return "verify-match";
+ else
+ return "verify-no-match";
+ }
+
+ if (error->domain == FP_DEVICE_RETRY)
+ {
+ switch (error->code)
+ {
+ case FP_DEVICE_RETRY_TOO_SHORT:
+ return "verify-swipe-too-short";
+
+ case FP_DEVICE_RETRY_CENTER_FINGER:
+ return "verify-finger-not-centered";
+
+ case FP_DEVICE_RETRY_REMOVE_FINGER:
+ return "verify-remove-and-retry";
+
+ default:
+ return "verify-retry-scan";
+ }
+ }
+ else
+ {
+ /* Which errors should be mapped to disconnection?
+ * Are drivers/libfprint/fprintd really in agreement here?
+ */
+ if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO))
+ return "verify-disconnected";
+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return "verify-no-match";
- return "verify-unknown-error";
- }
+ return "verify-unknown-error";
+ }
}
static const char *
enroll_result_to_name (gboolean completed, gboolean enrolled, GError *error)
{
- if (!error) {
- if (!completed)
- return "enroll-stage-passed";
- else if (enrolled)
- return "enroll-completed";
- else
- return "enroll-failed";
- }
-
- if (error->domain == FP_DEVICE_RETRY) {
- switch (error->code) {
- case FP_DEVICE_RETRY_TOO_SHORT:
- return "enroll-swipe-too-short";
- case FP_DEVICE_RETRY_CENTER_FINGER:
- return "enroll-finger-not-centered";
- case FP_DEVICE_RETRY_REMOVE_FINGER:
- return "verify-remove-and-retry";
- default:
- return "enroll-remove-and-retry";
- }
- } else {
- /* Which errors should be mapped to disconnection?
- * Are drivers/libfprint/fprintd really in agreement here?
- */
- if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO))
- return "enroll-disconnected";
- else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_FULL))
- return "enroll-data-full";
-
- return "enroll-unknown-error";
- }
+ if (!error)
+ {
+ if (!completed)
+ return "enroll-stage-passed";
+ else if (enrolled)
+ return "enroll-completed";
+ else
+ return "enroll-failed";
+ }
+
+ if (error->domain == FP_DEVICE_RETRY)
+ {
+ switch (error->code)
+ {
+ case FP_DEVICE_RETRY_TOO_SHORT:
+ return "enroll-swipe-too-short";
+
+ case FP_DEVICE_RETRY_CENTER_FINGER:
+ return "enroll-finger-not-centered";
+
+ case FP_DEVICE_RETRY_REMOVE_FINGER:
+ return "enroll-remove-and-retry";
+
+ default:
+ return "enroll-retry-scan";
+ }
+ }
+ else
+ {
+ /* Which errors should be mapped to disconnection?
+ * Are drivers/libfprint/fprintd really in agreement here?
+ */
+ if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO))
+ return "enroll-disconnected";
+ else if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_FULL))
+ return "enroll-data-full";
+ else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ return "enroll-failed";
+
+ return "enroll-unknown-error";
+ }
+}
+
+static FprintDevicePermission
+get_permissions_for_invocation (GDBusMethodInvocation *invocation)
+{
+ FprintDevicePermission required_perms;
+ const char *method_name;
+
+ required_perms = FPRINT_DEVICE_PERMISSION_NONE;
+ method_name = g_dbus_method_invocation_get_method_name (invocation);
+
+ if (g_str_equal (method_name, "Claim"))
+ {
+ required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
+ required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
+ }
+ else if (g_str_equal (method_name, "DeleteEnrolledFingers"))
+ {
+ required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
+ }
+ else if (g_str_equal (method_name, "DeleteEnrolledFingers2"))
+ {
+ required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
+ }
+ else if (g_str_equal (method_name, "EnrollStart"))
+ {
+ required_perms |= FPRINT_DEVICE_PERMISSION_ENROLL;
+ }
+ else if (g_str_equal (method_name, "ListEnrolledFingers"))
+ {
+ required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
+ }
+ else if (g_str_equal (method_name, "VerifyStart"))
+ {
+ required_perms |= FPRINT_DEVICE_PERMISSION_VERIFY;
+ }
+ else if (g_str_equal (method_name, "Release"))
+ {
+ }
+ else if (g_str_equal (method_name, "EnrollStop"))
+ {
+ }
+ else if (g_str_equal (method_name, "VerifyStop"))
+ {
+ /* Don't require permissiong for for release/stop operations.
+ * We are authenticated already if we could start, and we don't
+ * want to end up authorizing interactively again.
+ */
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ return required_perms;
+}
+
+static FprintDeviceClaimState
+get_claim_state_for_invocation (GDBusMethodInvocation *invocation)
+{
+ const char *method_name;
+
+ method_name = g_dbus_method_invocation_get_method_name (invocation);
+
+ if (g_str_equal (method_name, "Claim"))
+ return STATE_UNCLAIMED;
+ else if (g_str_equal (method_name, "DeleteEnrolledFingers"))
+ return STATE_AUTO_CLAIM;
+ else if (g_str_equal (method_name, "ListEnrolledFingers"))
+ return STATE_ANYTIME;
+
+ return STATE_CLAIMED;
+}
+
+static gboolean
+_fprint_device_check_claimed (FprintDevice *rdev,
+ GDBusMethodInvocation *invocation,
+ GError **error)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(SessionData) session = NULL;
+ FprintDeviceClaimState requested_state;
+ const char *sender;
+
+ requested_state = get_claim_state_for_invocation (invocation);
+
+ if (requested_state == STATE_ANYTIME)
+ return TRUE;
+
+ session = session_data_get (priv);
+ if (requested_state == STATE_AUTO_CLAIM)
+ requested_state = session ? STATE_CLAIMED : STATE_UNCLAIMED;
+
+ if (requested_state == STATE_UNCLAIMED)
+ {
+ /* Is it already claimed? */
+ if (!session)
+ return TRUE;
+
+ g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Device was already claimed");
+ return FALSE;
+ }
+
+ g_assert (requested_state == STATE_CLAIMED);
+
+ /* The device wasn't claimed, exit */
+ if (session == NULL)
+ {
+ g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
+ _("Device was not claimed before use"));
+ return FALSE;
+ }
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+
+ if (!g_str_equal (sender, session->sender) || session->invocation != NULL)
+ {
+ g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ _("Device already in use by another user"));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_fprint_device_check_polkit_for_action (FprintDevice *rdev,
+ GDBusMethodInvocation *invocation,
+ const char *action,
+ GError **error)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ const char *sender;
+
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(PolkitAuthorizationResult) result = NULL;
+ g_autoptr(PolkitSubject) subject = NULL;
+
+ /* Check that caller is privileged */
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ subject = polkit_system_bus_name_new (sender);
+
+ result = polkit_authority_check_authorization_sync (priv->auth,
+ subject,
+ action,
+ NULL,
+ POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
+ NULL, &local_error);
+ if (result == NULL)
+ {
+ g_set_error (error, FPRINT_ERROR,
+ FPRINT_ERROR_PERMISSION_DENIED,
+ "Not Authorized: %s", local_error->message);
+ return FALSE;
+ }
+
+ if (!polkit_authorization_result_get_is_authorized (result))
+ {
+ g_set_error (error, FPRINT_ERROR,
+ FPRINT_ERROR_PERMISSION_DENIED,
+ "Not Authorized: %s", action);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+fprint_device_check_polkit_for_permissions (FprintDevice *rdev,
+ GDBusMethodInvocation *invocation,
+ FprintDevicePermission permissions,
+ GError **error)
+{
+ g_autoptr(GFlagsClass) permission_flags = NULL;
+ unsigned i;
+
+ if (permissions == FPRINT_DEVICE_PERMISSION_NONE)
+ return TRUE;
+
+ permission_flags = g_type_class_ref (FPRINT_TYPE_DEVICE_PERMISSION);
+
+ for (i = 0; i < permission_flags->n_values; ++i)
+ {
+ GFlagsValue *value = &permission_flags->values[i];
+ const char *action;
+
+ if (!(value->value & permissions))
+ continue;
+
+ action = value->value_nick;
+ g_debug ("Getting authorization to perform Polkit action %s",
+ action);
+
+ g_clear_error (error);
+ if (_fprint_device_check_polkit_for_action (rdev, invocation,
+ action, error))
+ return TRUE;
+ }
+
+ g_assert (!error || *error);
+ return FALSE;
+}
+
+static char *
+_fprint_device_check_for_username (FprintDevice *rdev,
+ GDBusMethodInvocation *invocation,
+ const char *username,
+ GError **error)
+{
+ g_autoptr(GVariant) ret = NULL;
+ g_autoptr(GError) local_error = NULL;
+ GDBusConnection *connection;
+ const char *sender;
+ struct passwd *user;
+ guint32 uid;
+
+ /* Get details about the current sender, and username/uid */
+ connection = g_dbus_method_invocation_get_connection (invocation);
+ sender = g_dbus_method_invocation_get_sender (invocation);
+
+ ret = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixUser",
+ g_variant_new ("(s)", sender),
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &local_error);
+
+ if (!ret)
+ {
+ g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
+ "Could not get connection unix user ID: %s",
+ local_error->message);
+ return NULL;
+ }
+
+ g_variant_get (ret, "(u)", &uid);
+ user = getpwuid (uid);
+ if (user == NULL)
+ {
+ g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
+ "Failed to get information about user UID %u", uid);
+ return NULL;
+ }
+
+ /* The current user is usually allowed to access their
+ * own data, this should be followed by PolicyKit checks
+ * anyway */
+ if (username == NULL || *username == '\0' || g_str_equal (username, user->pw_name))
+ return g_strdup (user->pw_name);
+
+ /* If we're not allowed to set a different username,
+ * then fail */
+ if (!fprint_device_check_polkit_for_permissions (rdev, invocation,
+ FPRINT_DEVICE_PERMISSION_SETUSERNAME,
+ error))
+ return NULL;
+
+ return g_strdup (username);
+}
+
+static void
+_fprint_device_client_vanished (GDBusConnection *connection,
+ const char *name,
+ FprintDevice *rdev)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(SessionData) session = NULL;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ session = session_data_get (priv);
+
+ /* Was that the client that claimed the device? */
+ if (session != NULL &&
+ g_strcmp0 (session->sender, name) == 0)
+ {
+ g_cancellable_cancel (priv->current_cancellable);
+
+ if (!priv->current_cancellable)
+ {
+ /* This isn't optimal, but for verify/identify/enroll we expect the stop
+ * command. And we use current_cancellable as a flag to know that the
+ * underlying operation has finished already.
+ * If it has finished, unset the current_action. */
+ switch (priv->current_action)
+ {
+ case ACTION_VERIFY:
+ case ACTION_IDENTIFY:
+ case ACTION_ENROLL:
+ priv->current_action = ACTION_NONE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ while (priv->current_action != ACTION_NONE)
+ g_main_context_iteration (NULL, TRUE);
+
+ /* The session may have disappeared at this point if the device
+ * was already closing. */
+ g_clear_pointer (&session, session_data_unref);
+ session = session_data_get (priv);
+ if (session && !fp_device_close_sync (priv->dev, NULL, &error))
+ g_critical ("Error closing device after disconnect: %s", error->message);
+
+ session_data_set_new (priv, NULL, NULL);
+ }
+ g_hash_table_remove (priv->clients, name);
+
+ if (g_hash_table_size (priv->clients) == 0)
+ g_object_notify (G_OBJECT (rdev), "in-use");
+}
+
+static void
+_fprint_device_add_client (FprintDevice *rdev, const char *sender)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ guint id;
+
+ id = GPOINTER_TO_UINT (g_hash_table_lookup (priv->clients, sender));
+ if (id == 0)
+ {
+ id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ (GBusNameVanishedCallback) _fprint_device_client_vanished,
+ rdev,
+ NULL);
+ g_hash_table_insert (priv->clients, g_strdup (sender), GUINT_TO_POINTER (id));
+ g_object_notify (G_OBJECT (rdev), "in-use");
+ }
+}
+
+static void
+dev_open_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
+{
+ g_autoptr(GError) error = NULL;
+ FprintDevice *rdev = user_data;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(SessionData) session = NULL;
+ g_autoptr(GDBusMethodInvocation) invocation = NULL;
+ g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
+
+ action_unset = rdev;
+ session = session_data_get (priv);
+ invocation = g_steal_pointer (&session->invocation);
+
+ if (!fp_device_open_finish (dev, res, &error))
+ {
+ g_autoptr(GError) dbus_error = NULL;
+
+ dbus_error = g_error_new (FPRINT_ERROR,
+ FPRINT_ERROR_INTERNAL,
+ "Open failed with error: %s", error->message);
+ g_dbus_method_invocation_return_gerror (invocation, dbus_error);
+ session_data_set_new (priv, NULL, NULL);
+ return;
+ }
+
+ g_debug ("claimed device %d", priv->id);
+
+ fprint_dbus_device_complete_claim (FPRINT_DBUS_DEVICE (rdev),
+ invocation);
+}
+
+static gboolean
+fprintd_device_authorize_user (FprintDevice *rdev,
+ GDBusMethodInvocation *invocation,
+ GError **error)
+{
+ GVariant *params = NULL;
+ const char *username = NULL;
+ g_autofree char *user = NULL;
+
+ params = g_dbus_method_invocation_get_parameters (invocation);
+ g_assert (g_variant_n_children (params) == 1);
+ g_variant_get (params, "(&s)", &username);
+ g_assert (username);
+
+ user = _fprint_device_check_for_username (rdev,
+ invocation,
+ username,
+ error);
+ if (user == NULL)
+ return FALSE;
+
+ /* We keep the user attached to the invocation as it may not be the same
+ * of the requested one, in case an empty one was passed.
+ * Given that now we may have multiple cuncurrent requests, it wouldn't
+ * be safe to add another member to the priv, as it would need even more
+ * multi-thread checks around, and over-complicate things.
+ */
+ g_object_set_qdata_full (G_OBJECT (invocation), quark_auth_user,
+ g_steal_pointer (&user), g_free);
+
+ return TRUE;
+}
+
+static gboolean
+fprint_device_claim (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation,
+ const char *username)
+{
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(SessionData) session = NULL;
+ g_autoptr(GError) error = NULL;
+ char *sender, *user;
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ user = g_object_steal_qdata (G_OBJECT (invocation), quark_auth_user);
+ g_assert (user);
+ g_assert (g_str_equal (username, "") || g_str_equal (user, username));
+
+ sender = g_strdup (g_dbus_method_invocation_get_sender (invocation));
+ _fprint_device_add_client (rdev, sender);
+
+ session = session_data_set_new (priv, g_steal_pointer (&sender), g_steal_pointer (&user));
+ session->invocation = g_object_ref (invocation);
+
+ g_debug ("user '%s' claiming the device: %d", session->username, priv->id);
+
+ priv->current_action = ACTION_OPEN;
+ fp_device_open (priv->dev, NULL, (GAsyncReadyCallback) dev_open_cb, rdev);
+
+ return TRUE;
}
static void
-set_disconnected (FprintDevicePrivate *priv, const char *res)
-{
- if (g_str_equal (res, "enroll-disconnected") ||
- g_str_equal (res, "verify-disconnected"))
- priv->disconnected = TRUE;
+dev_close_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
+{
+ g_autoptr(GError) error = NULL;
+ FprintDevice *rdev = user_data;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(SessionData) session = NULL;
+ g_autoptr(GDBusMethodInvocation) invocation = NULL;
+ g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
+
+ session = session_data_get (priv);
+ session_data_set_new (priv, NULL, NULL);
+ invocation = g_steal_pointer (&session->invocation);
+ action_unset = rdev;
+
+ if (!fp_device_close_finish (dev, res, &error))
+ {
+ g_autoptr(GError) dbus_error = NULL;
+
+ dbus_error = g_error_new (FPRINT_ERROR,
+ FPRINT_ERROR_INTERNAL,
+ "Release failed with error: %s", error->message);
+ g_dbus_method_invocation_return_gerror (invocation, dbus_error);
+ return;
+ }
+
+ g_debug ("released device %d", priv->id);
+
+ fprint_dbus_device_complete_release (FPRINT_DBUS_DEVICE (rdev),
+ invocation);
}
static gboolean
-_fprint_device_check_claimed (FprintDevice *rdev,
- DBusGMethodInvocation *context,
- GError **error)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- char *sender;
- gboolean retval;
-
- /* The device wasn't claimed, exit */
- if (priv->session == NULL) {
- g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
- _("Device was not claimed before use"));
- return FALSE;
- }
-
- sender = dbus_g_method_get_sender (context);
- retval = g_str_equal (sender, priv->session->sender);
- g_free (sender);
-
- if (retval == FALSE ||
- priv->session->context != NULL) {
- g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
- _("Device already in use by another user"));
- }
+fprint_device_release (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(SessionData) session = NULL;
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (priv->current_cancellable)
+ {
+ if (priv->current_action == ACTION_ENROLL)
+ g_warning ("Enrollment was in progress, stopping it");
+ else if (priv->current_action == ACTION_IDENTIFY ||
+ priv->current_action == ACTION_VERIFY)
+ g_warning ("Verification was in progress, stopping it");
+ else if (priv->current_action == ACTION_DELETE)
+ g_warning ("Deletion was in progress, stopping it");
+
+ g_cancellable_cancel (priv->current_cancellable);
+ while (priv->current_action != ACTION_NONE)
+ g_main_context_iteration (NULL, TRUE);
+ }
+
+ session = session_data_get (priv);
+ session->invocation = g_object_ref (invocation);
- return retval;
+ priv->current_action = ACTION_CLOSE;
+ fp_device_close (priv->dev, NULL, (GAsyncReadyCallback) dev_close_cb, rdev);
+
+ return TRUE;
+}
+
+static void
+report_verify_status (FprintDevice *rdev,
+ gboolean match,
+ GError *error)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ const char *result = verify_result_to_name (match, error);
+
+ g_autoptr(SessionData) session = NULL;
+ gboolean done;
+
+ done = (error == NULL || error->domain != FP_DEVICE_RETRY);
+
+ session = session_data_get (priv);
+
+ if (done && session->verify_status_reported)
+ {
+ /* It is completely fine for cancellation to occur after a
+ * result has been reported. */
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Verify status already reported. Ignoring %s", result);
+ return;
+ }
+
+ g_debug ("report_verify_status: result %s", result);
+ g_signal_emit (rdev, signals[SIGNAL_VERIFY_STATUS], 0, result, done);
+
+ if (done)
+ session->verify_status_reported = TRUE;
}
static gboolean
-_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
+can_start_action (FprintDevice *rdev, GError **error)
{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- char *sender;
- PolkitSubject *subject;
- PolkitAuthorizationResult *result;
- GError *_error = NULL;
-
- /* Check that caller is privileged */
- sender = dbus_g_method_get_sender (context);
- subject = polkit_system_bus_name_new (sender);
- g_free (sender);
-
- result = polkit_authority_check_authorization_sync (priv->auth,
- subject,
- action,
- NULL,
- POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
- NULL, &_error);
- g_object_unref (subject);
-
- if (result == NULL) {
- g_set_error (error, FPRINT_ERROR,
- FPRINT_ERROR_PERMISSION_DENIED,
- "Not Authorized: %s", _error->message);
- g_error_free (_error);
- return FALSE;
- }
-
- if (!polkit_authorization_result_get_is_authorized (result)) {
- g_set_error (error, FPRINT_ERROR,
- FPRINT_ERROR_PERMISSION_DENIED,
- "Not Authorized: %s", action);
- g_object_unref (result);
- return FALSE;
- }
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ switch (priv->current_action)
+ {
+ case ACTION_NONE:
+ return TRUE;
+
+ case ACTION_ENROLL:
+ g_set_error (error,
+ FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Enrollment already in progress");
+ break;
+
+ case ACTION_IDENTIFY:
+ case ACTION_VERIFY:
+ g_set_error (error,
+ FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Verification already in progress");
+ break;
+
+ case ACTION_OPEN:
+ g_set_error (error,
+ FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Claim already in progress");
+ break;
+
+ case ACTION_CLOSE:
+ g_set_error (error,
+ FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Release already in progress");
+ break;
+
+ case ACTION_DELETE:
+ g_set_error (error,
+ FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Delete already in progress");
+ break;
+
+ default: /* Fallback only. */
+ g_assert_not_reached ();
+ g_set_error (error,
+ FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
+ "Another operation is already in progress");
+ }
+
+ return FALSE;
+}
- g_object_unref (result);
+static void
+stoppable_action_completed (FprintDevice *rdev)
+{
+ g_autoptr(SessionData) session = NULL;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (rdev);
+
+ session = session_data_get (priv);
+
+ /* Return the cancellation or reset action right away if vanished. */
+ if (priv->current_cancel_invocation)
+ {
+ switch (priv->current_action)
+ {
+ case ACTION_VERIFY:
+ case ACTION_IDENTIFY:
+ fprint_dbus_device_complete_verify_stop (dbus_dev,
+ g_steal_pointer (&priv->current_cancel_invocation));
+ break;
+
+ case ACTION_ENROLL:
+ fprint_dbus_device_complete_enroll_stop (dbus_dev,
+ g_steal_pointer (&priv->current_cancel_invocation));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ priv->current_action = ACTION_NONE;
+ session->verify_status_reported = FALSE;
+ }
+ else if (g_cancellable_is_cancelled (priv->current_cancellable))
+ {
+ priv->current_action = ACTION_NONE;
+ session->verify_status_reported = FALSE;
+ }
- return TRUE;
+ g_clear_object (&priv->current_cancellable);
+}
+
+static void
+match_cb (FpDevice *device,
+ FpPrint *match,
+ FpPrint *print,
+ gpointer user_data,
+ GError *error)
+{
+ FprintDevice *rdev = user_data;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ gboolean matched;
+ gboolean cancelled;
+
+ g_assert_true (error == NULL || error->domain == FP_DEVICE_RETRY);
+
+ cancelled = g_cancellable_is_cancelled (priv->current_cancellable);
+ matched = match != NULL && cancelled == FALSE;
+
+ /* No-match is reported only after the operation completes.
+ * This avoids problems when the operation is immediately restarted. */
+ report_verify_status (rdev, matched, error);
+}
+
+static void
+verify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
+{
+ g_autoptr(GError) error = NULL;
+ FprintDevice *rdev = user_data;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ gboolean success;
+ const char *name;
+ gboolean match;
+
+ success = fp_device_verify_finish (dev, res, &match, NULL, &error);
+ g_assert (!!success == !error);
+ name = verify_result_to_name (match, error);
+
+ g_debug ("verify_cb: result %s", name);
+
+ /* Automatically restart the operation for retry failures */
+ if (error && error->domain == FP_DEVICE_RETRY)
+ {
+ fp_device_verify (priv->dev,
+ priv->verify_data,
+ priv->current_cancellable,
+ match_cb, rdev, NULL,
+ (GAsyncReadyCallback) verify_cb,
+ rdev);
+ }
+ else
+ {
+ g_clear_object (&priv->verify_data);
+
+ if (error)
+ {
+ report_verify_status (rdev, FALSE, error);
+
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Device reported an error during verify: %s",
+ error->message);
+ }
+
+ stoppable_action_completed (rdev);
+ }
+}
+
+static void
+identify_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FpPrint) match = NULL;
+ FprintDevice *rdev = user_data;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ const char *name;
+ gboolean success;
+
+ success = fp_device_identify_finish (dev, res, &match, NULL, &error);
+ g_assert (!!success == !error);
+ name = verify_result_to_name (match != NULL, error);
+
+ g_debug ("identify_cb: result %s", name);
+
+ /* Automatically restart the operation for retry failures */
+ if (error && error->domain == FP_DEVICE_RETRY)
+ {
+ fp_device_identify (priv->dev,
+ priv->identify_data,
+ priv->current_cancellable,
+ match_cb, rdev, NULL,
+ (GAsyncReadyCallback) identify_cb,
+ rdev);
+ }
+ else
+ {
+ g_clear_pointer (&priv->identify_data, g_ptr_array_unref);
+
+ if (error)
+ {
+ report_verify_status (rdev, FALSE, error);
+
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Device reported an error during identify: %s",
+ error->message);
+ }
+
+ stoppable_action_completed (rdev);
+ }
}
static gboolean
-_fprint_device_check_polkit_for_actions (FprintDevice *rdev,
- DBusGMethodInvocation *context,
- const char *action1,
- const char *action2,
- GError **error)
+fprint_device_verify_start (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation,
+ const char *finger_name)
+{
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(GPtrArray) gallery = NULL;
+ g_autoptr(FpPrint) print = NULL;
+ g_autoptr(SessionData) session = NULL;
+ g_autoptr(GError) error = NULL;
+ FpFinger finger = finger_name_to_fp_finger (finger_name);
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ session = session_data_get (priv);
+
+ if (!can_start_action (rdev, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (finger == FP_FINGER_UNKNOWN)
+ {
+ g_autoptr(GSList) prints = NULL;
+
+ prints = store.discover_prints (priv->dev, session->username);
+ if (prints == NULL)
+ {
+ g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
+ "No fingerprints enrolled");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+ if (fp_device_supports_identify (priv->dev))
+ {
+ GSList *l;
+
+ gallery = g_ptr_array_new_with_free_func (g_object_unref);
+
+ for (l = prints; l != NULL; l = l->next)
+ {
+ g_debug ("adding finger %u to the gallery", GPOINTER_TO_UINT (l->data));
+ store.print_data_load (priv->dev, GPOINTER_TO_UINT (l->data),
+ session->username, &print);
+
+ if (print)
+ g_ptr_array_add (gallery, g_steal_pointer (&print));
+ }
+ }
+ else
+ {
+ finger = GPOINTER_TO_UINT (prints->data);
+ }
+ }
+
+ if (fp_device_supports_identify (priv->dev) && finger == FP_FINGER_UNKNOWN)
+ {
+ if (gallery->len == 0)
+ {
+ g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
+ "No fingerprints on that device");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+ priv->current_action = ACTION_IDENTIFY;
+
+ g_debug ("start identification device %d", priv->id);
+ priv->current_cancellable = g_cancellable_new ();
+ priv->identify_data = g_ptr_array_ref (gallery);
+ fp_device_identify (priv->dev, gallery, priv->current_cancellable,
+ match_cb, rdev, NULL,
+ (GAsyncReadyCallback) identify_cb, rdev);
+ }
+ else
+ {
+ priv->current_action = ACTION_VERIFY;
+
+ g_debug ("start verification device %d finger %d", priv->id, finger);
+
+ store.print_data_load (priv->dev, finger,
+ session->username, &print);
+
+ if (!print)
+ {
+ g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
+ "No such print %d", finger);
+ g_dbus_method_invocation_return_gerror (invocation,
+ error);
+ return TRUE;
+ }
+
+ priv->current_cancellable = g_cancellable_new ();
+ priv->verify_data = g_object_ref (print);
+ fp_device_verify (priv->dev, print, priv->current_cancellable,
+ match_cb, rdev, NULL,
+ (GAsyncReadyCallback) verify_cb, rdev);
+ }
+
+ fprint_dbus_device_complete_verify_start (dbus_dev, invocation);
+
+ /* Emit VerifyFingerSelected telling the front-end which finger
+ * we selected for auth */
+ g_signal_emit (rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
+ 0, fp_finger_to_name (finger));
+
+ return TRUE;
+}
+
+static gboolean
+fprint_device_verify_stop (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation)
+{
+ g_autoptr(SessionData) session = NULL;
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(GError) error = NULL;
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ switch (priv->current_action)
+ {
+ case ACTION_VERIFY:
+ case ACTION_IDENTIFY:
+ break;
+
+ case ACTION_NONE:
+ g_dbus_method_invocation_return_error_literal (
+ invocation, FPRINT_ERROR,
+ FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
+ "No verification in progress");
+ return TRUE;
+
+ default:
+ g_dbus_method_invocation_return_error_literal (
+ invocation, FPRINT_ERROR,
+ FPRINT_ERROR_ALREADY_IN_USE,
+ "Another operation is already in progress");
+ return TRUE;
+ }
+
+ if (priv->current_cancellable)
+ {
+ /* We return only when the action was cancelled */
+ g_cancellable_cancel (priv->current_cancellable);
+ priv->current_cancel_invocation = invocation;
+ }
+ else
+ {
+ fprint_dbus_device_complete_verify_stop (dbus_dev, invocation);
+ priv->current_action = ACTION_NONE;
+
+ session = session_data_get (priv);
+ session->verify_status_reported = FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+enroll_progress_cb (FpDevice *dev,
+ gint completed_stages,
+ FpPrint *print,
+ gpointer user_data,
+ GError *error)
{
- if (_fprint_device_check_polkit_for_action (rdev, context, action1, error) != FALSE)
- return TRUE;
+ FprintDevice *rdev = user_data;
+ const char *name = enroll_result_to_name (FALSE, FALSE, error);
- g_error_free (*error);
- *error = NULL;
+ g_debug ("enroll_stage_cb: result %s", name);
- return _fprint_device_check_polkit_for_action (rdev, context, action2, error);
+ if (completed_stages < fp_device_get_nr_enroll_stages (dev))
+ g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, FALSE);
}
-static char *
-_fprint_device_check_for_username (FprintDevice *rdev,
- DBusGMethodInvocation *context,
- const char *username,
- char **ret_sender,
- GError **error)
-{
- DBusConnection *conn;
- DBusError dbus_error;
- char *sender;
- unsigned long uid;
- struct passwd *user;
-
- /* Get details about the current sender, and username/uid */
- conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
- sender = dbus_g_method_get_sender (context);
- dbus_error_init (&dbus_error);
- uid = dbus_bus_get_unix_user (conn, sender, &dbus_error);
-
- if (dbus_error_is_set(&dbus_error)) {
- g_free (sender);
- dbus_set_g_error (error, &dbus_error);
- return NULL;
- }
-
- user = getpwuid (uid);
- if (user == NULL) {
- g_free (sender);
- g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
- "Failed to get information about user UID %lu", uid);
- return NULL;
- }
-
- /* The current user is usually allowed to access their
- * own data, this should be followed by PolicyKit checks
- * anyway */
- if (username == NULL || *username == '\0' || g_str_equal (username, user->pw_name)) {
- if (ret_sender != NULL)
- *ret_sender = sender;
- else
- g_free (sender);
- return g_strdup (user->pw_name);
- }
-
- /* If we're not allowed to set a different username,
- * then fail */
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.setusername", error) == FALSE) {
- g_free (sender);
- return NULL;
- }
-
- if (ret_sender != NULL)
- *ret_sender = sender;
- else
- g_free (sender);
+static gboolean
+try_delete_print (FprintDevice *rdev)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GPtrArray) device_prints = NULL;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ GSList *users, *user;
+
+ device_prints = fp_device_list_prints_sync (priv->dev, NULL, &error);
+ if (!device_prints)
+ {
+ g_warning ("Failed to query prints: %s", error->message);
+ return FALSE;
+ }
+
+ g_debug ("Device has %d prints stored", device_prints->len);
+
+ users = store.discover_users ();
+
+ for (user = users; user; user = user->next)
+ {
+ const char *username = user->data;
+ g_autoptr(GSList) fingers = NULL;
+ GSList *finger;
+
+ fingers = store.discover_prints (priv->dev, username);
+
+ for (finger = fingers; finger; finger = finger->next)
+ {
+ g_autoptr(FpPrint) print = NULL;
+ guint index;
+
+ store.print_data_load (priv->dev,
+ GPOINTER_TO_UINT (finger->data),
+ username,
+ &print);
+
+ if (!print)
+ continue;
+
+ if (!g_ptr_array_find_with_equal_func (device_prints,
+ print,
+ (GEqualFunc) fp_print_equal,
+ &index))
+ continue;
+
+ /* Found an equal print, remove it */
+ g_ptr_array_remove_index (device_prints, index);
+ }
+ }
+
+ g_slist_free_full (users, g_free);
+
+ g_debug ("Device has %d prints stored that we do not need", device_prints->len);
+ if (device_prints->len == 0)
+ return FALSE;
+
+ /* Just delete the first print in the list at this point.
+ * We could be smarter and fetch some more metadata. */
+ fp_device_delete_print_sync (priv->dev,
+ g_ptr_array_index (device_prints, 0),
+ NULL,
+ &error);
+
+ if (error)
+ {
+ g_warning ("Failed to garbage collect a print: %s", error->message);
+ return FALSE;
+ }
- return g_strdup (username);
+ return TRUE;
+}
+
+#if !GLIB_CHECK_VERSION (2, 63, 3)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
+#endif
+
+static FpPrint *
+fprint_device_create_enroll_template (FprintDevice *rdev, FpFinger finger)
+{
+ g_autoptr(SessionData) session = NULL;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(GDateTime) datetime = NULL;
+ g_autoptr(GDate) date = NULL;
+ FpPrint *template = NULL;
+ gint year, month, day;
+
+ session = session_data_get (priv);
+
+ template = fp_print_new (priv->dev);
+ fp_print_set_finger (template, finger);
+ fp_print_set_username (template, session->username);
+ datetime = g_date_time_new_now_local ();
+ g_date_time_get_ymd (datetime, &year, &month, &day);
+ date = g_date_new_dmy (day, month, year);
+ fp_print_set_enroll_date (template, date);
+
+ return template;
}
static void
-_fprint_device_client_vanished (GDBusConnection *connection,
- const char *name,
- FprintDevice *rdev)
+enroll_cb (FpDevice *dev, GAsyncResult *res, void *user_data)
+{
+ g_autoptr(GError) error = NULL;
+ FprintDevice *rdev = user_data;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(FpPrint) print = NULL;
+ const char *name;
+
+ print = fp_device_enroll_finish (dev, res, &error);
+
+ /* We need to special case the issue where the on device storage
+ * is completely full. In that case, we check whether we can delete
+ * a print that is not coming from us; assuming it is from an old
+ * installation.
+ * We do this synchronously, which is not great but should be good
+ * enough. */
+ if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_FULL))
+ {
+ g_debug ("Device storage is full, trying to garbage collect old prints");
+ if (try_delete_print (rdev))
+ {
+ /* Success? Then restart the operation */
+ fp_device_enroll (priv->dev,
+ fprint_device_create_enroll_template (rdev, priv->enroll_data),
+ priv->current_cancellable,
+ enroll_progress_cb,
+ rdev,
+ NULL,
+ (GAsyncReadyCallback) enroll_cb,
+ rdev);
+ return;
+ }
+ }
+
+ name = enroll_result_to_name (TRUE, print != NULL, error);
+
+ g_debug ("enroll_cb: result %s", name);
+
+ if (print)
+ {
+ int r;
+ r = store.print_data_save (print);
+ if (r < 0)
+ name = "enroll-failed";
+ }
+
+ g_signal_emit (rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, TRUE);
+
+ if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Device reported an error during enroll: %s", error->message);
+
+ stoppable_action_completed (rdev);
+}
+
+
+static gboolean
+fprint_device_enroll_start (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation,
+ const char *finger_name)
+{
+ g_autoptr(GError) error = NULL;
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ FpFinger finger = finger_name_to_fp_finger (finger_name);
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (finger == FP_FINGER_UNKNOWN)
+ {
+ g_set_error (&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
+ "Invalid finger name");
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (!can_start_action (rdev, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ g_debug ("start enrollment device %d finger %d", priv->id, finger);
+
+ priv->current_cancellable = g_cancellable_new ();
+ priv->enroll_data = finger;
+ fp_device_enroll (priv->dev,
+ fprint_device_create_enroll_template (rdev, priv->enroll_data),
+ priv->current_cancellable,
+ enroll_progress_cb,
+ rdev,
+ NULL,
+ (GAsyncReadyCallback) enroll_cb,
+ rdev);
+
+ priv->current_action = ACTION_ENROLL;
+
+ fprint_dbus_device_complete_enroll_start (dbus_dev, invocation);
+
+ return TRUE;
+}
+
+static gboolean
+fprint_device_enroll_stop (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation)
{
- g_autoptr(GError) error = NULL;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(GError) error = NULL;
- /* Was that the client that claimed the device? */
- if (priv->session != NULL &&
- g_strcmp0 (priv->session->sender, name) == 0) {
- while (priv->current_action != ACTION_NONE) {
- g_cancellable_cancel (priv->current_cancellable);
-
- g_main_context_iteration (NULL, TRUE);
- }
-
- if (!fp_device_close_sync (priv->dev, NULL, &error))
- g_warning ("Error closing device after disconnect: %s", error->message);
-
- g_clear_pointer(&priv->session, session_data_free);
- }
- g_hash_table_remove (priv->clients, name);
-
- if (g_hash_table_size (priv->clients) == 0) {
- g_object_notify (G_OBJECT (rdev), "in-use");
- }
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ switch (priv->current_action)
+ {
+ case ACTION_ENROLL:
+ break;
+
+ case ACTION_NONE:
+ g_dbus_method_invocation_return_error_literal (
+ invocation, FPRINT_ERROR,
+ FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
+ "No enrollment in progress");
+ return TRUE;
+
+ default:
+ g_dbus_method_invocation_return_error_literal (
+ invocation, FPRINT_ERROR,
+ FPRINT_ERROR_ALREADY_IN_USE,
+ "Another operation is already in progress");
+ return TRUE;
+ }
+
+ if (priv->current_cancellable)
+ {
+ /* We return only when the action was cancelled */
+ g_cancellable_cancel (priv->current_cancellable);
+ priv->current_cancel_invocation = invocation;
+ }
+ else
+ {
+ fprint_dbus_device_complete_enroll_stop (dbus_dev, invocation);
+ priv->current_action = ACTION_NONE;
+ }
+
+ return TRUE;
+}
+static gboolean
+fprint_device_list_enrolled_fingers (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation,
+ const char *username)
+{
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(GPtrArray) ret = NULL;
+ g_autoptr(GSList) prints = NULL;
+ GSList *item;
+ const char *sender;
+ const char *user;
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ _fprint_device_add_client (rdev, sender);
+
+ user = g_object_get_qdata (G_OBJECT (invocation), quark_auth_user);
+ g_assert (user);
+ prints = store.discover_prints (priv->dev, user);
+
+ if (!prints)
+ {
+ g_dbus_method_invocation_return_error_literal (invocation,
+ FPRINT_ERROR,
+ FPRINT_ERROR_NO_ENROLLED_PRINTS,
+ "Failed to discover prints");
+ return TRUE;
+ }
+
+ ret = g_ptr_array_new ();
+ for (item = prints; item; item = item->next)
+ {
+ FpFinger finger = GPOINTER_TO_UINT (item->data);
+ g_ptr_array_add (ret, (char *) fp_finger_to_name (finger));
+ }
+ g_ptr_array_add (ret, NULL);
+
+ fprint_dbus_device_complete_list_enrolled_fingers (dbus_dev,
+ invocation, (const gchar *const *) ret->pdata);
+
+ return TRUE;
}
static void
-_fprint_device_add_client (FprintDevice *rdev, const char *sender)
+delete_enrolled_fingers (FprintDevice *rdev, const char *user)
{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- guint id;
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ guint i;
+
+ g_debug ("Deleting enrolled fingers for user %s", user);
- id = GPOINTER_TO_UINT (g_hash_table_lookup (priv->clients, sender));
- if (id == 0) {
- id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
- sender,
- G_BUS_NAME_WATCHER_FLAGS_NONE,
- NULL,
- (GBusNameVanishedCallback) _fprint_device_client_vanished,
- rdev,
- NULL);
- g_hash_table_insert (priv->clients, g_strdup (sender), GUINT_TO_POINTER(id));
- g_object_notify (G_OBJECT (rdev), "in-use");
- }
-}
-
-static void dev_open_cb(FpDevice *dev, GAsyncResult *res, void *user_data)
-{
- g_autoptr(GError) error = NULL;
- FprintDevice *rdev = user_data;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- DBusGMethodInvocation *context = g_steal_pointer(&priv->session->context);
-
- if (!fp_device_open_finish (dev, res, &error)) {
- g_autoptr(GError) dbus_error = NULL;
-
- dbus_error = g_error_new (FPRINT_ERROR,
- FPRINT_ERROR_INTERNAL,
- "Open failed with error: %s", error->message);
- dbus_g_method_return_error(context, dbus_error);
- g_clear_pointer(&priv->session, session_data_free);
- return;
- }
-
- g_debug("claimed device %d", priv->id);
-
- dbus_g_method_return(context);
-}
-
-static void fprint_device_claim(FprintDevice *rdev,
- const char *username,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
- char *sender, *user;
-
- /* Is it already claimed? */
- if (priv->session) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
- "Device was already claimed");
- dbus_g_method_return_error(context, error);
- g_error_free(error);
- return;
- }
-
- g_assert_null(priv->session);
-
- sender = NULL;
- user = _fprint_device_check_for_username (rdev,
- context,
- username,
- &sender,
- &error);
- if (user == NULL) {
- g_free (sender);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_actions (rdev, context,
- "net.reactivated.fprint.device.verify",
- "net.reactivated.fprint.device.enroll",
- &error) == FALSE) {
- g_free (sender);
- g_free (user);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- _fprint_device_add_client (rdev, sender);
-
- priv->session = g_new0(SessionData, 1);
- priv->session->context = context;
- priv->session->username = user;
- priv->session->sender = sender;
-
- g_debug ("user '%s' claiming the device: %d", priv->session->username, priv->id);
-
- fp_device_open (priv->dev, NULL, (GAsyncReadyCallback) dev_open_cb, rdev);
-}
-
-static void dev_close_cb(FpDevice *dev, GAsyncResult *res, void *user_data)
-{
- g_autoptr(GError) error = NULL;
- FprintDevice *rdev = user_data;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- g_autoptr(SessionData) session = g_steal_pointer(&priv->session);
- DBusGMethodInvocation *context = g_steal_pointer(&session->context);
-
- if (!fp_device_close_finish (dev, res, &error)) {
- g_autoptr(GError) dbus_error = NULL;
-
- dbus_error = g_error_new (FPRINT_ERROR,
- FPRINT_ERROR_INTERNAL,
- "Release failed with error: %s", error->message);
- dbus_g_method_return_error(context, dbus_error);
- return;
- }
-
- g_debug("released device %d", priv->id);
-
- dbus_g_method_return(context);
-}
-
-static void fprint_device_release(FprintDevice *rdev,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free(error);
- return;
- }
-
- /* People that can claim can also release */
- if (_fprint_device_check_polkit_for_actions (rdev, context,
- "net.reactivated.fprint.device.verify",
- "net.reactivated.fprint.device.enroll",
- &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free(error);
- return;
- }
-
- priv->session->context = context;
- fp_device_close (priv->dev, NULL, (GAsyncReadyCallback) dev_close_cb, rdev);
-}
-
-static void verify_cb(FpDevice *dev, GAsyncResult *res, void *user_data)
-{
- g_autoptr(GError) error = NULL;
- FprintDevice *rdev = user_data;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- gboolean success;
- const char *name;
- gboolean match;
-
- success = fp_device_verify_finish (dev, res, &match, NULL, &error);
- g_assert (!!success == !error);
- name = verify_result_to_name (match, error);
-
- g_debug("verify_cb: result %s", name);
-
- set_disconnected (priv, name);
-
- /* Automatically restart the operation for retry failures */
- if (error && error->domain == FP_DEVICE_RETRY) {
- g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, FALSE);
-
- /* TODO: Support early match result callback from libfprint */
- fp_device_verify (priv->dev,
- priv->verify_data,
- priv->current_cancellable,
- NULL, NULL, NULL,
- (GAsyncReadyCallback) verify_cb,
- rdev);
- } else {
- g_clear_object (&priv->verify_data);
- g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, TRUE);
-
- if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Device reported an error during verify: %s", error->message);
-
- /* Return the cancellation or reset action right away if vanished. */
- if (priv->current_cancel_context) {
- dbus_g_method_return(priv->current_cancel_context);
- priv->current_cancel_context = NULL;
- priv->current_action = ACTION_NONE;
- } else if (g_cancellable_is_cancelled (priv->current_cancellable)) {
- priv->current_action = ACTION_NONE;
- }
-
- g_clear_object (&priv->current_cancellable);
- }
-}
-
-static void identify_cb(FpDevice *dev, GAsyncResult *res, void *user_data)
-{
- g_autoptr(GError) error = NULL;
- FprintDevice *rdev = user_data;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- const char *name;
- gboolean success;
- FpPrint *match;
-
- success = fp_device_identify_finish (dev, res, &match, NULL, &error);
- g_assert (!!success == !error);
- name = verify_result_to_name (match != NULL, error);
-
- g_debug("verify_cb: result %s", name);
-
- set_disconnected (priv, name);
-
- /* Automatically restart the operation for retry failures */
- if (error && error->domain == FP_DEVICE_RETRY) {
- g_signal_emit (rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, FALSE);
-
- /* TODO: Support early match result callback from libfprint */
- fp_device_identify (priv->dev,
- priv->identify_data,
- priv->current_cancellable,
- NULL, NULL, NULL,
- (GAsyncReadyCallback) identify_cb,
- rdev);
- } else {
- g_clear_pointer (&priv->identify_data, g_ptr_array_unref);
- g_signal_emit (rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, TRUE);
-
- if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Device reported an error during identify: %s", error->message);
-
- /* Return the cancellation or reset action right away if vanished. */
- if (priv->current_cancel_context) {
- dbus_g_method_return(priv->current_cancel_context);
- priv->current_cancel_context = NULL;
- priv->current_action = ACTION_NONE;
- } else if (g_cancellable_is_cancelled (priv->current_cancellable)) {
- priv->current_action = ACTION_NONE;
- }
-
- g_clear_object (&priv->current_cancellable);
- }
-}
-
-static void fprint_device_verify_start(FprintDevice *rdev,
- const char *finger_name, DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- g_autoptr(GPtrArray) gallery = NULL;
- g_autoptr(FpPrint) print = NULL;
- g_autoptr(GError) error = NULL;
- guint finger_num = finger_name_to_num (finger_name);
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- return;
- }
-
- if (priv->current_action != ACTION_NONE) {
- if (priv->current_action == ACTION_ENROLL) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
- "Enrollment in progress");
- } else {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
- "Verification already in progress");
- }
- dbus_g_method_return_error(context, error);
- return;
- }
-
- if (finger_num == -1) {
- GSList *prints;
-
- prints = store.discover_prints(priv->dev, priv->session->username);
- if (prints == NULL) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
- "No fingerprints enrolled");
- dbus_g_method_return_error(context, error);
- return;
- }
- if (fp_device_supports_identify (priv->dev)) {
- GSList *l;
-
- gallery = g_ptr_array_new_with_free_func (g_object_unref);
-
- for (l = prints; l != NULL; l = l->next) {
- g_debug ("adding finger %d to the gallery", GPOINTER_TO_INT (l->data));
- store.print_data_load(priv->dev, GPOINTER_TO_INT (l->data),
- priv->session->username, &print);
-
- if (print)
- g_ptr_array_add (gallery, g_steal_pointer (&print));
- }
- } else {
- finger_num = GPOINTER_TO_INT (prints->data);
- }
- g_slist_free(prints);
- }
-
- if (fp_device_supports_identify (priv->dev) && finger_num == -1) {
- if (gallery->len == 0) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
- "No fingerprints on that device");
- dbus_g_method_return_error(context, error);
- return;
- }
- priv->current_action = ACTION_IDENTIFY;
-
- g_debug ("start identification device %d", priv->id);
- priv->current_cancellable = g_cancellable_new ();
- priv->identify_data = g_ptr_array_ref (gallery);
- /* TODO: Support early match result callback from libfprint */
- fp_device_identify (priv->dev, gallery, priv->current_cancellable,
- NULL, NULL, NULL,
- (GAsyncReadyCallback) identify_cb, rdev);
- } else {
- priv->current_action = ACTION_VERIFY;
-
- g_debug("start verification device %d finger %d", priv->id, finger_num);
-
- store.print_data_load(priv->dev, finger_num,
- priv->session->username, &print);
-
- if (!print) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
- "No such print %d", finger_num);
- dbus_g_method_return_error(context, error);
- return;
- }
-
- priv->current_cancellable = g_cancellable_new ();
- priv->verify_data = g_object_ref (print);
- /* TODO: Support early match result callback from libfprint */
- fp_device_verify (priv->dev, print, priv->current_cancellable,
- NULL, NULL, NULL,
- (GAsyncReadyCallback) verify_cb, rdev);
- }
-
- /* Emit VerifyFingerSelected telling the front-end which finger
- * we selected for auth */
- g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
- 0, finger_num_to_name (finger_num));
-
- dbus_g_method_return(context);
-}
-
-static void fprint_device_verify_stop(FprintDevice *rdev,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free(error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free(error);
- return;
- }
-
- if (priv->current_action == ACTION_NONE) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
- "No verification in progress");
- dbus_g_method_return_error(context, error);
- g_error_free (error);
- return;
- }
-
- if (priv->current_cancellable) {
- /* We return only when the action was cancelled */
- g_cancellable_cancel (priv->current_cancellable);
- priv->current_cancel_context = context;
- } else {
- dbus_g_method_return (context);
- priv->current_action = ACTION_NONE;
- }
-}
-
-static void enroll_progress_cb(FpDevice *dev,
- gint completed_stages,
- FpPrint *print,
- gpointer user_data,
- GError *error)
-{
- FprintDevice *rdev = user_data;
- const char *name = enroll_result_to_name (FALSE, FALSE, error);
-
- g_debug("enroll_stage_cb: result %s", name);
-
- if (completed_stages < fp_device_get_nr_enroll_stages (dev))
- g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, FALSE);
-}
-
-static gboolean try_delete_print(FprintDevice *rdev)
-{
- g_autoptr(GError) error = NULL;
- g_autoptr(GPtrArray) device_prints = NULL;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GSList *users, *user;
-
- device_prints = fp_device_list_prints_sync (priv->dev, NULL, &error);
- if (!device_prints) {
- g_warning ("Failed to query prints: %s", error->message);
- return FALSE;
- }
-
- g_debug ("Device has %d prints stored", device_prints->len);
-
- users = store.discover_users();
-
- for (user = users; user; user = user->next) {
- const char *username = user->data;
- GSList *fingers, *finger;
-
- fingers = store.discover_prints (priv->dev, username);
-
- for (finger = fingers; finger; finger = finger->next) {
- g_autoptr(FpPrint) print = NULL;
- guint index;
-
- store.print_data_load (priv->dev,
- GPOINTER_TO_INT (fingers->data),
- username,
- &print);
-
- if (!print)
- continue;
-
- if (!g_ptr_array_find_with_equal_func (device_prints,
- print,
- (GEqualFunc) fp_print_equal,
- &index))
- continue;
-
- /* Found an equal print, remove it */
- g_ptr_array_remove_index (device_prints, index);
- }
-
- g_slist_free (fingers);
- }
-
- g_slist_free_full (users, g_free);
-
- g_debug ("Device has %d prints stored that we do not need", device_prints->len);
- if (device_prints->len == 0)
- return FALSE;
-
- /* Just delete the first print in the list at this point.
- * We could be smarter and fetch some more metadata. */
- fp_device_delete_print_sync (priv->dev,
- g_ptr_array_index (device_prints, 0),
- NULL,
- &error);
-
- if (error) {
- g_warning ("Failed to garbage collect a print: %s", error->message);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static FpPrint*
-fprint_device_create_enroll_template(FprintDevice *rdev, gint finger_num)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- FpPrint *template = NULL;
- GDateTime *datetime = NULL;
- GDate *date = NULL;
- gint year, month, day;
-
- template = fp_print_new (priv->dev);
- fp_print_set_finger (template, finger_num);
- fp_print_set_username (template, priv->session->username);
- datetime = g_date_time_new_now_local ();
- g_date_time_get_ymd (datetime, &year, &month, &day);
- date = g_date_new_dmy (day, month, year);
- fp_print_set_enroll_date (template, date);
- g_date_free (date);
- g_date_time_unref (datetime);
-
- return template;
-}
-
-static void enroll_cb(FpDevice *dev, GAsyncResult *res, void *user_data)
-{
- g_autoptr(GError) error = NULL;
- FprintDevice *rdev = user_data;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- g_autoptr(FpPrint) print = NULL;
- const char *name;
-
- print = fp_device_enroll_finish (dev, res, &error);
-
- /* We need to special case the issue where the on device storage
- * is completely full. In that case, we check whether we can delete
- * a print that is not coming from us; assuming it is from an old
- * installation.
- * We do this synchronously, which is not great but should be good
- * enough. */
- if (g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_FULL)) {
- g_debug ("Device storage is full, trying to garbage collect old prints");
- if (try_delete_print (rdev)) {
- /* Success? Then restart the operation */
- fp_device_enroll (priv->dev,
- fprint_device_create_enroll_template (rdev, priv->enroll_data),
- priv->current_cancellable,
- enroll_progress_cb,
- rdev,
- NULL,
- (GAsyncReadyCallback) enroll_cb,
- rdev);
- return;
- }
- }
-
- name = enroll_result_to_name (TRUE, print != NULL, error);
-
- g_debug ("enroll_cb: result %s", name);
-
- if (print) {
- int r;
- r = store.print_data_save(print);
- if (r < 0)
- name = "enroll-failed";
- }
-
- set_disconnected (priv, name);
-
- g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, TRUE);
-
- if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
- g_warning ("Device reported an error during enroll: %s", error->message);
-
- /* Return the cancellation or reset action right away if vanished. */
- if (priv->current_cancel_context) {
- dbus_g_method_return(priv->current_cancel_context);
- priv->current_cancel_context = NULL;
- priv->current_action = ACTION_NONE;
- } else if (g_cancellable_is_cancelled (priv->current_cancellable)) {
- priv->current_action = ACTION_NONE;
- }
- g_clear_object (&priv->current_cancellable);
-}
-
-
-static void fprint_device_enroll_start(FprintDevice *rdev,
- const char *finger_name, DBusGMethodInvocation *context)
-{
- g_autoptr(GError) error = NULL;
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- int finger_num = finger_name_to_num (finger_name);
-
- if (finger_num == -1) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
- "Invalid finger name");
- dbus_g_method_return_error(context, error);
- return;
- }
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- return;
- }
-
- if (priv->current_action != ACTION_NONE) {
- if (priv->current_action == ACTION_ENROLL) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
- "Enrollment already in progress");
- } else {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
- "Verification in progress");
- }
- dbus_g_method_return_error(context, error);
- return;
- }
-
- g_debug("start enrollment device %d finger %d", priv->id, finger_num);
-
- priv->current_cancellable = g_cancellable_new ();
- priv->enroll_data = finger_num;
- fp_device_enroll (priv->dev,
- fprint_device_create_enroll_template (rdev, priv->enroll_data),
- priv->current_cancellable,
- enroll_progress_cb,
- rdev,
- NULL,
- (GAsyncReadyCallback) enroll_cb,
- rdev);
-
- priv->current_action = ACTION_ENROLL;
-
- dbus_g_method_return(context);
-}
-
-static void fprint_device_enroll_stop(FprintDevice *rdev,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- if (priv->current_action != ACTION_ENROLL) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
- "No enrollment in progress");
- dbus_g_method_return_error(context, error);
- g_error_free (error);
- return;
- }
-
- if (priv->current_cancellable) {
- /* We return only when the action was cancelled */
- g_cancellable_cancel (priv->current_cancellable);
- priv->current_cancel_context = context;
- } else {
- dbus_g_method_return (context);
- priv->current_action = ACTION_NONE;
- }
-}
-
-static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
- const char *username,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
- GSList *prints;
- GSList *item;
- GPtrArray *ret;
- char *user, *sender;
-
- user = _fprint_device_check_for_username (rdev,
- context,
- username,
- NULL,
- &error);
- if (user == NULL) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
- g_free (user);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- sender = dbus_g_method_get_sender (context);
- _fprint_device_add_client (rdev, sender);
- g_free (sender);
-
- prints = store.discover_prints(priv->dev, user);
- g_free (user);
- if (!prints) {
- g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
- "Failed to discover prints");
- dbus_g_method_return_error(context, error);
- g_error_free (error);
- return;
- }
-
- ret = g_ptr_array_new ();
- for (item = prints; item; item = item->next) {
- int finger_num = GPOINTER_TO_INT (item->data);
- g_ptr_array_add (ret, g_strdup (finger_num_to_name (finger_num)));
- }
- g_ptr_array_add (ret, NULL);
-
- g_slist_free(prints);
-
- dbus_g_method_return(context, g_ptr_array_free (ret, FALSE));
-}
-
-static void delete_enrolled_fingers(FprintDevice *rdev, const char *user)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- guint i;
-
- /* First try deleting the print from the device, we don't consider it
- * fatal if this does not work. */
- if (fp_device_has_storage (priv->dev)) {
- g_autoptr(GSList) prints = NULL;
- GSList *l;
-
- prints = store.discover_prints(priv->dev, user);
-
- for (l = prints; l != NULL; l = l->next) {
- g_autoptr(FpPrint) print = NULL;
-
- store.print_data_load(priv->dev,
- GPOINTER_TO_INT (l->data),
- user,
- &print);
-
- if (print) {
- g_autoptr(GError) error = NULL;
-
- if (!fp_device_delete_print_sync (priv->dev, print, NULL, &error)) {
- g_warning ("Error deleting print from device: %s", error->message);
- g_warning ("This might indicate an issue in the libfprint driver or in the fingerprint device.");
- }
- }
- }
- }
-
- for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++) {
- store.print_data_delete(priv->dev, i, user);
- }
+ /* First try deleting the print from the device, we don't consider it
+ * fatal if this does not work. */
+ if (fp_device_has_storage (priv->dev))
+ {
+ g_autoptr(GSList) prints = NULL;
+ GSList *l;
+
+ prints = store.discover_prints (priv->dev, user);
+
+ for (l = prints; l != NULL; l = l->next)
+ {
+ g_autoptr(FpPrint) print = NULL;
+
+ store.print_data_load (priv->dev,
+ GPOINTER_TO_UINT (l->data),
+ user,
+ &print);
+
+ if (print)
+ {
+ g_autoptr(GError) error = NULL;
+
+ if (!fp_device_delete_print_sync (priv->dev, print, NULL, &error))
+ {
+ g_warning ("Error deleting print from device: %s", error->message);
+ g_warning ("This might indicate an issue in the libfprint driver or in the fingerprint device.");
+ }
+ }
+ }
+ }
+
+ for (i = FP_FINGER_FIRST; i <= FP_FINGER_LAST; i++)
+ store.print_data_delete (priv->dev, i, user);
}
#ifdef __linux__
-static void log_offending_client(DBusGMethodInvocation *context)
+static void
+log_offending_client_cb (GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (object);
+
+ g_autoptr(GVariant) ret = NULL;
+ g_autofree char *path = NULL;
+ g_autofree char *content = NULL;
+ guint pid = 0;
+
+ ret = g_dbus_connection_call_finish (connection, res, NULL);
+
+ if (!ret)
+ return;
+
+ g_variant_get (ret, "(u)", &pid);
+ path = g_strdup_printf ("/proc/%u/comm", pid);
+ if (g_file_get_contents (path, &content, NULL, NULL))
+ {
+ g_strchomp (content);
+ g_warning ("Offending API user is %s", content);
+ }
+}
+
+static void
+log_offending_client (GDBusMethodInvocation *invocation)
{
- g_autofree char *sender = NULL;
- g_autofree char *path = NULL;
- g_autofree char *content = NULL;
- DBusGProxy *proxy = NULL;
- guint pid = 0;
-
- sender = dbus_g_method_get_sender(context);
- proxy = dbus_g_proxy_new_for_name (fprintd_dbus_conn,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus");
-
- if (!dbus_g_proxy_call(proxy,
- "GetConnectionUnixProcessID",
- NULL,
- G_TYPE_STRING,
- sender,
- G_TYPE_INVALID,
- G_TYPE_UINT,
- &pid,
- G_TYPE_INVALID)) {
- goto out;
- }
-
- path = g_strdup_printf ("/proc/%u/comm", pid);
- if (g_file_get_contents (path, &content, NULL, NULL)) {
- g_strchomp (content);
- g_warning ("Offending API user is %s", content);
- }
+ const char *sender;
+ GDBusConnection *connection;
+
+ connection = g_dbus_method_invocation_get_connection (invocation);
+ sender = g_dbus_method_invocation_get_sender (invocation);
-out:
- g_clear_object (&proxy);
+ g_dbus_connection_call (connection,
+ "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "GetConnectionUnixProcessID",
+ g_variant_new ("(s)", sender),
+ NULL, G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, log_offending_client_cb, NULL);
}
#endif
-static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
- const char *username,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
- char *user, *sender;
- gboolean opened;
+static gboolean
+fprint_device_delete_enrolled_fingers (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation,
+ const char *username)
+{
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autofree char *user = NULL;
+ const char *sender;
+ gboolean opened;
- g_warning ("The API user should be updated to use DeleteEnrolledFingers2 method!");
+ g_warning ("The API user should be updated to use DeleteEnrolledFingers2 method!");
#ifdef __linux__
- log_offending_client(context);
+ log_offending_client (invocation);
#endif
- user = _fprint_device_check_for_username (rdev,
- context,
- username,
- NULL,
- &error);
- if (user == NULL) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
- g_free (user);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- /* Return error for anything but FPRINT_ERROR_CLAIM_DEVICE */
- if (!g_error_matches (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE)) {
- dbus_g_method_return_error (context, error);
- return;
- }
-
- g_clear_error (&error);
- opened = FALSE;
- } else {
- opened = TRUE;
- }
-
- sender = dbus_g_method_get_sender (context);
- _fprint_device_add_client (rdev, sender);
- g_free (sender);
-
- if (!opened && fp_device_has_storage (priv->dev))
- fp_device_open_sync (priv->dev, NULL, NULL);
-
- delete_enrolled_fingers (rdev, user);
-
- if (!opened && fp_device_has_storage (priv->dev))
- fp_device_close_sync (priv->dev, NULL, NULL);
-
- g_free (user);
-
- dbus_g_method_return(context);
-}
-
-static void fprint_device_delete_enrolled_fingers2(FprintDevice *rdev,
- DBusGMethodInvocation *context)
-{
- FprintDevicePrivate *priv = fprint_device_get_instance_private(rdev);
- GError *error = NULL;
-
- if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- return;
- }
-
- if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
+ if (!can_start_action (rdev, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ priv->current_action = ACTION_DELETE;
+ action_unset = rdev;
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ /* Return error for anything but FPRINT_ERROR_CLAIM_DEVICE */
+ if (!g_error_matches (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE))
+ {
+ g_dbus_method_invocation_return_gerror (invocation,
+ error);
+ return TRUE;
+ }
+
+ opened = FALSE;
+ }
+ else
+ {
+ opened = TRUE;
+ }
+
+ sender = g_dbus_method_invocation_get_sender (invocation);
+ _fprint_device_add_client (rdev, sender);
+
+ if (!opened && fp_device_has_storage (priv->dev))
+ fp_device_open_sync (priv->dev, NULL, NULL);
+
+ user = g_object_steal_qdata (G_OBJECT (invocation), quark_auth_user);
+ g_assert (user);
+ g_assert (g_str_equal (username, "") || g_str_equal (user, username));
+
+ delete_enrolled_fingers (rdev, user);
+
+ if (!opened && fp_device_has_storage (priv->dev))
+ fp_device_close_sync (priv->dev, NULL, NULL);
+
+ fprint_dbus_device_complete_delete_enrolled_fingers (dbus_dev,
+ invocation);
+ return TRUE;
+}
- delete_enrolled_fingers (rdev, priv->session->username);
+static gboolean
+fprint_device_delete_enrolled_fingers2 (FprintDBusDevice *dbus_dev,
+ GDBusMethodInvocation *invocation)
+{
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_autoptr(SessionData) session = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FprintDeviceActionUnset) action_unset = NULL;
+
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ if (!can_start_action (rdev, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
+
+ priv->current_action = ACTION_DELETE;
+ action_unset = rdev;
+
+ session = session_data_get (priv);
+
+ delete_enrolled_fingers (rdev, session->username);
+
+ fprint_dbus_device_complete_delete_enrolled_fingers2 (dbus_dev,
+ invocation);
+ return TRUE;
+}
+
+static gboolean
+handle_unauthorized_access (FprintDevice *rdev,
+ GDBusMethodInvocation *invocation,
+ GError *error)
+{
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+
+ g_assert (error);
+
+ g_warning ("Client %s not authorized to call method '%s' for device %s: %s",
+ g_dbus_method_invocation_get_sender (invocation),
+ g_dbus_method_invocation_get_method_name (invocation),
+ fp_device_get_name (priv->dev),
+ error->message);
+ g_dbus_method_invocation_return_gerror (invocation, error);
+
+ return FALSE;
+}
+
+static gboolean
+action_authorization_handler (GDBusInterfaceSkeleton *interface,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ FprintDBusDevice *dbus_dev = FPRINT_DBUS_DEVICE (interface);
+ FprintDevice *rdev = FPRINT_DEVICE (dbus_dev);
+ FprintDevicePrivate *priv = fprint_device_get_instance_private (rdev);
+ FprintDevicePermission required_perms;
+ gboolean needs_user_auth = FALSE;
+
+ g_autoptr(GError) error = NULL;
+ const gchar *method_name;
+
+ method_name = g_dbus_method_invocation_get_method_name (invocation);
+
+ g_debug ("Requesting device '%s' authorization for method %s from %s",
+ fp_device_get_name (priv->dev), method_name,
+ g_dbus_method_invocation_get_sender (invocation));
+
+ if (g_str_equal (method_name, "Claim"))
+ needs_user_auth = TRUE;
+ else if (g_str_equal (method_name, "DeleteEnrolledFingers"))
+ needs_user_auth = TRUE;
+ else if (g_str_equal (method_name, "ListEnrolledFingers"))
+ needs_user_auth = TRUE;
+
+ /* This is just a quick check in order to avoid authentication if
+ * the user cannot make the call at this time anyway.
+ * The method handler itself is required to check again! */
+ if (!_fprint_device_check_claimed (rdev, invocation, &error))
+ return handle_unauthorized_access (rdev, invocation, error);
+
+ if (needs_user_auth &&
+ !fprintd_device_authorize_user (rdev, invocation, &error))
+ return handle_unauthorized_access (rdev, invocation, error);
+
+ required_perms = get_permissions_for_invocation (invocation);
+
+ /* This may possibly block the invocation till the user has not
+ * provided an authentication method, so other calls could arrive */
+ if (!fprint_device_check_polkit_for_permissions (rdev, invocation,
+ required_perms,
+ &error))
+ return handle_unauthorized_access (rdev, invocation, error);
+
+ g_debug ("Authorization granted to %s to call method '%s' for device %s!",
+ fp_device_get_name (priv->dev),
+ g_dbus_method_invocation_get_method_name (invocation),
+ g_dbus_method_invocation_get_sender (invocation));
- dbus_g_method_return(context);
+ return TRUE;
}
+static void
+fprint_device_dbus_skeleton_iface_init (FprintDBusDeviceIface *iface)
+{
+ iface->handle_claim = fprint_device_claim;
+ iface->handle_delete_enrolled_fingers = fprint_device_delete_enrolled_fingers;
+ iface->handle_delete_enrolled_fingers2 = fprint_device_delete_enrolled_fingers2;
+ iface->handle_enroll_start = fprint_device_enroll_start;
+ iface->handle_enroll_stop = fprint_device_enroll_stop;
+ iface->handle_list_enrolled_fingers = fprint_device_list_enrolled_fingers;
+ iface->handle_release = fprint_device_release;
+ iface->handle_verify_start = fprint_device_verify_start;
+ iface->handle_verify_stop = fprint_device_verify_stop;
+}
diff -Nru fprintd-1.90.1/src/device.xml fprintd-1.90.9/src/device.xml
--- fprintd-1.90.1/src/device.xml 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/device.xml 2021-01-13 12:23:24.000000000 +0000
@@ -12,9 +12,6 @@
-
-
PolicyKit integration
@@ -282,8 +279,6 @@
An array of strings representing the enrolled fingerprints. See Fingerprint names.
-
-
@@ -304,8 +299,6 @@
The username for whom to delete the enrolled fingerprints. See Usernames.
-
-
@@ -327,8 +320,6 @@
-
-
@@ -348,8 +339,6 @@
The username for whom to claim the device. See Usernames.
-
-
@@ -368,8 +357,6 @@
-
-
@@ -390,8 +377,6 @@
A string representing the finger to verify. See Fingerprint names.
-
-
@@ -415,8 +400,6 @@
-
-
@@ -486,8 +469,6 @@
Fingerprint names.
Note that "any" is not a valid finger name for this method.
-
-
@@ -511,8 +492,6 @@
-
-
diff -Nru fprintd-1.90.1/src/file_storage.c fprintd-1.90.9/src/file_storage.c
--- fprintd-1.90.1/src/file_storage.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/file_storage.c 2021-01-13 12:23:24.000000000 +0000
@@ -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.
@@ -42,260 +42,319 @@
#define FILE_STORAGE_PATH "/var/lib/fprint"
#define DIR_PERMS 0700
-static const char *get_storage_path(void)
+static char *storage_path = NULL;
+
+static const char *
+get_storage_path (void)
{
- const char *path;
+ const char *path = NULL;
- /* set by systemd >= 240 to an absolute path
- * taking into account the StateDirectory
- * unit file setting */
- path = g_getenv ("STATE_DIRECTORY");
- if (path != NULL)
- return path;
+ if (storage_path != NULL)
+ return storage_path;
- return FILE_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]);
+ }
+ else if (*path)
+ {
+ storage_path = g_strdup (path);
+ }
+ }
+
+ if (storage_path == NULL)
+ storage_path = g_strdup (FILE_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)
{
- char *dirpath;
- 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);
- g_free(dirpath);
- 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;
- }
+ 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;
+ }
- //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_debug ("file_storage_print_data_save(): print saved to %s", path);
- return 0;
+ 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;
- 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)) {
- g_object_unref (new);
- 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 = 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);
+
+ path = get_path_to_print_dscv (dev, finger, base_store);
- base_store = file_storage_get_basestore_for_username(username);
+ if (!g_file_test (path, G_FILE_TEST_EXISTS))
+ return 0;
- 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));
- 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);
- /* FIXME: cleanup empty directory */
- return g_unlink(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);
- GDir *dir = g_dir_open(devpath, 0, &err);
- if (!dir) {
- g_debug("scan_dev_storedir(): opendir(\"%s\") failed: %s", devpath, err->message);
- return list;
- }
+ if (!dir)
+ {
+ g_debug ("scan_dev_storedir(): opendir(\"%s\") failed: %s", devpath, err->message);
+ return list;
+ }
- while ((ent = g_dir_read_name(dir))) {
- /* ent is an 1 hex character fp_finger code */
- guint64 val;
- gchar *endptr;
+ while ((ent = g_dir_read_name (dir)))
+ {
+ /* ent is an 1 hex character fp_finger code */
+ guint64 val;
+ gchar *endptr;
- if (*ent == 0 || strlen(ent) != 1)
- continue;
+ if (*ent == 0 || strlen (ent) != 1)
+ continue;
- 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;
- }
+ 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;
+ }
- list = g_slist_prepend(list, GINT_TO_POINTER(val));
- }
+ list = g_slist_prepend (list, GUINT_TO_POINTER (val));
+ }
- g_dir_close(dir);
- return list;
+ 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)
{
- /* Nothing to do */
- return 0;
+ g_clear_pointer (&storage_path, g_free);
+ return 0;
}
diff -Nru fprintd-1.90.1/src/file_storage.h fprintd-1.90.9/src/file_storage.h
--- fprintd-1.90.1/src/file_storage.h 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/file_storage.h 2021-01-13 12:23:24.000000000 +0000
@@ -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);
diff -Nru fprintd-1.90.1/src/fprintd.h fprintd-1.90.9/src/fprintd.h
--- fprintd-1.90.1/src/fprintd.h 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/fprintd.h 2021-01-13 12:23:24.000000000 +0000
@@ -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,56 +20,89 @@
#pragma once
#include
-#include
+#include
#include
+#include "fprintd-enums.h"
+#include "fprintd-dbus.h"
/* General */
#define TIMEOUT 30
#define FPRINT_SERVICE_NAME "net.reactivated.Fprint"
+#define FPRINT_SERVICE_PATH "/net/reactivated/Fprint"
/* Errors */
-GQuark fprint_error_quark(void);
-GType fprint_error_get_type(void);
+GQuark fprint_error_quark (void);
-#define FPRINT_ERROR fprint_error_quark()
-#define FPRINT_TYPE_ERROR fprint_error_get_type()
-#define FPRINT_ERROR_DBUS_INTERFACE "net.reactivated.Fprint.Error"
+#define FPRINT_ERROR fprint_error_quark ()
typedef enum {
- FPRINT_ERROR_CLAIM_DEVICE, /* developer didn't claim the device */
- FPRINT_ERROR_ALREADY_IN_USE, /* device is already claimed by somebody else */
- FPRINT_ERROR_INTERNAL, /* internal error occurred */
- FPRINT_ERROR_PERMISSION_DENIED, /* PolicyKit refused the action */
- FPRINT_ERROR_NO_ENROLLED_PRINTS, /* No prints are enrolled */
- FPRINT_ERROR_NO_ACTION_IN_PROGRESS, /* No actions currently in progress */
- FPRINT_ERROR_INVALID_FINGERNAME, /* the finger name passed was invalid */
- FPRINT_ERROR_NO_SUCH_DEVICE, /* device does not exist */
+ /* 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 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 >*/
+} 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(gboolean no_timeout);
+FprintManager *fprint_manager_new (GDBusConnection *connection,
+ gboolean no_timeout);
/* Device */
-#define FPRINT_TYPE_DEVICE (fprint_device_get_type())
-G_DECLARE_FINAL_TYPE (FprintDevice, fprint_device, FPRINT, DEVICE, GObject)
-
-struct _FprintDevice {
- GObject parent;
+#define FPRINT_TYPE_DEVICE (fprint_device_get_type ())
+G_DECLARE_FINAL_TYPE (FprintDevice, fprint_device, FPRINT, DEVICE,
+ FprintDBusDeviceSkeleton)
+
+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 */
-/* Binding data included in main.c through server-bindings.h which individual
- * class implementations need to access.
- */
-extern const DBusGObjectInfo dbus_glib_fprint_manager_object_info;
-extern const DBusGObjectInfo dbus_glib_fprint_device_object_info;
+
+/* Some compatibility definitions for older GLib. Copied from from libfprint. */
+#if !GLIB_CHECK_VERSION (2, 57, 0)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
+#else
+/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
+ * the version we depend on currently. */
+#undef G_SOURCE_FUNC
+#endif
+
+#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))
diff -Nru fprintd-1.90.1/src/fprintd-marshal.list fprintd-1.90.9/src/fprintd-marshal.list
--- fprintd-1.90.1/src/fprintd-marshal.list 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/fprintd-marshal.list 1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-VOID:STRING,BOOLEAN
diff -Nru fprintd-1.90.1/src/main.c fprintd-1.90.9/src/main.c
--- fprintd-1.90.1/src/main.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/main.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* fprint D-Bus daemon
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -19,10 +20,11 @@
#include "config.h"
+#include
#include
#include
-#include
+#include
#include
#include
#include
@@ -36,189 +38,185 @@
fp_storage store;
-DBusGConnection *fprintd_dbus_conn = NULL;
static gboolean no_timeout = FALSE;
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;
- char *filename;
+ GModule *module;
+ g_autofree char *filename = NULL;
- filename = g_module_build_path (PLUGINDIR, module_name);
- module = g_module_open (filename, 0);
- g_free (filename);
- 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;
- }
+ 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;
+ }
- g_module_make_resident (module);
+ g_module_make_resident (module);
- return TRUE;
+ return TRUE;
}
static gboolean
load_conf (void)
{
- GKeyFile *file;
- char *filename;
- char *module_name;
- GError *error = NULL;
- gboolean ret;
-
- 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);
- goto bail;
- }
-
- g_free (filename);
- filename = NULL;
-
- module_name = g_key_file_get_string (file, "storage", "type", &error);
- if (module_name == NULL)
- goto bail;
-
- g_key_file_free (file);
-
- if (g_str_equal (module_name, "file")) {
- g_free (module_name);
- set_storage_file ();
- return TRUE;
- }
-
- ret = load_storage_module (module_name);
- g_free (module_name);
-
- return ret;
-
-bail:
- g_key_file_free (file);
- g_free (filename);
- g_error_free (error);
+ g_autofree char *filename = NULL;
+ g_autofree char *module_name = NULL;
+
+ g_autoptr(GKeyFile) file = NULL;
+ g_autoptr(GError) error = 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;
+ }
+
+ module_name = g_key_file_get_string (file, "storage", "type", &error);
+ if (module_name == NULL)
+ return FALSE;
+
+ if (g_str_equal (module_name, "file"))
+ {
+ set_storage_file ();
+ return TRUE;
+ }
- return FALSE;
+ 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;
}
-int main(int argc, char **argv)
+static void
+on_name_acquired (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
{
- GOptionContext *context;
- GMainLoop *loop;
- GError *error = NULL;
- FprintManager *manager;
- DBusGProxy *driver_proxy;
- guint32 request_name_ret;
-
- setlocale (LC_ALL, "");
-
- 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);
-
- if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
- g_warning ("couldn't parse command-line options: %s\n", error->message);
- g_error_free (error);
- return 1;
- }
-
- 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);
- }
-
- /* Obtain a connection to the session bus */
- fprintd_dbus_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
- if (fprintd_dbus_conn == NULL) {
- g_warning("Failed to open connection to bus: %s", error->message);
- return 1;
- }
-
- driver_proxy = dbus_g_proxy_new_for_name(fprintd_dbus_conn,
- DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
-
- /* 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);
-
- g_debug("Launching FprintObject");
-
- /* create the one instance of the Manager object to be shared between
- * all fprintd users */
- manager = fprint_manager_new(no_timeout);
-
- /* Obtain the well-known name after the manager has been initialized.
- * Otherwise a client immediately enumerating the devices will not see
- * any. */
- if (!org_freedesktop_DBus_request_name(driver_proxy, FPRINT_SERVICE_NAME,
- 0, &request_name_ret, &error)) {
- g_warning("Failed to get name: %s", error->message);
- g_object_unref (manager);
- return 1;
- }
+ g_debug ("D-Bus service launched with name: %s", name);
+}
- if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- g_warning ("Got result code %u from requesting name", request_name_ret);
- g_object_unref (manager);
- return 1;
- }
+static void
+on_name_lost (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ GMainLoop *loop = user_data;
- g_debug("D-Bus service launched with name: %s", FPRINT_SERVICE_NAME);
+ g_warning ("Failed to get name: %s", name);
- g_debug("entering main loop");
- g_main_loop_run(loop);
- g_debug("main loop completed");
+ g_main_loop_quit (loop);
+}
- g_object_unref (manager);
+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;
+
+ setlocale (LC_ALL, "");
+
+ 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);
+
+ 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;
+
+ 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;
+ }
+
+ /* 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);
+
+ 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);
+
+ /* 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");
- return 0;
+ return 0;
}
-
diff -Nru fprintd-1.90.1/src/manager.c fprintd-1.90.9/src/manager.c
--- fprintd-1.90.1/src/manager.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/manager.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* /net/reactivated/Fprint/Manager object implementation
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -19,7 +20,6 @@
#include
#include
-#include
#include
#include
#include
@@ -27,251 +27,431 @@
#include "fprintd.h"
-extern DBusGConnection *fprintd_dbus_conn;
-
-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);
-#include "manager-dbus-glue.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);
typedef struct
{
- FpContext *context;
- GSList *dev_registry;
- 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))
-static void fprint_manager_finalize(GObject *object)
+enum {
+ PROP_0,
+ FPRINT_MANAGER_CONNECTION,
+ N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS];
+
+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->context);
- g_slist_free(priv->dev_registry);
+ 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 void fprint_manager_class_init(FprintManagerClass *klass)
+static FprintDevice *
+fprint_dbus_object_skeleton_get_device (FprintDBusObjectSkeleton *object)
{
- dbus_g_object_type_install_info(FPRINT_TYPE_MANAGER,
- &dbus_glib_fprint_manager_object_info);
- dbus_g_error_domain_register (FPRINT_ERROR, FPRINT_ERROR_DBUS_INTERFACE, FPRINT_TYPE_ERROR);
+ FprintDevice *rdev;
- G_OBJECT_CLASS(klass)->finalize = fprint_manager_finalize;
+ g_object_get (object, "device", &rdev, NULL);
+ return rdev;
}
-static gchar *get_device_path(FprintDevice *rdev)
+static void
+fprint_manager_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
{
- return g_strdup_printf("/net/reactivated/Fprint/Device/%d",
- _fprint_device_get_id(rdev));
+ 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;
+ }
}
-static gboolean
-fprint_manager_timeout_cb (FprintManager *manager)
+static void
+fprint_manager_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
{
- //FIXME kill all the devices
- exit(0);
- return FALSE;
+ 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;
+ }
}
static void
-fprint_manager_in_use_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager)
+fprint_manager_class_init (FprintManagerClass *klass)
{
- FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- guint num_devices_used = 0;
- GSList *l;
- gboolean in_use;
-
- if (priv->timeout_id > 0) {
- g_source_remove (priv->timeout_id);
- priv->timeout_id = 0;
- }
- if (priv->no_timeout)
- return;
-
- for (l = priv->dev_registry; l != NULL; l = l->next) {
- FprintDevice *dev = l->data;
-
- g_object_get (G_OBJECT(dev), "in-use", &in_use, NULL);
- if (in_use != FALSE)
- num_devices_used++;
- }
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
- if (num_devices_used == 0)
- priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager);
+ 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);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
}
-static void
-device_added_cb (FprintManager *manager, FpDevice *device, FpContext *context)
+static gchar *
+get_device_path (FprintDevice *rdev)
+{
+ return g_strdup_printf (FPRINT_SERVICE_PATH "/Device/%d",
+ _fprint_device_get_id (rdev));
+}
+
+static gboolean
+fprint_manager_timeout_cb (FprintManager *manager)
{
- FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- FprintDevice *rdev = fprint_device_new(device);
- g_autofree gchar *path = NULL;
-
- g_signal_connect (G_OBJECT(rdev), "notify::in-use",
- G_CALLBACK (fprint_manager_in_use_notified), manager);
-
- priv->dev_registry = g_slist_prepend (priv->dev_registry, rdev);
- path = get_device_path (rdev);
- dbus_g_connection_register_g_object(fprintd_dbus_conn, path,
- G_OBJECT(rdev));
+ //FIXME kill all the devices
+ exit (0);
+ return FALSE;
}
static void
-device_removed_cb (FprintManager *manager, FpDevice *device, FpContext *context)
+fprint_manager_in_use_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager)
{
- FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- GSList *item;
- g_autofree gchar *path = NULL;
+ FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
+ guint num_devices_used = 0;
- for (item = priv->dev_registry; item; item = item->next) {
- FprintDevice *rdev;
- g_autoptr(FpDevice) dev = NULL;
+ g_autolist (GDBusObject) devices = NULL;
+ GList *l;
+ gboolean in_use;
+
+ if (priv->timeout_id > 0)
+ {
+ g_source_remove (priv->timeout_id);
+ priv->timeout_id = 0;
+ }
+ if (priv->no_timeout)
+ return;
+
+ devices = g_dbus_object_manager_get_objects (priv->object_manager);
+
+ for (l = devices; l != NULL; l = l->next)
+ {
+ g_autoptr(FprintDevice) dev = NULL;
+ FprintDBusObjectSkeleton *object = l->data;
+
+ 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++;
+ }
- rdev = item->data;
+ if (num_devices_used == 0)
+ priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager);
+}
- g_object_get (rdev, "dev", &dev, NULL);
- if (dev != device)
- continue;
+static gboolean
+handle_get_devices (FprintManager *manager, GDBusMethodInvocation *invocation,
+ FprintDBusManager *skeleton)
+{
+ g_autoptr(GPtrArray) devices = NULL;
+ g_autoptr(GError) error = NULL;
- priv->dev_registry = g_slist_delete_link (priv->dev_registry, item);
+ 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);
- dbus_g_connection_unregister_g_object(fprintd_dbus_conn, G_OBJECT(rdev));
+ return TRUE;
+}
+
+static gboolean
+handle_get_default_device (FprintManager *manager,
+ GDBusMethodInvocation *invocation,
+ FprintDBusManager *skeleton)
+{
+ const gchar *device;
- g_signal_handlers_disconnect_by_data (rdev, manager);
- g_object_unref (rdev);
+ g_autoptr(GError) error = NULL;
- /* We cannot continue to iterate at this point, but we don't need to either */
- break;
- }
+ if (!fprint_manager_get_default_device (manager, &device, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ return TRUE;
+ }
- /* 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);
+ fprint_dbus_manager_complete_get_default_device (skeleton, invocation,
+ device);
+
+ return TRUE;
}
static void
-fprint_manager_init (FprintManager *manager)
+device_added_cb (FprintManager *manager, FpDevice *device, FpContext *context)
{
- FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
+ FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- priv->context = fp_context_new ();
+ g_autoptr(FprintDBusObjectSkeleton) object = NULL;
+ g_autoptr(FprintDevice) rdev = NULL;
+ g_autofree gchar *path = NULL;
- /* 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);
+ rdev = fprint_device_new (device);
- g_signal_connect_object (priv->context,
- "device-removed",
- (GCallback) device_removed_cb,
- manager,
- G_CONNECT_SWAPPED);
+ g_signal_connect (G_OBJECT (rdev), "notify::in-use",
+ G_CALLBACK (fprint_manager_in_use_notified), manager);
- /* Prepare everything by enumerating all devices. */
- fp_context_enumerate (priv->context);
+ path = get_device_path (rdev);
- dbus_g_connection_register_g_object(fprintd_dbus_conn,
- "/net/reactivated/Fprint/Manager", G_OBJECT(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));
}
-FprintManager *fprint_manager_new(gboolean no_timeout)
+static void
+device_removed_cb (FprintManager *manager, FpDevice *device, FpContext *context)
{
- FprintManagerPrivate *priv;
- GObject *object;
+ FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- object = g_object_new(FPRINT_TYPE_MANAGER, NULL);
- priv = fprint_manager_get_instance_private (FPRINT_MANAGER (object));
- priv->no_timeout = no_timeout;
+ g_autolist (FprintDBusObjectSkeleton) objects = NULL;
+ GList *item;
- if (!priv->no_timeout)
- priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, object);
+ objects = g_dbus_object_manager_get_objects (priv->object_manager);
- return FPRINT_MANAGER (object);
-}
+ for (item = objects; item; item = item->next)
+ {
+ g_autoptr(FprintDevice) rdev = NULL;
+ g_autoptr(FpDevice) dev = NULL;
+ FprintDBusObjectSkeleton *object = item->data;
-static gboolean fprint_manager_get_devices(FprintManager *manager,
- GPtrArray **devices, GError **error)
-{
- FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- GSList *elem;
- GSList *l;
- int num_open;
- GPtrArray *devs;
+ rdev = fprint_dbus_object_skeleton_get_device (object);
+ g_object_get (rdev, "dev", &dev, NULL);
+ if (dev != device)
+ continue;
- elem = g_slist_reverse(g_slist_copy(priv->dev_registry));
- num_open = g_slist_length(elem);
- devs = g_ptr_array_sized_new(num_open);
+ 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)));
- if (num_open > 0) {
- for (l = elem; l != NULL; l = l->next) {
- FprintDevice *rdev = l->data;
- g_ptr_array_add(devs, get_device_path(rdev));
- }
- }
+ g_signal_handlers_disconnect_by_data (rdev, manager);
- g_slist_free(elem);
+ /* We cannot continue to iterate at this point, but we don't need to either */
+ break;
+ }
- *devices = devs;
- return TRUE;
+ /* 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 gboolean fprint_manager_get_default_device(FprintManager *manager,
- const char **device, GError **error)
+static void
+fprint_manager_constructed (GObject *object)
{
- FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
- GSList *elem;;
- int num_open;
+ 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);
+
+ 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_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);
+
+ /* 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);
+
+ /* Prepare everything by enumerating all devices.
+ * This blocks the main loop until the existing devices are enumerated
+ */
+ fp_context_enumerate (priv->context);
- elem = priv->dev_registry;
- num_open = g_slist_length(elem);
+ G_OBJECT_CLASS (fprint_manager_parent_class)->constructed (object);
+}
- if (num_open > 0) {
- *device = get_device_path (g_slist_last (elem)->data);
- return TRUE;
- } else {
- g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_DEVICE,
- "No devices available");
- *device = NULL;
- return FALSE;
- }
+static void
+fprint_manager_init (FprintManager *manager)
+{
}
-GQuark fprint_error_quark(void)
+FprintManager *
+fprint_manager_new (GDBusConnection *connection, gboolean no_timeout)
{
- static GQuark quark = 0;
- if (!quark)
- quark = g_quark_from_static_string("fprintd-error-quark");
- return quark;
+ 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;
+
+ if (!priv->no_timeout)
+ priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, object);
+
+ return FPRINT_MANAGER (object);
}
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-GType
-fprint_error_get_type (void)
+static gboolean
+fprint_manager_get_devices (FprintManager *manager,
+ GPtrArray **devices, GError **error)
{
- static GType etype = 0;
+ FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
+
+ g_autolist (FprintDBusObjectSkeleton) objects = NULL;
+ GList *l;
+ int num_open;
+ GPtrArray *devs;
+
+ objects = g_dbus_object_manager_get_objects (priv->object_manager);
+ objects = g_list_reverse (objects);
+
+ num_open = g_list_length (objects);
+ devs = g_ptr_array_sized_new (num_open);
+
+ if (num_open > 0)
+ {
+ for (l = objects; l != NULL; l = l->next)
+ {
+ g_autoptr(FprintDevice) rdev = NULL;
+ FprintDBusObjectSkeleton *object = l->data;
+ const char *path;
+
+ 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)
+{
+ FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
+
+ g_autolist (FprintDBusObjectSkeleton) objects = NULL;
+ int num_open;
- if (etype == 0) {
- static const GEnumValue values[] =
- {
- ENUM_ENTRY (FPRINT_ERROR_CLAIM_DEVICE, "ClaimDevice"),
- ENUM_ENTRY (FPRINT_ERROR_ALREADY_IN_USE, "AlreadyInUse"),
- ENUM_ENTRY (FPRINT_ERROR_INTERNAL, "Internal"),
- ENUM_ENTRY (FPRINT_ERROR_PERMISSION_DENIED, "PermissionDenied"),
- ENUM_ENTRY (FPRINT_ERROR_NO_ENROLLED_PRINTS, "NoEnrolledPrints"),
- ENUM_ENTRY (FPRINT_ERROR_NO_ACTION_IN_PROGRESS, "NoActionInProgress"),
- ENUM_ENTRY (FPRINT_ERROR_INVALID_FINGERNAME, "InvalidFingername"),
- ENUM_ENTRY (FPRINT_ERROR_NO_SUCH_DEVICE, "NoSuchDevice"),
- { 0, 0, 0 }
- };
- etype = g_enum_register_static ("FprintError", values);
- }
- return etype;
+ objects = g_dbus_object_manager_get_objects (priv->object_manager);
+ num_open = g_list_length (objects);
+
+ 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)
+{
+ static gsize quark = 0;
+
+ if (g_once_init_enter (&quark))
+ {
+ g_autoptr(GEnumClass) errors_enum = NULL;
+ GQuark domain;
+ unsigned i;
+
+ domain = g_quark_from_static_string ("fprintd-error-quark");
+ errors_enum = g_type_class_ref (FPRINT_TYPE_ERROR);
+
+ for (i = 0; i < errors_enum->n_values; ++i)
+ {
+ GEnumValue *value = &errors_enum->values[i];
+
+ g_dbus_error_register_error (domain, value->value,
+ value->value_nick);
+ }
+
+ g_once_init_leave (&quark, domain);
+ }
+ return (GQuark) quark;
}
diff -Nru fprintd-1.90.1/src/manager.xml fprintd-1.90.9/src/manager.xml
--- fprintd-1.90.1/src/manager.xml 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/manager.xml 2021-01-13 12:23:24.000000000 +0000
@@ -5,8 +5,6 @@
]>
-
diff -Nru fprintd-1.90.1/src/meson.build fprintd-1.90.9/src/meson.build
--- fprintd-1.90.1/src/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -1,30 +1,10 @@
-fprintd_marshal = gnome.genmarshal('fprintd-marshal',
- prefix: 'fprintd_marshal',
- sources: 'fprintd-marshal.list',
- valist_marshallers: true,
-)
-
bash = find_program('bash')
-dbus_binding_tool = find_program('dbus-binding-tool')
dbus_interfaces = ['Manager', 'Device']
dbus_interfaces_files = []
-dbus_server_glue_sources = []
foreach interface_name: dbus_interfaces
interface = interface_name.to_lower()
interface_file = interface + '.xml'
- glue_name = interface + '-dbus-glue.h'
- dbus_server_glue_sources += custom_target(glue_name,
- input: interface_file,
- output: glue_name,
- command: [
- dbus_binding_tool,
- '--prefix=fprint_' + interface,
- '--mode=glib-server',
- '--output=@OUTPUT@',
- '@INPUT@',
- ])
-
dbus_interfaces_files += custom_target('dbus_interface_' + interface,
input: interface_file,
output: 'net.reactivated.Fprint.@0@.xml'.format(interface_name),
@@ -34,14 +14,48 @@
)
endforeach
+# NOTE: We should pass "--glib-min-required 2.64" but cannot
+fprintd_dbus_sources_base = gnome.gdbus_codegen('fprintd-dbus',
+ sources: dbus_interfaces_files,
+ autocleanup: 'all',
+ interface_prefix: 'net.reactivated.Fprint.',
+ namespace: 'FprintDBus',
+ object_manager: true,
+)
+
+# FIXME: remove this and just use fprintd_dbus_sources when we're on glib 2.64
+fprintd_dbus_sources = [
+ fprintd_dbus_sources_base[1] # header file
+]
+
+fprintd_dbus_sources += custom_target('fprintd-dbus-interactive',
+ input: fprintd_dbus_sources_base[0], # c file,
+ output: 'fprintd-dbus-interactive.c',
+ command: [
+ find_program('patch'),
+ '-p1',
+ '--merge',
+ '@INPUT@',
+ files('dbus-interactive-auth.patch'),
+ '-o', '@OUTPUT@',
+ ])
+
+fprintd_enum_files = gnome.mkenums_simple('fprintd-enums',
+ sources: 'fprintd.h',
+)
+
fprintd_deps = declare_dependency(
include_directories: [
include_directories('..'),
],
+ sources: [
+ fprintd_enum_files,
+ fprintd_dbus_sources,
+ ],
dependencies: [
- dbus_glib_dep,
glib_dep,
gio_dep,
+ gio_unix_dep,
gmodule_dep,
libfprint_dep,
polkit_gobject_dep,
@@ -58,8 +72,6 @@
'device.c',
'fprintd.h',
'manager.c',
- dbus_server_glue_sources,
- fprintd_marshal,
],
dependencies: fprintd_deps,
gnu_symbol_visibility: 'hidden',
diff -Nru fprintd-1.90.1/src/storage.h fprintd-1.90.9/src/storage.h
--- fprintd-1.90.1/src/storage.h 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/src/storage.h 2021-01-13 12:23:24.000000000 +0000
@@ -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_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;
diff -Nru fprintd-1.90.1/tests/dbusmock/fprintd.py fprintd-1.90.9/tests/dbusmock/fprintd.py
--- fprintd-1.90.1/tests/dbusmock/fprintd.py 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/tests/dbusmock/fprintd.py 2021-01-13 12:23:24.000000000 +0000
@@ -18,6 +18,8 @@
__copyright__ = '(c) 2020 Red Hat Inc.'
__license__ = 'LGPL 3+'
+import sys
+from gi.repository import GLib
import dbus
import asyncio
@@ -93,8 +95,9 @@
return devices[0]
@dbus.service.method(MANAGER_MOCK_IFACE,
- in_signature='sis', out_signature='s')
-def AddDevice(self, device_name, num_enroll_stages, scan_type):
+ in_signature='sisb', out_signature='s')
+def AddDevice(self, device_name, num_enroll_stages, scan_type,
+ has_identification=False):
'''Convenience method to add a fingerprint reader device
You have to specify a device name, the number of enrollment
@@ -139,12 +142,27 @@
device = mockobject.objects[path]
device.fingers = {}
+ device.has_identification = has_identification
device.claimed_user = None
device.action = None
+ device.selected_finger = None
device.verify_script = []
return path
+@dbus.service.method(MANAGER_MOCK_IFACE,
+ in_signature='o')
+def RemoveDevice(self, path):
+ # This isn't compatible with hotplugging devices, which fprintd doesn't
+ # support yet, but it's meant to remove devices added to the mock for
+ # testing purposes.
+ if not path:
+ raise dbus.exceptions.DBusException(
+ 'Invalid empty path.',
+ name='org.freedesktop.DBus.Error.InvalidArgs')
+
+ self.RemoveObject(path)
+
@dbus.service.method(DEVICE_IFACE,
in_signature='s', out_signature='as')
def ListEnrolledFingers(device, user):
@@ -186,6 +204,8 @@
'Device was not claimed before use',
name='net.reactivated.Fprint.Error.ClaimDevice')
device.claimed_user = None
+ device.action = None
+ device.selected_finger = None
def can_verify_finger(device, finger_name):
# We should already have checked that there are enrolled fingers
@@ -195,13 +215,26 @@
return True
return False
-async def send_verify_script(device, script):
- for [result, done, timeout] in device.verify_script:
- await asyncio.sleep(timeout)
- device.EmitSignal(DEVICE_IFACE, 'VerifyStatus', 'sb', [
- result,
- done
- ])
+def glib_sleep(timeout):
+ waiting = True
+
+ def done_waiting():
+ nonlocal waiting
+ waiting = False
+
+ GLib.timeout_add(timeout, done_waiting)
+ while (waiting):
+ GLib.main_context_default().iteration(True)
+
+def device_run_script(device, result, done):
+ if result == 'MOCK: quit':
+ sys.exit(0)
+
+ # Emit signal
+ device.EmitSignal(DEVICE_IFACE, 'VerifyStatus', 'sb', [
+ result,
+ done
+ ])
@dbus.service.method(DEVICE_IFACE,
in_signature='s', out_signature='')
@@ -228,15 +261,47 @@
name='net.reactivated.Fprint.Error.AlreadyInUse')
device.action = 'verify'
- if finger_name == 'any':
+ if finger_name == 'any' and not device.has_identification:
finger_name = device.fingers[device.claimed_user][0]
- device.EmitSignal(DEVICE_IFACE, 'VerifyFingerSelected', 's', [
- finger_name
- ])
-
- if device.verify_script is not None and len(device.verify_script) > 0:
- asyncio.run(send_verify_script(device, device.verify_script))
+ device.selected_finger = finger_name
+ # Needs to happen after method return
+ GLib.idle_add(device.EmitSignal,
+ DEVICE_IFACE, 'VerifyFingerSelected', 's', [
+ device.selected_finger
+ ])
+
+ error = None
+ base_delay = 0
+ while device.verify_script is not None and len(device.verify_script) > 0:
+ result, done, timeout = device.verify_script.pop(0)
+
+ # We stop when "timeout >= 0 and done"
+ if result == 'MOCK: no-prints':
+ # Special case to change return value of DBus call, ignores timeout
+ error = dbus.exceptions.DBusException(
+ 'No enrolled prints for user \'%s\'' % device.claimed_user,
+ name='net.reactivated.Fprint.Error.NoEnrolledPrints')
+
+ elif timeout < 0:
+ # Negative timeouts mean emitting before the DBus call returns
+ device_run_script(device, result, done)
+ glib_sleep(-timeout)
+
+ else:
+ # Positive or zero means emitting afterwards the given timeout
+ base_delay += timeout
+ GLib.timeout_add(base_delay,
+ device_run_script,
+ device,
+ result,
+ done)
+
+ # Stop processing commands when the done flag is set
+ if done:
+ break
+ if error:
+ raise error
@dbus.service.method(DEVICE_MOCK_IFACE,
in_signature='sb', out_signature='')
@@ -262,6 +327,7 @@
'No verification to stop',
name='net.reactivated.Fprint.Error.NoActionInProgress')
device.action = None
+ device.selected_finger = None
@dbus.service.method(DEVICE_IFACE,
in_signature='s', out_signature='')
@@ -317,11 +383,6 @@
Returns nothing.
'''
- if len(fingers) < 1:
- raise dbus.exceptions.DBusException(
- 'Fingers array must not be empty',
- name='org.freedesktop.DBus.Error.InvalidArgs')
-
for k in fingers:
if k not in VALID_FINGER_NAMES:
raise dbus.exceptions.DBusException(
@@ -331,6 +392,30 @@
device.fingers[user] = fingers
@dbus.service.method(DEVICE_MOCK_IFACE,
+ in_signature='', out_signature='s')
+def GetSelectedFinger(device):
+ '''Convenience method to get the finger under verification
+
+ Returns the finger name that the user has selected for verifying
+ '''
+ if not device.selected_finger:
+ raise dbus.exceptions.DBusException(
+ 'Device is not verifying',
+ name='net.reactivated.Fprint.Error.NoActionInProgress')
+
+ return device.selected_finger
+
+@dbus.service.method(DEVICE_MOCK_IFACE,
+ in_signature='', out_signature='b')
+def HasIdentification(device):
+ '''Convenience method to get if a device supports identification
+
+ Returns whether identification is supported.
+ '''
+
+ return device.has_identification
+
+@dbus.service.method(DEVICE_MOCK_IFACE,
in_signature='a(sbi)', out_signature='')
def SetVerifyScript(device, script):
'''Convenience method to set the verification script.
@@ -344,3 +429,11 @@
'''
device.verify_script = script
+
+@dbus.service.method(DEVICE_MOCK_IFACE,
+ in_signature='s', out_signature='')
+def SetClaimed(device, user):
+ if user == '':
+ device.claimed_user = None
+ else:
+ device.claimed_user = user
diff -Nru fprintd-1.90.1/tests/dbusmock/polkitd.py fprintd-1.90.9/tests/dbusmock/polkitd.py
--- fprintd-1.90.1/tests/dbusmock/polkitd.py 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/tests/dbusmock/polkitd.py 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,113 @@
+# -*- coding: utf-8 -*-
+
+'''polkit mock template
+
+This creates the basic methods and properties of the
+org.freedesktop.PolicyKit1.Authority object, so that we can use it async
+'''
+
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option) any
+# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
+# of the license.
+
+__author__ = 'Marco Trevisan'
+__email__ = 'marco.trevisan@canonical.com'
+__copyright__ = '(c) 2020 Canonical Ltd.'
+__license__ = 'LGPL 3+'
+
+import dbus
+import time
+
+from dbusmock import MOCK_IFACE, mockobject
+
+BUS_NAME = 'org.freedesktop.PolicyKit1'
+MAIN_OBJ = '/org/freedesktop/PolicyKit1/Authority'
+MAIN_IFACE = 'org.freedesktop.PolicyKit1.Authority'
+SYSTEM_BUS = True
+IS_OBJECT_MANAGER = False
+
+def load(mock, parameters):
+ polkitd = mockobject.objects[MAIN_OBJ]
+ # default state
+ polkitd.allow_unknown = False
+ polkitd.allowed = []
+ polkitd.delay = 0
+ polkitd.simulate_hang = False
+ polkitd.hanging_actions = []
+ polkitd.hanging_calls = []
+
+ mock.AddProperties(MAIN_IFACE,
+ dbus.Dictionary({
+ 'BackendName': 'local',
+ 'BackendVersion': '0.8.15',
+ 'BackendFeatures': dbus.UInt32(1, variant_level=1),
+ }, signature='sv'))
+
+
+@dbus.service.method(MAIN_IFACE,
+ in_signature='(sa{sv})sa{ss}us', out_signature='(bba{ss})',
+ async_callbacks=('ok_cb', 'err_cb'))
+def CheckAuthorization(self, subject, action_id, details, flags, cancellation_id,
+ ok_cb, err_cb):
+ time.sleep(self.delay)
+ allowed = action_id in self.allowed or self.allow_unknown
+ ret = (allowed, False, {'test': 'test'})
+
+ if self.simulate_hang or action_id in self.hanging_actions:
+ self.hanging_calls.append((ok_cb, ret))
+ else:
+ ok_cb(ret)
+
+@dbus.service.method(MOCK_IFACE, in_signature='b', out_signature='')
+def AllowUnknown(self, default):
+ '''Control whether unknown actions are allowed
+
+ This controls the return value of CheckAuthorization for actions which were
+ not explicitly allowed by SetAllowed().
+ '''
+ self.allow_unknown = default
+
+@dbus.service.method(MOCK_IFACE, in_signature='d', out_signature='')
+def SetDelay(self, delay):
+ '''Makes the CheckAuthorization() method to delay'''
+ self.delay = delay
+
+@dbus.service.method(MOCK_IFACE, in_signature='b', out_signature='')
+def SimulateHang(self, hang):
+ '''Makes the CheckAuthorization() method to hang'''
+ self.simulate_hang = hang
+
+@dbus.service.method(MOCK_IFACE, in_signature='as', out_signature='')
+def SimulateHangActions(self, actions):
+ '''Makes the CheckAuthorization() method to hang on such actions'''
+ self.hanging_actions = actions
+
+@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='')
+def ReleaseHangingCalls(self):
+ '''Calls all the hanging callbacks'''
+ for (cb, ret) in self.hanging_calls:
+ cb(ret)
+ self.hanging_calls = []
+
+@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='b')
+def HaveHangingCalls(self):
+ '''Check if we've hangling calls'''
+ return len(self.hanging_calls)
+
+@dbus.service.method(MOCK_IFACE, in_signature='as', out_signature='')
+def SetAllowed(self, actions):
+ '''Set allowed actions'''
+
+ self.allowed = actions
+
+@dbus.service.method(MAIN_IFACE,
+ in_signature='', out_signature='o')
+def GetDefaultDevice(self):
+ devices = self.GetDevices()
+ if len(devices) < 1:
+ raise dbus.exceptions.DBusException(
+ 'No devices available',
+ name='net.reactivated.Fprint.Error.NoSuchDevice')
+ return devices[0]
diff -Nru fprintd-1.90.1/tests/fprintd.py fprintd-1.90.9/tests/fprintd.py
--- fprintd-1.90.1/tests/fprintd.py 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/tests/fprintd.py 2021-01-13 12:23:24.000000000 +0000
@@ -1,5 +1,6 @@
#! /usr/bin/env python3
# Copyright © 2017, 2019 Red Hat, Inc
+# Copyright © 2020 Canonical Ltd
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -26,12 +27,14 @@
import sys
import tempfile
import glob
+import pwd
import shutil
import socket
import struct
import dbusmock
import gi
-from gi.repository import GLib, Gio
+gi.require_version('FPrint', '2.0')
+from gi.repository import GLib, Gio, FPrint
import cairo
try:
@@ -48,6 +51,11 @@
'default': 20,
'daemon_start': 60
},
+ 'asan': {
+ 'test': 120,
+ 'default': 6,
+ 'daemon_start': 10
+ },
'default': {
'test': 60,
'default': 3,
@@ -55,8 +63,13 @@
}
}
- valgrind = os.getenv('VALGRIND')
- lut = vals['valgrind' if valgrind is not None else 'default']
+ if os.getenv('VALGRIND') is not None:
+ lut = vals['valgrind']
+ elif os.getenv('ADDRESS_SANITIZER') is not None:
+ lut = vals['asan']
+ else:
+ lut = vals['default']
+
if topic not in lut:
raise ValueError('invalid topic')
return lut[topic]
@@ -121,7 +134,11 @@
@classmethod
def setUpClass(cls):
+ super().setUpClass()
fprintd = None
+ cls._polkitd = None
+
+ cls._has_hotplug = FPrint.Device.find_property("removed") is not None
if 'FPRINT_BUILD_DIR' in os.environ:
print('Testing local build')
@@ -152,16 +169,20 @@
cls.test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE)
cls.test_bus.up()
- try:
- del os.environ['DBUS_SESSION_BUS_ADDRESS']
- except KeyError:
- pass
- os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = cls.test_bus.get_bus_address()
- cls.dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
+ cls.test_bus.unset()
+ addr = cls.test_bus.get_bus_address()
+ os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = addr
+ cls.dbus = Gio.DBusConnection.new_for_address_sync(addr,
+ Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION |
+ Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT, None, None)
+ assert cls.dbus.is_closed() == False
@classmethod
def tearDownClass(cls):
+ cls.dbus.close()
cls.test_bus.down()
+ del cls.dbus
+ del cls.test_bus
shutil.rmtree(cls.tmpdir)
dbusmock.DBusTestCase.tearDownClass()
@@ -170,7 +191,7 @@
timeout = get_timeout('daemon_start') # seconds
env = os.environ.copy()
env['G_DEBUG'] = 'fatal-criticals'
- env['STATE_DIRECTORY'] = self.state_dir
+ env['STATE_DIRECTORY'] = (self.state_dir + ':' + '/hopefully/a/state_dir_path/that/shouldnt/be/writable')
env['RUNTIME_DIRECTORY'] = self.run_dir
argv = [self.paths['daemon'], '-t']
@@ -185,7 +206,7 @@
env=env,
stdout=None,
stderr=subprocess.STDOUT)
- self.device = None
+ self.addCleanup(self.daemon_stop)
timeout_count = timeout * 10
timeout_sleep = 0.1
@@ -234,13 +255,25 @@
except OSError:
pass
self.daemon.wait(timeout=2)
+ self.assertLess(self.daemon.returncode, 128)
+ self.assertGreaterEqual(self.daemon.returncode, 0)
self.daemon = None
- self.client = None
def polkitd_start(self):
+ if self._polkitd:
+ return
+
+ if 'POLKITD_MOCK_PATH' in os.environ:
+ polkitd_template = os.path.join(os.getenv('POLKITD_MOCK_PATH'), 'polkitd.py')
+ else:
+ polkitd_template = os.path.join(os.path.dirname(__file__), 'dbusmock/polkitd.py')
+ print ('Using template from %s' % polkitd_template)
+
self._polkitd, self._polkitd_obj = self.spawn_server_template(
- 'polkitd', {}, stdout=DEVNULL)
+ polkitd_template, {}, stdout=subprocess.PIPE)
+
+ return self._polkitd
def polkitd_stop(self):
if self._polkitd is None:
@@ -248,26 +281,51 @@
self._polkitd.terminate()
self._polkitd.wait()
-
+ def get_current_user(self):
+ return pwd.getpwuid(os.getuid()).pw_name
def setUp(self):
self.test_dir = tempfile.mkdtemp()
+ self.addCleanup(shutil.rmtree, self.test_dir)
self.state_dir = os.path.join(self.test_dir, 'state')
self.run_dir = os.path.join(self.test_dir, 'run')
+ os.environ['FP_DRIVERS_WHITELIST'] = 'virtual_image'
- def tearDown(self):
- shutil.rmtree(self.test_dir)
+ def assertFprintError(self, fprint_error):
+ return self.assertRaisesRegex(GLib.Error,
+ '.*net\.reactivated\.Fprint\.Error\.{}.*'.format(fprint_error))
# From libfprint tests
- def send_retry(self, retry_error=1):
- # The default (1) is 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, 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_image(self, image):
- img = self.prints[image]
+ def send_remove(self, con=None):
+ if con:
+ con.sendall(struct.pack('ii', -5, 0))
+ return
+
with Connection(self.sockaddr) as con:
+ self.send_remove(con=con)
+
+ # From libfprint tests
+ def send_image(self, image, con=None):
+ if con:
+ img = self.prints[image]
mem = img.get_data()
mem = mem.tobytes()
self.assertEqual(len(mem), img.get_width() * img.get_height())
@@ -276,27 +334,85 @@
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... """
+ self.device.call(method, GLib.Variant(*args),
+ Gio.DBusCallFlags.NONE, -1, None, self._method_call_handler)
+
+ def _method_call_handler(self, proxy, res):
+ try:
+ self._async_call_res = proxy.call_finish(res)
+ except Exception as e:
+ self._async_call_res = e
+
+ def wait_for_device_reply(self):
+ self._async_call_res = None
+ while not self._async_call_res:
+ ctx.iteration(True)
+
+ if isinstance(self._async_call_res, Exception):
+ raise self._async_call_res
+
+ def gdbus_device_method_call_process(self, method, args=[]):
+ return subprocess.Popen([
+ 'gdbus',
+ 'call',
+ '--system',
+ '--dest',
+ self.device.get_name(),
+ '--object-path',
+ self.device.get_object_path(),
+ '--method',
+ '{}.{}'.format(self.device.get_interface_name(), method),
+ ] + args, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
+
+ def call_device_method_from_other_client(self, method, args=[]):
+ try:
+ proc = self.gdbus_device_method_call_process(method, args)
+ proc.wait(timeout=5)
+ if proc.returncode != 0:
+ raise GLib.GError(proc.stdout.read())
+ return proc.stdout.read()
+ except subprocess.TimeoutExpired as e:
+ raise GLib.GError(e.output)
+
+class FPrintdVirtualDeviceBaseTest(FPrintdTest):
-class FPrintdVirtualDeviceTest(FPrintdTest):
def setUp(self):
super().setUp()
+ self.manager = None
+ self.device = None
self.polkitd_start()
self.daemon_start()
if self.device is None:
- self.daemon_stop()
- self.polkitd_stop()
self.skipTest("Need virtual_image device to run the test")
- def timeout_cb(*args):
- # Note: With meson we could just rely on it to kill us
- print("Test timed out, hard exiting")
- sys.exit(1)
-
- self.test_timeout = GLib.timeout_add(get_timeout('test') * 1000, timeout_cb)
-
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername',
'net.reactivated.fprint.device.enroll',
'net.reactivated.fprint.device.verify'])
@@ -307,8 +423,9 @@
self._abort = params[1]
self._last_result = params[0]
- if not self._abort and self._last_result == 'enroll-stage-passed':
- self.send_image('whorl')
+ if not self._abort and self._last_result.startswith('enroll-'):
+ # Exit wait loop, onto next enroll state (if any)
+ self._abort = True
elif self._abort:
pass
else:
@@ -328,24 +445,202 @@
self.g_signal_id = self.device.connect('g-signal', signal_cb)
def tearDown(self):
+ self.polkitd_stop()
+ self.device.disconnect(self.g_signal_id)
+ self.device = None
+ self.manager = None
+
super().tearDown()
- GLib.source_remove(self.test_timeout)
- self.device.disconnect(self.g_signal_id)
+ def wait_for_result(self, expected=None):
+ self._abort = False
+ while not self._abort:
+ ctx.iteration(True)
- self.daemon_stop()
- self.polkitd_stop()
+ self.assertTrue(self._abort)
+ self._abort = False
- def assertFprintError(self, fprint_error):
- return self.assertRaisesRegex(GLib.Error,
- '.*net\.reactivated\.Fprint\.Error\.{}.*'.format(fprint_error))
+ if expected is not None:
+ self.assertEqual(self._last_result, expected)
+
+ 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 = device.get_cached_property('num-enroll-stages').unpack()
+ for stage in range(stages):
+ self.send_image(img)
+ if stage < stages - 1:
+ self.wait_for_result('enroll-stage-passed')
+ else:
+ self.wait_for_result(expected_result)
+
+ device.EnrollStop()
+ self.assertEqual(self._last_result, expected_result)
+
+ def enroll_multiple_images(self, images_override={}, return_index=-1):
+ enroll_map = {
+ 'left-thumb': 'whorl',
+ 'right-index-finger': 'arch',
+ 'left-little-finger': 'loop-right',
+ }
+ enroll_map.update(images_override)
+
+ for finger, print in enroll_map.items():
+ self.enroll_image(print, finger=finger)
+
+ enrolled = self.device.ListEnrolledFingers('(s)', 'testuser')
+ self.assertCountEqual(enroll_map.keys(), enrolled)
+
+ if return_index >= 0:
+ return enroll_map[enrolled[return_index]]
+
+ 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):
+
+ def setUp(self):
+ super().setUp()
+ self._polkitd_obj.SetAllowed([''])
+
+ def test_manager_get_devices(self):
+ self.assertListEqual(self.manager.GetDevices(),
+ [ self.device.get_object_path() ])
+
+ def test_manager_get_default_device(self):
+ self.assertEqual(self.manager.GetDefaultDevice(),
+ self.device.get_object_path())
+
+
+class FPrintdManagerPreStartTests(FPrintdTest):
+
+ def test_manager_get_no_devices(self):
+ os.environ['FP_DRIVERS_WHITELIST'] = 'hopefully_no_existing_driver'
+ self.daemon_start()
+ self.assertListEqual(self.manager.GetDevices(), [])
+
+ def test_manager_get_no_default_device(self):
+ os.environ['FP_DRIVERS_WHITELIST'] = 'hopefully_no_existing_driver'
+ self.daemon_start()
+
+ with self.assertFprintError('NoSuchDevice'):
+ self.manager.GetDefaultDevice()
- def test_allowed_claim(self):
+ def test_manager_get_devices_on_name_appeared(self):
+ self._appeared_name = None
+
+ def on_name_appeared(connection, name, name_owner):
+ self._appeared_name = name
+
+ def on_name_vanished(connection, name):
+ self._appeared_name = 'NAME_VANISHED'
+
+ id = Gio.bus_watch_name_on_connection(self.dbus,
+ 'net.reactivated.Fprint', Gio.BusNameWatcherFlags.NONE,
+ on_name_appeared, on_name_vanished)
+ self.addCleanup(Gio.bus_unwatch_name, id)
+
+ self.daemon_start()
+ while not self._appeared_name:
+ ctx.iteration(True)
+
+ self.assertEqual(self._appeared_name, 'net.reactivated.Fprint')
+
+ try:
+ appeared_device = self.dbus.call_sync(
+ 'net.reactivated.Fprint',
+ '/net/reactivated/Fprint/Manager',
+ 'net.reactivated.Fprint.Manager',
+ 'GetDefaultDevice', None, None,
+ Gio.DBusCallFlags.NO_AUTO_START, 500, None)
+ except GLib.GError as e:
+ if 'net.reactivated.Fprint.Error.NoSuchDevice' in e.message:
+ self.skipTest("Need virtual_image device to run the test")
+ raise(e)
+
+ self.assertIsNotNone(appeared_device)
+ [dev_path] = appeared_device
+ self.assertTrue(dev_path.startswith('/net/reactivated/Fprint/Device/'))
+
+
+class FPrintdVirtualDeviceTest(FPrintdVirtualDeviceBaseTest):
+
+ def test_name_property(self):
+ self.assertEqual(self.device.get_cached_property('name').unpack(),
+ 'Virtual image device for debugging')
+
+ def test_enroll_stages_property(self):
+ self.assertEqual(self.device.get_cached_property('num-enroll-stages').unpack(), 5)
+
+ def test_scan_type(self):
+ self.assertEqual(self.device.get_cached_property('scan-type').unpack(),
+ 'swipe')
+
+ def test_allowed_claim_release_enroll(self):
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername',
'net.reactivated.fprint.device.enroll'])
self.device.Claim('(s)', 'testuser')
self.device.Release()
+ def test_allowed_claim_release_verify(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.verify'])
+ self.device.Claim('(s)', 'testuser')
+ self.device.Release()
+
+ def test_allowed_claim_current_user(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
+ self.device.Claim('(s)', '')
+ self.device.Release()
+
+ self.device.Claim('(s)', self.get_current_user())
+ self.device.Release()
+
+ def test_allowed_list_enrolled_fingers_empty_user(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
+ self.device.Claim('(s)', '')
+ self.enroll_image('whorl', finger='left-thumb')
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
+
+ self.assertEqual(self.device.ListEnrolledFingers('(s)', ''), ['left-thumb'])
+ self.assertEqual(self.device.ListEnrolledFingers('(s)', self.get_current_user()), ['left-thumb'])
+
+ def test_allowed_list_enrolled_fingers_current_user(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
+ self.device.Claim('(s)', self.get_current_user())
+ self.enroll_image('whorl', finger='right-thumb')
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
+
+ self.assertEqual(self.device.ListEnrolledFingers('(s)', ''), ['right-thumb'])
+ self.assertEqual(self.device.ListEnrolledFingers('(s)', self.get_current_user()), ['right-thumb'])
+
def test_unallowed_claim(self):
self._polkitd_obj.SetAllowed([''])
@@ -362,28 +657,61 @@
with self.assertFprintError('PermissionDenied'):
self.device.Claim('(s)', 'testuser')
- def test_multiple_claims(self):
- self.device.Claim('(s)', 'testuser')
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
- with self.assertFprintError('AlreadyInUse'):
+ with self.assertFprintError('PermissionDenied'):
self.device.Claim('(s)', 'testuser')
- self.device.Release()
+ def test_unallowed_enroll_with_verify_claim(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
+ self.device.Claim('(s)', '')
- def test_unallowed_release(self):
- self.device.Claim('(s)', 'testuser')
+ with self.assertFprintError('PermissionDenied'):
+ self.enroll_image('whorl', finger='right-thumb')
- self._polkitd_obj.SetAllowed([''])
+ def test_unallowed_delete_with_verify_claim(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
+ self.device.Claim('(s)', '')
with self.assertFprintError('PermissionDenied'):
- self.device.Release()
+ self.device.DeleteEnrolledFingers('(s)', 'testuser')
- self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername'])
+ def test_unallowed_delete2_with_verify_claim(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
+ self.device.Claim('(s)', '')
with self.assertFprintError('PermissionDenied'):
- self.device.Release()
+ self.device.DeleteEnrolledFingers2()
+ def test_unallowed_verify_with_enroll_claim(self):
self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
+ self.device.Claim('(s)', '')
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.VerifyStart('(s)', 'any')
+
+ def test_unallowed_claim_current_user(self):
+ self._polkitd_obj.SetAllowed([''])
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.Claim('(s)', '')
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.Claim('(s)', self.get_current_user())
+
+ def test_multiple_claims(self):
+ self.device.Claim('(s)', 'testuser')
+
+ with self.assertFprintError('AlreadyInUse'):
+ self.device.Claim('(s)', 'testuser')
+
+ self.device.Release()
+
+ def test_always_allowed_release(self):
+ self.device.Claim('(s)', 'testuser')
+
+ self._polkitd_obj.SetAllowed([''])
+
self.device.Release()
def test_unclaimed_release(self):
@@ -406,14 +734,6 @@
with self.assertFprintError('ClaimDevice'):
self.device.EnrollStop()
- def test_wrong_finger_enroll_start(self):
- self.device.Claim('(s)', 'testuser')
-
- with self.assertFprintError('InvalidFingername'):
- self.device.EnrollStart('(s)', 'any')
-
- self.device.Release()
-
def test_unclaimed_delete_enrolled_fingers(self):
self.device.DeleteEnrolledFingers('(s)', 'testuser')
@@ -425,27 +745,178 @@
with self.assertFprintError('NoEnrolledPrints'):
self.device.ListEnrolledFingers('(s)', 'testuser')
- def test_enroll_verify_list_delete(self):
+ def test_claim_device_open_fail(self):
+ os.rename(self.tmpdir, self.tmpdir + '-moved')
+ self.addCleanup(os.rename, self.tmpdir + '-moved', self.tmpdir)
+
+ with self.assertFprintError('Internal'):
+ self.device.Claim('(s)', 'testuser')
+ def test_claim_from_other_client_is_released_when_vanished(self):
+ self.call_device_method_from_other_client('Claim', ['testuser'])
+ time.sleep(1)
self.device.Claim('(s)', 'testuser')
+ self.device.Release()
- with self.assertFprintError('NoEnrolledPrints'):
- self.device.ListEnrolledFingers('(s)', 'testuser')
+ def test_claim_disconnect(self):
+ bus, dev = self.get_secondary_bus_and_device()
- with self.assertFprintError('NoEnrolledPrints'):
- self.device.ListEnrolledFingers('(s)', 'nottestuser')
+ def call_done(obj, result, user_data):
+ # Ignore the callback (should be an error)
+ pass
- self.device.EnrollStart('(s)', 'right-index-finger')
+ # Do an async call to claim and immediately close
+ dev.Claim('(s)', 'testuser', result_handler=call_done)
+
+ # Ensure the call is on the wire, then close immediately
+ 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)
- self._abort = False
- while not self._abort:
- ctx.iteration(True)
+ bus.close_sync()
- self.assertEqual(self._last_result, 'enroll-completed')
+ time.sleep(1)
- self.device.EnrollStop()
+ 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)
+
+ def test_removal_during_enroll(self):
+ if not self._has_hotplug:
+ self.skipTest("libfprint is too old for hotplug")
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll'])
+ self.device.Claim('(s)', 'testuser')
+ self.device.EnrollStart('(s)', 'left-index-finger')
+
+ # Now remove the device while we are enrolling, which will cause an error
+ self.send_remove()
+ self.wait_for_result(expected='enroll-unknown-error')
+
+ # The device will still be there now until it is released
+ devices = self.manager.GetDevices()
+ self.assertIn(self.device.get_object_path(), devices)
+ with self.assertFprintError('Internal'):
+ self.device.Release()
+
+ # And now it will be gone
+ devices = self.manager.GetDevices()
+ self.assertNotIn(self.device.get_object_path(), devices)
+
+
+class FPrintdVirtualDeviceClaimedTest(FPrintdVirtualDeviceBaseTest):
+
+ def setUp(self):
+ super().setUp()
+ self.device.Claim('(s)', 'testuser')
+
+ def tearDown(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
+ try:
+ self.device.Release()
+ except GLib.GError as e:
+ if not 'net.reactivated.Fprint.Error.ClaimDevice' in e.message:
+ raise(e)
+ super().tearDown()
+
+ def test_wrong_finger_enroll_start(self):
+ with self.assertFprintError('InvalidFingername'):
+ self.device.EnrollStart('(s)', 'any')
+
+ def test_verify_with_no_enrolled_prints(self):
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.VerifyStart('(s)', 'any')
+
+ def test_enroll_verify_list_delete(self):
+ # This test can trigger a race in older libfprint, only run if we have
+ # hotplug support, which coincides with the fixed release.
+ if not self._has_hotplug:
+ self.skipTest("libfprint is too old for hotplug")
+
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.ListEnrolledFingers('(s)', 'testuser')
+
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.ListEnrolledFingers('(s)', 'nottestuser')
+
+ self.enroll_image('whorl')
self.assertTrue(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
@@ -459,9 +930,7 @@
# Try a wrong print; will stop verification
self.send_image('tented_arch')
- self._abort = False
- while not self._abort:
- ctx.iteration(True)
+ self.wait_for_result()
self.assertTrue(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-no-match')
@@ -470,19 +939,16 @@
# Send a retry error (swipe too short); will not stop verification
self.send_retry()
- self._abort = False
- while not self._abort:
- ctx.iteration(True)
+ self.wait_for_result()
self.assertFalse(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-swipe-too-short')
# Try the correct print; will stop verification
self.send_image('whorl')
- self._abort = False
- while not self._abort:
- ctx.iteration(True)
+ self.wait_for_result()
self.assertTrue(self._verify_stopped)
self.assertEqual(self._last_result, 'verify-match')
+ self.device.VerifyStop()
self.assertEqual(self.device.ListEnrolledFingers('(s)', 'testuser'), ['right-index-finger'])
@@ -494,32 +960,745 @@
with self.assertFprintError('NoEnrolledPrints'):
self.device.ListEnrolledFingers('(s)', 'testuser')
- self.device.Release()
-
def test_enroll_delete2(self):
+ self.enroll_image('whorl')
- self.device.Claim('(s)', 'testuser')
-
- self.device.EnrollStart('(s)', 'right-index-finger')
+ self.assertTrue(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
+ # And delete the print(s) again using the new API
+ 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 will not exist yet
+ os.makedirs(self.state_dir, mode=0o500)
+ self.addCleanup(os.chmod, self.state_dir, mode=0o700)
+
+ try:
+ os.open(os.path.join(self.state_dir, "testfile"), os.O_CREAT | os.O_WRONLY)
+ self.skipTest('Permissions aren\'t respected (CI environment?)')
+ except PermissionError:
+ pass
+
+ self.enroll_image('whorl', expected_result='enroll-failed')
+
+ def test_verify_invalid_storage_dir(self):
+ self.enroll_image('whorl')
+ os.chmod(self.state_dir, mode=0o000)
+ self.addCleanup(os.chmod, self.state_dir, mode=0o700)
+
+ try:
+ os.open(os.path.join(self.state_dir, "testfile"), os.O_CREAT | os.O_WRONLY)
+ self.skipTest('Permissions aren\'t respected (CI environment?)')
+ except PermissionError:
+ pass
+
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.VerifyStart('(s)', 'any')
+
+ def test_enroll_stop_cancels(self):
+ self.device.EnrollStart('(s)', 'left-index-finger')
+ self.device.EnrollStop()
+ self.wait_for_result(expected='enroll-failed')
+
+ def test_verify_stop_cancels(self):
+ self.enroll_image('whorl')
+ self.device.VerifyStart('(s)', 'any')
+ self.device.VerifyStop()
+ self.wait_for_result(expected='verify-no-match')
+
+ def test_verify_finger_stop_cancels(self):
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.VerifyStart('(s)', 'left-thumb')
+ self.device.VerifyStop()
+
+ def test_busy_device_release_on_enroll(self):
+ self.device.EnrollStart('(s)', 'left-index-finger')
+
+ self.device.Release()
+ self.wait_for_result(expected='enroll-failed')
+
+ def test_busy_device_release_on_verify(self):
+ self.enroll_image('whorl', finger='left-index-finger')
+ self.device.VerifyStart('(s)', 'any')
+
+ self.device.Release()
+ self.wait_for_result(expected='verify-no-match')
+
+ def test_busy_device_release_on_verify_finger(self):
+ self.enroll_image('whorl', finger='left-middle-finger')
+ self.device.VerifyStart('(s)', 'left-middle-finger')
+
+ self.device.Release()
+ self.wait_for_result(expected='verify-no-match')
+
+ def test_enroll_stop_not_started(self):
+ with self.assertFprintError('NoActionInProgress'):
+ self.device.EnrollStop()
+
+ def test_verify_stop_not_started(self):
+ with self.assertFprintError('NoActionInProgress'):
+ self.device.VerifyStop()
+
+ def test_verify_finger_match(self):
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.VerifyStart('(s)', 'left-thumb')
self.send_image('whorl')
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, 'verify-match')
+ self.device.VerifyStop()
+ def test_verify_finger_no_match(self):
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.VerifyStart('(s)', 'left-thumb')
+ 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()
+
+ def test_verify_finger_no_match_restart(self):
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.VerifyStart('(s)', 'left-thumb')
+ 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()
+
+ # Immediately starting again after a no-match must work
+ self.device.VerifyStart('(s)', 'left-thumb')
+ self.send_image('whorl')
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, 'verify-match')
+ self.device.VerifyStop()
+
+ def test_verify_wrong_finger_match(self):
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.VerifyStart('(s)', 'left-toe')
+ self.send_image('whorl')
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, 'verify-match')
+ self.device.VerifyStop()
+
+ def test_verify_wrong_finger_no_match(self):
+ self.enroll_image('whorl', finger='right-thumb')
+ self.device.VerifyStart('(s)', 'right-toe')
+ 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()
+
+ def test_verify_any_finger_match(self):
+ second_image = self.enroll_multiple_images(return_index=1)
+ self.device.VerifyStart('(s)', 'any')
+ self.send_image(second_image)
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, 'verify-match')
+ self.device.VerifyStop()
+
+ def test_verify_any_finger_no_match(self):
+ enrolled, _map = self.enroll_multiple_images()
+ verify_image = 'tented_arch'
+ self.assertNotIn(verify_image, enrolled)
+ self.device.VerifyStart('(s)', 'any')
+ self.send_image(verify_image)
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, 'verify-no-match')
+ self.device.VerifyStop()
+
+ def test_verify_finger_not_enrolled(self):
+ self.enroll_image('whorl', finger='left-thumb')
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.VerifyStart('(s)', 'right-thumb')
+
+ def test_unallowed_enroll_start(self):
+ self._polkitd_obj.SetAllowed([''])
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.EnrollStart('(s)', 'right-index-finger')
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.enroll'])
+ self.enroll_image('whorl')
+
+ def test_always_allowed_enroll_stop(self):
+ self.device.EnrollStart('(s)', 'right-index-finger')
+
+ self._polkitd_obj.SetAllowed([''])
+
+ self.device.EnrollStop()
+
+ def test_unallowed_verify_start(self):
+ self._polkitd_obj.SetAllowed([''])
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.VerifyStart('(s)', 'any')
+
+ def test_always_allowed_verify_stop(self):
+ self.enroll_image('whorl')
+ self.device.VerifyStart('(s)', 'any')
+
+ self._polkitd_obj.SetAllowed([''])
+ self.device.VerifyStop()
+
+ def test_list_enrolled_fingers_current_user(self):
+ self.enroll_image('whorl')
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.verify'])
+
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.ListEnrolledFingers('(s)', '')
+
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.ListEnrolledFingers('(s)', self.get_current_user())
+
+ def test_unallowed_list_enrolled_fingers(self):
+ self.enroll_image('whorl')
+
+ self._polkitd_obj.SetAllowed([''])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.ListEnrolledFingers('(s)', 'testuser')
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername'])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.ListEnrolledFingers('(s)', 'testuser')
+
+ def test_unallowed_list_enrolled_fingers_current_user(self):
+ self.enroll_image('whorl')
+
+ self._polkitd_obj.SetAllowed([''])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.ListEnrolledFingers('(s)', '')
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.ListEnrolledFingers('(s)', self.get_current_user())
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername'])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.ListEnrolledFingers('(s)', '')
+
+ with self.assertFprintError('PermissionDenied'):
+ self.device.ListEnrolledFingers('(s)', self.get_current_user())
+
+ def test_unallowed_delete_enrolled_fingers(self):
+ self.enroll_image('whorl')
+
+ self._polkitd_obj.SetAllowed([''])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.DeleteEnrolledFingers('(s)', 'testuser')
+
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername'])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.DeleteEnrolledFingers('(s)', 'testuser')
+
+ def test_unallowed_delete_enrolled_fingers2(self):
+ self.enroll_image('whorl')
+
+ self._polkitd_obj.SetAllowed([''])
+ with self.assertFprintError('PermissionDenied'):
+ self.device.DeleteEnrolledFingers2()
+
+ def test_delete_enrolled_fingers_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('DeleteEnrolledFingers', ['testuser'])
+
+ def test_release_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('Release')
+
+ def test_enroll_start_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('EnrollStart', ['left-index-finger'])
+
+ def test_verify_start_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('VerifyStart', ['any'])
+
+ def test_verify_start_finger_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('VerifyStart', ['left-thumb'])
+
+
+class FPrintdVirtualDeviceEnrollTests(FPrintdVirtualDeviceBaseTest):
+
+ def setUp(self):
+ super().setUp()
self._abort = False
- while not self._abort:
- ctx.iteration(True)
+ self.device.Claim('(s)', 'testuser')
+ self.device.EnrollStart('(s)', 'left-middle-finger')
+
+ def tearDown(self):
+ self.device.EnrollStop()
+ self.device.Release()
+ super().tearDown()
+
+ def assertEnrollRetry(self, device_error, expected_error):
+ self.send_retry(retry_error=device_error)
+ self.wait_for_result(expected=expected_error)
+
+ def assertEnrollError(self, device_error, expected_error):
+ self.send_error(error=device_error)
+ self.wait_for_result(expected=expected_error)
+
+ def test_enroll_retry_general(self):
+ self.assertEnrollRetry(FPrint.DeviceRetry.GENERAL, 'enroll-retry-scan')
+
+ def test_enroll_retry_too_short(self):
+ self.assertEnrollRetry(FPrint.DeviceRetry.TOO_SHORT, 'enroll-swipe-too-short')
+
+ def test_enroll_retry_remove_finger(self):
+ self.assertEnrollRetry(FPrint.DeviceRetry.REMOVE_FINGER, 'enroll-remove-and-retry')
+
+ def test_enroll_retry_center_finger(self):
+ self.assertEnrollRetry(FPrint.DeviceRetry.CENTER_FINGER, 'enroll-finger-not-centered')
+
+ def test_enroll_error_general(self):
+ self.assertEnrollError(FPrint.DeviceError.GENERAL, 'enroll-unknown-error')
+
+ def test_enroll_error_not_supported(self):
+ self.assertEnrollError(FPrint.DeviceError.NOT_SUPPORTED, 'enroll-unknown-error')
+
+ def test_enroll_error_not_open(self):
+ self.assertEnrollError(FPrint.DeviceError.NOT_OPEN, 'enroll-unknown-error')
+
+ def test_enroll_error_already_open(self):
+ self.assertEnrollError(FPrint.DeviceError.ALREADY_OPEN, 'enroll-unknown-error')
+
+ def test_enroll_error_busy(self):
+ self.assertEnrollError(FPrint.DeviceError.BUSY, 'enroll-unknown-error')
+
+ def test_enroll_error_proto(self):
+ self.assertEnrollError(FPrint.DeviceError.PROTO, 'enroll-disconnected')
+
+ def test_enroll_error_data_invalid(self):
+ self.assertEnrollError(FPrint.DeviceError.DATA_INVALID, 'enroll-unknown-error')
+
+ def test_enroll_error_data_not_found(self):
+ self.assertEnrollError(FPrint.DeviceError.DATA_NOT_FOUND, 'enroll-unknown-error')
- self.assertEqual(self._last_result, 'enroll-completed')
+ def test_enroll_error_data_full(self):
+ self.assertEnrollError(FPrint.DeviceError.DATA_FULL, 'enroll-data-full')
+ def test_enroll_start_during_enroll(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.device.EnrollStart('(s)', 'left-thumb')
+
+ def test_verify_start_during_enroll(self):
self.device.EnrollStop()
+ self.wait_for_result()
+ self.enroll_image('whorl')
+ self.device.EnrollStart('(s)', 'right-thumb')
+ with self.assertFprintError('AlreadyInUse'):
+ self.device.VerifyStart('(s)', 'any')
- self.assertTrue(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
+ def test_verify_stop_during_enroll(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.device.VerifyStop()
- # And delete the print(s) again using the new API
- self.device.DeleteEnrolledFingers2()
+ def test_enroll_stop_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('EnrollStop')
- self.assertFalse(os.path.exists(os.path.join(self.state_dir, 'testuser/virtual_image/0/7')))
+class FPrintdVirtualDeviceVerificationTests(FPrintdVirtualDeviceBaseTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.enroll_finger = 'left-middle-finger'
+ cls.verify_finger = cls.enroll_finger
+
+ def setUp(self):
+ super().setUp()
+ self.device.Claim('(s)', 'testuser')
+ self.enroll_image('whorl', finger=self.enroll_finger)
+ self.device.VerifyStart('(s)', self.verify_finger)
+
+ def tearDown(self):
+ self.device.VerifyStop()
self.device.Release()
+ super().tearDown()
+
+ def assertVerifyRetry(self, device_error, expected_error):
+ self.send_retry(retry_error=device_error)
+ self.wait_for_result()
+ self.assertFalse(self._verify_stopped)
+ self.assertEqual(self._last_result, expected_error)
+
+ def assertVerifyError(self, device_error, expected_error):
+ self.send_error(error=device_error)
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, expected_error)
+
+ 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')
+
+ def test_verify_retry_remove_finger(self):
+ self.assertVerifyRetry(FPrint.DeviceRetry.REMOVE_FINGER, 'verify-remove-and-retry')
+
+ def test_verify_retry_center_finger(self):
+ self.assertVerifyRetry(FPrint.DeviceRetry.CENTER_FINGER, 'verify-finger-not-centered')
+
+ def test_verify_error_general(self):
+ self.assertVerifyError(FPrint.DeviceError.GENERAL, 'verify-unknown-error')
+
+ def test_verify_error_not_supported(self):
+ self.assertVerifyError(FPrint.DeviceError.NOT_SUPPORTED, 'verify-unknown-error')
+
+ def test_verify_error_not_open(self):
+ self.assertVerifyError(FPrint.DeviceError.NOT_OPEN, 'verify-unknown-error')
+
+ def test_verify_error_already_open(self):
+ self.assertVerifyError(FPrint.DeviceError.ALREADY_OPEN, 'verify-unknown-error')
+
+ def test_verify_error_busy(self):
+ self.assertVerifyError(FPrint.DeviceError.BUSY, 'verify-unknown-error')
+
+ def test_verify_error_proto(self):
+ self.assertVerifyError(FPrint.DeviceError.PROTO, 'verify-disconnected')
+
+ def test_verify_error_data_invalid(self):
+ self.assertVerifyError(FPrint.DeviceError.DATA_INVALID, 'verify-unknown-error')
+
+ def test_verify_error_data_not_found(self):
+ self.assertVerifyError(FPrint.DeviceError.DATA_NOT_FOUND, 'verify-unknown-error')
+
+ 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)
+
+ def test_enroll_start_during_verify(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.device.EnrollStart('(s)', 'right-thumb')
+
+ def test_enroll_stop_during_verify(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.device.EnrollStop()
+
+ def test_verify_stop_from_other_client(self):
+ with self.assertFprintError('AlreadyInUse'):
+ self.call_device_method_from_other_client('VerifyStop')
+
+
+class FPrintdVirtualDeviceIdentificationTests(FPrintdVirtualDeviceVerificationTests):
+ '''This class will just repeat the tests of FPrintdVirtualDeviceVerificationTests
+ but with 'any' finger parameter (leading to an identification, when possible
+ under the hood).
+ '''
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.verify_finger = 'any'
+
+
+class FPrindConcurrentPolkitRequestsTest(FPrintdVirtualDeviceBaseTest):
+
+ def wait_for_hanging_clients(self):
+ while not self._polkitd_obj.HaveHangingCalls():
+ pass
+ self.assertTrue(self._polkitd_obj.HaveHangingCalls())
+
+ def start_hanging_gdbus_claim(self, user='testuser'):
+ gdbus = self.gdbus_device_method_call_process('Claim', [user])
+ self.assertIsNone(gdbus.poll())
+ self.wait_for_hanging_clients()
+ self.addCleanup(gdbus.kill)
+ return gdbus
+
+ def test_hanging_claim_does_not_block_new_claim_external_client(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll' ])
+ self._polkitd_obj.SimulateHang(True)
+ self._polkitd_obj.SetDelay(0.5)
+
+ gdbus = self.start_hanging_gdbus_claim()
+
+ self._polkitd_obj.SimulateHang(False)
+ self.device.Claim('(s)', self.get_current_user())
+
+ self.assertIsNone(gdbus.poll())
+ self._polkitd_obj.ReleaseHangingCalls()
+
+ gdbus.wait()
+ with self.assertFprintError('AlreadyInUse'):
+ raise GLib.GError(gdbus.stdout.read())
+
+ self.device.Release()
+
+ def test_hanging_claim_does_not_block_new_claim(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll' ])
+ self._polkitd_obj.SimulateHang(True)
+ self._polkitd_obj.SetDelay(0.5)
+
+ self.call_device_method_async('Claim', '(s)', [''])
+ self.wait_for_hanging_clients()
+
+ self._polkitd_obj.SimulateHang(False)
+ self.device.Claim('(s)', self.get_current_user())
+
+ self._polkitd_obj.ReleaseHangingCalls()
+
+ with self.assertFprintError('AlreadyInUse'):
+ self.wait_for_device_reply()
+
+ self.device.Release()
+
+ def test_hanging_claim_enroll_does_not_block_new_claim(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll' ])
+ self._polkitd_obj.SimulateHangActions([
+ 'net.reactivated.fprint.device.enroll'])
+ self._polkitd_obj.SetDelay(0.5)
+
+ gdbus = self.start_hanging_gdbus_claim()
+
+ self._polkitd_obj.SimulateHangActions([''])
+ self.device.Claim('(s)', self.get_current_user())
+
+ self.assertIsNone(gdbus.poll())
+ self._polkitd_obj.ReleaseHangingCalls()
+
+ gdbus.wait()
+ with self.assertFprintError('AlreadyInUse'):
+ raise GLib.GError(gdbus.stdout.read())
+
+ self.device.Release()
+
+ def test_hanging_claim_does_not_block_new_release(self):
+ self._polkitd_obj.SetAllowed(['net.reactivated.fprint.device.setusername'])
+ self._polkitd_obj.SimulateHang(True)
+
+ gdbus = self.gdbus_device_method_call_process('Claim', ['testuser'])
+ self.addCleanup(gdbus.kill)
+
+ self.wait_for_hanging_clients()
+ with self.assertFprintError('ClaimDevice'):
+ self.device.Release()
+
+ self.assertIsNone(gdbus.poll())
+
+ def test_hanging_claim_does_not_block_list(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll',
+ 'net.reactivated.fprint.device.verify'])
+
+ self.device.Claim('(s)', '')
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.Release()
+
+ self._polkitd_obj.SimulateHangActions([
+ 'net.reactivated.fprint.device.setusername'])
+
+ gdbus = self.start_hanging_gdbus_claim()
+
+ self.assertEqual(self.device.ListEnrolledFingers('(s)',
+ self.get_current_user()), ['left-thumb'])
+
+ self.assertIsNone(gdbus.poll())
+
+ def test_hanging_claim_can_proceed_when_released(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.verify'])
+
+ self._polkitd_obj.SimulateHangActions([
+ 'net.reactivated.fprint.device.setusername'])
+
+ gdbus = self.start_hanging_gdbus_claim()
+
+ self._polkitd_obj.SimulateHangActions([''])
+ self.device.Claim('(s)', 'testuser')
+ self.device.Release()
+
+ self.assertIsNone(gdbus.poll())
+
+ self._polkitd_obj.ReleaseHangingCalls()
+ gdbus.wait()
+
+ self.assertEqual(gdbus.returncode, 0)
+
+ def test_hanging_claim_does_not_block_empty_list(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll',
+ 'net.reactivated.fprint.device.verify'])
+
+ self._polkitd_obj.SimulateHangActions([
+ 'net.reactivated.fprint.device.setusername'])
+
+ gdbus = self.start_hanging_gdbus_claim()
+
+ with self.assertFprintError('NoEnrolledPrints'):
+ self.device.ListEnrolledFingers('(s)', self.get_current_user())
+
+ self.assertIsNone(gdbus.poll())
+
+ def test_hanging_claim_does_not_block_verification(self):
+ self._polkitd_obj.SetAllowed([
+ 'net.reactivated.fprint.device.setusername',
+ 'net.reactivated.fprint.device.enroll',
+ 'net.reactivated.fprint.device.verify'])
+
+ self.device.Claim('(s)', '')
+ self.enroll_image('whorl', finger='left-thumb')
+ self.device.Release()
+
+ self._polkitd_obj.SimulateHangActions([
+ 'net.reactivated.fprint.device.setusername'])
+
+ gdbus = self.start_hanging_gdbus_claim()
+
+ self.device.Claim('(s)', '')
+ self.device.VerifyStart('(s)', 'any')
+ self.send_image('whorl')
+ self.wait_for_result()
+ self.assertTrue(self._verify_stopped)
+ self.assertEqual(self._last_result, 'verify-match')
+ self.device.VerifyStop()
+ self.device.Release()
+
+ self.assertIsNone(gdbus.poll())
+
+
+class FPrintdUtilsTest(FPrintdVirtualDeviceBaseTest):
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ utils = {
+ 'delete': None,
+ 'enroll': None,
+ 'list': None,
+ 'verify': None,
+ }
+
+ for util in utils:
+ util_bin = 'fprintd-{}'.format(util)
+ if 'FPRINT_BUILD_DIR' in os.environ:
+ print('Testing local build')
+ build_dir = os.environ['FPRINT_BUILD_DIR']
+ path = os.path.join(build_dir, '../utils', util_bin)
+ elif 'UNDER_JHBUILD' in os.environ:
+ print('Testing JHBuild version')
+ jhbuild_prefix = os.environ['JHBUILD_PREFIX']
+ path = os.path.join(jhbuild_prefix, 'bin', util_bin)
+ else:
+ # Assume it is in path
+ utils[util] = util_bin
+ continue
+
+ assert os.path.exists(path), 'failed to find {} in {}'.format(util, path)
+ utils[util] = path
+
+ cls.utils = utils
+ cls.utils_proc = {}
+
+ def util_start(self, name, args=[]):
+ env = os.environ.copy()
+ env['G_DEBUG'] = 'fatal-criticals'
+ env['STATE_DIRECTORY'] = self.state_dir
+ env['RUNTIME_DIRECTORY'] = self.run_dir
+
+ argv = [self.utils[name]] + args
+ valgrind = os.getenv('VALGRIND')
+ if valgrind is not None:
+ argv.insert(0, 'valgrind')
+ argv.insert(1, '--leak-check=full')
+ if os.path.exists(valgrind):
+ argv.insert(2, '--suppressions=%s' % valgrind)
+ self.valgrind = True
+ self.utils_proc[name] = subprocess.Popen(argv,
+ env=env,
+ stdout=None,
+ stderr=subprocess.STDOUT)
+ self.addCleanup(self.utils_proc[name].wait)
+ self.addCleanup(self.utils_proc[name].terminate)
+ return self.utils_proc[name]
+
+ def test_vanished_client_operation_is_cancelled(self):
+ self.device.Claim('(s)', self.get_current_user())
+ self.enroll_image('whorl')
+ self.device.Release()
+
+ verify = self.util_start('verify')
+ time.sleep(1)
+ verify.terminate()
+ self.assertLess(verify.wait(), 128)
+ time.sleep(1)
+
+ self.device.Claim('(s)', self.get_current_user())
+ self.device.Release()
+
+ def test_already_claimed_same_user_delete_enrolled_fingers(self):
+ self.device.DeleteEnrolledFingers('(s)', 'testuser')
+
+ def test_already_claimed_other_user_delete_enrolled_fingers(self):
+ self.device.DeleteEnrolledFingers('(s)', 'nottestuser')
+
+
+
+def list_tests():
+ import unittest_inspector
+ return unittest_inspector.list_tests(sys.modules[__name__])
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == "list-tests":
@@ -527,4 +1706,12 @@
print("%s %s" % (machine, human), end="\n")
sys.exit(0)
- unittest.main(verbosity=2)
+ prog = unittest.main(verbosity=2, exit=False)
+ if prog.result.errors or prog.result.failures:
+ sys.exit(1)
+
+ # Translate to skip error
+ if prog.result.testsRun == len(prog.result.skipped):
+ sys.exit(77)
+
+ sys.exit(0)
diff -Nru fprintd-1.90.1/tests/LSAN-leaks-suppress.txt fprintd-1.90.9/tests/LSAN-leaks-suppress.txt
--- fprintd-1.90.1/tests/LSAN-leaks-suppress.txt 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/tests/LSAN-leaks-suppress.txt 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,4 @@
+leak:initialize_device
+leak:usbi_alloc_device
+leak:libusb-1.0.so.*
+leak:PyMem_RawMalloc
diff -Nru fprintd-1.90.1/tests/meson.build fprintd-1.90.9/tests/meson.build
--- fprintd-1.90.1/tests/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/tests/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -1,36 +1,118 @@
+# Add a way to discover and run python unit tests separately
+# https://github.com/mesonbuild/meson/issues/6851
+python_tests = [
+ # List all the python tests, must be in the form:
+ # {
+ # 'name': 'test name',
+ # 'file': 'full test file path, use files('path')[0]',
+ # Fields below are optional:
+ # 'workdir': '',
+ # 'env': [],
+ # 'depends': [],
+ # 'suite': [],
+ # 'extra_args': [],
+ # 'timeout': 30,
+ # 'is_parallel': true,
+ # }
+]
+
+address_sanitizer = get_option('b_sanitize') == 'address'
+
tests = [
'fprintd',
'test_fprintd_utils',
]
foreach t: tests
- test(t,
- python3,
- args: meson.current_source_dir() / t + '.py',
- suite: ['daemon'],
- depends: [
- fprintd,
- fprintd_utils,
- ],
- env: [
- 'G_DEBUG=fatal-criticals',
- 'G_MESSAGES_DEBUG=all',
- 'FPRINT_BUILD_DIR=' + meson.build_root() / 'src',
- 'TOPSRCDIR=' + meson.source_root(),
- ],
- )
+ python_tests += [
+ {
+ 'name': t,
+ 'file': files(meson.current_source_dir() / t + '.py')[0],
+ 'env': [
+ 'G_DEBUG=fatal-criticals',
+ 'G_MESSAGES_DEBUG=all',
+ 'FPRINT_BUILD_DIR=' + meson.build_root() / 'src',
+ 'TOPSRCDIR=' + meson.source_root(),
+ ],
+ 'depends': [
+ fprintd,
+ fprintd_utils,
+ ],
+ 'suite': [t == 'fprintd' ? 'daemon' : ''],
+ }
+ ]
endforeach
+if get_option('pam')
+ subdir('pam')
+endif
+
+# Add a way to discover and run python unit tests separately
+# https://github.com/mesonbuild/meson/issues/6851
+unittest_inspector = find_program('unittest_inspector.py')
+
+foreach pt: python_tests
+ r = run_command(unittest_inspector, pt.get('file'))
+ unit_tests = r.stdout().strip().split('\n')
+ base_args = [ pt.get('file') ] + pt.get('extra_args', [])
+ suite = pt.get('suite', [])
+
+ if r.returncode() == 0 and unit_tests.length() > 0
+ suite += pt.get('name')
+ else
+ unit_tests = [pt.get('name')]
+ endif
+
+ foreach ut: unit_tests
+ ut_suite = suite
+ ut_args = base_args
+ if unit_tests.length() > 1
+ ut_args += ut
+ ut_suite += ut.split('.')[0]
+ endif
+ test(ut,
+ python3,
+ args: ut_args,
+ suite: ut_suite,
+ depends: pt.get('depends', []),
+ workdir: pt.get('workdir', meson.build_root()),
+ env: pt.get('env', []),
+ timeout: pt.get('timeout', 30),
+ is_parallel: pt.get('is_parallel', true),
+ )
+ endforeach
+endforeach
+
+timeout_multiplier = 1
+test_envs = [
+ 'G_SLICE=always-malloc',
+ 'MALLOC_CHECK_=2',
+]
+
+if address_sanitizer
+ timeout_multiplier = 3
+ test_envs += [
+ 'ADDRESS_SANITIZER=true',
+ 'ASAN_OPTIONS=@0@'.format(':'.join([
+ 'abort_on_error=true',
+ 'symbolize=true',
+ ])),
+ 'LSAN_OPTIONS=@0@'.format(':'.join([
+ 'exitcode=0',
+ 'strict_string_checks=true',
+ 'suppressions=@0@'.format(
+ files(meson.current_source_dir() / 'LSAN-leaks-suppress.txt')[0]),
+ ])),
+ ]
+endif
+
add_test_setup('default_setup',
is_default: true,
- env: [
- 'G_SLICE=always-malloc',
- 'MALLOC_CHECK_=2',
- 'MALLOC_PERTURB_=55',
- ],
+ env: test_envs,
+ timeout_multiplier: timeout_multiplier
)
-if find_program('valgrind', required: false).found()
+if not address_sanitizer and find_program('valgrind', required: false).found()
glib_share = glib_dep.get_pkgconfig_variable('prefix') / 'share' / glib_dep.name()
glib_suppressions = glib_share + '/valgrind/glib.supp'
add_test_setup('valgrind',
@@ -42,6 +124,3 @@
)
endif
-if get_option('pam')
- subdir('pam')
-endif
diff -Nru fprintd-1.90.1/tests/output_checker.py fprintd-1.90.9/tests/output_checker.py
--- fprintd-1.90.1/tests/output_checker.py 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/tests/output_checker.py 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,148 @@
+#! /usr/bin/env python3
+# Copyright © 2020, RedHat Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see .
+# Authors:
+# Benjamin Berg
+
+import os
+import sys
+import fcntl
+import io
+import re
+import time
+import threading
+
+class OutputChecker(object):
+
+ def __init__(self, out=sys.stdout):
+ self._output = out
+ self._pipe_fd_r, self._pipe_fd_w = os.pipe()
+ self._partial_buf = b''
+ self._lines_sem = threading.Semaphore()
+ self._lines = []
+ self._reader_io = io.StringIO()
+
+ # Just to be sure, shouldn't be a problem even if we didn't set it
+ fcntl.fcntl(self._pipe_fd_r, fcntl.F_SETFL,
+ fcntl.fcntl(self._pipe_fd_r, fcntl.F_GETFL) | os.O_CLOEXEC)
+ fcntl.fcntl(self._pipe_fd_w, fcntl.F_SETFL,
+ fcntl.fcntl(self._pipe_fd_w, fcntl.F_GETFL) | os.O_CLOEXEC)
+
+ # Start copier thread
+ self._thread = threading.Thread(target=self._copy)
+ self._thread.start()
+
+ def _copy(self):
+ while True:
+ r = os.read(self._pipe_fd_r, 1024)
+ if not r:
+ return
+
+ l = r.split(b'\n')
+ l[0] = self._partial_buf + l[0]
+ self._lines.extend(l[:-1])
+ self._partial_buf = l[-1]
+
+ self._lines_sem.release()
+
+ os.write(self._output.fileno(), r)
+
+ def check_line_re(self, needle_re, timeout=0, failmsg=None):
+ deadline = time.time() + timeout
+
+ if isinstance(needle_re, str):
+ needle_re = needle_re.encode('ascii')
+
+ r = re.compile(needle_re)
+ ret = []
+
+ while True:
+ try:
+ l = self._lines.pop(0)
+ except IndexError:
+ # Check if should wake up
+ if not self._lines_sem.acquire(timeout = deadline - time.time()):
+ if failmsg:
+ raise AssertionError(failmsg)
+ else:
+ raise AssertionError('Timed out waiting for needle %s (timeout: %0.2f)' % (str(needle_re), timeout))
+ continue
+
+ ret.append(l)
+ if r.search(l):
+ return ret
+
+ def check_line(self, needle, timeout=0, failmsg=None):
+ if isinstance(needle, str):
+ needle = needle.encode('ascii')
+
+ needle_re = re.escape(needle)
+
+ return self.check_line_re(needle_re, timeout=timeout, failmsg=failmsg)
+
+ def check_no_line_re(self, needle_re, wait=0, failmsg=None):
+ deadline = time.time() + wait
+
+ if isinstance(needle_re, str):
+ needle_re = needle_re.encode('ascii')
+
+ r = re.compile(needle_re)
+ ret = []
+
+ while True:
+ try:
+ l = self._lines.pop(0)
+ except IndexError:
+ # Check if should wake up
+ if not self._lines_sem.acquire(timeout = deadline - time.time()):
+ # Timed out, so everything is good
+ break
+ continue
+
+ ret.append(l)
+ if r.search(l):
+ if failmsg:
+ raise AssertionError(failmsg)
+ else:
+ raise AssertionError('Found needle %s but shouldn\'t have been there (timeout: %0.2f)' % (str(needle_re), timeout))
+
+ return ret
+
+ def check_no_line(self, needle, wait=0, failmsg=None):
+ if isinstance(needle, str):
+ needle = needle.encode('ascii')
+
+ needle_re = re.escape(needle)
+
+ return self.check_no_line_re(needle_re, wait=wait, failmsg=failmsg)
+
+ def clear(self):
+ ret = self._lines
+ self._lines = []
+ return ret
+
+ def assert_closed(self, timeout=1):
+ self._thread.join(timeout)
+ if self._thread.is_alive() != False:
+ raise AssertionError("OutputCheck: Write side has not been closed yet!")
+
+ @property
+ def fd(self):
+ return self._pipe_fd_w
+
+ def writer_attached(self):
+ os.close(self._pipe_fd_w)
+ self._pipe_fd_w = -1
+
diff -Nru fprintd-1.90.1/tests/pam/meson.build fprintd-1.90.9/tests/pam/meson.build
--- fprintd-1.90.1/tests/pam/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/tests/pam/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -4,24 +4,56 @@
'test_pam_fprintd',
]
+preloaded_libs = []
+pam_tests_ld_preload = []
+
+if address_sanitizer
+ # ASAN has to be the first in list
+ preloaded_libs += 'asan'
+endif
+
+preloaded_libs += 'pam_wrapper'
+
+foreach libname: preloaded_libs
+ lib = run_command(meson.get_compiler('c'),
+ '-print-file-name=lib@0@.so'.format(libname)
+ ).stdout().strip()
+
+ # Support linker script files
+ if run_command('grep', '-qI', '^INPUT', files(lib)).returncode() == 0
+ out = run_command('cat', lib).stdout()
+ lib = out.split('(')[1].split(')')[0].strip()
+ endif
+
+ if lib != '' and lib[0] == '/'
+ message('Found library @0@ as @1@'.format(libname, lib))
+ pam_tests_ld_preload += '@0@'.format(files(lib)[0])
+ else
+ tests = []
+ warning('No library found for ' + libname + ', skipping PAM tests')
+ endif
+endforeach
+
foreach t: tests
- test(t,
- python3,
- args: meson.current_source_dir() / t + '.py',
- suite: ['PAM'],
- depends: [
- pam_fprintd,
- pam_service_file,
- ],
- env: [
- 'TOPBUILDDIR=' + meson.build_root(),
- 'TOPSRCDIR=' + meson.source_root(),
- 'LD_PRELOAD=libpam_wrapper.so',
- 'PAM_WRAPPER=1',
- 'PAM_WRAPPER_DEBUGLEVEL=2',
- 'PAM_WRAPPER_SERVICE_DIR=' + meson.current_build_dir() / 'services',
- 'G_DEBUG=fatal-warnings',
- ],
- timeout: 60,
- )
+ python_tests += [
+ {
+ 'name': t,
+ 'file': files(meson.current_source_dir() / t + '.py')[0],
+ 'is_parallel': false,
+ 'env': [
+ 'TOPBUILDDIR=' + meson.build_root(),
+ 'TOPSRCDIR=' + meson.source_root(),
+ 'LD_PRELOAD=' + ' '.join(pam_tests_ld_preload),
+ 'PAM_WRAPPER=1',
+ 'PAM_WRAPPER_DEBUGLEVEL=2',
+ 'PAM_WRAPPER_SERVICE_DIR=' + meson.current_build_dir() / 'services',
+ 'G_DEBUG=fatal-warnings',
+ ],
+ 'depends': [
+ pam_fprintd,
+ pam_service_file,
+ ],
+ 'suite': ['PAM'],
+ }
+ ]
endforeach
diff -Nru fprintd-1.90.1/tests/pam/test_pam_fprintd.py fprintd-1.90.9/tests/pam/test_pam_fprintd.py
--- fprintd-1.90.1/tests/pam/test_pam_fprintd.py 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/tests/pam/test_pam_fprintd.py 2021-01-13 12:23:24.000000000 +0000
@@ -16,15 +16,13 @@
import sys
import subprocess
import dbus
-import dbus.mainloop.glib
import dbusmock
-import fcntl
+import glob
import os
+import shutil
import time
import pypamtest
-dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-
PAM_SUCCESS = 0
PAM_AUTH_ERR = 7
PAM_AUTHINFO_UNAVAIL = 9
@@ -71,12 +69,12 @@
def tearDownClass(klass):
klass.stop_monitor()
+ # Remove pam wrapper files, as they may break other tests
+ [shutil.rmtree(i) for i in glob.glob('/tmp/pam.[0-9A-z]')]
+
def setUp(self):
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
- self.template_name, {}, stdout=subprocess.PIPE)
- # set log to nonblocking
- flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
- fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+ self.template_name, {})
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
def tearDown(self):
@@ -88,6 +86,50 @@
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 = [
+ ( 'verify-unknown-error', True, 2 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
+ self.assertEqual(len(res.errors), 0)
+
+ def test_pam_fprintd_identify_error2(self):
+ self.setup_device()
+ script = [
+ ( 'verify-disconnected', True, 2 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
+ self.assertEqual(len(res.errors), 0)
+
+ def test_pam_fprintd_identify_error3(self):
+ self.setup_device()
+ script = [
+ ( 'verify-INVALID', True, 2 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTH_ERR)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
+ self.assertEqual(len(res.errors), 1)
+ self.assertRegex(res.errors[0], r'An unknown error occurred')
+
def test_pam_fprintd_auth(self):
self.setup_device()
script = [
@@ -101,6 +143,81 @@
self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
self.assertEqual(len(res.errors), 0)
+ def test_pam_fprintd_no_fingers(self):
+ self.setup_device()
+ self.device_mock.SetEnrolledFingers('toto', dbus.Array(set([]), signature='s'))
+ script = [
+ ( 'verify-match', True, 1 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ def test_pam_fprintd_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 = [
+ ( 'MOCK: no-prints', True, 1),
+ ( 'verify-match', True, 1 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_USER_UNKNOWN)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ def test_pam_fprintd_blocks_unexpected_auth(self):
+ self.setup_device()
+ script = [
+ ( 'verify-match', True, -500 ), # This one is sent before VerifyStart has completed
+ ( 'verify-no-match', True, 1 ),
+ ( 'verify-no-match', True, 1 ),
+ ( 'verify-no-match', True, 1 ),
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
+ self.assertEqual(len(res.errors), 3)
+ self.assertRegex(res.errors[0], r'Failed to match fingerprint')
+ self.assertRegex(res.errors[0], r'Failed to match fingerprint')
+ self.assertRegex(res.errors[0], r'Failed to match fingerprint')
+
+ def test_pam_fprintd_blocks_unexpected_auth2(self):
+ self.setup_device()
+ script = [
+ ( 'verify-no-match', True, 1 ),
+ ( 'verify-match', True, -500 ), # This one is sent before VerifyStart has completed
+ ( 'verify-no-match', True, 1 ),
+ ( 'verify-no-match', True, 1 ),
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_MAXTRIES)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertRegex(res.info[0], r'Swipe your left little finger across the fingerprint reader')
+ self.assertEqual(len(res.errors), 3)
+ self.assertRegex(res.errors[0], r'Failed to match fingerprint')
+ self.assertRegex(res.errors[0], r'Failed to match fingerprint')
+ self.assertRegex(res.errors[0], r'Failed to match fingerprint')
+
def test_pam_fprintd_dual_reader_auth(self):
device_path = self.obj_fprintd_mock.AddDevice('FDO Sandpaper Reader', 3, 'press')
sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
@@ -119,6 +236,31 @@
self.assertRegex(res.info[0], r'Place your left middle finger on FDO Sandpaper Reader')
self.assertEqual(len(res.errors), 0)
+ def test_pam_fprintd_multi_reader_not_all_enrolled(self):
+ # Add a 1st device with actual enrolled prints
+ device_path = self.obj_fprintd_mock.AddDevice('FDO Empty reader', 3, 'press')
+ empty_reader = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
+ empty_reader.SetEnrolledFingers('toto', dbus.Array(set([]), signature='s'))
+
+ # Add a 2nd device with actual enrolled prints
+ device_path = self.obj_fprintd_mock.AddDevice('FDO Most Used Reader', 3, 'press')
+ sandpaper_device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
+ sandpaper_device_mock.SetEnrolledFingers('toto', ['left-middle-finger', 'right-middle-finger'])
+ script = [
+ ( 'verify-match', True, 2 )
+ ]
+ sandpaper_device_mock.SetVerifyScript(script)
+
+ # Add a 3rd device, with only one enrolled finger
+ self.setup_device()
+ self.device_mock.SetEnrolledFingers('toto', ['left-middle-finger'])
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_SUCCESS)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertRegex(res.info[0], r'Place your left middle finger on FDO Most Used Reader')
+ self.assertEqual(len(res.errors), 0)
+
def test_pam_fprintd_last_try_auth(self):
self.setup_device()
script = [
@@ -154,6 +296,20 @@
self.assertRegex(res.errors[1], r'Failed to match fingerprint')
self.assertRegex(res.errors[2], r'Failed to match fingerprint')
+ def test_pam_already_claimed(self):
+ self.setup_device()
+ script = [
+ ( 'verify-match', True, 2 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+ self.device_mock.SetClaimed('toto')
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+
+ self.assertEqual(len(res.info), 0)
+ self.assertEqual(len(res.errors), 0)
+
def test_pam_timeout(self):
self.setup_device()
@@ -161,6 +317,19 @@
res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
self.assertRegex(res.info[1], r'Verification timed out')
+ def test_pam_notices_fprintd_disappearing(self):
+ self.setup_device()
+
+ script = [
+ ( 'MOCK: quit', True, 0 ),
+ ]
+ self.device_mock.SetVerifyScript(script)
+
+ tc = pypamtest.TestCase(pypamtest.PAMTEST_AUTHENTICATE, expected_rv=PAM_AUTHINFO_UNAVAIL)
+ res = pypamtest.run_pamtest("toto", "fprintd-pam-test", [tc], [ 'unused' ])
+ self.assertEqual(len(res.errors), 0)
+ self.assertEqual(len(res.info), 0)
+
if __name__ == '__main__':
if 'PAM_WRAPPER_SERVICE_DIR' not in os.environ:
print('Cannot run test without environment set correctly, run "meson test" instead')
diff -Nru fprintd-1.90.1/tests/test_fprintd_utils.py fprintd-1.90.9/tests/test_fprintd_utils.py
--- fprintd-1.90.1/tests/test_fprintd_utils.py 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/tests/test_fprintd_utils.py 2021-01-13 12:23:24.000000000 +0000
@@ -18,13 +18,27 @@
import dbus
import dbus.mainloop.glib
import dbusmock
-import fcntl
import os
import time
+from output_checker import OutputChecker
+
+
+VALID_FINGER_NAMES = [
+ 'left-thumb',
+ 'left-index-finger',
+ 'left-middle-finger',
+ 'left-ring-finger',
+ 'left-little-finger',
+ 'right-thumb',
+ 'right-index-finger',
+ 'right-middle-finger',
+ 'right-ring-finger',
+ 'right-little-finger'
+]
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-class TestFprintd(dbusmock.DBusTestCase):
+class TestFprintdUtilsBase(dbusmock.DBusTestCase):
'''Test fprintd utilities'''
@classmethod
@@ -57,130 +71,231 @@
if os.path.exists(valgrind):
klass.wrapper_args += ['--suppressions={}'.format(valgrind)]
+ if 'ADDRESS_SANITIZER' in os.environ:
+ klass.sleep_time *= 2
+
def setUp(self):
+ super().setUp()
(self.p_mock, self.obj_fprintd_manager) = self.spawn_server_template(
- self.template_name, {}, stdout=subprocess.PIPE)
+ self.template_name, {})
# set log to nonblocking
- flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
- fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
self.obj_fprintd_mock = dbus.Interface(self.obj_fprintd_manager, 'net.reactivated.Fprint.Manager.Mock')
def tearDown(self):
self.p_mock.terminate()
self.p_mock.wait()
+ super().tearDown()
def setup_device(self):
- device_path = self.obj_fprintd_mock.AddDevice('FDO Trigger Finger Laser Reader', 3, 'swipe')
- self.device_mock = self.dbus_con.get_object('net.reactivated.Fprint', device_path)
- self.device_mock.SetEnrolledFingers('toto', ['left-little-finger', 'right-little-finger'])
+ self.device_path = self.obj_fprintd_mock.AddDevice(
+ 'FDO Trigger Finger Laser Reader', 3, 'swipe')
+ self.device_mock = self.dbus_con.get_object('net.reactivated.Fprint',
+ self.device_path)
+ self.set_enrolled_fingers(['left-little-finger', 'right-little-finger'])
+
+ def set_enrolled_fingers(self, fingers, user='toto'):
+ self.enrolled_fingers = fingers
+ self.device_mock.SetEnrolledFingers('toto', self.enrolled_fingers,
+ signature='sas')
+
+ def start_utility_process(self, utility_name, args=[], sleep=True):
+ utility = [ os.path.join(self.tools_prefix, 'fprintd-{}'.format(utility_name)) ]
+ output = OutputChecker()
+ process = subprocess.Popen(self.wrapper_args + utility + args,
+ stdout=output.fd,
+ stderr=subprocess.STDOUT)
+ output.writer_attached()
+
+ self.addCleanup(output.assert_closed)
+ self.addCleanup(self.try_stop_utility_process, process)
+
+ if sleep:
+ time.sleep(self.sleep_time)
+
+ return process, output
+
+ def stop_utility_process(self, process):
+ process.terminate()
+ process.wait()
+
+ def try_stop_utility_process(self, process):
+ try:
+ self.stop_utility_process(process)
+ except:
+ pass
+
+ def run_utility_process(self, utility_name, args=[], sleep=True, timeout=None):
+ proc, output = self.start_utility_process(utility_name, args=args, sleep=sleep)
+ ret = proc.wait(timeout=timeout if timeout is not None else self.sleep_time * 4)
+ self.assertLessEqual(ret, 128)
- def test_fprintd_enroll(self):
- self.setup_device()
+ return b''.join(output.clear()), ret
- mock_log = tempfile.NamedTemporaryFile()
- process = subprocess.Popen(self.wrapper_args + [self.tools_prefix + 'fprintd-enroll', '-f', 'right-index-finger', 'toto'],
- stdout=mock_log,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- time.sleep(self.sleep_time)
+class TestFprintdUtils(TestFprintdUtilsBase):
+ def setUp(self):
+ super().setUp()
+ self.setup_device()
- with open(mock_log.name) as f:
- out = f.read()
- self.assertRegex(out, r'right-index-finger')
+ def test_fprintd_enroll(self):
+ process, out = self.start_utility_process('enroll', ['-f', 'right-index-finger', 'toto'])
+
+ out.check_line(rb'right-index-finger', 0)
self.device_mock.EmitEnrollStatus('enroll-completed', True)
- time.sleep(self.sleep_time)
- with open(mock_log.name) as f:
- out = f.read()
- self.assertRegex(out, 'Enroll result: enroll-completed')
+ out.check_line(rb'Enroll result: enroll-completed', self.sleep_time)
- def test_fprintd_verify(self):
- self.setup_device()
+ def test_fprintd_list(self):
+ # Rick has no fingerprints enrolled
+ out, ret = self.run_utility_process('list', ['rick'])
+ self.assertRegex(out, rb'has no fingers enrolled for')
+ self.assertEqual(ret, 0)
- mock_log = tempfile.NamedTemporaryFile()
- process = subprocess.Popen(self.wrapper_args + [self.tools_prefix + 'fprintd-verify', 'toto'],
- stdout=mock_log,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
+ # Toto does
+ out, ret = self.run_utility_process('list', ['toto'])
+ self.assertRegex(out, rb'right-little-finger')
+ self.assertEqual(ret, 0)
- time.sleep(self.sleep_time)
+ def test_fprintd_delete(self):
+ # Has fingerprints enrolled
+ out, ret = self.run_utility_process('list', ['toto'])
+ self.assertRegex(out, rb'left-little-finger')
+ self.assertEqual(ret, 0)
+ self.assertRegex(out, rb'right-little-finger')
- with open(mock_log.name) as f:
- out = f.read()
- self.assertRegex(out, r'left-little-finger')
- self.assertNotRegex(out, 'Verify result: verify-match \(done\)')
+ # Delete fingerprints
+ out, ret = self.run_utility_process('delete', ['toto'])
+ self.assertRegex(out, rb'Fingerprints deleted')
+ self.assertEqual(ret, 0)
- self.device_mock.EmitVerifyStatus('verify-match', True)
- time.sleep(self.sleep_time)
+ # Doesn't have fingerprints
+ out, ret = self.run_utility_process('list', ['toto'])
+ self.assertRegex(out, rb'has no fingers enrolled for')
+ self.assertEqual(ret, 0)
- with open(mock_log.name) as f:
- out = f.read()
- self.assertRegex(out, 'Verify result: verify-match \(done\)')
- def test_fprintd_verify_script(self):
+class TestFprintdUtilsNoDeviceTests(TestFprintdUtilsBase):
+ def test_fprintd_enroll(self):
+ out, ret = self.run_utility_process('enroll', ['toto'])
+ self.assertIn(b'No devices available', out)
+ self.assertEqual(ret, 1)
+
+ def test_fprintd_list(self):
+ out, ret = self.run_utility_process('list', ['toto'])
+ self.assertIn(b'No devices available', out)
+ self.assertEqual(ret, 1)
+
+ def test_fprintd_delete(self):
+ out, ret = self.run_utility_process('delete', ['toto'])
+ self.assertIn(b'No devices available', out)
+ self.assertEqual(ret, 1)
+
+ def test_fprintd_verify(self):
+ out, ret = self.run_utility_process('verify', ['toto'])
+ self.assertIn(b'No devices available', out)
+ self.assertEqual(ret, 1)
+
+
+class TestFprintdUtilsVerify(TestFprintdUtilsBase):
+ def setUp(self):
+ super().setUp()
self.setup_device()
- script = [
- ( 'verify-match', True, 2 )
- ]
- self.device_mock.SetVerifyScript(script)
- mock_log = tempfile.NamedTemporaryFile()
- process = subprocess.Popen(self.wrapper_args + [self.tools_prefix + 'fprintd-verify', 'toto'],
- stdout=mock_log,
- stderr=subprocess.STDOUT,
- universal_newlines=True)
+ def start_verify_process(self, user='toto', finger=None, nowait=False):
+ args = [user]
+ if finger:
+ args += ['-f', finger]
+
+ self.process, self.output = self.start_utility_process('verify', args)
+ if nowait:
+ return
+
+ preamble = self.output.check_line(b'Verify started!')
+
+ out = b''.join(preamble)
+
+ self.assertNotIn(b'Verify result:', out)
+
+ if finger:
+ expected_finger = finger
+ if finger == 'any' and not self.device_mock.HasIdentification():
+ expected_finger = self.enrolled_fingers[0]
+ self.assertEqual(self.device_mock.GetSelectedFinger(), expected_finger)
+
+ def assertVerifyMatch(self, match):
+ self.output.check_line(r'Verify result: {} (done)'.format(
+ 'verify-match' if match else 'verify-no-match'))
+ def test_fprintd_verify(self):
+ self.start_verify_process()
+
+ self.device_mock.EmitVerifyStatus('verify-match', True)
time.sleep(self.sleep_time)
+ self.assertVerifyMatch(True)
- with open(mock_log.name) as f:
- out = f.read()
- self.assertRegex(out, r'left-little-finger')
- self.assertNotRegex(out, 'Verify result: verify-match \(done\)')
+ def test_fprintd_verify_enrolled_fingers(self):
+ for finger in self.enrolled_fingers:
+ self.start_verify_process(finger=finger)
+
+ self.device_mock.EmitVerifyStatus('verify-match', True)
+ time.sleep(self.sleep_time)
+ self.assertVerifyMatch(True)
- time.sleep(2)
+ def test_fprintd_verify_any_finger_no_identification(self):
+ self.start_verify_process(finger='any')
- with open(mock_log.name) as f:
- out = f.read()
- self.assertRegex(out, 'Verify result: verify-match \(done\)')
+ self.device_mock.EmitVerifyStatus('verify-match', True)
+ time.sleep(self.sleep_time)
+ self.assertVerifyMatch(True)
- def test_fprintd_list(self):
- self.setup_device()
+ def test_fprintd_verify_any_finger_identification(self):
+ self.obj_fprintd_mock.RemoveDevice(self.device_path)
+ self.device_path = self.obj_fprintd_mock.AddDevice('Full powered device',
+ 3, 'press', True)
+ self.device_mock = self.dbus_con.get_object('net.reactivated.Fprint',
+ self.device_path)
+ self.set_enrolled_fingers(VALID_FINGER_NAMES)
+ self.start_verify_process(finger='any')
- # Rick has no fingerprints enrolled
- out = subprocess.check_output(self.wrapper_args + [self.tools_prefix + 'fprintd-list', 'rick'],
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- self.assertRegex(out, r'has no fingers enrolled for')
+ self.device_mock.EmitVerifyStatus('verify-match', True)
+ time.sleep(self.sleep_time)
+ self.assertVerifyMatch(True)
- # Toto does
- out = subprocess.check_output(self.wrapper_args + [self.tools_prefix + 'fprintd-list', 'toto'],
- universal_newlines=True)
- self.assertRegex(out, r'left-little-finger')
- self.assertRegex(out, r'right-little-finger')
+ def test_fprintd_verify_not_enrolled_fingers(self):
+ for finger in [f for f in VALID_FINGER_NAMES if f not in self.enrolled_fingers]:
+ self.start_verify_process(finger=finger, nowait=True)
+ regex = r'Finger \'{}\' not enrolled'.format(finger)
+ self.output.check_line_re(regex, timeout=self.sleep_time)
+
+ self.device_mock.Release()
+
+ def test_fprintd_verify_no_enrolled_fingers(self):
+ self.set_enrolled_fingers([])
+ self.start_verify_process(nowait=True)
+ self.output.check_line(b'No fingers enrolled for this device.', timeout=self.sleep_time)
+ self.assertEqual(self.process.poll(), 1)
+
+ def test_fprintd_list_all_fingers(self):
+ self.set_enrolled_fingers(VALID_FINGER_NAMES)
+ self.start_verify_process()
- def test_fprintd_delete(self):
- self.setup_device()
+ def test_fprintd_verify_script(self):
+ script = [
+ ( 'verify-match', True, 2 )
+ ]
+ self.device_mock.SetVerifyScript(script)
+ time.sleep(2)
- # Has fingerprints enrolled
- out = subprocess.check_output(self.wrapper_args + [self.tools_prefix + 'fprintd-list', 'toto'],
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- self.assertRegex(out, r'left-little-finger')
- self.assertRegex(out, r'right-little-finger')
+ self.start_verify_process()
+ time.sleep(2 + self.sleep_time)
+ self.assertVerifyMatch(True)
- # Delete fingerprints
- out = subprocess.check_output(self.wrapper_args + [self.tools_prefix + 'fprintd-delete', 'toto'],
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- self.assertRegex(out, r'Fingerprints deleted')
+ def test_fprintd_multiple_verify_fails(self):
+ self.start_verify_process()
- # Doesn't have fingerprints
- out = subprocess.check_output(self.wrapper_args + [self.tools_prefix + 'fprintd-list', 'toto'],
- stderr=subprocess.STDOUT,
- universal_newlines=True)
- self.assertRegex(out, r'has no fingers enrolled for')
+ self.start_verify_process(nowait=True)
+ self.output.check_line_re(rb'Device already in use by [A-z]+', timeout=self.sleep_time)
if __name__ == '__main__':
# avoid writing to stderr
diff -Nru fprintd-1.90.1/tests/unittest_inspector.py fprintd-1.90.9/tests/unittest_inspector.py
--- fprintd-1.90.1/tests/unittest_inspector.py 1970-01-01 00:00:00.000000000 +0000
+++ fprintd-1.90.9/tests/unittest_inspector.py 2021-01-13 12:23:24.000000000 +0000
@@ -0,0 +1,46 @@
+#! /usr/bin/env python3
+# Copyright © 2020, Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see .
+# Authors:
+# Marco Trevisan
+
+import argparse
+import importlib.util
+import inspect
+import os
+import unittest
+
+def list_tests(module):
+ tests = []
+ for name, obj in inspect.getmembers(module):
+ if inspect.isclass(obj) and issubclass(obj, unittest.TestCase):
+ cases = unittest.defaultTestLoader.getTestCaseNames(obj)
+ tests += [ (obj, '{}.{}'.format(name, t)) for t in cases ]
+ return tests
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('unittest_source', type=argparse.FileType('r'))
+
+ args = parser.parse_args()
+ source_path = args.unittest_source.name
+ spec = importlib.util.spec_from_file_location(
+ os.path.basename(source_path), source_path)
+ module = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(module)
+
+ for machine, human in list_tests(module):
+ print(human)
diff -Nru fprintd-1.90.1/utils/delete.c fprintd-1.90.9/utils/delete.c
--- fprintd-1.90.1/utils/delete.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/utils/delete.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* fprintd example to delete fingerprints
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -20,123 +21,151 @@
#include
#include
#include
-#include
-#include "manager-dbus-glue.h"
-#include "device-dbus-glue.h"
+#include "fprintd-dbus.h"
-static DBusGProxy *manager = NULL;
-static DBusGConnection *connection = NULL;
+static FprintDBusManager *manager = NULL;
+static GDBusConnection *connection = NULL;
-static void create_manager(void)
+static void
+create_manager (void)
{
- GError *error = NULL;
+ g_autoptr(GError) error = NULL;
- connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
- if (connection == NULL) {
- g_print("Failed to connect to session bus: %s\n", error->message);
- exit (1);
- }
-
- manager = dbus_g_proxy_new_for_name(connection,
- "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager",
- "net.reactivated.Fprint.Manager");
+ 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);
+ }
}
-static void delete_fingerprints(DBusGProxy *dev, const char *username)
+static void
+delete_fingerprints (FprintDBusDevice *dev, const char *username)
{
- GError *error = NULL;
- GHashTable *props;
- DBusGProxy *p;
-
- p = dbus_g_proxy_new_from_proxy(dev, "org.freedesktop.DBus.Properties", NULL);
- if (!dbus_g_proxy_call (p, "GetAll", &error, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID,
- dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) {
- g_print("GetAll on the Properties interface failed: %s\n", error->message);
- exit (1);
- }
-
- if (!net_reactivated_Fprint_Device_claim(dev, username, &error)) {
- g_print("failed to claim device: %s\n", error->message);
- exit (1);
- }
-
- if (!net_reactivated_Fprint_Device_delete_enrolled_fingers2(dev, &error)) {
- if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) {
- g_print("ListEnrolledFingers failed: %s\n", error->message);
- exit (1);
- } else {
- g_print ("No fingerprints to delete on %s\n", g_value_get_string (g_hash_table_lookup (props, "name")));
- }
- } else {
- g_print ("Fingerprints deleted on %s\n", g_value_get_string (g_hash_table_lookup (props, "name")));
- }
-
- if (!net_reactivated_Fprint_Device_release(dev, &error)) {
- g_print("ReleaseDevice failed: %s\n", error->message);
- exit (1);
- }
+ g_autoptr(GError) error = NULL;
- g_hash_table_destroy (props);
- g_object_unref (p);
+ 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_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)
{
- GError *error = NULL;
- GPtrArray *devices;
- char *path;
- guint i;
-
- if (!net_reactivated_Fprint_Manager_get_devices(manager, &devices, &error)) {
- g_print("list_devices failed: %s\n", error->message);
- exit (1);
- }
-
- if (devices->len == 0) {
- g_print("No devices found\n");
- exit(1);
- }
-
- g_print("found %d devices\n", devices->len);
- for (i = 0; i < devices->len; i++) {
- path = g_ptr_array_index(devices, i);
- g_print("Device at %s\n", path);
- }
-
- for (i = 0; i < devices->len; i++) {
- guint j;
- DBusGProxy *dev;
-
- path = g_ptr_array_index(devices, i);
- g_print("Using device %s\n", path);
-
- /* FIXME use for_name_owner?? */
- dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint",
- path, "net.reactivated.Fprint.Device");
-
- for (j = 1; argv[j] != NULL; j++)
- delete_fingerprints (dev, argv[j]);
-
- g_object_unref (dev);
- }
-
- g_ptr_array_foreach(devices, (GFunc) g_free, NULL);
- g_ptr_array_free(devices, TRUE);
+ 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);
+ }
+
+ 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);
+ }
+
+ for (i = 0; devices[i] != NULL; i++)
+ {
+ g_autoptr(FprintDBusDevice) dev = NULL;
+ guint j;
+
+ 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);
+
+ 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 [usernames...]\n", argv[0]);
- return 1;
- }
+ if (argc < 2)
+ {
+ g_print ("Usage: %s [usernames...]\n", argv[0]);
+ return 1;
+ }
- process_devices (argv);
+ process_devices (argv);
- return 0;
+ return 0;
}
-
diff -Nru fprintd-1.90.1/utils/enroll.c fprintd-1.90.9/utils/enroll.c
--- fprintd-1.90.1/utils/enroll.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/utils/enroll.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* fprintd example to enroll right index finger
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -21,170 +22,204 @@
#include
#include
#include
-#include
-#include "manager-dbus-glue.h"
-#include "device-dbus-glue.h"
-#include "marshal.h"
+#include "fprintd-dbus.h"
#define N_(x) x
#define TR(x) x
#include "fingerprint-strings.h"
-static DBusGProxy *manager = NULL;
-static DBusGConnection *connection = NULL;
+static FprintDBusManager *manager = NULL;
+static GDBusConnection *connection = NULL;
static char *finger_name = NULL;
static char **usernames = NULL;
-static void create_manager(void)
+static void
+create_manager (void)
{
- GError *error = NULL;
+ g_autoptr(GError) error = NULL;
- connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
- if (connection == NULL) {
- g_print("Failed to connect to session bus: %s\n", error->message);
- exit (1);
- }
-
- manager = dbus_g_proxy_new_for_name(connection,
- "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager",
- "net.reactivated.Fprint.Manager");
-}
-
-static DBusGProxy *open_device(const char *username)
-{
- GError *error = NULL;
- gchar *path;
- DBusGProxy *dev;
-
- if (!net_reactivated_Fprint_Manager_get_default_device(manager, &path, &error)) {
- g_print("list_devices failed: %s\n", error->message);
- exit (1);
- }
-
- if (path == NULL) {
- g_print("No devices found\n");
- exit(1);
- }
-
- g_print("Using device %s\n", path);
-
- /* FIXME use for_name_owner?? */
- dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint",
- path, "net.reactivated.Fprint.Device");
-
- g_free (path);
-
- if (!net_reactivated_Fprint_Device_claim(dev, username, &error)) {
- g_print("failed to claim device: %s\n", error->message);
- exit (1);
- }
- return dev;
-}
-
-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;
-}
-
-static void do_enroll(DBusGProxy *dev)
-{
- GError *error = NULL;
- gboolean enroll_completed = FALSE;
- gboolean found;
- guint i;
-
- dbus_g_proxy_add_signal(dev, "EnrollStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL);
- dbus_g_proxy_connect_signal(dev, "EnrollStatus", G_CALLBACK(enroll_result),
- &enroll_completed, 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) {
- GString *s;
-
- 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);
- g_string_free (s, TRUE);
- exit (1);
- }
-
- g_print("Enrolling %s finger.\n", finger_name);
- if (!net_reactivated_Fprint_Device_enroll_start(dev, finger_name, &error)) {
- g_print("EnrollStart failed: %s\n", error->message);
- exit (1);
- }
-
- while (!enroll_completed)
- g_main_context_iteration(NULL, TRUE);
-
- dbus_g_proxy_disconnect_signal(dev, "EnrollStatus",
- G_CALLBACK(enroll_result), &enroll_completed);
-
- if (!net_reactivated_Fprint_Device_enroll_stop(dev, &error)) {
- g_print("VerifyStop failed: %s\n", error->message);
- exit(1);
- }
-}
-
-static void release_device(DBusGProxy *dev)
-{
- GError *error = NULL;
- if (!net_reactivated_Fprint_Device_release(dev, &error)) {
- g_print("ReleaseDevice failed: %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);
+ }
+}
+
+static FprintDBusDevice *
+open_device (const char *username)
+{
+ 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);
+ }
+
+ 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);
+
+ 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);
+}
+
+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;
+}
+
+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;
+
+ g_variant_get (parameters, "(&sb)", &result, &done);
+ enroll_result (G_OBJECT (proxy), result, done, user_data);
+ }
+}
+
+static void
+do_enroll (FprintDBusDevice *dev)
+{
+ 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);
+
+ 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);
+ }
+
+ 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);
+
+ 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);
+ }
+}
+
+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);
+ }
}
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)
{
- GOptionContext *context;
- GError *err = NULL;
- DBusGProxy *dev;
+ g_autoptr(FprintDBusDevice) dev = NULL;
+ GOptionContext *context;
- setlocale (LC_ALL, "");
+ g_autoptr(GError) err = NULL;
- dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN,
- G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID);
+ setlocale (LC_ALL, "");
- context = g_option_context_new ("Enroll a fingerprint");
- g_option_context_add_main_entries (context, entries, NULL);
+ context = g_option_context_new ("Enroll 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);
- g_error_free (err);
- 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 (finger_name == NULL)
- finger_name = g_strdup("right-index-finger");
+ if (finger_name == NULL)
+ finger_name = g_strdup ("right-index-finger");
- create_manager();
+ create_manager ();
- dev = open_device(usernames ? usernames[0] : NULL);
- do_enroll(dev);
- release_device(dev);
- g_free(finger_name);
- g_strfreev(usernames);
- return 0;
+ dev = open_device (usernames ? usernames[0] : "");
+ do_enroll (dev);
+ release_device (dev);
+ g_free (finger_name);
+ g_strfreev (usernames);
+ return 0;
}
-
diff -Nru fprintd-1.90.1/utils/list.c fprintd-1.90.9/utils/list.c
--- fprintd-1.90.1/utils/list.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/utils/list.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* fprintd example to list enrolled fingerprints
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -20,128 +21,142 @@
#include
#include
#include
-#include
-#include "manager-dbus-glue.h"
-#include "device-dbus-glue.h"
+#include "fprintd-dbus.h"
-static DBusGProxy *manager = NULL;
-static DBusGConnection *connection = NULL;
+static FprintDBusManager *manager = NULL;
+static GDBusConnection *connection = NULL;
-static void create_manager(void)
+static void
+create_manager (void)
{
- GError *error = NULL;
+ g_autoptr(GError) error = NULL;
- connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
- if (connection == NULL) {
- g_print("Failed to connect to session bus: %s\n", error->message);
- exit (1);
- }
-
- manager = dbus_g_proxy_new_for_name(connection,
- "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager",
- "net.reactivated.Fprint.Manager");
+ 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);
+ }
}
-static void list_fingerprints(DBusGProxy *dev, const char *username)
+static void
+list_fingerprints (FprintDBusDevice *dev, const char *username)
{
- GError *error = NULL;
- char **fingers;
- GHashTable *props;
- DBusGProxy *p;
- guint i;
-
- if (!net_reactivated_Fprint_Device_list_enrolled_fingers(dev, username, &fingers, &error)) {
- if (dbus_g_error_has_name (error, "net.reactivated.Fprint.Error.NoEnrolledPrints") == FALSE) {
- g_print("ListEnrolledFingers failed: %s\n", error->message);
- exit (1);
- } else {
- fingers = NULL;
- }
- }
-
- p = dbus_g_proxy_new_from_proxy(dev, "org.freedesktop.DBus.Properties", NULL);
- if (!dbus_g_proxy_call (p, "GetAll", &error, G_TYPE_STRING, "net.reactivated.Fprint.Device", G_TYPE_INVALID,
- dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &props, G_TYPE_INVALID)) {
- g_print("GetAll on the Properties interface 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, g_value_get_string (g_hash_table_lookup (props, "name")));
- return;
- }
-
- g_print("Fingerprints for user %s on %s (%s):\n",
- username,
- g_value_get_string (g_hash_table_lookup (props, "name")),
- g_value_get_string (g_hash_table_lookup (props, "scan-type")));
- g_hash_table_destroy (props);
- g_object_unref (p);
-
- for (i = 0; fingers[i] != NULL; i++) {
- g_print(" - #%d: %s\n", i, fingers[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 (!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;
+ }
+
+ 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_strfreev (fingers);
+ 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)
{
- GError *error = NULL;
- GPtrArray *devices;
- char *path;
- guint i;
-
- if (!net_reactivated_Fprint_Manager_get_devices(manager, &devices, &error)) {
- g_print("list_devices failed: %s\n", error->message);
- exit (1);
- }
-
- if (devices->len == 0) {
- g_print("No devices found\n");
- exit(1);
- }
-
- g_print("found %d devices\n", devices->len);
- for (i = 0; i < devices->len; i++) {
- path = g_ptr_array_index(devices, i);
- g_print("Device at %s\n", path);
- }
-
- for (i = 0; i < devices->len; i++) {
- guint j;
- DBusGProxy *dev;
-
- path = g_ptr_array_index(devices, i);
- g_print("Using device %s\n", path);
-
- /* FIXME use for_name_owner?? */
- dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint",
- path, "net.reactivated.Fprint.Device");
-
- for (j = 1; argv[j] != NULL; j++)
- list_fingerprints (dev, argv[j]);
-
- g_object_unref (dev);
- }
-
- g_ptr_array_foreach(devices, (GFunc) g_free, NULL);
- g_ptr_array_free(devices, TRUE);
+ 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);
+ }
+
+ 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);
+ }
+
+ for (i = 0; devices[i] != NULL; i++)
+ {
+ g_autoptr(FprintDBusDevice) dev = NULL;
+ guint j;
+
+ 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);
+
+ 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 [usernames...]\n", argv[0]);
- return 1;
- }
+ if (argc < 2)
+ {
+ g_print ("Usage: %s [usernames...]\n", argv[0]);
+ return 1;
+ }
- process_devices (argv);
+ process_devices (argv);
- return 0;
+ return 0;
}
-
diff -Nru fprintd-1.90.1/utils/meson.build fprintd-1.90.9/utils/meson.build
--- fprintd-1.90.1/utils/meson.build 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/utils/meson.build 2021-01-13 12:23:24.000000000 +0000
@@ -1,52 +1,19 @@
-dbus_client_glue_sources = []
-
-foreach interface_name: dbus_interfaces
- interface = interface_name.to_lower()
- interface_file = meson.source_root() / 'src' / interface + '.xml'
- glue_name = interface + '-dbus-glue.h'
- dbus_client_glue_sources += custom_target(glue_name,
- input: interface_file,
- output: glue_name,
- command: [
- dbus_binding_tool,
- '--prefix=fprint_' + interface,
- '--mode=glib-client',
- '--output=@OUTPUT@',
- '@INPUT@',
- ])
-endforeach
-
-utils_marshal = custom_target('utils_marshal',
- depends: fprintd_marshal,
- input: fprintd_marshal,
- output: ['marshal.c', 'marshal.h'],
- command: [bash, '-c',
- 'cp @INPUT0@ @OUTPUT0@;' +
- 'cp @INPUT1@ @OUTPUT1@;' +
- 'sed s/fprintd-//g -i ' + meson.current_build_dir() / 'marshal*.{h,c}']
-)
-
libfprintd_utils_dep = declare_dependency(
include_directories: [
+ include_directories('../src'),
include_directories('../pam'),
],
dependencies: [
glib_dep,
- dbus_glib_dep,
+ gio_dep,
+ gio_unix_dep,
],
sources: [
- utils_marshal,
- dbus_client_glue_sources,
+ fprintd_dbus_sources,
+ ],
+ link_with: [
+ libfprintd_private
],
- link_with: static_library('fprintd_utils',
- sources: [
- dbus_client_glue_sources,
- utils_marshal,
- ],
- dependencies: [
- glib_dep,
- ]
- ),
)
utils = [
diff -Nru fprintd-1.90.1/utils/verify.c fprintd-1.90.9/utils/verify.c
--- fprintd-1.90.1/utils/verify.c 2020-02-10 14:08:32.000000000 +0000
+++ fprintd-1.90.9/utils/verify.c 2021-01-13 12:23:24.000000000 +0000
@@ -1,17 +1,18 @@
/*
* fprintd example to verify a fingerprint
* Copyright (C) 2008 Daniel Drake
+ * Copyright (C) 2020 Marco Trevisan
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
@@ -21,192 +22,285 @@
#include
#include
#include
-#include
-#include "manager-dbus-glue.h"
-#include "device-dbus-glue.h"
-#include "marshal.h"
+#include
+#include "fprintd-dbus.h"
-static DBusGProxy *manager = NULL;
-static DBusGConnection *connection = NULL;
+static FprintDBusManager *manager = NULL;
+static GDBusConnection *connection = NULL;
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)
{
- GError *error = NULL;
-
- connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
- if (connection == NULL) {
- g_print("Failed to connect to session bus: %s\n", error->message);
- exit (1);
- }
+ g_autoptr(GError) error = NULL;
- manager = dbus_g_proxy_new_for_name(connection,
- "net.reactivated.Fprint", "/net/reactivated/Fprint/Manager",
- "net.reactivated.Fprint.Manager");
+ 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);
+ }
}
-static DBusGProxy *open_device(const char *username)
+static FprintDBusDevice *
+open_device (const char *username)
{
- GError *error = NULL;
- gchar *path;
- DBusGProxy *dev;
-
- if (!net_reactivated_Fprint_Manager_get_default_device(manager, &path, &error)) {
- g_print("list_devices failed: %s\n", error->message);
- exit (1);
- }
-
- if (path == NULL) {
- g_print("No devices found\n");
- exit(1);
- }
-
- g_print("Using device %s\n", path);
+ 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);
+ }
+
+ 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);
+
+ 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);
+ }
- /* FIXME use for_name_owner?? */
- dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint",
- path, "net.reactivated.Fprint.Device");
-
- g_free (path);
-
- if (!net_reactivated_Fprint_Device_claim(dev, username, &error)) {
- g_print("failed to claim device: %s\n", error->message);
- exit (1);
- }
-
- return dev;
+ return g_steal_pointer (&dev);
}
-static void find_finger(DBusGProxy *dev, const char *username)
+static void
+find_finger (FprintDBusDevice *dev, const char *username)
{
- GError *error = NULL;
- char **fingers;
- 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 (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]);
+
+ 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 (!net_reactivated_Fprint_Device_list_enrolled_fingers(dev, username, &fingers, &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 (finger_name == NULL)
+ finger_name = g_strdup (fingers[0]);
+}
- g_print("Listing enrolled fingers:\n");
- for (i = 0; fingers[i] != NULL; i++) {
- g_print(" - #%d: %s\n", i, fingers[i]);
- }
+struct VerifyState
+{
+ GError *error;
+ gboolean started;
+ gboolean completed;
+};
- if (finger_name == NULL || strcmp (finger_name, "any") == 0) {
- g_free (finger_name);
- finger_name = g_strdup (fingers[0]);
- }
+static void
+verify_result (GObject *object, const char *result, gboolean done, void *user_data)
+{
+ struct VerifyState *verify_state = user_data;
- g_strfreev (fingers);
+ g_print ("Verify result: %s (%s)\n", result, done ? "done" : "not done");
+ if (done != FALSE)
+ verify_state->completed = TRUE;
}
-static void verify_result(GObject *object, const char *result, gboolean done, void *user_data)
+static void
+verify_finger_selected (GObject *object, const char *name, void *user_data)
{
- gboolean *verify_completed = user_data;
- g_print("Verify result: %s (%s)\n", result, done ? "done" : "not done");
- if (done != FALSE)
- *verify_completed = TRUE;
+ g_print ("Verifying: %s\n", name);
}
-static void verify_finger_selected(GObject *object, const char *name, void *user_data)
+static void
+verify_started_cb (GObject *obj,
+ GAsyncResult *res,
+ gpointer user_data)
{
- g_print("Verifying: %s\n", name);
+ struct VerifyState *verify_state = user_data;
+
+ 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 do_verify(DBusGProxy *dev)
+static void
+proxy_signal_cb (GDBusProxy *proxy,
+ const gchar *sender_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
- GError *error = NULL;
- gboolean verify_completed = FALSE;
+ struct VerifyState *verify_state = user_data;
- dbus_g_proxy_add_signal(dev, "VerifyStatus", G_TYPE_STRING, G_TYPE_BOOLEAN, NULL);
- dbus_g_proxy_add_signal(dev, "VerifyFingerSelected", G_TYPE_INT, NULL);
- dbus_g_proxy_connect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result),
- &verify_completed, NULL);
- dbus_g_proxy_connect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected),
- NULL, NULL);
+ if (!verify_state->started)
+ return;
- if (!net_reactivated_Fprint_Device_verify_start(dev, finger_name, &error)) {
- g_print("VerifyStart failed: %s\n", error->message);
- exit (1);
- }
-
- while (!verify_completed)
- g_main_context_iteration(NULL, TRUE);
+ 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, "(&s)", &name);
+ verify_finger_selected (G_OBJECT (proxy), name, user_data);
+ }
+}
- dbus_g_proxy_disconnect_signal(dev, "VerifyStatus", G_CALLBACK(verify_result), &verify_completed);
- dbus_g_proxy_disconnect_signal(dev, "VerifyFingerSelected", G_CALLBACK(verify_finger_selected), NULL);
+static void
+do_verify (FprintDBusDevice *dev)
+{
+ g_autoptr(GError) error = NULL;
+ struct VerifyState verify_state = { 0 };
- if (!net_reactivated_Fprint_Device_verify_stop(dev, &error)) {
- g_print("VerifyStop failed: %s\n", error->message);
- exit (1);
- }
+ /* 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);
+
+ 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);
+
+ 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);
+
+
+ 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);
+ }
}
-static void release_device(DBusGProxy *dev)
+static void
+release_device (FprintDBusDevice *dev)
{
- GError *error = NULL;
- if (!net_reactivated_Fprint_Device_release(dev, &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)
{
- GOptionContext *context;
- GError *err = NULL;
- DBusGProxy *dev;
- const char *username = NULL;
-
- setlocale (LC_ALL, "");
-
- dbus_g_object_register_marshaller (fprintd_marshal_VOID__STRING_BOOLEAN,
- G_TYPE_NONE, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INVALID);
-
- 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);
- g_error_free (err);
- return 1;
- }
-
- if (usernames == NULL) {
- username = "";
- } else {
- username = usernames[0];
- }
-
- 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);
- }
-
- create_manager();
-
- dev = open_device(username);
- find_finger(dev, username);
- do_verify(dev);
- release_device(dev);
- return 0;
+ g_autoptr(FprintDBusDevice) dev = NULL;
+ g_autoptr(GError) err = NULL;
+ GOptionContext *context;
+ const char *username = NULL;
+
+ setlocale (LC_ALL, "");
+
+ 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 (usernames == NULL)
+ username = "";
+ else
+ username = usernames[0];
+
+ 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);
+ }
+
+ create_manager ();
+
+ dev = open_device (username);
+ find_finger (dev, username);
+ do_verify (dev);
+ release_device (dev);
+ return 0;
}
-