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