device.c 32.5 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);
Bastien Nocera's avatar
Bastien Nocera committed
71
72
static void fprint_device_get_properties (FprintDevice *rdev,
					  DBusGMethodInvocation *context);
Daniel Drake's avatar
Daniel Drake committed
73
74
75

#include "device-dbus-glue.h"

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

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

Daniel Drake's avatar
Daniel Drake committed
87
88
89
90
91
92
93
94
95
96
97
98
	/* 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;
99

Bastien Nocera's avatar
Bastien Nocera committed
100
101
	PolKitContext *pol_ctx;

102
103
104
	/* The current user of the device, if claimed */
	char *sender;

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

109
110
	/* type of storage */
	int storage_type;
Bastien Nocera's avatar
Bastien Nocera committed
111

112
113
114
	/* Hashtable of connected clients */
	GHashTable *clients;

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

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,
125
	FPRINT_DEVICE_IN_USE,
Daniel Drake's avatar
Daniel Drake committed
126
127
};

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

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

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

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

148
static void fprint_device_set_property(GObject *object, guint property_id,
Daniel Drake's avatar
Daniel Drake committed
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
	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
164
165
166
167
168
169
170
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) {
171
172
	case FPRINT_DEVICE_IN_USE:
		g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0);
Bastien Nocera's avatar
Bastien Nocera committed
173
174
175
176
177
178
179
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

180
static void fprint_device_class_init(FprintDeviceClass *klass)
Daniel Drake's avatar
Daniel Drake committed
181
182
183
184
185
186
187
188
{
	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);

189
190
	gobject_class->finalize = fprint_device_finalize;
	gobject_class->set_property = fprint_device_set_property;
Bastien Nocera's avatar
Bastien Nocera committed
191
	gobject_class->get_property = fprint_device_get_property;
192
	g_type_class_add_private(klass, sizeof(FprintDevicePrivate));
Daniel Drake's avatar
Daniel Drake committed
193
194
195
196
197
198

	pspec = g_param_spec_pointer("discovered-dev", "Discovered device",
		"Set discovered device construction property",
		G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
	g_object_class_install_property(gobject_class,
		FPRINT_DEVICE_CONSTRUCT_DDEV, pspec);
199
200
201
	pspec = g_param_spec_boolean("in-use", "In use",
				 "Whether the device is currently in use", FALSE,
				 G_PARAM_READABLE);
Bastien Nocera's avatar
Bastien Nocera committed
202
	g_object_class_install_property(gobject_class,
203
					FPRINT_DEVICE_IN_USE, pspec);
Daniel Drake's avatar
Daniel Drake committed
204

Daniel Drake's avatar
Daniel Drake committed
205
206
	signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
207
		fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
Daniel Drake's avatar
Daniel Drake committed
208
	signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status",
209
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
210
		fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
Bastien Nocera's avatar
Bastien Nocera committed
211
212
	signals[SIGNAL_VERIFY_FINGER_SELECTED] = g_signal_new("verify-finger-selected",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
213
		g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
Daniel Drake's avatar
Daniel Drake committed
214
215
}

Bastien Nocera's avatar
Bastien Nocera committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
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);
}

250
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
251
{
252
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
253
	priv->id = ++last_id;
Bastien Nocera's avatar
Bastien Nocera committed
254
255
256
257
258
259
260
261
262

	/* 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;
	}
263
264
265
266
	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
267
268
}

269
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
270
271
272
273
274
275
276
277
278
279
280

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;
}

281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
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;
}

308
309
310
311
312
313
314
315
316
317
318
319
320
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
348
349
350
351
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";
	}
}

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
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
382
static gboolean
Bastien Nocera's avatar
Bastien Nocera committed
383
_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
384
385
386
387
388
389
390
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
	DBusError dbus_error;
	PolKitCaller *pk_caller;
	PolKitAction *pk_action;
	PolKitResult pk_result;
391
	uid_t uid;
Bastien Nocera's avatar
Bastien Nocera committed
392
393
394
395
396
397
398
399
400

	/* 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
401
402
403
404
		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
405
406
407
408
		dbus_error_free (&dbus_error);
		return FALSE;
	}

409
410
411
412
413
414
415
416
417
418
419
	/* 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
420
421
422
	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
423
							 TRUE, NULL);
Bastien Nocera's avatar
Bastien Nocera committed
424
425
426
427
	polkit_caller_unref (pk_caller);
	polkit_action_unref (pk_action);

	if (pk_result != POLKIT_RESULT_YES) {
Bastien Nocera's avatar
Bastien Nocera committed
428
429
430
431
432
		g_set_error (error, FPRINT_ERROR,
			     FPRINT_ERROR_INTERNAL,
			     "%s %s <-- (action, result)",
			     action,
			     polkit_result_to_string_representation (pk_result));
Bastien Nocera's avatar
Bastien Nocera committed
433
434
435
436
437
438
439
		dbus_error_free (&dbus_error);
		return FALSE;
	}

	return TRUE;
}

Bastien Nocera's avatar
Bastien Nocera committed
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
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);
}

456
457
458
459
460
461
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
462
{
463
464
465
466
467
468
	DBusConnection *conn;
	DBusError dbus_error;
	char *sender;
	unsigned long uid;
	struct passwd *user;
	char *client_username;
Bastien Nocera's avatar
Bastien Nocera committed
469

470
471
472
473
474
	/* 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
475

476
477
478
479
	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
480
481
	}

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
	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;
Bastien Nocera's avatar
Bastien Nocera committed
507
508
	}

509
510
511
512
	if (ret_sender != NULL)
		*ret_sender = sender;
	else
		g_free (sender);
Bastien Nocera's avatar
Bastien Nocera committed
513

514
	return g_strdup (username);
Bastien Nocera's avatar
Bastien Nocera committed
515
516
}

517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
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
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
593
594
595
596
597
598
599
600
601
602
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;
603
604
605
606

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

Daniel Drake's avatar
Daniel Drake committed
607
608
609
610
611
612
613
614
615
616
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			"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
617
static void fprint_device_claim(FprintDevice *rdev,
618
619
				const char *username,
				DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
620
621
622
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
623
	char *sender, *user;
Daniel Drake's avatar
Daniel Drake committed
624
625
	int r;

626
	/* Is it already claimed? */
627
628
629
630
	if (priv->sender != NULL) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			    "Device was already claimed");
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
631
		return;
632
633
	}

634
635
	g_assert (priv->username == NULL);
	g_assert (priv->sender == NULL);
Bastien Nocera's avatar
Bastien Nocera committed
636

637
638
639
640
641
642
643
	sender = NULL;
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  &sender,
						  &error);
	if (user == NULL) {
644
		g_free (sender);
645
		dbus_g_method_return_error (context, error);
646
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
647
		return;
648
649
	}

650
651
652
653
	if (_fprint_device_check_polkit_for_actions (rdev, context,
						     "net.reactivated.fprint.device.verify",
						     "net.reactivated.fprint.device.enroll",
						     &error) == FALSE) {
654
		g_free (sender);
655
656
		g_free (user);
		dbus_g_method_return_error (context, error);
657
658
659
		return;
	}

660
661
	_fprint_device_add_client (rdev, sender);

662
	priv->username = user;
663
664
	priv->sender = sender;

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

Daniel Drake's avatar
Daniel Drake committed
667
668
669
670
671
672
673
	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;
674
675
676
677
678
679

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

Daniel Drake's avatar
Daniel Drake committed
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			"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;

697
698
699
	g_free (priv->sender);
	priv->sender = NULL;

700
701
702
	g_free (priv->username);
	priv->username = NULL;

Daniel Drake's avatar
Daniel Drake committed
703
704
705
706
	g_message("released device %d", priv->id);
	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
707
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
708
709
710
711
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
712
713
714
715
	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
716
		return;
717
	}
Daniel Drake's avatar
Daniel Drake committed
718

Bastien Nocera's avatar
Bastien Nocera committed
719
720
721
722
723
724
725
726
727
	/* 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
728
729
730
731
732
	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
733
734
735
		      void *user_data)
{
	struct FprintDevice *rdev = user_data;
736
	const char *name = verify_result_to_name (r);
737
738
	gboolean done = FALSE;

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

741
742
743
	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
744
745
746
747
748
	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
749
750
{
	struct FprintDevice *rdev = user_data;
751
	const char *name = verify_result_to_name (r);
752
753
	gboolean done = FALSE;

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

756
757
758
	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);
759
	fp_img_free(img);
Daniel Drake's avatar
Daniel Drake committed
760
761
}

Bastien Nocera's avatar
Bastien Nocera committed
762
static void fprint_device_verify_start(FprintDevice *rdev,
763
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
764
765
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
Bastien Nocera's avatar
Bastien Nocera committed
766
	struct fp_print_data **gallery = NULL;
Daniel Drake's avatar
Daniel Drake committed
767
	struct fp_print_data *data = NULL;
768
	GError *error = NULL;
769
	guint finger_num = finger_name_to_num (finger_name);
Daniel Drake's avatar
Daniel Drake committed
770
771
	int r;

772
773
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
774
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
775
		return;
776
777
	}

Bastien Nocera's avatar
Bastien Nocera committed
778
779
	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
780
781
782
783
784
		g_error_free (error);
		return;
	}

	if (priv->current_action != ACTION_NONE) {
Bastien Nocera's avatar
Bastien Nocera committed
785
786
787
788
789
790
791
		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
792
793
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
794
795
796
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
797
798
799
800
801
	if (finger_num == -1) {
		GSList *prints;

		prints = store.discover_prints(priv->ddev, priv->username);
		if (prints == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
802
803
804
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
				    "No fingerprints enrolled");
			dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
805
806
807
808
809
810
811
812
813
			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
814
815
				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
816
817
818
819
820
							  &data, priv->username);
				//FIXME r < 0 ?
				g_ptr_array_add (array, data);
			}
			data = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
821
822
823
824
825
826
827

			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
828
		} else {
Bastien Nocera's avatar
Bastien Nocera committed
829
			finger_num = GPOINTER_TO_INT (prints->data);
Bastien Nocera's avatar
Bastien Nocera committed
830
831
		}
		g_slist_free(prints);
Daniel Drake's avatar
Daniel Drake committed
832
	}
Bastien Nocera's avatar
Bastien Nocera committed
833

Bastien Nocera's avatar
Bastien Nocera committed
834
	if (fp_dev_supports_identification(priv->dev) && finger_num == -1) {
Bastien Nocera's avatar
Bastien Nocera committed
835
		if (gallery == NULL) {
836
837
838
839
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
				    "No fingerprints on that device");
			dbus_g_method_return_error(context, error);
			g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
840
841
			return;
		}
842
		priv->current_action = ACTION_IDENTIFY;
Bastien Nocera's avatar
Bastien Nocera committed
843
844
845
846
847

		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 {
848
		priv->current_action = ACTION_VERIFY;
Bastien Nocera's avatar
Bastien Nocera committed
849
850
851
852
853
854
855
856
857
858
859
860

		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) {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
				    "No such print %d", finger_num);
			dbus_g_method_return_error(context, error);
			return;
		}
Bastien Nocera's avatar
Bastien Nocera committed
861

Bastien Nocera's avatar
Bastien Nocera committed
862
863
864
865
		/* FIXME fp_async_verify_start should copy the fp_print_data */
		r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	}

866
867
	/* Emit VerifyFingerSelected telling the front-end which finger
	 * we selected for auth */
868
869
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
		      0, finger_num_to_name (finger_num));
870
871


Daniel Drake's avatar
Daniel Drake committed
872
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
873
874
875
876
877
878
879
880
		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);
		}
881
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_START,
Daniel Drake's avatar
Daniel Drake committed
882
			"Verify start failed with error %d", r);
883
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
884
		return;
Daniel Drake's avatar
Daniel Drake committed
885
886
	}

887
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
888
889
890
891
892
893
894
}

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
895
896
897
898
899
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
900
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
901
902
903
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
904
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
905
906
	int r;

907
908
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
909
		return;
910
911
	}

Bastien Nocera's avatar
Bastien Nocera committed
912
913
914
915
916
	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
917
	if (priv->current_action == ACTION_VERIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
918
		r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
919
	} else if (priv->current_action == ACTION_IDENTIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
920
		r = fp_async_identify_stop(priv->dev, identify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
921
922
923
924
925
926
	} else {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_STOP,
			    "No verification in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
Bastien Nocera's avatar
Bastien Nocera committed
927
	}
Bastien Nocera's avatar
Bastien Nocera committed
928

Daniel Drake's avatar
Daniel Drake committed
929
930
931
932
	if (r < 0) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_STOP,
			"Verify stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
933
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
934
	}
Bastien Nocera's avatar
Bastien Nocera committed
935

936
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
937
938
}

Daniel Drake's avatar
Daniel Drake committed
939
940
941
942
943
944
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;
945
	gboolean done = FALSE;
Bastien Nocera's avatar
Bastien Nocera committed
946
	int r;
Daniel Drake's avatar
Daniel Drake committed
947
948

	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
949
	if (result == FP_ENROLL_COMPLETE) {
950
		r = store.print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
951
952
953
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
954

955
956
957
	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
958
959
960
961
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
962
static void fprint_device_enroll_start(FprintDevice *rdev,
963
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
964
965
966
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
967
	int finger_num = finger_name_to_num (finger_name);
968
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
969
970
	int r;

971
972
973
974
975
976
977
978
	if (finger_num == -1) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
			    "Invalid print name");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

979
980
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
981
		return;
982
983
	}

Bastien Nocera's avatar
Bastien Nocera committed
984
985
986
987
988
	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
989
990
991
992
993
994
995
996
997
998
999
1000
1001
	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
1002
1003
1004
1005
1006
	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) {
1007
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_START,
Daniel Drake's avatar
Daniel Drake committed
1008
			"Enroll start failed with error %d", r);
1009
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1010
		return;
Daniel Drake's avatar
Daniel Drake committed
1011
1012
	}

1013
	priv->current_action = ACTION_ENROLL;
Bastien Nocera's avatar
Bastien Nocera committed
1014

1015
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
1016
1017
1018
1019
1020
1021
1022
}

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
1023
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
1024
1025
1026
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1027
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1028
1029
	int r;

1030
1031
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1032
		return;
1033
1034
	}

Bastien Nocera's avatar
Bastien Nocera committed
1035
1036
1037
1038
1039
	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
1040
1041
1042
1043
1044
1045
1046
1047
	if (priv->current_action != ACTION_ENROLL) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_STOP,
			    "No enrollment in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

Daniel Drake's avatar
Daniel Drake committed
1048
1049
1050
1051
1052
	r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context);
	if (r < 0) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_STOP,
			"Enroll stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1053
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1054
	}
Bastien Nocera's avatar
Bastien Nocera committed
1055

1056
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1057
1058
}

1059
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
1060
1061
						const char *username,
						DBusGMethodInvocation *context)
1062
1063
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1064
	GError *error = NULL;
1065
1066
	GSList *prints;
	GSList *item;
1067
	GPtrArray *ret;
1068
	char *user, *sender;
1069
1070
1071
1072
1073
1074
1075

	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
1076
		dbus_g_method_return_error (context, error);
1077
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
1078
		return;
1079
1080
	}

Bastien Nocera's avatar
Bastien Nocera committed
1081
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
1082
		g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1083
1084
1085
1086
		dbus_g_method_return_error (context, error);
		return;
	}

1087
1088
1089
1090
	sender = dbus_g_method_get_sender (context);
	_fprint_device_add_client (rdev, sender);
	g_free (sender);

1091
1092
	prints = store.discover_prints(priv->ddev, user);
	g_free (user);
1093
	if (!prints) {
1094
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS,
1095
			"Failed to discover prints");
1096
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1097
		return;
1098
1099
	}

1100
	ret = g_ptr_array_new ();
1101
	for (item = prints; item; item = item->next) {
1102
1103
		int finger_num = GPOINTER_TO_INT (item->data);
		g_ptr_array_add (ret, g_strdup (finger_num_to_name (finger_num)));
1104
	}
1105
	g_ptr_array_add (ret, NULL);
1106
1107

	g_slist_free(prints);
1108

1109
	dbus_g_method_return(context, g_ptr_array_free (ret, FALSE));
1110
1111
}

Bastien Nocera's avatar
Bastien Nocera committed
1112
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
1113
						  const char *username,
Bastien Nocera's avatar
Bastien Nocera committed
1114
1115
1116
1117
1118
						  DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
	guint i;
1119
	char *user, *sender;
Bastien Nocera's avatar
Bastien Nocera committed
1120

1121
1122
1123
1124
1125
1126
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
1127
		dbus_g_method_return_error (context, error);
1128
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
1129
1130
1131
		return;
	}

1132
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
1133
		g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1134
1135
1136
1137
		dbus_g_method_return_error (context, error);
		return;
	}

1138
1139
1140
1141
	sender = dbus_g_method_get_sender (context);
	_fprint_device_add_client (rdev, sender);
	g_free (sender);

Bastien Nocera's avatar
Bastien Nocera committed
1142
	for (i = LEFT_THUMB; i <= RIGHT_LITTLE; i++) {
1143
		store.print_data_delete(priv->ddev, i, user);
Bastien Nocera's avatar
Bastien Nocera committed
1144
	}
1145
	g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1146
1147
1148
1149

	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
1150
1151
static void fprint_device_get_properties (FprintDevice *rdev,
					  DBusGMethodInvocation *context)
Bastien Nocera's avatar
Bastien Nocera committed
1152
1153
1154
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GHashTable *table;
1155
	GValue *value;
Bastien Nocera's avatar
Bastien Nocera committed
1156
1157
1158

	table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);

1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
	value = g_new0 (GValue, 1);
	g_value_init (value, G_TYPE_STRING);
	g_value_set_string (value, fp_driver_get_full_name (fp_dscv_dev_get_driver (priv->ddev)));
	g_hash_table_insert (table, "Name", value);

	value = g_new0 (GValue, 1);
	g_value_init (value, G_TYPE_STRING);
	g_value_set_static_string (value,
				   fp_driver_get_scan_type (fp_dscv_dev_get_driver (priv->ddev)) == FP_SCAN_TYPE_PRESS ? "press" : "swipe");
	g_hash_table_insert (table, "ScanType", value);

	if (priv->dev != NULL) {
		value = g_new0 (GValue, 1);
		g_value_init (value, G_TYPE_INT);
		g_value_set_int (value, fp_dev_get_nr_enroll_stages (priv->dev));
		g_hash_table_insert (table, "NumberEnrollStages", value);
	}
Bastien Nocera's avatar
Bastien Nocera committed
1176

Bastien Nocera's avatar
Bastien Nocera committed
1177
	dbus_g_method_return (context, table);
1178
1179

	g_hash_table_destroy (table);
Bastien Nocera's avatar
Bastien Nocera committed
1180
1181
}