1 /* csd-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., 51 Franklin Street - Suite 500, Boston, MA
19 * 02110-1335, USA.
20 *
21 * Written By: Ray Strode
22 */
23 #include "config.h"
24
25 #include "csd-smartcard-manager.h"
26
27 #define SMARTCARD_ENABLE_INTERNAL_API
28 #include "csd-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 CSD_SMARTCARD_MANAGER_DRIVER
54 #define CSD_SMARTCARD_MANAGER_DRIVER LIBDIR"/pkcs11/libcoolkeypk11.so"
55 #endif
56
57 #ifndef CSD_SMARTCARD_MANAGER_NSS_DB
58 #define CSD_SMARTCARD_MANAGER_NSS_DB SYSCONFDIR"/pki/nssdb"
59 #endif
60
61 #ifndef CSD_MAX_OPEN_FILE_DESCRIPTORS
62 #define CSD_MAX_OPEN_FILE_DESCRIPTORS 1024
63 #endif
64
65 #ifndef CSD_OPEN_FILE_DESCRIPTORS_DIR
66 #define CSD_OPEN_FILE_DESCRIPTORS_DIR "/proc/self/fd"
67 #endif
68
69 typedef enum _CsdSmartcardManagerState CsdSmartcardManagerState;
70 typedef struct _CsdSmartcardManagerWorker CsdSmartcardManagerWorker;
71
72 enum _CsdSmartcardManagerState {
73 CSD_SMARTCARD_MANAGER_STATE_STOPPED = 0,
74 CSD_SMARTCARD_MANAGER_STATE_STARTING,
75 CSD_SMARTCARD_MANAGER_STATE_STARTED,
76 CSD_SMARTCARD_MANAGER_STATE_STOPPING,
77 };
78
79 struct _CsdSmartcardManagerPrivate {
80 CsdSmartcardManagerState 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 _CsdSmartcardManagerWorker {
96 CsdSmartcardManager *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 csd_smartcard_manager_finalize (GObject *object);
109 static void csd_smartcard_manager_class_install_signals (CsdSmartcardManagerClass *service_class);
110 static void csd_smartcard_manager_class_install_properties (CsdSmartcardManagerClass *service_class);
111 static void csd_smartcard_manager_set_property (GObject *object,
112 guint prop_id,
113 const GValue *value,
114 GParamSpec *pspec);
115 static void csd_smartcard_manager_get_property (GObject *object,
116 guint prop_id,
117 GValue *value,
118 GParamSpec *pspec);
119 static void csd_smartcard_manager_set_module_path (CsdSmartcardManager *manager,
120 const char *module_path);
121 static void csd_smartcard_manager_card_removed_handler (CsdSmartcardManager *manager,
122 CsdSmartcard *card);
123 static void csd_smartcard_manager_card_inserted_handler (CsdSmartcardManager *manager_class,
124 CsdSmartcard *card);
125 static gboolean csd_smartcard_manager_stop_now (CsdSmartcardManager *manager);
126 static void csd_smartcard_manager_queue_stop (CsdSmartcardManager *manager);
127
128 static CsdSmartcardManagerWorker *csd_smartcard_manager_create_worker (CsdSmartcardManager *manager,
129 SECMODModule *module);
130
131 static CsdSmartcardManagerWorker * csd_smartcard_manager_worker_new (CsdSmartcardManager *manager,
132 int worker_fd,
133 int manager_fd,
134 SECMODModule *module);
135 static void csd_smartcard_manager_worker_free (CsdSmartcardManagerWorker *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 CsdSmartcard *read_smartcard (int fd, SECMODModule *module);
140 static gboolean write_smartcard (int fd, CsdSmartcard *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 csd_smartcard_manager_signals[NUMBER_OF_SIGNALS];
156
157 G_DEFINE_TYPE (CsdSmartcardManager,
158 csd_smartcard_manager,
159 G_TYPE_OBJECT);
160
161 static void
csd_smartcard_manager_class_init(CsdSmartcardManagerClass * manager_class)162 csd_smartcard_manager_class_init (CsdSmartcardManagerClass *manager_class)
163 {
164 GObjectClass *gobject_class;
165
166 gobject_class = G_OBJECT_CLASS (manager_class);
167
168 gobject_class->finalize = csd_smartcard_manager_finalize;
169
170 csd_smartcard_manager_class_install_signals (manager_class);
171 csd_smartcard_manager_class_install_properties (manager_class);
172
173 g_type_class_add_private (manager_class,
174 sizeof (CsdSmartcardManagerPrivate));
175 }
176
177 static void
csd_smartcard_manager_class_install_properties(CsdSmartcardManagerClass * card_class)178 csd_smartcard_manager_class_install_properties (CsdSmartcardManagerClass *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 = csd_smartcard_manager_set_property;
185 object_class->get_property = csd_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
csd_smartcard_manager_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)194 csd_smartcard_manager_set_property (GObject *object,
195 guint prop_id,
196 const GValue *value,
197 GParamSpec *pspec)
198 {
199 CsdSmartcardManager *manager = CSD_SMARTCARD_MANAGER (object);
200
201 switch (prop_id) {
202 case PROP_MODULE_PATH:
203 csd_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
csd_smartcard_manager_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)214 csd_smartcard_manager_get_property (GObject *object,
215 guint prop_id,
216 GValue *value,
217 GParamSpec *pspec)
218 {
219 CsdSmartcardManager *manager = CSD_SMARTCARD_MANAGER (object);
220 char *module_path;
221
222 switch (prop_id) {
223 case PROP_MODULE_PATH:
224 module_path = csd_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 *
csd_smartcard_manager_get_module_path(CsdSmartcardManager * manager)236 csd_smartcard_manager_get_module_path (CsdSmartcardManager *manager)
237 {
238 return manager->priv->module_path;
239 }
240
241 static void
csd_smartcard_manager_set_module_path(CsdSmartcardManager * manager,const char * module_path)242 csd_smartcard_manager_set_module_path (CsdSmartcardManager *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
csd_smartcard_manager_card_removed_handler(CsdSmartcardManager * manager,CsdSmartcard * card)259 csd_smartcard_manager_card_removed_handler (CsdSmartcardManager *manager,
260 CsdSmartcard *card)
261 {
262 g_debug ("informing smartcard of its removal");
263 _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_REMOVED);
264 g_debug ("done");
265 }
266
267 static void
csd_smartcard_manager_card_inserted_handler(CsdSmartcardManager * manager,CsdSmartcard * card)268 csd_smartcard_manager_card_inserted_handler (CsdSmartcardManager *manager,
269 CsdSmartcard *card)
270 {
271 g_debug ("informing smartcard of its insertion");
272
273 _csd_smartcard_set_state (card, CSD_SMARTCARD_STATE_INSERTED);
274 g_debug ("done");
275
276 }
277
278 static void
csd_smartcard_manager_class_install_signals(CsdSmartcardManagerClass * manager_class)279 csd_smartcard_manager_class_install_signals (CsdSmartcardManagerClass *manager_class)
280 {
281 GObjectClass *object_class;
282
283 object_class = G_OBJECT_CLASS (manager_class);
284
285 csd_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 (CsdSmartcardManagerClass,
290 smartcard_inserted),
291 NULL, NULL, g_cclosure_marshal_VOID__POINTER,
292 G_TYPE_NONE, 1, G_TYPE_POINTER);
293 manager_class->smartcard_inserted = csd_smartcard_manager_card_inserted_handler;
294
295 csd_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 (CsdSmartcardManagerClass,
300 smartcard_removed),
301 NULL, NULL, g_cclosure_marshal_VOID__POINTER,
302 G_TYPE_NONE, 1, G_TYPE_POINTER);
303 manager_class->smartcard_removed = csd_smartcard_manager_card_removed_handler;
304
305 csd_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 (CsdSmartcardManagerClass, 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
slot_id_equal(CK_SLOT_ID * slot_id_1,CK_SLOT_ID * slot_id_2)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
slot_id_hash(CK_SLOT_ID * slot_id)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
csd_smartcard_manager_init(CsdSmartcardManager * manager)347 csd_smartcard_manager_init (CsdSmartcardManager *manager)
348 {
349 g_debug ("initializing smartcard manager");
350
351 manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
352 CSD_TYPE_SMARTCARD_MANAGER,
353 CsdSmartcardManagerPrivate);
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
csd_smartcard_manager_finalize(GObject * object)365 csd_smartcard_manager_finalize (GObject *object)
366 {
367 CsdSmartcardManager *manager;
368 GObjectClass *gobject_class;
369
370 manager = CSD_SMARTCARD_MANAGER (object);
371 gobject_class =
372 G_OBJECT_CLASS (csd_smartcard_manager_parent_class);
373
374 csd_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
csd_smartcard_manager_error_quark(void)383 csd_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 ("csd-smartcard-manager-error-quark");
389 }
390
391 return error_quark;
392 }
393
394 CsdSmartcardManager *
csd_smartcard_manager_new_default(void)395 csd_smartcard_manager_new_default (void)
396 {
397 return csd_smartcard_manager_new (NULL);
398 }
399
400 CsdSmartcardManager *
csd_smartcard_manager_new(const char * module_path)401 csd_smartcard_manager_new (const char *module_path)
402 {
403 CsdSmartcardManager *instance;
404
405 instance = CSD_SMARTCARD_MANAGER (g_object_new (CSD_TYPE_SMARTCARD_MANAGER,
406 "module-path", module_path,
407 NULL));
408
409 return instance;
410 }
411
412 static void
csd_smartcard_manager_emit_error(CsdSmartcardManager * manager,GError * error)413 csd_smartcard_manager_emit_error (CsdSmartcardManager *manager,
414 GError *error)
415 {
416 manager->priv->is_unstoppable = TRUE;
417 g_signal_emit (manager, csd_smartcard_manager_signals[ERROR], 0,
418 error);
419 manager->priv->is_unstoppable = FALSE;
420 }
421
422 static void
csd_smartcard_manager_emit_smartcard_inserted(CsdSmartcardManager * manager,CsdSmartcard * card)423 csd_smartcard_manager_emit_smartcard_inserted (CsdSmartcardManager *manager,
424 CsdSmartcard *card)
425 {
426 manager->priv->is_unstoppable = TRUE;
427 g_signal_emit (manager, csd_smartcard_manager_signals[SMARTCARD_INSERTED], 0,
428 card);
429 manager->priv->is_unstoppable = FALSE;
430 }
431
432 static void
csd_smartcard_manager_emit_smartcard_removed(CsdSmartcardManager * manager,CsdSmartcard * card)433 csd_smartcard_manager_emit_smartcard_removed (CsdSmartcardManager *manager,
434 CsdSmartcard *card)
435 {
436 manager->priv->is_unstoppable = TRUE;
437 g_signal_emit (manager, csd_smartcard_manager_signals[SMARTCARD_REMOVED], 0,
438 card);
439 manager->priv->is_unstoppable = FALSE;
440 }
441
442 static gboolean
csd_smartcard_manager_check_for_and_process_events(GIOChannel * io_channel,GIOCondition condition,CsdSmartcardManagerWorker * worker)443 csd_smartcard_manager_check_for_and_process_events (GIOChannel *io_channel,
444 GIOCondition condition,
445 CsdSmartcardManagerWorker *worker)
446 {
447 CsdSmartcard *card;
448 CsdSmartcardManager *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 = csd_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 csd_smartcard_manager_emit_smartcard_inserted (manager, card);
501 card = NULL;
502 break;
503
504 case 'R':
505 csd_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 (CSD_SMARTCARD_MANAGER_ERROR,
528 CSD_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 csd_smartcard_manager_emit_error (manager, error);
532 g_error_free (error);
533 csd_smartcard_manager_stop_now (manager);
534 return FALSE;
535 }
536
537 return TRUE;
538 }
539
540 static void
stop_manager(CsdSmartcardManager * manager)541 stop_manager (CsdSmartcardManager *manager)
542 {
543 manager->priv->state = CSD_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
stop_worker(CsdSmartcardManagerWorker * worker)553 stop_worker (CsdSmartcardManagerWorker *worker)
554 {
555 CsdSmartcardManager *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 != CSD_SMARTCARD_MANAGER_STATE_STOPPED) {
573 stop_manager (manager);
574 }
575 }
576
577 static void
csd_smartcard_manager_event_processing_stopped_handler(CsdSmartcardManagerWorker * worker)578 csd_smartcard_manager_event_processing_stopped_handler (CsdSmartcardManagerWorker *worker)
579 {
580 worker->event_source = NULL;
581
582 stop_worker (worker);
583 }
584
585 static gboolean
open_pipe(int * write_fd,int * read_fd)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
csd_smartcard_manager_stop_watching_for_events(CsdSmartcardManager * manager)617 csd_smartcard_manager_stop_watching_for_events (CsdSmartcardManager *manager)
618 {
619 GList *node;
620
621 node = manager->priv->workers;
622 while (node != NULL) {
623 CsdSmartcardManagerWorker *worker;
624 GList *next_node;
625
626 worker = (CsdSmartcardManagerWorker *) node->data;
627 next_node = node->next;
628
629 stop_worker (worker);
630
631 node = next_node;
632 }
633 }
634
635 static gboolean
load_nss(GError ** error)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 CSD_SMARTCARD_MANAGER_NSS_DB);
646
647 PR_Init (PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
648
649 status = NSS_Initialize (CSD_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 CSD_SMARTCARD_MANAGER_ERROR,
662 CSD_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 CSD_SMARTCARD_MANAGER_ERROR,
672 CSD_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 successfully loaded");
683 return TRUE;
684
685 out:
686 g_debug ("NSS database couldn't be successfully loaded");
687 return FALSE;
688 }
689
690 static GList *
get_available_modules(CsdSmartcardManager * manager)691 get_available_modules (CsdSmartcardManager *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
load_driver(CsdSmartcardManager * manager,char * module_path,GError ** error)715 load_driver (CsdSmartcardManager *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 = CSD_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 CSD_SMARTCARD_MANAGER_ERROR,
790 CSD_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 CSD_SMARTCARD_MANAGER_ERROR,
804 CSD_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 CSD_SMARTCARD_MANAGER_ERROR,
815 CSD_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
csd_smartcard_manager_get_all_cards(CsdSmartcardManager * manager)829 csd_smartcard_manager_get_all_cards (CsdSmartcardManager *manager)
830 {
831 GList *node;
832 int i;
833
834 node = manager->priv->workers;
835 while (node != NULL) {
836
837 CsdSmartcardManagerWorker *worker;
838
839 worker = (CsdSmartcardManagerWorker *) node->data;
840
841 for (i = 0; i < worker->module->slotCount; i++) {
842 CsdSmartcard *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 = _csd_smartcard_new (worker->module,
851 slot_id, slot_series);
852
853 card_name = csd_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 CsdSmartcardManagerWorker *
start_worker(CsdSmartcardManager * manager,SECMODModule * module,GError ** error)863 start_worker (CsdSmartcardManager *manager,
864 SECMODModule *module,
865 GError **error)
866 {
867 GIOChannel *io_channel;
868 GSource *source;
869 CsdSmartcardManagerWorker *worker;
870
871 worker = csd_smartcard_manager_create_worker (manager, module);
872
873 if (worker == NULL) {
874 g_set_error (error,
875 CSD_SMARTCARD_MANAGER_ERROR,
876 CSD_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 csd_smartcard_manager_check_for_and_process_events,
894 worker,
895 (GDestroyNotify)
896 csd_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
start_workers(CsdSmartcardManager * manager)904 start_workers (CsdSmartcardManager *manager)
905 {
906 GList *node;
907
908 node = manager->priv->modules;
909 while (node != NULL) {
910 SECMODModule *module;
911 CsdSmartcardManagerWorker *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
csd_smartcard_manager_start(CsdSmartcardManager * manager,GError ** error)930 csd_smartcard_manager_start (CsdSmartcardManager *manager,
931 GError **error)
932 {
933 GError *nss_error;
934
935 if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STARTED) {
936 g_debug ("smartcard manager already started");
937 return TRUE;
938 }
939
940 manager->priv->state = CSD_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 csd_smartcard_manager_get_all_cards (manager);
961
962 manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STARTED;
963
964 out:
965 /* don't leave it in a half started state
966 */
967 if (manager->priv->state != CSD_SMARTCARD_MANAGER_STATE_STARTED) {
968 g_debug ("smartcard manager could not be completely started");
969 csd_smartcard_manager_stop (manager);
970 } else {
971 g_debug ("smartcard manager started");
972 }
973
974 return manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STARTED;
975 }
976
977 static gboolean
csd_smartcard_manager_stop_now(CsdSmartcardManager * manager)978 csd_smartcard_manager_stop_now (CsdSmartcardManager *manager)
979 {
980 if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STOPPED) {
981 return FALSE;
982 }
983
984 csd_smartcard_manager_stop_watching_for_events (manager);
985
986 return FALSE;
987 }
988
989 static void
csd_smartcard_manager_queue_stop(CsdSmartcardManager * manager)990 csd_smartcard_manager_queue_stop (CsdSmartcardManager *manager)
991 {
992
993 manager->priv->state = CSD_SMARTCARD_MANAGER_STATE_STOPPING;
994
995 g_idle_add ((GSourceFunc) csd_smartcard_manager_stop_now, manager);
996 }
997
998 void
csd_smartcard_manager_stop(CsdSmartcardManager * manager)999 csd_smartcard_manager_stop (CsdSmartcardManager *manager)
1000 {
1001 if (manager->priv->state == CSD_SMARTCARD_MANAGER_STATE_STOPPED) {
1002 return;
1003 }
1004
1005 if (manager->priv->is_unstoppable) {
1006 csd_smartcard_manager_queue_stop (manager);
1007 return;
1008 }
1009
1010 csd_smartcard_manager_stop_now (manager);
1011 }
1012
1013 static void
csd_smartcard_manager_check_for_login_card(CK_SLOT_ID slot_id,CsdSmartcard * card,gboolean * is_inserted)1014 csd_smartcard_manager_check_for_login_card (CK_SLOT_ID slot_id,
1015 CsdSmartcard *card,
1016 gboolean *is_inserted)
1017 {
1018 g_assert (is_inserted != NULL);
1019
1020 if (csd_smartcard_is_login_card (card)) {
1021 *is_inserted = TRUE;
1022 }
1023
1024 }
1025
1026 gboolean
csd_smartcard_manager_login_card_is_inserted(CsdSmartcardManager * manager)1027 csd_smartcard_manager_login_card_is_inserted (CsdSmartcardManager *manager)
1028
1029 {
1030 gboolean is_inserted;
1031
1032 is_inserted = FALSE;
1033 g_hash_table_foreach (manager->priv->smartcards,
1034 (GHFunc)
1035 csd_smartcard_manager_check_for_login_card,
1036 &is_inserted);
1037 return is_inserted;
1038 }
1039
1040 static CsdSmartcardManagerWorker *
csd_smartcard_manager_worker_new(CsdSmartcardManager * manager,int worker_fd,int manager_fd,SECMODModule * module)1041 csd_smartcard_manager_worker_new (CsdSmartcardManager *manager,
1042 int worker_fd,
1043 int manager_fd,
1044 SECMODModule *module)
1045 {
1046 CsdSmartcardManagerWorker *worker;
1047
1048 worker = g_slice_new0 (CsdSmartcardManagerWorker);
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
csd_smartcard_manager_worker_free(CsdSmartcardManagerWorker * worker)1064 csd_smartcard_manager_worker_free (CsdSmartcardManagerWorker *worker)
1065 {
1066 if (worker->smartcards != NULL) {
1067 g_hash_table_destroy (worker->smartcards);
1068 worker->smartcards = NULL;
1069 }
1070
1071 g_slice_free (CsdSmartcardManagerWorker, worker);
1072 }
1073
1074 static gboolean
read_bytes(int fd,gpointer bytes,gsize num_bytes)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
write_bytes(int fd,gconstpointer bytes,gsize num_bytes)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 CsdSmartcard *
read_smartcard(int fd,SECMODModule * module)1149 read_smartcard (int fd,
1150 SECMODModule *module)
1151 {
1152 CsdSmartcard *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 = _csd_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
write_smartcard(int fd,CsdSmartcard * card)1173 write_smartcard (int fd,
1174 CsdSmartcard *card)
1175 {
1176 gsize card_name_size;
1177 char *card_name;
1178
1179 card_name = csd_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
csd_smartcard_manager_worker_emit_smartcard_removed(CsdSmartcardManagerWorker * worker,CsdSmartcard * card,GError ** error)1197 csd_smartcard_manager_worker_emit_smartcard_removed (CsdSmartcardManagerWorker *worker,
1198 CsdSmartcard *card,
1199 GError **error)
1200 {
1201 g_debug ("card '%s' removed!", csd_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, CSD_SMARTCARD_MANAGER_ERROR,
1215 CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
1216 "%s", g_strerror (errno));
1217 return FALSE;
1218 }
1219
1220 static gboolean
csd_smartcard_manager_worker_emit_smartcard_inserted(CsdSmartcardManagerWorker * worker,CsdSmartcard * card,GError ** error)1221 csd_smartcard_manager_worker_emit_smartcard_inserted (CsdSmartcardManagerWorker *worker,
1222 CsdSmartcard *card,
1223 GError **error)
1224 {
1225 g_debug ("card '%s' inserted!", csd_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, CSD_SMARTCARD_MANAGER_ERROR,
1238 CSD_SMARTCARD_MANAGER_ERROR_REPORTING_EVENTS,
1239 "%s", g_strerror (errno));
1240 return FALSE;
1241 }
1242
1243 static gboolean
csd_smartcard_manager_worker_watch_for_and_process_event(CsdSmartcardManagerWorker * worker,GError ** error)1244 csd_smartcard_manager_worker_watch_for_and_process_event (CsdSmartcardManagerWorker *worker,
1245 GError **error)
1246 {
1247 PK11SlotInfo *slot;
1248 CK_SLOT_ID slot_id, *key = NULL;
1249 int slot_series, card_slot_series;
1250 CsdSmartcard *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 ("spurious 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, CSD_SMARTCARD_MANAGER_ERROR,
1274 CSD_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 = csd_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 (!csd_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 = _csd_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 (!csd_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 (!csd_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 = _csd_smartcard_new (worker->module,
1347 slot_id, slot_series);
1348 g_hash_table_replace (worker->smartcards,
1349 key, card);
1350 key = NULL;
1351 if (!csd_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 (!csd_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
csd_smartcard_manager_worker_run(CsdSmartcardManagerWorker * worker)1379 csd_smartcard_manager_worker_run (CsdSmartcardManagerWorker *worker)
1380 {
1381 GError *error;
1382 gboolean should_continue;
1383
1384 do
1385 {
1386 error = NULL;
1387 should_continue = csd_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 csd_smartcard_manager_worker_free (worker);
1397 }
1398
1399 static CsdSmartcardManagerWorker *
csd_smartcard_manager_create_worker(CsdSmartcardManager * manager,SECMODModule * module)1400 csd_smartcard_manager_create_worker (CsdSmartcardManager *manager,
1401 SECMODModule *module)
1402 {
1403 CsdSmartcardManagerWorker *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 = csd_smartcard_manager_worker_new (manager,
1413 write_fd,
1414 read_fd,
1415 module);
1416
1417 worker->thread = g_thread_create ((GThreadFunc)
1418 csd_smartcard_manager_worker_run,
1419 worker, FALSE, NULL);
1420
1421 if (worker->thread == NULL) {
1422 csd_smartcard_manager_worker_free (worker);
1423 return NULL;
1424 }
1425
1426 return worker;
1427 }
1428
1429 #ifdef CSD_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
on_timeout(CsdSmartcardManager * manager)1436 on_timeout (CsdSmartcardManager *manager)
1437 {
1438 GError *error;
1439 g_print ("Re-enabling manager.\n");
1440
1441 if (!csd_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
on_device_inserted(CsdSmartcardManager * manager,CsdSmartcard * card)1455 on_device_inserted (CsdSmartcardManager *manager,
1456 CsdSmartcard *card)
1457 {
1458 g_print ("smartcard inserted!\n");
1459 g_print ("Please remove it.\n");
1460 }
1461
1462 static void
on_device_removed(CsdSmartcardManager * manager,CsdSmartcard * card)1463 on_device_removed (CsdSmartcardManager *manager,
1464 CsdSmartcard *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 csd_smartcard_manager_stop (manager);
1473 g_timeout_add_seconds (2, (GSourceFunc) on_timeout, manager);
1474 }
1475 }
1476
1477 int
main(int argc,char * argv[])1478 main (int argc,
1479 char *argv[])
1480 {
1481 CsdSmartcardManager *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
1488 g_message ("creating instance of 'smartcard manager' object...");
1489 manager = csd_smartcard_manager_new (NULL);
1490 g_message ("'smartcard manager' object created successfully");
1491
1492 g_signal_connect (manager, "smartcard-inserted",
1493 G_CALLBACK (on_device_inserted), NULL);
1494
1495 g_signal_connect (manager, "smartcard-removed",
1496 G_CALLBACK (on_device_removed), NULL);
1497
1498 g_message ("starting listener...");
1499
1500 error = NULL;
1501 if (!csd_smartcard_manager_start (manager, &error)) {
1502 g_warning ("could not start smartcard manager - %s",
1503 error->message);
1504 g_error_free (error);
1505 return 1;
1506 }
1507
1508 event_loop = g_main_loop_new (NULL, FALSE);
1509 g_main_loop_run (event_loop);
1510 g_main_loop_unref (event_loop);
1511 event_loop = NULL;
1512
1513 g_message ("destroying previously created 'smartcard manager' object...");
1514 g_object_unref (manager);
1515 manager = NULL;
1516 g_message ("'smartcard manager' object destroyed successfully");
1517
1518 return 0;
1519 }
1520 #endif
1521