commit b048be548508dd1958bb7271568f388d0f6cbcf8 Author: Ingo Franzki Date: Mon Feb 8 16:50:00 2021 +0100 Event support: API and token level changes Signed-off-by: Ingo Franzki diff --git a/usr/include/apictl.h b/usr/include/apictl.h index 8898cae3..81c65dad 100644 --- a/usr/include/apictl.h +++ b/usr/include/apictl.h @@ -57,6 +57,8 @@ typedef struct { API_Slot_t SltList[NUMBER_SLOTS_MANAGED]; DLL_Load_t DLLs[NUMBER_SLOTS_MANAGED]; // worst case we have a separate DLL // per slot + int socketfd; + pthread_t event_thread; } API_Proc_Struct_t; #endif diff --git a/usr/include/events.h b/usr/include/events.h new file mode 100644 index 00000000..dac6ad52 --- /dev/null +++ b/usr/include/events.h @@ -0,0 +1,83 @@ +/* + * COPYRIGHT (c) International Business Machines Corp. 2021 + * + * This program is provided under the terms of the Common Public License, + * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this + * software constitutes recipient's acceptance of CPL-1.0 terms which can be + * found in the file LICENSE file or at + * https://opensource.org/licenses/cpl1.0.php + */ + +#include +#include +#include +#include + +#include "local_types.h" +#include "pkcs32.h" + +#ifndef _EVENTS_H +#define _EVENTS_H + +typedef struct { + unsigned int version; /* EVENT_VERSION_xxx */ + unsigned int type; /* EVENT_TYPE_xxx */ + unsigned int flags; /* EVENT_FLAGS_xxx */ + unsigned int token_type; /* Destination token type: EVENT_TOK_TYPE_xxx */ + char token_label[member_size(CK_TOKEN_INFO_32, label)]; + /* Label of destination token (or blanks) */ + pid_t process_id; /* Process ID of destination process (or 0) */ + unsigned int payload_len; /* Length of payload in bytes */ + /* Followed by payload_len bytes of payload (event specific) */ +} __attribute__ ((__packed__)) event_msg_t; + +typedef struct { + unsigned int version; /* EVENT_VERSION_xxx */ + unsigned int positive_replies; /* Number of tokens that replied a */ + unsigned int negative_replies; /* positive, or negative feedback, */ + unsigned int nothandled_replies; /* or that did not handle the event. */ + /* Note: Only tokens matching the event + * destination fields (pid, label, + * token-type) are counted. */ +} __attribute__ ((__packed__)) event_reply_t; + +/* Event and reply versions */ +#define EVENT_VERSION_1 1 + +/* Event classes (encoded into event type) */ +#define EVENT_CLASS_MASK 0xffff0000 +#define EVENT_CLASS_UDEV 0x00010000 +#define EVENT_CLASS_ADMIN 0x00020000 + +/* Event types */ +#define EVENT_TYPE_APQN_ADD EVENT_CLASS_UDEV + 0x00000001 +#define EVENT_TYPE_APQN_REMOVE EVENT_CLASS_UDEV + 0x00000002 + +/* Event flags */ +#define EVENT_FLAGS_NONE 0x00000000 +#define EVENT_FLAGS_REPLY_REQ 0x00000001 + +/* Event token destination types */ +#define EVENT_TOK_TYPE_ALL 0x00000000 +#define EVENT_TOK_TYPE_CCA 0x00000001 +#define EVENT_TOK_TYPE_EP11 0x00000002 + +/* Maximum event payload length 128k */ +#define EVENT_MAX_PAYLOAD_LENGTH (128 * 1024) + +/* Event payload for EVENT_TYPE_APQN_ADD and EVENT_TYPE_APQN_REMOVE */ +typedef struct { + unsigned short card; + unsigned short domain; + unsigned int device_type; /* from uevent DEV_TYPE property */ +} __attribute__ ((__packed__)) event_udev_apqn_data_t; + +/* AP device types */ +#define AP_DEVICE_TYPE_CEX3A 8 +#define AP_DEVICE_TYPE_CEX3C 9 +#define AP_DEVICE_TYPE_CEX4 10 +#define AP_DEVICE_TYPE_CEX5 11 +#define AP_DEVICE_TYPE_CEX6 12 +#define AP_DEVICE_TYPE_CEX7 13 + +#endif diff --git a/usr/include/include.mk b/usr/include/include.mk index a36afb25..79e593d7 100644 --- a/usr/include/include.mk +++ b/usr/include/include.mk @@ -7,4 +7,5 @@ opencryptokiinclude_HEADERS = \ noinst_HEADERS += \ usr/include/apictl.h usr/include/local_types.h \ - usr/include/pkcs32.h usr/include/slotmgr.h usr/include/stdll.h + usr/include/pkcs32.h usr/include/slotmgr.h usr/include/stdll.h \ + usr/include/events.h diff --git a/usr/include/local_types.h b/usr/include/local_types.h index f03c6629..c7c7f5ec 100644 --- a/usr/include/local_types.h +++ b/usr/include/local_types.h @@ -11,6 +11,8 @@ #ifndef __LOCAL_TYPES #define __LOCAL_TYPES +#define member_size(type, member) sizeof(((type *)0)->member) + typedef unsigned char uint8; typedef unsigned short uint16; diff --git a/usr/include/stdll.h b/usr/include/stdll.h index 57f6c6e8..9a3b760c 100644 --- a/usr/include/stdll.h +++ b/usr/include/stdll.h @@ -350,6 +350,11 @@ typedef CK_RV (CK_PTR ST_C_IBM_ReencryptSingle)(STDLL_TokData_t *tokdata, CK_BYTE_PTR pReencryptedData, CK_ULONG_PTR pulReencryptedDataLen); +typedef CK_RV (CK_PTR ST_C_HandleEvent)(STDLL_TokData_t *tokdata, + unsigned int event_type, + unsigned int event_flags, + const char *payload, + unsigned int payload_len); struct ST_FCN_LIST { @@ -424,6 +429,9 @@ struct ST_FCN_LIST { ST_C_CancelFunction ST_CancelFunction; ST_C_IBM_ReencryptSingle ST_IBM_ReencryptSingle; + + /* The functions defined below are not part of the external API */ + ST_C_HandleEvent ST_HandleEvent; }; typedef struct ST_FCN_LIST STDLL_FcnList_t; diff --git a/usr/lib/api/api_interface.c b/usr/lib/api/api_interface.c index f1ee9132..b74b763f 100644 --- a/usr/lib/api/api_interface.c +++ b/usr/lib/api/api_interface.c @@ -286,7 +286,31 @@ void child_fork_initializer() if (Anchor != NULL) C_Finalize(NULL); in_child_fork_initializer = FALSE; - } +} + +void parent_fork_prepare() +{ + if (Anchor == NULL) + return; + + /* + * Stop the event thread in the fork parent, since having the event thread + * active when a fork is performed causes various problems (e.g. deadlocks + * in glibc). + */ + if (Anchor->event_thread > 0) + stop_event_thread(); +} + +void parent_fork_after() +{ + if (Anchor == NULL) + return; + + /* Restart the event thread in the parent when fork is complete */ + if (Anchor->event_thread == 0) + start_event_thread(); +} //------------------------------------------------------------------------ // API function C_CancelFunction @@ -1501,6 +1525,20 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) shData = &(Anchor->SocketDataP); + /* + * Stop the event thread and close the socket. + * If C_Finalize is called as part of the fork initializer, don't stop + * the thread, since a forked process does not have any threads, and don't + * close the socket, as this would close the connection of the parent + * process to the pkcsslotd as well. + * */ + if (!in_child_fork_initializer) { + if (Anchor->event_thread > 0) + stop_event_thread(); + if (Anchor->socketfd >= 0) + close(Anchor->socketfd); + } + // unload all the STDLL's from the application // This is in case the APP decides to do the re-initialize and // continue on @@ -2642,6 +2680,8 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) CK_C_INITIALIZE_ARGS *pArg; char fcnmap = 0; CK_RV rc = CKR_OK; + CK_SLOT_ID slotID; + API_Slot_t *sltp; /* * Lock so that only one thread can run C_Initialize or C_Finalize at @@ -2674,6 +2714,7 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) // This must be done prior to all goto error calls, else bt_destroy() // will fail because it accesses uninitialized memory when t->size > 0. memset(Anchor, 0, sizeof(API_Proc_Struct_t)); + Anchor->socketfd = -1; TRACE_DEBUG("Anchor allocated at %s\n", (char *) Anchor); @@ -2789,11 +2830,21 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) } TRACE_DEBUG("Shared memory %p \n", Anchor->SharedMemP); - if (!init_socket_data()) { + /* Connect to slot daemon and retrieve slot infos */ + Anchor->socketfd = connect_socket(SOCKET_FILE_PATH); + if (Anchor->socketfd < 0) { OCK_SYSLOG(LOG_ERR, "C_Initialize: Module failed to create a " "socket. Verify that the slot management daemon is " "running.\n"); - TRACE_ERROR("Cannot attach to socket.\n"); + TRACE_ERROR("Failed to connect to slot daemon\n"); + rc = CKR_FUNCTION_FAILED; + goto error_shm; + } + + if (!init_socket_data(Anchor->socketfd)) { + OCK_SYSLOG(LOG_ERR, "C_Initialize: Module failed to retrieve slot " + "infos from slot deamon.\n"); + TRACE_ERROR("Failed to receive slot infos from socket.\n"); rc = CKR_FUNCTION_FAILED; goto error_shm; } @@ -2810,15 +2861,35 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) } // // load all the slot DLL's here - { - CK_SLOT_ID slotID; - API_Slot_t *sltp; + for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { + sltp = &(Anchor->SltList[slotID]); + slot_loaded[slotID] = DL_Load_and_Init(sltp, slotID); + } + /* Start event receiver thread */ + if (start_event_thread() != 0) { + TRACE_ERROR("Failed to start event thread\n"); + + // unload all the STDLL's from the application + // This is in case the APP decides to do the re-initialize and + // continue on for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { sltp = &(Anchor->SltList[slotID]); - slot_loaded[slotID] = DL_Load_and_Init(sltp, slotID); + if (slot_loaded[slotID]) { + if (sltp->pSTfini) { + // call the terminate function.. + sltp->pSTfini(sltp->TokData, slotID, + &Anchor->SocketDataP.slot_info[slotID], + &trace, 0); + } + } + DL_UnLoad(sltp, slotID); } + API_UnRegister(); + + rc = CKR_FUNCTION_FAILED; + goto error_shm; } pthread_mutex_unlock(&GlobMutex); @@ -2829,6 +2900,8 @@ error_shm: error: bt_destroy(&Anchor->sess_btree); + if (Anchor->socketfd >= 0) + close(Anchor->socketfd); free((void *) Anchor); Anchor = NULL; @@ -5052,7 +5125,8 @@ void api_init(void) { // Should only have to do the atfork stuff at load time... if (!Initialized) { - pthread_atfork(NULL, NULL, (void (*)()) child_fork_initializer); + pthread_atfork(parent_fork_prepare, parent_fork_after, + child_fork_initializer); Initialized = 1; } } diff --git a/usr/lib/api/apiproto.h b/usr/lib/api/apiproto.h index 871f3778..8523fb8e 100644 --- a/usr/lib/api/apiproto.h +++ b/usr/lib/api/apiproto.h @@ -50,6 +50,9 @@ void CK_Info_From_Internal(CK_INFO_PTR dest, CK_INFO_PTR_64 src); int sessions_exist(CK_SLOT_ID); void CloseAllSessions(CK_SLOT_ID slot_id, CK_BBOOL in_fork_initializer); -int init_socket_data(); +int connect_socket(const char *file_path); +int init_socket_data(int socketfd); +int start_event_thread(); +int stop_event_thread(); #endif diff --git a/usr/lib/api/socket_client.c b/usr/lib/api/socket_client.c index 6bacf151..e344ddbf 100644 --- a/usr/lib/api/socket_client.c +++ b/usr/lib/api/socket_client.c @@ -23,114 +23,421 @@ #include #include #include +#include +#include #include "apiproto.h" #include "slotmgr.h" #include "apictl.h" +#include "trace.h" #include "ock_syslog.h" +#include "events.h" extern API_Proc_Struct_t *Anchor; -// -// Will fill out the Slot_Mgr_Socket_t structure in the Anchor global data -// structure with the values passed by the pkcsslotd via a socket RPC. -int init_socket_data() + +int connect_socket(const char *file_path) { int socketfd; struct sockaddr_un daemon_address; struct stat file_info; struct group *grp; - int n; - unsigned int bytes_received = 0; - Slot_Mgr_Socket_t *daemon_socket_data = NULL; - int ret = FALSE; - if (stat(SOCKET_FILE_PATH, &file_info)) { + if (stat(file_path, &file_info)) { OCK_SYSLOG(LOG_ERR, - "init_socket_data: failed to find socket file, errno=%d", + "connect_socket: failed to find socket file, errno=%d", errno); - return FALSE; + return -1; } grp = getgrnam("pkcs11"); if (!grp) { OCK_SYSLOG(LOG_ERR, - "init_socket_data: pkcs11 group does not exist, errno=%d", + "connect_socket: pkcs11 group does not exist, errno=%d", errno); - return FALSE; + return -1; } if (file_info.st_uid != 0 || file_info.st_gid != grp->gr_gid) { OCK_SYSLOG(LOG_ERR, - "init_socket_data: incorrect permissions on socket file"); - return FALSE; + "connect_socket: incorrect permissions on socket file"); + return -1; } if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { OCK_SYSLOG(LOG_ERR, - "init_socket_data: failed to create socket, errno=%d", + "connect_socket: failed to create socket, errno=%d", errno); - return FALSE; + return -1; } memset(&daemon_address, 0, sizeof(struct sockaddr_un)); daemon_address.sun_family = AF_UNIX; - strcpy(daemon_address.sun_path, SOCKET_FILE_PATH); + strcpy(daemon_address.sun_path, file_path); if (connect(socketfd, (struct sockaddr *) &daemon_address, sizeof(struct sockaddr_un)) != 0) { OCK_SYSLOG(LOG_ERR, - "init_socket_data: failed to connect to slotmanager daemon, " + "connect_socket: failed to connect to slotmanager daemon, " "errno=%d", errno); - goto exit; - } - // allocate data buffer - daemon_socket_data = - (Slot_Mgr_Socket_t *) malloc(sizeof(*daemon_socket_data)); - if (!daemon_socket_data) { - OCK_SYSLOG(LOG_ERR, "init_socket_data: failed to \ - allocate %lu bytes \ - for daemon data, errno=%d", - sizeof(*daemon_socket_data), errno); - goto exit; + goto error; } - while (bytes_received < sizeof(*daemon_socket_data)) { - n = read(socketfd, ((char *) daemon_socket_data) + bytes_received, - sizeof(*daemon_socket_data) - bytes_received); + return socketfd; + +error: + close(socketfd); + return -1; +} + +static ssize_t read_all(int socketfd, char *buffer, size_t size) +{ + size_t bytes_received = 0; + ssize_t n; + + while (bytes_received < size) { + n = read(socketfd, buffer + bytes_received, size - bytes_received); if (n < 0) { // read error if (errno == EINTR) continue; - OCK_SYSLOG(LOG_ERR, "init_socket_data: read error \ - on daemon socket, errno=%d", errno); - goto exit; - } else if (n == 0) { - // eof but we still expect some bytes - OCK_SYSLOG(LOG_ERR, "init_socket_data: read returned \ - with eof but we still \ - expect %lu bytes from daemon", - sizeof(*daemon_socket_data) - bytes_received); - goto exit; - } else { - // n > 0, we got some bytes - bytes_received += n; + return -errno; } + if (n == 0) + break; + + bytes_received += n; } - ret = TRUE; + return bytes_received; +} + +static ssize_t send_all(int socketfd, char *buffer, size_t size) +{ + size_t bytes_sent = 0; + ssize_t n; - // copy the Slot_Mgr_Socket_t struct into global - // Anchor SocketDataPdata buffer - memcpy(&(Anchor->SocketDataP), daemon_socket_data, - sizeof(*daemon_socket_data)); + while (bytes_sent < size) { + n = send(socketfd, buffer + bytes_sent, size - bytes_sent, 0); + if (n < 0) { + // send error + if (errno == EINTR) + continue; + return -errno; + } + if (n == 0) + break; -exit: - //free the data buffer after copy - if (daemon_socket_data) - free(daemon_socket_data); + bytes_sent += n; + } - close(socketfd); + return bytes_sent; +} + +// +// Will fill out the Slot_Mgr_Socket_t structure in the Anchor global data +// structure with the values passed by the pkcsslotd via a socket RPC. +int init_socket_data(int socketfd) +{ + ssize_t n; + int ret = TRUE; + + n = read_all(socketfd, (char *)&Anchor->SocketDataP, + sizeof(Anchor->SocketDataP)); + if (n < 0) { + // read error + OCK_SYSLOG(LOG_ERR, "init_socket_data: read error \ + on daemon socket, errno=%d", -n); + ret = FALSE; + } + if (n != sizeof(Anchor->SocketDataP)) { + // eof but we still expect some bytes + OCK_SYSLOG(LOG_ERR, "init_socket_data: read returned \ + with eof but we still \ + expect %lu bytes from daemon", + sizeof(Anchor->SocketDataP) - n); + ret = FALSE; + } return ret; } + +static bool match_token_label_filter(event_msg_t *event, API_Slot_t *sltp) +{ + if (event->token_label[0] == ' ' || event->token_label[0] == '\0') + return true; + + return memcmp(event->token_label, + sltp->TokData->nv_token_data->token_info.label, + sizeof(event->token_label)) == 0; +} + +struct type_model { + unsigned int type; + char model[member_size(CK_TOKEN_INFO_32, model)]; +}; + +static const struct type_model type_model_flt[] = { + { .type = EVENT_TOK_TYPE_CCA, .model = "CCA " }, + { .type = EVENT_TOK_TYPE_EP11, .model = "EP11 " }, +}; + +static bool match_token_type_filter(event_msg_t *event, API_Slot_t *sltp) +{ + size_t i; + + if (event->token_type == EVENT_TOK_TYPE_ALL) + return true; + + for (i = 0; i < sizeof(type_model_flt) / sizeof(struct type_model); i++) { + if (memcmp(sltp->TokData->nv_token_data->token_info.model, + type_model_flt[i].model, + sizeof(type_model_flt[i].model)) == 0 && + (event->token_type & type_model_flt[i].type) != 0) + return true; + } + + return false; +} + +static int handle_event(API_Proc_Struct_t *anchor, event_msg_t *event, + char *payload, event_reply_t *reply) +{ + CK_SLOT_ID slotID; + API_Slot_t *sltp; + CK_RV rc; + + /* If its not for our process, ignore it, don't increment reply counters */ + if (event->process_id != 0 && event->process_id != anchor->Pid) + return 0; + + for (slotID = 0; slotID < NUMBER_SLOTS_MANAGED; slotID++) { + sltp = &anchor->SltList[slotID]; + if (sltp->DLLoaded == FALSE || sltp->FcnList == NULL) + continue; + + if (!match_token_label_filter(event, sltp)) + continue; + if (!match_token_type_filter(event, sltp)) + continue; + + if (sltp->FcnList->ST_HandleEvent != NULL) + rc = sltp->FcnList->ST_HandleEvent(sltp->TokData, event->type, + event->flags, payload, + event->payload_len); + else + rc = CKR_FUNCTION_NOT_SUPPORTED; + + TRACE_DEVEL("Slot %lu ST_HandleEvent rc: 0x%lx\n", slotID, rc); + switch (rc) { + case CKR_OK: + reply->positive_replies++; + break; + case CKR_FUNCTION_NOT_SUPPORTED: + reply->nothandled_replies++; + break; + default: + reply->negative_replies++; + break; + } + } + + return 0; +} + +static void event_thread_cleanup(void *arg) +{ + API_Proc_Struct_t *anchor = arg; + + UNUSED(anchor); + + TRACE_DEVEL("Event thread %lu terminating\n", pthread_self()); +} + +static void *event_thread(void *arg) +{ + API_Proc_Struct_t *anchor = arg; + int oldstate, oldtype; + struct pollfd pollfd; + event_msg_t event; + char *payload; + event_reply_t reply; + ssize_t num; + int rc; + + UNUSED(arg); + + TRACE_DEVEL("Event thread %lu running\n", pthread_self()); + + if (anchor->socketfd < 0) { + TRACE_ERROR("socket is already closed.\n"); + TRACE_DEVEL("Event thread %lu terminating\n", pthread_self()); + return NULL; + } + + /* Enable cancellation */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype); + pthread_cleanup_push(event_thread_cleanup, anchor); + + pollfd.fd = anchor->socketfd; + pollfd.events = POLLIN | POLLHUP | POLLERR; + + while (1) { + pollfd.revents = 0; + rc = poll(&pollfd, 1, -1); + if (rc < 0) { + if (errno == EINTR) + continue; + TRACE_ERROR("poll failed: %d\n", errno); + break; + } + + if (rc == 0) + continue; + + if (pollfd.revents & (POLLHUP | POLLERR)) { + TRACE_ERROR("Error on socket, possibly closed by slot daemon\n"); + break; + } + if ((pollfd.revents & POLLIN) == 0) + continue; + + /* Disable for cancellation while we are working on an event */ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate); + + TRACE_DEVEL("Receive new event ....\n"); + + num = read_all(anchor->socketfd, (char *)&event, sizeof(event)); + if (num != sizeof(event)) { + TRACE_ERROR("Error receiving the event, rc: %ld\n", num); + break; + } + + TRACE_DEBUG("Event version: %u\n", event.version); + TRACE_DEBUG("Event type: 0x%08x\n", event.type); + TRACE_DEBUG("Event flags: 0x%08x\n", event.flags); + TRACE_DEBUG("Event token_type: 0x%08x\n", event.token_type); + TRACE_DEBUG("Event token_name: '%.32s'\n", event.token_label); + TRACE_DEBUG("Event process_id: %u\n", event.process_id); + TRACE_DEBUG("Event payload_len: %u\n", event.payload_len); + + if (event.version != EVENT_VERSION_1) { + TRACE_ERROR("Event version invalid: %u\n", event.version); + break; + } + + payload = NULL; + if (event.payload_len > 0) { + payload = malloc(event.payload_len); + if (payload == NULL) { + TRACE_ERROR("Failed to allocate buffer for event payload\n"); + break; + } + + num = read_all(anchor->socketfd, payload, event.payload_len); + if (num != event.payload_len) { + TRACE_ERROR("Error receiving the event payload, rc: %ld\n", num); + if (payload != NULL) + free(payload); + break; + } + + TRACE_DEBUG("Event payload:\n"); + TRACE_DEBUG_DUMP(" ", payload, event.payload_len); + } + + memset(&reply, 0, sizeof(reply)); + reply.version = EVENT_VERSION_1; + rc = handle_event(anchor, &event, payload, &reply); + if (rc != 0) { + TRACE_ERROR("Error handling the event, rc: %d\n", rc); + if (payload != NULL) + free(payload); + break; + } + + TRACE_DEBUG("Reply version: %u\n", reply.version); + TRACE_DEBUG("Reply positive: %u\n", reply.positive_replies); + TRACE_DEBUG("Reply negative: %u\n", reply.negative_replies); + TRACE_DEBUG("Reply not-handled: %u\n", reply.nothandled_replies); + + if (event.flags & EVENT_FLAGS_REPLY_REQ) { + num = send_all(anchor->socketfd, (char *)&reply, sizeof(reply)); + if (num != sizeof(reply)) { + TRACE_ERROR("Error sending the event reply, rc: %ld\n", num); + if (payload != NULL) + free(payload); + break; + } + } + + if (payload != NULL) + free(payload); + + /* Re-enable for and test if we got canceled in the meantime */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate); + pthread_testcancel(); + } + + /* + * Close the socket if we encounter an unrecoverable error (e.g. received + * invalid event) and stop the thread because of that. + * If the thread is stopped via stop_event_thread(), then it gets canceled + * via pthread_cancel(), and will not reach this place, thus the socket is + * not closed. This is intended, and the socket will then be closed by + * C_Finalize(). The atfork 'prepare' handler in the parent process also + * stops the thread (via stop_event_thread()), and the socket must not be + * closed in this case, because the thread is restarted in the atfork + * 'parent' handler, and should continue to receive events from the + * socket. + */ + close(anchor->socketfd); + anchor->socketfd = -1; + + pthread_cleanup_pop(1); + return NULL; +} + +int start_event_thread() +{ + int rc; + + rc = pthread_create(&Anchor->event_thread, NULL, event_thread, Anchor); + if (rc != 0) { + OCK_SYSLOG(LOG_ERR, "start_event_thread: pthread_create failed, " + "errno=%d", rc); + TRACE_ERROR("Failed to start event thread, errno=%d\n", rc); + return rc; + } + + TRACE_DEVEL("Event thread %lu has been started\n", Anchor->event_thread); + return 0; +} + +int stop_event_thread() +{ + int rc; + void *status; + + TRACE_DEVEL("Canceling event thread %lu\n", Anchor->event_thread); + rc = pthread_cancel(Anchor->event_thread); + if (rc != 0 && rc != ESRCH) + return rc; + + TRACE_DEVEL("Waiting for event thread %lu to terminate\n", + Anchor->event_thread); + rc = pthread_join(Anchor->event_thread, &status); + if (rc != 0) + return rc; + + if (status != PTHREAD_CANCELED) { + TRACE_ERROR("Event thread was stopped, but did not return the " + "expected status\n"); + } + + TRACE_DEVEL("Event thread %lu has terminated\n", Anchor->event_thread); + + Anchor->event_thread = 0; + return 0; +} diff --git a/usr/lib/cca_stdll/tok_struct.h b/usr/lib/cca_stdll/tok_struct.h index 2b43fa8e..182e2ac2 100644 --- a/usr/lib/cca_stdll/tok_struct.h +++ b/usr/lib/cca_stdll/tok_struct.h @@ -134,6 +134,7 @@ token_spec_t token_specific = { &token_specific_reencrypt_single, NULL, // set_attribute_values NULL, // set_attrs_for_new_object + NULL, // handle_event }; #endif diff --git a/usr/lib/common/new_host.c b/usr/lib/common/new_host.c index aae00984..a3749d26 100644 --- a/usr/lib/common/new_host.c +++ b/usr/lib/common/new_host.c @@ -4039,6 +4039,24 @@ done: return rc; } +CK_RV SC_HandleEvent(STDLL_TokData_t *tokdata, unsigned int event_type, + unsigned int event_flags, const char *payload, + unsigned int payload_len) +{ + CK_RV rc; + + if (token_specific.t_handle_event == NULL) + return CKR_FUNCTION_NOT_SUPPORTED; + + rc = token_specific.t_handle_event(tokdata, event_type, event_flags, + payload, payload_len); + + TRACE_INFO("SC_HandleEvent: rc = 0x%08lx, event_type = 0x%08x, " + "event_flags = 0x%08x\n", rc, event_type, event_flags); + + return rc; +} + void SC_SetFunctionList(void) { function_list.ST_Initialize = ST_Initialize; @@ -4104,4 +4122,6 @@ void SC_SetFunctionList(void) function_list.ST_CancelFunction = NULL; // SC_CancelFunction; function_list.ST_IBM_ReencryptSingle = SC_IBM_ReencryptSingle; + + function_list.ST_HandleEvent = SC_HandleEvent; } diff --git a/usr/lib/common/tok_spec_struct.h b/usr/lib/common/tok_spec_struct.h index 30ffcf02..0e90d411 100644 --- a/usr/lib/common/tok_spec_struct.h +++ b/usr/lib/common/tok_spec_struct.h @@ -278,6 +278,10 @@ struct token_specific_struct { CK_RV(*t_set_attrs_for_new_object) (STDLL_TokData_t *, CK_OBJECT_CLASS, CK_ULONG, TEMPLATE *); + + CK_RV(*t_handle_event) (STDLL_TokData_t *tokdata, unsigned int event_type, + unsigned int event_flags, const char *payload, + unsigned int payload_len); }; typedef struct token_specific_struct token_spec_t; diff --git a/usr/lib/common/tok_specific.h b/usr/lib/common/tok_specific.h index ffb72909..997fa7e1 100644 --- a/usr/lib/common/tok_specific.h +++ b/usr/lib/common/tok_specific.h @@ -326,4 +326,10 @@ CK_RV token_specific_set_attrs_for_new_object(STDLL_TokData_t *, CK_OBJECT_CLASS, CK_ULONG, TEMPLATE *); +CK_RV token_specific_handle_event(STDLL_TokData_t *tokdata, + unsigned int event_type, + unsigned int event_flags, + const char *payload, + unsigned int payload_len); + #endif diff --git a/usr/lib/ep11_stdll/new_host.c b/usr/lib/ep11_stdll/new_host.c index 6fcef68a..4e592363 100644 --- a/usr/lib/ep11_stdll/new_host.c +++ b/usr/lib/ep11_stdll/new_host.c @@ -4262,6 +4262,24 @@ done: return rc; } +CK_RV SC_HandleEvent(STDLL_TokData_t *tokdata, unsigned int event_type, + unsigned int event_flags, const char *payload, + unsigned int payload_len) +{ + CK_RV rc; + + if (token_specific.t_handle_event == NULL) + return CKR_FUNCTION_NOT_SUPPORTED; + + rc = token_specific.t_handle_event(tokdata, event_type, event_flags, + payload, payload_len); + + TRACE_INFO("SC_HandleEvent: rc = 0x%08lx, event_type = 0x%08x, " + "event_flags = 0x%08x\n", rc, event_type, event_flags); + + return rc; +} + void SC_SetFunctionList(void) { function_list.ST_Initialize = ST_Initialize; @@ -4327,4 +4345,6 @@ void SC_SetFunctionList(void) function_list.ST_CancelFunction = NULL; // SC_CancelFunction; function_list.ST_IBM_ReencryptSingle = SC_IBM_ReencryptSingle; + + function_list.ST_HandleEvent = SC_HandleEvent; } diff --git a/usr/lib/ep11_stdll/tok_struct.h b/usr/lib/ep11_stdll/tok_struct.h index 51aae6fb..2c0af9cf 100644 --- a/usr/lib/ep11_stdll/tok_struct.h +++ b/usr/lib/ep11_stdll/tok_struct.h @@ -137,6 +137,7 @@ token_spec_t token_specific = { &token_specific_reencrypt_single, &token_specific_set_attribute_values, &token_specific_set_attrs_for_new_object, + NULL, // handle_event }; #endif diff --git a/usr/lib/ica_s390_stdll/tok_struct.h b/usr/lib/ica_s390_stdll/tok_struct.h index 13ee72c9..a260a276 100644 --- a/usr/lib/ica_s390_stdll/tok_struct.h +++ b/usr/lib/ica_s390_stdll/tok_struct.h @@ -147,6 +147,7 @@ token_spec_t token_specific = { NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object + NULL, // handle_event }; #endif diff --git a/usr/lib/icsf_stdll/new_host.c b/usr/lib/icsf_stdll/new_host.c index 0f93ce5c..cfef7425 100644 --- a/usr/lib/icsf_stdll/new_host.c +++ b/usr/lib/icsf_stdll/new_host.c @@ -3332,6 +3332,24 @@ done: return rc; } +CK_RV SC_HandleEvent(STDLL_TokData_t *tokdata, unsigned int event_type, + unsigned int event_flags, const char *payload, + unsigned int payload_len) +{ + CK_RV rc; + + if (token_specific.t_handle_event == NULL) + return CKR_FUNCTION_NOT_SUPPORTED; + + rc = token_specific.t_handle_event(tokdata, event_type, event_flags, + payload, payload_len); + + TRACE_INFO("SC_HandleEvent: rc = 0x%08lx, event_type = 0x%08x, " + "event_flags = 0x%08x\n", rc, event_type, event_flags); + + return rc; +} + void SC_SetFunctionList(void) { function_list.ST_Initialize = ST_Initialize; @@ -3397,4 +3415,6 @@ void SC_SetFunctionList(void) function_list.ST_CancelFunction = NULL; // SC_CancelFunction; function_list.ST_IBM_ReencryptSingle = SC_IBM_ReencryptSingle; + + function_list.ST_HandleEvent = SC_HandleEvent; } diff --git a/usr/lib/icsf_stdll/tok_struct.h b/usr/lib/icsf_stdll/tok_struct.h index fb1619ee..0f930a29 100644 --- a/usr/lib/icsf_stdll/tok_struct.h +++ b/usr/lib/icsf_stdll/tok_struct.h @@ -129,6 +129,7 @@ token_spec_t token_specific = { NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object + NULL, // handle_event }; #endif diff --git a/usr/lib/soft_stdll/tok_struct.h b/usr/lib/soft_stdll/tok_struct.h index acf7c5d7..e43df038 100644 --- a/usr/lib/soft_stdll/tok_struct.h +++ b/usr/lib/soft_stdll/tok_struct.h @@ -172,6 +172,7 @@ token_spec_t token_specific = { NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object + NULL, // handle_event }; #endif diff --git a/usr/lib/tpm_stdll/tok_struct.h b/usr/lib/tpm_stdll/tok_struct.h index d48b93e5..8903f123 100644 --- a/usr/lib/tpm_stdll/tok_struct.h +++ b/usr/lib/tpm_stdll/tok_struct.h @@ -120,4 +120,5 @@ struct token_specific_struct token_specific = { NULL, // reencrypt_single NULL, // set_attribute_values NULL, // set_attrs_for_new_object + NULL, // handle_event };