clean unneeded files

This commit is contained in:
Misha
2021-12-09 23:22:07 -05:00
parent 6870e3c370
commit 2f22fab80a
59 changed files with 0 additions and 13144 deletions

View File

@ -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
View File

@ -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
View File

@ -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

View File

@ -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/

View File

@ -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"

View File

@ -1,2 +0,0 @@
[storage]
type=file

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -1,5 +0,0 @@
[D-BUS Service]
Name=net.reactivated.Fprint
Exec=@LIBEXECDIR@/fprintd
User=root
SystemdService=fprintd.service

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -1 +0,0 @@
@VERSION@

View File

@ -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

View File

@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -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;
}

View File

@ -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);

View File

@ -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))

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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>

View File

@ -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,
)

View File

@ -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;

View File

@ -1,4 +0,0 @@
leak:initialize_device
leak:usbi_alloc_device
leak:libusb-1.0.so.*
leak:PyMem_RawMalloc

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
auth required @FPRINTDPAMPATH@ debug timeout=10

View File

@ -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(),
}),
),
)

View File

@ -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))

View File

@ -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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

View File

@ -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))

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}