During VerifyStart we may return early if there are no enrolled prints.
In such case we don't require the verification to be stopped if we're
using identification, but in the verification case we may leave the
device into the verification state.
So ensure we only set the device current state only when we're about to
start it.
Add tests ensuring those cases
The user may have some invalid prints saved (like the ones enrolled with
fprintd 1) in the storage, this lead to list such prints as enrolled but
they're actually not valid.
So load the prints to ensure that those are of the valid type instead of
just discovering them.
We may make just store.discover_prints to be aware of this, but this
would break some assumptions we do in tests, so better to go this way.
We may want to be able to load the user prints to check whether they
are usable, so add an utility function for this.
And use it also in load_all_prints().
It might make sense to push this into the storage layer. But, overall,
it is OK to live here, and if we do make changes on the storage layer we
probably want to change more than just this.
Loading saved prints may lead to an error if they were stored long time
ago and so they're using a wrong format.
In such case we list the prints as available even though they are really
not, so the PAM module won't return PAM_AUTHINFO_UNAVAIL as in the
no-prints case but PAM_USER_UNKNOWN.
This will lead some auth systems (such as gdm) to keep retrying using
PAM fprintd module, even if it's not really available.
When saving the prints we use g_file_set_contents under the hood and in
case return its error code that is a positive value.
So in such case we don't fail if we have a write failure at the end of
the enrollment.
While we could ensure in file storage to always return a negative value,
it's always better to ensure that is has to be 0 when we didn't get an
error.
When claiming a device for delete operation we'd not get an error in
case we can claim it but it's not already claimed, so in such case we
should explicitly check that the device has been opened.
In case we get concurrent requests on EnrollStart/EnrollStop we'd just
continue with the operation, making the first processed request to start
the process and the second to hang (in code before the introduction of
stoppable_action_stop()) or to crash (in the current code).
So in such case we should always check that we're not handling already
the request, by checking priv->current_cancel_invocation value.
Add tests to verify the race.
This makes garbage collection a bit more predictable overall. Note that
we'll first delete prints that we do not know the age of.
If we cannot sort them by age, then randomize the order so that we don't
end up deleting in the order that the device returned the prints.
The stoppable actions (Verify/Enroll) have the same logic during
completion. Create a common function to share this logic instead of
copying it in each of the handlers.
Fixes: #97
When multiple devices are available PAM module will just pick the first
one, even if it has not enrolled fingers.
Since this can't be user configured (yet) we can be a bit smarter and
select the device that has more fingerprints configured for the user.
In the garbage collection code we always ended up to load the first
enrolled print, and this may lead to removing from device storage prints
that are actually in use.
We have a condition where a client vanishing instead of cleaning up the
operation using VerifyStop would cause fprintd to hang. This only
happens if the underlying enroll/verify/identify operation has already
finished when the client vanishes.
Fix this by correctly interpreting current_cancellable as a flag for
these operations.
Fixes: #97
This is useful in the functions where we have to unset the device's
current action but we may use early-return to handle multiple conditions
such as in open, close and delete functions.
The latest also currently is a bit buggy as it won't reset the state on
some failures.