Commit e8c36e95 authored by Bastien Nocera's avatar Bastien Nocera Committed by Daniel Drake
Browse files

Rework the "SetUsername" functionality

- Remove SetUsername itself, and add a username parameter to DeviceClaim,
  ListEnrolledFingers and DeleteEnrolledFingers.
- For each of those calls, check that the incoming connection is allowed
  to operate on that particular username
- Don't require a claimed device to list or remove fingerprints
- Clean up username and sender when releasing the device
- Modify the storage backend to not require an opened device to list
  or delete fingerprints
- Add a simple test program to list registered fingerprints for the
  usernames passed as argument
parent bd2debc0
......@@ -34,11 +34,9 @@
extern DBusGConnection *fprintd_dbus_conn;
static void fprint_device_set_username(FprintDevice *rdev,
const char *username,
DBusGMethodInvocation *context);
static void fprint_device_claim(FprintDevice *rdev,
DBusGMethodInvocation *context);
const char *username,
DBusGMethodInvocation *context);
static void fprint_device_release(FprintDevice *rdev,
DBusGMethodInvocation *context);
static void fprint_device_verify_start(FprintDevice *rdev,
......@@ -50,9 +48,11 @@ static void fprint_device_enroll_start(FprintDevice *rdev,
static void fprint_device_enroll_stop(FprintDevice *rdev,
DBusGMethodInvocation *context);
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
DBusGMethodInvocation *context);
const char *username,
DBusGMethodInvocation *context);
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
DBusGMethodInvocation *context);
const char *username,
DBusGMethodInvocation *context);
#include "device-dbus-glue.h"
......@@ -310,33 +310,65 @@ _fprint_device_check_polkit_for_actions (FprintDevice *rdev,
return _fprint_device_check_polkit_for_action (rdev, context, action2, error);
}
static void
fprint_device_set_username (FprintDevice *rdev,
const char *username,
DBusGMethodInvocation *context)
static char *
_fprint_device_check_for_username (FprintDevice *rdev,
DBusGMethodInvocation *context,
const char *username,
char **ret_sender,
GError **error)
{
FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
GError *error = NULL;
DBusConnection *conn;
DBusError dbus_error;
char *sender;
unsigned long uid;
struct passwd *user;
char *client_username;
if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
/* Get details about the current sender, and username/uid */
conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
sender = dbus_g_method_get_sender (context);
dbus_error_init (&dbus_error);
uid = dbus_bus_get_unix_user (conn, sender, &dbus_error);
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.setusername", &error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
if (dbus_error_is_set(&dbus_error)) {
g_free (sender);
dbus_set_g_error (error, &dbus_error);
return NULL;
}
if (username == NULL) {
dbus_g_method_return (context);
return;
user = getpwuid (uid);
if (user == NULL) {
g_free (sender);
g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
"Failed to get information about user UID %lu", uid);
return NULL;
}
client_username = g_strdup (user->pw_name);
/* The current user is usually allowed to access their
* own data, this should be followed by PolicyKit checks
* anyway */
if (username == NULL || *username == '\0' || g_str_equal (username, client_username)) {
if (ret_sender != NULL)
*ret_sender = sender;
else
g_free (sender);
return client_username;
}
/* If we're not allowed to set a different username,
* then fail */
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.setusername", error) == FALSE) {
g_free (sender);
return NULL;
}
g_free (priv->username);
priv->username = g_strdup (username);
if (ret_sender != NULL)
*ret_sender = sender;
else
g_free (sender);
dbus_g_method_return (context);
return g_strdup (username);
}
static void dev_open_cb(struct fp_dev *dev, int status, void *user_data)
......@@ -364,15 +396,12 @@ static void dev_open_cb(struct fp_dev *dev, int status, void *user_data)
}
static void fprint_device_claim(FprintDevice *rdev,
DBusGMethodInvocation *context)
const char *username,
DBusGMethodInvocation *context)
{
FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
GError *error = NULL;
DBusConnection *conn;
DBusError dbus_error;
char *sender;
unsigned long uid;
struct passwd *user;
char *sender, *user;
int r;
/* Is it already claimed? */
......@@ -383,42 +412,36 @@ static void fprint_device_claim(FprintDevice *rdev,
return;
}
if (_fprint_device_check_polkit_for_actions (rdev, context,
"net.reactivated.fprint.device.verify",
"net.reactivated.fprint.device.enroll",
&error) == FALSE) {
dbus_g_method_return_error (context, error);
return;
}
g_assert (priv->username == NULL);
g_assert (priv->sender == NULL);
/* Get details about the current sender, and username/uid */
conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
sender = dbus_g_method_get_sender (context);
dbus_error_init (&dbus_error);
uid = dbus_bus_get_unix_user (conn, sender, &dbus_error);
if (dbus_error_is_set(&dbus_error)) {
sender = NULL;
user = _fprint_device_check_for_username (rdev,
context,
username,
&sender,
&error);
if (user == NULL) {
g_free (sender);
dbus_set_g_error (&error, &dbus_error);
dbus_g_method_return_error(context, error);
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
user = getpwuid (uid);
if (user == NULL) {
if (_fprint_device_check_polkit_for_actions (rdev, context,
"net.reactivated.fprint.device.verify",
"net.reactivated.fprint.device.enroll",
&error) == FALSE) {
g_free (sender);
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
"Failed to get information about user UID %lu", uid);
dbus_g_method_return_error(context, error);
g_free (user);
dbus_g_method_return_error (context, error);
return;
}
priv->username = g_strdup (user->pw_name);
priv->username = user;
priv->sender = sender;
g_message ("user claiming the device: %s (%ld)", priv->username, uid);
/* FIXME call polkit to check whether allowed */
g_message ("user claiming the device: %s", priv->username);
g_message("claiming device %d", priv->id);
priv->session = g_slice_new0(struct session_data);
......@@ -478,6 +501,10 @@ static void fprint_device_release(FprintDevice *rdev,
session->context_release_device = context;
fp_async_dev_close(priv->dev, dev_close_cb, rdev);
g_free (priv->sender);
priv->sender = NULL;
g_free (priv->username);
priv->username = NULL;
}
static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img,
......@@ -647,25 +674,37 @@ static void fprint_device_enroll_stop(FprintDevice *rdev,
}
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
DBusGMethodInvocation *context)
const char *username,
DBusGMethodInvocation *context)
{
FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
GError *error = NULL;
GSList *prints;
GSList *item;
GArray *ret;
if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
char *user;
g_message ("orig username: %s", username);
user = _fprint_device_check_for_username (rdev,
context,
username,
NULL,
&error);
g_message ("user: %s", user);
if (user == NULL) {
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
g_free (user);
dbus_g_method_return_error (context, error);
return;
}
prints = store.discover_prints(priv->dev, priv->username);
prints = store.discover_prints(priv->ddev, user);
g_free (user);
if (!prints) {
g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS,
"Failed to discover prints");
......@@ -685,25 +724,35 @@ static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
}
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
const char *username,
DBusGMethodInvocation *context)
{
FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
GError *error = NULL;
guint i;
char *user;
if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
user = _fprint_device_check_for_username (rdev,
context,
username,
NULL,
&error);
if (user == NULL) {
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
g_free (user);
dbus_g_method_return_error (context, error);
return;
}
for (i = LEFT_THUMB; i <= RIGHT_LITTLE; i++) {
store.print_data_delete(priv->dev, i, priv->username);
store.print_data_delete(priv->ddev, i, user);
}
g_free (user);
dbus_g_method_return(context);
}
......
......@@ -4,20 +4,23 @@
<annotation name="org.freedesktop.DBus.GLib.CSymbol"
value="fprint_device" />
<method name="Claim">
<method name="ListEnrolledFingers">
<arg type="s" name="username" direction="in" />
<arg type="au" name="enrolled_fingers" direction="out" />
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method>
<method name="Release">
<method name="DeleteEnrolledFingers">
<arg type="s" name="username" direction="in" />
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method>
<method name="ListEnrolledFingers">
<arg type="au" name="enrolled_fingers" direction="out" />
<method name="Claim">
<arg type="s" name="username" direction="in" />
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method>
<method name="DeleteEnrolledFingers">
<method name="Release">
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method>
......@@ -47,11 +50,6 @@
<arg type="i" name="result" />
</signal>
<method name="SetUsername">
<arg type="s" name="username" direction="in" />
<annotation name="org.freedesktop.DBus.GLib.Async" value="" />
</method>
</interface>
</node>
......@@ -78,6 +78,12 @@ static char *get_path_to_print(struct fp_dev *dev, enum fp_finger finger, char *
fp_dev_get_devtype(dev), finger, base_store);
}
static char *get_path_to_print_dscv(struct fp_dscv_dev *dev, enum fp_finger finger, char *base_store)
{
return __get_path_to_print(fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)),
fp_dscv_dev_get_devtype(dev), finger, base_store);
}
static int file_storage_get_basestore_for_username(const char *username, char **base_store)
{
char *dirpath = FILE_STORAGE_PATH;
......@@ -193,7 +199,7 @@ int file_storage_print_data_load(struct fp_dev *dev,
return 0;
}
int file_storage_print_data_delete(struct fp_dev *dev,
int file_storage_print_data_delete(struct fp_dscv_dev *dev,
enum fp_finger finger, const char *username)
{
int r;
......@@ -205,7 +211,7 @@ int file_storage_print_data_delete(struct fp_dev *dev,
return r;
}
gchar *path = get_path_to_print(dev, finger, base_store);
gchar *path = get_path_to_print_dscv(dev, finger, base_store);
r = g_unlink(path);
g_free(path);
......@@ -252,7 +258,7 @@ static GSList *scan_dev_storedir(char *devpath, uint16_t driver_id,
return list;
}
GSList *file_storage_discover_prints(struct fp_dev *dev, const char *username)
GSList *file_storage_discover_prints(struct fp_dscv_dev *dev, const char *username)
{
//GDir *dir;
//const gchar *ent;
......@@ -270,12 +276,12 @@ GSList *file_storage_discover_prints(struct fp_dev *dev, const char *username)
return NULL;
}
storedir = get_path_to_storedir(fp_driver_get_driver_id(fp_dev_get_driver(dev)),
fp_dev_get_devtype(dev), base_store);
storedir = get_path_to_storedir(fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)),
fp_dscv_dev_get_devtype(dev), base_store);
g_message("Entering %s", storedir);
list = scan_dev_storedir(storedir, fp_driver_get_driver_id(fp_dev_get_driver(dev)),
fp_dev_get_devtype(dev), list);
list = scan_dev_storedir(storedir, fp_driver_get_driver_id(fp_dscv_dev_get_driver(dev)),
fp_dscv_dev_get_devtype(dev), list);
g_free(base_store);
g_free(storedir);
......
......@@ -29,13 +29,13 @@ int file_storage_print_data_save(struct fp_print_data *data,
int file_storage_print_data_load(struct fp_dev *dev,
enum fp_finger finger, struct fp_print_data **data, const char *username);
int file_storage_print_data_delete(struct fp_dev *dev,
int file_storage_print_data_delete(struct fp_dscv_dev *dev,
enum fp_finger finger, const char *username);
int file_storage_init(void);
int file_storage_deinit(void);
GSList *file_storage_discover_prints(struct fp_dev *dev, const char *username);
GSList *file_storage_discover_prints(struct fp_dscv_dev *dev, const char *username);
#endif
......@@ -26,9 +26,9 @@ typedef int (*storage_print_data_save)(struct fp_print_data *data,
enum fp_finger finger, const char *username);
typedef int (*storage_print_data_load)(struct fp_dev *dev,
enum fp_finger finger, struct fp_print_data **data, const char *username);
typedef int (*storage_print_data_delete)(struct fp_dev *dev,
typedef int (*storage_print_data_delete)(struct fp_dscv_dev *dev,
enum fp_finger finger, const char *username);
typedef GSList *(*storage_discover_prints)(struct fp_dev *dev, const char *username);
typedef GSList *(*storage_discover_prints)(struct fp_dscv_dev *dev, const char *username);
typedef int (*storage_init)(void);
typedef int (*storage_deinit)(void);
......
......@@ -2,7 +2,7 @@ BUILT_SOURCES = manager-dbus-glue.h device-dbus-glue.h
noinst_HEADERS = $(BUILT_SOURCES)
CLEANFILES = $(BUILT_SOURCES)
bin_PROGRAMS = verify enroll
bin_PROGRAMS = verify enroll list
verify_SOURCES = verify.c
verify_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS)
......@@ -12,6 +12,10 @@ enroll_SOURCES = enroll.c
enroll_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS)
enroll_LDADD = $(GLIB_LIBS)
list_SOURCES = list.c
list_CFLAGS = $(AM_CFLAGS) $(GLIB_CFLAGS)
list_LDADD = $(GLIB_LIBS)
manager-dbus-glue.h: ../src/manager.xml
dbus-binding-tool --prefix=fprint_manager --mode=glib-client $< --output=$@
......
......@@ -83,7 +83,7 @@ static void create_manager(void)
"net.reactivated.Fprint.Manager");
}
static DBusGProxy *open_device(void)
static DBusGProxy *open_device(const char *username)
{
GError *error = NULL;
GPtrArray *devices;
......@@ -115,7 +115,7 @@ static DBusGProxy *open_device(void)
g_ptr_array_foreach(devices, (GFunc) g_free, NULL);
g_ptr_array_free(devices, TRUE);
if (!net_reactivated_Fprint_Device_claim(dev, &error))
if (!net_reactivated_Fprint_Device_claim(dev, username, &error))
g_error("failed to claim device: %s", error->message);
return dev;
}
......@@ -158,30 +158,20 @@ static void release_device(DBusGProxy *dev)
g_error("ReleaseDevice failed: %s", error->message);
}
static gboolean set_username(DBusGProxy *dev, const char *username)
{
GError *error = NULL;
if (!net_reactivated_Fprint_Device_set_username(dev, username, &error)) {
g_error("SetUsename failed: %s", error->message);
return FALSE;
}
return TRUE;
}
int main(int argc, char **argv)
{
GMainLoop *loop;
DBusGProxy *dev;
char *username;
g_type_init();
loop = g_main_loop_new(NULL, FALSE);
create_manager();
dev = open_device();
if (argc == 2) {
if (set_username(dev, argv[1]) == FALSE)
return 1;
}
username = NULL;
if (argc == 2)
username = argv[1];
dev = open_device(username);
do_enroll(dev);
release_device(dev);
return 0;
......
/*
* fprintd example to verify a fingerprint
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus-glib-bindings.h>
#include "manager-dbus-glue.h"
#include "device-dbus-glue.h"
static DBusGProxy *manager = NULL;
static DBusGConnection *connection = NULL;
enum fp_finger {
LEFT_THUMB = 1, /** thumb (left hand) */
LEFT_INDEX, /** index finger (left hand) */
LEFT_MIDDLE, /** middle finger (left hand) */
LEFT_RING, /** ring finger (left hand) */
LEFT_LITTLE, /** little finger (left hand) */
RIGHT_THUMB, /** thumb (right hand) */
RIGHT_INDEX, /** index finger (right hand) */
RIGHT_MIDDLE, /** middle finger (right hand) */
RIGHT_RING, /** ring finger (right hand) */
RIGHT_LITTLE, /** little finger (right hand) */
};
static const char *fingerstr(guint32 fingernum)
{
switch (fingernum) {
case LEFT_THUMB:
return "Left thumb";
case LEFT_INDEX:
return "Left index finger";
case LEFT_MIDDLE:
return "Left middle finger";
case LEFT_RING:
return "Left ring finger";
case LEFT_LITTLE:
return "Left little finger";
case RIGHT_THUMB:
return "Right thumb";
case RIGHT_INDEX:
return "Right index finger";
case RIGHT_MIDDLE:
return "Right middle finger";
case RIGHT_RING:
return "Right ring finger";
case RIGHT_LITTLE:
return "Right little finger";
default:
return "Unknown finger";
}
}
static void create_manager(void)
{
GError *error = NULL;
connection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
if (connection == NULL)
g_error("Failed to connect to session bus: %s", error->message);
manager = dbus_g_proxy_new_for_name(connection,
"net.reactivated.Fprint", "/net/reactivated/Fprint/Manager",
"net.reactivated.Fprint.Manager");
}
static DBusGProxy *open_device(void)
{
GError *error = NULL;
GPtrArray *devices;
gchar *path;
DBusGProxy *dev;
guint i;
if (!net_reactivated_Fprint_Manager_get_devices(manager, &devices, &error))
g_error("list_devices failed: %s", error->message);
if (devices->len == 0) {
g_print("No devices found\n");
exit(1);
}
g_print("found %d devices\n", devices->len);
for (i = 0; i < devices->len; i++) {
path = g_ptr_array_index(devices, i);
g_print("Device at %s\n", path);
}
path = g_ptr_array_index(devices, 0);
g_print("Using device %s\n", path);
/* FIXME use for_name_owner?? */
dev = dbus_g_proxy_new_for_name(connection, "net.reactivated.Fprint",
path, "net.reactivated.Fprint.Device");
g_ptr_array_foreach(devices, (GFunc) g_free, NULL);
g_ptr_array_free(devices, TRUE);
return dev;
}
static void list_fingerprints(DBusGProxy *dev, const char *username)
{
GError *error = NULL;
GArray *fingers;
guint i;
int fingernum;
if (!net_reactivated_Fprint_Device_list_enrolled_fingers(dev, username, &fingers, &error))
g_error("ListEnrolledFingers failed: %s", error->message);
if (fingers->len == 0) {
g_print("User %s has no fingers enrolled for this device.\n", username);
return;
}
g_print("Fingerprints for user %s:\n", username);
for (i = 0; i < fingers->len; i++) {
fingernum = g_array_index(fingers, guint32, i);
g_print(" - #%d: %s\n", fingernum, fingerstr(fingernum));
}
fingernum = g_array_index(fingers, guint32, 0);
g_array_free(fingers, TRUE);
}
int main(int argc, char **argv)
{
GMainLoop *loop;
DBusGProxy *dev;
guint32 i;