~jderose/ubuntu/utopic/unity-settings-daemon/tune-syndaemon

« back to all changes in this revision

Viewing changes to plugins/smartcard/gsd-smartcard-manager.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-02-07 11:44:36 UTC
  • Revision ID: package-import@ubuntu.com-20140207114436-7t5u3yvwc4ul7w3e
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* gsd-smartcard-manager.c - object for monitoring smartcard insertion and
 
2
 *                           removal events
 
3
 *
 
4
 * Copyright (C) 2006, 2009 Red Hat, Inc.
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2, or (at your option)
 
9
 * any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
 * 02111-1307, USA.
 
20
 *
 
21
 * Written By: Ray Strode
 
22
 */
 
23
#include "config.h"
 
24
 
 
25
#include "gsd-smartcard-manager.h"
 
26
 
 
27
#define SMARTCARD_ENABLE_INTERNAL_API
 
28
#include "gsd-smartcard.h"
 
29
 
 
30
#include <dirent.h>
 
31
#include <errno.h>
 
32
#include <fcntl.h>
 
33
#include <limits.h>
 
34
#include <poll.h>
 
35
#include <signal.h>
 
36
#include <stdlib.h>
 
37
#include <string.h>
 
38
#include <sys/resource.h>
 
39
#include <sys/time.h>
 
40
#include <sys/wait.h>
 
41
#include <unistd.h>
 
42
 
 
43
#include <glib.h>
 
44
#include <glib/gi18n.h>
 
45
 
 
46
#include <prerror.h>
 
47
#include <prinit.h>
 
48
#include <nss.h>
 
49
#include <pk11func.h>
 
50
#include <secmod.h>
 
51
#include <secerr.h>
 
52
 
 
53
#ifndef GSD_SMARTCARD_MANAGER_DRIVER
 
54
#define GSD_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so"
 
55
#endif
 
56
 
 
57
#ifndef GSD_SMARTCARD_MANAGER_NSS_DB
 
58
#define GSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb"
 
59
#endif
 
60
 
 
61
#ifndef GSD_MAX_OPEN_FILE_DESCRIPTORS
 
62
#define GSD_MAX_OPEN_FILE_DESCRIPTORS 1024
 
63
#endif
 
64
 
 
65
#ifndef GSD_OPEN_FILE_DESCRIPTORS_DIR
 
66
#define GSD_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd"
 
67
#endif
 
68
 
 
69
typedef enum _GsdSmartcardManagerState GsdSmartcardManagerState;
 
70
typedef struct _GsdSmartcardManagerWorker GsdSmartcardManagerWorker;
 
71
 
 
72
enum _GsdSmartcardManagerState {
 
73
        GSD_SMARTCARD_MANAGER_STATE_STOPPED = 0,
 
74
        GSD_SMARTCARD_MANAGER_STATE_STARTING,
 
75
        GSD_SMARTCARD_MANAGER_STATE_STARTED,
 
76
        GSD_SMARTCARD_MANAGER_STATE_STOPPING,
 
77
};
 
78
 
 
79
struct _GsdSmartcardManagerPrivate {
 
80
        GsdSmartcardManagerState state;
 
81
        GList        *modules;
 
82
        char        *module_path;
 
83
 
 
84
        GList        *workers;
 
85
 
 
86
        GPid smartcard_event_watcher_pid;
 
87
        GHashTable *smartcards;
 
88
 
 
89
        guint poll_timeout_id;
 
90
 
 
91
        guint32 is_unstoppable : 1;
 
92
        guint32 nss_is_loaded : 1;
 
93
};
 
94
 
 
95
struct _GsdSmartcardManagerWorker {
 
96
        GsdSmartcardManager *manager;
 
97
        int manager_fd;
 
98
 
 
99
        GThread      *thread;
 
100
        SECMODModule *module;
 
101
        GHashTable *smartcards;
 
102
        int fd;
 
103
        GSource *event_source;
 
104
 
 
105
        guint32 nss_is_loaded : 1;
 
106
};
 
107
 
 
108
static void gsd_smartcard_manager_finalize (GObject *object);
 
109
static void gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *service_class);
 
110
static void gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *service_class);
 
111
static void gsd_smartcard_manager_set_property (GObject       *object,
 
112
                                                guint          prop_id,
 
113
                                                const GValue  *value,
 
114
                                                GParamSpec    *pspec);
 
115
static void gsd_smartcard_manager_get_property (GObject    *object,
 
116
                                                guint       prop_id,
 
117
                                                GValue     *value,
 
118
                                                GParamSpec *pspec);
 
119
static void gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager,
 
120
                                                   const char          *module_path);
 
121
static void gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager,
 
122
                                                        GsdSmartcard        *card);
 
123
static void gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager_class,
 
124
                                                         GsdSmartcard        *card);
 
125
static gboolean gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager);
 
126
static void gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager);
 
127
 
 
128
static GsdSmartcardManagerWorker *gsd_smartcard_manager_create_worker (GsdSmartcardManager  *manager,
 
129
                                                                       SECMODModule         *module);
 
130
 
 
131
static GsdSmartcardManagerWorker * gsd_smartcard_manager_worker_new (GsdSmartcardManager *manager,
 
132
                                                                     int                  worker_fd,
 
133
                                                                     int                  manager_fd,
 
134
                                                                     SECMODModule        *module);
 
135
static void gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker);
 
136
static gboolean open_pipe (int *write_fd, int *read_fd);
 
137
static gboolean read_bytes (int fd, gpointer bytes, gsize num_bytes);
 
138
static gboolean write_bytes (int fd, gconstpointer bytes, gsize num_bytes);
 
139
static GsdSmartcard *read_smartcard (int fd, SECMODModule *module);
 
140
static gboolean write_smartcard (int fd, GsdSmartcard *card);
 
141
 
 
142
enum {
 
143
        PROP_0 = 0,
 
144
        PROP_MODULE_PATH,
 
145
        NUMBER_OF_PROPERTIES
 
146
};
 
147
 
 
148
enum {
 
149
        SMARTCARD_INSERTED = 0,
 
150
        SMARTCARD_REMOVED,
 
151
        ERROR,
 
152
        NUMBER_OF_SIGNALS
 
153
};
 
154
 
 
155
static guint gsd_smartcard_manager_signals[NUMBER_OF_SIGNALS];
 
156
 
 
157
G_DEFINE_TYPE (GsdSmartcardManager,
 
158
               gsd_smartcard_manager,
 
159
               G_TYPE_OBJECT);
 
160
 
 
161
static void
 
162
gsd_smartcard_manager_class_init (GsdSmartcardManagerClass *manager_class)
 
163
{
 
164
        GObjectClass *gobject_class;
 
165
 
 
166
        gobject_class = G_OBJECT_CLASS (manager_class);
 
167
 
 
168
        gobject_class->finalize = gsd_smartcard_manager_finalize;
 
169
 
 
170
        gsd_smartcard_manager_class_install_signals (manager_class);
 
171
        gsd_smartcard_manager_class_install_properties (manager_class);
 
172
 
 
173
        g_type_class_add_private (manager_class,
 
174
                                  sizeof (GsdSmartcardManagerPrivate));
 
175
}
 
176
 
 
177
static void
 
178
gsd_smartcard_manager_class_install_properties (GsdSmartcardManagerClass *card_class)
 
179
{
 
180
        GObjectClass *object_class;
 
181
        GParamSpec *param_spec;
 
182
 
 
183
        object_class = G_OBJECT_CLASS (card_class);
 
184
        object_class->set_property = gsd_smartcard_manager_set_property;
 
185
        object_class->get_property = gsd_smartcard_manager_get_property;
 
186
 
 
187
        param_spec = g_param_spec_string ("module-path", "Module Path",
 
188
                                          "path to smartcard PKCS #11 driver",
 
189
                                          NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
 
190
        g_object_class_install_property (object_class, PROP_MODULE_PATH, param_spec);
 
191
}
 
192
 
 
193
static void
 
194
gsd_smartcard_manager_set_property (GObject       *object,
 
195
                                    guint          prop_id,
 
196
                                    const GValue  *value,
 
197
                                    GParamSpec    *pspec)
 
198
{
 
199
        GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object);
 
200
 
 
201
        switch (prop_id) {
 
202
                case PROP_MODULE_PATH:
 
203
                        gsd_smartcard_manager_set_module_path (manager,
 
204
                                                                   g_value_get_string (value));
 
205
                        break;
 
206
 
 
207
                default:
 
208
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
209
                        break;
 
210
        }
 
211
}
 
212
 
 
213
static void
 
214
gsd_smartcard_manager_get_property (GObject    *object,
 
215
                                    guint       prop_id,
 
216
                                    GValue     *value,
 
217
                                    GParamSpec *pspec)
 
218
{
 
219
        GsdSmartcardManager *manager = GSD_SMARTCARD_MANAGER (object);
 
220
        char *module_path;
 
221
 
 
222
        switch (prop_id) {
 
223
                case PROP_MODULE_PATH:
 
224
                        module_path = gsd_smartcard_manager_get_module_path (manager);
 
225
                        g_value_set_string (value, module_path);
 
226
                        g_free (module_path);
 
227
                        break;
 
228
 
 
229
                default:
 
230
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
231
                        break;
 
232
        }
 
233
}
 
234
 
 
235
char *
 
236
gsd_smartcard_manager_get_module_path (GsdSmartcardManager *manager)
 
237
{
 
238
        return manager->priv->module_path;
 
239
}
 
240
 
 
241
static void
 
242
gsd_smartcard_manager_set_module_path (GsdSmartcardManager *manager,
 
243
                                       const char          *module_path)
 
244
{
 
245
        if ((manager->priv->module_path == NULL) && (module_path == NULL)) {
 
246
                return;
 
247
        }
 
248
 
 
249
        if (((manager->priv->module_path == NULL) ||
 
250
         (module_path == NULL) ||
 
251
         (strcmp (manager->priv->module_path, module_path) != 0))) {
 
252
                g_free (manager->priv->module_path);
 
253
                manager->priv->module_path = g_strdup (module_path);
 
254
                g_object_notify (G_OBJECT (manager), "module-path");
 
255
        }
 
256
}
 
257
 
 
258
static void
 
259
gsd_smartcard_manager_card_removed_handler (GsdSmartcardManager *manager,
 
260
                                            GsdSmartcard        *card)
 
261
{
 
262
        g_debug ("informing smartcard of its removal");
 
263
        _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_REMOVED);
 
264
        g_debug ("done");
 
265
}
 
266
 
 
267
static void
 
268
gsd_smartcard_manager_card_inserted_handler (GsdSmartcardManager *manager,
 
269
                                             GsdSmartcard        *card)
 
270
{
 
271
        g_debug ("informing smartcard of its insertion");
 
272
 
 
273
        _gsd_smartcard_set_state (card, GSD_SMARTCARD_STATE_INSERTED);
 
274
        g_debug ("done");
 
275
 
 
276
}
 
277
 
 
278
static void
 
279
gsd_smartcard_manager_class_install_signals (GsdSmartcardManagerClass *manager_class)
 
280
{
 
281
        GObjectClass *object_class;
 
282
 
 
283
        object_class = G_OBJECT_CLASS (manager_class);
 
284
 
 
285
        gsd_smartcard_manager_signals[SMARTCARD_INSERTED] =
 
286
                g_signal_new ("smartcard-inserted",
 
287
                              G_OBJECT_CLASS_TYPE (object_class),
 
288
                              G_SIGNAL_RUN_FIRST,
 
289
                              G_STRUCT_OFFSET (GsdSmartcardManagerClass,
 
290
                                               smartcard_inserted),
 
291
                              NULL, NULL, g_cclosure_marshal_VOID__POINTER,
 
292
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
 
293
        manager_class->smartcard_inserted = gsd_smartcard_manager_card_inserted_handler;
 
294
 
 
295
        gsd_smartcard_manager_signals[SMARTCARD_REMOVED] =
 
296
                g_signal_new ("smartcard-removed",
 
297
                              G_OBJECT_CLASS_TYPE (object_class),
 
298
                              G_SIGNAL_RUN_FIRST,
 
299
                              G_STRUCT_OFFSET (GsdSmartcardManagerClass,
 
300
                                               smartcard_removed),
 
301
                              NULL, NULL, g_cclosure_marshal_VOID__POINTER,
 
302
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
 
303
        manager_class->smartcard_removed = gsd_smartcard_manager_card_removed_handler;
 
304
 
 
305
        gsd_smartcard_manager_signals[ERROR] =
 
306
                g_signal_new ("error",
 
307
                              G_OBJECT_CLASS_TYPE (object_class),
 
308
                              G_SIGNAL_RUN_LAST,
 
309
                              G_STRUCT_OFFSET (GsdSmartcardManagerClass, error),
 
310
                              NULL, NULL, g_cclosure_marshal_VOID__POINTER,
 
311
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
 
312
        manager_class->error = NULL;
 
313
}
 
314
 
 
315
static gboolean
 
316
slot_id_equal (CK_SLOT_ID *slot_id_1,
 
317
               CK_SLOT_ID *slot_id_2)
 
318
{
 
319
        g_assert (slot_id_1 != NULL);
 
320
        g_assert (slot_id_2 != NULL);
 
321
 
 
322
        return *slot_id_1 == *slot_id_2;
 
323
}
 
324
 
 
325
static gboolean
 
326
slot_id_hash (CK_SLOT_ID *slot_id)
 
327
{
 
328
        guint32 upper_bits, lower_bits;
 
329
        int temp;
 
330
 
 
331
        if (sizeof (CK_SLOT_ID) == sizeof (int)) {
 
332
                return g_int_hash (slot_id);
 
333
        }
 
334
 
 
335
        upper_bits = ((*slot_id) >> 31) - 1;
 
336
        lower_bits = (*slot_id) & 0xffffffff;
 
337
 
 
338
        /* The upper bits are almost certainly always zero,
 
339
         * so let's degenerate to g_int_hash for the
 
340
         * (very) common case
 
341
         */
 
342
        temp = lower_bits + upper_bits;
 
343
        return upper_bits + g_int_hash (&temp);
 
344
}
 
345
 
 
346
static void
 
347
gsd_smartcard_manager_init (GsdSmartcardManager *manager)
 
348
{
 
349
        g_debug ("initializing smartcard manager");
 
350
 
 
351
        manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
 
352
                                                     GSD_TYPE_SMARTCARD_MANAGER,
 
353
                                                     GsdSmartcardManagerPrivate);
 
354
        manager->priv->poll_timeout_id = 0;
 
355
        manager->priv->is_unstoppable = FALSE;
 
356
 
 
357
        manager->priv->smartcards =
 
358
                g_hash_table_new_full (g_str_hash,
 
359
                                       g_str_equal,
 
360
                                       (GDestroyNotify) g_free,
 
361
                                       (GDestroyNotify) g_object_unref);
 
362
}
 
363
 
 
364
static void
 
365
gsd_smartcard_manager_finalize (GObject *object)
 
366
{
 
367
        GsdSmartcardManager *manager;
 
368
        GObjectClass *gobject_class;
 
369
 
 
370
        manager = GSD_SMARTCARD_MANAGER (object);
 
371
        gobject_class =
 
372
                G_OBJECT_CLASS (gsd_smartcard_manager_parent_class);
 
373
 
 
374
        gsd_smartcard_manager_stop_now (manager);
 
375
 
 
376
        g_hash_table_destroy (manager->priv->smartcards);
 
377
        manager->priv->smartcards = NULL;
 
378
 
 
379
        gobject_class->finalize (object);
 
380
}
 
381
 
 
382
GQuark
 
383
gsd_smartcard_manager_error_quark (void)
 
384
{
 
385
        static GQuark error_quark = 0;
 
386
 
 
387
        if (error_quark == 0) {
 
388
                error_quark = g_quark_from_static_string ("gsd-smartcard-manager-error-quark");
 
389
        }
 
390
 
 
391
        return error_quark;
 
392
}
 
393
 
 
394
GsdSmartcardManager *
 
395
gsd_smartcard_manager_new_default (void)
 
396
{
 
397
  return gsd_smartcard_manager_new (NULL);
 
398
}
 
399
 
 
400
GsdSmartcardManager *
 
401
gsd_smartcard_manager_new (const char *module_path)
 
402
{
 
403
        GsdSmartcardManager *instance;
 
404
 
 
405
        instance = GSD_SMARTCARD_MANAGER (g_object_new (GSD_TYPE_SMARTCARD_MANAGER,
 
406
                                                        "module-path", module_path,
 
407
                                                        NULL));
 
408
 
 
409
        return instance;
 
410
}
 
411
 
 
412
static void
 
413
gsd_smartcard_manager_emit_error (GsdSmartcardManager *manager,
 
414
                                  GError              *error)
 
415
{
 
416
        manager->priv->is_unstoppable = TRUE;
 
417
        g_signal_emit (manager, gsd_smartcard_manager_signals[ERROR], 0,
 
418
                       error);
 
419
        manager->priv->is_unstoppable = FALSE;
 
420
}
 
421
 
 
422
static void
 
423
gsd_smartcard_manager_emit_smartcard_inserted (GsdSmartcardManager *manager,
 
424
                                               GsdSmartcard        *card)
 
425
{
 
426
        manager->priv->is_unstoppable = TRUE;
 
427
        g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_INSERTED], 0,
 
428
                       card);
 
429
        manager->priv->is_unstoppable = FALSE;
 
430
}
 
431
 
 
432
static void
 
433
gsd_smartcard_manager_emit_smartcard_removed (GsdSmartcardManager *manager,
 
434
                                              GsdSmartcard        *card)
 
435
{
 
436
        manager->priv->is_unstoppable = TRUE;
 
437
        g_signal_emit (manager, gsd_smartcard_manager_signals[SMARTCARD_REMOVED], 0,
 
438
                       card);
 
439
        manager->priv->is_unstoppable = FALSE;
 
440
}
 
441
 
 
442
static gboolean
 
443
gsd_smartcard_manager_check_for_and_process_events (GIOChannel          *io_channel,
 
444
                                                    GIOCondition         condition,
 
445
                                                    GsdSmartcardManagerWorker *worker)
 
446
{
 
447
        GsdSmartcard *card;
 
448
        GsdSmartcardManager *manager;
 
449
        gboolean should_stop;
 
450
        guchar event_type;
 
451
        char *card_name;
 
452
        int fd;
 
453
 
 
454
        manager = worker->manager;
 
455
 
 
456
        g_debug ("event!");
 
457
        card = NULL;
 
458
        should_stop = (condition & G_IO_HUP) || (condition & G_IO_ERR);
 
459
 
 
460
        if (should_stop) {
 
461
                g_debug ("received %s on event socket, stopping "
 
462
                          "manager...",
 
463
                          (condition & G_IO_HUP) && (condition & G_IO_ERR)?
 
464
                          "error and hangup" :
 
465
                          (condition & G_IO_HUP)?
 
466
                          "hangup" : "error");
 
467
        }
 
468
 
 
469
        if (!(condition & G_IO_IN)) {
 
470
                g_debug ("nevermind outta here!");
 
471
                goto out;
 
472
        }
 
473
 
 
474
        fd = g_io_channel_unix_get_fd (io_channel);
 
475
 
 
476
        event_type = '\0';
 
477
        if (!read_bytes (fd, &event_type, 1)) {
 
478
                g_debug ("could not read event type, stopping");
 
479
                should_stop = TRUE;
 
480
                goto out;
 
481
        }
 
482
 
 
483
        card = read_smartcard (fd, worker->module);
 
484
 
 
485
        if (card == NULL) {
 
486
                g_debug ("could not read card, stopping");
 
487
                should_stop = TRUE;
 
488
                goto out;
 
489
        }
 
490
 
 
491
        card_name = gsd_smartcard_get_name (card);
 
492
        g_debug ("card '%s' had event %c", card_name, event_type);
 
493
 
 
494
        switch (event_type) {
 
495
                case 'I':
 
496
                        g_hash_table_replace (manager->priv->smartcards,
 
497
                                              card_name, card);
 
498
                        card_name = NULL;
 
499
 
 
500
                        gsd_smartcard_manager_emit_smartcard_inserted (manager, card);
 
501
                        card = NULL;
 
502
                        break;
 
503
 
 
504
                case 'R':
 
505
                        gsd_smartcard_manager_emit_smartcard_removed (manager, card);
 
506
                        if (!g_hash_table_remove (manager->priv->smartcards, card_name)) {
 
507
                                g_debug ("got removal event of unknown card!");
 
508
                        }
 
509
                        g_free (card_name);
 
510
                        card_name = NULL;
 
511
                        card = NULL;
 
512
                        break;
 
513
 
 
514
                default:
 
515
                        g_free (card_name);
 
516
                        card_name = NULL;
 
517
                        g_object_unref (card);
 
518
 
 
519
                        should_stop = TRUE;
 
520
                        break;
 
521
        }
 
522
 
 
523
out:
 
524
        if (should_stop) {
 
525
                GError *error;
 
526
 
 
527
                error = g_error_new (GSD_SMARTCARD_MANAGER_ERROR,
 
528
                                     GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
 
529
                                     "%s", (condition & G_IO_IN) ? g_strerror (errno) : _("received error or hang up from event source"));
 
530
 
 
531
                gsd_smartcard_manager_emit_error (manager, error);
 
532
                g_error_free (error);
 
533
                gsd_smartcard_manager_stop_now (manager);
 
534
                return FALSE;
 
535
        }
 
536
 
 
537
        return TRUE;
 
538
}
 
539
 
 
540
static void
 
541
stop_manager (GsdSmartcardManager *manager)
 
542
{
 
543
        manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPED;
 
544
 
 
545
        if (manager->priv->nss_is_loaded) {
 
546
                NSS_Shutdown ();
 
547
                manager->priv->nss_is_loaded = FALSE;
 
548
        }
 
549
        g_debug ("smartcard manager stopped");
 
550
}
 
551
 
 
552
static void
 
553
stop_worker (GsdSmartcardManagerWorker *worker)
 
554
{
 
555
        GsdSmartcardManager *manager;
 
556
 
 
557
        manager = worker->manager;
 
558
 
 
559
        if (worker->event_source != NULL) {
 
560
                g_source_destroy (worker->event_source);
 
561
                worker->event_source = NULL;
 
562
        }
 
563
 
 
564
        if (worker->thread != NULL) {
 
565
                SECMOD_CancelWait (worker->module);
 
566
                worker->thread = NULL;
 
567
        }
 
568
 
 
569
        SECMOD_DestroyModule (worker->module);
 
570
        manager->priv->workers = g_list_remove (manager->priv->workers, worker);
 
571
 
 
572
        if (manager->priv->workers == NULL && manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STOPPED) {
 
573
                stop_manager (manager);
 
574
        }
 
575
}
 
576
 
 
577
static void
 
578
gsd_smartcard_manager_event_processing_stopped_handler (GsdSmartcardManagerWorker *worker)
 
579
{
 
580
        worker->event_source = NULL;
 
581
 
 
582
        stop_worker (worker);
 
583
}
 
584
 
 
585
static gboolean
 
586
open_pipe (int *write_fd,
 
587
           int *read_fd)
 
588
{
 
589
        int pipe_fds[2] = { -1, -1 };
 
590
 
 
591
        g_assert (write_fd != NULL);
 
592
        g_assert (read_fd != NULL);
 
593
 
 
594
        if (pipe (pipe_fds) < 0) {
 
595
                return FALSE;
 
596
        }
 
597
 
 
598
        if (fcntl (pipe_fds[0], F_SETFD, FD_CLOEXEC) < 0) {
 
599
                close (pipe_fds[0]);
 
600
                close (pipe_fds[1]);
 
601
                return FALSE;
 
602
        }
 
603
 
 
604
        if (fcntl (pipe_fds[1], F_SETFD, FD_CLOEXEC) < 0) {
 
605
                close (pipe_fds[0]);
 
606
                close (pipe_fds[1]);
 
607
                return FALSE;
 
608
        }
 
609
 
 
610
        *read_fd = pipe_fds[0];
 
611
        *write_fd = pipe_fds[1];
 
612
 
 
613
        return TRUE;
 
614
}
 
615
 
 
616
static void
 
617
gsd_smartcard_manager_stop_watching_for_events (GsdSmartcardManager  *manager)
 
618
{
 
619
        GList *node;
 
620
 
 
621
        node = manager->priv->workers;
 
622
        while (node != NULL) {
 
623
                GsdSmartcardManagerWorker *worker;
 
624
                GList *next_node;
 
625
 
 
626
                worker = (GsdSmartcardManagerWorker *) node->data;
 
627
                next_node = node->next;
 
628
 
 
629
                stop_worker (worker);
 
630
 
 
631
                node = next_node;
 
632
        }
 
633
}
 
634
 
 
635
static gboolean
 
636
load_nss (GError **error)
 
637
{
 
638
        SECStatus status = SECSuccess;
 
639
        static const guint32 flags =
 
640
        NSS_INIT_READONLY |
 
641
        NSS_INIT_FORCEOPEN | NSS_INIT_NOROOTINIT |
 
642
        NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD;
 
643
 
 
644
        g_debug ("attempting to load NSS database '%s'",
 
645
                 GSD_SMARTCARD_MANAGER_NSS_DB);
 
646
 
 
647
        PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
 
648
 
 
649
        status = NSS_Initialize (GSD_SMARTCARD_MANAGER_NSS_DB,
 
650
                                 "", "", SECMOD_DB, flags);
 
651
 
 
652
        if (status != SECSuccess) {
 
653
                gsize error_message_size;
 
654
                char *error_message;
 
655
 
 
656
                error_message_size = PR_GetErrorTextLength ();
 
657
 
 
658
                if (error_message_size == 0) {
 
659
                        g_debug ("NSS security system could not be initialized");
 
660
                        g_set_error (error,
 
661
                                     GSD_SMARTCARD_MANAGER_ERROR,
 
662
                                     GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
 
663
                                     _("NSS security system could not be initialized"));
 
664
                        goto out;
 
665
                }
 
666
 
 
667
                error_message = g_slice_alloc0 (error_message_size);
 
668
                PR_GetErrorText (error_message);
 
669
 
 
670
                g_set_error (error,
 
671
                             GSD_SMARTCARD_MANAGER_ERROR,
 
672
                             GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
 
673
                             "%s", error_message);
 
674
                g_debug ("NSS security system could not be initialized - %s",
 
675
                          error_message);
 
676
 
 
677
                g_slice_free1 (error_message_size, error_message);
 
678
 
 
679
                goto out;
 
680
        }
 
681
 
 
682
        g_debug ("NSS database sucessfully loaded");
 
683
        return TRUE;
 
684
 
 
685
out:
 
686
        g_debug ("NSS database couldn't be sucessfully loaded");
 
687
        return FALSE;
 
688
}
 
689
 
 
690
static GList *
 
691
get_available_modules (GsdSmartcardManager  *manager)
 
692
{
 
693
        SECMODModuleList *module_list, *tmp;
 
694
        GList *modules;
 
695
 
 
696
        g_debug ("Getting list of suitable modules");
 
697
 
 
698
        module_list = SECMOD_GetDefaultModuleList ();
 
699
        modules = NULL;
 
700
        for (tmp = module_list; tmp != NULL; tmp = tmp->next) {
 
701
                if (!SECMOD_HasRemovableSlots (tmp->module) ||
 
702
                    !tmp->module->loaded)
 
703
                        continue;
 
704
 
 
705
                g_debug ("Using module '%s'", tmp->module->commonName);
 
706
 
 
707
                modules = g_list_prepend (modules,
 
708
                                          SECMOD_ReferenceModule (tmp->module));
 
709
        }
 
710
 
 
711
        return modules;
 
712
}
 
713
 
 
714
static gboolean
 
715
load_driver (GsdSmartcardManager  *manager,
 
716
             char                 *module_path,
 
717
             GError              **error)
 
718
{
 
719
        GList *modules;
 
720
        char *module_spec;
 
721
        gboolean module_explicitly_specified;
 
722
 
 
723
        g_debug ("attempting to load driver...");
 
724
 
 
725
        modules = NULL;
 
726
        module_explicitly_specified = module_path != NULL;
 
727
        if (module_explicitly_specified) {
 
728
                SECMODModule *module;
 
729
 
 
730
                module_spec = g_strdup_printf ("library=\"%s\"", module_path);
 
731
                g_debug ("loading smartcard driver using spec '%s'",
 
732
                          module_spec);
 
733
 
 
734
                module = SECMOD_LoadUserModule (module_spec,
 
735
                                                NULL /* parent */,
 
736
                                                FALSE /* recurse */);
 
737
                g_free (module_spec);
 
738
                module_spec = NULL;
 
739
 
 
740
                if (SECMOD_HasRemovableSlots (module) &&
 
741
                    module->loaded) {
 
742
                        modules = g_list_prepend (modules, module);
 
743
                } else {
 
744
                        g_debug ("fallback module found but not %s",
 
745
                                 SECMOD_HasRemovableSlots (module)?
 
746
                                 "removable" : "loaded");
 
747
                        SECMOD_DestroyModule (module);
 
748
                }
 
749
 
 
750
        } else {
 
751
                SECMODListLock *lock;
 
752
 
 
753
                lock = SECMOD_GetDefaultModuleListLock ();
 
754
 
 
755
                if (lock != NULL) {
 
756
                        SECMOD_GetReadLock (lock);
 
757
                        modules = get_available_modules (manager);
 
758
                        SECMOD_ReleaseReadLock (lock);
 
759
                }
 
760
 
 
761
                /* fallback to compiled in driver path
 
762
                 */
 
763
                if (modules == NULL) {
 
764
                        SECMODModule *module;
 
765
                        module_path = GSD_SMARTCARD_MANAGER_DRIVER;
 
766
                        module_spec = g_strdup_printf ("library=\"%s\"", module_path);
 
767
                        g_debug ("loading smartcard driver using spec '%s'",
 
768
                                module_spec);
 
769
 
 
770
                        module = SECMOD_LoadUserModule (module_spec,
 
771
                                NULL /* parent */,
 
772
                                FALSE /* recurse */);
 
773
                        g_free (module_spec);
 
774
                        module_spec = NULL;
 
775
 
 
776
                        if (SECMOD_HasRemovableSlots (module) &&
 
777
                            module->loaded) {
 
778
                                modules = g_list_prepend (modules, module);
 
779
                        } else {
 
780
                                g_debug ("fallback module found but not loaded");
 
781
                                SECMOD_DestroyModule (module);
 
782
                        }
 
783
                }
 
784
 
 
785
        }
 
786
 
 
787
        if (!module_explicitly_specified && modules == NULL) {
 
788
                g_set_error (error,
 
789
                             GSD_SMARTCARD_MANAGER_ERROR,
 
790
                             GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
 
791
                             _("no suitable smartcard driver could be found"));
 
792
        } else if (modules == NULL) {
 
793
 
 
794
                gsize error_message_size;
 
795
                char *error_message;
 
796
 
 
797
                error_message_size = PR_GetErrorTextLength ();
 
798
 
 
799
                if (error_message_size == 0) {
 
800
                        g_debug ("smartcard driver '%s' could not be loaded",
 
801
                                  module_path);
 
802
                        g_set_error (error,
 
803
                                     GSD_SMARTCARD_MANAGER_ERROR,
 
804
                                     GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
 
805
                                     _("smartcard driver '%s' could not be "
 
806
                                       "loaded"), module_path);
 
807
                        goto out;
 
808
                }
 
809
 
 
810
                error_message = g_slice_alloc0 (error_message_size);
 
811
                PR_GetErrorText (error_message);
 
812
 
 
813
                g_set_error (error,
 
814
                             GSD_SMARTCARD_MANAGER_ERROR,
 
815
                             GSD_SMARTCARD_MANAGER_ERROR_LOADING_DRIVER,
 
816
                             "%s", error_message);
 
817
 
 
818
                g_debug ("smartcard driver '%s' could not be loaded - %s",
 
819
                          module_path, error_message);
 
820
                g_slice_free1 (error_message_size, error_message);
 
821
        }
 
822
 
 
823
        manager->priv->modules = modules;
 
824
out:
 
825
        return manager->priv->modules != NULL;
 
826
}
 
827
 
 
828
static void
 
829
gsd_smartcard_manager_get_all_cards (GsdSmartcardManager *manager)
 
830
{
 
831
        GList *node;
 
832
        int i;
 
833
 
 
834
        node = manager->priv->workers;
 
835
        while (node != NULL) {
 
836
 
 
837
                GsdSmartcardManagerWorker *worker;
 
838
 
 
839
                worker = (GsdSmartcardManagerWorker *) node->data;
 
840
 
 
841
                for (i = 0; i < worker->module->slotCount; i++) {
 
842
                        GsdSmartcard *card;
 
843
                        CK_SLOT_ID    slot_id;
 
844
                        int          slot_series;
 
845
                        char         *card_name;
 
846
 
 
847
                        slot_id = PK11_GetSlotID (worker->module->slots[i]);
 
848
                        slot_series = PK11_GetSlotSeries (worker->module->slots[i]);
 
849
 
 
850
                        card = _gsd_smartcard_new (worker->module,
 
851
                                                   slot_id, slot_series);
 
852
 
 
853
                        card_name = gsd_smartcard_get_name (card);
 
854
 
 
855
                        g_hash_table_replace (manager->priv->smartcards,
 
856
                                              card_name, card);
 
857
                }
 
858
                node = node->next;
 
859
        }
 
860
}
 
861
 
 
862
static GsdSmartcardManagerWorker *
 
863
start_worker (GsdSmartcardManager  *manager,
 
864
              SECMODModule         *module,
 
865
              GError              **error)
 
866
{
 
867
        GIOChannel *io_channel;
 
868
        GSource *source;
 
869
        GsdSmartcardManagerWorker *worker;
 
870
 
 
871
        worker = gsd_smartcard_manager_create_worker (manager, module);
 
872
 
 
873
        if (worker == NULL) {
 
874
                g_set_error (error,
 
875
                             GSD_SMARTCARD_MANAGER_ERROR,
 
876
                             GSD_SMARTCARD_MANAGER_ERROR_WATCHING_FOR_EVENTS,
 
877
                             _("could not watch for incoming card events - %s"),
 
878
                             g_strerror (errno));
 
879
 
 
880
                goto out;
 
881
        }
 
882
 
 
883
        io_channel = g_io_channel_unix_new (worker->manager_fd);
 
884
 
 
885
        source = g_io_create_watch (io_channel, G_IO_IN | G_IO_HUP);
 
886
        g_io_channel_unref (io_channel);
 
887
        io_channel = NULL;
 
888
 
 
889
        worker->event_source = source;
 
890
 
 
891
        g_source_set_callback (worker->event_source,
 
892
                               (GSourceFunc) (GIOFunc)
 
893
                               gsd_smartcard_manager_check_for_and_process_events,
 
894
                               worker,
 
895
                               (GDestroyNotify)
 
896
                               gsd_smartcard_manager_event_processing_stopped_handler);
 
897
        g_source_attach (worker->event_source, NULL);
 
898
        g_source_unref (worker->event_source);
 
899
out:
 
900
        return worker;
 
901
}
 
902
 
 
903
static void
 
904
start_workers (GsdSmartcardManager *manager)
 
905
{
 
906
        GList        *node;
 
907
 
 
908
        node = manager->priv->modules;
 
909
        while (node != NULL) {
 
910
                SECMODModule *module;
 
911
                GsdSmartcardManagerWorker *worker;
 
912
                GError *error;
 
913
 
 
914
                module = (SECMODModule *) node->data;
 
915
 
 
916
                error = NULL;
 
917
                worker = start_worker (manager, module, &error);
 
918
                if (worker == NULL) {
 
919
                        g_warning ("%s", error->message);
 
920
                        g_error_free (error);
 
921
                } else {
 
922
                        manager->priv->workers = g_list_prepend (manager->priv->workers,
 
923
                                                                 worker);
 
924
                }
 
925
                node = node->next;
 
926
        }
 
927
}
 
928
 
 
929
gboolean
 
930
gsd_smartcard_manager_start (GsdSmartcardManager  *manager,
 
931
                             GError              **error)
 
932
{
 
933
        GError *nss_error;
 
934
 
 
935
        if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED) {
 
936
                g_debug ("smartcard manager already started");
 
937
                return TRUE;
 
938
        }
 
939
 
 
940
        manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTING;
 
941
 
 
942
        nss_error = NULL;
 
943
        if (!manager->priv->nss_is_loaded && !load_nss (&nss_error)) {
 
944
                g_propagate_error (error, nss_error);
 
945
                goto out;
 
946
        }
 
947
        manager->priv->nss_is_loaded = TRUE;
 
948
 
 
949
        if (manager->priv->modules == NULL) {
 
950
                if (!load_driver (manager, manager->priv->module_path, &nss_error)) {
 
951
                        g_propagate_error (error, nss_error);
 
952
                        goto out;
 
953
                }
 
954
        }
 
955
 
 
956
        start_workers (manager);
 
957
 
 
958
        /* populate the hash with cards that are already inserted
 
959
         */
 
960
        gsd_smartcard_manager_get_all_cards (manager);
 
961
 
 
962
        manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STARTED;
 
963
 
 
964
out:
 
965
        /* don't leave it in a half started state
 
966
         */
 
967
        if (manager->priv->state != GSD_SMARTCARD_MANAGER_STATE_STARTED) {
 
968
                g_debug ("smartcard manager could not be completely started");
 
969
                gsd_smartcard_manager_stop (manager);
 
970
        } else {
 
971
                g_debug ("smartcard manager started");
 
972
        }
 
973
 
 
974
        return manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STARTED;
 
975
}
 
976
 
 
977
static gboolean
 
978
gsd_smartcard_manager_stop_now (GsdSmartcardManager *manager)
 
979
{
 
980
        if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) {
 
981
                return FALSE;
 
982
        }
 
983
 
 
984
        gsd_smartcard_manager_stop_watching_for_events (manager);
 
985
 
 
986
        return FALSE;
 
987
}
 
988
 
 
989
static void
 
990
gsd_smartcard_manager_queue_stop (GsdSmartcardManager *manager)
 
991
{
 
992
 
 
993
        manager->priv->state = GSD_SMARTCARD_MANAGER_STATE_STOPPING;
 
994
 
 
995
        g_idle_add ((GSourceFunc) gsd_smartcard_manager_stop_now, manager);
 
996
}
 
997
 
 
998
void
 
999
gsd_smartcard_manager_stop (GsdSmartcardManager *manager)
 
1000
{
 
1001
        if (manager->priv->state == GSD_SMARTCARD_MANAGER_STATE_STOPPED) {
 
1002
                return;
 
1003
        }
 
1004
 
 
1005
        if (manager->priv->is_unstoppable) {
 
1006
                gsd_smartcard_manager_queue_stop (manager);
 
1007
                return;
 
1008
        }
 
1009
 
 
1010
        gsd_smartcard_manager_stop_now (manager);
 
1011
}
 
1012
 
 
1013
static void
 
1014
gsd_smartcard_manager_check_for_login_card (CK_SLOT_ID    slot_id,
 
1015
                                            GsdSmartcard *card,
 
1016
                                            gboolean     *is_inserted)
 
1017
{
 
1018
        g_assert (is_inserted != NULL);
 
1019
 
 
1020
        if (gsd_smartcard_is_login_card (card)) {
 
1021
                *is_inserted = TRUE;
 
1022
        }
 
1023
 
 
1024
}
 
1025
 
 
1026
gboolean
 
1027
gsd_smartcard_manager_login_card_is_inserted (GsdSmartcardManager *manager)
 
1028
 
 
1029
{
 
1030
        gboolean is_inserted;
 
1031
 
 
1032
        is_inserted = FALSE;
 
1033
        g_hash_table_foreach (manager->priv->smartcards,
 
1034
                              (GHFunc)
 
1035
                              gsd_smartcard_manager_check_for_login_card,
 
1036
                              &is_inserted);
 
1037
        return is_inserted;
 
1038
}
 
1039
 
 
1040
static GsdSmartcardManagerWorker *
 
1041
gsd_smartcard_manager_worker_new (GsdSmartcardManager *manager,
 
1042
                                  int                 worker_fd,
 
1043
                                  int                 manager_fd,
 
1044
                                  SECMODModule        *module)
 
1045
{
 
1046
        GsdSmartcardManagerWorker *worker;
 
1047
 
 
1048
        worker = g_slice_new0 (GsdSmartcardManagerWorker);
 
1049
        worker->manager = manager;
 
1050
        worker->fd = worker_fd;
 
1051
        worker->manager_fd = manager_fd;
 
1052
        worker->module = module;
 
1053
 
 
1054
        worker->smartcards =
 
1055
                g_hash_table_new_full ((GHashFunc) slot_id_hash,
 
1056
                                       (GEqualFunc) slot_id_equal,
 
1057
                                       (GDestroyNotify) g_free,
 
1058
                                       (GDestroyNotify) g_object_unref);
 
1059
 
 
1060
        return worker;
 
1061
}
 
1062
 
 
1063
static void
 
1064
gsd_smartcard_manager_worker_free (GsdSmartcardManagerWorker *worker)
 
1065
{
 
1066
        if (worker->smartcards != NULL) {
 
1067
                g_hash_table_destroy (worker->smartcards);
 
1068
                worker->smartcards = NULL;
 
1069
        }
 
1070
 
 
1071
        g_slice_free (GsdSmartcardManagerWorker, worker);
 
1072
}
 
1073
 
 
1074
static gboolean
 
1075
read_bytes (int      fd,
 
1076
            gpointer bytes,
 
1077
            gsize    num_bytes)
 
1078
{
 
1079
        size_t bytes_left;
 
1080
        size_t total_bytes_read;
 
1081
        ssize_t bytes_read;
 
1082
 
 
1083
        bytes_left = (size_t) num_bytes;
 
1084
        total_bytes_read = 0;
 
1085
 
 
1086
        do {
 
1087
                bytes_read = read (fd,
 
1088
                                   (char *) bytes + total_bytes_read,
 
1089
                                   bytes_left);
 
1090
                g_assert (bytes_read <= (ssize_t) bytes_left);
 
1091
 
 
1092
                if (bytes_read <= 0) {
 
1093
                        if ((bytes_read < 0) && (errno == EINTR || errno == EAGAIN)) {
 
1094
                                continue;
 
1095
                        }
 
1096
 
 
1097
                        bytes_left = 0;
 
1098
                } else {
 
1099
                        bytes_left -= bytes_read;
 
1100
                        total_bytes_read += bytes_read;
 
1101
                }
 
1102
        } while (bytes_left > 0);
 
1103
 
 
1104
        if (total_bytes_read <  (size_t) num_bytes) {
 
1105
                return FALSE;
 
1106
        }
 
1107
 
 
1108
        return TRUE;
 
1109
}
 
1110
 
 
1111
static gboolean
 
1112
write_bytes (int           fd,
 
1113
             gconstpointer bytes,
 
1114
             gsize         num_bytes)
 
1115
{
 
1116
        size_t bytes_left;
 
1117
        size_t total_bytes_written;
 
1118
        ssize_t bytes_written;
 
1119
 
 
1120
        bytes_left = (size_t) num_bytes;
 
1121
        total_bytes_written = 0;
 
1122
 
 
1123
        do {
 
1124
                bytes_written = write (fd,
 
1125
                                       (char *) bytes + total_bytes_written,
 
1126
                                       bytes_left);
 
1127
                g_assert (bytes_written <= (ssize_t) bytes_left);
 
1128
 
 
1129
                if (bytes_written <= 0) {
 
1130
                        if ((bytes_written < 0) && (errno == EINTR || errno == EAGAIN)) {
 
1131
                                continue;
 
1132
                        }
 
1133
 
 
1134
                        bytes_left = 0;
 
1135
                } else {
 
1136
                        bytes_left -= bytes_written;
 
1137
                        total_bytes_written += bytes_written;
 
1138
                }
 
1139
        } while (bytes_left > 0);
 
1140
 
 
1141
        if (total_bytes_written <  (size_t) num_bytes) {
 
1142
                return FALSE;
 
1143
        }
 
1144
 
 
1145
        return TRUE;
 
1146
}
 
1147
 
 
1148
static GsdSmartcard *
 
1149
read_smartcard (int           fd,
 
1150
                SECMODModule *module)
 
1151
{
 
1152
        GsdSmartcard *card;
 
1153
        char *card_name;
 
1154
        gsize card_name_size;
 
1155
 
 
1156
        card_name_size = 0;
 
1157
        if (!read_bytes (fd, &card_name_size, sizeof (card_name_size))) {
 
1158
                return NULL;
 
1159
        }
 
1160
 
 
1161
        card_name = g_slice_alloc0 (card_name_size);
 
1162
        if (!read_bytes (fd, card_name, card_name_size)) {
 
1163
                g_slice_free1 (card_name_size, card_name);
 
1164
                return NULL;
 
1165
        }
 
1166
        card = _gsd_smartcard_new_from_name (module, card_name);
 
1167
        g_slice_free1 (card_name_size, card_name);
 
1168
 
 
1169
        return card;
 
1170
}
 
1171
 
 
1172
static gboolean
 
1173
write_smartcard (int          fd,
 
1174
                    GsdSmartcard *card)
 
1175
{
 
1176
        gsize card_name_size;
 
1177
        char *card_name;
 
1178
 
 
1179
        card_name = gsd_smartcard_get_name (card);
 
1180
        card_name_size = strlen (card_name) + 1;
 
1181
 
 
1182
        if (!write_bytes (fd, &card_name_size, sizeof (card_name_size))) {
 
1183
                g_free (card_name);
 
1184
                return FALSE;
 
1185
        }
 
1186
 
 
1187
        if (!write_bytes (fd, card_name, card_name_size)) {
 
1188
                g_free (card_name);
 
1189
                return FALSE;
 
1190
        }
 
1191
        g_free (card_name);
 
1192
 
 
1193
        return TRUE;
 
1194
}
 
1195
 
 
1196
static gboolean
 
1197
gsd_smartcard_manager_worker_emit_smartcard_removed (GsdSmartcardManagerWorker  *worker,
 
1198
                                                     GsdSmartcard               *card,
 
1199
                                                     GError                    **error)
 
1200
{
 
1201
        g_debug ("card '%s' removed!", gsd_smartcard_get_name (card));
 
1202
 
 
1203
        if (!write_bytes (worker->fd, "R", 1)) {
 
1204
                goto error_out;
 
1205
        }
 
1206
 
 
1207
        if (!write_smartcard (worker->fd, card)) {
 
1208
                goto error_out;
 
1209
        }
 
1210
 
 
1211
        return TRUE;
 
1212
 
 
1213
error_out:
 
1214
        g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR,
 
1215
                     GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
 
1216
                     "%s", g_strerror (errno));
 
1217
        return FALSE;
 
1218
}
 
1219
 
 
1220
static gboolean
 
1221
gsd_smartcard_manager_worker_emit_smartcard_inserted (GsdSmartcardManagerWorker  *worker,
 
1222
                                                      GsdSmartcard               *card,
 
1223
                                                      GError                    **error)
 
1224
{
 
1225
        g_debug ("card '%s' inserted!", gsd_smartcard_get_name (card));
 
1226
        if (!write_bytes (worker->fd, "I", 1)) {
 
1227
                goto error_out;
 
1228
        }
 
1229
 
 
1230
        if (!write_smartcard (worker->fd, card)) {
 
1231
                goto error_out;
 
1232
        }
 
1233
 
 
1234
        return TRUE;
 
1235
 
 
1236
error_out:
 
1237
        g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR,
 
1238
                     GSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
 
1239
                     "%s", g_strerror (errno));
 
1240
        return FALSE;
 
1241
}
 
1242
 
 
1243
static gboolean
 
1244
gsd_smartcard_manager_worker_watch_for_and_process_event (GsdSmartcardManagerWorker  *worker,
 
1245
                                                          GError                    **error)
 
1246
{
 
1247
        PK11SlotInfo *slot;
 
1248
        CK_SLOT_ID slot_id, *key = NULL;
 
1249
        int slot_series, card_slot_series;
 
1250
        GsdSmartcard *card;
 
1251
        GError *processing_error;
 
1252
        gboolean ret;
 
1253
 
 
1254
        g_debug ("waiting for card event");
 
1255
        ret = FALSE;
 
1256
 
 
1257
        slot = SECMOD_WaitForAnyTokenEvent (worker->module, 0, PR_SecondsToInterval (1));
 
1258
 
 
1259
        processing_error = NULL;
 
1260
 
 
1261
        if (slot == NULL) {
 
1262
                int error_code;
 
1263
 
 
1264
                error_code = PORT_GetError ();
 
1265
                if ((error_code == 0) || (error_code == SEC_ERROR_NO_EVENT)) {
 
1266
                        g_debug ("spurrious event occurred");
 
1267
                        return TRUE;
 
1268
                }
 
1269
 
 
1270
                /* FIXME: is there a function to convert from a PORT error
 
1271
                 * code to a translated string?
 
1272
                 */
 
1273
                g_set_error (error, GSD_SMARTCARD_MANAGER_ERROR,
 
1274
                             GSD_SMARTCARD_MANAGER_ERROR_WITH_NSS,
 
1275
                             _("encountered unexpected error while "
 
1276
                               "waiting for smartcard events"));
 
1277
                goto out;
 
1278
        }
 
1279
 
 
1280
        /* the slot id and series together uniquely identify a card.
 
1281
         * You can never have two cards with the same slot id at the
 
1282
         * same time, however (I think), so we can key off of it.
 
1283
         */
 
1284
        slot_id = PK11_GetSlotID (slot);
 
1285
        slot_series = PK11_GetSlotSeries (slot);
 
1286
 
 
1287
        /* First check to see if there is a card that we're currently
 
1288
         * tracking in the slot.
 
1289
         */
 
1290
        key = g_new (CK_SLOT_ID, 1);
 
1291
        *key = slot_id;
 
1292
        card = g_hash_table_lookup (worker->smartcards, key);
 
1293
 
 
1294
        if (card != NULL) {
 
1295
                card_slot_series = gsd_smartcard_get_slot_series (card);
 
1296
        } else {
 
1297
                card_slot_series = -1;
 
1298
        }
 
1299
 
 
1300
        if (PK11_IsPresent (slot)) {
 
1301
                /* Now, check to see if their is a new card in the slot.
 
1302
                 * If there was a different card in the slot now than
 
1303
                 * there was before, then we need to emit a removed signal
 
1304
                 * for the old card (we don't want unpaired insertion events).
 
1305
                 */
 
1306
                if ((card != NULL) &&
 
1307
                    card_slot_series != slot_series) {
 
1308
                        if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) {
 
1309
                                g_propagate_error (error, processing_error);
 
1310
                                goto out;
 
1311
                        }
 
1312
                }
 
1313
 
 
1314
                card = _gsd_smartcard_new (worker->module,
 
1315
                                           slot_id, slot_series);
 
1316
 
 
1317
                g_hash_table_replace (worker->smartcards,
 
1318
                                      key, card);
 
1319
                key = NULL;
 
1320
 
 
1321
                if (!gsd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) {
 
1322
                        g_propagate_error (error, processing_error);
 
1323
                        goto out;
 
1324
                }
 
1325
        } else {
 
1326
                /* if we aren't tracking the card, just discard the event.
 
1327
                 * We don't want unpaired remove events.  Note on startup
 
1328
                 * NSS will generate an "insertion" event if a card is
 
1329
                 * already inserted in the slot.
 
1330
                 */
 
1331
                if ((card != NULL)) {
 
1332
                        /* FIXME: i'm not sure about this code.  Maybe we
 
1333
                         * shouldn't do this at all, or maybe we should do it
 
1334
                         * n times (where n = slot_series - card_slot_series + 1)
 
1335
                         *
 
1336
                         * Right now, i'm just doing it once.
 
1337
                         */
 
1338
                        if ((slot_series - card_slot_series) > 1) {
 
1339
 
 
1340
                                if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) {
 
1341
                                        g_propagate_error (error, processing_error);
 
1342
                                        goto out;
 
1343
                                }
 
1344
                                g_hash_table_remove (worker->smartcards, key);
 
1345
 
 
1346
                                card = _gsd_smartcard_new (worker->module,
 
1347
                                                                slot_id, slot_series);
 
1348
                                g_hash_table_replace (worker->smartcards,
 
1349
                                                      key, card);
 
1350
                                key = NULL;
 
1351
                                if (!gsd_smartcard_manager_worker_emit_smartcard_inserted (worker, card, &processing_error)) {
 
1352
                                        g_propagate_error (error, processing_error);
 
1353
                                        goto out;
 
1354
                                }
 
1355
                        }
 
1356
 
 
1357
                        if (!gsd_smartcard_manager_worker_emit_smartcard_removed (worker, card, &processing_error)) {
 
1358
                                g_propagate_error (error, processing_error);
 
1359
                                goto out;
 
1360
                        }
 
1361
 
 
1362
                        g_hash_table_remove (worker->smartcards, key);
 
1363
                        card = NULL;
 
1364
                } else {
 
1365
                        g_debug ("got spurious remove event");
 
1366
                }
 
1367
        }
 
1368
 
 
1369
        ret = TRUE;
 
1370
 
 
1371
out:
 
1372
        g_free (key);
 
1373
        PK11_FreeSlot (slot);
 
1374
 
 
1375
        return ret;
 
1376
}
 
1377
 
 
1378
static void
 
1379
gsd_smartcard_manager_worker_run (GsdSmartcardManagerWorker *worker)
 
1380
{
 
1381
        GError *error;
 
1382
        gboolean should_continue;
 
1383
 
 
1384
        do
 
1385
        {
 
1386
                error = NULL;
 
1387
                should_continue = gsd_smartcard_manager_worker_watch_for_and_process_event (worker, &error);
 
1388
        }
 
1389
        while (should_continue);
 
1390
 
 
1391
        if (error != NULL)  {
 
1392
                g_debug ("could not process card event - %s", error->message);
 
1393
                g_error_free (error);
 
1394
        }
 
1395
 
 
1396
        gsd_smartcard_manager_worker_free (worker);
 
1397
}
 
1398
 
 
1399
static GsdSmartcardManagerWorker *
 
1400
gsd_smartcard_manager_create_worker (GsdSmartcardManager  *manager,
 
1401
                                     SECMODModule         *module)
 
1402
{
 
1403
        GsdSmartcardManagerWorker *worker;
 
1404
        int write_fd, read_fd;
 
1405
 
 
1406
        write_fd = -1;
 
1407
        read_fd = -1;
 
1408
        if (!open_pipe (&write_fd, &read_fd)) {
 
1409
                return NULL;
 
1410
        }
 
1411
 
 
1412
        worker = gsd_smartcard_manager_worker_new (manager,
 
1413
                                                   write_fd,
 
1414
                                                   read_fd,
 
1415
                                                   module);
 
1416
 
 
1417
        worker->thread = g_thread_create ((GThreadFunc)
 
1418
                                          gsd_smartcard_manager_worker_run,
 
1419
                                          worker, FALSE, NULL);
 
1420
 
 
1421
        if (worker->thread == NULL) {
 
1422
                gsd_smartcard_manager_worker_free (worker);
 
1423
                return NULL;
 
1424
        }
 
1425
 
 
1426
        return worker;
 
1427
}
 
1428
 
 
1429
#ifdef GSD_SMARTCARD_MANAGER_ENABLE_TEST
 
1430
#include <glib.h>
 
1431
 
 
1432
static GMainLoop *event_loop;
 
1433
static gboolean should_exit_on_next_remove = FALSE;
 
1434
 
 
1435
static gboolean
 
1436
on_timeout (GsdSmartcardManager *manager)
 
1437
{
 
1438
        GError *error;
 
1439
        g_print ("Re-enabling manager.\n");
 
1440
 
 
1441
        if (!gsd_smartcard_manager_start (manager, &error)) {
 
1442
                g_warning ("could not start smartcard manager - %s",
 
1443
                           error->message);
 
1444
                g_error_free (error);
 
1445
                return TRUE;
 
1446
        }
 
1447
        g_print ("Please re-insert smartcard\n");
 
1448
 
 
1449
        should_exit_on_next_remove = TRUE;
 
1450
 
 
1451
        return FALSE;
 
1452
}
 
1453
 
 
1454
static void
 
1455
on_device_inserted (GsdSmartcardManager *manager,
 
1456
                    GsdSmartcard        *card)
 
1457
{
 
1458
        g_print ("smartcard inserted!\n");
 
1459
        g_print ("Please remove it.\n");
 
1460
}
 
1461
 
 
1462
static void
 
1463
on_device_removed (GsdSmartcardManager *manager,
 
1464
                   GsdSmartcard        *card)
 
1465
{
 
1466
        g_print ("smartcard removed!\n");
 
1467
 
 
1468
        if (should_exit_on_next_remove) {
 
1469
                g_main_loop_quit (event_loop);
 
1470
        } else {
 
1471
                g_print ("disabling manager for 2 seconds\n");
 
1472
                gsd_smartcard_manager_stop (manager);
 
1473
                g_timeout_add_seconds (2, (GSourceFunc) on_timeout, manager);
 
1474
        }
 
1475
}
 
1476
 
 
1477
int
 
1478
main (int   argc,
 
1479
      char *argv[])
 
1480
{
 
1481
        GsdSmartcardManager *manager;
 
1482
        GError *error;
 
1483
 
 
1484
        g_log_set_always_fatal (G_LOG_LEVEL_ERROR
 
1485
                                | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
 
1486
 
 
1487
        g_message ("creating instance of 'smartcard manager' object...");
 
1488
        manager = gsd_smartcard_manager_new (NULL);
 
1489
        g_message ("'smartcard manager' object created successfully");
 
1490
 
 
1491
        g_signal_connect (manager, "smartcard-inserted",
 
1492
                          G_CALLBACK (on_device_inserted), NULL);
 
1493
 
 
1494
        g_signal_connect (manager, "smartcard-removed",
 
1495
                          G_CALLBACK (on_device_removed), NULL);
 
1496
 
 
1497
        g_message ("starting listener...");
 
1498
 
 
1499
        error = NULL;
 
1500
        if (!gsd_smartcard_manager_start (manager, &error)) {
 
1501
                g_warning ("could not start smartcard manager - %s",
 
1502
                           error->message);
 
1503
                g_error_free (error);
 
1504
                return 1;
 
1505
        }
 
1506
 
 
1507
        event_loop = g_main_loop_new (NULL, FALSE);
 
1508
        g_main_loop_run (event_loop);
 
1509
        g_main_loop_unref (event_loop);
 
1510
        event_loop = NULL;
 
1511
 
 
1512
        g_message ("destroying previously created 'smartcard manager' object...");
 
1513
        g_object_unref (manager);
 
1514
        manager = NULL;
 
1515
        g_message ("'smartcard manager' object destroyed successfully");
 
1516
 
 
1517
        return 0;
 
1518
}
 
1519
#endif