opencryptoki/SOURCES/opencryptoki-3.16.0-b048be548508dd1958bb7271568f388d0f6cbcf8.patch
2021-11-09 10:08:07 +00:00

1024 lines
34 KiB
Diff

commit b048be548508dd1958bb7271568f388d0f6cbcf8
Author: Ingo Franzki <ifranzki@linux.ibm.com>
Date: Mon Feb 8 16:50:00 2021 +0100
Event support: API and token level changes
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
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 <stdint.h>
+#include <pkcs11types.h>
+#include <limits.h>
+#include <stdio.h>
+
+#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 <grp.h>
#include <errno.h>
#include <stdlib.h>
+#include <stdbool.h>
+#include <poll.h>
#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
};