clean unneeded files
132
.gitlab-ci.yml
@ -1,132 +0,0 @@
|
|||||||
include:
|
|
||||||
- project: 'libfprint/libfprint'
|
|
||||||
ref: master
|
|
||||||
file: '/.gitlab-ci/libfprint-templates.yaml'
|
|
||||||
- project: 'freedesktop/ci-templates'
|
|
||||||
ref: master
|
|
||||||
file: '/templates/fedora.yml'
|
|
||||||
|
|
||||||
variables:
|
|
||||||
extends: .libfprint_common_variables
|
|
||||||
FDO_DISTRIBUTION_TAG: latest
|
|
||||||
FDO_DISTRIBUTION_VERSION: rawhide
|
|
||||||
FDO_UPSTREAM_REPO: "libfprint/$CI_PROJECT_NAME"
|
|
||||||
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
|
|
||||||
patch
|
|
||||||
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,virtual_device,virtual_device_storage -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
|
|
||||||
allow_failure: true
|
|
||||||
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 --print-errorlogs --no-stdsplit --timeout-multiplier 3
|
|
||||||
- ninja -C _build coverage
|
|
||||||
- cat _build/meson-logs/coverage.txt
|
|
||||||
artifacts:
|
|
||||||
expose_as: 'Coverage Report'
|
|
||||||
paths:
|
|
||||||
- _build/meson-logs
|
|
||||||
- _build/meson-logs/coveragereport/index.html
|
|
||||||
expire_in: 1 week
|
|
||||||
|
|
||||||
test_dev_with_sanitizer:
|
|
||||||
extends:
|
|
||||||
- .fprintd_build_preconditions
|
|
||||||
- .install_libfprint_dev
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- meson _build -Db_sanitize=address
|
|
||||||
- meson test -C _build --print-errorlogs --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
|
|
||||||
FDO_FORCE_REBUILD: 1
|
|
||||||
# a list of packages to install
|
|
||||||
FDO_DISTRIBUTION_PACKAGES:
|
|
||||||
$DEPENDENCIES
|
|
||||||
$LIBFPRINT_DEPENDENCIES
|
|
||||||
195
NEWS
@ -1,195 +0,0 @@
|
|||||||
This file lists notable changes in each release. For the full history of all
|
|
||||||
changes, see ChangeLog.
|
|
||||||
|
|
||||||
Version 1.94.1:
|
|
||||||
|
|
||||||
API users, please adjust now to planned API changes in 2.0:
|
|
||||||
- EnrollStart will throw an error if the finger was enrolled already
|
|
||||||
- Interactive DBus authentication will only happen when requested
|
|
||||||
|
|
||||||
Highlights.
|
|
||||||
- Fix systemd unit so that udev hotplug events are processed
|
|
||||||
- Report back the selected finger if there is only one
|
|
||||||
- Change PolicyKit strings for clarity
|
|
||||||
- Various fixes to the testsuite
|
|
||||||
- Plenty of translation updates
|
|
||||||
|
|
||||||
Version 1.94.0:
|
|
||||||
|
|
||||||
API users, please adjust now to planned API changes in 2.0:
|
|
||||||
- EnrollStart will throw an error if the finger was enrolled already
|
|
||||||
- Interactive DBus authentication will only happen when requested
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
- Implement suspend/resume handling.
|
|
||||||
This requires writing "power/persist" and "power/wakeup" in sysfs.
|
|
||||||
- Support libfprint overheat protections
|
|
||||||
- Delete host prints when device prints disappeared
|
|
||||||
- pam: Immediately return success information
|
|
||||||
- Plenty of updated translations thanks to move to Fedora Weblate
|
|
||||||
- Fix possible race when retrieving session information
|
|
||||||
- Fix possible race when a client disconnects
|
|
||||||
- GLib 2.56 compatibility fixes
|
|
||||||
|
|
||||||
|
|
||||||
Version 1.92.0:
|
|
||||||
|
|
||||||
API users, please adjust now to planned API changes in 2.0:
|
|
||||||
- EnrollStart will throw an error if the finger was enrolled already
|
|
||||||
- Interactive DBus authentication will only happen when requested
|
|
||||||
|
|
||||||
Highlights:
|
|
||||||
- fprintd now prevents the same finger to be enrolled twice
|
|
||||||
- Support clearing storage of match-on-chip devices
|
|
||||||
- pam: Cancel authentication on SIGINT (e.g. ctrl+c with sudo)
|
|
||||||
- pam: Always return PAM_AUTHINFO_UNAVAIL for devices without prints
|
|
||||||
- Expose finger status on DBus
|
|
||||||
- Add method to delete only a specific print of a user
|
|
||||||
- Improved error reporting for deletion
|
|
||||||
- Wait for finger removal before cancelling operations
|
|
||||||
- Prefer older prints when garbage collecting
|
|
||||||
- Major improvements to test coverage
|
|
||||||
|
|
||||||
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
|
|
||||||
tests for the utilities
|
|
||||||
- Port build system to meson
|
|
||||||
- Loads of build warnings and memory leak fixes
|
|
||||||
|
|
||||||
- PAM module:
|
|
||||||
- Port PAM module to sd-bus from dbus-glib
|
|
||||||
- Use systemd to not ask for a fingerprint scan on remote logins
|
|
||||||
- Add man page for PAM module
|
|
||||||
- Add tests
|
|
||||||
|
|
||||||
This version requires libfprint 1.90.1, a 2.0 pre-release.
|
|
||||||
|
|
||||||
version 0.9.0:
|
|
||||||
- Fix hangs when there the verification error was "retry"
|
|
||||||
- Update for fp_get_pollfds() changes
|
|
||||||
- Fix "client_username" memory leak, fix memory leak when saving a file
|
|
||||||
- Create the fingerprint storage directory at install time,
|
|
||||||
the storage path is now hard-coded as /var/lib/fprint and created by
|
|
||||||
systemd when the service is started
|
|
||||||
|
|
||||||
version 0.8.1:
|
|
||||||
- Fix build when builddir != srcdir
|
|
||||||
- Fix possible crash on exit
|
|
||||||
- Avoid warnings in copy/paste header
|
|
||||||
- Sandbox fprintd daemon more
|
|
||||||
- Update website address
|
|
||||||
- Minimise debug output
|
|
||||||
- Updated translations
|
|
||||||
|
|
||||||
version 0.8.0:
|
|
||||||
- Lockdown the daemon to minimise potential security issues
|
|
||||||
- Don't wake up readers when there's no enrolled fingerprints
|
|
||||||
|
|
||||||
version 0.7.0:
|
|
||||||
- Fix crash in the daemon when cancelling PAM conversation
|
|
||||||
- Fix build warnings and update translations
|
|
||||||
|
|
||||||
version 0.6.0:
|
|
||||||
- Fix warning in fprintd.pod file
|
|
||||||
- Reduce logging during normal operation
|
|
||||||
- Fix eventfd leak in PAM module
|
|
||||||
- List possible values for finger when enrolling
|
|
||||||
- Fix possible crash in fprintd-verify
|
|
||||||
- Fix listing and deleting fingerprints when there's more than
|
|
||||||
one reader available
|
|
||||||
|
|
||||||
version 0.5.1:
|
|
||||||
- Add max-tries and timeout arguments to PAM module
|
|
||||||
- Add ability to require the fingerprint for enrolled users
|
|
||||||
- Add "-f <finger>" option to enroll utilities
|
|
||||||
|
|
||||||
version 0.5.0:
|
|
||||||
- Don't use a device name if there's only one reader
|
|
||||||
- Avoid possible crash when trying to login without devices
|
|
||||||
- Fix possible crashes due to uninitialised variables
|
|
||||||
- Fix hang when the machine has no USB bus
|
|
||||||
- Add a systemd unit file
|
|
||||||
|
|
||||||
version 0.4.1:
|
|
||||||
- Enable gtk-doc by default so that file aren't
|
|
||||||
missing in the tarball
|
|
||||||
|
|
||||||
version 0.4.0:
|
|
||||||
- Loads of new translations
|
|
||||||
- Fix crasher when PAM module gets unloaded
|
|
||||||
- Use GIO to monitor D-Bus clients instead of custom code
|
|
||||||
|
|
||||||
version 0.2.0:
|
|
||||||
- First actual release
|
|
||||||
6
TODO
@ -1,6 +0,0 @@
|
|||||||
Verify PAM messages fit with GDM/gnome-screensaver
|
|
||||||
|
|
||||||
Automatically show the fingerprint registration when logged in and
|
|
||||||
not having any registered prints?
|
|
||||||
http://uk.youtube.com/watch?v=F_x_vwCltbc
|
|
||||||
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
This project and its community follow the [Freedesktop.org code of conduct]
|
|
||||||
|
|
||||||
[Freedesktop.org code of conduct]: https://www.freedesktop.org/wiki/CodeOfConduct/
|
|
||||||
213
data/fprintd.1
@ -1,213 +0,0 @@
|
|||||||
.\" Automatically generated by Pod::Man 4.12 (Pod::Simple 3.39)
|
|
||||||
.\"
|
|
||||||
.\" Standard preamble:
|
|
||||||
.\" ========================================================================
|
|
||||||
.de Sp \" Vertical space (when we can't use .PP)
|
|
||||||
.if t .sp .5v
|
|
||||||
.if n .sp
|
|
||||||
..
|
|
||||||
.de Vb \" Begin verbatim text
|
|
||||||
.ft CW
|
|
||||||
.nf
|
|
||||||
.ne \\$1
|
|
||||||
..
|
|
||||||
.de Ve \" End verbatim text
|
|
||||||
.ft R
|
|
||||||
.fi
|
|
||||||
..
|
|
||||||
.\" Set up some character translations and predefined strings. \*(-- will
|
|
||||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
|
||||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
|
||||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
|
||||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
|
||||||
.\" nothing in troff, for use with C<>.
|
|
||||||
.tr \(*W-
|
|
||||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
|
||||||
.ie n \{\
|
|
||||||
. ds -- \(*W-
|
|
||||||
. ds PI pi
|
|
||||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
|
||||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
|
||||||
. ds L" ""
|
|
||||||
. ds R" ""
|
|
||||||
. ds C`
|
|
||||||
. ds C'
|
|
||||||
'br\}
|
|
||||||
.el\{\
|
|
||||||
. ds -- \|\(em\|
|
|
||||||
. ds PI \(*p
|
|
||||||
. ds L" ``
|
|
||||||
. ds R" ''
|
|
||||||
. ds C`
|
|
||||||
. ds C'
|
|
||||||
'br\}
|
|
||||||
.\"
|
|
||||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
|
||||||
.ie \n(.g .ds Aq \(aq
|
|
||||||
.el .ds Aq '
|
|
||||||
.\"
|
|
||||||
.\" If the F register is >0, we'll generate index entries on stderr for
|
|
||||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
|
||||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
|
||||||
.\" output yourself in some meaningful fashion.
|
|
||||||
.\"
|
|
||||||
.\" Avoid warning from groff about undefined register 'F'.
|
|
||||||
.de IX
|
|
||||||
..
|
|
||||||
.nr rF 0
|
|
||||||
.if \n(.g .if rF .nr rF 1
|
|
||||||
.if (\n(rF:(\n(.g==0)) \{\
|
|
||||||
. if \nF \{\
|
|
||||||
. de IX
|
|
||||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
|
||||||
..
|
|
||||||
. if !\nF==2 \{\
|
|
||||||
. nr % 0
|
|
||||||
. nr F 2
|
|
||||||
. \}
|
|
||||||
. \}
|
|
||||||
.\}
|
|
||||||
.rr rF
|
|
||||||
.\"
|
|
||||||
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
|
|
||||||
.\" Fear. Run. Save yourself. No user-serviceable parts.
|
|
||||||
. \" fudge factors for nroff and troff
|
|
||||||
.if n \{\
|
|
||||||
. ds #H 0
|
|
||||||
. ds #V .8m
|
|
||||||
. ds #F .3m
|
|
||||||
. ds #[ \f1
|
|
||||||
. ds #] \fP
|
|
||||||
.\}
|
|
||||||
.if t \{\
|
|
||||||
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
|
|
||||||
. ds #V .6m
|
|
||||||
. ds #F 0
|
|
||||||
. ds #[ \&
|
|
||||||
. ds #] \&
|
|
||||||
.\}
|
|
||||||
. \" simple accents for nroff and troff
|
|
||||||
.if n \{\
|
|
||||||
. ds ' \&
|
|
||||||
. ds ` \&
|
|
||||||
. ds ^ \&
|
|
||||||
. ds , \&
|
|
||||||
. ds ~ ~
|
|
||||||
. ds /
|
|
||||||
.\}
|
|
||||||
.if t \{\
|
|
||||||
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
|
|
||||||
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
|
|
||||||
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
|
|
||||||
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
|
|
||||||
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
|
|
||||||
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
|
|
||||||
.\}
|
|
||||||
. \" troff and (daisy-wheel) nroff accents
|
|
||||||
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
|
|
||||||
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
|
|
||||||
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
|
|
||||||
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
|
|
||||||
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
|
|
||||||
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
|
|
||||||
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
|
|
||||||
.ds ae a\h'-(\w'a'u*4/10)'e
|
|
||||||
.ds Ae A\h'-(\w'A'u*4/10)'E
|
|
||||||
. \" corrections for vroff
|
|
||||||
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
|
|
||||||
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
|
|
||||||
. \" for low resolution devices (crt and lpr)
|
|
||||||
.if \n(.H>23 .if \n(.V>19 \
|
|
||||||
\{\
|
|
||||||
. ds : e
|
|
||||||
. ds 8 ss
|
|
||||||
. ds o a
|
|
||||||
. ds d- d\h'-1'\(ga
|
|
||||||
. ds D- D\h'-1'\(hy
|
|
||||||
. ds th \o'bp'
|
|
||||||
. ds Th \o'LP'
|
|
||||||
. ds ae ae
|
|
||||||
. ds Ae AE
|
|
||||||
.\}
|
|
||||||
.rm #[ #] #H #V #F C
|
|
||||||
.\" ========================================================================
|
|
||||||
.\"
|
|
||||||
.IX Title "fprintd 1"
|
|
||||||
.TH fprintd 1 "2020-01-24" "freedesktop" ""
|
|
||||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
|
||||||
.\" way too many mistakes in technical documents.
|
|
||||||
.if n .ad l
|
|
||||||
.nh
|
|
||||||
.SH "NAME"
|
|
||||||
fprintd \- Fingerprint management daemon, and test applications
|
|
||||||
.SH "SYNOPSIS"
|
|
||||||
.IX Header "SYNOPSIS"
|
|
||||||
\&\fBfprintd-enroll\fR [\-f finger] [usename]
|
|
||||||
.PP
|
|
||||||
\&\fBfprintd-list\fR username [usernames...]
|
|
||||||
.PP
|
|
||||||
\&\fBfprintd-verify\fR [\-f finger] [usename]
|
|
||||||
.PP
|
|
||||||
\&\fBfprintd-delete\fR username [usernames...]
|
|
||||||
.SH "DESCRIPTION"
|
|
||||||
.IX Header "DESCRIPTION"
|
|
||||||
This manual page documents briefly the \fBfprintd\fR command-line utilities.
|
|
||||||
.PP
|
|
||||||
The \fBfprintd\fR daemon is accessed through \fBD\-Bus\fR by those command-line utilities.
|
|
||||||
.SH "ARGUMENTS"
|
|
||||||
.IX Header "ARGUMENTS"
|
|
||||||
.IP "\fBusername\fR" 8
|
|
||||||
.IX Item "username"
|
|
||||||
The username for the user for which you want to query or modify the fingerprint database.
|
|
||||||
.Sp
|
|
||||||
Not that \fBfprintd-list\fR and \fBfprintd-delete\fR require at least one username to be passed, and support multiple usernames.
|
|
||||||
.Sp
|
|
||||||
\&\fBfprintd-enroll\fR and \fBfprintd-verify\fR will use the current username if none are passed on the command-line.
|
|
||||||
.IP "\fB\-f finger\fR" 8
|
|
||||||
.IX Item "-f finger"
|
|
||||||
For \fBfprintd-enroll\fR, the finger to enroll. Possible values are:
|
|
||||||
.Sp
|
|
||||||
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.
|
|
||||||
.Sp
|
|
||||||
The default is automatic, selecting the first available finger for swipe devices, or all the enrolled fingers, for press devices.
|
|
||||||
.SH "TEST APPLICATIONS"
|
|
||||||
.IX Header "TEST APPLICATIONS"
|
|
||||||
.SS "fprintd-enroll"
|
|
||||||
.IX Subsection "fprintd-enroll"
|
|
||||||
.RS 8
|
|
||||||
Will enroll the user's right index finger into the database.
|
|
||||||
.RE
|
|
||||||
.SS "fprintd-list"
|
|
||||||
.IX Subsection "fprintd-list"
|
|
||||||
.RS 8
|
|
||||||
Will list the user's enrolled fingerprints.
|
|
||||||
.RE
|
|
||||||
.SS "fprintd-verify"
|
|
||||||
.IX Subsection "fprintd-verify"
|
|
||||||
.RS 8
|
|
||||||
Will verify the user's fingerprints against the database.
|
|
||||||
.RE
|
|
||||||
.SS "fprintd-delete"
|
|
||||||
.IX Subsection "fprintd-enroll"
|
|
||||||
.RS 8
|
|
||||||
Will delete the user's right index finger into the database.
|
|
||||||
.RE
|
|
||||||
.SH "AUTHOR"
|
|
||||||
.IX Header "AUTHOR"
|
|
||||||
\&\fBfprintd\fR was written by Bastien Nocera and Daniel Drake.
|
|
||||||
.SH "DIRECTORIES"
|
|
||||||
.IX Header "DIRECTORIES"
|
|
||||||
By default, fprintd stores the fingerprints in \fB/var/lib/fprint/\fR
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.IX Header "SEE ALSO"
|
|
||||||
.IP "\fBgnome-control-center\fR" 8
|
|
||||||
.IX Item "gnome-control-center"
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
[storage]
|
|
||||||
type=file
|
|
||||||
104
data/fprintd.pod
@ -1,104 +0,0 @@
|
|||||||
=head1 NAME
|
|
||||||
|
|
||||||
fprintd - Fingerprint management daemon, and test applications
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
B<fprintd-enroll> [-f finger] [usename]
|
|
||||||
|
|
||||||
B<fprintd-list> username [usernames...]
|
|
||||||
|
|
||||||
B<fprintd-verify> [-f finger] [usename]
|
|
||||||
|
|
||||||
B<fprintd-delete> username [usernames...]
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
This manual page documents briefly the B<fprintd> command-line utilities.
|
|
||||||
|
|
||||||
The B<fprintd> daemon is accessed through B<D-Bus> by those command-line utilities.
|
|
||||||
|
|
||||||
=head1 ARGUMENTS
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=item B<username>
|
|
||||||
|
|
||||||
The username for the user for which you want to query or modify the fingerprint database.
|
|
||||||
|
|
||||||
Not that B<fprintd-list> and B<fprintd-delete> require at least one username to be passed, and support multiple usernames.
|
|
||||||
|
|
||||||
B<fprintd-enroll> and B<fprintd-verify> will use the current username if none are passed on the command-line.
|
|
||||||
|
|
||||||
=item B<-f finger>
|
|
||||||
|
|
||||||
For B<fprintd-enroll>, the finger to enroll. Possible values are:
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
The default is automatic, selecting the first available finger for swipe devices, or all the enrolled fingers, for press devices.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 TEST APPLICATIONS
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 fprintd-enroll
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
Will enroll the user's right index finger into the database.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 fprintd-list
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
Will list the user's enrolled fingerprints.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 fprintd-verify
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
Will verify the user's fingerprints against the database.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head2 fprintd-delete
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
Will delete the user's right index finger into the database.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
B<fprintd> was written by Bastien Nocera and Daniel Drake.
|
|
||||||
|
|
||||||
=head1 DIRECTORIES
|
|
||||||
|
|
||||||
By default, fprintd stores the fingerprints in B</var/lib/fprint/>
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=item B<gnome-control-center>
|
|
||||||
|
|
||||||
=back
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Fingerprint Authentication Daemon
|
|
||||||
Documentation=man:fprintd(1)
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=dbus
|
|
||||||
BusName=net.reactivated.Fprint
|
|
||||||
ExecStart=@libexecdir@/fprintd
|
|
||||||
|
|
||||||
# Filesystem lockdown
|
|
||||||
ProtectSystem=strict
|
|
||||||
ProtectKernelTunables=true
|
|
||||||
ProtectKernelLogs=true
|
|
||||||
ProtectControlGroups=true
|
|
||||||
# This always corresponds to /var/lib/fprint
|
|
||||||
StateDirectory=fprint
|
|
||||||
StateDirectoryMode=0700
|
|
||||||
ProtectHome=true
|
|
||||||
PrivateTmp=true
|
|
||||||
|
|
||||||
SystemCallFilter=@system-service
|
|
||||||
|
|
||||||
# Network
|
|
||||||
RestrictAddressFamilies=AF_UNIX AF_LOCAL AF_NETLINK
|
|
||||||
|
|
||||||
# Execute Mappings
|
|
||||||
MemoryDenyWriteExecute=true
|
|
||||||
|
|
||||||
# Modules
|
|
||||||
ProtectKernelModules=true
|
|
||||||
|
|
||||||
# Real-time
|
|
||||||
RestrictRealtime=true
|
|
||||||
|
|
||||||
# Privilege escalation
|
|
||||||
NoNewPrivileges=true
|
|
||||||
|
|
||||||
# Protect clock, allow USB and SPI device access
|
|
||||||
ProtectClock=yes
|
|
||||||
DeviceAllow=char-usb_device rw
|
|
||||||
DeviceAllow=char-spi rw
|
|
||||||
DeviceAllow=char-hidraw rw
|
|
||||||
|
|
||||||
# Allow tuning USB parameters (wakeup and persist)
|
|
||||||
ReadWritePaths=/sys/devices
|
|
||||||
@ -1,72 +0,0 @@
|
|||||||
install_data('net.reactivated.Fprint.conf',
|
|
||||||
install_dir: dbus_conf_dir)
|
|
||||||
|
|
||||||
configure_file(
|
|
||||||
configuration: configuration_data({
|
|
||||||
'LIBEXECDIR': fprintd_installdir,
|
|
||||||
}),
|
|
||||||
input: 'net.reactivated.Fprint.service.in',
|
|
||||||
output: 'net.reactivated.Fprint.service',
|
|
||||||
install: true,
|
|
||||||
install_dir: dbus_service_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(
|
|
||||||
input: '@0@.in'.format(polkit_policy),
|
|
||||||
output: polkit_policy,
|
|
||||||
po_dir: meson.source_root() / 'po',
|
|
||||||
install: true,
|
|
||||||
install_dir: polkit_policy_directory,
|
|
||||||
)
|
|
||||||
|
|
||||||
if xmllint.found()
|
|
||||||
test(polkit_policy,
|
|
||||||
xmllint,
|
|
||||||
depends: polkit_policy_target,
|
|
||||||
args: [
|
|
||||||
'--noout',
|
|
||||||
polkit_policy_target.full_path(),
|
|
||||||
])
|
|
||||||
endif
|
|
||||||
|
|
||||||
install_data('fprintd.conf',
|
|
||||||
install_dir: sysconfdir)
|
|
||||||
|
|
||||||
if get_option('man')
|
|
||||||
manfiles = {
|
|
||||||
'fprintd': 1,
|
|
||||||
'pam_fprintd': 8,
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach man_name, man_section: manfiles
|
|
||||||
custom_target('man_' + man_name + '.' + man_section.to_string(),
|
|
||||||
input: man_name + '.pod',
|
|
||||||
output: man_name + '.' + man_section.to_string(),
|
|
||||||
command: [
|
|
||||||
pod2man,
|
|
||||||
'-c', '',
|
|
||||||
'-s', man_section.to_string(),
|
|
||||||
'-q', 'none',
|
|
||||||
'-n', man_name,
|
|
||||||
'-r', 'freedesktop',
|
|
||||||
'@INPUT@',
|
|
||||||
'@OUTPUT@',
|
|
||||||
],
|
|
||||||
install: true,
|
|
||||||
install_dir: datadir / 'man' / 'man' + man_section.to_string(),
|
|
||||||
)
|
|
||||||
endforeach
|
|
||||||
endif
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
|
||||||
|
|
||||||
<!DOCTYPE busconfig PUBLIC
|
|
||||||
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
|
||||||
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
|
||||||
<busconfig>
|
|
||||||
|
|
||||||
<!-- Only root can own the service -->
|
|
||||||
<policy user="root">
|
|
||||||
<allow own="net.reactivated.Fprint"/>
|
|
||||||
</policy>
|
|
||||||
|
|
||||||
<!-- Anyone can talk to the service -->
|
|
||||||
<policy context="default">
|
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
|
||||||
send_interface="net.reactivated.Fprint.Manager"/>
|
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
|
||||||
send_interface="net.reactivated.Fprint.Device"/>
|
|
||||||
|
|
||||||
<!-- Basic D-Bus API stuff -->
|
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
|
||||||
send_interface="org.freedesktop.DBus.Introspectable"/>
|
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
|
||||||
send_interface="org.freedesktop.DBus.Properties"/>
|
|
||||||
<allow send_destination="net.reactivated.Fprint"
|
|
||||||
send_interface="org.freedesktop.DBus.ObjectManager"/>
|
|
||||||
</policy>
|
|
||||||
|
|
||||||
</busconfig>
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
[D-BUS Service]
|
|
||||||
Name=net.reactivated.Fprint
|
|
||||||
Exec=@LIBEXECDIR@/fprintd
|
|
||||||
User=root
|
|
||||||
SystemdService=fprintd.service
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE policyconfig PUBLIC
|
|
||||||
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
|
|
||||||
"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
|
|
||||||
|
|
||||||
<policyconfig>
|
|
||||||
|
|
||||||
<vendor>The FPrint Project</vendor>
|
|
||||||
<vendor_url>https://fprint.freedesktop.org/</vendor_url>
|
|
||||||
<icon_name>fprint</icon_name>
|
|
||||||
|
|
||||||
<action id="net.reactivated.fprint.device.verify">
|
|
||||||
<description>Verify a fingerprint</description>
|
|
||||||
<message>Privileges are required to verify fingerprints.</message>
|
|
||||||
<defaults>
|
|
||||||
<allow_any>no</allow_any>
|
|
||||||
<allow_inactive>no</allow_inactive>
|
|
||||||
<allow_active>yes</allow_active>
|
|
||||||
</defaults>
|
|
||||||
</action>
|
|
||||||
|
|
||||||
<action id="net.reactivated.fprint.device.enroll">
|
|
||||||
<description>Enroll or Delete fingerprints</description>
|
|
||||||
<message>Privileges are required to enroll or delete fingerprints.</message>
|
|
||||||
<defaults>
|
|
||||||
<allow_any>no</allow_any>
|
|
||||||
<allow_inactive>no</allow_inactive>
|
|
||||||
<allow_active>auth_self_keep</allow_active>
|
|
||||||
</defaults>
|
|
||||||
</action>
|
|
||||||
|
|
||||||
<action id="net.reactivated.fprint.device.setusername">
|
|
||||||
<description>Select a user to manage fingerprints for</description>
|
|
||||||
<message>Privileges are required to manage fingerprints for other users.</message>
|
|
||||||
<defaults>
|
|
||||||
<allow_any>no</allow_any>
|
|
||||||
<allow_inactive>no</allow_inactive>
|
|
||||||
<allow_active>auth_admin_keep</allow_active>
|
|
||||||
</defaults>
|
|
||||||
</action>
|
|
||||||
|
|
||||||
</policyconfig>
|
|
||||||
@ -1,184 +0,0 @@
|
|||||||
.\" Automatically generated by Pod::Man 4.12 (Pod::Simple 3.39)
|
|
||||||
.\"
|
|
||||||
.\" Standard preamble:
|
|
||||||
.\" ========================================================================
|
|
||||||
.de Sp \" Vertical space (when we can't use .PP)
|
|
||||||
.if t .sp .5v
|
|
||||||
.if n .sp
|
|
||||||
..
|
|
||||||
.de Vb \" Begin verbatim text
|
|
||||||
.ft CW
|
|
||||||
.nf
|
|
||||||
.ne \\$1
|
|
||||||
..
|
|
||||||
.de Ve \" End verbatim text
|
|
||||||
.ft R
|
|
||||||
.fi
|
|
||||||
..
|
|
||||||
.\" Set up some character translations and predefined strings. \*(-- will
|
|
||||||
.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
|
||||||
.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
|
||||||
.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
|
||||||
.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
|
||||||
.\" nothing in troff, for use with C<>.
|
|
||||||
.tr \(*W-
|
|
||||||
.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
|
||||||
.ie n \{\
|
|
||||||
. ds -- \(*W-
|
|
||||||
. ds PI pi
|
|
||||||
. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
|
||||||
. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
|
||||||
. ds L" ""
|
|
||||||
. ds R" ""
|
|
||||||
. ds C`
|
|
||||||
. ds C'
|
|
||||||
'br\}
|
|
||||||
.el\{\
|
|
||||||
. ds -- \|\(em\|
|
|
||||||
. ds PI \(*p
|
|
||||||
. ds L" ``
|
|
||||||
. ds R" ''
|
|
||||||
. ds C`
|
|
||||||
. ds C'
|
|
||||||
'br\}
|
|
||||||
.\"
|
|
||||||
.\" Escape single quotes in literal strings from groff's Unicode transform.
|
|
||||||
.ie \n(.g .ds Aq \(aq
|
|
||||||
.el .ds Aq '
|
|
||||||
.\"
|
|
||||||
.\" If the F register is >0, we'll generate index entries on stderr for
|
|
||||||
.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
|
||||||
.\" entries marked with X<> in POD. Of course, you'll have to process the
|
|
||||||
.\" output yourself in some meaningful fashion.
|
|
||||||
.\"
|
|
||||||
.\" Avoid warning from groff about undefined register 'F'.
|
|
||||||
.de IX
|
|
||||||
..
|
|
||||||
.nr rF 0
|
|
||||||
.if \n(.g .if rF .nr rF 1
|
|
||||||
.if (\n(rF:(\n(.g==0)) \{\
|
|
||||||
. if \nF \{\
|
|
||||||
. de IX
|
|
||||||
. tm Index:\\$1\t\\n%\t"\\$2"
|
|
||||||
..
|
|
||||||
. if !\nF==2 \{\
|
|
||||||
. nr % 0
|
|
||||||
. nr F 2
|
|
||||||
. \}
|
|
||||||
. \}
|
|
||||||
.\}
|
|
||||||
.rr rF
|
|
||||||
.\"
|
|
||||||
.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
|
|
||||||
.\" Fear. Run. Save yourself. No user-serviceable parts.
|
|
||||||
. \" fudge factors for nroff and troff
|
|
||||||
.if n \{\
|
|
||||||
. ds #H 0
|
|
||||||
. ds #V .8m
|
|
||||||
. ds #F .3m
|
|
||||||
. ds #[ \f1
|
|
||||||
. ds #] \fP
|
|
||||||
.\}
|
|
||||||
.if t \{\
|
|
||||||
. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
|
|
||||||
. ds #V .6m
|
|
||||||
. ds #F 0
|
|
||||||
. ds #[ \&
|
|
||||||
. ds #] \&
|
|
||||||
.\}
|
|
||||||
. \" simple accents for nroff and troff
|
|
||||||
.if n \{\
|
|
||||||
. ds ' \&
|
|
||||||
. ds ` \&
|
|
||||||
. ds ^ \&
|
|
||||||
. ds , \&
|
|
||||||
. ds ~ ~
|
|
||||||
. ds /
|
|
||||||
.\}
|
|
||||||
.if t \{\
|
|
||||||
. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
|
|
||||||
. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
|
|
||||||
. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
|
|
||||||
. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
|
|
||||||
. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
|
|
||||||
. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
|
|
||||||
.\}
|
|
||||||
. \" troff and (daisy-wheel) nroff accents
|
|
||||||
.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
|
|
||||||
.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
|
|
||||||
.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
|
|
||||||
.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
|
|
||||||
.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
|
|
||||||
.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
|
|
||||||
.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
|
|
||||||
.ds ae a\h'-(\w'a'u*4/10)'e
|
|
||||||
.ds Ae A\h'-(\w'A'u*4/10)'E
|
|
||||||
. \" corrections for vroff
|
|
||||||
.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
|
|
||||||
.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
|
|
||||||
. \" for low resolution devices (crt and lpr)
|
|
||||||
.if \n(.H>23 .if \n(.V>19 \
|
|
||||||
\{\
|
|
||||||
. ds : e
|
|
||||||
. ds 8 ss
|
|
||||||
. ds o a
|
|
||||||
. ds d- d\h'-1'\(ga
|
|
||||||
. ds D- D\h'-1'\(hy
|
|
||||||
. ds th \o'bp'
|
|
||||||
. ds Th \o'LP'
|
|
||||||
. ds ae ae
|
|
||||||
. ds Ae AE
|
|
||||||
.\}
|
|
||||||
.rm #[ #] #H #V #F C
|
|
||||||
.\" ========================================================================
|
|
||||||
.\"
|
|
||||||
.IX Title "pam_fprintd 8"
|
|
||||||
.TH pam_fprintd 8 "2020-01-24" "freedesktop" ""
|
|
||||||
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
|
||||||
.\" way too many mistakes in technical documents.
|
|
||||||
.if n .ad l
|
|
||||||
.nh
|
|
||||||
.SH "NAME"
|
|
||||||
pam_fprintd \- PAM module to authenticate against fprintd, the fingerprint daemon
|
|
||||||
.SH "SYNOPSIS"
|
|
||||||
.IX Header "SYNOPSIS"
|
|
||||||
\&\fBpam_fprintd.so\fR [debug|debug=[\fIon\fR|\fIoff\fR|\fItrue\fR|\fIfalse\fR|\fI1\fR|\fI0\fR]] [max\-tries=\fI\s-1MAX_TRIES\s0\fR] [timeout=\fI\s-1TIMEOUT\s0\fR]
|
|
||||||
.SH "DESCRIPTION"
|
|
||||||
.IX Header "DESCRIPTION"
|
|
||||||
The pam_fprintd module is used to verify a user's fingerprints against fingerprints
|
|
||||||
enrolled using fprintd, the fingerprint management daemon.
|
|
||||||
.SH "OPTIONS"
|
|
||||||
.IX Header "OPTIONS"
|
|
||||||
.IP "\fBdebug\fR" 8
|
|
||||||
.IX Item "debug"
|
|
||||||
.PD 0
|
|
||||||
.IP "\fBdebug=[\f(BIon\fB|\f(BIoff\fB|\f(BItrue\fB|\f(BIfalse\fB|\f(BI1\fB|\f(BI0\fB]\fR" 8
|
|
||||||
.IX Item "debug=[on|off|true|false|1|0]"
|
|
||||||
.PD
|
|
||||||
Whether debug should be turned on or off. Debug messages will be generated using
|
|
||||||
pam_syslog which means that they will be saved in the systemd journal by default.
|
|
||||||
.IP "\fBmax\-tries=\f(BI\s-1MAX_TRIES\s0\fB\fR" 8
|
|
||||||
.IX Item "max-tries=MAX_TRIES"
|
|
||||||
The number of attempts at fingerprint authentication to try before returning an
|
|
||||||
authentication failure. The minimum, and default, number of tries is 3.
|
|
||||||
.IP "\fBtimeout=\f(BI\s-1TIMEOUT\s0\fB\fR" 8
|
|
||||||
.IX Item "timeout=TIMEOUT"
|
|
||||||
The amount of time before returning an authentication failure. The default timeout
|
|
||||||
is 30 seconds, with 10 seconds being the minimum.
|
|
||||||
.SH "LIMITATIONS"
|
|
||||||
.IX Header "LIMITATIONS"
|
|
||||||
The \s-1PAM\s0 stack is by design a serialised authentication, so it is not
|
|
||||||
possible for pam_fprintd to allow authentication through passwords and
|
|
||||||
fingerprints at the same time.
|
|
||||||
.PP
|
|
||||||
It is up to the application using the \s-1PAM\s0 services to implement separate
|
|
||||||
\&\s-1PAM\s0 processes and run separate authentication stacks separately. This
|
|
||||||
is the way multiple authentication methods are made available to users
|
|
||||||
of gdm for example.
|
|
||||||
.SH "AUTHOR"
|
|
||||||
.IX Header "AUTHOR"
|
|
||||||
\&\fBfprintd\fR was written by Bastien Nocera.
|
|
||||||
.SH "SEE ALSO"
|
|
||||||
.IX Header "SEE ALSO"
|
|
||||||
.IP "\fBfprintd\fR, \fB\s-1PAM\s0\fR" 8
|
|
||||||
.IX Item "fprintd, PAM"
|
|
||||||
@ -1,63 +0,0 @@
|
|||||||
=head1 NAME
|
|
||||||
|
|
||||||
pam_fprintd - PAM module to authenticate against fprintd, the fingerprint daemon
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
B<pam_fprintd.so> [debug|debug=[I<on>|I<off>|I<true>|I<false>|I<1>|I<0>]] [max-tries=I<MAX_TRIES>] [timeout=I<TIMEOUT>]
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
The pam_fprintd module is used to verify a user's fingerprints against fingerprints
|
|
||||||
enrolled using fprintd, the fingerprint management daemon.
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=item B<debug>
|
|
||||||
|
|
||||||
=item B<debug=[I<on>|I<off>|I<true>|I<false>|I<1>|I<0>]>
|
|
||||||
|
|
||||||
Whether debug should be turned on or off. Debug messages will be generated using
|
|
||||||
pam_syslog which means that they will be saved in the systemd journal by default.
|
|
||||||
|
|
||||||
=item B<max-tries=I<MAX_TRIES>>
|
|
||||||
|
|
||||||
The number of attempts at fingerprint authentication to try before returning an
|
|
||||||
authentication failure. The minimum number of tries is 1 while the default is 3.
|
|
||||||
|
|
||||||
=item B<timeout=I<TIMEOUT>>
|
|
||||||
|
|
||||||
The amount of time before returning an authentication failure. The default timeout
|
|
||||||
is 30 seconds, with 10 seconds being the minimum.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 LIMITATIONS
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
The PAM stack is by design a serialised authentication, so it is not
|
|
||||||
possible for pam_fprintd to allow authentication through passwords and
|
|
||||||
fingerprints at the same time.
|
|
||||||
|
|
||||||
It is up to the application using the PAM services to implement separate
|
|
||||||
PAM processes and run separate authentication stacks separately. This
|
|
||||||
is the way multiple authentication methods are made available to users
|
|
||||||
of gdm for example.
|
|
||||||
|
|
||||||
=head1 AUTHOR
|
|
||||||
|
|
||||||
B<fprintd> was written by Bastien Nocera.
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=item B<fprintd>, B<PAM>
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
<!-- DTD for D-Bus Introspection Documentation -->
|
|
||||||
|
|
||||||
<!ELEMENT doc (summary?,description?,errors?,permission?,since?,deprecated,seealso?)>
|
|
||||||
|
|
||||||
<!ELEMENT summary (#PCDATA|ref)*>
|
|
||||||
<!ELEMENT description (#PCDATA|para|example)*>
|
|
||||||
<!ELEMENT errors (error)*>
|
|
||||||
<!ELEMENT permission (#PCDATA|ref|para)*>
|
|
||||||
<!ELEMENT since EMPTY>
|
|
||||||
<!ATTLIST since version CDATA #REQUIRED>
|
|
||||||
<!ELEMENT deprecated (#PCDATA|ref)>
|
|
||||||
<!ATTLIST deprecated version CDATA #REQUIRED>
|
|
||||||
<!ATTLIST deprecated instead CDATA #REQUIRED>
|
|
||||||
<!ELEMENT seealso (ref+)>
|
|
||||||
|
|
||||||
<!ELEMENT error (#PCDATA|para)*>
|
|
||||||
<!ATTLIST error name CDATA #REQUIRED>
|
|
||||||
<!ELEMENT para (#PCDATA|example|code|list|ref)*>
|
|
||||||
<!ELEMENT example (#PCDATA|para|code|ref)*>
|
|
||||||
<!ATTLIST language (c|glib|python|shell) #REQUIRED>
|
|
||||||
<!ATTLIST title CDATA #IMPLIED>
|
|
||||||
<!ELEMENT list (item*)>
|
|
||||||
<!ATTLIST list type (bullet|number) #REQUIRED>
|
|
||||||
<!ELEMENT item (term|definition)*>
|
|
||||||
<!ELEMENT term (#PCDATA|ref)*>
|
|
||||||
<!ELEMENT definition (#PCDATA|para)*>
|
|
||||||
|
|
||||||
<!ELEMENT code (#PCDATA)>
|
|
||||||
<!ATTLIST code lang CDATA #IMPLIED>
|
|
||||||
<!ELEMENT ref CDATA>
|
|
||||||
<!ATTLIST ref type (parameter|arg|signal|method|interface) #REQUIRED>
|
|
||||||
<!ATTLIST ref to CDATA #REQUIRED>
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
docbook_xml_header = custom_target('docbook_xml_header',
|
|
||||||
output: 'docbook-xml-header.xml',
|
|
||||||
command: [
|
|
||||||
'echo', '-n',
|
|
||||||
'<?xml version="1.0"?>\n',
|
|
||||||
'<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">\n',
|
|
||||||
],
|
|
||||||
capture: true,
|
|
||||||
)
|
|
||||||
|
|
||||||
dbus_interfaces_refs = []
|
|
||||||
foreach interface_file: dbus_interfaces_files
|
|
||||||
basename = run_command('basename', interface_file.full_path(), '.xml').stdout().strip()
|
|
||||||
dbus_interfaces_refs += custom_target(basename + '_ref',
|
|
||||||
input: docbook_xml_header,
|
|
||||||
output: basename + '.ref.xml',
|
|
||||||
build_by_default: true,
|
|
||||||
depends: interface_file,
|
|
||||||
capture: true,
|
|
||||||
command: [
|
|
||||||
bash, '-c',
|
|
||||||
'cat @INPUT@;' +
|
|
||||||
xsltproc.path() + ' @0@/@1@ '.format(
|
|
||||||
meson.source_root(),
|
|
||||||
files('spec-to-docbook.xsl')[0]) +
|
|
||||||
interface_file.full_path() + '| tail -n +2;',
|
|
||||||
],
|
|
||||||
)
|
|
||||||
endforeach
|
|
||||||
@ -1,550 +0,0 @@
|
|||||||
<?xml version='1.0'?>
|
|
||||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
|
||||||
xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"
|
|
||||||
exclude-result-prefixes="doc">
|
|
||||||
<!--
|
|
||||||
Convert D-Bus Glib xml into DocBook refentries
|
|
||||||
Copyright (C) 2007 William Jon McCann
|
|
||||||
License: GPL
|
|
||||||
-->
|
|
||||||
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
|
|
||||||
|
|
||||||
<xsl:template match="/">
|
|
||||||
|
|
||||||
<xsl:variable name="interface" select="//interface/@name"/>
|
|
||||||
<xsl:variable name="basename">
|
|
||||||
<xsl:call-template name="interface-basename">
|
|
||||||
<xsl:with-param name="str" select="$interface"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
|
|
||||||
<refentry><xsl:attribute name="id"><xsl:value-of select="$basename"/></xsl:attribute>
|
|
||||||
<refmeta>
|
|
||||||
<refentrytitle role="top_of_page"><xsl:value-of select="//interface/@name"/></refentrytitle>
|
|
||||||
</refmeta>
|
|
||||||
|
|
||||||
<refnamediv>
|
|
||||||
<refname><xsl:value-of select="//interface/@name"/></refname>
|
|
||||||
<refpurpose><xsl:value-of select="$basename"/> interface</refpurpose>
|
|
||||||
</refnamediv>
|
|
||||||
|
|
||||||
<refsynopsisdiv role="synopsis">
|
|
||||||
<title role="synopsis.title">Methods</title>
|
|
||||||
<synopsis>
|
|
||||||
<xsl:call-template name="methods-synopsis">
|
|
||||||
<xsl:with-param name="basename" select="$basename"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</synopsis>
|
|
||||||
</refsynopsisdiv>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="count(///signal) > 0">
|
|
||||||
<refsect1 role="signal_proto">
|
|
||||||
<title role="signal_proto.title">Signals</title>
|
|
||||||
<synopsis>
|
|
||||||
<xsl:call-template name="signals-synopsis">
|
|
||||||
<xsl:with-param name="basename" select="$basename"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</synopsis>
|
|
||||||
</refsect1>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
|
|
||||||
<refsect1 role="impl_interfaces">
|
|
||||||
<title role="impl_interfaces.title">Implemented Interfaces</title>
|
|
||||||
<para>
|
|
||||||
Objects implementing <xsl:value-of select="$interface"/> also implements
|
|
||||||
org.freedesktop.DBus.Introspectable,
|
|
||||||
org.freedesktop.DBus.Properties
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="count(///property) > 0">
|
|
||||||
<refsect1 role="properties">
|
|
||||||
<title role="properties.title">Properties</title>
|
|
||||||
<synopsis>
|
|
||||||
<xsl:call-template name="properties-synopsis">
|
|
||||||
<xsl:with-param name="basename" select="$basename"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</synopsis>
|
|
||||||
</refsect1>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
|
|
||||||
<refsect1 role="desc">
|
|
||||||
<title role="desc.title">Description</title>
|
|
||||||
<para>
|
|
||||||
<xsl:apply-templates select="//interface/doc:doc"/>
|
|
||||||
</para>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<refsect1 role="details">
|
|
||||||
<title role="details.title">Details</title>
|
|
||||||
<xsl:call-template name="method-details">
|
|
||||||
<xsl:with-param name="basename" select="$basename"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</refsect1>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="count(///signal) > 0">
|
|
||||||
<refsect1 role="signals">
|
|
||||||
<title role="signals.title">Signal Details</title>
|
|
||||||
<xsl:call-template name="signal-details">
|
|
||||||
<xsl:with-param name="basename" select="$basename"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</refsect1>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="count(///property) > 0">
|
|
||||||
<refsect1 role="property_details">
|
|
||||||
<title role="property_details.title">Property Details</title>
|
|
||||||
<xsl:call-template name="property-details">
|
|
||||||
<xsl:with-param name="basename" select="$basename"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</refsect1>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
|
|
||||||
</refentry>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="property-doc">
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:description"/>
|
|
||||||
|
|
||||||
<variablelist role="params">
|
|
||||||
<xsl:for-each select="arg">
|
|
||||||
<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term>
|
|
||||||
<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</xsl:for-each>
|
|
||||||
</variablelist>
|
|
||||||
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:since"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:deprecated"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:permission"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:seealso"/>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="property-details">
|
|
||||||
<xsl:param name="basename"/>
|
|
||||||
<xsl:variable name="longest">
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="@name"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
<xsl:for-each select="///property">
|
|
||||||
<refsect2>
|
|
||||||
<title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute></anchor>The "<xsl:value-of select="@name"/>" property</title>
|
|
||||||
<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm>
|
|
||||||
<programlisting>'<xsl:value-of select="@name"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="2"/></xsl:call-template>
|
|
||||||
<xsl:call-template name="property-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/></xsl:call-template></programlisting>
|
|
||||||
</refsect2>
|
|
||||||
|
|
||||||
<xsl:call-template name="property-doc"/>
|
|
||||||
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="signal-doc">
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:description"/>
|
|
||||||
|
|
||||||
<variablelist role="params">
|
|
||||||
<xsl:for-each select="arg">
|
|
||||||
<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term>
|
|
||||||
<listitem><simpara><xsl:value-of select="doc:doc/doc:summary"/></simpara></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</xsl:for-each>
|
|
||||||
</variablelist>
|
|
||||||
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:since"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:deprecated"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:permission"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:seealso"/>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="signal-details">
|
|
||||||
<xsl:param name="basename"/>
|
|
||||||
<xsl:variable name="longest">
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="@name"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
<xsl:for-each select="///signal">
|
|
||||||
<refsect2>
|
|
||||||
<title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute></anchor>The <xsl:value-of select="@name"/> signal</title>
|
|
||||||
<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm>
|
|
||||||
<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting>
|
|
||||||
</refsect2>
|
|
||||||
|
|
||||||
<xsl:call-template name="signal-doc"/>
|
|
||||||
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:code">
|
|
||||||
<programlisting>
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</programlisting>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:tt">
|
|
||||||
<literal>
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</literal>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:i">
|
|
||||||
<emphasis>
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</emphasis>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:b">
|
|
||||||
<emphasis role="bold">
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</emphasis>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:ulink">
|
|
||||||
<ulink>
|
|
||||||
<xsl:attribute name="url"><xsl:value-of select="@url"/></xsl:attribute>
|
|
||||||
<xsl:value-of select="."/>
|
|
||||||
</ulink>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:summary">
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:example">
|
|
||||||
<informalexample>
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</informalexample>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="listitems-do-term">
|
|
||||||
<xsl:param name="str"/>
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="string-length($str) > 0">
|
|
||||||
<emphasis role="bold"><xsl:value-of select="$str"/>: </emphasis>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="do-listitems">
|
|
||||||
<xsl:for-each select="doc:item">
|
|
||||||
<listitem>
|
|
||||||
<xsl:call-template name="listitems-do-term"><xsl:with-param name="str" select="doc:term"/></xsl:call-template>
|
|
||||||
<xsl:apply-templates select="doc:definition"/>
|
|
||||||
</listitem>
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:list">
|
|
||||||
<para>
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="contains(@type,'number')">
|
|
||||||
<orderedlist>
|
|
||||||
<xsl:call-template name="do-listitems"/>
|
|
||||||
</orderedlist>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<itemizedlist>
|
|
||||||
<xsl:call-template name="do-listitems"/>
|
|
||||||
</itemizedlist>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:para">
|
|
||||||
<para>
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:title">
|
|
||||||
<refsect2><title role="title.description"><anchor role="description"><xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute></anchor><xsl:value-of select="."/></title></refsect2>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:description">
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:since">
|
|
||||||
<para role="since">Since <xsl:value-of select="@version"/>
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:deprecated">
|
|
||||||
<xsl:variable name="name" select="../../@name"/>
|
|
||||||
<xsl:variable name="parent">
|
|
||||||
<xsl:call-template name="interface-basename">
|
|
||||||
<xsl:with-param name="str" select="../../../@name"/>/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
|
|
||||||
<xsl:variable name="type" select="name(../..)"/>
|
|
||||||
|
|
||||||
<para role="deprecated">
|
|
||||||
<warning><para><literal><xsl:value-of select="$name"/></literal> is deprecated since version <xsl:value-of select="@version"/> and should not be used in newly-written code. Use
|
|
||||||
|
|
||||||
<xsl:variable name="to">
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="contains($type,'property')">
|
|
||||||
<xsl:value-of select="$parent"/>:<xsl:value-of select="@instead"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'signal')">
|
|
||||||
<xsl:value-of select="$parent"/>::<xsl:value-of select="@instead"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'method')">
|
|
||||||
<xsl:value-of select="$parent"/>.<xsl:value-of select="@instead"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'interface')">
|
|
||||||
<xsl:value-of select="@instead"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<xsl:value-of select="@instead"/>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
</xsl:variable>
|
|
||||||
|
|
||||||
<xsl:call-template name="create-link">
|
|
||||||
<xsl:with-param name="type" select="$type"/>
|
|
||||||
<xsl:with-param name="to" select="$to"/>
|
|
||||||
<xsl:with-param name="val" select="@instead"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
instead.</para></warning>
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:permission">
|
|
||||||
<para role="permission">
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:errors">
|
|
||||||
<para role="errors">
|
|
||||||
<xsl:apply-templates />
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:seealso">
|
|
||||||
<para>
|
|
||||||
See also:
|
|
||||||
<xsl:apply-templates />
|
|
||||||
|
|
||||||
</para>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="create-link">
|
|
||||||
<xsl:param name="type"/>
|
|
||||||
<xsl:param name="to"/>
|
|
||||||
<xsl:param name="val"/>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="contains($type,'property')">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'signal')">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><literal><xsl:value-of select="$val"/></literal></link>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'method')">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><function><xsl:value-of select="$val"/></function></link>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'interface')">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><xsl:value-of select="$val"/></link>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="contains($type,'description')">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$to"/></xsl:attribute><xsl:value-of select="$val"/></link>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template match="doc:ref">
|
|
||||||
<xsl:call-template name="create-link">
|
|
||||||
<xsl:with-param name="type" select="@type"/>
|
|
||||||
<xsl:with-param name="to" select="@to"/>
|
|
||||||
<xsl:with-param name="val" select="."/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="method-doc">
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:description"/>
|
|
||||||
|
|
||||||
<variablelist role="params">
|
|
||||||
<xsl:for-each select="arg">
|
|
||||||
<varlistentry><term><parameter><xsl:value-of select="@name"/></parameter>:</term>
|
|
||||||
<listitem><simpara><xsl:apply-templates select="doc:doc/doc:summary"/></simpara></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</xsl:for-each>
|
|
||||||
</variablelist>
|
|
||||||
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:since"/>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:deprecated"/>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="count(doc:doc/doc:errors) > 0">
|
|
||||||
<refsect3>
|
|
||||||
<title>Errors</title>
|
|
||||||
<variablelist role="errors">
|
|
||||||
<xsl:for-each select="doc:doc/doc:errors/doc:error">
|
|
||||||
<varlistentry>
|
|
||||||
<term><parameter><xsl:value-of select="@name"/></parameter>:</term>
|
|
||||||
<listitem><simpara><xsl:apply-templates select="."/></simpara></listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</xsl:for-each>
|
|
||||||
</variablelist>
|
|
||||||
</refsect3>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="count(doc:doc/doc:permission) > 0">
|
|
||||||
<refsect3>
|
|
||||||
<title>Permissions</title>
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:permission"/>
|
|
||||||
</refsect3>
|
|
||||||
</xsl:when>
|
|
||||||
</xsl:choose>
|
|
||||||
|
|
||||||
<xsl:apply-templates select="doc:doc/doc:seealso"/>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="method-details">
|
|
||||||
<xsl:param name="basename"/>
|
|
||||||
<xsl:variable name="longest">
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="@name"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
<xsl:for-each select="///method">
|
|
||||||
<refsect2>
|
|
||||||
<title><anchor role="function"><xsl:attribute name="id"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute></anchor><xsl:value-of select="@name"/> ()</title>
|
|
||||||
<indexterm><primary><xsl:value-of select="@name"/></primary><secondary><xsl:value-of select="$basename"/></secondary></indexterm>
|
|
||||||
<programlisting><xsl:value-of select="@name"/> (<xsl:call-template name="method-args"><xsl:with-param name="indent" select="string-length(@name) + 2"/><xsl:with-param name="prefix" select="."/></xsl:call-template>)</programlisting>
|
|
||||||
</refsect2>
|
|
||||||
|
|
||||||
<xsl:call-template name="method-doc"/>
|
|
||||||
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="properties-synopsis">
|
|
||||||
<xsl:param name="basename"/>
|
|
||||||
<xsl:variable name="longest">
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="///property/@name"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
<xsl:for-each select="///property">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>:<xsl:value-of select="@name"/></xsl:attribute>'<xsl:value-of select="@name"/>'</link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template> <xsl:call-template name="property-args"><xsl:with-param name="indent" select="$longest + 2"/></xsl:call-template>
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="signals-synopsis">
|
|
||||||
<xsl:param name="basename"/>
|
|
||||||
<xsl:variable name="longest">
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="///signal/@name"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
<xsl:for-each select="///signal">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>::<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="signal-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///signal"/></xsl:call-template>)
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="methods-synopsis">
|
|
||||||
<xsl:param name="basename"/>
|
|
||||||
<xsl:variable name="longest">
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="///method/@name"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:variable>
|
|
||||||
<xsl:for-each select="///method">
|
|
||||||
<link><xsl:attribute name="linkend"><xsl:value-of select="$basename"/>.<xsl:value-of select="@name"/></xsl:attribute><xsl:value-of select="@name"/></link><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@name) + 1"/></xsl:call-template>(<xsl:call-template name="method-args"><xsl:with-param name="indent" select="$longest + 2"/><xsl:with-param name="prefix" select="///method"/></xsl:call-template>)
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="method-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg"><xsl:value-of select="@direction"/>
|
|
||||||
<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="4 - string-length(@direction)"/></xsl:call-template>'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template>
|
|
||||||
<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">,
|
|
||||||
<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if>
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="signal-args"><xsl:param name="indent"/><xsl:param name="prefix"/><xsl:variable name="longest"><xsl:call-template name="find-longest"><xsl:with-param name="set" select="$prefix/arg/@type"/></xsl:call-template></xsl:variable><xsl:for-each select="arg">'<xsl:value-of select="@type"/>'<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$longest - string-length(@type) + 1"/></xsl:call-template>
|
|
||||||
<xsl:value-of select="@name"/><xsl:if test="not(position() = last())">,
|
|
||||||
<xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="$indent"/></xsl:call-template></xsl:if>
|
|
||||||
</xsl:for-each>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="property-args"><xsl:param name="indent"/>
|
|
||||||
<xsl:value-of select="@access"/><xsl:call-template name="pad-spaces"><xsl:with-param name="width" select="9 - string-length(@access) + 1"/></xsl:call-template>'<xsl:value-of select="@type"/>'
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="pad-spaces">
|
|
||||||
<xsl:param name="width"/>
|
|
||||||
<xsl:variable name="spaces" xml:space="preserve"> </xsl:variable>
|
|
||||||
<xsl:value-of select="substring($spaces,1,$width)"/>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="find-longest">
|
|
||||||
<xsl:param name="set"/>
|
|
||||||
<xsl:param name="index" select="1"/>
|
|
||||||
<xsl:param name="longest" select="0"/>
|
|
||||||
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="$index > count($set)">
|
|
||||||
<!--finished looking-->
|
|
||||||
<xsl:value-of select="$longest"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="string-length($set[$index])>$longest">
|
|
||||||
<!--found new longest-->
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="$set"/>
|
|
||||||
<xsl:with-param name="index" select="$index + 1"/>
|
|
||||||
<xsl:with-param name="longest" select="string-length($set[$index])"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<!--this isn't any longer-->
|
|
||||||
<xsl:call-template name="find-longest">
|
|
||||||
<xsl:with-param name="set" select="$set"/>
|
|
||||||
<xsl:with-param name="index" select="$index + 1"/>
|
|
||||||
<xsl:with-param name="longest" select="$longest"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
|
|
||||||
<xsl:template name="interface-basename">
|
|
||||||
<xsl:param name="str"/>
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="contains($str,'.')">
|
|
||||||
<xsl:call-template name="interface-basename">
|
|
||||||
<xsl:with-param name="str" select="substring-after($str,'.')"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<xsl:value-of select="$str"/>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
</xsl:stylesheet>
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
|
|
||||||
"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
|
|
||||||
<!ENTITY version SYSTEM "version.xml">
|
|
||||||
]>
|
|
||||||
<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude">
|
|
||||||
<bookinfo>
|
|
||||||
<title>fprintd Reference Manual</title>
|
|
||||||
<releaseinfo>Version &version;</releaseinfo>
|
|
||||||
<authorgroup>
|
|
||||||
<author>
|
|
||||||
<firstname>Bastien</firstname>
|
|
||||||
<surname>Nocera</surname>
|
|
||||||
<affiliation>
|
|
||||||
<address>
|
|
||||||
<email>hadess@hadess.net</email>
|
|
||||||
</address>
|
|
||||||
</affiliation>
|
|
||||||
</author>
|
|
||||||
</authorgroup>
|
|
||||||
|
|
||||||
<copyright>
|
|
||||||
<year>2008</year>
|
|
||||||
<holder>The fprintd Authors</holder>
|
|
||||||
</copyright>
|
|
||||||
|
|
||||||
<legalnotice>
|
|
||||||
<para>
|
|
||||||
Permission is granted to copy, distribute and/or modify this
|
|
||||||
document under the terms of the <citetitle>GNU Free
|
|
||||||
Documentation License</citetitle>, Version 1.1 or any later
|
|
||||||
version published by the Free Software Foundation with no
|
|
||||||
Invariant Sections, no Front-Cover Texts, and no Back-Cover
|
|
||||||
Texts. You may obtain a copy of the <citetitle>GNU Free
|
|
||||||
Documentation License</citetitle> from the Free Software
|
|
||||||
Foundation by visiting <ulink type="http"
|
|
||||||
url="http://www.fsf.org">their Web site</ulink> or by writing
|
|
||||||
to:
|
|
||||||
|
|
||||||
<address>
|
|
||||||
The Free Software Foundation, Inc.,
|
|
||||||
<street>59 Temple Place</street> - Suite 330,
|
|
||||||
<city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>,
|
|
||||||
<country>USA</country>
|
|
||||||
</address>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Many of the names used by companies to distinguish their
|
|
||||||
products and services are claimed as trademarks. Where those
|
|
||||||
names appear in any GNOME documentation, and those trademarks
|
|
||||||
are made aware to the members of the GNOME Documentation
|
|
||||||
Project, the names have been printed in caps or initial caps.
|
|
||||||
</para>
|
|
||||||
</legalnotice>
|
|
||||||
</bookinfo>
|
|
||||||
|
|
||||||
<reference id="ref-dbus">
|
|
||||||
<title>D-Bus API Reference</title>
|
|
||||||
<partintro>
|
|
||||||
<para>
|
|
||||||
This part documents the D-Bus interface used to access the
|
|
||||||
fprintd daemon.
|
|
||||||
</para>
|
|
||||||
</partintro>
|
|
||||||
<xi:include href="dbus/net.reactivated.Fprint.Manager.ref.xml"/>
|
|
||||||
<xi:include href="dbus/net.reactivated.Fprint.Device.ref.xml"/>
|
|
||||||
</reference>
|
|
||||||
|
|
||||||
<index>
|
|
||||||
<title>Index</title>
|
|
||||||
</index>
|
|
||||||
|
|
||||||
<!-- License -->
|
|
||||||
|
|
||||||
<appendix id="license">
|
|
||||||
<title>License</title>
|
|
||||||
<para>
|
|
||||||
<programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="../COPYING" parse="text"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting>
|
|
||||||
</para>
|
|
||||||
</appendix>
|
|
||||||
</book>
|
|
||||||
@ -1,27 +0,0 @@
|
|||||||
subdir('dbus')
|
|
||||||
|
|
||||||
version_file = configure_file(
|
|
||||||
input: 'version.xml.in',
|
|
||||||
output: 'version.xml',
|
|
||||||
configuration: configuration_data({
|
|
||||||
'VERSION': meson.project_version(),
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
gnome.gtkdoc(meson.project_name(),
|
|
||||||
main_xml: 'fprintd-docs.xml',
|
|
||||||
src_dir: meson.source_root() / 'src',
|
|
||||||
dependencies: [
|
|
||||||
declare_dependency(
|
|
||||||
sources: dbus_interfaces_refs,
|
|
||||||
link_with: libfprintd_private,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
content_files: [
|
|
||||||
version_file,
|
|
||||||
dbus_interfaces_refs,
|
|
||||||
],
|
|
||||||
ignore_headers: [
|
|
||||||
'config.h',
|
|
||||||
],
|
|
||||||
install: true)
|
|
||||||
@ -1 +0,0 @@
|
|||||||
@VERSION@
|
|
||||||
@ -1,137 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
#!/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
|
|
||||||
@ -1,110 +0,0 @@
|
|||||||
--- 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);
|
|
||||||
2763
src/device.c
645
src/device.xml
@ -1,645 +0,0 @@
|
|||||||
<!DOCTYPE node PUBLIC
|
|
||||||
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
|
||||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [
|
|
||||||
<!ENTITY ERROR_CLAIM_DEVICE "net.reactivated.Fprint.Error.ClaimDevice">
|
|
||||||
<!ENTITY ERROR_ALREADY_IN_USE "net.reactivated.Fprint.Error.AlreadyInUse">
|
|
||||||
<!ENTITY ERROR_INTERNAL "net.reactivated.Fprint.Error.Internal">
|
|
||||||
<!ENTITY ERROR_PERMISSION_DENIED "net.reactivated.Fprint.Error.PermissionDenied">
|
|
||||||
<!ENTITY ERROR_NO_ENROLLED_PRINTS "net.reactivated.Fprint.Error.NoEnrolledPrints">
|
|
||||||
<!ENTITY ERROR_NO_ACTION_IN_PROGRESS "net.reactivated.Fprint.Error.NoActionInProgress">
|
|
||||||
<!ENTITY ERROR_INVALID_FINGERNAME "net.reactivated.Fprint.Error.InvalidFingername">
|
|
||||||
<!ENTITY ERROR_PRINTS_NOT_DELETED "net.reactivated.Fprint.Error.PrintsNotDeleted">
|
|
||||||
<!ENTITY ERROR_PRINTS_NOT_DELETED_FROM_DEVICE "net.reactivated.Fprint.Error.PrintsNotDeletedFromDevice">
|
|
||||||
]>
|
|
||||||
|
|
||||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
|
||||||
<interface name="net.reactivated.Fprint.Device">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:title id="polkit-integration">
|
|
||||||
PolicyKit integration
|
|
||||||
</doc:title>
|
|
||||||
<doc:para>
|
|
||||||
fprintd uses PolicyKit to check whether users are allowed to access fingerprint data, or the
|
|
||||||
fingerprint readers itself.
|
|
||||||
<doc:list>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>net.reactivated.fprint.device.verify</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Whether the user is allowed to verify fingers against saved fingerprints.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>net.reactivated.fprint.device.enroll</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Whether the user is allowed to enroll new fingerprints.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>net.reactivated.fprint.device.setusername</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Whether the user is allowed to query, verify, or enroll fingerprints for users other than itself.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
</doc:list>
|
|
||||||
</doc:para>
|
|
||||||
|
|
||||||
<doc:title id="usernames">
|
|
||||||
Usernames
|
|
||||||
</doc:title>
|
|
||||||
<doc:para>
|
|
||||||
When a username argument is used for a method, a PolicyKit check is done on the
|
|
||||||
<doc:tt>net.reactivated.fprint.device.setusername</doc:tt> PolicyKit
|
|
||||||
action to see whether the user the client is running as is allowed to access data from other users.
|
|
||||||
</doc:para>
|
|
||||||
<doc:para>
|
|
||||||
By default, only root is allowed to access fingerprint data for users other than itself. For a normal user,
|
|
||||||
it is recommended that you use an empty string for the username, which will mean "the client the user is
|
|
||||||
running as".
|
|
||||||
</doc:para>
|
|
||||||
<doc:para>
|
|
||||||
See <doc:ref type="description" to="polkit-integration">PolicyKit integration</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
|
|
||||||
<doc:title id="fingerprint-names">
|
|
||||||
Fingerprint names
|
|
||||||
</doc:title>
|
|
||||||
<doc:para>
|
|
||||||
When a finger name argument is used for a method, it refers to either a single finger, or
|
|
||||||
"any" finger. See the list of possible values below:
|
|
||||||
<doc:list>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>left-thumb</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Left thumb
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>left-index-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Left index finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>left-middle-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Left middle finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>left-ring-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Left ring finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>left-little-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Left little finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>right-thumb</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Right thumb
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>right-index-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Right index finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>right-middle-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Right middle finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>right-ring-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Right ring finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>right-little-finger</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Right little finger
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>any</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
Any finger. This is only used for <doc:ref type="method" to="Device.VerifyStart">Device.VerifyStart</doc:ref>
|
|
||||||
(select the first finger with a fingerprint associated, or all the fingerprints available for the user when
|
|
||||||
the device supports it) and <doc:ref type="signal" to="Device::VerifyFingerSelected">Device::VerifyFingerSelected</doc:ref>
|
|
||||||
(any finger with an associated fingerprint can be used).
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
</doc:list>
|
|
||||||
</doc:para>
|
|
||||||
|
|
||||||
<doc:title id="verify-statuses">
|
|
||||||
Verify Statuses
|
|
||||||
</doc:title>
|
|
||||||
<doc:para>
|
|
||||||
<doc:list>
|
|
||||||
Possible values for the result passed through <doc:ref type="signal" to="Device::VerifyResult">Device::VerifyResult</doc:ref> are:
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-no-match</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The verification did not match, <doc:ref type="method" to="Device.VerifyStop">Device.VerifyStop</doc:ref> should now be called.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-match</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The verification succeeded, <doc:ref type="method" to="Device.VerifyStop">Device.VerifyStop</doc:ref> should now be called.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-retry-scan</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user should retry scanning their finger, the verification is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-swipe-too-short</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user's swipe was too short. The user should retry scanning their finger, the verification is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-finger-not-centered</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user's finger was not centered on the reader. The user should retry scanning their finger, the verification is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-remove-and-retry</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user should remove their finger from the reader and retry scanning their finger, the verification is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-disconnected</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The device was disconnected during the verification, no other actions should be taken, and you shouldn't use the device any more.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>verify-unknown-error</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
An unknown error occurred (usually a driver problem), <doc:ref type="method" to="Device.VerifyStop">Device.VerifyStop</doc:ref> should now be called.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
</doc:list>
|
|
||||||
</doc:para>
|
|
||||||
|
|
||||||
<doc:title id="enroll-statuses">
|
|
||||||
Enroll Statuses
|
|
||||||
</doc:title>
|
|
||||||
<doc:para>
|
|
||||||
<doc:list>
|
|
||||||
Possible values for the result passed through <doc:ref type="signal" to="Device::EnrollResult">Device::EnrollResult</doc:ref> are:
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-completed</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The enrollment successfully completed, <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-failed</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The enrollment failed, <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-stage-passed</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
One stage of the enrollment passed, the enrollment is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-retry-scan</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user should retry scanning their finger, the enrollment is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-swipe-too-short</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user's swipe was too short. The user should retry scanning their finger, the enrollment is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-finger-not-centered</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user's finger was not centered on the reader. The user should retry scanning their finger, the enrollment is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-remove-and-retry</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The user should remove their finger from the reader and retry scanning their finger, the enrollment is still ongoing.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-data-full</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
No further prints can be enrolled on this device, <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called.
|
|
||||||
|
|
||||||
<doc:ref type="method" to="DeleteEnrolledFinger">Delete other prints</doc:ref> from the device first to continue
|
|
||||||
(e.g. from other users). Note that old prints or prints from other operating systems may be deleted automatically
|
|
||||||
to resolve this error without any notification.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-duplicate</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The print has already been enrolled, <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called.
|
|
||||||
|
|
||||||
The user should enroll a different finger, or delete the print that has been enrolled already.
|
|
||||||
This print may be enrolled for a different user.
|
|
||||||
Note that an old duplicate (e.g. from a previous install) will be automatically garbage collected and should not cause any issues.
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-disconnected</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
The device was disconnected during the enrollment, no other actions should be taken, and you shouldn't use the device any more.
|
|
||||||
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
<doc:item>
|
|
||||||
<doc:term>enroll-unknown-error</doc:term>
|
|
||||||
<doc:definition>
|
|
||||||
An unknown error occurred (usually a driver problem), <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref> should now be called.
|
|
||||||
|
|
||||||
</doc:definition>
|
|
||||||
</doc:item>
|
|
||||||
</doc:list>
|
|
||||||
</doc:para>
|
|
||||||
</doc:doc>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="ListEnrolledFingers">
|
|
||||||
<arg type="s" name="username" direction="in">
|
|
||||||
<doc:doc><doc:summary>The username for whom to list the enrolled fingerprints. See <doc:ref type="description" to="usernames">Usernames</doc:ref>.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
<arg type="as" name="enrolled_fingers" direction="out">
|
|
||||||
<doc:doc><doc:summary>An array of strings representing the enrolled fingerprints. See <doc:ref type="description" to="fingerprint-names">Fingerprint names</doc:ref>.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
List all the enrolled fingerprints for the chosen user.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_NO_ENROLLED_PRINTS;">if the chosen user doesn't have any fingerprints enrolled</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="DeleteEnrolledFingers">
|
|
||||||
<arg type="s" name="username" direction="in">
|
|
||||||
<doc:doc><doc:summary>The username for whom to delete the enrolled fingerprints. See <doc:ref type="description" to="usernames">Usernames</doc:ref>.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Delete all the enrolled fingerprints for the chosen user.
|
|
||||||
</doc:para>
|
|
||||||
<doc:para>
|
|
||||||
This call only exists for compatibility reasons, you should instead claim the device using
|
|
||||||
<doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref> and then call
|
|
||||||
<doc:ref type="method" to="DeleteEnrolledFingers2">DeleteEnrolledFingers2</doc:ref> or
|
|
||||||
<doc:ref type="method" to="DeleteEnrolledFinger">DeleteEnrolledFinger</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_PRINTS_NOT_DELETED;">if the fingerprint is not deleted from fprintd storage</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="DeleteEnrolledFingers2">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Delete all the enrolled fingerprints for the user currently claiming the device with <doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_PRINTS_NOT_DELETED;">if the fingerprint is not deleted from fprintd storage</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="DeleteEnrolledFinger">
|
|
||||||
<arg type="s" name="finger_name" direction="in">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>A string representing the finger to delete. See
|
|
||||||
<doc:ref type="description" to="fingerprint-names">Fingerprint names</doc:ref>.
|
|
||||||
Note that "any" is not a valid finger name for this method.</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Delete the enrolled fingerprint for the user currently claiming the device with <doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
|
|
||||||
<doc:error name="&ERROR_INVALID_FINGERNAME;">if the finger name passed is invalid</doc:error>
|
|
||||||
<doc:error name="&ERROR_NO_ENROLLED_PRINTS;">if the chosen user doesn't have the requsted fingerprint enrolled</doc:error>
|
|
||||||
<doc:error name="&ERROR_PRINTS_NOT_DELETED;">if the fingerprint is not deleted from fprintd storage</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="Claim">
|
|
||||||
<arg type="s" name="username" direction="in">
|
|
||||||
<doc:doc><doc:summary>The username for whom to claim the device. See <doc:ref type="description" to="usernames">Usernames</doc:ref>.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Claim the device for the chosen user.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_ALREADY_IN_USE;">if the device is already claimed</doc:error>
|
|
||||||
<doc:error name="&ERROR_INTERNAL;">if the device couldn't be claimed</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="Release">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Release a device claimed with <doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="VerifyStart">
|
|
||||||
<arg type="s" name="finger_name" direction="in">
|
|
||||||
<doc:doc><doc:summary>A string representing the finger to verify. See <doc:ref type="description" to="fingerprint-names">Fingerprint names</doc:ref>.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Check the chosen finger against a saved fingerprint. You need to have claimed the device using
|
|
||||||
<doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref>. The finger selected is sent to the front-end
|
|
||||||
using <doc:ref type="signal" to="Device::VerifyFingerSelected">Device::VerifyFingerSelected</doc:ref> and
|
|
||||||
verification status through <doc:ref type="signal" to="Device::VerifyStatus">Device::VerifyStatus</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
|
|
||||||
<doc:error name="&ERROR_ALREADY_IN_USE;">if the device was already being used</doc:error>
|
|
||||||
<doc:error name="&ERROR_NO_ENROLLED_PRINTS;">if there are no enrolled prints for the chosen user</doc:error>
|
|
||||||
<doc:error name="&ERROR_INTERNAL;">if there was an internal error</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="VerifyStop">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Stop an on-going fingerprint verification started with <doc:ref type="method" to="Device.VerifyStart">Device.VerifyStart</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
|
|
||||||
<doc:error name="&ERROR_NO_ACTION_IN_PROGRESS;">if there was no ongoing verification</doc:error>
|
|
||||||
<doc:error name="&ERROR_INTERNAL;">if there was an internal error</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<signal name="VerifyFingerSelected">
|
|
||||||
<arg type="s" name="finger_name">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
<doc:para>
|
|
||||||
A string representing the finger select to be verified.
|
|
||||||
</doc:para>
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:seealso>
|
|
||||||
<doc:ref type="description" to="fingerprint-names">Fingerprint names</doc:ref>.
|
|
||||||
</doc:seealso>
|
|
||||||
</doc:doc>
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<signal name="VerifyStatus">
|
|
||||||
<arg type="s" name="result">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
A string representing the status of the verification.
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
|
|
||||||
<arg type="b" name="done">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
Whether the verification finished and can be stopped.
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
|
|
||||||
<doc:doc>
|
|
||||||
<doc:seealso>
|
|
||||||
<doc:ref type="description" to="verify-statuses">Verify Statuses</doc:ref> and <doc:ref type="method" to="Device.VerifyStop">Device.VerifyStop</doc:ref>.
|
|
||||||
</doc:seealso>
|
|
||||||
</doc:doc>
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="EnrollStart">
|
|
||||||
<arg type="s" name="finger_name" direction="in">
|
|
||||||
<doc:doc><doc:summary>A string representing the finger to enroll. See
|
|
||||||
<doc:ref type="description" to="fingerprint-names">Fingerprint names</doc:ref>.
|
|
||||||
Note that "any" is not a valid finger name for this method.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Start enrollment for the selected finger. You need to have claimed the device using
|
|
||||||
<doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref> before calling
|
|
||||||
this method. Enrollment status is sent through <doc:ref type="signal" to="Device::EnrollStatus">Device::EnrollStatus</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
|
|
||||||
<doc:error name="&ERROR_ALREADY_IN_USE;">if the device was already being used</doc:error>
|
|
||||||
<doc:error name="&ERROR_INVALID_FINGERNAME;">if the finger name passed is invalid</doc:error>
|
|
||||||
<doc:error name="&FINGER_ALREADY_ENROLLED;">if the finger has been already enrolled by the user</doc:error>
|
|
||||||
<doc:error name="&ERROR_INTERNAL;">if there was an internal error</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="EnrollStop">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Stop an on-going fingerprint enrollment started with <doc:ref type="method" to="Device.EnrollStart">Device.EnrollStart</doc:ref>.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_PERMISSION_DENIED;">if the caller lacks the appropriate PolicyKit authorization</doc:error>
|
|
||||||
<doc:error name="&ERROR_CLAIM_DEVICE;">if the device was not claimed</doc:error>
|
|
||||||
<doc:error name="&ERROR_NO_ACTION_IN_PROGRESS;">if there was no ongoing verification</doc:error>
|
|
||||||
<doc:error name="&ERROR_INTERNAL;">if there was an internal error</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<signal name="EnrollStatus">
|
|
||||||
<arg type="s" name="result">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
A string representing the status of the enrollment.
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
|
|
||||||
<arg type="b" name="done">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:summary>
|
|
||||||
Whether the enrollment finished and can be stopped.
|
|
||||||
</doc:summary>
|
|
||||||
</doc:doc>
|
|
||||||
</arg>
|
|
||||||
|
|
||||||
<doc:doc>
|
|
||||||
<doc:seealso>
|
|
||||||
<doc:ref type="description" to="enroll-statuses">Enrollment Statuses</doc:ref> and <doc:ref type="method" to="Device.EnrollStop">Device.EnrollStop</doc:ref>.
|
|
||||||
</doc:seealso>
|
|
||||||
</doc:doc>
|
|
||||||
</signal>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<property name="name" type="s" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The product name of the device.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<property name="num-enroll-stages" type="i" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The number of enrollment stages for the device. This is only available when the device has been claimed, otherwise it will be undefined (-1).
|
|
||||||
</doc:para>
|
|
||||||
<doc:seealso>
|
|
||||||
<doc:ref type="method" to="Device.Claim">Device.Claim</doc:ref> and <doc:ref type="method" to="Device.EnrollStart">Device.EnrollStart</doc:ref>.
|
|
||||||
</doc:seealso>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<property name="scan-type" type="s" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
The scan type of the device, either "press" if you place your finger on the device, or "swipe" if you have to swipe your finger.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<property name="finger-present" type="b" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Whether the finger is on sensor.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<property name="finger-needed" type="b" access="read">
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Whether the sensor is waiting for the finger.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</property>
|
|
||||||
|
|
||||||
</interface>
|
|
||||||
</node>
|
|
||||||
|
|
||||||
@ -1,368 +0,0 @@
|
|||||||
/*
|
|
||||||
* Simple file storage for fprintd
|
|
||||||
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2008 Vasily Khoruzhick <anarsoul@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* FIXME:
|
|
||||||
* This file almost duplicate data.c from libfprint
|
|
||||||
* Maybe someday data.c will be upgraded to this one ;)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gstdio.h>
|
|
||||||
|
|
||||||
#include <fprint.h>
|
|
||||||
|
|
||||||
#include "file_storage.h"
|
|
||||||
|
|
||||||
#define FILE_STORAGE_PATH "/var/lib/fprint"
|
|
||||||
#define DIR_PERMS 0700
|
|
||||||
|
|
||||||
static char *storage_path = NULL;
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
get_storage_path (void)
|
|
||||||
{
|
|
||||||
const char *path = NULL;
|
|
||||||
|
|
||||||
if (storage_path != NULL)
|
|
||||||
return storage_path;
|
|
||||||
|
|
||||||
/* set by systemd >= 240 to an absolute path
|
|
||||||
* taking into account the StateDirectory
|
|
||||||
* unit file setting */
|
|
||||||
path = g_getenv ("STATE_DIRECTORY");
|
|
||||||
if (path != NULL)
|
|
||||||
{
|
|
||||||
/* If multiple directories are set, then in the environment variable
|
|
||||||
* the paths are concatenated with colon (":"). */
|
|
||||||
if (strchr (path, ':'))
|
|
||||||
{
|
|
||||||
g_auto(GStrv) elems = NULL;
|
|
||||||
elems = g_strsplit (path, ":", -1);
|
|
||||||
storage_path = g_strdup (elems[0]);
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
g_autofree char *dirpath = NULL;
|
|
||||||
char *path;
|
|
||||||
char fingername[2];
|
|
||||||
|
|
||||||
g_snprintf (fingername, 2, "%x", finger);
|
|
||||||
|
|
||||||
dirpath = get_path_to_storedir (driver, device_id, base_store);
|
|
||||||
path = g_build_filename (dirpath, fingername, NULL);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
|
||||||
file_storage_get_basestore_for_username (const char *username)
|
|
||||||
{
|
|
||||||
return g_build_filename (get_storage_path (), username, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_debug ("file_storage_print_data_save(): print saved to %s", path);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
load_from_file (char *path, FpPrint **print)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) err = NULL;
|
|
||||||
gsize length;
|
|
||||||
g_autofree char *contents = NULL;
|
|
||||||
FpPrint *new;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
*print = new;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
file_storage_print_data_load (FpDevice *dev,
|
|
||||||
FpFinger finger,
|
|
||||||
const char *username,
|
|
||||||
FpPrint **print)
|
|
||||||
{
|
|
||||||
g_autofree gchar *path = NULL;
|
|
||||||
g_autofree gchar *base_store = NULL;
|
|
||||||
|
|
||||||
g_autoptr(FpPrint) new = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
base_store = file_storage_get_basestore_for_username (username);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* Make sure the username/finger matches our expectations. */
|
|
||||||
if (fp_print_get_finger (new) != finger)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (g_strcmp0 (fp_print_get_username (new), username) != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* And that the print is compatible with the device. */
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!g_file_test (path, G_FILE_TEST_EXISTS))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = g_unlink (path);
|
|
||||||
g_debug ("file_storage_print_data_delete(): unlink(\"%s\") %s",
|
|
||||||
path, g_strerror (r));
|
|
||||||
|
|
||||||
prints = file_storage_discover_prints (dev, username);
|
|
||||||
if (!prints)
|
|
||||||
{
|
|
||||||
g_autofree char *dir = g_steal_pointer (&path);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
g_autofree char *tmp = g_steal_pointer (&dir);
|
|
||||||
dir = g_path_get_dirname (tmp);
|
|
||||||
}
|
|
||||||
while (g_str_has_prefix (dir, base_store) && g_rmdir (dir) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSList *
|
|
||||||
scan_dev_storedir (char *devpath,
|
|
||||||
GSList *list)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) err = NULL;
|
|
||||||
const gchar *ent;
|
|
||||||
|
|
||||||
GDir *dir = g_dir_open (devpath, 0, &err);
|
|
||||||
|
|
||||||
if (!dir)
|
|
||||||
{
|
|
||||||
g_debug ("scan_dev_storedir(): opendir(\"%s\") failed: %s", devpath, err->message);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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, GUINT_TO_POINTER (val));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dir_close (dir);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
GSList *
|
|
||||||
file_storage_discover_prints (FpDevice *dev, const char *username)
|
|
||||||
{
|
|
||||||
GSList *list = NULL;
|
|
||||||
g_autofree gchar *base_store = NULL;
|
|
||||||
g_autofree gchar *storedir = NULL;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
g_debug ("file_storage_discover_prints() for user '%s' in '%s'",
|
|
||||||
username, storedir);
|
|
||||||
|
|
||||||
list = scan_dev_storedir (storedir, list);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!dir)
|
|
||||||
return list;
|
|
||||||
|
|
||||||
while ((ent = g_dir_read_name (dir)))
|
|
||||||
{
|
|
||||||
/* ent is a username */
|
|
||||||
if (*ent == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
list = g_slist_prepend (list, g_strdup (ent));
|
|
||||||
}
|
|
||||||
|
|
||||||
g_dir_close (dir);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
file_storage_init (void)
|
|
||||||
{
|
|
||||||
/* Nothing to do */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
file_storage_deinit (void)
|
|
||||||
{
|
|
||||||
g_clear_pointer (&storage_path, g_free);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Simple file storage for fprintd
|
|
||||||
* Copyright (C) 2008 Vasily Khoruzhick <anarsoul@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
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_delete (FpDevice *dev,
|
|
||||||
FpFinger finger,
|
|
||||||
const char *username);
|
|
||||||
|
|
||||||
int file_storage_init (void);
|
|
||||||
|
|
||||||
int file_storage_deinit (void);
|
|
||||||
|
|
||||||
GSList *file_storage_discover_prints (FpDevice *dev,
|
|
||||||
const char *username);
|
|
||||||
GSList *file_storage_discover_users (void);
|
|
||||||
130
src/fprintd.h
@ -1,130 +0,0 @@
|
|||||||
/*
|
|
||||||
* fprintd header file
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
*
|
|
||||||
* 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 <glib.h>
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <fprint.h>
|
|
||||||
#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);
|
|
||||||
|
|
||||||
#define FPRINT_ERROR fprint_error_quark ()
|
|
||||||
typedef enum {
|
|
||||||
/* developer didn't claim the device */
|
|
||||||
FPRINT_ERROR_CLAIM_DEVICE, /*< nick=net.reactivated.Fprint.Error.ClaimDevice >*/
|
|
||||||
/* device is already claimed by somebody else */
|
|
||||||
FPRINT_ERROR_ALREADY_IN_USE, /*< nick=net.reactivated.Fprint.Error.AlreadyInUse >*/
|
|
||||||
/* internal error occurred */
|
|
||||||
FPRINT_ERROR_INTERNAL, /*< nick=net.reactivated.Fprint.Error.Internal >*/
|
|
||||||
/* PolicyKit refused the action */
|
|
||||||
FPRINT_ERROR_PERMISSION_DENIED, /*< nick=net.reactivated.Fprint.Error.PermissionDenied >*/
|
|
||||||
/* No prints are enrolled */
|
|
||||||
FPRINT_ERROR_NO_ENROLLED_PRINTS, /*< nick=net.reactivated.Fprint.Error.NoEnrolledPrints >*/
|
|
||||||
/* Prints has already been enrolled */
|
|
||||||
FPRINT_ERROR_FINGER_ALREADY_ENROLLED, /*< nick=net.reactivated.Fprint.Error.FingerAlreadyEnrolled >*/
|
|
||||||
/* 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 >*/
|
|
||||||
/* Prints cannot be deleted from the fprintd storage */
|
|
||||||
FPRINT_ERROR_PRINTS_NOT_DELETED, /*< nick=net.reactivated.Fprint.Error.PrintsNotDeleted >*/
|
|
||||||
/* Prints cannot be deleted from the device storage */
|
|
||||||
FPRINT_ERROR_PRINTS_NOT_DELETED_FROM_DEVICE, /*< nick=net.reactivated.Fprint.Error.PrintsNotDeletedFromDevice >*/
|
|
||||||
} 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 ())
|
|
||||||
G_DECLARE_FINAL_TYPE (FprintManager, fprint_manager, FPRINT, MANAGER, GObject)
|
|
||||||
|
|
||||||
struct _FprintManager
|
|
||||||
{
|
|
||||||
GObject parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
FprintDBusDeviceSkeleton)
|
|
||||||
|
|
||||||
struct _FprintDevice
|
|
||||||
{
|
|
||||||
FprintDBusDeviceSkeleton parent;
|
|
||||||
};
|
|
||||||
|
|
||||||
FprintDevice *fprint_device_new (FpDevice *dev);
|
|
||||||
guint32 _fprint_device_get_id (FprintDevice *rdev);
|
|
||||||
|
|
||||||
void fprint_device_suspend (FprintDevice *rdev,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
void *user_data);
|
|
||||||
void fprint_device_resume (FprintDevice *rdev,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
void *user_data);
|
|
||||||
|
|
||||||
void fprint_device_suspend_finish (FprintDevice *rdev,
|
|
||||||
GAsyncResult *result,
|
|
||||||
GError **error);
|
|
||||||
void fprint_device_resume_finish (FprintDevice *rdev,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
|
|
||||||
/* Print */
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
|
|
||||||
/* Some compatibility definitions for older GLib. Copied from from libfprint. */
|
|
||||||
#if !GLIB_CHECK_VERSION (2, 57, 0)
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref);
|
|
||||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
|
|
||||||
#else
|
|
||||||
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
|
|
||||||
* the version we depend on currently. */
|
|
||||||
#undef G_SOURCE_FUNC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))
|
|
||||||
224
src/main.c
@ -1,224 +0,0 @@
|
|||||||
/*
|
|
||||||
* fprint D-Bus daemon
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
#include <locale.h>
|
|
||||||
#include <poll.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gi18n.h>
|
|
||||||
#include <fprint.h>
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <glib-unix.h>
|
|
||||||
#include <gmodule.h>
|
|
||||||
|
|
||||||
#include "fprintd.h"
|
|
||||||
#include "storage.h"
|
|
||||||
#include "file_storage.h"
|
|
||||||
|
|
||||||
fp_storage store;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
load_storage_module (const char *module_name)
|
|
||||||
{
|
|
||||||
GModule *module;
|
|
||||||
g_autofree char *filename = NULL;
|
|
||||||
|
|
||||||
filename = g_module_build_path (PLUGINDIR, module_name);
|
|
||||||
module = g_module_open (filename, 0);
|
|
||||||
if (module == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
load_conf (void)
|
|
||||||
{
|
|
||||||
g_autofree char *filename = NULL;
|
|
||||||
g_autofree char *module_name = NULL;
|
|
||||||
|
|
||||||
g_autoptr(GKeyFile) file = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
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 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 }
|
|
||||||
};
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
sigterm_callback (gpointer data)
|
|
||||||
{
|
|
||||||
GMainLoop *loop = data;
|
|
||||||
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_name_acquired (GDBusConnection *connection,
|
|
||||||
const char *name,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
g_debug ("D-Bus service launched with name: %s", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
on_name_lost (GDBusConnection *connection,
|
|
||||||
const char *name,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GMainLoop *loop = user_data;
|
|
||||||
|
|
||||||
g_warning ("Failed to get name: %s", name);
|
|
||||||
|
|
||||||
g_main_loop_quit (loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
store.deinit ();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
631
src/manager.c
@ -1,631 +0,0 @@
|
|||||||
/*
|
|
||||||
* /net/reactivated/Fprint/Manager object implementation
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <glib.h>
|
|
||||||
#include <glib/gi18n.h>
|
|
||||||
#include <fprint.h>
|
|
||||||
#include <glib-object.h>
|
|
||||||
#include <gio/gunixfdlist.h>
|
|
||||||
|
|
||||||
#include "fprintd.h"
|
|
||||||
|
|
||||||
#define LOGIND_BUS_NAME "org.freedesktop.login1"
|
|
||||||
#define LOGIND_IFACE_NAME "org.freedesktop.login1.Manager"
|
|
||||||
#define LOGIND_OBJ_PATH "/org/freedesktop/login1"
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
GDBusConnection *connection;
|
|
||||||
GDBusObjectManager *object_manager;
|
|
||||||
FprintDBusManager *dbus_manager;
|
|
||||||
FpContext *context;
|
|
||||||
gboolean no_timeout;
|
|
||||||
guint timeout_id;
|
|
||||||
gint prepare_for_sleep_pending;
|
|
||||||
guint prepare_for_sleep_id;
|
|
||||||
gint sleep_inhibit_fd;
|
|
||||||
} FprintManagerPrivate;
|
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_CODE (FprintManager, fprint_manager, G_TYPE_OBJECT, G_ADD_PRIVATE (FprintManager))
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
if (priv->prepare_for_sleep_id)
|
|
||||||
g_dbus_connection_signal_unsubscribe (priv->connection,
|
|
||||||
priv->prepare_for_sleep_id);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FprintDevice *
|
|
||||||
fprint_dbus_object_skeleton_get_device (FprintDBusObjectSkeleton *object)
|
|
||||||
{
|
|
||||||
FprintDevice *rdev;
|
|
||||||
|
|
||||||
g_object_get (object, "device", &rdev, NULL);
|
|
||||||
return rdev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fprint_manager_set_property (GObject *object, guint property_id,
|
|
||||||
const GValue *value, GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
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 void
|
|
||||||
fprint_manager_get_property (GObject *object, guint property_id,
|
|
||||||
GValue *value, GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
FprintManager *self = FPRINT_MANAGER (object);
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (self);
|
|
||||||
|
|
||||||
switch (property_id)
|
|
||||||
{
|
|
||||||
case FPRINT_MANAGER_CONNECTION:
|
|
||||||
g_value_set_object (value, priv->connection);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fprint_manager_class_init (FprintManagerClass *klass)
|
|
||||||
{
|
|
||||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
||||||
|
|
||||||
object_class->constructed = fprint_manager_constructed;
|
|
||||||
object_class->set_property = fprint_manager_set_property;
|
|
||||||
object_class->get_property = fprint_manager_get_property;
|
|
||||||
object_class->finalize = fprint_manager_finalize;
|
|
||||||
|
|
||||||
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 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)
|
|
||||||
{
|
|
||||||
//FIXME kill all the devices
|
|
||||||
exit (0);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fprint_manager_busy_notified (FprintDevice *rdev, GParamSpec *spec, FprintManager *manager)
|
|
||||||
{
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
guint num_devices_busy = 0;
|
|
||||||
|
|
||||||
g_autolist (GDBusObject) devices = NULL;
|
|
||||||
GList *l;
|
|
||||||
gboolean busy;
|
|
||||||
|
|
||||||
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), "busy", &busy, NULL);
|
|
||||||
if (busy != FALSE)
|
|
||||||
num_devices_busy++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_devices_busy == 0)
|
|
||||||
priv->timeout_id = g_timeout_add_seconds (TIMEOUT, (GSourceFunc) fprint_manager_timeout_cb, manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
handle_get_devices (FprintManager *manager, GDBusMethodInvocation *invocation,
|
|
||||||
FprintDBusManager *skeleton)
|
|
||||||
{
|
|
||||||
g_autoptr(GPtrArray) devices = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fprint_manager_get_devices (manager, &devices, &error))
|
|
||||||
{
|
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprint_dbus_manager_complete_get_devices (skeleton, invocation,
|
|
||||||
(const gchar *const *)
|
|
||||||
devices->pdata);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
handle_get_default_device (FprintManager *manager,
|
|
||||||
GDBusMethodInvocation *invocation,
|
|
||||||
FprintDBusManager *skeleton)
|
|
||||||
{
|
|
||||||
const gchar *device;
|
|
||||||
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fprint_manager_get_default_device (manager, &device, &error))
|
|
||||||
{
|
|
||||||
g_dbus_method_invocation_return_gerror (invocation, error);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprint_dbus_manager_complete_get_default_device (skeleton, invocation,
|
|
||||||
device);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fprint_device_suspend_cb (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
FprintManager *manager = FPRINT_MANAGER (user_data);
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
|
|
||||||
/* Fetch the result (except for the NULL dummy call). */
|
|
||||||
if (source_object != NULL)
|
|
||||||
{
|
|
||||||
fprint_device_suspend_finish (FPRINT_DEVICE (source_object), res, &error);
|
|
||||||
if (error)
|
|
||||||
{
|
|
||||||
if (!g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_OPEN) &&
|
|
||||||
!g_error_matches (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_NOT_SUPPORTED))
|
|
||||||
g_message ("Unexpected error while suspending device: %s", error->message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->prepare_for_sleep_pending -= 1;
|
|
||||||
|
|
||||||
/* Close FD when all devices are prepared for sleeping. */
|
|
||||||
if (priv->prepare_for_sleep_pending == 0)
|
|
||||||
{
|
|
||||||
if (priv->sleep_inhibit_fd >= 0)
|
|
||||||
close (priv->sleep_inhibit_fd);
|
|
||||||
priv->sleep_inhibit_fd = -1;
|
|
||||||
g_debug ("Released delay inhibitor for sleep.");
|
|
||||||
}
|
|
||||||
|
|
||||||
g_object_unref (manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
logind_sleep_inhibit_cb (GObject *source_object,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
g_autoptr(GVariant) data = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
g_autoptr(GUnixFDList) out_fd_list = NULL;
|
|
||||||
g_autoptr(FprintManager) manager = FPRINT_MANAGER (user_data);
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
gint fd_offset;
|
|
||||||
|
|
||||||
data = g_dbus_connection_call_with_unix_fd_list_finish (priv->connection, &out_fd_list, res, &error);
|
|
||||||
|
|
||||||
if (!data)
|
|
||||||
{
|
|
||||||
g_warning ("Failed to install a sleep delay inhibitor: %s", error->message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (priv->sleep_inhibit_fd >= 0)
|
|
||||||
close (priv->sleep_inhibit_fd);
|
|
||||||
|
|
||||||
g_debug ("Got delay inhibitor for sleep.");
|
|
||||||
|
|
||||||
g_variant_get (data, "(h)", &fd_offset);
|
|
||||||
priv->sleep_inhibit_fd = g_unix_fd_list_get (out_fd_list, fd_offset, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_prepare_for_sleep_signal (GDBusConnection *connection,
|
|
||||||
const gchar *sender_name,
|
|
||||||
const gchar *object_path,
|
|
||||||
const gchar *interface_name,
|
|
||||||
const gchar *signal_name,
|
|
||||||
GVariant *parameters,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
g_autolist (GDBusObject) devices = NULL;
|
|
||||||
FprintManager *manager = FPRINT_MANAGER (user_data);
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
gboolean prepare_for_sleep;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
if (!g_variant_check_format_string (parameters, "(b)", FALSE))
|
|
||||||
{
|
|
||||||
g_warning ("Received incorrect parameter for PrepareForSleep signal");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_variant_get (parameters, "(b)", &prepare_for_sleep);
|
|
||||||
|
|
||||||
/* called one more time to handle the case of no devices */
|
|
||||||
if (prepare_for_sleep)
|
|
||||||
priv->prepare_for_sleep_pending = 1;
|
|
||||||
|
|
||||||
devices = g_dbus_object_manager_get_objects (priv->object_manager);
|
|
||||||
|
|
||||||
g_debug ("Preparing devices for %s", prepare_for_sleep ? "sleep" : "resume");
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (prepare_for_sleep)
|
|
||||||
{
|
|
||||||
priv->prepare_for_sleep_pending += 1;
|
|
||||||
g_object_ref (manager);
|
|
||||||
fprint_device_suspend (dev, fprint_device_suspend_cb, manager);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fprint_device_resume (dev, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prepare_for_sleep)
|
|
||||||
{
|
|
||||||
/* "Notify" the initial dummy device we added, handling no devices that suspending */
|
|
||||||
g_object_ref (manager);
|
|
||||||
fprint_device_suspend_cb (NULL, NULL, manager);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GVariant *arg = NULL;
|
|
||||||
|
|
||||||
arg = g_variant_new ("(ssss)",
|
|
||||||
"sleep",
|
|
||||||
"net.reactivated.Fprint",
|
|
||||||
"Suspend fingerprint readers",
|
|
||||||
"delay");
|
|
||||||
|
|
||||||
/* Grab a sleep inhibitor. */
|
|
||||||
g_dbus_connection_call_with_unix_fd_list (priv->connection,
|
|
||||||
LOGIND_BUS_NAME,
|
|
||||||
LOGIND_OBJ_PATH,
|
|
||||||
LOGIND_IFACE_NAME,
|
|
||||||
"Inhibit",
|
|
||||||
arg,
|
|
||||||
G_VARIANT_TYPE ("(h)"),
|
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
|
||||||
-1,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
logind_sleep_inhibit_cb,
|
|
||||||
g_object_ref (manager));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
device_added_cb (FprintManager *manager, FpDevice *device, FpContext *context)
|
|
||||||
{
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
|
|
||||||
g_autoptr(FprintDBusObjectSkeleton) object = NULL;
|
|
||||||
g_autoptr(FprintDevice) rdev = NULL;
|
|
||||||
g_autofree gchar *path = NULL;
|
|
||||||
|
|
||||||
rdev = fprint_device_new (device);
|
|
||||||
|
|
||||||
g_signal_connect (G_OBJECT (rdev), "notify::busy",
|
|
||||||
G_CALLBACK (fprint_manager_busy_notified), manager);
|
|
||||||
|
|
||||||
path = get_device_path (rdev);
|
|
||||||
|
|
||||||
object = fprint_dbus_object_skeleton_new (path);
|
|
||||||
fprint_dbus_object_skeleton_set_device (object,
|
|
||||||
FPRINT_DBUS_DEVICE (rdev));
|
|
||||||
g_dbus_object_manager_server_export (
|
|
||||||
G_DBUS_OBJECT_MANAGER_SERVER (priv->object_manager),
|
|
||||||
G_DBUS_OBJECT_SKELETON (object));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
device_removed_cb (FprintManager *manager, FpDevice *device, FpContext *context)
|
|
||||||
{
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
|
|
||||||
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
|
|
||||||
GList *item;
|
|
||||||
|
|
||||||
objects = g_dbus_object_manager_get_objects (priv->object_manager);
|
|
||||||
|
|
||||||
for (item = objects; item; item = item->next)
|
|
||||||
{
|
|
||||||
g_autoptr(FprintDevice) rdev = NULL;
|
|
||||||
g_autoptr(FpDevice) dev = NULL;
|
|
||||||
FprintDBusObjectSkeleton *object = item->data;
|
|
||||||
|
|
||||||
rdev = fprint_dbus_object_skeleton_get_device (object);
|
|
||||||
g_object_get (rdev, "dev", &dev, NULL);
|
|
||||||
if (dev != device)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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)));
|
|
||||||
|
|
||||||
g_signal_handlers_disconnect_by_data (rdev, manager);
|
|
||||||
|
|
||||||
/* We cannot continue to iterate at this point, but we don't need to either */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The device that disappeared might have been busy.
|
|
||||||
* Do we need to do anything else in this case to clean up more gracefully? */
|
|
||||||
fprint_manager_busy_notified (NULL, NULL, manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fprint_manager_constructed (GObject *object)
|
|
||||||
{
|
|
||||||
g_autoptr(GVariant) param_false = NULL;
|
|
||||||
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);
|
|
||||||
|
|
||||||
priv->prepare_for_sleep_id = g_dbus_connection_signal_subscribe (priv->connection,
|
|
||||||
LOGIND_BUS_NAME,
|
|
||||||
LOGIND_IFACE_NAME,
|
|
||||||
"PrepareForSleep",
|
|
||||||
LOGIND_OBJ_PATH,
|
|
||||||
NULL,
|
|
||||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
|
||||||
handle_prepare_for_sleep_signal,
|
|
||||||
manager,
|
|
||||||
NULL);
|
|
||||||
/* Fake a resume as that triggers the inhibitor to be taken. */
|
|
||||||
param_false = g_variant_new ("(b)", FALSE);
|
|
||||||
handle_prepare_for_sleep_signal (priv->connection, NULL, NULL, NULL, NULL, param_false, manager);
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (fprint_manager_parent_class)->constructed (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
fprint_manager_init (FprintManager *manager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FprintManager *
|
|
||||||
fprint_manager_new (GDBusConnection *connection, gboolean no_timeout)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
fprint_manager_get_devices (FprintManager *manager,
|
|
||||||
GPtrArray **devices, GError **error)
|
|
||||||
{
|
|
||||||
FprintManagerPrivate *priv = fprint_manager_get_instance_private (manager);
|
|
||||||
|
|
||||||
g_autolist (FprintDBusObjectSkeleton) objects = NULL;
|
|
||||||
GList *l;
|
|
||||||
int num_open;
|
|
||||||
GPtrArray *devs;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
<!DOCTYPE node PUBLIC
|
|
||||||
"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
|
||||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" [
|
|
||||||
<!ENTITY ERROR_NO_SUCH_DEVICE "net.reactivated.Fprint.Error.NoSuchDevice">
|
|
||||||
]>
|
|
||||||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
|
||||||
<interface name="net.reactivated.Fprint.Manager">
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="GetDevices">
|
|
||||||
<arg type="ao" name="devices" direction="out">
|
|
||||||
<doc:doc><doc:summary>An array of object paths for devices.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Enumerate all the fingerprint readers attached to the system. If there are
|
|
||||||
no devices available, an empty array is returned.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
<!-- ************************************************************ -->
|
|
||||||
|
|
||||||
<method name="GetDefaultDevice">
|
|
||||||
<arg type="o" name="device" direction="out">
|
|
||||||
<doc:doc><doc:summary>The object path for the default device.</doc:summary></doc:doc>
|
|
||||||
</arg>
|
|
||||||
|
|
||||||
<doc:doc>
|
|
||||||
<doc:description>
|
|
||||||
<doc:para>
|
|
||||||
Returns the default fingerprint reader device.
|
|
||||||
</doc:para>
|
|
||||||
</doc:description>
|
|
||||||
|
|
||||||
<doc:errors>
|
|
||||||
<doc:error name="&ERROR_NO_SUCH_DEVICE;">if the device does not exist</doc:error>
|
|
||||||
</doc:errors>
|
|
||||||
</doc:doc>
|
|
||||||
</method>
|
|
||||||
|
|
||||||
</interface>
|
|
||||||
</node>
|
|
||||||
|
|
||||||
@ -1,93 +0,0 @@
|
|||||||
bash = find_program('bash')
|
|
||||||
dbus_interfaces = ['Manager', 'Device']
|
|
||||||
dbus_interfaces_files = []
|
|
||||||
|
|
||||||
foreach interface_name: dbus_interfaces
|
|
||||||
interface = interface_name.to_lower()
|
|
||||||
interface_file = interface + '.xml'
|
|
||||||
dbus_interfaces_files += custom_target('dbus_interface_' + interface,
|
|
||||||
input: interface_file,
|
|
||||||
output: 'net.reactivated.Fprint.@0@.xml'.format(interface_name),
|
|
||||||
command: ['cp', '@INPUT@', '@OUTPUT@'],
|
|
||||||
install: true,
|
|
||||||
install_dir: dbus_interfaces_dir,
|
|
||||||
)
|
|
||||||
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: [
|
|
||||||
glib_dep,
|
|
||||||
gio_dep,
|
|
||||||
gio_unix_dep,
|
|
||||||
gmodule_dep,
|
|
||||||
libfprint_dep,
|
|
||||||
polkit_gobject_dep,
|
|
||||||
],
|
|
||||||
compile_args: [
|
|
||||||
'-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()),
|
|
||||||
'-DLOCALEDIR="@0@"'.format(localedir),
|
|
||||||
'-DPLUGINDIR="@0@"'.format(fprintd_plugindir),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
libfprintd_private = static_library('fprintd-private',
|
|
||||||
sources: [
|
|
||||||
'device.c',
|
|
||||||
'fprintd.h',
|
|
||||||
'manager.c',
|
|
||||||
],
|
|
||||||
dependencies: fprintd_deps,
|
|
||||||
gnu_symbol_visibility: 'hidden',
|
|
||||||
)
|
|
||||||
|
|
||||||
fprintd = executable('fprintd',
|
|
||||||
sources: [
|
|
||||||
'file_storage.c',
|
|
||||||
'file_storage.h',
|
|
||||||
'fprintd.h',
|
|
||||||
'main.c',
|
|
||||||
'storage.h',
|
|
||||||
],
|
|
||||||
dependencies: fprintd_deps,
|
|
||||||
link_with: libfprintd_private,
|
|
||||||
gnu_symbol_visibility: 'hidden',
|
|
||||||
install: true,
|
|
||||||
install_dir: fprintd_installdir,
|
|
||||||
)
|
|
||||||
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Simple file storage for fprintd
|
|
||||||
* Copyright (C) 2008 Vasily Khoruzhick <anarsoul@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
typedef int (*storage_print_data_save)(FpPrint *print);
|
|
||||||
typedef int (*storage_print_data_load)(FpDevice *dev,
|
|
||||||
FpFinger finger,
|
|
||||||
const char *username,
|
|
||||||
FpPrint **print);
|
|
||||||
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_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;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct storage fp_storage;
|
|
||||||
|
|
||||||
/* The currently setup store */
|
|
||||||
extern fp_storage store;
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
leak:initialize_device
|
|
||||||
leak:usbi_alloc_device
|
|
||||||
leak:libusb-1.0.so.*
|
|
||||||
leak:PyMem_RawMalloc
|
|
||||||
@ -1,433 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
'''fprintd mock template
|
|
||||||
|
|
||||||
This creates the expected methods and properties of the
|
|
||||||
net.reactivated.Fprint.Manager object (/net/reactivated/Fprint/Manager)
|
|
||||||
but no devices.
|
|
||||||
'''
|
|
||||||
|
|
||||||
# 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__ = 'Bastien Nocera'
|
|
||||||
__email__ = 'hadess@hadess.net'
|
|
||||||
__copyright__ = '(c) 2020 Red Hat Inc.'
|
|
||||||
__license__ = 'LGPL 3+'
|
|
||||||
|
|
||||||
import sys
|
|
||||||
from gi.repository import GLib
|
|
||||||
import dbus
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from dbusmock import MOCK_IFACE, mockobject
|
|
||||||
|
|
||||||
BUS_NAME = 'net.reactivated.Fprint'
|
|
||||||
MAIN_OBJ = '/net/reactivated/Fprint/Manager'
|
|
||||||
SYSTEM_BUS = True
|
|
||||||
IS_OBJECT_MANAGER = False
|
|
||||||
|
|
||||||
MAIN_IFACE = 'net.reactivated.Fprint.Manager'
|
|
||||||
MANAGER_MOCK_IFACE = 'net.reactivated.Fprint.Manager.Mock'
|
|
||||||
|
|
||||||
DEVICE_IFACE = 'net.reactivated.Fprint.Device'
|
|
||||||
DEVICE_MOCK_IFACE = 'net.reactivated.Fprint.Device.Mock'
|
|
||||||
|
|
||||||
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'
|
|
||||||
]
|
|
||||||
|
|
||||||
VALID_VERIFY_STATUS = [
|
|
||||||
'verify-no-match',
|
|
||||||
'verify-match',
|
|
||||||
'verify-retry-scan',
|
|
||||||
'verify-swipe-too-short',
|
|
||||||
'verify-finger-not-centered',
|
|
||||||
'verify-remove-and-retry',
|
|
||||||
'verify-disconnected',
|
|
||||||
'verify-unknown-error'
|
|
||||||
]
|
|
||||||
|
|
||||||
VALID_ENROLL_STATUS = [
|
|
||||||
'enroll-completed',
|
|
||||||
'enroll-failed',
|
|
||||||
'enroll-stage-passed',
|
|
||||||
'enroll-retry-scan',
|
|
||||||
'enroll-swipe-too-short',
|
|
||||||
'enroll-finger-not-centered',
|
|
||||||
'enroll-remove-and-retry',
|
|
||||||
'enroll-data-full',
|
|
||||||
'enroll-disconnected',
|
|
||||||
'enroll-unknown-error'
|
|
||||||
]
|
|
||||||
|
|
||||||
def load(mock, parameters):
|
|
||||||
fprintd = mockobject.objects[MAIN_OBJ]
|
|
||||||
mock.last_device_id = 0
|
|
||||||
fprintd.fingers = {}
|
|
||||||
mock.loop = asyncio.new_event_loop()
|
|
||||||
|
|
||||||
@dbus.service.method(MAIN_IFACE,
|
|
||||||
in_signature='', out_signature='ao')
|
|
||||||
def GetDevices(self):
|
|
||||||
return [(k) for k in mockobject.objects.keys() if "/Device/" in k]
|
|
||||||
|
|
||||||
@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]
|
|
||||||
|
|
||||||
@dbus.service.method(MANAGER_MOCK_IFACE,
|
|
||||||
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
|
|
||||||
stages it would use (> 0) and the scan type, as a string
|
|
||||||
(either 'press' or 'swipe')
|
|
||||||
'''
|
|
||||||
|
|
||||||
if scan_type not in ['swipe', 'press']:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Invalid scan_type \'%s\'.' % scan_type,
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
|
|
||||||
if num_enroll_stages <= 0:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Invalid num_enroll_stages \'%s\'.' % num_enroll_stages,
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
|
|
||||||
self.last_device_id += 1
|
|
||||||
path = '/net/reactivated/Fprint/Device/%d' % self.last_device_id
|
|
||||||
device_properties = {
|
|
||||||
'name': dbus.String(device_name, variant_level=1),
|
|
||||||
'num-enroll-stages': dbus.Int32(num_enroll_stages, variant_level=1),
|
|
||||||
'scan-type': scan_type
|
|
||||||
}
|
|
||||||
|
|
||||||
self.AddObject(path,
|
|
||||||
DEVICE_IFACE,
|
|
||||||
# Properties
|
|
||||||
device_properties,
|
|
||||||
[])
|
|
||||||
|
|
||||||
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):
|
|
||||||
if user in device.fingers:
|
|
||||||
return device.fingers[user]
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'No enrolled prints in device %s for user %s' % (device.path, user),
|
|
||||||
name='net.reactivated.Fprint.Error.NoEnrolledPrints')
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_IFACE,
|
|
||||||
in_signature='s', out_signature='')
|
|
||||||
def DeleteEnrolledFingers(device, user):
|
|
||||||
device.fingers[user] = []
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_IFACE,
|
|
||||||
in_signature='', out_signature='')
|
|
||||||
def DeleteEnrolledFingers2(device):
|
|
||||||
if not device.claimed_user:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Device was not claimed before use',
|
|
||||||
name='net.reactivated.Fprint.Error.ClaimDevice')
|
|
||||||
if not device.fingers[device.claimed_user]:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'No enrolled prints in device {} for user {}'.format(device.path,
|
|
||||||
device.claimed_user),
|
|
||||||
name='net.reactivated.Fprint.Error.NoEnrolledPrints')
|
|
||||||
device.fingers[device.claimed_user] = []
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_IFACE,
|
|
||||||
in_signature='s', out_signature='')
|
|
||||||
def Claim(device, user):
|
|
||||||
if device.claimed_user:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Device already in use by %s' % device.claimed_user,
|
|
||||||
name='net.reactivated.Fprint.Error.AlreadyInUse')
|
|
||||||
|
|
||||||
device.claimed_user = user
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_IFACE,
|
|
||||||
in_signature='', out_signature='')
|
|
||||||
def Release(device):
|
|
||||||
if not device.claimed_user:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'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
|
|
||||||
if finger_name == 'any':
|
|
||||||
return True
|
|
||||||
if finger_name in device.fingers[device.claimed_user]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
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='')
|
|
||||||
def VerifyStart(device, finger_name):
|
|
||||||
if not device.claimed_user:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Device was not claimed before use',
|
|
||||||
name='net.reactivated.Fprint.Error.ClaimDevice')
|
|
||||||
if device.claimed_user not in device.fingers:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'No enrolled prints for user \'%s\'' % device.claimed_user,
|
|
||||||
name='net.reactivated.Fprint.Error.NoEnrolledPrints')
|
|
||||||
if not finger_name:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Invalid empty finger_name.',
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
if not can_verify_finger(device, finger_name):
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Finger \'%s\' not enrolled.' % finger_name,
|
|
||||||
name='org.freedesktop.DBus.Error.Internal')
|
|
||||||
if device.action:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Action \'%s\' already in progress' % device.action,
|
|
||||||
name='net.reactivated.Fprint.Error.AlreadyInUse')
|
|
||||||
device.action = 'verify'
|
|
||||||
|
|
||||||
if finger_name == 'any' and not device.has_identification:
|
|
||||||
finger_name = device.fingers[device.claimed_user][0]
|
|
||||||
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='')
|
|
||||||
def EmitVerifyStatus(device, result, done):
|
|
||||||
if (not device.action) or (device.action != 'verify'):
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Cannot send verify statuses when not verifying',
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
if result not in VALID_VERIFY_STATUS:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Unknown verify status \'%s\'' % result,
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
device.EmitSignal(DEVICE_IFACE, 'VerifyStatus', 'sb', [
|
|
||||||
result,
|
|
||||||
done
|
|
||||||
])
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_IFACE,
|
|
||||||
in_signature='', out_signature='')
|
|
||||||
def VerifyStop(device):
|
|
||||||
if device.action != 'verify':
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'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='')
|
|
||||||
def EnrollStart(device, finger_name):
|
|
||||||
if finger_name not in VALID_FINGER_NAMES:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Invalid finger name \'%s\'' % finger_name,
|
|
||||||
name='net.reactivated.Fprint.Error.InvalidFingername')
|
|
||||||
if not device.claimed_user:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Device was not claimed before use',
|
|
||||||
name='net.reactivated.Fprint.Error.ClaimDevice')
|
|
||||||
if device.action:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Action \'%s\' already in progress' % device.action,
|
|
||||||
name='net.reactivated.Fprint.Error.AlreadyInUse')
|
|
||||||
device.action = 'enroll'
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_MOCK_IFACE,
|
|
||||||
in_signature='sb', out_signature='')
|
|
||||||
def EmitEnrollStatus(device, result, done):
|
|
||||||
if (not device.action) or (device.action != 'enroll'):
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Cannot send enroll statuses when not enrolling',
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
if result not in VALID_ENROLL_STATUS:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Unknown enroll status \'%s\'' % result,
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
device.EmitSignal(DEVICE_IFACE, 'EnrollStatus', 'sb', [
|
|
||||||
result,
|
|
||||||
done
|
|
||||||
])
|
|
||||||
# FIXME save enrolled finger?
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_IFACE,
|
|
||||||
in_signature='', out_signature='')
|
|
||||||
def EnrollStop(device):
|
|
||||||
if device.action != 'enroll':
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'No enrollment to stop',
|
|
||||||
name='net.reactivated.Fprint.Error.NoActionInProgress')
|
|
||||||
device.action = None
|
|
||||||
|
|
||||||
@dbus.service.method(DEVICE_MOCK_IFACE,
|
|
||||||
in_signature='sas', out_signature='')
|
|
||||||
def SetEnrolledFingers(device, user, fingers):
|
|
||||||
'''Convenience method to set the list of enrolled fingers.
|
|
||||||
|
|
||||||
The device_path is the return value from AddDevice(), and the
|
|
||||||
array of fingers must only contain valid finger names.
|
|
||||||
|
|
||||||
Returns nothing.
|
|
||||||
'''
|
|
||||||
|
|
||||||
for k in fingers:
|
|
||||||
if k not in VALID_FINGER_NAMES:
|
|
||||||
raise dbus.exceptions.DBusException(
|
|
||||||
'Invalid finger name \'%s\'' % k,
|
|
||||||
name='org.freedesktop.DBus.Error.InvalidArgs')
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
After VerifyStart is called, signal results will be sent in order after
|
|
||||||
a certain timeout declared in seconds. The array contains each
|
|
||||||
'result' followed by the 'done' argument for VerifyStatus, and the
|
|
||||||
amount of time to wait before each signal is sent.
|
|
||||||
|
|
||||||
Returns nothing.
|
|
||||||
'''
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -1,101 +0,0 @@
|
|||||||
# -*- 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
|
|
||||||
|
|
||||||
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):
|
|
||||||
mock.allow_unknown = False
|
|
||||||
mock.allowed = []
|
|
||||||
mock.delay = 0
|
|
||||||
mock.simulate_hang = False
|
|
||||||
mock.hanging_actions = []
|
|
||||||
mock.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
|
|
||||||
3440
tests/fprintd.py
@ -1,126 +0,0 @@
|
|||||||
# 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
|
|
||||||
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: test_envs,
|
|
||||||
timeout_multiplier: timeout_multiplier
|
|
||||||
)
|
|
||||||
|
|
||||||
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',
|
|
||||||
env: [
|
|
||||||
'G_SLICE=always-malloc',
|
|
||||||
'VALGRIND=' + glib_suppressions,
|
|
||||||
],
|
|
||||||
timeout_multiplier: 5
|
|
||||||
)
|
|
||||||
endif
|
|
||||||
|
|
||||||
@ -1,199 +0,0 @@
|
|||||||
#! /usr/bin/env python3
|
|
||||||
# Copyright © 2020, RedHat Inc.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
# Authors:
|
|
||||||
# Benjamin Berg <bberg@redhat.com>
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import fcntl
|
|
||||||
import io
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
import threading
|
|
||||||
import select
|
|
||||||
import errno
|
|
||||||
|
|
||||||
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 | os.O_NONBLOCK)
|
|
||||||
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, daemon=True)
|
|
||||||
self._thread.start()
|
|
||||||
|
|
||||||
def _copy(self):
|
|
||||||
p = select.poll()
|
|
||||||
p.register(self._pipe_fd_r)
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
# Be lazy and wake up occasionally in case _pipe_fd_r became invalid
|
|
||||||
# The reason to do this is because os.read() will *not* return if the
|
|
||||||
# FD is forcefully closed.
|
|
||||||
p.poll(0.1)
|
|
||||||
|
|
||||||
r = os.read(self._pipe_fd_r, 1024)
|
|
||||||
if not r:
|
|
||||||
os.close(self._pipe_fd_r)
|
|
||||||
self._pipe_fd_r = -1
|
|
||||||
self._lines_sem.release()
|
|
||||||
return
|
|
||||||
except OSError as e:
|
|
||||||
if e.errno == errno.EWOULDBLOCK:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# We get a bad file descriptor error when the outside closes the FD
|
|
||||||
if self._pipe_fd_r >= 0:
|
|
||||||
os.close(self._pipe_fd_r)
|
|
||||||
self._pipe_fd_r = -1
|
|
||||||
self._lines_sem.release()
|
|
||||||
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:
|
|
||||||
# EOF, throw error
|
|
||||||
if self._pipe_fd_r == -1:
|
|
||||||
if failmsg:
|
|
||||||
raise AssertionError("No further messages: " % failmsg)
|
|
||||||
else:
|
|
||||||
raise AssertionError('No client waiting for needle %s' % (str(needle_re)))
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
# EOF, so everything good
|
|
||||||
if self._pipe_fd_r == -1:
|
|
||||||
break
|
|
||||||
|
|
||||||
# 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), wait))
|
|
||||||
|
|
||||||
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!")
|
|
||||||
|
|
||||||
def force_close(self):
|
|
||||||
|
|
||||||
fd = self._pipe_fd_r
|
|
||||||
self._pipe_fd_r = -1
|
|
||||||
if fd >= 0:
|
|
||||||
os.close(fd)
|
|
||||||
|
|
||||||
self._thread.join()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def fd(self):
|
|
||||||
return self._pipe_fd_w
|
|
||||||
|
|
||||||
def writer_attached(self):
|
|
||||||
os.close(self._pipe_fd_w)
|
|
||||||
self._pipe_fd_w = -1
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if self._pipe_fd_r >= 0:
|
|
||||||
os.close(self._pipe_fd_r)
|
|
||||||
self._pipe_fd_r = -1
|
|
||||||
if self._pipe_fd_w >= 0:
|
|
||||||
os.close(self._pipe_fd_w)
|
|
||||||
self._pipe_fd_w = -1
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
subdir('services')
|
|
||||||
|
|
||||||
tests = [
|
|
||||||
'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
|
|
||||||
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
|
|
||||||
@ -1 +0,0 @@
|
|||||||
auth required @FPRINTDPAMPATH@ debug timeout=10
|
|
||||||
@ -1,13 +0,0 @@
|
|||||||
# Meson doesn't allow to have configure_file's as targets we depend on... Meh!
|
|
||||||
pam_service_file = custom_target('pam_test_service_file',
|
|
||||||
output: 'null',
|
|
||||||
command: 'true',
|
|
||||||
depends: pam_fprintd,
|
|
||||||
depend_files: configure_file(
|
|
||||||
input: 'fprintd-pam-test.in',
|
|
||||||
output: 'fprintd-pam-test',
|
|
||||||
configuration: configuration_data({
|
|
||||||
'FPRINTDPAMPATH': pam_fprintd.full_path(),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
@ -1,351 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
# 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__ = 'Bastien Nocera'
|
|
||||||
__email__ = 'hadess@hadess.net'
|
|
||||||
__copyright__ = '(c) 2020 Red Hat Inc.'
|
|
||||||
__license__ = 'LGPL 3+'
|
|
||||||
|
|
||||||
import tempfile
|
|
||||||
import unittest
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import dbus
|
|
||||||
import dbusmock
|
|
||||||
import glob
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
import time
|
|
||||||
import pypamtest
|
|
||||||
|
|
||||||
PAM_SUCCESS = 0
|
|
||||||
PAM_AUTH_ERR = 7
|
|
||||||
PAM_AUTHINFO_UNAVAIL = 9
|
|
||||||
PAM_USER_UNKNOWN = 10
|
|
||||||
PAM_MAXTRIES = 11
|
|
||||||
|
|
||||||
class TestPamFprintd(dbusmock.DBusTestCase):
|
|
||||||
'''Test pam_fprintd'''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def start_monitor(klass):
|
|
||||||
'''Start dbus-monitor'''
|
|
||||||
|
|
||||||
workdir = os.environ['TOPBUILDDIR'] + '/tests/pam/'
|
|
||||||
klass.monitor_log = open(os.path.join(workdir, 'dbus-monitor.log'), 'wb', buffering=0)
|
|
||||||
klass.monitor = subprocess.Popen(['dbus-monitor', '--monitor', '--system'],
|
|
||||||
stdout=klass.monitor_log,
|
|
||||||
stderr=subprocess.STDOUT)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def stop_monitor(klass):
|
|
||||||
'''Stop dbus-monitor'''
|
|
||||||
|
|
||||||
assert klass.monitor
|
|
||||||
klass.monitor.terminate()
|
|
||||||
klass.monitor.wait()
|
|
||||||
|
|
||||||
klass.monitor_log.flush()
|
|
||||||
klass.monitor_log.close()
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(klass):
|
|
||||||
klass.start_system_bus()
|
|
||||||
klass.start_monitor()
|
|
||||||
klass.dbus_con = klass.get_dbus(True)
|
|
||||||
|
|
||||||
template_path = './'
|
|
||||||
if 'TOPSRCDIR' in os.environ:
|
|
||||||
template_path = os.environ['TOPSRCDIR'] + '/tests/'
|
|
||||||
klass.template_name = template_path + 'dbusmock/fprintd.py'
|
|
||||||
print ('Using template from %s' % klass.template_name)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
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, {})
|
|
||||||
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()
|
|
||||||
|
|
||||||
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'])
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
( 'verify-match', True, 2 )
|
|
||||||
]
|
|
||||||
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.assertEqual(len(res.errors), 0)
|
|
||||||
|
|
||||||
# Check that we can stop verification and release the device. i.e.
|
|
||||||
# this has not been done by PAM already (the real fprintd would notice
|
|
||||||
# the disconnect, the mock service does not).
|
|
||||||
self.device_mock.VerifyStop()
|
|
||||||
self.device_mock.Release()
|
|
||||||
|
|
||||||
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_AUTHINFO_UNAVAIL)
|
|
||||||
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')
|
|
||||||
|
|
||||||
# Check that we can cannot stop verification or release the device. i.e.
|
|
||||||
# PAM should have correctly done this after verification was done.
|
|
||||||
with self.assertRaisesRegex(dbus.exceptions.DBusException, r'net\.reactivated\.Fprint\.Error\.NoActionInProgress'):
|
|
||||||
self.device_mock.VerifyStop()
|
|
||||||
with self.assertRaisesRegex(dbus.exceptions.DBusException, r'net\.reactivated\.Fprint\.Error\.ClaimDevice'):
|
|
||||||
self.device_mock.Release()
|
|
||||||
|
|
||||||
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)
|
|
||||||
sandpaper_device_mock.SetEnrolledFingers('toto', ['left-middle-finger', 'right-middle-finger'])
|
|
||||||
script = [
|
|
||||||
( 'verify-match', True, 2 )
|
|
||||||
]
|
|
||||||
sandpaper_device_mock.SetVerifyScript(script)
|
|
||||||
|
|
||||||
# Add a 2nd device
|
|
||||||
self.setup_device()
|
|
||||||
|
|
||||||
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 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 = [
|
|
||||||
( 'verify-no-match', True, 1 ),
|
|
||||||
( 'verify-no-match', True, 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.assertEqual(len(res.errors), 2)
|
|
||||||
self.assertRegex(res.errors[0], r'Failed to match fingerprint')
|
|
||||||
self.assertRegex(res.errors[1], r'Failed to match fingerprint')
|
|
||||||
|
|
||||||
def test_pam_fprintd_failed_auth(self):
|
|
||||||
self.setup_device()
|
|
||||||
script = [
|
|
||||||
( '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[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()
|
|
||||||
|
|
||||||
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[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')
|
|
||||||
sys.exit(1)
|
|
||||||
# set stream to sys.stderr to get debug output
|
|
||||||
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
These are example images from NIST and are in the public domain.
|
|
||||||
|
|
||||||
The PNG files have been generated by using the greyscale data as a mask.
|
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 107 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 102 KiB |
@ -1,296 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
|
|
||||||
# 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__ = 'Bastien Nocera'
|
|
||||||
__email__ = 'hadess@hadess.net'
|
|
||||||
__copyright__ = '(c) 2020 Red Hat Inc.'
|
|
||||||
__license__ = 'LGPL 3+'
|
|
||||||
|
|
||||||
import tempfile
|
|
||||||
import unittest
|
|
||||||
import sys
|
|
||||||
import subprocess
|
|
||||||
import dbus
|
|
||||||
import dbus.mainloop.glib
|
|
||||||
import dbusmock
|
|
||||||
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 TestFprintdUtilsBase(dbusmock.DBusTestCase):
|
|
||||||
'''Test fprintd utilities'''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setUpClass(klass):
|
|
||||||
klass.start_system_bus()
|
|
||||||
klass.dbus_con = klass.get_dbus(True)
|
|
||||||
klass.sleep_time = 0.5
|
|
||||||
|
|
||||||
template_path = './'
|
|
||||||
if 'TOPSRCDIR' in os.environ:
|
|
||||||
template_path = os.environ['TOPSRCDIR'] + '/tests/'
|
|
||||||
klass.template_name = template_path + 'dbusmock/fprintd.py'
|
|
||||||
print ('Using template from %s' % klass.template_name)
|
|
||||||
|
|
||||||
klass.tools_prefix = ''
|
|
||||||
if 'FPRINT_BUILD_DIR' in os.environ:
|
|
||||||
klass.tools_prefix = os.environ['FPRINT_BUILD_DIR'] + '/../utils/'
|
|
||||||
print ('Using tools from %s' % klass.tools_prefix)
|
|
||||||
else:
|
|
||||||
print ('Using tools from $PATH')
|
|
||||||
|
|
||||||
klass.wrapper_args = []
|
|
||||||
klass.valgrind = False
|
|
||||||
if 'VALGRIND' in os.environ:
|
|
||||||
valgrind = os.environ['VALGRIND']
|
|
||||||
if valgrind is not None:
|
|
||||||
klass.valgrind = True
|
|
||||||
klass.sleep_time *= 4
|
|
||||||
klass.wrapper_args = ['valgrind', '--leak-check=full']
|
|
||||||
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, {})
|
|
||||||
# set log to nonblocking
|
|
||||||
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):
|
|
||||||
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)
|
|
||||||
|
|
||||||
return b''.join(output.clear()), ret
|
|
||||||
|
|
||||||
|
|
||||||
class TestFprintdUtils(TestFprintdUtilsBase):
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
self.setup_device()
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
out.check_line(rb'Enroll result: enroll-completed', self.sleep_time)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# Toto does
|
|
||||||
out, ret = self.run_utility_process('list', ['toto'])
|
|
||||||
self.assertRegex(out, rb'right-little-finger')
|
|
||||||
self.assertEqual(ret, 0)
|
|
||||||
|
|
||||||
def test_fprintd_delete(self):
|
|
||||||
# Delete fingerprints
|
|
||||||
out, ret = self.run_utility_process('delete', ['toto'])
|
|
||||||
self.assertRegex(out, rb'Fingerprints of user toto deleted')
|
|
||||||
self.assertEqual(ret, 0)
|
|
||||||
|
|
||||||
# Doesn't have fingerprints
|
|
||||||
out, ret = self.run_utility_process('delete', ['toto'])
|
|
||||||
self.assertRegex(out, rb'No fingerprints to delete on')
|
|
||||||
self.assertEqual(ret, 0)
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
def test_fprintd_verify_any_finger_no_identification(self):
|
|
||||||
self.start_verify_process(finger='any')
|
|
||||||
|
|
||||||
self.device_mock.EmitVerifyStatus('verify-match', True)
|
|
||||||
time.sleep(self.sleep_time)
|
|
||||||
self.assertVerifyMatch(True)
|
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
self.device_mock.EmitVerifyStatus('verify-match', True)
|
|
||||||
time.sleep(self.sleep_time)
|
|
||||||
self.assertVerifyMatch(True)
|
|
||||||
|
|
||||||
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_verify_script(self):
|
|
||||||
script = [
|
|
||||||
( 'verify-match', True, 2 )
|
|
||||||
]
|
|
||||||
self.device_mock.SetVerifyScript(script)
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
self.start_verify_process()
|
|
||||||
time.sleep(2 + self.sleep_time)
|
|
||||||
self.assertVerifyMatch(True)
|
|
||||||
|
|
||||||
def test_fprintd_multiple_verify_fails(self):
|
|
||||||
self.start_verify_process()
|
|
||||||
|
|
||||||
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
|
|
||||||
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
#! /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 <http://www.gnu.org/licenses/>.
|
|
||||||
# Authors:
|
|
||||||
# Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
|
|
||||||
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)
|
|
||||||
250
utils/delete.c
@ -1,250 +0,0 @@
|
|||||||
/*
|
|
||||||
* fprintd example to delete fingerprints
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include "fprintd-dbus.h"
|
|
||||||
|
|
||||||
static FprintDBusManager *manager = NULL;
|
|
||||||
static GDBusConnection *connection = NULL;
|
|
||||||
|
|
||||||
static void
|
|
||||||
create_manager (void)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
||||||
if (connection == NULL)
|
|
||||||
{
|
|
||||||
g_print ("Failed to connect to session bus: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 gboolean
|
|
||||||
delete_user_prints (FprintDBusDevice *dev,
|
|
||||||
const char *fingername,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
if (fingername)
|
|
||||||
return fprint_dbus_device_call_delete_enrolled_finger_sync (dev, fingername,
|
|
||||||
NULL, error);
|
|
||||||
else
|
|
||||||
return fprint_dbus_device_call_delete_enrolled_fingers2_sync (dev, NULL,
|
|
||||||
error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
delete_fingerprints (FprintDBusDevice *dev,
|
|
||||||
const char *username,
|
|
||||||
const char *fingername)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
if (!fprint_dbus_device_call_claim_sync (dev, username, NULL, &error))
|
|
||||||
{
|
|
||||||
g_print ("failed to claim device: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!delete_user_prints (dev, fingername, &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 ("Failed to delete fingerprints: %s\n",
|
|
||||||
error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_print ("No fingerprints to delete on %s\n",
|
|
||||||
fprint_dbus_device_get_name (dev));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (fingername)
|
|
||||||
g_print ("Fingerprint %s of user %s deleted on %s\n",
|
|
||||||
fingername, username,
|
|
||||||
fprint_dbus_device_get_name (dev));
|
|
||||||
else
|
|
||||||
g_print ("Fingerprints of user %s deleted on %s\n", username,
|
|
||||||
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 (guint argc, char **argv)
|
|
||||||
{
|
|
||||||
g_autoptr(GOptionContext) option_context = NULL;
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
g_auto(GStrv) devices = NULL;
|
|
||||||
char *fingername = 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const GOptionEntry user_options[] = {
|
|
||||||
{ "finger", 'f', 0, G_OPTION_ARG_STRING, &fingername, "Finger selected to verify (default is automatic)", NULL },
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
option_context = g_option_context_new (NULL);
|
|
||||||
g_option_context_add_main_entries (option_context, user_options, NULL);
|
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
|
||||||
const char *username = argv[j];
|
|
||||||
fingername = NULL;
|
|
||||||
|
|
||||||
if (argc > j + 1 && argv[j + 1][0] == '-')
|
|
||||||
{
|
|
||||||
g_autoptr(GError) local_error = NULL;
|
|
||||||
g_autoptr(GPtrArray) user_args = NULL;
|
|
||||||
|
|
||||||
user_args = g_ptr_array_new_full (3, NULL);
|
|
||||||
g_ptr_array_add (user_args, argv[j]);
|
|
||||||
g_ptr_array_add (user_args, argv[j + 1]);
|
|
||||||
|
|
||||||
if (argc > j + 2)
|
|
||||||
g_ptr_array_add (user_args, argv[j + 2]);
|
|
||||||
|
|
||||||
int new_argc = user_args->len;
|
|
||||||
char **new_argv = (char **) user_args->pdata;
|
|
||||||
|
|
||||||
if (!g_option_context_parse (option_context, &new_argc,
|
|
||||||
&new_argv, &local_error))
|
|
||||||
{
|
|
||||||
g_print ("couldn't parse command-line options: %s\n",
|
|
||||||
local_error->message);
|
|
||||||
j += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
j += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_fingerprints (dev, username, fingername);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
g_autoptr(GOptionContext) option_context = NULL;
|
|
||||||
g_autoptr(GError) local_error = NULL;
|
|
||||||
|
|
||||||
option_context = g_option_context_new ("Delete fingerprints");
|
|
||||||
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
|
|
||||||
g_option_context_set_ignore_unknown_options (option_context, TRUE);
|
|
||||||
g_option_context_set_summary (option_context,
|
|
||||||
"<username> [-f finger-name [usernames [-f finger-name ]...]");
|
|
||||||
|
|
||||||
if (!g_option_context_parse (option_context, &argc, &argv, &local_error))
|
|
||||||
{
|
|
||||||
g_print ("couldn't parse command-line options: %s\n", local_error->message);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
g_autofree char *usage = NULL;
|
|
||||||
|
|
||||||
usage = g_option_context_get_help (option_context, FALSE, NULL);
|
|
||||||
g_print ("%s", usage);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
create_manager ();
|
|
||||||
process_devices (argc, argv);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
239
utils/enroll.c
@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
* fprintd example to enroll right index finger
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include "fprintd-dbus.h"
|
|
||||||
|
|
||||||
#define N_(x) x
|
|
||||||
#define TR(x) x
|
|
||||||
#include "fingerprint-strings.h"
|
|
||||||
|
|
||||||
static FprintDBusManager *manager = NULL;
|
|
||||||
static GDBusConnection *connection = NULL;
|
|
||||||
static char *finger_name = NULL;
|
|
||||||
static char **usernames = NULL;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
ENROLL_INCOMPLETE,
|
|
||||||
ENROLL_COMPLETED,
|
|
||||||
ENROLL_FAILED,
|
|
||||||
} FprintEnrollStatus;
|
|
||||||
|
|
||||||
static void
|
|
||||||
create_manager (void)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
||||||
if (connection == NULL)
|
|
||||||
{
|
|
||||||
g_print ("Failed to connect to session bus: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
FprintEnrollStatus *enroll_status = user_data;
|
|
||||||
|
|
||||||
g_print ("Enroll result: %s\n", result);
|
|
||||||
if (done != FALSE)
|
|
||||||
{
|
|
||||||
if (g_str_equal (result, "enroll-completed"))
|
|
||||||
*enroll_status = ENROLL_COMPLETED;
|
|
||||||
else
|
|
||||||
*enroll_status = ENROLL_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 FprintEnrollStatus
|
|
||||||
do_enroll (FprintDBusDevice *dev)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
FprintEnrollStatus enroll_status = ENROLL_INCOMPLETE;
|
|
||||||
gboolean found;
|
|
||||||
guint i;
|
|
||||||
|
|
||||||
g_signal_connect (dev, "g-signal", G_CALLBACK (proxy_signal_cb),
|
|
||||||
&enroll_status);
|
|
||||||
|
|
||||||
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_status == ENROLL_INCOMPLETE)
|
|
||||||
g_main_context_iteration (NULL, TRUE);
|
|
||||||
|
|
||||||
g_signal_handlers_disconnect_by_func (dev, proxy_signal_cb, &enroll_status);
|
|
||||||
|
|
||||||
if (!fprint_dbus_device_call_enroll_stop_sync (dev, NULL, &error))
|
|
||||||
{
|
|
||||||
g_print ("EnrollStop failed: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return enroll_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 }
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
|
||||||
main (int argc, char **argv)
|
|
||||||
{
|
|
||||||
g_autoptr(FprintDBusDevice) dev = NULL;
|
|
||||||
GOptionContext *context;
|
|
||||||
FprintEnrollStatus status;
|
|
||||||
|
|
||||||
g_autoptr(GError) err = NULL;
|
|
||||||
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
|
|
||||||
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);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (finger_name == NULL)
|
|
||||||
finger_name = g_strdup ("right-index-finger");
|
|
||||||
|
|
||||||
create_manager ();
|
|
||||||
|
|
||||||
dev = open_device (usernames ? usernames[0] : "");
|
|
||||||
status = do_enroll (dev);
|
|
||||||
release_device (dev);
|
|
||||||
g_free (finger_name);
|
|
||||||
g_strfreev (usernames);
|
|
||||||
return status == ENROLL_COMPLETED ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
162
utils/list.c
@ -1,162 +0,0 @@
|
|||||||
/*
|
|
||||||
* fprintd example to list enrolled fingerprints
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include "fprintd-dbus.h"
|
|
||||||
|
|
||||||
static FprintDBusManager *manager = NULL;
|
|
||||||
static GDBusConnection *connection = NULL;
|
|
||||||
|
|
||||||
static void
|
|
||||||
create_manager (void)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
||||||
if (connection == NULL)
|
|
||||||
{
|
|
||||||
g_print ("Failed to connect to session bus: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
manager = fprint_dbus_manager_proxy_new_sync (connection,
|
|
||||||
G_DBUS_PROXY_FLAGS_NONE,
|
|
||||||
"net.reactivated.Fprint",
|
|
||||||
"/net/reactivated/Fprint/Manager",
|
|
||||||
NULL, &error);
|
|
||||||
if (manager == NULL)
|
|
||||||
{
|
|
||||||
g_print ("Failed to get Fprintd manager: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
list_fingerprints (FprintDBusDevice *dev, const char *username)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
|
|
||||||
for (i = 0; fingers[i] != NULL; i++)
|
|
||||||
g_print (" - #%d: %s\n", i, fingers[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
process_devices (char **argv)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
setlocale (LC_ALL, "");
|
|
||||||
|
|
||||||
create_manager ();
|
|
||||||
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
g_print ("Usage: %s <username> [usernames...]\n", argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
process_devices (argv);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
libfprintd_utils_dep = declare_dependency(
|
|
||||||
include_directories: [
|
|
||||||
include_directories('../src'),
|
|
||||||
include_directories('../pam'),
|
|
||||||
],
|
|
||||||
dependencies: [
|
|
||||||
glib_dep,
|
|
||||||
gio_dep,
|
|
||||||
gio_unix_dep,
|
|
||||||
],
|
|
||||||
sources: [
|
|
||||||
fprintd_dbus_sources,
|
|
||||||
],
|
|
||||||
link_with: [
|
|
||||||
libfprintd_private
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
utils = [
|
|
||||||
'delete',
|
|
||||||
'enroll',
|
|
||||||
'list',
|
|
||||||
'verify',
|
|
||||||
]
|
|
||||||
|
|
||||||
fprintd_utils = []
|
|
||||||
|
|
||||||
foreach util: utils
|
|
||||||
fprintd_utils += executable('fprintd-' + util,
|
|
||||||
sources: util + '.c',
|
|
||||||
dependencies: libfprintd_utils_dep,
|
|
||||||
install: true,
|
|
||||||
)
|
|
||||||
endforeach
|
|
||||||
312
utils/verify.c
@ -1,312 +0,0 @@
|
|||||||
/*
|
|
||||||
* fprintd example to verify a fingerprint
|
|
||||||
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
|
|
||||||
* Copyright (C) 2020 Marco Trevisan <marco.trevisan@canonical.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <locale.h>
|
|
||||||
#include <gio/gio.h>
|
|
||||||
#include "fprintd-dbus.h"
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
|
|
||||||
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
||||||
if (connection == NULL)
|
|
||||||
{
|
|
||||||
g_print ("Failed to connect to session bus: %s\n", error->message);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return g_steal_pointer (&dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
find_finger (FprintDBusDevice *dev, const char *username)
|
|
||||||
{
|
|
||||||
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 (finger_name == NULL)
|
|
||||||
finger_name = g_strdup (fingers[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VerifyState
|
|
||||||
{
|
|
||||||
GError *error;
|
|
||||||
gboolean started;
|
|
||||||
gboolean completed;
|
|
||||||
gboolean match;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
verify_result (GObject *object, const char *result, gboolean done, void *user_data)
|
|
||||||
{
|
|
||||||
struct VerifyState *verify_state = user_data;
|
|
||||||
|
|
||||||
g_print ("Verify result: %s (%s)\n", result, done ? "done" : "not done");
|
|
||||||
verify_state->match = g_str_equal (result, "verify-match");
|
|
||||||
|
|
||||||
if (done != FALSE)
|
|
||||||
verify_state->completed = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
verify_finger_selected (GObject *object, const char *name, void *user_data)
|
|
||||||
{
|
|
||||||
g_print ("Verifying: %s\n", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
verify_started_cb (GObject *obj,
|
|
||||||
GAsyncResult *res,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
struct VerifyState *verify_state = user_data;
|
|
||||||
|
|
||||||
if (fprint_dbus_device_call_verify_start_finish (FPRINT_DBUS_DEVICE (obj), res, &verify_state->error))
|
|
||||||
{
|
|
||||||
g_print ("Verify started!\n");
|
|
||||||
verify_state->started = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
proxy_signal_cb (GDBusProxy *proxy,
|
|
||||||
const gchar *sender_name,
|
|
||||||
const gchar *signal_name,
|
|
||||||
GVariant *parameters,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
struct VerifyState *verify_state = user_data;
|
|
||||||
|
|
||||||
if (!verify_state->started)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
do_verify (FprintDBusDevice *dev)
|
|
||||||
{
|
|
||||||
g_autoptr(GError) error = NULL;
|
|
||||||
struct VerifyState verify_state = { 0 };
|
|
||||||
|
|
||||||
/* This one is funny. We connect to the signal immediately to avoid
|
|
||||||
* race conditions. However, we must ignore any authentication results
|
|
||||||
* that happen before our start call returns.
|
|
||||||
* This is because the verify call itself may internally try to verify
|
|
||||||
* against fprintd (possibly using a separate account).
|
|
||||||
*
|
|
||||||
* To do so, we *must* use the async version of the verify call, as the
|
|
||||||
* sync version would cause the signals to be queued and only processed
|
|
||||||
* after it returns.
|
|
||||||
*/
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return verify_state.match;
|
|
||||||
}
|
|
||||||
|
|
||||||
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-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)
|
|
||||||
{
|
|
||||||
g_autoptr(FprintDBusDevice) dev = NULL;
|
|
||||||
g_autoptr(GError) err = NULL;
|
|
||||||
GOptionContext *context;
|
|
||||||
const char *username = NULL;
|
|
||||||
gboolean match;
|
|
||||||
|
|
||||||
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);
|
|
||||||
match = do_verify (dev);
|
|
||||||
release_device (dev);
|
|
||||||
return match ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
||||||
}
|
|
||||||