1 /*
2 * COPYRIGHT (c) International Business Machines Corp. 2001-2017
3 *
4 * This program is provided under the terms of the Common Public License,
5 * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
6 * software constitutes recipient's acceptance of CPL-1.0 terms which can be
7 * found in the file LICENSE file or at
8 * https://opensource.org/licenses/cpl1.0.php
9 */
10
11 //
12 //
13 //AIX Pkcs11 Api Utility functions
14 //
15
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <strings.h>
21 #include <unistd.h>
22 #include <dlfcn.h>
23 #include <errno.h>
24 #include <sys/syslog.h>
25 #include <limits.h>
26
27 #include <sys/ipc.h>
28
29 #include <pkcs11types.h>
30 #include <apiclient.h> // Function prototypes for PKCS11
31 #include <slotmgr.h>
32 #include <apictl.h>
33 #include <apiproto.h>
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38
39 static int xplfd = -1;
40
41 #include <libgen.h>
42
43 #define LIBLOCATION LIB_PATH
44
45 extern API_Proc_Struct_t *Anchor;
46
47 #include <stdarg.h>
48 #include "trace.h"
49 #include "ock_syslog.h"
50
CreateProcLock(void)51 CK_RV CreateProcLock(void)
52 {
53 struct stat statbuf;
54
55 if (xplfd == -1) {
56
57 /* The slot mgr daemon should have already created lock,
58 * so just open it so we can get a lock...
59 */
60 if (stat(OCK_API_LOCK_FILE, &statbuf) == 0)
61 xplfd = open(OCK_API_LOCK_FILE, O_RDONLY);
62
63 if (xplfd == -1) {
64 OCK_SYSLOG(LOG_ERR, "Could not open %s\n", OCK_API_LOCK_FILE);
65 return CKR_FUNCTION_FAILED;
66 }
67 }
68
69 return CKR_OK;
70 }
71
ProcLock(void)72 CK_RV ProcLock(void)
73 {
74 if (xplfd != -1)
75 flock(xplfd, LOCK_EX);
76 else
77 TRACE_DEVEL("No file descriptor to lock with.\n");
78
79 return CKR_OK;
80 }
81
ProcUnLock(void)82 CK_RV ProcUnLock(void)
83 {
84 if (xplfd != -1)
85 flock(xplfd, LOCK_UN);
86 else
87 TRACE_DEVEL("No file descriptor to unlock with.\n");
88
89 return CKR_OK;
90 }
91
ProcClose(void)92 CK_RV ProcClose(void)
93 {
94 if (xplfd != -1)
95 close(xplfd);
96 else
97 TRACE_DEVEL("ProcClose: No file descriptor open to close.\n");
98
99 return CKR_OK;
100 }
101
AddToSessionList(ST_SESSION_T * pSess)102 unsigned long AddToSessionList(ST_SESSION_T *pSess)
103 {
104 unsigned long handle;
105
106 handle = bt_node_add(&(Anchor->sess_btree), pSess);
107
108 return handle;
109 }
110
RemoveFromSessionList(CK_SESSION_HANDLE handle)111 void RemoveFromSessionList(CK_SESSION_HANDLE handle)
112 {
113 bt_node_free(&(Anchor->sess_btree), handle, free);
114 }
115
116 /* CloseMe
117 *
118 * Callback function used to close an individual session for a slot
119 */
CloseMe(STDLL_TokData_t * tokdata,void * node_value,unsigned long node_handle,void * arg)120 void CloseMe(STDLL_TokData_t *tokdata, void *node_value,
121 unsigned long node_handle, void *arg)
122 {
123 CK_RV rv;
124 CK_SLOT_ID slot_id = *(CK_SLOT_ID *) arg;
125 ST_SESSION_T *s = (ST_SESSION_T *) node_value;
126 API_Slot_t *sltp;
127 STDLL_FcnList_t *fcn;
128
129 UNUSED(tokdata);
130
131 if (s->slotID == slot_id) {
132 /* the single ugliest part about moving to a binary tree: these are the
133 * guts of the C_CloseSession function, copied here without tests for
134 * validity, since if we're here, they must already have been valid */
135 sltp = &(Anchor->SltList[slot_id]);
136 fcn = sltp->FcnList;
137 rv = fcn->ST_CloseSession(sltp->TokData, s);
138 if (rv == CKR_OK) {
139 decr_sess_counts(slot_id);
140 bt_node_free(&(Anchor->sess_btree), node_handle, free);
141 }
142 }
143 }
144
145 /* CloseAllSessions
146 *
147 * Run through all the nodes in the binary tree and call CloseMe on each one.
148 * CloseMe will look at @slot_id and if it matches, will close the session.
149 * Once all the nodes are closed, we check to see if the tree is empty and if
150 * so, destroy it
151 */
CloseAllSessions(CK_SLOT_ID slot_id)152 void CloseAllSessions(CK_SLOT_ID slot_id)
153 {
154 API_Slot_t *sltp = &(Anchor->SltList[slot_id]);
155
156 /* for every node in the API-level session tree, call CloseMe on it */
157 bt_for_each_node(sltp->TokData, &(Anchor->sess_btree), CloseMe,
158 (void *) &slot_id);
159
160 if (bt_is_empty(&(Anchor->sess_btree)))
161 bt_destroy(&(Anchor->sess_btree), NULL);
162 }
163
Valid_Session(CK_SESSION_HANDLE handle,ST_SESSION_T * rSession)164 int Valid_Session(CK_SESSION_HANDLE handle, ST_SESSION_T *rSession)
165 {
166 ST_SESSION_T *tmp;
167
168 tmp = bt_get_node_value(&(Anchor->sess_btree), handle);
169 if (tmp) {
170 rSession->slotID = tmp->slotID;
171 rSession->sessionh = tmp->sessionh;
172 }
173
174 return (tmp ? TRUE : FALSE);
175 }
176
API_Initialized()177 int API_Initialized()
178 {
179 if (Anchor == NULL)
180 return FALSE;
181
182 return TRUE;
183 }
184
slot_present(CK_SLOT_ID id)185 int slot_present(CK_SLOT_ID id)
186 {
187 Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP);
188 #ifdef PKCS64
189 Slot_Info_t_64 *sinfp;
190 #else
191 Slot_Info_t *sinfp;
192 #endif
193
194 sinfp = &(shData->slot_info[id]);
195 if (sinfp->present == FALSE) {
196 return FALSE;
197 }
198
199 return TRUE;
200 }
201
get_sess_count(CK_SLOT_ID slotID,CK_ULONG * ret)202 void get_sess_count(CK_SLOT_ID slotID, CK_ULONG *ret)
203 {
204 Slot_Mgr_Shr_t *shm;
205
206 shm = Anchor->SharedMemP;
207 ProcLock();
208 *ret = shm->slot_global_sessions[slotID];
209 ProcUnLock();
210 }
211
incr_sess_counts(CK_SLOT_ID slotID)212 void incr_sess_counts(CK_SLOT_ID slotID)
213 {
214 Slot_Mgr_Shr_t *shm;
215 #ifdef PKCS64
216 Slot_Mgr_Proc_t_64 *procp;
217 #else
218 Slot_Mgr_Proc_t *procp;
219 #endif
220
221 // Get the slot mutex
222 shm = Anchor->SharedMemP;
223
224 ProcLock();
225
226 shm->slot_global_sessions[slotID]++;
227
228 procp = &shm->proc_table[Anchor->MgrProcIndex];
229 procp->slot_session_count[slotID]++;
230
231 ProcUnLock();
232 }
233
decr_sess_counts(CK_SLOT_ID slotID)234 void decr_sess_counts(CK_SLOT_ID slotID)
235 {
236 Slot_Mgr_Shr_t *shm;
237 #ifdef PKCS64
238 Slot_Mgr_Proc_t_64 *procp;
239 #else
240 Slot_Mgr_Proc_t *procp;
241 #endif
242
243 // Get the slot mutex
244 shm = Anchor->SharedMemP;
245
246 ProcLock();
247
248 if (shm->slot_global_sessions[slotID] > 0) {
249 shm->slot_global_sessions[slotID]--;
250 }
251
252 procp = &shm->proc_table[Anchor->MgrProcIndex];
253 if (procp->slot_session_count[slotID] > 0) {
254 procp->slot_session_count[slotID]++;
255 }
256
257 ProcUnLock();
258 }
259
260 // Check if any sessions from other applicaitons exist on this particular
261 // token.... This will also validate our own sessions as well.
262 // There might be an issue with the fact that a session is created but the
263 // number is not incremented until the session allocation is completed by
264 // the token. The API may need to lock the shared memory prior to creating
265 // the session and then unlock when the stdll has completed its work.
266 // Closing sessions should probably behave the same way.
sessions_exist(CK_SLOT_ID slotID)267 int sessions_exist(CK_SLOT_ID slotID)
268 {
269 Slot_Mgr_Shr_t *shm;
270 uint32 numSessions;
271
272 // Get the slot mutex
273 shm = Anchor->SharedMemP;
274
275 ProcLock();
276 numSessions = shm->slot_global_sessions[slotID];
277 ProcUnLock();
278
279 return numSessions != 0;
280 }
281
282 // Terminates all sessions associated with a given process
283 // this cleans up any lingering sessions with the process
284 // and does not
285 //
286 // It is only called from the C_Finalize routine
Terminate_All_Process_Sessions()287 void Terminate_All_Process_Sessions()
288 {
289 CK_SLOT_ID id;
290 CK_RV rv;
291
292 TRACE_DEBUG("Terminate_All_Process_Sessions\n");
293 for (id = 0; id < NUMBER_SLOTS_MANAGED; id++) {
294 // Check if the slot is present in the slot manager
295 // if not just skip it...
296 if (slot_present(id) == TRUE) {
297 rv = C_CloseAllSessions(id);
298 } else {
299 continue;
300 }
301 // If the return code is not OK, we are really hosed
302 // since we are terminating the session.
303 // For now we will just log it
304 if (rv != CKR_OK) {
305 TRACE_DEBUG("Terminate_All_Process_Sessions RV %lx\n", rv);
306 }
307 }
308 }
309
310 // Register the process with PKCSSLOTD in the shared memory.
311 // This call must be made with the API Global Mutex Locked
312 // and the Anchor control block initialized with the
313 // shared memory. No checking for shared memory validity is done
API_Register()314 int API_Register()
315 {
316 long int reuse = -1, free = -1;
317 Slot_Mgr_Shr_t *shm;
318
319 #ifdef PKCS64
320 Slot_Mgr_Proc_t_64 *procp;
321 #else
322 Slot_Mgr_Proc_t *procp;
323 #endif
324
325 uint16 indx;
326
327 // Grab the Shared Memory lock to prevent other updates to the
328 // SHM Process
329 // The registration is done to allow for future handling of
330 // the Slot Event List. Which is maintained by the Slotd.
331
332 shm = Anchor->SharedMemP;
333
334 ProcLock();
335
336 procp = shm->proc_table;
337 for (indx = 0; indx < NUMBER_PROCESSES_ALLOWED; indx++, procp++) {
338 // Is the entry in use
339
340 if (procp->inuse == TRUE) {
341 // Handle the weird case of the process terminating without
342 // un-registering, and restarting with exactly the same PID
343 // before the slot manager garbage collection can performed.
344 // To eliminate the race condition between garbage collection
345 // the lock should protect us.
346 // This should be a VERY rare (if ever) occurance, given the
347 // way AIX deals with re-allocation of PID;s, however if this
348 // ever gets ported over to another platform we want to deal
349 // with this accordingly since it may re-use pids differently
350 // (Linux appears to re-use pids more rapidly).
351 if (procp->proc_id == getpid()) {
352 if (reuse == -1) {
353 reuse = indx;
354 }
355 }
356 } else {
357 //Already found the first free
358 if (free == -1) {
359 free = indx;
360 }
361 }
362 }
363
364 // If we did not find a free entry then we fail the routine
365 if ((reuse == -1) && (free == -1)) {
366 ProcUnLock();
367 return FALSE;
368 }
369 // check if we are reusing a control block or taking the first free.
370 // Since th mutex is helt, we don;t have to worry about some other
371 // process grabbing the slot... Garbage collection from
372 // the slotd should not affect this since it will grab the mutex
373 // before doing its thing.
374 if (reuse != -1) {
375 procp = &(shm->proc_table[reuse]);
376 indx = reuse;
377 } else {
378 procp = &(shm->proc_table[free]);
379 indx = free;
380 }
381
382 #ifdef PKCS64
383 memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t_64));
384 #else
385 memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t));
386 #endif
387 procp->inuse = TRUE;
388 procp->proc_id = getpid();
389 procp->reg_time = time(NULL);
390
391 Anchor->MgrProcIndex = indx;
392
393 TRACE_DEVEL("API_Register MgrProcIndc %d pid %ld \n", procp->proc_id,
394 (long int) Anchor->MgrProcIndex);
395
396 //??? What to do about the Mutex and cond variable
397 //Does initializing them in the slotd allow for them to not be
398 //initialized in the application.
399
400 ProcUnLock();
401
402 return TRUE;
403 }
404
405 // DeRegister the process with PKCSSLOTD in the shared memory.
406 // This call must be made with the API Global Mutex Locked
407 // and the Anchor control block initialized with the
408 // shared memory. No checking for shared memory validity is done
API_UnRegister()409 void API_UnRegister()
410 {
411 Slot_Mgr_Shr_t *shm;
412
413 #ifdef PKCS64
414 Slot_Mgr_Proc_t_64 *procp;
415 #else
416 Slot_Mgr_Proc_t *procp;
417 #endif
418
419 // Grab the Shared Memory lock to prevent other updates to the
420 // SHM Process
421 // The registration is done to allow for future handling of
422 // the Slot Event List. Which is maintained by the Slotd.
423
424 shm = Anchor->SharedMemP;
425
426 ProcLock();
427
428 procp = &(shm->proc_table[Anchor->MgrProcIndex]);
429
430 #ifdef PKCS64
431 memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t_64));
432 #else
433 memset((char *) procp, 0, sizeof(Slot_Mgr_Proc_t));
434 #endif
435
436 Anchor->MgrProcIndex = 0;
437
438 //??? What to do about the Mutex and cond variable
439 //Does initializing them in the slotd allow for them to not be
440 //initialized in the application.
441
442 ProcUnLock();
443 }
444
DL_UnLoad(API_Slot_t * sltp,CK_SLOT_ID slotID)445 void DL_UnLoad(API_Slot_t *sltp, CK_SLOT_ID slotID)
446 {
447 Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP);
448 #ifdef PKCS64
449 Slot_Info_t_64 *sinfp;
450 #else
451 Slot_Info_t *sinfp;
452 #endif
453
454 sinfp = &(shData->slot_info[slotID]);
455
456 if (sinfp->present == FALSE) {
457 return;
458 }
459 if (!sltp->dlop_p) {
460 return;
461 }
462 // Call the routine to properly unload the DLL
463 DL_Unload(sltp);
464
465 return;
466 }
467
DL_Loaded(char * location,DLL_Load_t * dllload)468 int DL_Loaded(char *location, DLL_Load_t *dllload)
469 {
470 int i;
471
472 for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) {
473 if (dllload[i].dll_name != NULL) {
474 TRACE_DEBUG("DL_LOADED Looking for index %d name %s\n",
475 i, dllload[i].dll_name);
476 if (strcmp(location, dllload[i].dll_name) == 0) {
477 return i; // Return the index of the dll
478 }
479 }
480 }
481
482 return -1; // Indicate failure to find the dll
483 }
484
485 #ifdef PKCS64
DL_Load(Slot_Info_t_64 * sinfp,API_Slot_t * sltp,DLL_Load_t * dllload)486 int DL_Load(Slot_Info_t_64 *sinfp, API_Slot_t *sltp, DLL_Load_t *dllload)
487 #else
488 int DL_Load(Slot_Info_t *sinfp, API_Slot_t *sltp, DLL_Load_t *dllload)
489 #endif
490 {
491 int i;
492
493 TRACE_DEBUG("DL_LOAD\n");
494 for (i = 0; i < NUMBER_SLOTS_MANAGED; i++) {
495 if (dllload[i].dll_name == NULL) {
496 TRACE_DEBUG("Empty slot at %d \n", i);
497 break;
498 }
499 }
500 if (i == NUMBER_SLOTS_MANAGED) {
501 TRACE_DEBUG("No empty slots.\n");
502 return 0; // Failed to find it..
503 }
504
505 dllload[i].dll_name = sinfp->dll_location; // Point to the location
506
507 dllload[i].dlop_p = dlopen(sinfp->dll_location, (RTLD_GLOBAL | RTLD_LAZY));
508
509 if (dllload[i].dlop_p != NULL) {
510 sltp->dlop_p = dllload[i].dlop_p;
511 sltp->dll_information = &dllload[i];
512 dllload[i].dll_load_count++;;
513
514 } else {
515 char *e = dlerror();
516 OCK_SYSLOG(LOG_WARNING,
517 "%s: dlopen() failed for [%s]; dlerror = [%s]\n",
518 __func__, sinfp->dll_location, e);
519 TRACE_DEVEL("DL_Load of %s failed, dlerror: %s\n",
520 sinfp->dll_location, e);
521 sltp->dlop_p = NULL;
522 return 0;
523 }
524
525 return 1;
526 }
527
DL_Unload(API_Slot_t * sltp)528 void DL_Unload(API_Slot_t *sltp)
529 {
530 DLL_Load_t *dllload;
531
532 // Decrement the count of loads. When 0 then unload this thing;
533 //
534 dllload = sltp->dll_information;
535 dllload->dll_load_count--;
536 if (dllload->dll_load_count == 0) {
537 dlclose(dllload->dlop_p);
538 dllload->dll_name = NULL;
539 }
540 // Clear out the slot information
541 sltp->DLLoaded = FALSE;
542 sltp->dlop_p = NULL;
543 sltp->pSTfini = NULL;
544 sltp->pSTcloseall = NULL;
545 }
546
DL_Load_and_Init(API_Slot_t * sltp,CK_SLOT_ID slotID)547 int DL_Load_and_Init(API_Slot_t *sltp, CK_SLOT_ID slotID)
548 {
549 Slot_Mgr_Socket_t *shData = &(Anchor->SocketDataP);
550 #ifdef PKCS64
551 Slot_Info_t_64 *sinfp;
552 #else
553 Slot_Info_t *sinfp;
554 #endif
555
556 int (*pSTinit) ();
557 void (*pSTfini) ();
558 CK_RV rv;
559 int dll_len, dl_index;
560 DLL_Load_t *dllload;
561
562 // Get pointer to shared memory from the anchor block
563 //
564
565 sinfp = &(shData->slot_info[slotID]);
566 dllload = Anchor->DLLs; // list of dll's in the system
567
568 if (sinfp->present == FALSE) {
569 return FALSE;
570 }
571
572 if ((dll_len = strlen(sinfp->dll_location))) {
573 // Check if this DLL has been loaded already.. If so, just increment
574 // the counter in the dllload structure and copy the data to
575 // the slot pointer.
576 if ((dl_index = DL_Loaded(sinfp->dll_location, dllload)) != -1) {
577 dllload[dl_index].dll_load_count++;
578 sltp->dll_information = &dllload[dl_index];
579 sltp->dlop_p = dllload[dl_index].dlop_p;
580 } else {
581 TRACE_DEBUG("DL_Load_and_Init dll_location %s\n",
582 sinfp->dll_location);
583 DL_Load(sinfp, sltp, dllload);
584 }
585 } else {
586 return FALSE;
587 }
588
589 if (!sltp->dlop_p) {
590 TRACE_DEBUG("DL_Load_and_Init pointer %p\n", sltp->dlop_p);
591
592 return FALSE;
593 }
594
595 *(void **)(&pSTinit) = dlsym(sltp->dlop_p, "ST_Initialize");
596 if (!pSTinit) {
597 // Unload the DLL
598 DL_Unload(sltp);
599 return FALSE;
600 }
601 // Returns true or false
602 rv = pSTinit(sltp, slotID, sinfp, trace);
603 TRACE_DEBUG("return from STDDLL Init = %lx\n", rv);
604
605 if (rv != CKR_OK) {
606 // clean up and unload
607 DL_Unload(sltp);
608 sltp->DLLoaded = FALSE;
609 return FALSE;
610 } else {
611 sltp->DLLoaded = TRUE;
612 // Check if a SC_Finalize function has been exported
613 *(void **)(&pSTfini) = dlsym(sltp->dlop_p, "SC_Finalize");
614 sltp->pSTfini = pSTfini;
615
616 *(void **)(&sltp->pSTcloseall) =
617 dlsym(sltp->dlop_p, "SC_CloseAllSessions");
618 return TRUE;
619 }
620
621 return TRUE;
622 }
623
624 // copies internal representation of ck_info structure to local process
625 // representation
CK_Info_From_Internal(CK_INFO_PTR dest,CK_INFO_PTR_64 src)626 void CK_Info_From_Internal(CK_INFO_PTR dest, CK_INFO_PTR_64 src)
627 {
628 dest->cryptokiVersion = src->cryptokiVersion;
629
630 memcpy(dest->manufacturerID, src->manufacturerID,
631 sizeof(dest->manufacturerID));
632
633 dest->flags = src->flags;
634
635 memcpy(dest->libraryDescription, src->libraryDescription,
636 sizeof(dest->libraryDescription));
637
638 dest->libraryVersion = src->libraryVersion;
639 }
640