Table of Contents
For developers who want to understand and possible change something in the Fingerprint GUI project it might be required to give some hints about how the system works. It is assumed the reader of this document has a certain understanding of PAM.
There are 6 executables and one library used:
“fingerprint-gui”
The main application to be used for discovering fingerprint scanners on the USB bus, acquiring (enrollment) and verification of fingerprints and testing the PAM settings.
“fingerprint-identifier”
An application for testing the identification of users by their fingerprints and to be used in special cases for any user-defined scripts in which a fingerprint identification is required.
“fingerprint-helper”
A helper application to be called out of PAM for requesting fingerprints while identifying or authenticating a user. This application should not be called from the command line.
“fingerprint-suid”
Another helper application to be called from “fingerprint-gui” when a new user directory has to be created in “/var/lib/fingerprint-gui/”, where user settings and fingerprint (bir) data are stored. This application should not be called from the command line.
“fingerprint-plugin”
A helper application to be plugged in into some other applications (like gnome-screensaver) that don't allow other GUI applications to be displayed on top of their own screen. This application should not be called from the command line.
“pam_fingerprint-gui.so”
A PAM module that is called by PAM when a user has to be identified or authenticated by their fingerprint.
“fingerprint-polkit-agent”
An authentication agent for policykit-1 with fingerprint recognition.
All modules accept a “debug
” (or
“-d
” or “--debug
”) argument
to be given for execution. This argument causes a lot of debug output
printed to syslog. Depending on syslog settings the output might be
printed to “/var/log/auth.log
”,
“/var/log/messages
” or
“/var/log/syslog
”.
This software should be self explanatory. So no further information is needed at the moment. When running, a users manual is available in the help menu.
This program first tries to collect all stored fingerprint data of
all users from user-specific directories in
“/var/lib/fingerprint-gui/<username>/<drivername>/
”.
If a directory named after the user is available and can be read it
collects all fingerprint data and tries to identify the user after a
finger swipe was given. If it doesn't run with root permissions the
directories of other users are not readable. In this case the fingerprints
of the current user are accessible only. So only the current user can be
identified or authenticated. After a successful authentication the user's
login name is printed to stdout and the program exits.
All Fingerprint GUI modules are developed using the Qt system,
except the
“pam_fingerprint-gui.so
”
module. This means the executables create a QApplication or a
QCoreApplication object when running. Qt doesn't allow more than one of
these objects to be created in an executable. Now, if some other Qt
application would call PAM for authenticating a user and PAM would call
the “pam_fingerprint-gui.so” library this would
cause a crash, when “pam_fingerprint-gui.so”
would try to create a (second) QApplication or QCoreApplication object
while prompting for a finger swipe. Therefore
“pam_fingerprint-gui.so
”
is not a Qt application but forks a child process (the
fingerprint-helper
) to
prompt the user for a finger swipe and handle fingerprints.
If a user acquires (enrolls) his fingerprints the first time, the
user's data directory in “/var/lib/fingerprint-gui/
”
does not exist yet. Because the directory
“/var/lib/fingerprint-gui/
” is owned by root and has
mode 755 it is required to create the user's data directory from a process
running suid root. In this case
“fingerprint-gui” executes
“fingerprint-suid” (which is owned by root and
has the mode u+s Bit set). “fingerprint-suid”
creates then the required <user> directory, makes it owned by this
user and his primary group and sets its mode to 700.
Some applications (namely "gnome-screensaver") don't accept for security reasons any GUI window to be displayed on top of their own screen. This means if gnome-screensaver calls PAM to prompt the user for authentication for the screensaver to be unlocked, the “pam_fingerprint-gui.so” module is called by PAM. This module forkes the “fingerprint-helper” process to request a finger swipe, but the window of this process is not visible (it is displayed “under” the locked screen). Therefore an additional “fingerprint-plugin” was created. This application is “plugged in” into the gnome-screensaver the same way an “embedded keyboard command” would be (by gnome-screensaver configuration).
When gnome-screensaver starts its unlock
prompt, it starts the “fingerprint-plugin”
module. This module plugs into the screensaver and is displayed below the
normal unlock prompt. Then the
“fingerprint-plugin” listens for “display
commands” at a named pipe “/tmp/fingerprint-plugin
”.
The “fingerprint-helper” process, forked from
“pam_fingerprint-gui.so” finds this named pipe
and sends all strings to be displayed at the GUI to this pipe. If no
fingerprints for the user are available a “stop” command is sent to the
pipe that causes the “fingerprint-plugin” to
exit before “fingerprint-helper” exits itself. If some other command has
to be displayed to the user (e.g. “ready...” or “authenticating
<username>”) this command will be received by
“fingerprint-plugin” via it's named pipe and
then displayed on its GUI window.
This is the PAM module to be called out of PAM in case some
application requests authentication. When its
“pam_sm_authenticate
” entry is called the module
determines whether DISPLAY and XAUTHORITY environment variables are
available. If DISPLAY is available and XAUTHORITY
is missing the module tries to find the xauthority filename by searching
the command line of the X display process. If it was found
“pam_fingerprint-gui.so” sets the XAUTHORITY
environment variable.
The module then creates an anonymous pipe and forkes into a child process. This process executes “fingerprint-helper” with pipe, display, PAM service to authenticate and username (if available) as arguments. After forking, a random number (10 digits) is sent to the child process via the anonymous pipe. This number will be given back (via the anonymous pipe) as a “password” if the user was identified or authenticated by his fingerprint. If the helper process has sent something to the pipe, it uses libfakekey or uinput to exit the “PAM conversation function”.
The parent process then calls the “PAM conversation function” of the calling application for prompting the username and/or password by keyboard while the child process (fingerprint-helper) prompts the user for swiping their finger.
Now the two processes wait for input in the following cases:
The PAM conversation function returns to the parent process (pam_fingerprint-gui.so) with a non empty username. This means the user did type his name on the keyboard. The helper process is stopped immediately by sending SIGUSR1 to it, the helper widget disappears and the user must type his password for login.
In this case the child process (fingerprint-helper) writes <enter> to the prompt using libfakekey or uinput and sends the username of the identified user via the pipe to his parent process (pam_fingerprint-gui.so). So the PAM conversation function returns an empty username field. Pam_fingerprint-gui.so then polls the fifo for a username and, if it can read it, sets this username to the PAM stack and sends SIGUSR1 to the helper. The helper then continues with case 3 below.
If there is nothing in the pipe to read, the user might have typed <enter> on the keyboard. In this case pam_fingerprint-gui.so sends SIGUSR2 to the helper to stop it immediately and returns PAM_AUTHINFO_UNAVAIL.
If the helper process has given the username to pam_fingerprint-gui.so via the pipe and receives SIGUSR1 it tries to get the users password from an encrypted file on the external media (USB stick, see 9. below). If available it sends this password via the pipe to pam_fingerprint-gui.so. If no “real” password is available it sends the random number to the pipe. Then the helper sends the <enter> key to the PAM prompt (via libfakekey or uinput) and exits. The same procedure happens, when the helper was forked with a known username from pam_fingerprint-gui.so.
Then the PAM module returns from its password prompt with an empty password. It polls the pipe for the password and compares this with the random number. If it matches, there was no “real” password available and the module returns PAM_SUCCESS. If it doesn't match it is the “real” password of this user. The PAM module then sets this password to the PAM stack and returns PAM_IGNORE. This causes the other PAM modules in the PAM stack to check the given username against this password.
If the PAM module returns from its password prompt with a non empty password field the user has typed his password at the prompt. Then the module sends SIGUSR2 to the helper to stop it immediately and returns PAM_IGNORE. So the other PAM modules can check the given username/password.
The pam_fingerprint-gui.so module allows
to be called with the argument
“try_first_identified
”. This allows calling the
module more then once in a given PAM stack without the effect to request a
finger swipe more then once. If the user was successful
identified/authenticated by his fingerprint in the first call of
pam_fingerprint-gui.so the module saves this
username to the PAM stack by a “pam_set_data” call. If
pam_fingerprint-gui.so is then called a second
time with the “try_first_identified
” argument, it
tries to read this username by a “pam_get_data
” call.
If there is a username available and this name matches the current
username to be authenticated, it returns PAM_SUCCESS immediately.
With “fingerprint-gui” (“Password” Tab) the user can chose some directory on a mounted removable media, invoke his login password and save it to this media. This way the system can provide the login password to PAM while the user logs in with fingerprint to avoid a password request when e.g. gnome-keyring has to be opened or an encrypted home directory has to be mounted.
This login password information is split into 2 different locations:
A file
“<username>@<machinename>.xml
” in a
subdirectory “.fingerprints
” on the chosen
removable media, containing the encrypted password;
A file “config.xml
” in the directory
“/var/lib/fingerprint-gui/<username>
”
containing the path to the
“<username>@<machinename>.xml
” file,
the UUID of the chosen partition on removable media and the key for
decrypting the password.
The password is encrypted with a random symmetric key (AES128-CBC-PKS7).
THERE IS A SECURITY RISK when this user is not the
only one who has root access to the machine! Someone with root permission
could connect to this machine (e.g. via ssh)
and copy the “config.xml
” file and the
“<username>@<machinename>.xml
” from the
connected removable media and then decrypt the user's password.
When configured (see users manual) and the removable media is connected while fingerprint login, the system takes the following steps:
After the user is identified (by fingerprint) the
“fingerprint-helper” looks for the user's
“/var/lib/fingerprint-gui/<username>/config.xml
”
and, if found, reads the UUID, the decryption key and the
initialization vector;
Then creates a temporary directory
“/tmp/<UUID>
” and tries to mount the
partition with this UUID there;
Then reads the encrypted key from
“<username>@<machinename>.xml
” file
and unmounts the media immediately;
If the password can be decrypted it is given to pam_fingerprint-gui.so by an anonymous pipe;
The pam_fingerprint-gui.so sets this
password to PAM by a “pam_set_item()
” call. If
this call was successful it returns PAM_IGNORE. Then PAM calls the
next module in stack (pam_unix.so) to
validate username and password and complete the login process.
I'M NOT A CRYPTO EXPERT! If you are, please have a look at the sources (UserSettings.cpp) and let me know if there are possible problems.
You need the Qt4 environment (incl. libqca2) and the “developer”
packages of the used libraries installed on your system for being able to
compile the sources. You can then use the “qmake-qt4”
command to create the makefiles for your system. Then call
“make” and it will create all executables in
“./bin/...
” subdirectories. After binaries are
successful created you can use “sudo make install” to
copy them to their proper locations. If you have a fingerprint scanner
manufactured by UPEK inc. or SGS Thomson, you can install the bundled
proprietary driver “libbsapi.so” by executing
“sudo make install-upek”. This is needed because the
open source driver (in libfprint) lacks the ability of comparing
one-to-many fingerprints. Please have a look into the README file for more
informations about the build options.