2007-10-16 13:23:30 +00:00
|
|
|
/*
|
2019-11-20 13:29:46 +00:00
|
|
|
* Example fingerprint verification program, which verifies the
|
2007-10-16 13:23:30 +00:00
|
|
|
* finger which has been previously enrolled to disk.
|
|
|
|
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
|
2019-11-19 19:18:13 +00:00
|
|
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
2007-10-16 13:23:30 +00:00
|
|
|
*
|
|
|
|
* This library 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 library 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
2020-01-16 13:37:07 +00:00
|
|
|
#define FP_COMPONENT "example-verify"
|
|
|
|
|
2007-10-16 13:23:30 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <libfprint/fprint.h>
|
2020-04-20 15:46:14 +00:00
|
|
|
#include <glib-unix.h>
|
2007-10-16 13:23:30 +00:00
|
|
|
|
2019-06-13 13:10:59 +00:00
|
|
|
#include "storage.h"
|
2019-11-20 13:29:46 +00:00
|
|
|
#include "utilities.h"
|
2019-06-13 13:10:59 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
typedef struct _VerifyData
|
|
|
|
{
|
2020-04-20 15:46:14 +00:00
|
|
|
GMainLoop *loop;
|
|
|
|
GCancellable *cancellable;
|
|
|
|
unsigned int sigint_handler;
|
|
|
|
FpFinger finger;
|
|
|
|
int ret_value;
|
2019-11-19 19:18:13 +00:00
|
|
|
} VerifyData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
verify_data_free (VerifyData *verify_data)
|
2007-10-16 13:23:30 +00:00
|
|
|
{
|
2020-04-20 15:46:14 +00:00
|
|
|
g_clear_handle_id (&verify_data->sigint_handler, g_source_remove);
|
|
|
|
g_clear_object (&verify_data->cancellable);
|
2019-11-19 19:18:13 +00:00
|
|
|
g_main_loop_unref (verify_data->loop);
|
|
|
|
g_free (verify_data);
|
|
|
|
}
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (VerifyData, verify_data_free)
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
|
|
{
|
|
|
|
VerifyData *verify_data = user_data;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
|
|
|
|
fp_device_close_finish (dev, res, &error);
|
|
|
|
|
|
|
|
if (error)
|
2020-09-29 08:42:03 +00:00
|
|
|
g_warning ("Failed closing device %s", error->message);
|
2019-11-19 19:18:13 +00:00
|
|
|
|
|
|
|
g_main_loop_quit (verify_data->loop);
|
|
|
|
}
|
|
|
|
|
2020-01-16 13:36:41 +00:00
|
|
|
static void
|
|
|
|
verify_quit (FpDevice *dev,
|
|
|
|
VerifyData *verify_data)
|
|
|
|
{
|
|
|
|
if (!fp_device_is_open (dev))
|
|
|
|
{
|
|
|
|
g_main_loop_quit (verify_data->loop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
|
|
|
|
}
|
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
static void start_verification (FpDevice *dev,
|
|
|
|
VerifyData *verify_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
|
2007-10-16 13:23:30 +00:00
|
|
|
{
|
2019-11-19 19:18:13 +00:00
|
|
|
VerifyData *verify_data = user_data;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_autoptr(FpPrint) print = NULL;
|
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
char buffer[20];
|
|
|
|
gboolean match;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
if (!fp_device_verify_finish (dev, res, &match, &print, &error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to verify print: %s", error->message);
|
|
|
|
verify_data->ret_value = EXIT_FAILURE;
|
2020-01-17 16:22:15 +00:00
|
|
|
|
|
|
|
if (error->domain != FP_DEVICE_RETRY)
|
|
|
|
{
|
|
|
|
verify_quit (dev, verify_data);
|
|
|
|
return;
|
|
|
|
}
|
2019-11-19 19:18:13 +00:00
|
|
|
}
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_print ("Verify again? [Y/n]? ");
|
|
|
|
if (fgets (buffer, sizeof (buffer), stdin) &&
|
2020-01-02 17:43:59 +00:00
|
|
|
(buffer[0] == 'Y' || buffer[0] == 'y' || buffer[0] == '\n'))
|
2019-11-19 19:18:13 +00:00
|
|
|
{
|
|
|
|
start_verification (dev, verify_data);
|
|
|
|
return;
|
|
|
|
}
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2020-01-16 13:36:41 +00:00
|
|
|
verify_quit (dev, verify_data);
|
2019-11-19 19:18:13 +00:00
|
|
|
}
|
|
|
|
|
2020-01-16 16:00:37 +00:00
|
|
|
static void
|
|
|
|
on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
|
|
|
|
gpointer user_data, GError *error)
|
|
|
|
{
|
2020-01-17 16:22:15 +00:00
|
|
|
VerifyData *verify_data = user_data;
|
|
|
|
|
2020-01-16 16:00:37 +00:00
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
g_warning ("Match report: Finger not matched, retry error reported: %s",
|
|
|
|
error->message);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-06-17 12:00:19 +00:00
|
|
|
if (print && fp_print_get_image (print) &&
|
2020-01-17 16:22:15 +00:00
|
|
|
print_image_save (print, "verify.pgm"))
|
|
|
|
g_print ("Print image saved as verify.pgm\n");
|
|
|
|
|
2020-01-16 16:00:37 +00:00
|
|
|
if (match)
|
|
|
|
{
|
|
|
|
char date_str[128];
|
|
|
|
|
2020-01-17 16:22:15 +00:00
|
|
|
verify_data->ret_value = EXIT_SUCCESS;
|
|
|
|
|
2020-01-16 16:00:37 +00:00
|
|
|
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
|
|
|
|
fp_print_get_enroll_date (match));
|
|
|
|
g_debug ("Match report: device %s matched finger %s successifully "
|
|
|
|
"with print %s, enrolled on date %s by user %s",
|
|
|
|
fp_device_get_name (dev),
|
|
|
|
finger_to_string (fp_print_get_finger (match)),
|
|
|
|
fp_print_get_description (match), date_str,
|
|
|
|
fp_print_get_username (match));
|
2020-01-17 16:22:15 +00:00
|
|
|
|
|
|
|
g_print ("MATCH!\n");
|
2020-01-16 16:00:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_debug ("Match report: Finger not matched");
|
2020-01-17 16:22:15 +00:00
|
|
|
g_print ("NO MATCH!\n");
|
2020-01-16 16:00:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-08 01:12:05 +00:00
|
|
|
static FpPrint *
|
|
|
|
get_stored_print (FpDevice *dev, VerifyData *verify_data)
|
|
|
|
{
|
|
|
|
FpPrint *verify_print;
|
|
|
|
|
|
|
|
g_print ("Loading previously enrolled %s finger data...\n",
|
|
|
|
finger_to_string (verify_data->finger));
|
|
|
|
|
|
|
|
verify_print = print_data_load (dev, verify_data->finger);
|
|
|
|
|
|
|
|
if (!verify_print)
|
|
|
|
{
|
|
|
|
g_warning ("Failed to load fingerprint data");
|
|
|
|
g_warning ("Did you remember to enroll your %s finger first?",
|
|
|
|
finger_to_string (verify_data->finger));
|
|
|
|
}
|
|
|
|
|
|
|
|
return verify_print;
|
|
|
|
}
|
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
static void
|
|
|
|
on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
|
|
|
|
{
|
|
|
|
VerifyData *verify_data = user_data;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_autoptr(GPtrArray) prints = NULL;
|
|
|
|
g_autoptr(GError) error = NULL;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
prints = fp_device_list_prints_finish (dev, res, &error);
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
if (!error)
|
|
|
|
{
|
|
|
|
FpPrint *verify_print = NULL;
|
2020-11-08 01:12:05 +00:00
|
|
|
g_autoptr(FpPrint) stored_print = NULL;
|
2019-11-19 19:18:13 +00:00
|
|
|
guint i;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
if (!prints->len)
|
2020-11-08 01:12:05 +00:00
|
|
|
{
|
|
|
|
g_warning ("No prints saved on device");
|
|
|
|
verify_quit (dev, verify_data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stored_print = get_stored_print (dev, verify_data);
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
for (i = 0; i < prints->len; ++i)
|
|
|
|
{
|
|
|
|
FpPrint *print = prints->pdata[i];
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2020-11-08 01:12:05 +00:00
|
|
|
if (stored_print && fp_print_equal (stored_print, print))
|
|
|
|
/* If the private print data matches, let's use the stored print
|
|
|
|
* as it contains more metadata to show */
|
|
|
|
print = stored_print;
|
|
|
|
|
2019-11-20 13:29:46 +00:00
|
|
|
if (fp_print_get_finger (print) == verify_data->finger &&
|
2019-11-19 19:18:13 +00:00
|
|
|
g_strcmp0 (fp_print_get_username (print), g_get_user_name ()) == 0)
|
|
|
|
{
|
2019-11-27 18:14:35 +00:00
|
|
|
const GDate *verify_print_date = NULL;
|
|
|
|
const GDate *print_date = fp_print_get_enroll_date (print);
|
|
|
|
|
|
|
|
if (verify_print)
|
|
|
|
verify_print_date = fp_print_get_enroll_date (verify_print);
|
|
|
|
|
|
|
|
if (!verify_print || !print_date || !verify_print_date ||
|
|
|
|
g_date_compare (print_date, verify_print_date) >= 0)
|
2019-11-19 19:18:13 +00:00
|
|
|
verify_print = print;
|
|
|
|
}
|
|
|
|
}
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
if (!verify_print)
|
|
|
|
{
|
2020-01-16 13:36:41 +00:00
|
|
|
verify_quit (dev, verify_data);
|
2019-11-19 19:18:13 +00:00
|
|
|
return;
|
2007-10-16 13:23:30 +00:00
|
|
|
}
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_debug ("Comparing print with %s",
|
|
|
|
fp_print_get_description (verify_print));
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_print ("Print loaded. Time to verify!\n");
|
2020-04-20 15:46:14 +00:00
|
|
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
2020-01-16 16:00:37 +00:00
|
|
|
on_match_cb, verify_data, NULL,
|
2019-11-19 19:18:13 +00:00
|
|
|
(GAsyncReadyCallback) on_verify_completed,
|
|
|
|
verify_data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Loading prints failed with error %s", error->message);
|
2020-01-16 13:36:41 +00:00
|
|
|
verify_quit (dev, verify_data);
|
2019-11-19 19:18:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
start_verification (FpDevice *dev, VerifyData *verify_data)
|
|
|
|
{
|
2020-01-02 17:44:34 +00:00
|
|
|
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
|
|
|
{
|
|
|
|
g_print ("Choose the finger to verify:\n");
|
|
|
|
verify_data->finger = finger_chooser ();
|
|
|
|
}
|
2019-11-20 13:29:46 +00:00
|
|
|
|
|
|
|
if (verify_data->finger == FP_FINGER_UNKNOWN)
|
|
|
|
{
|
|
|
|
g_warning ("Unknown finger selected");
|
|
|
|
verify_data->ret_value = EXIT_FAILURE;
|
2020-01-16 13:36:41 +00:00
|
|
|
verify_quit (dev, verify_data);
|
2019-11-20 13:29:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-09 20:01:00 +00:00
|
|
|
if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_STORAGE))
|
2019-11-19 19:18:13 +00:00
|
|
|
{
|
|
|
|
g_print ("Creating finger template, using device storage...\n");
|
|
|
|
fp_device_list_prints (dev, NULL,
|
|
|
|
(GAsyncReadyCallback) on_list_completed,
|
|
|
|
verify_data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-11-08 01:12:05 +00:00
|
|
|
g_autoptr(FpPrint) verify_print = get_stored_print (dev, verify_data);
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
if (!verify_print)
|
|
|
|
{
|
2020-01-16 13:36:41 +00:00
|
|
|
verify_quit (dev, verify_data);
|
2019-11-19 19:18:13 +00:00
|
|
|
return;
|
2007-10-16 13:23:30 +00:00
|
|
|
}
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
g_print ("Print loaded. Time to verify!\n");
|
2020-04-20 15:46:14 +00:00
|
|
|
fp_device_verify (dev, verify_print, verify_data->cancellable,
|
2020-06-17 12:14:35 +00:00
|
|
|
on_match_cb, verify_data, NULL,
|
2019-11-19 19:18:13 +00:00
|
|
|
(GAsyncReadyCallback) on_verify_completed,
|
|
|
|
verify_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
|
|
|
|
{
|
|
|
|
VerifyData *verify_data = user_data;
|
|
|
|
|
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
|
|
|
|
if (!fp_device_open_finish (dev, res, &error))
|
2019-11-19 20:13:11 +00:00
|
|
|
{
|
2019-11-19 19:18:13 +00:00
|
|
|
g_warning ("Failed to open device: %s", error->message);
|
2020-01-16 13:36:41 +00:00
|
|
|
verify_quit (dev, verify_data);
|
2019-11-19 20:13:11 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-11-19 19:18:13 +00:00
|
|
|
|
|
|
|
g_print ("Opened device. ");
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
start_verification (dev, verify_data);
|
2007-10-16 13:23:30 +00:00
|
|
|
}
|
|
|
|
|
2020-04-20 15:46:14 +00:00
|
|
|
static gboolean
|
|
|
|
sigint_cb (void *user_data)
|
|
|
|
{
|
|
|
|
VerifyData *verify_data = user_data;
|
|
|
|
|
|
|
|
g_cancellable_cancel (verify_data->cancellable);
|
|
|
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
}
|
|
|
|
|
2007-10-16 13:23:30 +00:00
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
{
|
2019-11-19 19:18:13 +00:00
|
|
|
g_autoptr(FpContext) ctx = NULL;
|
|
|
|
g_autoptr(VerifyData) verify_data = NULL;
|
|
|
|
GPtrArray *devices;
|
|
|
|
FpDevice *dev;
|
2007-10-16 13:23:30 +00:00
|
|
|
|
2018-05-24 10:42:47 +00:00
|
|
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
|
|
setenv ("LIBUSB_DEBUG", "3", 0);
|
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
ctx = fp_context_new ();
|
2007-10-16 13:23:30 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
devices = fp_context_get_devices (ctx);
|
|
|
|
if (!devices)
|
|
|
|
{
|
|
|
|
g_warning ("Impossible to get devices");
|
|
|
|
return EXIT_FAILURE;
|
2007-10-16 13:23:30 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
dev = discover_device (devices);
|
2007-10-16 13:23:30 +00:00
|
|
|
if (!dev)
|
|
|
|
{
|
2019-11-19 19:18:13 +00:00
|
|
|
g_warning ("No devices detected.");
|
|
|
|
return EXIT_FAILURE;
|
2007-10-16 13:23:30 +00:00
|
|
|
}
|
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
verify_data = g_new0 (VerifyData, 1);
|
|
|
|
verify_data->ret_value = EXIT_FAILURE;
|
|
|
|
verify_data->loop = g_main_loop_new (NULL, FALSE);
|
2020-04-20 15:46:14 +00:00
|
|
|
verify_data->cancellable = g_cancellable_new ();
|
|
|
|
verify_data->sigint_handler = g_unix_signal_add_full (G_PRIORITY_HIGH,
|
|
|
|
SIGINT,
|
|
|
|
sigint_cb,
|
|
|
|
verify_data,
|
|
|
|
NULL);
|
|
|
|
fp_device_open (dev, verify_data->cancellable,
|
|
|
|
(GAsyncReadyCallback) on_device_opened,
|
2019-11-19 19:18:13 +00:00
|
|
|
verify_data);
|
|
|
|
|
|
|
|
g_main_loop_run (verify_data->loop);
|
2007-10-16 13:23:30 +00:00
|
|
|
|
2019-11-19 19:18:13 +00:00
|
|
|
return verify_data->ret_value;
|
2007-10-16 13:23:30 +00:00
|
|
|
}
|