device.c 32.7 KB
Newer Older
Daniel Drake's avatar
Daniel Drake committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * /net/reactivated/Fprint/Device/foo object implementation
 * 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.
 */

20 21
#include "config.h"

Daniel Drake's avatar
Daniel Drake committed
22
#include <dbus/dbus-glib-bindings.h>
23 24
#include <dbus/dbus-glib-lowlevel.h>
#include <glib/gi18n.h>
Bastien Nocera's avatar
Bastien Nocera committed
25 26
#include <polkit/polkit.h>
#include <polkit-dbus/polkit-dbus.h>
Daniel Drake's avatar
Daniel Drake committed
27 28
#include <libfprint/fprint.h>

29 30 31
#include <sys/types.h>
#include <pwd.h>

32
#include "fprintd-marshal.h"
Daniel Drake's avatar
Daniel Drake committed
33
#include "fprintd.h"
34
#include "storage.h"
35
#include "egg-dbus-monitor.h"
Daniel Drake's avatar
Daniel Drake committed
36

37 38 39 40 41 42 43 44 45 46 47 48 49
static char *fingers[] = {
	"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"
};

50 51
extern DBusGConnection *fprintd_dbus_conn;

Bastien Nocera's avatar
Bastien Nocera committed
52
static void fprint_device_claim(FprintDevice *rdev,
53 54
				const char *username,
				DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
55
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
56
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
57
static void fprint_device_verify_start(FprintDevice *rdev,
58
	const char *finger_name, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
59
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
60
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
61
static void fprint_device_enroll_start(FprintDevice *rdev,
62
	const char *finger_name, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
63
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
64
	DBusGMethodInvocation *context);
65
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, 
66 67
						const char *username,
						DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
68
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
69 70
						  const char *username,
						  DBusGMethodInvocation *context);
Daniel Drake's avatar
Daniel Drake committed
71 72 73

#include "device-dbus-glue.h"

Bastien Nocera's avatar
Bastien Nocera committed
74 75 76
typedef enum {
	ACTION_NONE = 0,
	ACTION_IDENTIFY,
Bastien Nocera's avatar
Bastien Nocera committed
77 78
	ACTION_VERIFY,
	ACTION_ENROLL
Bastien Nocera's avatar
Bastien Nocera committed
79 80
} FprintDeviceAction;

Daniel Drake's avatar
Daniel Drake committed
81
struct session_data {
Daniel Drake's avatar
Daniel Drake committed
82 83 84
	/* finger being enrolled */
	int enroll_finger;

Daniel Drake's avatar
Daniel Drake committed
85 86 87 88 89 90 91 92 93 94 95 96
	/* method invocation for async ClaimDevice() */
	DBusGMethodInvocation *context_claim_device;

	/* method invocation for async ReleaseDevice() */
	DBusGMethodInvocation *context_release_device;
};

struct FprintDevicePrivate {
	guint32 id;
	struct fp_dscv_dev *ddev;
	struct fp_dev *dev;
	struct session_data *session;
97

Bastien Nocera's avatar
Bastien Nocera committed
98 99
	PolKitContext *pol_ctx;

100 101 102
	/* The current user of the device, if claimed */
	char *sender;

Bastien Nocera's avatar
Bastien Nocera committed
103 104
	/* The current user of the device, or if allowed,
	 * what was passed as a username argument */
105 106
	char *username;

107 108
	/* type of storage */
	int storage_type;
Bastien Nocera's avatar
Bastien Nocera committed
109

110 111 112
	/* Hashtable of connected clients */
	GHashTable *clients;

Bastien Nocera's avatar
Bastien Nocera committed
113
	/* whether we're running an identify, or a verify */
Bastien Nocera's avatar
Bastien Nocera committed
114
	FprintDeviceAction current_action;
Daniel Drake's avatar
Daniel Drake committed
115 116 117 118 119 120 121 122
};

typedef struct FprintDevicePrivate FprintDevicePrivate;

#define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), FPRINT_TYPE_DEVICE, FprintDevicePrivate))

enum fprint_device_properties {
	FPRINT_DEVICE_CONSTRUCT_DDEV = 1,
123
	FPRINT_DEVICE_IN_USE,
124 125 126
	FPRINT_DEVICE_NAME,
	FPRINT_DEVICE_NUM_ENROLL,
	FPRINT_DEVICE_SCAN_TYPE
Daniel Drake's avatar
Daniel Drake committed
127 128
};

129
enum fprint_device_signals {
Daniel Drake's avatar
Daniel Drake committed
130
	SIGNAL_VERIFY_STATUS,
Bastien Nocera's avatar
Bastien Nocera committed
131
	SIGNAL_VERIFY_FINGER_SELECTED,
Daniel Drake's avatar
Daniel Drake committed
132
	SIGNAL_ENROLL_STATUS,
133 134 135
	NUM_SIGNALS,
};

Daniel Drake's avatar
Daniel Drake committed
136 137
static GObjectClass *parent_class = NULL;
static guint32 last_id = ~0;
138
static guint signals[NUM_SIGNALS] = { 0, };
Daniel Drake's avatar
Daniel Drake committed
139

140
static void fprint_device_finalize(GObject *object)
Daniel Drake's avatar
Daniel Drake committed
141
{
142 143 144 145
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	g_hash_table_destroy (priv->clients);
Daniel Drake's avatar
Daniel Drake committed
146 147 148
	/* FIXME close and stuff */
}

149
static void fprint_device_set_property(GObject *object, guint property_id,
Daniel Drake's avatar
Daniel Drake committed
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	const GValue *value, GParamSpec *pspec)
{
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	switch (property_id) {
	case FPRINT_DEVICE_CONSTRUCT_DDEV:
		priv->ddev = g_value_get_pointer(value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

Bastien Nocera's avatar
Bastien Nocera committed
165 166 167 168 169 170 171
static void fprint_device_get_property(GObject *object, guint property_id,
				       GValue *value, GParamSpec *pspec)
{
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	switch (property_id) {
172 173
	case FPRINT_DEVICE_IN_USE:
		g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0);
Bastien Nocera's avatar
Bastien Nocera committed
174
		break;
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
	case FPRINT_DEVICE_NAME:
		g_value_set_static_string (value, fp_driver_get_full_name (fp_dscv_dev_get_driver (priv->ddev)));
		break;
	case FPRINT_DEVICE_NUM_ENROLL:
		if (priv->dev)
			g_value_set_int (value, fp_dev_get_nr_enroll_stages (priv->dev));
		else
			g_value_set_int (value, -1);
		break;
	case FPRINT_DEVICE_SCAN_TYPE: {
		const char *type;

		if (fp_driver_get_scan_type (fp_dscv_dev_get_driver (priv->ddev)) == FP_SCAN_TYPE_PRESS)
			type = "press";
		else
			type = "swipe";

		g_value_set_static_string (value, type);
		break;
	}
Bastien Nocera's avatar
Bastien Nocera committed
195 196 197 198 199 200
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

201
static void fprint_device_class_init(FprintDeviceClass *klass)
Daniel Drake's avatar
Daniel Drake committed
202 203 204 205 206 207 208 209
{
	GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
	GParamSpec *pspec;

	dbus_g_object_type_install_info(FPRINT_TYPE_DEVICE,
		&dbus_glib_fprint_device_object_info);
	parent_class = g_type_class_peek_parent(klass);

210 211
	gobject_class->finalize = fprint_device_finalize;
	gobject_class->set_property = fprint_device_set_property;
Bastien Nocera's avatar
Bastien Nocera committed
212
	gobject_class->get_property = fprint_device_get_property;
213
	g_type_class_add_private(klass, sizeof(FprintDevicePrivate));
Daniel Drake's avatar
Daniel Drake committed
214 215

	pspec = g_param_spec_pointer("discovered-dev", "Discovered device",
216 217
				     "Set discovered device construction property",
				     G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
Daniel Drake's avatar
Daniel Drake committed
218
	g_object_class_install_property(gobject_class,
219 220
					FPRINT_DEVICE_CONSTRUCT_DDEV, pspec);

221
	pspec = g_param_spec_boolean("in-use", "In use",
222 223
				     "Whether the device is currently in use", FALSE,
				     G_PARAM_READABLE);
Bastien Nocera's avatar
Bastien Nocera committed
224
	g_object_class_install_property(gobject_class,
225
					FPRINT_DEVICE_IN_USE, pspec);
Daniel Drake's avatar
Daniel Drake committed
226

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
	pspec = g_param_spec_string("name", "Name",
				    "The product name of the device", NULL,
				    G_PARAM_READABLE);
	g_object_class_install_property(gobject_class,
					FPRINT_DEVICE_NAME, pspec);

	pspec = g_param_spec_string("scan-type", "Scan Type",
				    "The scan type of the device", "press",
				    G_PARAM_READABLE);
	g_object_class_install_property(gobject_class,
					FPRINT_DEVICE_SCAN_TYPE, pspec);

	pspec = g_param_spec_int("num-enroll-stages", "Number of enrollments stages",
				  "Number of enrollment stages for the device.",
				  -1, G_MAXINT, -1, G_PARAM_READABLE);
	g_object_class_install_property(gobject_class,
					FPRINT_DEVICE_NUM_ENROLL, pspec);

Daniel Drake's avatar
Daniel Drake committed
245 246
	signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
247
		fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
Daniel Drake's avatar
Daniel Drake committed
248
	signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status",
249
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
250
		fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
Bastien Nocera's avatar
Bastien Nocera committed
251 252
	signals[SIGNAL_VERIFY_FINGER_SELECTED] = g_signal_new("verify-finger-selected",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
253
		g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
Daniel Drake's avatar
Daniel Drake committed
254 255
}

Bastien Nocera's avatar
Bastien Nocera committed
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
static gboolean
pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
{
	int fd;
	PolKitContext *pk_context = user_data;
	fd = g_io_channel_unix_get_fd (channel);
	polkit_context_io_func (pk_context, fd);
	return TRUE;
}

static int 
pk_io_add_watch (PolKitContext *pk_context, int fd)
{
	guint id = 0;
	GIOChannel *channel;
	channel = g_io_channel_unix_new (fd);
	if (channel == NULL)
		goto out;
	id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context);
	if (id == 0) {
		g_io_channel_unref (channel);
		goto out;
	}
	g_io_channel_unref (channel);
out:
	return id;
}

static void 
pk_io_remove_watch (PolKitContext *pk_context, int watch_id)
{
	g_source_remove (watch_id);
}

290
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
291
{
292
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
293
	priv->id = ++last_id;
Bastien Nocera's avatar
Bastien Nocera committed
294 295 296 297 298 299 300 301 302

	/* Setup PolicyKit */
	priv->pol_ctx = polkit_context_new ();
	polkit_context_set_io_watch_functions (priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch);
	if (!polkit_context_init (priv->pol_ctx, NULL)) {
		g_critical ("cannot initialize libpolkit");
		polkit_context_unref (priv->pol_ctx);
		priv->pol_ctx = NULL;
	}
303 304 305 306
	priv->clients = g_hash_table_new_full (g_str_hash,
					       g_str_equal,
					       g_free,
					       g_object_unref);
Daniel Drake's avatar
Daniel Drake committed
307 308
}

309
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
310 311 312 313 314 315 316 317 318 319 320

FprintDevice *fprint_device_new(struct fp_dscv_dev *ddev)
{
	return g_object_new(FPRINT_TYPE_DEVICE, "discovered-dev", ddev, NULL);	
}

guint32 _fprint_device_get_id(FprintDevice *rdev)
{
	return DEVICE_GET_PRIVATE(rdev)->id;
}

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
static const char *
finger_num_to_name (int finger_num)
{
	if (finger_num == -1)
		return "any";
	if (finger_num < LEFT_THUMB || finger_num > RIGHT_LITTLE)
		return NULL;
	return fingers[finger_num - 1];
}

static int
finger_name_to_num (const char *finger_name)
{
	guint i;

	if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any"))
		return -1;

	for (i = 0; i < G_N_ELEMENTS (fingers); i++) {
		if (g_str_equal (finger_name, fingers[i]))
			return i + 1;
	}

	/* Invalid, let's try that */
	return -1;
}

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
static const char *
verify_result_to_name (int result)
{
	switch (result) {
	case FP_VERIFY_NO_MATCH:
		return "verify-no-match";
	case FP_VERIFY_MATCH:
		return "verify-match";
	case FP_VERIFY_RETRY:
		return "verify-retry-scan";
	case FP_VERIFY_RETRY_TOO_SHORT:
		return "verify-swipe-too-short";
	case FP_VERIFY_RETRY_CENTER_FINGER:
		return "verify-finger-not-centered";
	case FP_VERIFY_RETRY_REMOVE_FINGER:
		return "verify-remove-and-retry";
	default:
		return "verify-unknown-error";
	}
}

static const char *
enroll_result_to_name (int result)
{
	switch (result) {
	case FP_ENROLL_COMPLETE:
		return "enroll-completed";
	case FP_ENROLL_FAIL:
		return "enroll-failed";
	case FP_ENROLL_PASS:
		return "enroll-stage-passed";
	case FP_ENROLL_RETRY:
		return "enroll-retry-scan";
	case FP_ENROLL_RETRY_TOO_SHORT:
		return "enroll-swipe-too-short";
	case FP_ENROLL_RETRY_CENTER_FINGER:
		return "enroll-finger-not-centered";
	case FP_ENROLL_RETRY_REMOVE_FINGER:
		return "enroll-remove-and-retry";
	default:
		return "enroll-unknown-error";
	}
}

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
static gboolean
_fprint_device_check_claimed (FprintDevice *rdev,
			      DBusGMethodInvocation *context,
			      GError **error)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	DBusConnection *conn;
	char *sender;
	gboolean retval;

	/* The device wasn't claimed, exit */
	if (priv->sender == NULL) {
		g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			     _("Device was not claimed before use"));
		return FALSE;
	}

	conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
	sender = dbus_g_method_get_sender (context);
	retval = g_str_equal (sender, priv->sender);
	g_free (sender);

	if (retval == FALSE) {
		g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
			     _("Device already in use by another user"));
	}

	return retval;
}

Bastien Nocera's avatar
Bastien Nocera committed
422
static gboolean
Bastien Nocera's avatar
Bastien Nocera committed
423
_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
424 425 426 427 428 429 430
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
	DBusError dbus_error;
	PolKitCaller *pk_caller;
	PolKitAction *pk_action;
	PolKitResult pk_result;
431
	uid_t uid;
Bastien Nocera's avatar
Bastien Nocera committed
432 433 434 435 436 437 438 439 440

	/* Check that caller is privileged */
	sender = dbus_g_method_get_sender (context);
	dbus_error_init (&dbus_error);
	pk_caller = polkit_caller_new_from_dbus_name (
	    dbus_g_connection_get_connection (fprintd_dbus_conn),
	    sender, 
	    &dbus_error);
	if (pk_caller == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
441 442 443 444
		g_set_error (error, FPRINT_ERROR,
			     FPRINT_ERROR_INTERNAL,
			     "Error getting information about caller: %s: %s",
			     dbus_error.name, dbus_error.message);
Bastien Nocera's avatar
Bastien Nocera committed
445 446 447 448
		dbus_error_free (&dbus_error);
		return FALSE;
	}

449 450 451 452 453 454 455 456 457 458 459
	/* XXX Hack?
	 * We'd like to allow root to set the username by default, so
	 * it can authenticate users through PAM
	 * https://bugzilla.redhat.com/show_bug.cgi?id=447266 */
	if ((polkit_caller_get_uid (pk_caller, &uid) && uid == 0) &&
	    (g_str_equal (action, "net.reactivated.fprint.device.setusername") ||
	     g_str_equal (action, "net.reactivated.fprint.device.verify"))) {
		polkit_caller_unref (pk_caller);
		return TRUE;
	}

Bastien Nocera's avatar
Bastien Nocera committed
460 461 462
	pk_action = polkit_action_new ();
	polkit_action_set_action_id (pk_action, action);
	pk_result = polkit_context_is_caller_authorized (priv->pol_ctx, pk_action, pk_caller,
Bastien Nocera's avatar
Bastien Nocera committed
463
							 TRUE, NULL);
Bastien Nocera's avatar
Bastien Nocera committed
464 465 466 467
	polkit_caller_unref (pk_caller);
	polkit_action_unref (pk_action);

	if (pk_result != POLKIT_RESULT_YES) {
Bastien Nocera's avatar
Bastien Nocera committed
468
		g_set_error (error, FPRINT_ERROR,
469
			     FPRINT_ERROR_PERMISSION_DENIED,
Bastien Nocera's avatar
Bastien Nocera committed
470 471 472
			     "%s %s <-- (action, result)",
			     action,
			     polkit_result_to_string_representation (pk_result));
Bastien Nocera's avatar
Bastien Nocera committed
473 474 475 476 477 478 479
		dbus_error_free (&dbus_error);
		return FALSE;
	}

	return TRUE;
}

Bastien Nocera's avatar
Bastien Nocera committed
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
static gboolean
_fprint_device_check_polkit_for_actions (FprintDevice *rdev,
					 DBusGMethodInvocation *context,
					 const char *action1,
					 const char *action2,
					 GError **error)
{
	if (_fprint_device_check_polkit_for_action (rdev, context, action1, error) != FALSE)
		return TRUE;

	g_error_free (*error);
	*error = NULL;

	return _fprint_device_check_polkit_for_action (rdev, context, action2, error);
}

496 497 498 499 500 501
static char *
_fprint_device_check_for_username (FprintDevice *rdev,
				   DBusGMethodInvocation *context,
				   const char *username,
				   char **ret_sender,
				   GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
502
{
503 504 505 506 507 508
	DBusConnection *conn;
	DBusError dbus_error;
	char *sender;
	unsigned long uid;
	struct passwd *user;
	char *client_username;
Bastien Nocera's avatar
Bastien Nocera committed
509

510 511 512 513 514
	/* 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);
Bastien Nocera's avatar
Bastien Nocera committed
515

516 517 518 519
	if (dbus_error_is_set(&dbus_error)) {
		g_free (sender);
		dbus_set_g_error (error, &dbus_error);
		return NULL;
Bastien Nocera's avatar
Bastien Nocera committed
520 521
	}

522 523 524
	user = getpwuid (uid);
	if (user == NULL) {
		g_free (sender);
525
		g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
			    "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;
Bastien Nocera's avatar
Bastien Nocera committed
547 548
	}

549 550 551 552
	if (ret_sender != NULL)
		*ret_sender = sender;
	else
		g_free (sender);
Bastien Nocera's avatar
Bastien Nocera committed
553

554
	return g_strdup (username);
Bastien Nocera's avatar
Bastien Nocera committed
555 556
}

557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
static void action_stop_cb(struct fp_dev *dev, void *user_data)
{
	gboolean *done = (gboolean *) user_data;
	*done = TRUE;
}

static void
_fprint_device_client_disconnected (EggDbusMonitor *monitor, gboolean connected, FprintDevice *rdev)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);

	if (connected == FALSE) {
		const char *sender;
		sender = egg_dbus_monitor_get_service (monitor);

		/* Was that the client that claimed the device? */
		if (priv->sender != NULL) {
			gboolean done = FALSE;
			switch (priv->current_action) {
			case ACTION_NONE:
				break;
			case ACTION_IDENTIFY:
				fp_async_identify_stop(priv->dev, action_stop_cb, &done);
				while (done == FALSE)
					g_main_context_iteration (NULL, TRUE);
				break;
			case ACTION_VERIFY:
				fp_async_verify_stop(priv->dev, action_stop_cb, &done);
				while (done == FALSE)
					g_main_context_iteration (NULL, TRUE);
				break;
			case ACTION_ENROLL:
				fp_async_enroll_stop(priv->dev, action_stop_cb, &done);
				while (done == FALSE)
					g_main_context_iteration (NULL, TRUE);
				break;
			}
			priv->current_action = ACTION_NONE;
			done = FALSE;

			/* Close the claimed device as well */
			fp_async_dev_close (priv->dev, action_stop_cb, &done);
			while (done == FALSE)
				g_main_context_iteration (NULL, TRUE);

			g_free (priv->sender);
			priv->sender = NULL;
			g_free (priv->username);
			priv->username = NULL;
		}
		g_hash_table_remove (priv->clients, sender);
	}

	if (g_hash_table_size (priv->clients) == 0) {
		g_object_notify (G_OBJECT (rdev), "in-use");
	}
}

static void
_fprint_device_add_client (FprintDevice *rdev, const char *sender)
{
	EggDbusMonitor *monitor;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);

	monitor = g_hash_table_lookup (priv->clients, sender);
	if (monitor == NULL) {
		monitor = egg_dbus_monitor_new ();
		egg_dbus_monitor_assign (monitor, fprintd_dbus_conn, sender);
		//FIXME handle replaced
		g_signal_connect (G_OBJECT (monitor), "connection-changed",
					 G_CALLBACK (_fprint_device_client_disconnected), rdev);
		g_hash_table_insert (priv->clients, g_strdup (sender), monitor);
		g_object_notify (G_OBJECT (rdev), "in-use");
	}
}

Daniel Drake's avatar
Daniel Drake committed
633 634 635 636 637 638 639 640 641 642
static void dev_open_cb(struct fp_dev *dev, int status, void *user_data)
{
	FprintDevice *rdev = user_data;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;

	g_message("device %d claim status %d", priv->id, status);

	if (status != 0) {
		GError *error;
643 644 645 646

		g_free (priv->sender);
		priv->sender = NULL;

647
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
648 649 650 651 652 653 654 655 656
			"Open failed with error %d", status);
		dbus_g_method_return_error(session->context_claim_device, error);
		return;
	}

	priv->dev = dev;
	dbus_g_method_return(session->context_claim_device);
}

Bastien Nocera's avatar
Bastien Nocera committed
657
static void fprint_device_claim(FprintDevice *rdev,
658 659
				const char *username,
				DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
660 661 662
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
663
	char *sender, *user;
Daniel Drake's avatar
Daniel Drake committed
664 665
	int r;

666
	/* Is it already claimed? */
667
	if (priv->sender != NULL) {
668
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
669 670
			    "Device was already claimed");
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
671
		return;
672 673
	}

674 675
	g_assert (priv->username == NULL);
	g_assert (priv->sender == NULL);
Bastien Nocera's avatar
Bastien Nocera committed
676

677 678 679 680 681 682 683
	sender = NULL;
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  &sender,
						  &error);
	if (user == NULL) {
684
		g_free (sender);
685
		dbus_g_method_return_error (context, error);
686
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
687
		return;
688 689
	}

690 691 692 693
	if (_fprint_device_check_polkit_for_actions (rdev, context,
						     "net.reactivated.fprint.device.verify",
						     "net.reactivated.fprint.device.enroll",
						     &error) == FALSE) {
694
		g_free (sender);
695 696
		g_free (user);
		dbus_g_method_return_error (context, error);
697 698 699
		return;
	}

700 701
	_fprint_device_add_client (rdev, sender);

702
	priv->username = user;
703 704
	priv->sender = sender;

Bastien Nocera's avatar
Bastien Nocera committed
705
	g_message ("user '%s' claiming the device: %d", priv->username, priv->id);
706

Daniel Drake's avatar
Daniel Drake committed
707 708 709 710 711 712 713
	priv->session = g_slice_new0(struct session_data);
	priv->session->context_claim_device = context;

	r = fp_async_dev_open(priv->ddev, dev_open_cb, rdev);
	if (r < 0) {
		g_slice_free(struct session_data, priv->session);
		priv->session = NULL;
714 715 716 717 718 719

		g_free (priv->username);
		priv->username = NULL;
		g_free (priv->sender);
		priv->sender = NULL;

720
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
			"Could not attempt device open, error %d", r);
		dbus_g_method_return_error(context, error);
	}
}

static void dev_close_cb(struct fp_dev *dev, void *user_data)
{
	FprintDevice *rdev = user_data;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
	DBusGMethodInvocation *context = session->context_release_device;

	priv->dev = NULL;
	g_slice_free(struct session_data, session);
	priv->session = NULL;

737 738 739
	g_free (priv->sender);
	priv->sender = NULL;

740 741 742
	g_free (priv->username);
	priv->username = NULL;

Daniel Drake's avatar
Daniel Drake committed
743 744 745 746
	g_message("released device %d", priv->id);
	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
747
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
748 749 750 751
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
752 753 754 755
	GError *error = NULL;

	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
756
		return;
757
	}
Daniel Drake's avatar
Daniel Drake committed
758

Bastien Nocera's avatar
Bastien Nocera committed
759 760 761 762 763 764 765 766 767
	/* People that can claim can also release */
	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;
	}

Daniel Drake's avatar
Daniel Drake committed
768 769 770 771 772
	session->context_release_device = context;
	fp_async_dev_close(priv->dev, dev_close_cb, rdev);
}

static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img,
Bastien Nocera's avatar
Bastien Nocera committed
773 774 775
		      void *user_data)
{
	struct FprintDevice *rdev = user_data;
776
	const char *name = verify_result_to_name (r);
777 778
	gboolean done = FALSE;

779
	g_message("verify_cb: result %s (%d)", name, r);
Bastien Nocera's avatar
Bastien Nocera committed
780

781 782 783
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
		done = TRUE;
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, done);
Bastien Nocera's avatar
Bastien Nocera committed
784 785 786 787 788
	fp_img_free(img);
}

static void identify_cb(struct fp_dev *dev, int r,
			 size_t match_offset, struct fp_img *img, void *user_data)
Daniel Drake's avatar
Daniel Drake committed
789 790
{
	struct FprintDevice *rdev = user_data;
791
	const char *name = verify_result_to_name (r);
792 793
	gboolean done = FALSE;

794
	g_message("identify_cb: result %s (%d)", name, r);
Daniel Drake's avatar
Daniel Drake committed
795

796 797 798
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
		done = TRUE;
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, done);
799
	fp_img_free(img);
Daniel Drake's avatar
Daniel Drake committed
800 801
}

Bastien Nocera's avatar
Bastien Nocera committed
802
static void fprint_device_verify_start(FprintDevice *rdev,
803
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
804 805
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
Bastien Nocera's avatar
Bastien Nocera committed
806
	struct fp_print_data **gallery = NULL;
Daniel Drake's avatar
Daniel Drake committed
807
	struct fp_print_data *data = NULL;
808
	GError *error = NULL;
809
	guint finger_num = finger_name_to_num (finger_name);
Daniel Drake's avatar
Daniel Drake committed
810 811
	int r;

812 813
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
814
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
815
		return;
816 817
	}

Bastien Nocera's avatar
Bastien Nocera committed
818 819
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
820 821 822 823 824
		g_error_free (error);
		return;
	}

	if (priv->current_action != ACTION_NONE) {
Bastien Nocera's avatar
Bastien Nocera committed
825 826 827 828 829 830 831
		if (priv->current_action == ACTION_ENROLL) {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Enrollment in progress");
		} else {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Verification already in progress");
		}
Bastien Nocera's avatar
Bastien Nocera committed
832 833
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
834 835 836
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
837 838 839 840 841
	if (finger_num == -1) {
		GSList *prints;

		prints = store.discover_prints(priv->ddev, priv->username);
		if (prints == NULL) {
842
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
Bastien Nocera's avatar
Bastien Nocera committed
843 844
				    "No fingerprints enrolled");
			dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
845 846 847 848 849 850 851 852 853
			return;
		}
		if (fp_dev_supports_identification(priv->dev)) {
			GSList *l;
			GPtrArray *array;

			array = g_ptr_array_new ();

			for (l = prints; l != NULL; l = l->next) {
Bastien Nocera's avatar
Bastien Nocera committed
854 855
				g_message ("adding finger %d to the gallery", GPOINTER_TO_INT (l->data));
				r = store.print_data_load(priv->dev, GPOINTER_TO_INT (l->data),
Bastien Nocera's avatar
Bastien Nocera committed
856
							  &data, priv->username);
857 858
				if (r == 0)
					g_ptr_array_add (array, data);
Bastien Nocera's avatar
Bastien Nocera committed
859 860
			}
			data = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
861 862 863 864 865 866 867

			if (array->len > 0) {
				g_ptr_array_add (array,  NULL);
				gallery = (struct fp_print_data **) g_ptr_array_free (array, FALSE);
			} else {
				gallery = NULL;
			}
Bastien Nocera's avatar
Bastien Nocera committed
868
		} else {
Bastien Nocera's avatar
Bastien Nocera committed
869
			finger_num = GPOINTER_TO_INT (prints->data);
Bastien Nocera's avatar
Bastien Nocera committed
870 871
		}
		g_slist_free(prints);
Daniel Drake's avatar
Daniel Drake committed
872
	}
Bastien Nocera's avatar
Bastien Nocera committed
873

Bastien Nocera's avatar
Bastien Nocera committed
874
	if (fp_dev_supports_identification(priv->dev) && finger_num == -1) {
Bastien Nocera's avatar
Bastien Nocera committed
875
		if (gallery == NULL) {
876
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
877 878 879
				    "No fingerprints on that device");
			dbus_g_method_return_error(context, error);
			g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
880 881
			return;
		}
882
		priv->current_action = ACTION_IDENTIFY;
Bastien Nocera's avatar
Bastien Nocera committed
883 884 885 886 887

		g_message ("start identification device %d", priv->id);
		//FIXME we're supposed to free the gallery here?
		r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev);
	} else {
888
		priv->current_action = ACTION_VERIFY;
Bastien Nocera's avatar
Bastien Nocera committed
889 890 891 892 893 894 895

		g_message("start verification device %d finger %d", priv->id, finger_num);

		r = store.print_data_load(priv->dev, (enum fp_finger)finger_num, 
					  &data, priv->username);

		if (r < 0 || !data) {
896
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Bastien Nocera's avatar
Bastien Nocera committed
897 898 899 900
				    "No such print %d", finger_num);
			dbus_g_method_return_error(context, error);
			return;
		}
Bastien Nocera's avatar
Bastien Nocera committed
901

Bastien Nocera's avatar
Bastien Nocera committed
902 903 904 905
		/* FIXME fp_async_verify_start should copy the fp_print_data */
		r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	}

906 907
	/* Emit VerifyFingerSelected telling the front-end which finger
	 * we selected for auth */
908 909
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
		      0, finger_num_to_name (finger_num));
910 911


Daniel Drake's avatar
Daniel Drake committed
912
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
913 914 915 916 917 918 919 920
		if (data != NULL) {
			fp_print_data_free (data);
		} else if (gallery != NULL) {
			guint i;
			for (i = 0; gallery[i] != NULL; i++)
				fp_print_data_free(gallery[i]);
			g_free (gallery);
		}
921
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
922
			"Verify start failed with error %d", r);
923
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
924
		return;
Daniel Drake's avatar
Daniel Drake committed
925 926
	}

927
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
928 929 930 931 932 933 934
}

static void verify_stop_cb(struct fp_dev *dev, void *user_data)
{
	dbus_g_method_return((DBusGMethodInvocation *) user_data);
}

Bastien Nocera's avatar
Bastien Nocera committed
935 936 937 938 939
static void identify_stop_cb(struct fp_dev *dev, void *user_data)
{
	dbus_g_method_return((DBusGMethodInvocation *) user_data);
}

Bastien Nocera's avatar
Bastien Nocera committed
940
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
941 942 943
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
944
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
945 946
	int r;

947 948
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
949
		return;
950 951
	}

Bastien Nocera's avatar
Bastien Nocera committed
952 953 954 955 956
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
957
	if (priv->current_action == ACTION_VERIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
958
		r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
959
	} else if (priv->current_action == ACTION_IDENTIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
960
		r = fp_async_identify_stop(priv->dev, identify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
961
	} else {
962
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
963 964 965 966
			    "No verification in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
Bastien Nocera's avatar
Bastien Nocera committed
967
	}
Bastien Nocera's avatar
Bastien Nocera committed
968

Daniel Drake's avatar
Daniel Drake committed
969
	if (r < 0) {
970
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
971 972
			"Verify stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
973
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
974
	}
Bastien Nocera's avatar
Bastien Nocera committed
975

976
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
977 978
}

Daniel Drake's avatar
Daniel Drake committed
979 980 981 982 983 984
static void enroll_stage_cb(struct fp_dev *dev, int result,
	struct fp_print_data *print, struct fp_img *img, void *user_data)
{
	struct FprintDevice *rdev = user_data;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
985
	gboolean done = FALSE;
Bastien Nocera's avatar
Bastien Nocera committed
986
	int r;
Daniel Drake's avatar
Daniel Drake committed
987 988

	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
989
	if (result == FP_ENROLL_COMPLETE) {
990
		r = store.print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
991 992 993
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
994

995 996 997
	if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0)
		done = TRUE;
	g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, enroll_result_to_name (result), done);
Daniel Drake's avatar
Daniel Drake committed
998 999 1000 1001
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
1002
static void fprint_device_enroll_start(FprintDevice *rdev,
1003
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
1004 1005 1006
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
1007
	int finger_num = finger_name_to_num (finger_name);
1008
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1009 1010
	int r;

1011
	if (finger_num == -1) {
1012
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
1013 1014 1015 1016 1017 1018
			    "Invalid print name");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

1019 1020
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1021
		return;
1022 1023
	}

Bastien Nocera's avatar
Bastien Nocera committed
1024 1025 1026 1027 1028
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
	if (priv->current_action != ACTION_NONE) {
		if (priv->current_action == ACTION_ENROLL) {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Enrollment already in progress");
		} else {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Verification in progress");
		}
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

Daniel Drake's avatar
Daniel Drake committed
1042 1043 1044 1045 1046
	g_message("start enrollment device %d finger %d", priv->id, finger_num);
	session->enroll_finger = finger_num;
	
	r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev);
	if (r < 0) {
1047
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1048
			"Enroll start failed with error %d", r);
1049
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1050
		return;
Daniel Drake's avatar
Daniel Drake committed
1051 1052
	}

1053
	priv->current_action = ACTION_ENROLL;
Bastien Nocera's avatar
Bastien Nocera committed
1054

1055
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
1056 1057 1058 1059 1060 1061 1062
}

static void enroll_stop_cb(struct fp_dev *dev, void *user_data)
{
	dbus_g_method_return((DBusGMethodInvocation *) user_data);
}

Bastien Nocera's avatar
Bastien Nocera committed
1063
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
1064 1065 1066
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1067
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1068 1069
	int r;

1070 1071
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1072
		return;
1073 1074
	}

Bastien Nocera's avatar
Bastien Nocera committed
1075 1076 1077 1078 1079
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
1080
	if (priv->current_action != ACTION_ENROLL) {
1081
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
1082 1083 1084 1085 1086 1087
			    "No enrollment in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}