28bfbcca91
- Resolves: #1924120, Event Notification Support
1024 lines
34 KiB
Diff
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
|
|
};
|