lib: All settings use configured namespace
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_manager.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "pkcs11_manager.h"
17
18 #include <utils/debug.h>
19 #include <collections/linked_list.h>
20 #include <threading/thread.h>
21
22 #include "pkcs11_library.h"
23
24 #include <processing/jobs/callback_job.h>
25
26 typedef struct private_pkcs11_manager_t private_pkcs11_manager_t;
27
28 /**
29 * Private data of an pkcs11_manager_t object.
30 */
31 struct private_pkcs11_manager_t {
32
33 /**
34 * Public pkcs11_manager_t interface.
35 */
36 pkcs11_manager_t public;
37
38 /**
39 * List of loaded libraries, as lib_entry_t
40 */
41 linked_list_t *libs;
42
43 /**
44 * Slot event callback function
45 */
46 pkcs11_manager_token_event_t cb;
47
48 /**
49 * Slot event user data
50 */
51 void *data;
52 };
53
54 /**
55 * Entry for a loaded library
56 */
57 typedef struct {
58 /* back reference to this */
59 private_pkcs11_manager_t *this;
60 /* associated library path */
61 char *path;
62 /* loaded library */
63 pkcs11_library_t *lib;
64 } lib_entry_t;
65
66 /**
67 * Destroy a lib_entry_t
68 */
69 static void lib_entry_destroy(lib_entry_t *entry)
70 {
71 entry->lib->destroy(entry->lib);
72 free(entry);
73 }
74
75 /**
76 * Print supported mechanisms of a token in a slot
77 */
78 static void print_mechs(lib_entry_t *entry, CK_SLOT_ID slot)
79 {
80 enumerator_t *enumerator;
81 CK_MECHANISM_TYPE type;
82 CK_MECHANISM_INFO info;
83
84 enumerator = entry->lib->create_mechanism_enumerator(entry->lib, slot);
85 while (enumerator->enumerate(enumerator, &type, &info))
86 {
87 DBG2(DBG_CFG, " %N %lu-%lu [ %s%s%s%s%s%s%s%s%s%s%s%s%s]",
88 ck_mech_names, type,
89 info.ulMinKeySize, info.ulMaxKeySize,
90 info.flags & CKF_HW ? "HW " : "",
91 info.flags & CKF_ENCRYPT ? "ENCR " : "",
92 info.flags & CKF_DECRYPT ? "DECR " : "",
93 info.flags & CKF_DIGEST ? "DGST " : "",
94 info.flags & CKF_SIGN ? "SIGN " : "",
95 info.flags & CKF_SIGN_RECOVER ? "SIGN_RCVR " : "",
96 info.flags & CKF_VERIFY ? "VRFY " : "",
97 info.flags & CKF_VERIFY_RECOVER ? "VRFY_RCVR " : "",
98 info.flags & CKF_GENERATE ? "GEN " : "",
99 info.flags & CKF_GENERATE_KEY_PAIR ? "GEN_KEY_PAIR " : "",
100 info.flags & CKF_WRAP ? "WRAP " : "",
101 info.flags & CKF_UNWRAP ? "UNWRAP " : "",
102 info.flags & CKF_DERIVE ? "DERIVE " : "");
103 }
104 enumerator->destroy(enumerator);
105 }
106
107 /**
108 * Handle a token
109 */
110 static void handle_token(lib_entry_t *entry, CK_SLOT_ID slot)
111 {
112 CK_TOKEN_INFO info;
113 CK_RV rv;
114
115 rv = entry->lib->f->C_GetTokenInfo(slot, &info);
116 if (rv != CKR_OK)
117 {
118 DBG1(DBG_CFG, "C_GetTokenInfo failed: %N", ck_rv_names, rv);
119 return;
120 }
121 pkcs11_library_trim(info.label, sizeof(info.label));
122 pkcs11_library_trim(info.manufacturerID, sizeof(info.manufacturerID));
123 pkcs11_library_trim(info.model, sizeof(info.model));
124 DBG1(DBG_CFG, " %s (%s: %s)",
125 info.label, info.manufacturerID, info.model);
126
127 print_mechs(entry, slot);
128 }
129
130 /**
131 * Handle slot changes
132 */
133 static void handle_slot(lib_entry_t *entry, CK_SLOT_ID slot, bool hot)
134 {
135 CK_SLOT_INFO info;
136 CK_RV rv;
137
138 rv = entry->lib->f->C_GetSlotInfo(slot, &info);
139 if (rv != CKR_OK)
140 {
141 DBG1(DBG_CFG, "C_GetSlotInfo failed: %N", ck_rv_names, rv);
142 return;
143 }
144
145 pkcs11_library_trim(info.slotDescription, sizeof(info.slotDescription));
146 if (info.flags & CKF_TOKEN_PRESENT)
147 {
148 DBG1(DBG_CFG, " found token in slot '%s':%lu (%s)",
149 entry->lib->get_name(entry->lib), slot, info.slotDescription);
150 handle_token(entry, slot);
151 if (hot)
152 {
153 entry->this->cb(entry->this->data, entry->lib, slot, TRUE);
154 }
155 }
156 else
157 {
158 DBG1(DBG_CFG, "token removed from slot '%s':%lu (%s)",
159 entry->lib->get_name(entry->lib), slot, info.slotDescription);
160 if (hot)
161 {
162 entry->this->cb(entry->this->data, entry->lib, slot, FALSE);
163 }
164 }
165 }
166
167 /**
168 * Dispatch slot events
169 */
170 static job_requeue_t dispatch_slot_events(lib_entry_t *entry)
171 {
172 CK_SLOT_ID slot;
173 CK_RV rv;
174 bool old;
175
176 old = thread_cancelability(TRUE);
177 rv = entry->lib->f->C_WaitForSlotEvent(0, &slot, NULL);
178 thread_cancelability(old);
179 if (rv == CKR_FUNCTION_NOT_SUPPORTED || rv == CKR_NO_EVENT)
180 {
181 DBG1(DBG_CFG, "module '%s' does not support hot-plugging, cancelled",
182 entry->lib->get_name(entry->lib));
183 return JOB_REQUEUE_NONE;
184 }
185 if (rv == CKR_CRYPTOKI_NOT_INITIALIZED)
186 { /* C_Finalize called, abort */
187 return JOB_REQUEUE_NONE;
188 }
189 if (rv != CKR_OK)
190 {
191 DBG1(DBG_CFG, "error in C_WaitForSlotEvent: %N", ck_rv_names, rv);
192 }
193 handle_slot(entry, slot, TRUE);
194
195 return JOB_REQUEUE_DIRECT;
196 }
197
198 /**
199 * Get the slot list of a library
200 */
201 static CK_SLOT_ID_PTR get_slot_list(pkcs11_library_t *p11, CK_ULONG *out)
202 {
203 CK_SLOT_ID_PTR slots;
204 CK_ULONG count;
205 CK_RV rv;
206
207 rv = p11->f->C_GetSlotList(TRUE, NULL, &count);
208 if (rv != CKR_OK)
209 {
210 DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
211 return NULL;
212 }
213 if (count == 0)
214 {
215 return NULL;
216 }
217 slots = malloc(sizeof(CK_SLOT_ID) * count);
218 rv = p11->f->C_GetSlotList(TRUE, slots, &count);
219 if (rv != CKR_OK)
220 {
221 DBG1(DBG_CFG, "C_GetSlotList() failed: %N", ck_rv_names, rv);
222 free(slots);
223 return NULL;
224 }
225 *out = count;
226 return slots;
227 }
228
229 /**
230 * Query the slots for tokens
231 */
232 static void query_slots(lib_entry_t *entry)
233 {
234 CK_ULONG count;
235 CK_SLOT_ID_PTR slots;
236 int i;
237
238 slots = get_slot_list(entry->lib, &count);
239 if (slots)
240 {
241 for (i = 0; i < count; i++)
242 {
243 handle_slot(entry, slots[i], FALSE);
244 }
245 free(slots);
246 }
247 }
248
249 /**
250 * Token enumerator
251 */
252 typedef struct {
253 /* implements enumerator */
254 enumerator_t public;
255 /* inner enumerator over PKCS#11 libraries */
256 enumerator_t *inner;
257 /* active library entry */
258 lib_entry_t *entry;
259 /* slot list with tokens */
260 CK_SLOT_ID_PTR slots;
261 /* number of slots */
262 CK_ULONG count;
263 /* current slot */
264 int current;
265 } token_enumerator_t;
266
267 METHOD(enumerator_t, enumerate_token, bool,
268 token_enumerator_t *this, pkcs11_library_t **out, CK_SLOT_ID *slot)
269 {
270 if (this->current >= this->count)
271 {
272 free(this->slots);
273 this->slots = NULL;
274 this->current = 0;
275 }
276 while (!this->slots)
277 {
278 if (!this->inner->enumerate(this->inner, &this->entry))
279 {
280 return FALSE;
281 }
282 this->slots = get_slot_list(this->entry->lib, &this->count);
283 }
284 *out = this->entry->lib;
285 *slot = this->slots[this->current++];
286 return TRUE;
287 }
288
289 METHOD(enumerator_t, destroy_token, void,
290 token_enumerator_t *this)
291 {
292 this->inner->destroy(this->inner);
293 free(this->slots);
294 free(this);
295 }
296
297 METHOD(pkcs11_manager_t, create_token_enumerator, enumerator_t*,
298 private_pkcs11_manager_t *this)
299 {
300 token_enumerator_t *enumerator;
301
302 INIT(enumerator,
303 .public = {
304 .enumerate = (void*)_enumerate_token,
305 .destroy = _destroy_token,
306 },
307 .inner = this->libs->create_enumerator(this->libs),
308 );
309 return &enumerator->public;
310 }
311
312 METHOD(pkcs11_manager_t, destroy, void,
313 private_pkcs11_manager_t *this)
314 {
315 this->libs->destroy_function(this->libs, (void*)lib_entry_destroy);
316 free(this);
317 }
318
319 /**
320 * See header
321 */
322 pkcs11_manager_t *pkcs11_manager_create(pkcs11_manager_token_event_t cb,
323 void *data)
324 {
325 private_pkcs11_manager_t *this;
326 enumerator_t *enumerator;
327 lib_entry_t *entry;
328 char *module;
329
330 INIT(this,
331 .public = {
332 .create_token_enumerator = _create_token_enumerator,
333 .destroy = _destroy,
334 },
335 .libs = linked_list_create(),
336 .cb = cb,
337 .data = data,
338 );
339
340 enumerator = lib->settings->create_section_enumerator(lib->settings,
341 "%s.plugins.pkcs11.modules", lib->ns);
342 while (enumerator->enumerate(enumerator, &module))
343 {
344 INIT(entry,
345 .this = this,
346 );
347
348 entry->path = lib->settings->get_str(lib->settings,
349 "%s.plugins.pkcs11.modules.%s.path", NULL, lib->ns, module);
350 if (!entry->path)
351 {
352 DBG1(DBG_CFG, "PKCS11 module '%s' lacks library path", module);
353 free(entry);
354 continue;
355 }
356 entry->lib = pkcs11_library_create(module, entry->path,
357 lib->settings->get_bool(lib->settings,
358 "%s.plugins.pkcs11.modules.%s.os_locking",
359 FALSE, lib->ns, module));
360 if (!entry->lib)
361 {
362 free(entry);
363 continue;
364 }
365 this->libs->insert_last(this->libs, entry);
366 }
367 enumerator->destroy(enumerator);
368
369 enumerator = this->libs->create_enumerator(this->libs);
370 while (enumerator->enumerate(enumerator, &entry))
371 {
372 query_slots(entry);
373 lib->processor->queue_job(lib->processor,
374 (job_t*)callback_job_create_with_prio((void*)dispatch_slot_events,
375 entry, NULL, (void*)return_false, JOB_PRIO_CRITICAL));
376 }
377 enumerator->destroy(enumerator);
378
379 return &this->public;
380 }
381