4
* Copyright (C) 2008 Stefan Walter
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General License as
8
* published by the Free Software Foundation; either version 2.1 of
9
* the License, or (at your option) any later version.
11
* This program is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General License for more details.
16
* You should have received a copy of the GNU Lesser General
17
* License along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24
#include "gkd-pkcs11-data.h"
26
#include "egg/egg-cleanup.h"
27
#include "egg/egg-secure-memory.h"
29
#include "login/gkd-login.h"
31
#include "pkcs11/pkcs11.h"
33
#include "prompt/gkd-prompt.h"
36
#include <glib/gi18n.h>
41
* THREADING INFO: These functions are called from multiple threads. All gkd_pkcs11_data_*()
42
* functions here with the exception of gkd_pkcs11_data_free_object() are locked. Again with
43
* the exception of gkd_pkcs11_data_free_object() they must not be called from one another.
46
typedef struct _SlotData {
48
GHashTable *session_to_data;
51
typedef struct _SessionData {
53
GDestroyNotify destroy_func;
56
/* A hash table of CK_SLOT_ID_PTR to SlotData */
57
static GHashTable *per_slot_data = NULL;
58
G_LOCK_DEFINE_STATIC (pkcs11_data);
61
free_slot_data (gpointer data)
63
SlotData *sdata = data;
65
if (sdata->session_to_data)
66
g_hash_table_destroy (sdata->session_to_data);
67
g_slice_free (SlotData, sdata);
71
free_session_data (gpointer data)
73
SessionData *sdata = data;
75
if (sdata->destroy_func && sdata->user_data)
76
(sdata->destroy_func) (sdata->user_data);
77
g_slice_free (SessionData, sdata);
81
ulong_alloc (CK_ULONG value)
83
return g_slice_dup (CK_ULONG, &value);
87
ulong_free (gpointer ptr_to_ulong)
89
g_slice_free (CK_ULONG, ptr_to_ulong);
93
ulong_hash (gconstpointer v)
95
const signed char *p = v;
97
for(i = 0; i < sizeof (CK_ULONG); ++i)
98
h = (h << 5) - h + *(p++);
103
ulong_equal (gconstpointer v1, gconstpointer v2)
105
return *((const CK_ULONG*)v1) == *((const CK_ULONG*)v2);
109
store_data_unlocked (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle,
110
gpointer data, GDestroyNotify destroy_func)
115
/* Because we should have been notified when a session was opened */
116
g_return_if_fail (per_slot_data);
118
slot = g_hash_table_lookup (per_slot_data, &slot_id);
119
g_return_if_fail (slot);
121
/* Delayed allocation because we may never use this on a slot */
122
if (slot->session_to_data == NULL)
123
slot->session_to_data = g_hash_table_new_full (ulong_hash, ulong_equal, ulong_free, free_session_data);
125
sdata = g_slice_new0 (SessionData);
126
sdata->user_data = data;
127
sdata->destroy_func = destroy_func;
128
g_hash_table_replace (slot->session_to_data, ulong_alloc (handle), sdata);
132
gkd_pkcs11_data_session_store (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle,
133
gpointer data, GDestroyNotify destroy_func)
136
store_data_unlocked (slot_id, handle, data, destroy_func);
137
G_UNLOCK (pkcs11_data);
141
lookup_data_unlocked (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle)
146
/* Because we should have been notified of open session */
147
g_return_val_if_fail (per_slot_data, FALSE);
149
/* Lookup the structure for this slot */
150
slot = g_hash_table_lookup (per_slot_data, &slot_id);
151
if (slot == NULL || slot->session_to_data == NULL)
154
sdata = g_hash_table_lookup (slot->session_to_data, &handle);
158
return sdata->user_data;
162
gkd_pkcs11_data_session_lookup (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle)
165
G_LOCK (pkcs11_data);
166
ret = lookup_data_unlocked (slot_id, handle);
167
G_UNLOCK (pkcs11_data);
172
remove_data_unlocked (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle)
176
/* Because we should have been notified of open session */
177
g_return_if_fail (per_slot_data);
179
slot = g_hash_table_lookup (per_slot_data, &slot_id);
180
g_assert (slot != NULL && slot->session_to_data != NULL);
182
g_hash_table_remove (slot->session_to_data, &handle);
186
gkd_pkcs11_data_session_remove (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle)
188
G_LOCK (pkcs11_data);
189
remove_data_unlocked (slot_id, handle);
190
G_UNLOCK (pkcs11_data);
194
gkd_pkcs11_data_initialized (void)
196
G_LOCK (pkcs11_data);
197
g_warn_if_fail (!per_slot_data);
198
per_slot_data = g_hash_table_new_full (ulong_hash, ulong_equal, ulong_free,
199
(GDestroyNotify)free_slot_data);
200
G_UNLOCK (pkcs11_data);
204
gkd_pkcs11_data_session_opened (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle)
208
G_LOCK (pkcs11_data);
210
slot = g_hash_table_lookup (per_slot_data, &slot_id);
212
slot = g_slice_new0 (SlotData);
213
g_hash_table_replace (per_slot_data, ulong_alloc (slot_id), slot);
216
/* Track how many open sessions there are */
217
++slot->open_sessions;
219
G_UNLOCK (pkcs11_data);
223
gkd_pkcs11_data_session_closed (CK_SLOT_ID slot_id, CK_SESSION_HANDLE handle)
227
G_LOCK (pkcs11_data);
229
g_warn_if_fail (per_slot_data);
231
slot = g_hash_table_lookup (per_slot_data, &slot_id);
232
g_warn_if_fail (slot);
233
g_assert (slot->open_sessions > 0);
235
/* Track how many open sessions there are */
236
--(slot->open_sessions);
237
if (slot->open_sessions == 0)
238
g_hash_table_remove (per_slot_data, &slot_id);
240
G_UNLOCK (pkcs11_data);
244
gkd_pkcs11_data_session_closed_all (CK_SLOT_ID id)
246
G_LOCK (pkcs11_data);
248
/* Remove all information about this slot */
249
g_warn_if_fail (per_slot_data);
250
g_hash_table_remove (per_slot_data, &id);
252
G_UNLOCK (pkcs11_data);
256
gkd_pkcs11_data_finalized (void)
258
G_LOCK (pkcs11_data);
259
g_warn_if_fail (per_slot_data);
260
g_hash_table_destroy (per_slot_data);
261
per_slot_data = NULL;
262
G_UNLOCK (pkcs11_data);