device.c 33 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
#include <polkit/polkit.h>
Daniel Drake's avatar
Daniel Drake committed
26
27
#include <libfprint/fprint.h>

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

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

Matthias Clasen's avatar
Matthias Clasen committed
98
	PolkitAuthority *auth;
Bastien Nocera's avatar
Bastien Nocera committed
99

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
114
115
116
117
	/* The data passed to fp_async_verify_start or
	 * fp_async_identify_start */
	struct fp_print_data *verify_data;
	struct fp_print_data **identify_data;

Bastien Nocera's avatar
Bastien Nocera committed
118
	/* whether we're running an identify, or a verify */
Bastien Nocera's avatar
Bastien Nocera committed
119
	FprintDeviceAction current_action;
120
121
	/* Whether we should ignore new signals on the device */
	gboolean action_done;
122
123
	/* Whether the device was disconnected */
	gboolean disconnected;
Daniel Drake's avatar
Daniel Drake committed
124
125
126
127
128
129
130
131
};

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,
132
	FPRINT_DEVICE_IN_USE,
133
134
135
	FPRINT_DEVICE_NAME,
	FPRINT_DEVICE_NUM_ENROLL,
	FPRINT_DEVICE_SCAN_TYPE
Daniel Drake's avatar
Daniel Drake committed
136
137
};

138
enum fprint_device_signals {
Daniel Drake's avatar
Daniel Drake committed
139
	SIGNAL_VERIFY_STATUS,
Bastien Nocera's avatar
Bastien Nocera committed
140
	SIGNAL_VERIFY_FINGER_SELECTED,
Daniel Drake's avatar
Daniel Drake committed
141
	SIGNAL_ENROLL_STATUS,
142
143
144
	NUM_SIGNALS,
};

Daniel Drake's avatar
Daniel Drake committed
145
146
static GObjectClass *parent_class = NULL;
static guint32 last_id = ~0;
147
static guint signals[NUM_SIGNALS] = { 0, };
Daniel Drake's avatar
Daniel Drake committed
148

149
static void fprint_device_finalize(GObject *object)
Daniel Drake's avatar
Daniel Drake committed
150
{
151
152
153
154
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	g_hash_table_destroy (priv->clients);
Daniel Drake's avatar
Daniel Drake committed
155
156
157
	/* FIXME close and stuff */
}

158
static void fprint_device_set_property(GObject *object, guint property_id,
Daniel Drake's avatar
Daniel Drake committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
	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
174
175
176
177
178
179
180
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) {
181
182
	case FPRINT_DEVICE_IN_USE:
		g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0);
Bastien Nocera's avatar
Bastien Nocera committed
183
		break;
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
	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
204
205
206
207
208
209
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

210
static void fprint_device_class_init(FprintDeviceClass *klass)
Daniel Drake's avatar
Daniel Drake committed
211
212
213
214
215
216
217
218
{
	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);

219
220
	gobject_class->finalize = fprint_device_finalize;
	gobject_class->set_property = fprint_device_set_property;
Bastien Nocera's avatar
Bastien Nocera committed
221
	gobject_class->get_property = fprint_device_get_property;
222
	g_type_class_add_private(klass, sizeof(FprintDevicePrivate));
Daniel Drake's avatar
Daniel Drake committed
223
224

	pspec = g_param_spec_pointer("discovered-dev", "Discovered device",
225
226
				     "Set discovered device construction property",
				     G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
Daniel Drake's avatar
Daniel Drake committed
227
	g_object_class_install_property(gobject_class,
228
229
					FPRINT_DEVICE_CONSTRUCT_DDEV, pspec);

230
	pspec = g_param_spec_boolean("in-use", "In use",
231
232
				     "Whether the device is currently in use", FALSE,
				     G_PARAM_READABLE);
Bastien Nocera's avatar
Bastien Nocera committed
233
	g_object_class_install_property(gobject_class,
234
					FPRINT_DEVICE_IN_USE, pspec);
Daniel Drake's avatar
Daniel Drake committed
235

236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
	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
254
255
	signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
256
		fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
Daniel Drake's avatar
Daniel Drake committed
257
	signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status",
258
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
259
		fprintd_marshal_VOID__STRING_BOOLEAN, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);
Bastien Nocera's avatar
Bastien Nocera committed
260
261
	signals[SIGNAL_VERIFY_FINGER_SELECTED] = g_signal_new("verify-finger-selected",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
262
		g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
Daniel Drake's avatar
Daniel Drake committed
263
264
}

265
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
266
{
267
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
268
	priv->id = ++last_id;
Bastien Nocera's avatar
Bastien Nocera committed
269
270

	/* Setup PolicyKit */
Matthias Clasen's avatar
Matthias Clasen committed
271
	priv->auth = polkit_authority_get ();
272
273
274
275
	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
276
277
}

278
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
279
280
281
282
283
284
285
286
287
288
289

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

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
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;
}

317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
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";
333
334
	case -EPROTO:
		return "verify-disconnected";
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
	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";
358
359
	case -EPROTO:
		return "enroll-disconnected";
360
361
362
363
364
	default:
		return "enroll-unknown-error";
	}
}

365
366
367
368
369
370
371
372
static void
set_disconnected (FprintDevicePrivate *priv, const char *res)
{
	if (g_str_equal (res, "enroll-disconnected") ||
	    g_str_equal (res, "verify-disconnected"))
		priv->disconnected = TRUE;
}

373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
static gboolean
_fprint_device_check_claimed (FprintDevice *rdev,
			      DBusGMethodInvocation *context,
			      GError **error)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	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;
	}

	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
401
static gboolean
Bastien Nocera's avatar
Bastien Nocera committed
402
_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
403
404
405
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
Matthias Clasen's avatar
Matthias Clasen committed
406
407
408
	PolkitSubject *subject;
	PolkitAuthorizationResult *result;
	GError *_error = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
409
410
411

	/* Check that caller is privileged */
	sender = dbus_g_method_get_sender (context);
Matthias Clasen's avatar
Matthias Clasen committed
412
413
414
415
416
417
418
419
420
421
422
	subject = polkit_system_bus_name_new (sender);

	result = polkit_authority_check_authorization_sync (priv->auth,
                                                            subject,
                                                            action,
							    NULL,
                                                            POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
					                    NULL, &_error);
	g_object_unref (subject);

	if (result == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
423
		g_set_error (error, FPRINT_ERROR,
Matthias Clasen's avatar
Matthias Clasen committed
424
425
426
			     FPRINT_ERROR_PERMISSION_DENIED,
			     "Not Authorized: %s", _error->message);
		g_error_free (_error);
Bastien Nocera's avatar
Bastien Nocera committed
427
428
429
		return FALSE;
	}

Matthias Clasen's avatar
Matthias Clasen committed
430
	if (!polkit_authorization_result_get_is_authorized (result)) {
Bastien Nocera's avatar
Bastien Nocera committed
431
		g_set_error (error, FPRINT_ERROR,
432
			     FPRINT_ERROR_PERMISSION_DENIED,
Matthias Clasen's avatar
Matthias Clasen committed
433
434
			     "Not Authorized: %s", action);
		g_object_unref (result);
Bastien Nocera's avatar
Bastien Nocera committed
435
436
437
		return FALSE;
	}

Matthias Clasen's avatar
Matthias Clasen committed
438
439
	g_object_unref (result);

Bastien Nocera's avatar
Bastien Nocera committed
440
441
442
	return TRUE;
}

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

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

473
474
475
476
477
	/* 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
478

479
480
481
482
	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
483
484
	}

485
486
487
	user = getpwuid (uid);
	if (user == NULL) {
		g_free (sender);
488
		g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
			    "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
510
511
	}

512
513
514
515
	if (ret_sender != NULL)
		*ret_sender = sender;
	else
		g_free (sender);
Bastien Nocera's avatar
Bastien Nocera committed
516

517
	return g_strdup (username);
Bastien Nocera's avatar
Bastien Nocera committed
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
593
594
595
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
596
597
598
599
600
601
602
603
604
605
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;
606
607
608
609

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

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

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

637
638
	g_assert (priv->username == NULL);
	g_assert (priv->sender == NULL);
Bastien Nocera's avatar
Bastien Nocera committed
639

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

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

663
664
	_fprint_device_add_client (rdev, sender);

665
	priv->username = user;
666
667
	priv->sender = sender;

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

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

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

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

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

703
704
705
	g_free (priv->username);
	priv->username = NULL;

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

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

Bastien Nocera's avatar
Bastien Nocera committed
722
723
724
725
726
727
728
729
730
	/* 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
731
732
733
734
735
	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
736
737
738
		      void *user_data)
{
	struct FprintDevice *rdev = user_data;
Bastien Nocera's avatar
Bastien Nocera committed
739
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
740
	const char *name = verify_result_to_name (r);
741
742
743

	if (priv->action_done != FALSE)
		return;
744

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

747
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
748
		priv->action_done = TRUE;
749
	set_disconnected (priv, name);
750
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, priv->action_done);
Bastien Nocera's avatar
Bastien Nocera committed
751
	fp_img_free(img);
Bastien Nocera's avatar
Bastien Nocera committed
752

753
	if (priv->action_done && priv->verify_data) {
Bastien Nocera's avatar
Bastien Nocera committed
754
755
756
		fp_print_data_free (priv->verify_data);
		priv->verify_data = NULL;
	}
Bastien Nocera's avatar
Bastien Nocera committed
757
758
759
760
}

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
761
762
{
	struct FprintDevice *rdev = user_data;
Bastien Nocera's avatar
Bastien Nocera committed
763
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
764
	const char *name = verify_result_to_name (r);
765
766
767

	if (priv->action_done != FALSE)
		return;
768

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

771
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
772
		priv->action_done = TRUE;
773
	set_disconnected (priv, name);
774
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, priv->action_done);
775
	fp_img_free(img);
Bastien Nocera's avatar
Bastien Nocera committed
776

777
	if (priv->action_done && priv->identify_data != NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
778
779
780
781
782
783
		guint i;
		for (i = 0; priv->identify_data[i] != NULL; i++)
			fp_print_data_free(priv->identify_data[i]);
		g_free (priv->identify_data);
		priv->identify_data = NULL;
	}
Daniel Drake's avatar
Daniel Drake committed
784
785
}

Bastien Nocera's avatar
Bastien Nocera committed
786
static void fprint_device_verify_start(FprintDevice *rdev,
787
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
788
789
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
Bastien Nocera's avatar
Bastien Nocera committed
790
	struct fp_print_data **gallery = NULL;
Daniel Drake's avatar
Daniel Drake committed
791
	struct fp_print_data *data = NULL;
792
	GError *error = NULL;
793
	guint finger_num = finger_name_to_num (finger_name);
Daniel Drake's avatar
Daniel Drake committed
794
795
	int r;

796
797
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
798
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
799
		return;
800
801
	}

Bastien Nocera's avatar
Bastien Nocera committed
802
803
	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
804
805
806
807
808
		g_error_free (error);
		return;
	}

	if (priv->current_action != ACTION_NONE) {
Bastien Nocera's avatar
Bastien Nocera committed
809
810
811
812
813
814
815
		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
816
817
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
818
819
		return;
	}
820
	priv->action_done = FALSE;
Bastien Nocera's avatar
Bastien Nocera committed
821

Bastien Nocera's avatar
Bastien Nocera committed
822
823
824
825
826
	if (finger_num == -1) {
		GSList *prints;

		prints = store.discover_prints(priv->ddev, priv->username);
		if (prints == NULL) {
827
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
Bastien Nocera's avatar
Bastien Nocera committed
828
829
				    "No fingerprints enrolled");
			dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
830
831
832
833
834
835
836
837
838
			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
839
840
				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
841
							  &data, priv->username);
842
843
				if (r == 0)
					g_ptr_array_add (array, data);
Bastien Nocera's avatar
Bastien Nocera committed
844
845
			}
			data = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
846
847
848
849
850
851
852

			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
853
		} else {
Bastien Nocera's avatar
Bastien Nocera committed
854
			finger_num = GPOINTER_TO_INT (prints->data);
Bastien Nocera's avatar
Bastien Nocera committed
855
856
		}
		g_slist_free(prints);
Daniel Drake's avatar
Daniel Drake committed
857
	}
Bastien Nocera's avatar
Bastien Nocera committed
858

Bastien Nocera's avatar
Bastien Nocera committed
859
	if (fp_dev_supports_identification(priv->dev) && finger_num == -1) {
Bastien Nocera's avatar
Bastien Nocera committed
860
		if (gallery == NULL) {
861
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
862
863
864
				    "No fingerprints on that device");
			dbus_g_method_return_error(context, error);
			g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
865
866
			return;
		}
867
		priv->current_action = ACTION_IDENTIFY;
Bastien Nocera's avatar
Bastien Nocera committed
868
869
870
871

		g_message ("start identification device %d", priv->id);
		r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev);
	} else {
872
		priv->current_action = ACTION_VERIFY;
Bastien Nocera's avatar
Bastien Nocera committed
873
874
875
876
877
878
879

		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) {
880
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Bastien Nocera's avatar
Bastien Nocera committed
881
882
883
884
				    "No such print %d", finger_num);
			dbus_g_method_return_error(context, error);
			return;
		}
Bastien Nocera's avatar
Bastien Nocera committed
885

Bastien Nocera's avatar
Bastien Nocera committed
886
887
888
		r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	}

889
890
	/* Emit VerifyFingerSelected telling the front-end which finger
	 * we selected for auth */
891
892
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
		      0, finger_num_to_name (finger_num));
893
894


Daniel Drake's avatar
Daniel Drake committed
895
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
896
897
898
899
900
901
902
903
		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);
		}
904
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
905
			"Verify start failed with error %d", r);
906
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
907
		return;
Daniel Drake's avatar
Daniel Drake committed
908
	}
Bastien Nocera's avatar
Bastien Nocera committed
909
910
	priv->verify_data = data;
	priv->identify_data = gallery;
Daniel Drake's avatar
Daniel Drake committed
911

912
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
913
914
915
916
917
918
919
}

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
920
921
922
923
924
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
925
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
926
927
928
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
929
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
930
931
	int r;

932
933
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
934
		return;
935
936
	}

Bastien Nocera's avatar
Bastien Nocera committed
937
938
939
940
941
	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
942
	if (priv->current_action == ACTION_VERIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
943
944
945
946
		if (priv->verify_data) {
			fp_print_data_free (priv->verify_data);
			priv->verify_data = NULL;
		}
947
948
949
950
		if (!priv->disconnected)
			r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
		else
			r = 0;
Bastien Nocera's avatar
Bastien Nocera committed
951
	} else if (priv->current_action == ACTION_IDENTIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
952
953
954
955
956
957
958
		if (priv->identify_data != NULL) {
			guint i;
			for (i = 0; priv->identify_data[i] != NULL; i++)
				fp_print_data_free(priv->identify_data[i]);
			g_free (priv->identify_data);
			priv->identify_data = NULL;
		}
959
960
961
962
		if (!priv->disconnected)
			r = fp_async_identify_stop(priv->dev, identify_stop_cb, context);
		else
			r = 0;
Bastien Nocera's avatar
Bastien Nocera committed
963
	} else {
964
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
965
966
967
968
			    "No verification in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
Bastien Nocera's avatar
Bastien Nocera committed
969
	}
Bastien Nocera's avatar
Bastien Nocera committed
970

Daniel Drake's avatar
Daniel Drake committed
971
	if (r < 0) {
972
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
973
974
			"Verify stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
975
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
976
	}
977
978
	if (priv->disconnected)
		dbus_g_method_return(context);
Bastien Nocera's avatar
Bastien Nocera committed
979

980
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
981
982
}

Daniel Drake's avatar
Daniel Drake committed
983
984
985
986
987
988
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;
989
	const char *name = enroll_result_to_name (result);
Bastien Nocera's avatar
Bastien Nocera committed
990
	int r;
Daniel Drake's avatar
Daniel Drake committed
991

992
993
994
995
	/* We're done, ignore new events for the action */
	if (priv->action_done != FALSE)
		return;

Daniel Drake's avatar
Daniel Drake committed
996
	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
997
	if (result == FP_ENROLL_COMPLETE) {
998
		r = store.print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
999
1000
1001
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
1002

1003
	if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0)
1004
		priv->action_done = TRUE;
1005
	set_disconnected (priv, name);
1006

1007
	g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, name, priv->action_done);
1008

Daniel Drake's avatar
Daniel Drake committed
1009
1010
1011
1012
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
1013
static void fprint_device_enroll_start(FprintDevice *rdev,
1014
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
1015
1016
1017
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
1018
	int finger_num = finger_name_to_num (finger_name);
1019
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1020
1021
	int r;

1022
	if (finger_num == -1) {
1023
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
1024
1025
1026
1027
1028
1029
			    "Invalid print name");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

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
1048
1049
1050
1051
1052
	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
1053
1054
	g_message("start enrollment device %d finger %d", priv->id, finger_num);
	session->enroll_finger = finger_num;
1055
	priv->action_done = FALSE;
Daniel Drake's avatar
Daniel Drake committed
1056
1057
1058
	
	r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev);
	if (r < 0) {
1059
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1060
			"Enroll start failed with error %d", r);
1061
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1062
		return;
Daniel Drake's avatar
Daniel Drake committed
1063
1064
	}

1065
	priv->current_action = ACTION_ENROLL;
Bastien Nocera's avatar
Bastien Nocera committed
1066

1067
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
1068
1069
1070
1071
1072
1073
1074
}

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
1075
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
1076
1077
1078
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1079
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1080
1081
	int r;

1082
1083
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1084
		return;
1085
1086
	}

Bastien Nocera's avatar
Bastien Nocera committed
1087
1088
1089
1090
1091
	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
1092
	if (priv->current_action != ACTION_ENROLL) {
1093
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
1094
1095
1096
1097
1098
1099
			    "No enrollment in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

1100
1101
1102
1103
	if (!priv->disconnected)
		r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context);
	else
		r = 0;
Daniel Drake's avatar
Daniel Drake committed
1104
	if (r < 0) {
1105
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1106
1107
			"Enroll stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1108
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1109
	}
1110
1111
	if (priv->disconnected)
		dbus_g_method_return(context);
Bastien Nocera's avatar
Bastien Nocera committed
1112

1113
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1114
1115
}

1116
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
1117
1118
						const char *username,
						DBusGMethodInvocation *context)
1119
1120
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1121
	GError *error = NULL;
1122
1123
	GSList *prints;
	GSList *item;
1124
	GPtrArray *ret;
1125
	char *user, *sender;
1126
1127
1128
1129
1130
1131
1132

	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
1133
		dbus_g_method_return_error (context, error);
1134
		g_error_free (error);