device.c 33.5 KB
Newer Older
Daniel Drake's avatar
Daniel Drake committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * /net/reactivated/Fprint/Device/foo object implementation
 * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

20
21
#include "config.h"

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

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

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

37
38
39
40
41
42
43
44
45
46
47
48
49
static char *fingers[] = {
	"left-thumb",
	"left-index-finger",
	"left-middle-finger",
	"left-ring-finger",
	"left-little-finger",
	"right-thumb",
	"right-index-finger",
	"right-middle-finger",
	"right-ring-finger",
	"right-little-finger"
};

50
51
extern DBusGConnection *fprintd_dbus_conn;

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

#include "device-dbus-glue.h"

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

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

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

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

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

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

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

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

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

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

Bastien Nocera's avatar
Bastien Nocera committed
113
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;
Daniel Drake's avatar
Daniel Drake committed
120
121
122
123
124
125
126
127
};

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,
128
	FPRINT_DEVICE_IN_USE,
129
130
131
	FPRINT_DEVICE_NAME,
	FPRINT_DEVICE_NUM_ENROLL,
	FPRINT_DEVICE_SCAN_TYPE
Daniel Drake's avatar
Daniel Drake committed
132
133
};

134
enum fprint_device_signals {
Daniel Drake's avatar
Daniel Drake committed
135
	SIGNAL_VERIFY_STATUS,
Bastien Nocera's avatar
Bastien Nocera committed
136
	SIGNAL_VERIFY_FINGER_SELECTED,
Daniel Drake's avatar
Daniel Drake committed
137
	SIGNAL_ENROLL_STATUS,
138
139
140
	NUM_SIGNALS,
};

Daniel Drake's avatar
Daniel Drake committed
141
142
static GObjectClass *parent_class = NULL;
static guint32 last_id = ~0;
143
static guint signals[NUM_SIGNALS] = { 0, };
Daniel Drake's avatar
Daniel Drake committed
144

145
static void fprint_device_finalize(GObject *object)
Daniel Drake's avatar
Daniel Drake committed
146
{
147
148
149
150
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	g_hash_table_destroy (priv->clients);
Daniel Drake's avatar
Daniel Drake committed
151
152
153
	/* FIXME close and stuff */
}

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

206
static void fprint_device_class_init(FprintDeviceClass *klass)
Daniel Drake's avatar
Daniel Drake committed
207
208
209
210
211
212
213
214
{
	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);

215
216
	gobject_class->finalize = fprint_device_finalize;
	gobject_class->set_property = fprint_device_set_property;
Bastien Nocera's avatar
Bastien Nocera committed
217
	gobject_class->get_property = fprint_device_get_property;
218
	g_type_class_add_private(klass, sizeof(FprintDevicePrivate));
Daniel Drake's avatar
Daniel Drake committed
219
220

	pspec = g_param_spec_pointer("discovered-dev", "Discovered device",
221
222
				     "Set discovered device construction property",
				     G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
Daniel Drake's avatar
Daniel Drake committed
223
	g_object_class_install_property(gobject_class,
224
225
					FPRINT_DEVICE_CONSTRUCT_DDEV, pspec);

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

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

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

295
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
296
{
297
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
298
	priv->id = ++last_id;
Bastien Nocera's avatar
Bastien Nocera committed
299
300
301
302
303
304
305
306
307

	/* 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;
	}
308
309
310
311
	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
312
313
}

314
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
315
316
317
318
319
320
321
322
323
324
325

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

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
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;
}

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

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

397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
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
427
static gboolean
Bastien Nocera's avatar
Bastien Nocera committed
428
_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
429
430
431
432
433
434
435
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
	DBusError dbus_error;
	PolKitCaller *pk_caller;
	PolKitAction *pk_action;
	PolKitResult pk_result;
436
	uid_t uid;
Bastien Nocera's avatar
Bastien Nocera committed
437
438
439
440
441
442
443
444
445

	/* 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
446
447
448
449
		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
450
451
452
453
		dbus_error_free (&dbus_error);
		return FALSE;
	}

454
455
456
457
458
459
460
461
462
463
464
	/* 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
465
466
467
	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
468
							 TRUE, NULL);
Bastien Nocera's avatar
Bastien Nocera committed
469
470
471
472
	polkit_caller_unref (pk_caller);
	polkit_action_unref (pk_action);

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

	return TRUE;
}

Bastien Nocera's avatar
Bastien Nocera committed
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
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);
}

501
502
503
504
505
506
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
507
{
508
509
510
511
512
513
	DBusConnection *conn;
	DBusError dbus_error;
	char *sender;
	unsigned long uid;
	struct passwd *user;
	char *client_username;
Bastien Nocera's avatar
Bastien Nocera committed
514

515
516
517
518
519
	/* 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
520

521
522
523
524
	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
525
526
	}

527
528
529
	user = getpwuid (uid);
	if (user == NULL) {
		g_free (sender);
530
		g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
			    "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
552
553
	}

554
555
556
557
	if (ret_sender != NULL)
		*ret_sender = sender;
	else
		g_free (sender);
Bastien Nocera's avatar
Bastien Nocera committed
558

559
	return g_strdup (username);
Bastien Nocera's avatar
Bastien Nocera committed
560
561
}

562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
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
638
639
640
641
642
643
644
645
646
647
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;
648
649
650
651

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

652
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
653
654
655
656
657
658
659
660
661
			"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
662
static void fprint_device_claim(FprintDevice *rdev,
663
664
				const char *username,
				DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
665
666
667
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
668
	char *sender, *user;
Daniel Drake's avatar
Daniel Drake committed
669
670
	int r;

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

679
680
	g_assert (priv->username == NULL);
	g_assert (priv->sender == NULL);
Bastien Nocera's avatar
Bastien Nocera committed
681

682
683
684
685
686
687
688
	sender = NULL;
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  &sender,
						  &error);
	if (user == NULL) {
689
		g_free (sender);
690
		dbus_g_method_return_error (context, error);
691
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
692
		return;
693
694
	}

695
696
697
698
	if (_fprint_device_check_polkit_for_actions (rdev, context,
						     "net.reactivated.fprint.device.verify",
						     "net.reactivated.fprint.device.enroll",
						     &error) == FALSE) {
699
		g_free (sender);
700
701
		g_free (user);
		dbus_g_method_return_error (context, error);
702
703
704
		return;
	}

705
706
	_fprint_device_add_client (rdev, sender);

707
	priv->username = user;
708
709
	priv->sender = sender;

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

Daniel Drake's avatar
Daniel Drake committed
712
713
714
715
716
717
718
	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;
719
720
721
722
723
724

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

725
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
			"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;

742
743
744
	g_free (priv->sender);
	priv->sender = NULL;

745
746
747
	g_free (priv->username);
	priv->username = NULL;

Daniel Drake's avatar
Daniel Drake committed
748
749
750
751
	g_message("released device %d", priv->id);
	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
752
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
753
754
755
756
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
757
758
759
760
	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
761
		return;
762
	}
Daniel Drake's avatar
Daniel Drake committed
763

Bastien Nocera's avatar
Bastien Nocera committed
764
765
766
767
768
769
770
771
772
	/* 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
773
774
775
776
777
	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
778
779
780
		      void *user_data)
{
	struct FprintDevice *rdev = user_data;
Bastien Nocera's avatar
Bastien Nocera committed
781
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
782
	const char *name = verify_result_to_name (r);
783
784
	gboolean done = FALSE;

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

787
788
789
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
		done = TRUE;
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, done);
Bastien Nocera's avatar
Bastien Nocera committed
790
	fp_img_free(img);
Bastien Nocera's avatar
Bastien Nocera committed
791
792
793
794
795

	if (done && priv->verify_data) {
		fp_print_data_free (priv->verify_data);
		priv->verify_data = NULL;
	}
Bastien Nocera's avatar
Bastien Nocera committed
796
797
798
799
}

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
800
801
{
	struct FprintDevice *rdev = user_data;
Bastien Nocera's avatar
Bastien Nocera committed
802
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
803
	const char *name = verify_result_to_name (r);
804
805
	gboolean done = FALSE;

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

808
809
810
	if (r == FP_VERIFY_NO_MATCH || r == FP_VERIFY_MATCH || r < 0)
		done = TRUE;
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name, done);
811
	fp_img_free(img);
Bastien Nocera's avatar
Bastien Nocera committed
812
813
814
815
816
817
818
819

	if (done && 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;
	}
Daniel Drake's avatar
Daniel Drake committed
820
821
}

Bastien Nocera's avatar
Bastien Nocera committed
822
static void fprint_device_verify_start(FprintDevice *rdev,
823
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
824
825
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
Bastien Nocera's avatar
Bastien Nocera committed
826
	struct fp_print_data **gallery = NULL;
Daniel Drake's avatar
Daniel Drake committed
827
	struct fp_print_data *data = NULL;
828
	GError *error = NULL;
829
	guint finger_num = finger_name_to_num (finger_name);
Daniel Drake's avatar
Daniel Drake committed
830
831
	int r;

832
833
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
834
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
835
		return;
836
837
	}

Bastien Nocera's avatar
Bastien Nocera committed
838
839
	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
840
841
842
843
844
		g_error_free (error);
		return;
	}

	if (priv->current_action != ACTION_NONE) {
Bastien Nocera's avatar
Bastien Nocera committed
845
846
847
848
849
850
851
		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
852
853
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
854
855
856
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
857
858
859
860
861
	if (finger_num == -1) {
		GSList *prints;

		prints = store.discover_prints(priv->ddev, priv->username);
		if (prints == NULL) {
862
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
Bastien Nocera's avatar
Bastien Nocera committed
863
864
				    "No fingerprints enrolled");
			dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
865
866
867
868
869
870
871
872
873
			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
874
875
				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
876
							  &data, priv->username);
877
878
				if (r == 0)
					g_ptr_array_add (array, data);
Bastien Nocera's avatar
Bastien Nocera committed
879
880
			}
			data = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
881
882
883
884
885
886
887

			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
888
		} else {
Bastien Nocera's avatar
Bastien Nocera committed
889
			finger_num = GPOINTER_TO_INT (prints->data);
Bastien Nocera's avatar
Bastien Nocera committed
890
891
		}
		g_slist_free(prints);
Daniel Drake's avatar
Daniel Drake committed
892
	}
Bastien Nocera's avatar
Bastien Nocera committed
893

Bastien Nocera's avatar
Bastien Nocera committed
894
	if (fp_dev_supports_identification(priv->dev) && finger_num == -1) {
Bastien Nocera's avatar
Bastien Nocera committed
895
		if (gallery == NULL) {
896
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
897
898
899
				    "No fingerprints on that device");
			dbus_g_method_return_error(context, error);
			g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
900
901
			return;
		}
902
		priv->current_action = ACTION_IDENTIFY;
Bastien Nocera's avatar
Bastien Nocera committed
903
904
905
906

		g_message ("start identification device %d", priv->id);
		r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev);
	} else {
907
		priv->current_action = ACTION_VERIFY;
Bastien Nocera's avatar
Bastien Nocera committed
908
909
910
911
912
913
914

		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) {
915
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Bastien Nocera's avatar
Bastien Nocera committed
916
917
918
919
				    "No such print %d", finger_num);
			dbus_g_method_return_error(context, error);
			return;
		}
Bastien Nocera's avatar
Bastien Nocera committed
920

Bastien Nocera's avatar
Bastien Nocera committed
921
922
923
		r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	}

924
925
	/* Emit VerifyFingerSelected telling the front-end which finger
	 * we selected for auth */
926
927
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
		      0, finger_num_to_name (finger_num));
928
929


Daniel Drake's avatar
Daniel Drake committed
930
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
931
932
933
934
935
936
937
938
		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);
		}
939
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
940
			"Verify start failed with error %d", r);
941
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
942
		return;
Daniel Drake's avatar
Daniel Drake committed
943
	}
Bastien Nocera's avatar
Bastien Nocera committed
944
945
	priv->verify_data = data;
	priv->identify_data = gallery;
Daniel Drake's avatar
Daniel Drake committed
946

947
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
948
949
950
951
952
953
954
}

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
955
956
957
958
959
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
960
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
961
962
963
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
964
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
965
966
	int r;

967
968
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
969
		return;
970
971
	}

Bastien Nocera's avatar
Bastien Nocera committed
972
973
974
975
976
	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
977
	if (priv->current_action == ACTION_VERIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
978
979
980
981
		if (priv->verify_data) {
			fp_print_data_free (priv->verify_data);
			priv->verify_data = NULL;
		}
Bastien Nocera's avatar
Bastien Nocera committed
982
		r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
983
	} else if (priv->current_action == ACTION_IDENTIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
984
985
986
987
988
989
990
		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;
		}
Bastien Nocera's avatar
Bastien Nocera committed
991
		r = fp_async_identify_stop(priv->dev, identify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
992
	} else {
993
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
994
995
996
997
			    "No verification in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
Bastien Nocera's avatar
Bastien Nocera committed
998
	}
Bastien Nocera's avatar
Bastien Nocera committed
999

Daniel Drake's avatar
Daniel Drake committed
1000
	if (r < 0) {
1001
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1002
1003
			"Verify stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1004
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1005
	}
Bastien Nocera's avatar
Bastien Nocera committed
1006

1007
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1008
1009
}

Daniel Drake's avatar
Daniel Drake committed
1010
1011
1012
1013
1014
1015
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;
1016
	gboolean done = FALSE;
Bastien Nocera's avatar
Bastien Nocera committed
1017
	int r;
Daniel Drake's avatar
Daniel Drake committed
1018
1019

	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
1020
	if (result == FP_ENROLL_COMPLETE) {
1021
		r = store.print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
1022
1023
1024
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
1025

1026
1027
1028
	if (result == FP_ENROLL_COMPLETE || result == FP_ENROLL_FAIL || result < 0)
		done = TRUE;
	g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, enroll_result_to_name (result), done);
Daniel Drake's avatar
Daniel Drake committed
1029
1030
1031
1032
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
1033
static void fprint_device_enroll_start(FprintDevice *rdev,
1034
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
1035
1036
1037
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
1038
	int finger_num = finger_name_to_num (finger_name);
1039
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1040
1041
	int r;

1042
	if (finger_num == -1) {
1043
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INVALID_FINGERNAME,
1044
1045
1046
1047
1048
1049
			    "Invalid print name");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

1050
1051
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1052
		return;
1053
1054
	}

Bastien Nocera's avatar
Bastien Nocera committed
1055
1056
1057
1058
1059
	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
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
	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
1073
1074
1075
1076
1077
	g_message("start enrollment device %d finger %d", priv->id, finger_num);
	session->enroll_finger = finger_num;
	
	r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev);
	if (r < 0) {
1078
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1079
			"Enroll start failed with error %d", r);
1080
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1081
		return;
Daniel Drake's avatar
Daniel Drake committed
1082
1083
	}

1084
	priv->current_action = ACTION_ENROLL;
Bastien Nocera's avatar
Bastien Nocera committed
1085

1086
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
1087
1088
1089
1090
1091
1092
1093
}

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
1094
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
1095
1096
1097
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1098
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1099
1100
	int r;

1101
1102
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1103
		return;
1104
1105
	}

Bastien Nocera's avatar
Bastien Nocera committed
1106
1107
1108
1109
1110
	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
1111
	if (priv->current_action != ACTION_ENROLL) {
1112
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ACTION_IN_PROGRESS,
Bastien Nocera's avatar
Bastien Nocera committed
1113
1114
1115
1116
1117
1118
			    "No enrollment in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

Daniel Drake's avatar
Daniel Drake committed
1119
1120
	r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context);
	if (r < 0) {
1121
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_INTERNAL,
Daniel Drake's avatar
Daniel Drake committed
1122
1123
			"Enroll stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1124
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1125
	}
Bastien Nocera's avatar
Bastien Nocera committed
1126

1127
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1128
1129
}

1130
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
1131
1132
						const char *username,
						DBusGMethodInvocation *context)
1133
1134
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1135
	GError *error = NULL;
1136
1137
	GSList *prints;
	GSList *item;
1138
	GPtrArray *ret;
1139
	char *user, *sender;
1140
1141
1142
1143
1144
1145
1146

	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
1147
		dbus_g_method_return_error (context, error);
1148
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
1149
		return;
1150
1151
	}

Bastien Nocera's avatar
Bastien Nocera committed
1152
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
1153
		g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1154
1155
1156
1157
		dbus_g_method_return_error (context, error);
		return;
	}

1158
1159
1160
1161
	sender = dbus_g_method_get_sender (context);
	_fprint_device_add_client (rdev, sender);
	g_free (sender);

1162
1163
	prints = store.discover_prints(priv->ddev, user);
	g_free (user);
1164
	if (!prints) {
1165
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_ENROLLED_PRINTS,
1166
			"Failed to discover prints");
1167
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1168
		return;
1169
1170
	}

1171
	ret = g_ptr_array_new ();
1172
	for (item = prints; item; item = item->next) {
1173
1174
		int finger_num = GPOINTER_TO_INT (item->data);
		g_ptr_array_add (ret, g_strdup (finger_num_to_name (finger_num)));
1175
	}
1176
	g_ptr_array_add (ret, NULL);
1177
1178

	g_slist_free(prints);
1179

1180
	dbus_g_method_return(context, g_ptr_array_free (ret, FALSE));
1181
1182
}

Bastien Nocera's avatar
Bastien Nocera committed
1183
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
1184
						  const char *username,
Bastien Nocera's avatar
Bastien Nocera committed
1185
1186
1187
1188
1189
						  DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
	guint i;
1190
	char *user, *sender;
Bastien Nocera's avatar
Bastien Nocera committed
1191

1192
1193
1194
1195
1196
1197
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
1198
		dbus_g_method_return_error (context, error);
1199
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
1200
1201
1202
		return;
	}

1203
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
1204
		g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1205
1206
1207
1208
		dbus_g_method_return_error (context, error);
		return;
	}

1209
1210
1211
1212
	sender = dbus_g_method_get_sender (context);
	_fprint_device_add_client (rdev, sender);
	g_free (sender);

Bastien Nocera's avatar
Bastien Nocera committed
1213
	for (i = LEFT_THUMB; i <= RIGHT_LITTLE; i++) {
1214
		store.print_data_delete(priv->ddev, i, user);
Bastien Nocera's avatar
Bastien Nocera committed
1215
	}
1216
	g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1217
1218
1219
1220

	dbus_g_method_return(context);
}