device.c 34.6 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
#include <sys/types.h>
#include <pwd.h>
31
#include <errno.h>
32

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

38
39
40
41
42
43
44
45
46
47
48
49
50
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"
};

51
52
extern DBusGConnection *fprintd_dbus_conn;

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

#include "device-dbus-glue.h"

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

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

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

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

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

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

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

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

Bastien Nocera's avatar
Bastien Nocera committed
114
115
116
117
118
	/* 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
119
	/* whether we're running an identify, or a verify */
Bastien Nocera's avatar
Bastien Nocera committed
120
	FprintDeviceAction current_action;
121
122
	/* Whether we should ignore new signals on the device */
	gboolean action_done;
123
124
	/* Whether the device was disconnected */
	gboolean disconnected;
Daniel Drake's avatar
Daniel Drake committed
125
126
127
128
129
130
131
132
};

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

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

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

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

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

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

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

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

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

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

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

Bastien Nocera's avatar
Bastien Nocera committed
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
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);
}

300
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
301
{
302
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
303
	priv->id = ++last_id;
Bastien Nocera's avatar
Bastien Nocera committed
304
305
306
307
308
309
310
311
312

	/* 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;
	}
313
314
315
316
	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
317
318
}

319
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
320
321
322
323
324
325
326
327
328
329
330

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

331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
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;
}

358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
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";
374
375
	case -EPROTO:
		return "verify-disconnected";
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
	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";
399
400
	case -EPROTO:
		return "enroll-disconnected";
401
402
403
404
405
	default:
		return "enroll-unknown-error";
	}
}

406
407
408
409
410
411
412
413
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;
}

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
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
444
static gboolean
Bastien Nocera's avatar
Bastien Nocera committed
445
_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
446
447
448
449
450
451
452
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
	DBusError dbus_error;
	PolKitCaller *pk_caller;
	PolKitAction *pk_action;
	PolKitResult pk_result;
453
	uid_t uid;
Bastien Nocera's avatar
Bastien Nocera committed
454
455
456
457
458
459
460
461
462

	/* 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
463
464
465
466
		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
467
468
469
470
		dbus_error_free (&dbus_error);
		return FALSE;
	}

471
472
473
474
475
476
477
478
479
480
481
	/* 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
482
483
484
	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
485
							 TRUE, NULL);
Bastien Nocera's avatar
Bastien Nocera committed
486
487
488
489
	polkit_caller_unref (pk_caller);
	polkit_action_unref (pk_action);

	if (pk_result != POLKIT_RESULT_YES) {
Bastien Nocera's avatar
Bastien Nocera committed
490
		g_set_error (error, FPRINT_ERROR,
491
			     FPRINT_ERROR_PERMISSION_DENIED,
Bastien Nocera's avatar
Bastien Nocera committed
492
493
494
			     "%s %s <-- (action, result)",
			     action,
			     polkit_result_to_string_representation (pk_result));
Bastien Nocera's avatar
Bastien Nocera committed
495
496
497
498
499
500
501
		dbus_error_free (&dbus_error);
		return FALSE;
	}

	return TRUE;
}

Bastien Nocera's avatar
Bastien Nocera committed
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
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);
}

518
519
520
521
522
523
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
524
{
525
526
527
528
529
530
	DBusConnection *conn;
	DBusError dbus_error;
	char *sender;
	unsigned long uid;
	struct passwd *user;
	char *client_username;
Bastien Nocera's avatar
Bastien Nocera committed
531

532
533
534
535
536
	/* 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
537

538
539
540
541
	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
542
543
	}

544
545
546
	user = getpwuid (uid);
	if (user == NULL) {
		g_free (sender);
547
		g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
			    "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
569
570
	}

571
572
573
574
	if (ret_sender != NULL)
		*ret_sender = sender;
	else
		g_free (sender);
Bastien Nocera's avatar
Bastien Nocera committed
575

576
	return g_strdup (username);
Bastien Nocera's avatar
Bastien Nocera committed
577
578
}

579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
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
655
656
657
658
659
660
661
662
663
664
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;
665
666
667
668

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

669
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
670
671
672
673
674
675
676
677
678
			"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
679
static void fprint_device_claim(FprintDevice *rdev,
680
681
				const char *username,
				DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
682
683
684
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
685
	char *sender, *user;
Daniel Drake's avatar
Daniel Drake committed
686
687
	int r;

688
	/* Is it already claimed? */
689
	if (priv->sender != NULL) {
690
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
691
692
			    "Device was already claimed");
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
693
		return;
694
695
	}

696
697
	g_assert (priv->username == NULL);
	g_assert (priv->sender == NULL);
Bastien Nocera's avatar
Bastien Nocera committed
698

699
700
701
702
703
704
705
	sender = NULL;
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  &sender,
						  &error);
	if (user == NULL) {
706
		g_free (sender);
707
		dbus_g_method_return_error (context, error);
708
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
709
		return;
710
711
	}

712
713
714
715
	if (_fprint_device_check_polkit_for_actions (rdev, context,
						     "net.reactivated.fprint.device.verify",
						     "net.reactivated.fprint.device.enroll",
						     &error) == FALSE) {
716
		g_free (sender);
717
718
		g_free (user);
		dbus_g_method_return_error (context, error);
719
720
721
		return;
	}

722
723
	_fprint_device_add_client (rdev, sender);

724
	priv->username = user;
725
726
	priv->sender = sender;

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

Daniel Drake's avatar
Daniel Drake committed
729
730
731
732
733
734
735
	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;
736
737
738
739
740
741

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

742
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
			"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;

759
760
761
	g_free (priv->sender);
	priv->sender = NULL;

762
763
764
	g_free (priv->username);
	priv->username = NULL;

Daniel Drake's avatar
Daniel Drake committed
765
766
767
768
	g_message("released device %d", priv->id);
	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
769
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
770
771
772
773
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
774
775
776
777
	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
778
		return;
779
	}
Daniel Drake's avatar
Daniel Drake committed
780

Bastien Nocera's avatar
Bastien Nocera committed
781
782
783
784
785
786
787
788
789
	/* 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
790
791
792
793
794
	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
795
796
797
		      void *user_data)
{
	struct FprintDevice *rdev = user_data;
Bastien Nocera's avatar
Bastien Nocera committed
798
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
799
	const char *name = verify_result_to_name (r);
800
801
802

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

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

806
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
807
		priv->action_done = TRUE;
808
	set_disconnected (priv, name);
809
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, priv->action_done);
Bastien Nocera's avatar
Bastien Nocera committed
810
	fp_img_free(img);
Bastien Nocera's avatar
Bastien Nocera committed
811

812
	if (priv->action_done && priv->verify_data) {
Bastien Nocera's avatar
Bastien Nocera committed
813
814
815
		fp_print_data_free (priv->verify_data);
		priv->verify_data = NULL;
	}
Bastien Nocera's avatar
Bastien Nocera committed
816
817
818
819
}

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
820
821
{
	struct FprintDevice *rdev = user_data;
Bastien Nocera's avatar
Bastien Nocera committed
822
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
823
	const char *name = verify_result_to_name (r);
824
825
826

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

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

830
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
831
		priv->action_done = TRUE;
832
	set_disconnected (priv, name);
833
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, priv->action_done);
834
	fp_img_free(img);
Bastien Nocera's avatar
Bastien Nocera committed
835

836
	if (priv->action_done && priv->identify_data != NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
837
838
839
840
841
842
		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
843
844
}

Bastien Nocera's avatar
Bastien Nocera committed
845
static void fprint_device_verify_start(FprintDevice *rdev,
846
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
847
848
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
Bastien Nocera's avatar
Bastien Nocera committed
849
	struct fp_print_data **gallery = NULL;
Daniel Drake's avatar
Daniel Drake committed
850
	struct fp_print_data *data = NULL;
851
	GError *error = NULL;
852
	guint finger_num = finger_name_to_num (finger_name);
Daniel Drake's avatar
Daniel Drake committed
853
854
	int r;

855
856
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
857
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
858
		return;
859
860
	}

Bastien Nocera's avatar
Bastien Nocera committed
861
862
	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
863
864
865
866
867
		g_error_free (error);
		return;
	}

	if (priv->current_action != ACTION_NONE) {
Bastien Nocera's avatar
Bastien Nocera committed
868
869
870
871
872
873
874
		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
875
876
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
877
878
		return;
	}
879
	priv->action_done = FALSE;
Bastien Nocera's avatar
Bastien Nocera committed
880

Bastien Nocera's avatar
Bastien Nocera committed
881
882
883
884
885
	if (finger_num == -1) {
		GSList *prints;

		prints = store.discover_prints(priv->ddev, priv->username);
		if (prints == NULL) {
886
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
Bastien Nocera's avatar
Bastien Nocera committed
887
888
				    "No fingerprints enrolled");
			dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
889
890
891
892
893
894
895
896
897
			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
898
899
				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
900
							  &data, priv->username);
901
902
				if (r == 0)
					g_ptr_array_add (array, data);
Bastien Nocera's avatar
Bastien Nocera committed
903
904
			}
			data = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
905
906
907
908
909
910
911

			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
912
		} else {
Bastien Nocera's avatar
Bastien Nocera committed
913
			finger_num = GPOINTER_TO_INT (prints->data);
Bastien Nocera's avatar
Bastien Nocera committed
914
915
		}
		g_slist_free(prints);
Daniel Drake's avatar
Daniel Drake committed
916
	}
Bastien Nocera's avatar
Bastien Nocera committed
917

Bastien Nocera's avatar
Bastien Nocera committed
918
	if (fp_dev_supports_identification(priv->dev) && finger_num == -1) {
Bastien Nocera's avatar
Bastien Nocera committed
919
		if (gallery == NULL) {
920
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
921
922
923
				    "No fingerprints on that device");
			dbus_g_method_return_error(context, error);
			g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
924
925
			return;
		}
926
		priv->current_action = ACTION_IDENTIFY;
Bastien Nocera's avatar
Bastien Nocera committed
927
928
929
930

		g_message ("start identification device %d", priv->id);
		r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev);
	} else {
931
		priv->current_action = ACTION_VERIFY;
Bastien Nocera's avatar
Bastien Nocera committed
932
933
934
935
936
937
938

		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) {
939
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Bastien Nocera's avatar
Bastien Nocera committed
940
941
942
943
				    "No such print %d", finger_num);
			dbus_g_method_return_error(context, error);
			return;
		}
Bastien Nocera's avatar
Bastien Nocera committed
944

Bastien Nocera's avatar
Bastien Nocera committed
945
946
947
		r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	}

948
949
	/* Emit VerifyFingerSelected telling the front-end which finger
	 * we selected for auth */
950
951
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
		      0, finger_num_to_name (finger_num));
952
953


Daniel Drake's avatar
Daniel Drake committed
954
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
955
956
957
958
959
960
961
962
		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);
		}
963
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
964
			"Verify start failed with error %d", r);
965
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
966
		return;
Daniel Drake's avatar
Daniel Drake committed
967
	}
Bastien Nocera's avatar
Bastien Nocera committed
968
969
	priv->verify_data = data;
	priv->identify_data = gallery;
Daniel Drake's avatar
Daniel Drake committed
970

971
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
972
973
974
975
976
977
978
}

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
979
980
981
982
983
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
984
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
985
986
987
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
988
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
989
990
	int r;

991
992
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
993
		return;
994
995
	}

Bastien Nocera's avatar
Bastien Nocera committed
996
997
998
999
1000
	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
1001
	if (priv->current_action == ACTION_VERIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
1002
1003
1004
1005
		if (priv->verify_data) {
			fp_print_data_free (priv->verify_data);
			priv->verify_data = NULL;
		}
1006
1007
1008
1009
		if (!priv->disconnected)
			r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
		else
			r = 0;
Bastien Nocera's avatar
Bastien Nocera committed
1010
	} else if (priv->current_action == ACTION_IDENTIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
1011
1012
1013
1014
1015
1016
1017
		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;
		}
1018
1019
1020
1021
		if (!priv->disconnected)
			r = fp_async_identify_stop(priv->dev, identify_stop_cb, context);
		else
			r = 0;
Bastien Nocera's avatar
Bastien Nocera committed
1022
	} else {
1023
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
1024
1025
1026
1027
			    "No verification in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
Bastien Nocera's avatar
Bastien Nocera committed
1028
	}
Bastien Nocera's avatar
Bastien Nocera committed
1029

Daniel Drake's avatar
Daniel Drake committed
1030
	if (r < 0) {
1031
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1032
1033
			"Verify stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1034
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1035
	}
1036
1037
	if (priv->disconnected)
		dbus_g_method_return(context);
Bastien Nocera's avatar
Bastien Nocera committed
1038

1039
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1040
1041
}

Daniel Drake's avatar
Daniel Drake committed
1042
1043
1044
1045
1046
1047
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;
1048
	const char *name = enroll_result_to_name (result);
Bastien Nocera's avatar
Bastien Nocera committed
1049
	int r;
Daniel Drake's avatar
Daniel Drake committed
1050

1051
1052
1053
1054
	/* We're done, ignore new events for the action */
	if (priv->action_done != FALSE)
		return;

Daniel Drake's avatar
Daniel Drake committed
1055
	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
1056
	if (result == FP_ENROLL_COMPLETE) {
1057
		r = store.print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
1058
1059
1060
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
1061

1062
	if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0)
1063
		priv->action_done = TRUE;
1064
	set_disconnected (priv, name);
1065

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

Daniel Drake's avatar
Daniel Drake committed
1068
1069
1070
1071
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
1072
static void fprint_device_enroll_start(FprintDevice *rdev,
1073
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
1074
1075
1076
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
1077
	int finger_num = finger_name_to_num (finger_name);
1078
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1079
1080
	int r;

1081
	if (finger_num == -1) {
1082
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
1083
1084
1085
1086
1087
1088
			    "Invalid print name");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

1089
1090
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1091
		return;
1092
1093
	}

Bastien Nocera's avatar
Bastien Nocera committed
1094
1095
1096
1097
1098
	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
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
	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
1112
1113
	g_message("start enrollment device %d finger %d", priv->id, finger_num);
	session->enroll_finger = finger_num;
1114
	priv->action_done = FALSE;
Daniel Drake's avatar
Daniel Drake committed
1115
1116
1117
	
	r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev);
	if (r < 0) {
1118
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1119
			"Enroll start failed with error %d", r);
1120
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1121
		return;
Daniel Drake's avatar
Daniel Drake committed
1122
1123
	}

1124
	priv->current_action = ACTION_ENROLL;
Bastien Nocera's avatar
Bastien Nocera committed
1125

1126
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
1127
1128
1129
1130
1131
1132
1133
}

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
1134
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
1135
1136
1137
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1138
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1139
1140
	int r;

1141
1142
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1143
		return;
1144
1145
	}

Bastien Nocera's avatar
Bastien Nocera committed
1146
1147
1148
1149
1150
	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
1151
	if (priv->current_action != ACTION_ENROLL) {
1152
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
1153
1154
1155
1156
1157
1158
			    "No enrollment in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

1159
1160
1161
1162
	if (!priv->disconnected)
		r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context);
	else
		r = 0;
Daniel Drake's avatar
Daniel Drake committed
1163
	if (r < 0) {
1164
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1165
1166
			"Enroll stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1167
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1168
	}
1169
1170
	if (priv->disconnected)
		dbus_g_method_return(context);
Bastien Nocera's avatar
Bastien Nocera committed
1171

1172
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1173
1174
}

1175
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
1176
1177
						const char *username,
						DBusGMethodInvocation *context)