From 28bfbcca915c16b128c0684c9e58f52669ee8dd5 Mon Sep 17 00:00:00 2001 From: Than Ngo Date: Mon, 17 May 2021 17:23:09 +0200 Subject: [PATCH] - Resolves: #1959894, Soft token does not check if an EC key is valid - Resolves: #1924120, Event Notification Support --- ...6d12b302b87e1dacf613cc61a063ad209d15.patch | 136 + ...0e4497b0078e73e0004e3492db647c7c458b.patch | 2304 +++++++++++++++++ ...fbeb8275f5ea6ed52dd3f30126614ec1d037.patch | 2159 +++++++++++++++ ...43c3d8844402c04a66b55c6c940f965109f0.patch | 47 + ...4a5e0d9dfec3ef534b19b89a541576bb17dc.patch | 23 + ...83c571ceb3050969359817d4145600f14ae8.patch | 367 +++ ...be548508dd1958bb7271568f388d0f6cbcf8.patch | 1023 ++++++++ ...05993dd8b2f367cf3b630f6da186e4e8550d.patch | 37 + ...2c652c49d7e248b115d121a4f7f6568941a2.patch | 21 + ...899d77a5724635a9d4451a34a240e2c7e891.patch | 462 ++++ ...5092247a0efc2c397f12977a7c9925420143.patch | 239 ++ ...fe8470e99f4dcbbd889e7aa87e147d0d5b48.patch | 619 +++++ ...8127edae313da7840bcb87fd0afd04549c2e.patch | 310 +++ ...a16116d8382a987ddf9e8cdd88027dd1f647.patch | 287 ++ opencryptoki.spec | 22 +- 15 files changed, 8055 insertions(+), 1 deletion(-) create mode 100644 opencryptoki-3.16.0-19f56d12b302b87e1dacf613cc61a063ad209d15.patch create mode 100644 opencryptoki-3.16.0-1fdd0e4497b0078e73e0004e3492db647c7c458b.patch create mode 100644 opencryptoki-3.16.0-342dfbeb8275f5ea6ed52dd3f30126614ec1d037.patch create mode 100644 opencryptoki-3.16.0-4e3b43c3d8844402c04a66b55c6c940f965109f0.patch create mode 100644 opencryptoki-3.16.0-69244a5e0d9dfec3ef534b19b89a541576bb17dc.patch create mode 100644 opencryptoki-3.16.0-7b7d83c571ceb3050969359817d4145600f14ae8.patch create mode 100644 opencryptoki-3.16.0-b048be548508dd1958bb7271568f388d0f6cbcf8.patch create mode 100644 opencryptoki-3.16.0-b07505993dd8b2f367cf3b630f6da186e4e8550d.patch create mode 100644 opencryptoki-3.16.0-bf812c652c49d7e248b115d121a4f7f6568941a2.patch create mode 100644 opencryptoki-3.16.0-c79e899d77a5724635a9d4451a34a240e2c7e891.patch create mode 100644 opencryptoki-3.16.0-d7de5092247a0efc2c397f12977a7c9925420143.patch create mode 100644 opencryptoki-3.16.0-d929fe8470e99f4dcbbd889e7aa87e147d0d5b48.patch create mode 100644 opencryptoki-3.16.0-e9548127edae313da7840bcb87fd0afd04549c2e.patch create mode 100644 opencryptoki-3.16.0-fa94a16116d8382a987ddf9e8cdd88027dd1f647.patch diff --git a/opencryptoki-3.16.0-19f56d12b302b87e1dacf613cc61a063ad209d15.patch b/opencryptoki-3.16.0-19f56d12b302b87e1dacf613cc61a063ad209d15.patch new file mode 100644 index 0000000..e7872d6 --- /dev/null +++ b/opencryptoki-3.16.0-19f56d12b302b87e1dacf613cc61a063ad209d15.patch @@ -0,0 +1,136 @@ +commit 19f56d12b302b87e1dacf613cc61a063ad209d15 +Author: Ingo Franzki +Date: Fri Feb 12 15:57:20 2021 +0100 + + Fix compile warning when compiling pkcsslotd with -DDEV and/or -DTHREADED + + Signed-off-by: Ingo Franzki + +diff --git a/usr/sbin/pkcsslotd/garbage_linux.c b/usr/sbin/pkcsslotd/garbage_linux.c +index d4878c3b..a4dd9713 100644 +--- a/usr/sbin/pkcsslotd/garbage_linux.c ++++ b/usr/sbin/pkcsslotd/garbage_linux.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include "log.h" + #include "slotmgr.h" +@@ -80,8 +81,8 @@ BOOL StartGCThread(Slot_Mgr_Shr_t *MemPtr) + #ifdef DEV + // Only development builds + LogLog("StartGCThread: garbage collection thread started as ID " +- "%d (%#x) by ID %d (%#x)", +- GCThread, GCThread, pthread_self(), pthread_self()); ++ "%lu by ID %lu", ++ GCThread, pthread_self()); + #endif + + return TRUE; +@@ -115,8 +116,8 @@ BOOL StopGCThread(void *Ptr) + return FALSE; + } + +- DbgLog(DL0, "StopGCThread: tid %d is stopping the garbage collection " +- "thread (tid %d)", ++ DbgLog(DL0, "StopGCThread: tid %lu is stopping the garbage collection " ++ "thread (tid %lu)", + pthread_self(), GCThread); + + /* Cause the GC thread to be cancelled */ +@@ -245,7 +246,7 @@ void GCCancel(void *Ptr) + UNUSED(Ptr); + + /* Yeah, yeah. Doesn't do anything, but I had plans */ +- DbgLog(DL3, "GCCancel: tid: %d running cleanup routine", pthread_self()); ++ DbgLog(DL3, "GCCancel: tid: %lu running cleanup routine", pthread_self()); + + return; + } +@@ -268,7 +269,7 @@ BOOL CheckForGarbage(Slot_Mgr_Shr_t *MemPtr) + + ASSERT(MemPtr != NULL_PTR); + #ifdef DEV +- DbgLog(DL5, "Thread %d is checking for garbage", pthread_self()); ++ DbgLog(DL5, "Thread %lu is checking for garbage", pthread_self()); + #endif /* DEV */ + + +@@ -326,9 +327,9 @@ BOOL CheckForGarbage(Slot_Mgr_Shr_t *MemPtr) + if (*pProcSessions > 0) { + + #ifdef DEV +- DbgLog(DL2, "GC: Invalid pid (%d) is holding %d sessions " ++ DbgLog(DL2, "GC: Invalid pid (%d) is holding %u sessions " + "open on slot %d. Global session count for this " +- "slot is %d", ++ "slot is %u", + pProc->proc_id, *pProcSessions, SlotIndex, + *pGlobalSessions); + #endif /* DEV */ +@@ -338,9 +339,9 @@ BOOL CheckForGarbage(Slot_Mgr_Shr_t *MemPtr) + WarnLog("Garbage Collection: Illegal values in table " + "for defunct process"); + DbgLog(DL0, "Garbage collection: A process " +- "( Index: %d, pid: %d ) showed %d sessions " +- "open on slot %s, but the global count for this " +- "slot is only %d", ++ "( Index: %d, pid: %d ) showed %u sessions " ++ "open on slot %d, but the global count for this " ++ "slot is only %u", + ProcIndex, pProc->proc_id, *pProcSessions, + SlotIndex, *pGlobalSessions); + #endif /* DEV */ +@@ -395,14 +396,8 @@ int Stat2Proc(int pid, proc_t *p) + char fbuf[800]; // about 40 fields, 64-bit decimal is about 20 chars + char *tmp; + int fd, num; +- // FILE *fp; +- +- // sprintf(buf, "%s/%d/stat", PROC_BASE, pid); +- // if( (fp = fopen(buf, "r")) == NULL ) +- // return FALSE; + + sprintf(fbuf, "%s/%d/stat", PROC_BASE, pid); +- printf("Buff = %s \n", fbuf); + fflush(stdout); + if ((fd = open(fbuf, O_RDONLY, 0)) == -1) + return FALSE; +diff --git a/usr/sbin/pkcsslotd/log.c b/usr/sbin/pkcsslotd/log.c +index 0214f952..0394cc7d 100644 +--- a/usr/sbin/pkcsslotd/log.c ++++ b/usr/sbin/pkcsslotd/log.c +@@ -463,8 +463,8 @@ BOOL PKCS_Log(pLogHandle phLog, char *fmt, va_list ap) + #endif /* DEV */ + + if (WriteNow) { +- fprintf(stderr, "%s[%d.%d]: %s\n", pInfo->Descrip, getpid(), +- (int) pthread_self(), buf); ++ fprintf(stderr, "%s[%d.%lu]: %s\n", pInfo->Descrip, getpid(), ++ pthread_self(), buf); + } + } + +@@ -482,7 +482,7 @@ BOOL PKCS_Log(pLogHandle phLog, char *fmt, va_list ap) + GetCurrentTimeString(timebuf); + + /* Date/Time stamp, descrip, Error message */ +- fprintf(fd, "%s %s[%d.%d]: ", timebuf, pInfo->Descrip, getpid(), ++ fprintf(fd, "%s %s[%d.%lu]: ", timebuf, pInfo->Descrip, getpid(), + pthread_self()); + fprintf(fd, "%s\n", buf); + fflush(fd); +diff --git a/usr/sbin/pkcsslotd/slotmgr.c b/usr/sbin/pkcsslotd/slotmgr.c +index 94288f13..efbfe8fd 100644 +--- a/usr/sbin/pkcsslotd/slotmgr.c ++++ b/usr/sbin/pkcsslotd/slotmgr.c +@@ -660,7 +660,6 @@ int main(int argc, char *argv[], char *envp[]) + */ + + #if !defined(NOGARBAGE) +- printf("Start garbage \n"); + /* start garbage collection thread */ + if (!StartGCThread(shmp)) { + term_socket_server(); diff --git a/opencryptoki-3.16.0-1fdd0e4497b0078e73e0004e3492db647c7c458b.patch b/opencryptoki-3.16.0-1fdd0e4497b0078e73e0004e3492db647c7c458b.patch new file mode 100644 index 0000000..264f27d --- /dev/null +++ b/opencryptoki-3.16.0-1fdd0e4497b0078e73e0004e3492db647c7c458b.patch @@ -0,0 +1,2304 @@ +commit 1fdd0e4497b0078e73e0004e3492db647c7c458b +Author: Ingo Franzki +Date: Wed Feb 24 15:47:05 2021 +0100 + + EP11: Handle APQN events to update APQN version, CP infos and target + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c +index 52f95d7a..728fedd5 100644 +--- a/usr/lib/ep11_stdll/ep11_specific.c ++++ b/usr/lib/ep11_stdll/ep11_specific.c +@@ -38,6 +38,7 @@ + #include "ock_syslog.h" + #include "ec_defs.h" + #include "p11util.h" ++#include "events.h" + + #include + #include +@@ -197,19 +198,27 @@ typedef struct { + + #define MAX_RETRY_COUNT 100 + +-#define RETRY_START do { \ ++#define RETRY_START(rc, tokdata) \ ++ do { \ + int retry_count; \ ++ ep11_target_info_t* target_info = \ ++ get_target_info((tokdata)); \ ++ if (target_info == NULL) \ ++ (rc) = CKR_FUNCTION_FAILED; \ + for(retry_count = 0; \ ++ target_info != NULL && \ + retry_count < MAX_RETRY_COUNT; \ + retry_count ++) { + + #define RETRY_END(rc, tokdata, session) if ((rc) != CKR_SESSION_CLOSED) \ + break; \ + (rc) = ep11tok_relogin_session( \ +- tokdata, session); \ ++ (tokdata), (session)); \ + if ((rc) != CKR_OK) \ + break; \ + } \ ++ put_target_info((tokdata), \ ++ target_info); \ + } while (0); + + #define CKF_EP11_HELPER_SESSION 0x80000000 +@@ -248,7 +257,6 @@ typedef struct ep11_card_version { + } ep11_card_version_t; + + static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version); +-static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata); + static void free_card_versions(ep11_card_version_t *card_version); + static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, + const CK_VERSION *ep11_lib_version, +@@ -476,16 +484,23 @@ static CK_RV handle_all_ep11_cards(ep11_target_t * ep11_targets, + #define PKEY_MODE_ENABLE4NONEXTR 2 + + typedef struct { ++ volatile unsigned long ref_count; + target_t target; ++ ep11_card_version_t *card_versions; ++ CK_ULONG used_firmware_API_version; ++ unsigned char control_points[XCP_CP_BYTES]; ++ size_t control_points_len; ++ size_t max_control_point_index; ++ CK_CHAR serialNumber[16]; ++} ep11_target_info_t; ++ ++typedef struct { + ep11_target_t target_list; + CK_BYTE raw2key_wrap_blob[MAX_BLOBSIZE]; + size_t raw2key_wrap_blob_l; + int cka_sensitive_default_true; + char cp_filter_config_filename[PATH_MAX]; + cp_config_t *cp_config; +- unsigned char control_points[XCP_CP_BYTES]; +- size_t control_points_len; +- size_t max_control_point_index; + int strict_mode; + int vhsm_mode; + int optimize_single_ops; +@@ -497,12 +512,14 @@ typedef struct { + char digest_libica_path[PATH_MAX]; + libica_t libica; + CK_VERSION ep11_lib_version; +- ep11_card_version_t *card_versions; +- CK_ULONG used_firmware_API_version; +- CK_CHAR serialNumber[16]; ++ volatile ep11_target_info_t *target_info; ++ pthread_rwlock_t target_rwlock; + } ep11_private_data_t; + +-static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata); ++static ep11_target_info_t *get_target_info(STDLL_TokData_t *tokdata); ++static void put_target_info(STDLL_TokData_t *tokdata, ++ ep11_target_info_t *target_info); ++static CK_RV refresh_target_info(STDLL_TokData_t *tokdata); + + static CK_RV get_ep11_target_for_apqn(uint_32 adapter, uint_32 domain, + target_t *target, uint64_t flags); +@@ -704,8 +721,13 @@ static CK_RV ep11tok_pkey_get_firmware_mk_vp(STDLL_TokData_t *tokdata) + CK_BYTE blob[MAX_BLOBSIZE]; + size_t blobsize = sizeof(blob); + CK_ATTRIBUTE *pkey_attr = NULL, *blob_attr=NULL; ++ ep11_target_info_t* target_info; + CK_RV ret; + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ + /* Check if CPACF_WRAP mech supported */ + if (ep11tok_is_mechanism_supported(tokdata, CKM_IBM_CPACF_WRAP) != CKR_OK) { + TRACE_INFO("CKM_IBM_CPACF_WRAP not supported on this system.\n"); +@@ -717,7 +739,7 @@ static CK_RV ep11tok_pkey_get_firmware_mk_vp(STDLL_TokData_t *tokdata) + + /* Create an AES testkey with CKA_IBM_PROTKEY_EXTRACTABLE */ + ret = dll_m_GenerateKey(&mech, tmpl, tmpl_len, NULL, 0, +- blob, &blobsize, csum, &csum_l, ep11_data->target); ++ blob, &blobsize, csum, &csum_l, target_info->target); + if (ret != CKR_OK) { + TRACE_ERROR("dll_m_GenerateKey failed with rc=0x%lx\n",ret); + goto done; +@@ -749,6 +771,8 @@ done: + if (blob_attr) + free(blob_attr); + ++ put_target_info(tokdata, target_info); ++ + return ret; + } + +@@ -1337,7 +1361,7 @@ static CK_RV ab_unwrap_update_template(STDLL_TokData_t * tokdata, + OBJECT *obj, + CK_KEY_TYPE keytype) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; ++ ep11_target_info_t* target_info; + CK_RV rc; + CK_BBOOL trusted, encrypt, decrypt, wrap, unwrap, sign, sign_recover, + verify, verify_recover, derive, extractable, local, +@@ -1367,9 +1391,16 @@ static CK_RV ab_unwrap_update_template(STDLL_TokData_t * tokdata, + CK_ATTRIBUTE *attr; + CK_BBOOL cktrue = TRUE; + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ + rc = dll_m_GetAttributeValue(blob, blob_len, attrs, + sizeof(attrs) / sizeof(CK_ATTRIBUTE), +- ep11_data->target); ++ target_info->target); ++ ++ put_target_info(tokdata, target_info); ++ + if (rc != CKR_OK) { + TRACE_ERROR("Retrieving attributes from AB unwrapped key failed, rc=0x%lx\n", + rc); +@@ -2117,10 +2148,10 @@ static CK_RV rawkey_2_blob(STDLL_TokData_t * tokdata, SESSION * sess, + * calls the ep11 lib (which in turns sends the request to the card), + * all m_ function are ep11 functions + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, &mech, key, +- ksize, cipher, &clen, ep11_data->target); ++ ksize, cipher, &clen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -2146,12 +2177,12 @@ static CK_RV rawkey_2_blob(STDLL_TokData_t * tokdata, SESSION * sess, + /* the encrypted key is decrypted and a blob is build, + * card accepts only blobs as keys + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(cipher, clen, ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, NULL, ~0, + ep11_pin_blob, ep11_pin_blob_len, &mech, + new_p_attrs, new_attrs_len, blob, blen, csum, +- &cslen, ep11_data->target); ++ &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -2194,14 +2225,20 @@ rawkey_2_blob_end: + CK_RV token_specific_rng(STDLL_TokData_t * tokdata, CK_BYTE * output, + CK_ULONG bytes) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + +- CK_RV rc = dll_m_GenerateRandom(output, bytes, ep11_data->target); ++ CK_RV rc = dll_m_GenerateRandom(output, bytes, target_info->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s output=%p bytes=%lu rc=0x%lx\n", + __func__, (void *)output, bytes, rc); + } ++ ++ put_target_info(tokdata, target_info); + return rc; + } + +@@ -2215,6 +2252,7 @@ static CK_RV make_wrapblob(STDLL_TokData_t * tokdata, CK_ATTRIBUTE * tmpl_in, + { + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_MECHANISM mech = { CKM_AES_KEY_GEN, NULL_PTR, 0 }; ++ ep11_target_info_t* target_info; + CK_BYTE csum[MAX_CSUMSIZE]; + size_t csum_l = sizeof(csum); + CK_RV rc; +@@ -2225,11 +2263,15 @@ static CK_RV make_wrapblob(STDLL_TokData_t * tokdata, CK_ATTRIBUTE * tmpl_in, + return CKR_OK; + } + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ + ep11_data->raw2key_wrap_blob_l = sizeof(ep11_data->raw2key_wrap_blob); + rc = dll_m_GenerateKey(&mech, tmpl_in, tmpl_len, NULL, 0, + ep11_data->raw2key_wrap_blob, + &ep11_data->raw2key_wrap_blob_l, csum, &csum_l, +- ep11_data->target); ++ target_info->target); + + + if (rc != CKR_OK) { +@@ -2240,6 +2282,7 @@ static CK_RV make_wrapblob(STDLL_TokData_t * tokdata, CK_ATTRIBUTE * tmpl_in, + __func__, ep11_data->raw2key_wrap_blob_l, rc); + } + ++ put_target_info(tokdata, target_info); + return rc; + } + +@@ -2479,6 +2522,14 @@ CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + if (ep11_data == NULL) + return CKR_HOST_MEMORY; + ++ if (pthread_rwlock_init(&ep11_data->target_rwlock, NULL) != 0) { ++ TRACE_DEVEL("Target Lock init failed.\n"); ++ OCK_SYSLOG(LOG_ERR, "%s: Failed to initialize the target lock\n", ++ __func__); ++ rc = CKR_CANT_LOCK; ++ goto error; ++ } ++ + tokdata->private_data = ep11_data; + + /* read ep11 specific config file with user specified +@@ -2513,13 +2564,28 @@ CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + } + #endif + +- rc = ep11tok_get_ep11_version(tokdata); +- if (rc != CKR_OK) ++ rc = ep11tok_get_ep11_library_version(&ep11_data->ep11_lib_version); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s Failed to get the Ep11 library version " ++ "(ep11tok_get_ep11_library_version rc=0x%lx)\n", __func__, ++ rc); ++ OCK_SYSLOG(LOG_ERR, "%s: Failed to get the EP11 library version " ++ "rc=0x%lx\n", __func__, rc); + goto error; ++ } + +- rc = ep11tok_setup_target(tokdata); +- if (rc != CKR_OK) ++ TRACE_INFO("%s Host library version: %d.%d\n", __func__, ++ ep11_data->ep11_lib_version.major, ++ ep11_data->ep11_lib_version.minor); ++ ++ rc = refresh_target_info(tokdata); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s Failed to get the target info (refresh_target_info " ++ "rc=0x%lx)\n", __func__, rc); ++ OCK_SYSLOG(LOG_ERR, "%s: Failed to get the target info rc=0x%lx\n", ++ __func__, rc); + goto error; ++ } + + if (ep11_data->digest_libica) { + rc = ep11tok_load_libica(tokdata); +@@ -2530,18 +2596,6 @@ CK_RV ep11tok_init(STDLL_TokData_t * tokdata, CK_SLOT_ID SlotNumber, + ep11_data->msa_level = get_msa_level(); + TRACE_INFO("MSA level = %i\n", ep11_data->msa_level); + +- ep11_data->control_points_len = sizeof(ep11_data->control_points); +- rc = get_control_points(tokdata, ep11_data->control_points, +- &ep11_data->control_points_len, +- &ep11_data->max_control_point_index); +- if (rc != CKR_OK) { +- TRACE_ERROR("%s Failed to get the control points (get_control_points " +- "rc=0x%lx)\n", __func__, rc); +- OCK_SYSLOG(LOG_ERR, "%s: Failed to get the control points rc=0x%lx\n", +- __func__, rc); +- goto error; +- } +- + /* create an AES key needed for importing keys + * (encrypt by wrap_key and m_UnwrapKey by wrap key) + */ +@@ -2600,10 +2654,14 @@ CK_RV ep11tok_final(STDLL_TokData_t * tokdata) + TRACE_INFO("ep11 %s running\n", __func__); + + if (ep11_data != NULL) { +- if (dll_m_rm_module != NULL) +- dll_m_rm_module(NULL, ep11_data->target); ++ if (ep11_data->target_info != NULL) { ++ if (dll_m_rm_module != NULL) ++ dll_m_rm_module(NULL, ep11_data->target_info->target); ++ free_card_versions(ep11_data->target_info->card_versions); ++ free((void* )ep11_data->target_info); ++ } ++ pthread_rwlock_destroy(&ep11_data->target_rwlock); + free_cp_config(ep11_data->cp_config); +- free_card_versions(ep11_data->card_versions); + free(ep11_data); + tokdata->private_data = NULL; + } +@@ -2619,7 +2677,6 @@ static CK_RV make_maced_spki(STDLL_TokData_t *tokdata, SESSION * sess, + CK_BYTE *spki, CK_ULONG spki_len, + CK_BYTE *maced_spki, CK_ULONG *maced_spki_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + unsigned char *ep11_pin_blob = NULL; + CK_ULONG ep11_pin_blob_len = 0; + ep11_session_t *ep11_session = (ep11_session_t *) sess->private_data; +@@ -2712,11 +2769,11 @@ static CK_RV make_maced_spki(STDLL_TokData_t *tokdata, SESSION * sess, + ep11_get_pin_blob(ep11_session, object_is_session_object(pub_key_obj), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(spki, spki_len, NULL, 0, NULL, 0, + ep11_pin_blob, ep11_pin_blob_len, &mech, + p_attrs, attrs_len, maced_spki, maced_spki_len, +- csum, &cslen, ep11_data->target); ++ csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -2870,11 +2927,11 @@ static CK_RV import_RSA_key(STDLL_TokData_t * tokdata, SESSION * sess, + } + + /* encrypt */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, &mech_w, + data, data_len, cipher, &cipher_l, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", +@@ -2901,12 +2958,12 @@ static CK_RV import_RSA_key(STDLL_TokData_t * tokdata, SESSION * sess, + /* calls the card, it decrypts the private RSA key, + * reads its BER format and builds a blob. + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(cipher, cipher_l, ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, NULL, ~0, + ep11_pin_blob, ep11_pin_blob_len, &mech_w, + new_p_attrs, new_attrs_len, blob, blob_size, +- csum, &cslen, ep11_data->target); ++ csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -3101,11 +3158,11 @@ static CK_RV import_EC_key(STDLL_TokData_t * tokdata, SESSION * sess, + } + + /* encrypt */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, +- cipher, &cipher_l, ep11_data->target); ++ cipher, &cipher_l, target_info->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", +@@ -3133,14 +3190,14 @@ static CK_RV import_EC_key(STDLL_TokData_t * tokdata, SESSION * sess, + /* calls the card, it decrypts the private EC key, + * reads its BER format and builds a blob. + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, NULL, ~0, + ep11_pin_blob, + ep11_pin_blob_len, &mech_w, + new_p_attrs, new_attrs_len, blob, +- blob_size, csum, &cslen, ep11_data->target); ++ blob_size, csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -3295,11 +3352,11 @@ static CK_RV import_DSA_key(STDLL_TokData_t * tokdata, SESSION * sess, + } + + /* encrypt */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, +- cipher, &cipher_l, ep11_data->target); ++ cipher, &cipher_l, target_info->target); + RETRY_END(rc, tokdata, sess) + + +@@ -3327,14 +3384,14 @@ static CK_RV import_DSA_key(STDLL_TokData_t * tokdata, SESSION * sess, + /* calls the card, it decrypts the private EC key, + * reads its BER format and builds a blob. + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, NULL, ~0, + ep11_pin_blob, + ep11_pin_blob_len, &mech_w, + new_p_attrs, new_attrs_len, blob, +- blob_size, csum, &cslen, ep11_data->target); ++ blob_size, csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -3478,11 +3535,11 @@ static CK_RV import_DH_key(STDLL_TokData_t * tokdata, SESSION * sess, + } + + /* encrypt */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, +- cipher, &cipher_l, ep11_data->target); ++ cipher, &cipher_l, target_info->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", +@@ -3509,14 +3566,14 @@ static CK_RV import_DH_key(STDLL_TokData_t * tokdata, SESSION * sess, + /* calls the card, it decrypts the private EC key, + * reads its BER format and builds a blob. + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, NULL, ~0, + ep11_pin_blob, + ep11_pin_blob_len, &mech_w, + new_p_attrs, new_attrs_len, blob, +- blob_size, csum, &cslen, ep11_data->target); ++ blob_size, csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -3666,11 +3723,11 @@ static CK_RV import_IBM_Dilithium_key(STDLL_TokData_t * tokdata, SESSION * sess, + } + + /* encrypt */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, + &mech_w, data, data_len, +- cipher, &cipher_l, ep11_data->target); ++ cipher, &cipher_l, target_info->target); + RETRY_END(rc, tokdata, sess) + + TRACE_INFO("%s wrapping wrap key rc=0x%lx cipher_l=0x%lx\n", +@@ -3699,14 +3756,14 @@ static CK_RV import_IBM_Dilithium_key(STDLL_TokData_t * tokdata, SESSION * sess, + /* calls the card, it decrypts the private Dilithium key, + * reads its BER format and builds a blob. + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(cipher, cipher_l, + ep11_data->raw2key_wrap_blob, + ep11_data->raw2key_wrap_blob_l, NULL, ~0, + ep11_pin_blob, + ep11_pin_blob_len, &mech_w, + new_p_attrs, new_attrs_len, blob, +- blob_size, csum, &cslen, ep11_data->target); ++ blob_size, csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -3884,7 +3941,6 @@ CK_RV ep11tok_generate_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len, CK_OBJECT_HANDLE_PTR handle) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_BYTE blob[MAX_BLOBSIZE]; + size_t blobsize = sizeof(blob); + CK_BYTE csum[MAX_CSUMSIZE]; +@@ -3936,10 +3992,10 @@ CK_RV ep11tok_generate_key(STDLL_TokData_t * tokdata, SESSION * session, + ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_GenerateKey(mech, new_attrs2, new_attrs2_len, ep11_pin_blob, + ep11_pin_blob_len, blob, &blobsize, +- csum, &csum_len, ep11_data->target); ++ csum, &csum_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4354,6 +4410,7 @@ CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + size_t state_len = MAX(MAX_DIGEST_STATE_BYTES, sizeof(libica_sha_context_t)); + CK_BYTE *state; + libica_sha_context_t *libica_ctx; ++ ep11_target_info_t* target_info; + + state = calloc(state_len, 1); /* freed by dig_mgr.c */ + if (!state) { +@@ -4361,15 +4418,21 @@ CK_RV token_specific_sha_init(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + return CKR_HOST_MEMORY; + } + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ + if (ep11tok_libica_digest_available(ep11_data, mech->mechanism)) { + libica_ctx = (libica_sha_context_t *)state; + state_len = sizeof(libica_sha_context_t); + libica_ctx->first = CK_TRUE; + rc = get_sha_block_size(mech->mechanism, &libica_ctx->block_size); + } else { +- rc = dll_m_DigestInit(state, &state_len, mech, ep11_data->target); ++ rc = dll_m_DigestInit(state, &state_len, mech, target_info->target); + } + ++ put_target_info(tokdata, target_info); ++ + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); +@@ -4399,6 +4462,11 @@ CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + { + ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + + if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) { + rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism, +@@ -4408,7 +4476,7 @@ CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + SHA_MSG_PART_ONLY); + } else { + rc = dll_m_Digest(c->context, c->context_len, in_data, in_data_len, +- out_data, out_data_len, ep11_data->target); ++ out_data, out_data_len, target_info->target); + } + + if (rc != CKR_OK) { +@@ -4417,6 +4485,8 @@ CK_RV token_specific_sha(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } ++ ++ put_target_info(tokdata, target_info); + return rc; + } + +@@ -4430,6 +4500,11 @@ CK_RV token_specific_sha_update(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + CK_ULONG out_len = sizeof(temp_out); + CK_ULONG len; + CK_RV rc = CKR_OK; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + + if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) { + if (libica_ctx->offset > 0 || in_data_len < libica_ctx->block_size) { +@@ -4479,7 +4554,7 @@ CK_RV token_specific_sha_update(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + } + } else { + rc = dll_m_DigestUpdate(c->context, c->context_len, +- in_data, in_data_len, ep11_data->target); ++ in_data, in_data_len, target_info->target); + } + + out: +@@ -4489,6 +4564,8 @@ out: + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } ++ ++ put_target_info(tokdata, target_info); + return rc; + } + +@@ -4499,6 +4576,11 @@ CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + ep11_private_data_t *ep11_data = tokdata->private_data; + libica_sha_context_t *libica_ctx = (libica_sha_context_t *)c->context; + CK_RV rc; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + + if (ep11tok_libica_digest_available(ep11_data, c->mech.mechanism)) { + rc = ep11tok_libica_digest(ep11_data, c->mech.mechanism, +@@ -4510,7 +4592,7 @@ CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + SHA_MSG_PART_FINAL); + } else { + rc = dll_m_DigestFinal(c->context, c->context_len, +- out_data, out_data_len, ep11_data->target); ++ out_data, out_data_len, target_info->target); + } + + if (rc != CKR_OK) { +@@ -4520,6 +4602,7 @@ CK_RV token_specific_sha_final(STDLL_TokData_t * tokdata, DIGEST_CONTEXT * c, + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } + ++ put_target_info(tokdata, target_info); + return rc; + } + +@@ -4528,7 +4611,6 @@ CK_RV token_specific_rsa_sign(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key_obj) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; +@@ -4544,9 +4626,9 @@ CK_RV token_specific_rsa_sign(STDLL_TokData_t *tokdata, SESSION *session, + mech.pParameter = NULL; + mech.ulParameterLen = 0; + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, +- out_data, out_data_len, ep11_data->target); ++ out_data, out_data_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4563,7 +4645,6 @@ CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *signature, CK_ULONG sig_len, + OBJECT *key_obj) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; +@@ -4579,9 +4660,9 @@ CK_RV token_specific_rsa_verify(STDLL_TokData_t *tokdata, SESSION *session, + mech.pParameter = NULL; + mech.ulParameterLen = 0; + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, +- signature, sig_len, ep11_data->target); ++ signature, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4598,7 +4679,6 @@ CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *sig, CK_ULONG *sig_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; +@@ -4616,9 +4696,9 @@ CK_RV token_specific_rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *session, + mech.ulParameterLen = ctx->mech.ulParameterLen; + mech.pParameter = ctx->mech.pParameter; + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, +- sig, sig_len, ep11_data->target); ++ sig, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4638,7 +4718,6 @@ CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *signature, CK_ULONG sig_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; +@@ -4656,9 +4735,9 @@ CK_RV token_specific_rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *session, + mech.ulParameterLen = ctx->mech.ulParameterLen; + mech.pParameter = ctx->mech.pParameter; + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, +- signature, sig_len, ep11_data->target); ++ signature, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4678,7 +4757,6 @@ CK_RV token_specific_ec_sign(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *out_data, CK_ULONG *out_data_len, + OBJECT *key_obj ) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + SIGN_VERIFY_CONTEXT *ctx = &(session->sign_ctx); + CK_RV rc; + size_t keyblobsize = 0; +@@ -4707,9 +4785,9 @@ CK_RV token_specific_ec_sign(STDLL_TokData_t *tokdata, SESSION *session, + mech.pParameter = NULL; + mech.ulParameterLen = 0; + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignSingle(keyblob, keyblobsize, &mech, in_data, in_data_len, +- out_data, out_data_len, ep11_data->target); ++ out_data, out_data_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4728,7 +4806,6 @@ CK_RV token_specific_ec_verify(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *out_data, CK_ULONG out_data_len, + OBJECT *key_obj ) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + SIGN_VERIFY_CONTEXT *ctx = &(session->verify_ctx); + CK_RV rc; + CK_BYTE *spki; +@@ -4757,9 +4834,9 @@ CK_RV token_specific_ec_verify(STDLL_TokData_t *tokdata, SESSION *session, + mech.pParameter = NULL; + mech.ulParameterLen = 0; + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifySingle(spki, spki_len, &mech, in_data, in_data_len, +- out_data, out_data_len, ep11_data->target); ++ out_data, out_data_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4784,7 +4861,6 @@ CK_RV token_specific_reencrypt_single(STDLL_TokData_t *tokdata, + CK_BYTE *in_data, CK_ULONG in_data_len, + CK_BYTE *out_data, CK_ULONG *out_data_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *decr_key, *encr_key; + size_t decr_key_len = 0, encr_key_len = 0; +@@ -4813,10 +4889,10 @@ CK_RV token_specific_reencrypt_single(STDLL_TokData_t *tokdata, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_ReencryptSingle(decr_key, decr_key_len, encr_key, encr_key_len, + decr_mech, encr_mech, in_data, in_data_len, +- out_data, out_data_len, ep11_data->target); ++ out_data, out_data_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -4892,7 +4968,6 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_OBJECT_HANDLE_PTR handle, CK_ATTRIBUTE_PTR attrs, + CK_ULONG attrs_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *keyblob; + size_t keyblobsize; +@@ -4920,6 +4995,8 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_ULONG privlen; + int curve_type; + CK_BBOOL allocated = FALSE; ++ ep11_target_info_t* target_info; ++ CK_ULONG used_firmware_API_version; + + memset(newblob, 0, sizeof(newblob)); + +@@ -5009,7 +5086,15 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session, + * then we can pass the mechanism parameters as-is, otherwise we still + * need to use the old way. + */ +- if (ep11_data->used_firmware_API_version <= 2) { ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ ++ used_firmware_API_version = target_info->used_firmware_API_version; ++ ++ put_target_info(tokdata, target_info); ++ ++ if (used_firmware_API_version <= 2) { + if (ecdh1_parms->kdf != CKD_NULL) { + TRACE_ERROR("%s KDF for CKM_ECDH1_DERIVE not supported: %lu\n", + __func__, ecdh1_parms->kdf); +@@ -5133,11 +5218,11 @@ CK_RV ep11tok_derive_key(STDLL_TokData_t * tokdata, SESSION * session, + ep11_get_pin_blob(ep11_session, ep11_is_session_object(attrs, attrs_len), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = + dll_m_DeriveKey(mech, new_attrs2, new_attrs2_len, keyblob, keyblobsize, + NULL, 0, ep11_pin_blob, ep11_pin_blob_len, newblob, +- &newblobsize, csum, &cslen, ep11_data->target); ++ &newblobsize, csum, &cslen, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -5231,7 +5316,6 @@ static CK_RV dh_generate_keypair(STDLL_TokData_t * tokdata, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE publblob[MAX_BLOBSIZE]; + size_t publblobsize = sizeof(publblob); +@@ -5418,13 +5502,13 @@ static CK_RV dh_generate_keypair(STDLL_TokData_t * tokdata, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_GenerateKeyPair(pMechanism, + new_publ_attrs, new_publ_attrs_len, + new_priv_attrs, new_priv_attrs_len, + ep11_pin_blob, ep11_pin_blob_len, + privblob, &privblobsize, +- publblob, &publblobsize, ep11_data->target); ++ publblob, &publblobsize, target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -5543,7 +5627,6 @@ static CK_RV dsa_generate_keypair(STDLL_TokData_t * tokdata, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE publblob[MAX_BLOBSIZE]; + size_t publblobsize = sizeof(publblob); +@@ -5752,13 +5835,13 @@ static CK_RV dsa_generate_keypair(STDLL_TokData_t * tokdata, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_GenerateKeyPair(pMechanism, + new_publ_attrs2, new_publ_attrs2_len, + new_priv_attrs2, new_priv_attrs2_len, + ep11_pin_blob, ep11_pin_blob_len, privblob, + &privblobsize, publblob, &publblobsize, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, sess) + + if (rc != CKR_OK) { +@@ -5866,7 +5949,6 @@ static CK_RV rsa_ec_generate_keypair(STDLL_TokData_t * tokdata, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_ATTRIBUTE *n_attr = NULL; +@@ -5967,13 +6049,13 @@ static CK_RV rsa_ec_generate_keypair(STDLL_TokData_t * tokdata, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_GenerateKeyPair(pMechanism, + new_publ_attrs2, new_publ_attrs2_len, + new_priv_attrs2, new_priv_attrs2_len, + ep11_pin_blob, ep11_pin_blob_len, + privkey_blob, &privkey_blob_len, spki, +- &spki_len, ep11_data->target); ++ &spki_len, target_info->target); + RETRY_END(rc, tokdata, sess) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); +@@ -6225,7 +6307,6 @@ static CK_RV ibm_dilithium_generate_keypair(STDLL_TokData_t * tokdata, + CK_ULONG ulPrivateKeyAttributeCount, + CK_SESSION_HANDLE h) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_ATTRIBUTE *attr = NULL; + CK_BYTE privkey_blob[MAX_BLOBSIZE]; +@@ -6308,13 +6389,13 @@ static CK_RV ibm_dilithium_generate_keypair(STDLL_TokData_t * tokdata, + ulPrivateKeyAttributeCount)), + &ep11_pin_blob, &ep11_pin_blob_len); + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_GenerateKeyPair(pMechanism, + new_publ_attrs2, new_publ_attrs2_len, + new_priv_attrs2, new_priv_attrs2_len, + ep11_pin_blob, ep11_pin_blob_len, + privkey_blob, &privkey_blob_len, spki, +- &spki_len, ep11_data->target); ++ &spki_len, target_info->target); + RETRY_END(rc, tokdata, sess) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, sess); +@@ -6914,7 +6995,6 @@ CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM * mech, CK_BBOOL recover_mode, + CK_OBJECT_HANDLE key) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + size_t keyblobsize = 0; + CK_BYTE *keyblob; +@@ -6980,9 +7060,9 @@ CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, + goto done; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignInit(ep11_sign_state, &ep11_sign_state_l, +- mech, keyblob, keyblobsize, ep11_data->target); ++ mech, keyblob, keyblobsize, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7017,7 +7097,6 @@ CK_RV ep11tok_sign(STDLL_TokData_t * tokdata, SESSION * session, + CK_ULONG in_data_len, CK_BYTE * signature, + CK_ULONG * sig_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + size_t keyblobsize = 0; +@@ -7049,9 +7128,9 @@ CK_RV ep11tok_sign(STDLL_TokData_t * tokdata, SESSION * session, + goto done; /* no ep11 fallback possible */ + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_Sign(ctx->context, ctx->context_len, in_data, in_data_len, +- signature, sig_len, ep11_data->target); ++ signature, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7073,7 +7152,6 @@ done: + CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + size_t keyblobsize = 0; +@@ -7095,9 +7173,9 @@ CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignUpdate(ctx->context, ctx->context_len, in_data, +- in_data_len, ep11_data->target); ++ in_data_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7120,7 +7198,6 @@ CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BBOOL length_only, CK_BYTE * signature, + CK_ULONG * sig_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->sign_ctx; + size_t keyblobsize = 0; +@@ -7139,9 +7216,9 @@ CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignFinal(ctx->context, ctx->context_len, signature, sig_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7169,7 +7246,6 @@ CK_RV ep11tok_sign_single(STDLL_TokData_t *tokdata, SESSION *session, + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; +- ep11_private_data_t *ep11_data = tokdata->private_data; + + UNUSED(length_only); + +@@ -7186,9 +7262,9 @@ CK_RV ep11tok_sign_single(STDLL_TokData_t *tokdata, SESSION *session, + goto done; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_SignSingle(keyblob, keyblobsize, mech, in_data, in_data_len, +- signature, sig_len, ep11_data->target); ++ signature, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -7209,7 +7285,6 @@ CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM * mech, CK_BBOOL recover_mode, + CK_OBJECT_HANDLE key) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *spki; + size_t spki_len = 0; +@@ -7285,9 +7360,9 @@ CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session, + goto done; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifyInit(ep11_sign_state, &ep11_sign_state_l, mech, +- spki, spki_len, ep11_data->target); ++ spki, spki_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7320,7 +7395,6 @@ CK_RV ep11tok_verify(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len, + CK_BYTE * signature, CK_ULONG sig_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + size_t keyblobsize = 0; +@@ -7353,9 +7427,9 @@ CK_RV ep11tok_verify(STDLL_TokData_t * tokdata, SESSION * session, + goto done; /* no ep11 fallback possible */ + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_Verify(ctx->context, ctx->context_len, in_data, in_data_len, +- signature, sig_len, ep11_data->target); ++ signature, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7377,7 +7451,6 @@ done: + CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * in_data, CK_ULONG in_data_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + size_t keyblobsize = 0; +@@ -7399,9 +7472,9 @@ CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifyUpdate(ctx->context, ctx->context_len, in_data, +- in_data_len, ep11_data->target); ++ in_data_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7423,7 +7496,6 @@ done: + CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE * signature, CK_ULONG sig_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + SIGN_VERIFY_CONTEXT *ctx = &session->verify_ctx; + size_t keyblobsize = 0; +@@ -7442,9 +7514,9 @@ CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifyFinal(ctx->context, ctx->context_len, signature, +- sig_len, ep11_data->target); ++ sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7471,7 +7543,6 @@ CK_RV ep11tok_verify_single(STDLL_TokData_t *tokdata, SESSION *session, + CK_BYTE *spki; + size_t spki_len = 0; + OBJECT *key_obj = NULL; +- ep11_private_data_t *ep11_data = tokdata->private_data; + + rc = h_opaque_2_blob(tokdata, key, &spki, &spki_len, &key_obj, READ_LOCK); + if (rc != CKR_OK) { +@@ -7495,9 +7566,9 @@ CK_RV ep11tok_verify_single(STDLL_TokData_t *tokdata, SESSION *session, + goto done; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_VerifySingle(spki, spki_len, mech, in_data, in_data_len, +- signature, sig_len, ep11_data->target); ++ signature, sig_len, target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -7517,7 +7588,6 @@ CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); +@@ -7538,10 +7608,10 @@ CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_DecryptFinal(ctx->context, ctx->context_len, + output_part, p_output_part_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7564,7 +7634,6 @@ CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_data, CK_ULONG input_data_len, + CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + CK_BBOOL length_only = (output_data == NULL ? CK_TRUE : CK_FALSE); +@@ -7586,10 +7655,10 @@ CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_Decrypt(ctx->context, ctx->context_len, input_data, + input_data_len, output_data, p_output_data_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7613,7 +7682,6 @@ CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; + CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); +@@ -7640,10 +7708,10 @@ CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_DecryptUpdate(ctx->context, ctx->context_len, + input_part, input_part_len, output_part, +- p_output_part_len, ep11_data->target); ++ p_output_part_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7671,7 +7739,6 @@ CK_RV ep11tok_decrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; +- ep11_private_data_t *ep11_data = tokdata->private_data; + + UNUSED(length_only); + +@@ -7688,10 +7755,10 @@ CK_RV ep11tok_decrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + goto done; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_DecryptSingle(keyblob, keyblobsize, mech, input_data, + input_data_len, output_data, p_output_data_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -7711,7 +7778,6 @@ CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); +@@ -7732,10 +7798,10 @@ CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptFinal(ctx->context, ctx->context_len, + output_part, p_output_part_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7758,7 +7824,6 @@ CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR input_data, CK_ULONG input_data_len, + CK_BYTE_PTR output_data, CK_ULONG_PTR p_output_data_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + CK_BBOOL length_only = (output_data == NULL ? CK_TRUE : CK_FALSE); +@@ -7780,10 +7845,10 @@ CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_Encrypt(ctx->context, ctx->context_len, input_data, + input_data_len, output_data, p_output_data_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7807,7 +7872,6 @@ CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE_PTR output_part, + CK_ULONG_PTR p_output_part_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + ENCR_DECR_CONTEXT *ctx = &session->encr_ctx; + CK_BBOOL length_only = (output_part == NULL ? CK_TRUE : CK_FALSE); +@@ -7834,10 +7898,10 @@ CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptUpdate(ctx->context, ctx->context_len, + input_part, input_part_len, output_part, +- p_output_part_len, ep11_data->target); ++ p_output_part_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -7865,7 +7929,6 @@ CK_RV ep11tok_encrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + size_t keyblobsize = 0; + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; +- ep11_private_data_t *ep11_data = tokdata->private_data; + + UNUSED(length_only); + +@@ -7893,10 +7956,10 @@ CK_RV ep11tok_encrypt_single(STDLL_TokData_t *tokdata, SESSION *session, + goto done; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptSingle(keyblob, keyblobsize, mech, input_data, + input_data_len, output_data, p_output_data_len, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -7916,7 +7979,6 @@ static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session, + CK_MECHANISM_PTR mech, CK_OBJECT_HANDLE key, + int op) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = CKR_OK; + CK_BYTE *blob; + size_t blob_len = 0; +@@ -7979,9 +8041,9 @@ static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session, + + if (op == DECRYPT) { + ENCR_DECR_CONTEXT *ctx = &session->decr_ctx; +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_DecryptInit(ep11_state, &ep11_state_l, mech, blob, +- blob_len, ep11_data->target); ++ blob_len, target_info->target); + RETRY_END(rc, tokdata, session) + ctx->key = key; + ctx->active = TRUE; +@@ -8012,9 +8074,9 @@ static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session, + goto error; + } + +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_EncryptInit(ep11_state, &ep11_state_l, mech, blob, +- blob_len, ep11_data->target); ++ blob_len, target_info->target); + RETRY_END(rc, tokdata, session) + ctx->key = key; + ctx->active = TRUE; +@@ -8092,7 +8154,6 @@ CK_RV ep11tok_wrap_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_OBJECT_HANDLE key, CK_BYTE_PTR wrapped_key, + CK_ULONG_PTR p_wrapped_key_len) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *wrapping_blob; + size_t wrapping_blob_len; +@@ -8192,11 +8253,11 @@ CK_RV ep11tok_wrap_key(STDLL_TokData_t * tokdata, SESSION * session, + * (wrapping blob). The wrapped key can be processed by any PKCS11 + * implementation. + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = + dll_m_WrapKey(wrap_target_blob, wrap_target_blob_len, wrapping_blob, + wrapping_blob_len, sign_blob, sign_blob_len, mech, +- wrapped_key, p_wrapped_key_len, ep11_data->target); ++ wrapped_key, p_wrapped_key_len, target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -8228,7 +8289,6 @@ CK_RV ep11tok_unwrap_key(STDLL_TokData_t * tokdata, SESSION * session, + CK_OBJECT_HANDLE wrapping_key, + CK_OBJECT_HANDLE_PTR p_key) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + CK_BYTE *wrapping_blob, *temp; + size_t wrapping_blob_len; +@@ -8388,13 +8448,13 @@ CK_RV ep11tok_unwrap_key(STDLL_TokData_t * tokdata, SESSION * session, + /* we need a blob for the new key created by unwrapping, + * the wrapped key comes in BER + */ +- RETRY_START ++ RETRY_START(rc, tokdata) + rc = dll_m_UnwrapKey(wrapped_key, wrapped_key_len, wrapping_blob, + wrapping_blob_len, verifyblob, verifyblobsize, + ep11_pin_blob, + ep11_pin_blob_len, mech, new_attrs2, new_attrs2_len, + keyblob, &keyblobsize, csum, &cslen, +- ep11_data->target); ++ target_info->target); + RETRY_END(rc, tokdata, session) + + if (rc != CKR_OK) { +@@ -8657,21 +8717,25 @@ CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE_PTR pMechanismList, + CK_ULONG_PTR pulCount) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc = 0; + CK_ULONG counter = 0, size = 0; + CK_MECHANISM_TYPE_PTR mlist = NULL; + CK_ULONG i; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + + /* size querry */ + if (pMechanismList == NULL) { + rc = dll_m_GetMechanismList(0, pMechanismList, pulCount, +- ep11_data->target); ++ target_info->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #1\n", + __func__, rc); +- return rc; ++ goto out; + } + + /* adjust the size according to the ban list, +@@ -8693,16 +8757,16 @@ CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + sizeof(CK_MECHANISM_TYPE) * counter); + if (!mlist) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); +- return CKR_HOST_MEMORY; ++ rc = CKR_HOST_MEMORY; ++ goto out; + } +- rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target); ++ rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #2\n", + __func__, rc); +- free(mlist); + if (rc != CKR_BUFFER_TOO_SMALL) +- return rc; ++ goto out; + } + } while (rc == CKR_BUFFER_TOO_SMALL); + +@@ -8722,12 +8786,12 @@ CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + * that comes as parameter, this is a 'reduced size', + * ep11 would complain about insufficient list size + */ +- rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target); ++ rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #3\n", + __func__, rc); +- return rc; ++ goto out; + } + + /* +@@ -8744,17 +8808,17 @@ CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + sizeof(CK_MECHANISM_TYPE) * counter); + if (!mlist) { + TRACE_ERROR("%s Memory allocation failed\n", __func__); +- return CKR_HOST_MEMORY; ++ rc = CKR_HOST_MEMORY; ++ goto out; + } + /* all the card has */ +- rc = dll_m_GetMechanismList(0, mlist, &counter, ep11_data->target); ++ rc = dll_m_GetMechanismList(0, mlist, &counter, target_info->target); + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s bad rc=0x%lx from m_GetMechanismList() #4\n", + __func__, rc); +- free(mlist); + if (rc != CKR_BUFFER_TOO_SMALL) +- return rc; ++ goto out; + } + } while (rc == CKR_BUFFER_TOO_SMALL); + +@@ -8775,8 +8839,10 @@ CK_RV ep11tok_get_mechanism_list(STDLL_TokData_t * tokdata, + rc = CKR_BUFFER_TOO_SMALL; + } + ++out: + if (mlist) + free(mlist); ++ put_target_info(tokdata, target_info); + return rc; + } + +@@ -8790,6 +8856,8 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + CK_BBOOL found = FALSE; + CK_ULONG i; + int status; ++ CK_RV rc = CKR_OK; ++ ep11_target_info_t* target_info; + + for (i = 0; i < supported_mech_list_len; i++) { + if (type == ep11_supported_mech_list[i]) { +@@ -8804,13 +8872,18 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + return CKR_MECHANISM_INVALID; + } + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ + if (check_cps_for_mechanism(ep11_data->cp_config, +- type, ep11_data->control_points, +- ep11_data->control_points_len, +- ep11_data->max_control_point_index) != CKR_OK) { ++ type, target_info->control_points, ++ target_info->control_points_len, ++ target_info->max_control_point_index) != CKR_OK) { + TRACE_INFO("%s Mech '%s' banned due to control point\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + + switch(type) { +@@ -8840,14 +8913,17 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + if (status == -1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + break; + + case CKM_RSA_PKCS_OAEP: + /* CKM_RSA_PKCS_OAEP is not supported with EP11 host library <= 1.3 */ +- if (compare_ck_version(&ep11_data->ep11_lib_version, &ver1_3) <= 0) +- return CKR_MECHANISM_INVALID; ++ if (compare_ck_version(&ep11_data->ep11_lib_version, &ver1_3) <= 0) { ++ rc = CKR_MECHANISM_INVALID; ++ goto out; ++ } + break; + + case CKM_IBM_SHA3_224: +@@ -8863,7 +8939,8 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + break; + +@@ -8876,7 +8953,8 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + break; + +@@ -8887,7 +8965,8 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) < 0) { + TRACE_INFO("%s Mech '%s' banned due to host library version\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + + status = check_required_versions(tokdata, edwards_req_versions, +@@ -8895,7 +8974,8 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + break; + +@@ -8903,14 +8983,16 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + if (compare_ck_version(&ep11_data->ep11_lib_version, &ver3) <= 0) { + TRACE_INFO("%s Mech '%s' banned due to host library version\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + status = check_required_versions(tokdata, ibm_dilithium_req_versions, + NUM_DILITHIUM_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + break; + +@@ -8919,19 +9001,23 @@ CK_RV ep11tok_is_mechanism_supported(STDLL_TokData_t *tokdata, + TRACE_INFO("%s Mech '%s' banned due to host library version\n", + __func__, ep11_get_ckm(type)); + +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + status = check_required_versions(tokdata, ibm_cpacf_wrap_req_versions, + NUM_CPACF_WRAP_REQ); + if (status != 1) { + TRACE_INFO("%s Mech '%s' banned due to mixed firmware versions\n", + __func__, ep11_get_ckm(type)); +- return CKR_MECHANISM_INVALID; ++ rc = CKR_MECHANISM_INVALID; ++ goto out; + } + break; + } + +- return CKR_OK; ++out: ++ put_target_info(tokdata, target_info); ++ return rc; + } + + CK_RV ep11tok_is_mechanism_supported_ex(STDLL_TokData_t *tokdata, +@@ -8976,9 +9062,9 @@ CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata, + CK_MECHANISM_TYPE type, + CK_MECHANISM_INFO_PTR pInfo) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_RV rc; + int status; ++ ep11_target_info_t* target_info; + + rc = ep11tok_is_mechanism_supported(tokdata, type); + if (rc != CKR_OK) { +@@ -8987,7 +9073,14 @@ CK_RV ep11tok_get_mechanism_info(STDLL_TokData_t * tokdata, + return rc; + } + +- rc = dll_m_GetMechanismInfo(0, type, pInfo, ep11_data->target); ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ ++ rc = dll_m_GetMechanismInfo(0, type, pInfo, target_info->target); ++ ++ put_target_info(tokdata, target_info); ++ + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s m_GetMechanismInfo(0x%lx) failed with rc=0x%lx\n", +@@ -10265,6 +10358,11 @@ static CK_RV generate_ep11_session_id(STDLL_TokData_t * tokdata, + CK_MECHANISM mech; + CK_ULONG len; + libica_sha_context_t ctx; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + + session_id_data.handle = session->handle; + gettimeofday(&session_id_data.timeofday, NULL); +@@ -10286,7 +10384,9 @@ static CK_RV generate_ep11_session_id(STDLL_TokData_t * tokdata, + rc = dll_m_DigestSingle(&mech, (CK_BYTE_PTR)&session_id_data, + sizeof(session_id_data), + ep11_session->session_id, &len, +- ep11_data->target); ++ target_info->target); ++ ++ put_target_info(tokdata, target_info); + + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, session); +@@ -10964,7 +11064,7 @@ static CK_RV get_card_type(uint_32 adapter, CK_ULONG *type) + + typedef struct query_version + { +- ep11_private_data_t *ep11_data; ++ ep11_target_info_t *target_info; + CK_CHAR serialNumber[16]; + CK_BBOOL first; + CK_BBOOL error; +@@ -11005,7 +11105,7 @@ static CK_RV version_query_handler(uint_32 adapter, uint_32 domain, + } + + /* Try to find existing version info for this card type */ +- card_version = qv->ep11_data->card_versions; ++ card_version = qv->target_info->card_versions; + while (card_version != NULL) { + if (card_version->card_type == card_type) + break; +@@ -11050,8 +11150,8 @@ static CK_RV version_query_handler(uint_32 adapter, uint_32 domain, + card_version->firmware_version = xcp_info.firmwareVersion; + #endif + +- card_version->next = qv->ep11_data->card_versions; +- qv->ep11_data->card_versions = card_version; ++ card_version->next = qv->target_info->card_versions; ++ qv->target_info->card_versions = card_version; + } else { + /* + * Version info for this card type is already available, so check this +@@ -11134,23 +11234,16 @@ static CK_RV ep11tok_get_ep11_library_version(CK_VERSION *lib_version) + return CKR_OK; + } + +-static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata) ++static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata, ++ ep11_target_info_t *target_info) + { + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_card_version_t *card_version; + query_version_t qv; + CK_RV rc; + +- rc = ep11tok_get_ep11_library_version(&ep11_data->ep11_lib_version); +- if (rc != CKR_OK) +- return rc; +- +- TRACE_INFO("%s Host library version: %d.%d\n", __func__, +- ep11_data->ep11_lib_version.major, +- ep11_data->ep11_lib_version.minor); +- + memset(&qv, 0, sizeof(qv)); +- qv.ep11_data = ep11_data; ++ qv.target_info = target_info; + qv.first = TRUE; + + rc = handle_all_ep11_cards(&ep11_data->target_list, version_query_handler, +@@ -11169,18 +11262,18 @@ static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata) + return CKR_DEVICE_ERROR; + } + +- memcpy(ep11_data->serialNumber, qv.serialNumber, +- sizeof(ep11_data->serialNumber)); ++ memcpy(target_info->serialNumber, qv.serialNumber, ++ sizeof(target_info->serialNumber)); + +- TRACE_INFO("%s Serial number: %.16s\n", __func__, ep11_data->serialNumber); ++ TRACE_INFO("%s Serial number: %.16s\n", __func__, target_info->serialNumber); + + /* EP11 host lib version <= 2 only support API version 2 */ + if (ep11_data->ep11_lib_version.major <= 2) +- ep11_data->used_firmware_API_version = 2; ++ target_info->used_firmware_API_version = 2; + else +- ep11_data->used_firmware_API_version = 0; ++ target_info->used_firmware_API_version = 0; + +- card_version = ep11_data->card_versions; ++ card_version = target_info->card_versions; + while (card_version != NULL) { + TRACE_INFO("%s Card type: CEX%luP\n", __func__, + card_version->card_type); +@@ -11190,19 +11283,19 @@ static CK_RV ep11tok_get_ep11_version(STDLL_TokData_t *tokdata) + card_version->firmware_version.major, + card_version->firmware_version.minor); + +- if (ep11_data->used_firmware_API_version == 0) +- ep11_data->used_firmware_API_version = ++ if (target_info->used_firmware_API_version == 0) ++ target_info->used_firmware_API_version = + card_version->firmware_API_version; + else +- ep11_data->used_firmware_API_version = +- MIN(ep11_data->used_firmware_API_version, ++ target_info->used_firmware_API_version = ++ MIN(target_info->used_firmware_API_version, + card_version->firmware_API_version); + + card_version = card_version->next; + } + + TRACE_INFO("%s Used Firmware API: %lu\n", __func__, +- ep11_data->used_firmware_API_version); ++ target_info->used_firmware_API_version); + + return CKR_OK; + } +@@ -11220,20 +11313,29 @@ static void free_card_versions(ep11_card_version_t *card_version) + } + } + +-void ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, ++CK_RV ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, + CK_TOKEN_INFO_PTR pInfo) + { + ep11_private_data_t *ep11_data = tokdata->private_data; ++ ep11_target_info_t* target_info; ++ ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; + + /* + * report the EP11 firmware version as hardware version, and + * the EP11 host library version as firmware version + */ +- if (ep11_data->card_versions != NULL) +- pInfo->hardwareVersion = ep11_data->card_versions->firmware_version; ++ if (target_info->card_versions != NULL) ++ pInfo->hardwareVersion = target_info->card_versions->firmware_version; + pInfo->firmwareVersion = ep11_data->ep11_lib_version; +- memcpy(pInfo->serialNumber, ep11_data->serialNumber, ++ memcpy(pInfo->serialNumber, target_info->serialNumber, + sizeof(pInfo->serialNumber)); ++ ++ put_target_info(tokdata, target_info); ++ ++ return CKR_OK; + } + + /** +@@ -11247,13 +11349,17 @@ static int check_required_versions(STDLL_TokData_t *tokdata, + const version_req_t req[], + CK_ULONG num_req) + { +- ep11_private_data_t *ep11_data = tokdata->private_data; + CK_ULONG i, max_card_type = 0, min_card_type = 0xFFFFFFFF; + CK_BBOOL req_not_fullfilled = CK_FALSE; + CK_BBOOL req_fullfilled = CK_FALSE; + ep11_card_version_t *card_version; ++ ep11_target_info_t* target_info; + int status; + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return CKR_FUNCTION_FAILED; ++ + for (i = 0; i < num_req; i++) { + status = check_card_version(tokdata, req[i].card_type, + req[i].min_lib_version, +@@ -11268,7 +11374,7 @@ static int check_required_versions(STDLL_TokData_t *tokdata, + } + + /* Are card types < min_card_type present? */ +- card_version = ep11_data->card_versions; ++ card_version = target_info->card_versions; + while (card_version != NULL) { + if (card_version->card_type < min_card_type) + req_not_fullfilled = CK_TRUE; +@@ -11276,7 +11382,7 @@ static int check_required_versions(STDLL_TokData_t *tokdata, + } + + /* Are card types > max_card_type present? */ +- card_version = ep11_data->card_versions; ++ card_version = target_info->card_versions; + while (card_version != NULL) { + if (card_version->card_type > max_card_type) { + /* +@@ -11285,9 +11391,10 @@ static int check_required_versions(STDLL_TokData_t *tokdata, + * So all others must also meet the version requirements or be + * not present. + */ ++ status = 1; + if (req_not_fullfilled == CK_TRUE) +- return -1; +- return 1; ++ status = -1; ++ goto out; + } + card_version = card_version->next; + } +@@ -11298,13 +11405,19 @@ static int check_required_versions(STDLL_TokData_t *tokdata, + * At least one don't meet the requirements, so all other must not + * fulfill the requirements, too, or are not present. + */ ++ status = 0; + if (req_fullfilled == CK_TRUE) +- return -1; +- return 0; ++ status = -1; ++ goto out; + } else { + /* All of the cards that are present fulfill the requirements */ +- return 1; ++ status = 1; ++ goto out; + } ++ ++out: ++ put_target_info(tokdata, target_info); ++ return status; + } + + /** +@@ -11320,6 +11433,8 @@ static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, + { + ep11_private_data_t *ep11_data = tokdata->private_data; + ep11_card_version_t *card_version; ++ ep11_target_info_t* target_info; ++ int status = 1; + + TRACE_DEBUG("%s checking versions for CEX%luP cards.\n", __func__, card_type); + +@@ -11331,21 +11446,28 @@ static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, + } + } + +- card_version = ep11_data->card_versions; ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) ++ return -1; ++ ++ card_version = target_info->card_versions; + while (card_version != NULL) { + if (card_version->card_type == card_type) + break; + card_version = card_version->next; + } + +- if (card_version == NULL) +- return -1; ++ if (card_version == NULL) { ++ status = -1; ++ goto out; ++ } + + if (firmware_version != NULL) { + if (compare_ck_version(&card_version->firmware_version, + firmware_version) < 0) { + TRACE_DEBUG("%s firmware_version is less than required\n", __func__); +- return 0; ++ status = 0; ++ goto out; + } + } + +@@ -11353,53 +11475,57 @@ static int check_card_version(STDLL_TokData_t *tokdata, CK_ULONG card_type, + if (card_version->firmware_API_version < *firmware_API_version) { + TRACE_DEBUG("%s firmware_API_version is less than required\n", + __func__); +- return 0; ++ status = 0; ++ goto out; + } + } + +- return 1; ++ out: ++ put_target_info(tokdata, target_info); ++ return status; + } + +-static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata) ++static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata, ++ ep11_target_info_t *target_info) + { + ep11_private_data_t *ep11_data = tokdata->private_data; + struct XCP_Module module; +- CK_RV rc; ++ CK_RV rc = CKR_OK; + short i; + + if (dll_m_add_module == NULL) { + TRACE_WARNING("%s Function dll_m_add_module is not available, falling " + "back to old target handling\n", __func__); + +- if (ep11_data->used_firmware_API_version > 2) { ++ if (target_info->used_firmware_API_version > 2) { + TRACE_ERROR("%s selecting an API version is not possible with old " + "target handling\n", __func__); + return CKR_FUNCTION_FAILED; + } + +- ep11_data->target = (target_t)&ep11_data->target_list; ++ target_info->target = (target_t)&ep11_data->target_list; + return CKR_OK; + } + +- if (ep11_data->used_firmware_API_version > 2 && ++ if (target_info->used_firmware_API_version > 2 && + ep11_data->ep11_lib_version.major < 3) { + TRACE_ERROR("%s selecting an API version is not possible with an EP11" + " host library version < 3.0\n", __func__); + return CKR_FUNCTION_FAILED; + } + +- ep11_data->target = XCP_TGT_INIT; ++ target_info->target = XCP_TGT_INIT; + memset(&module, 0, sizeof(module)); + module.version = ep11_data->ep11_lib_version.major >= 3 ? XCP_MOD_VERSION_2 + : XCP_MOD_VERSION_1; + module.flags = XCP_MFL_VIRTUAL | XCP_MFL_MODULE; +- module.api = ep11_data->used_firmware_API_version; ++ module.api = target_info->used_firmware_API_version; + + TRACE_DEVEL("%s XCP_MOD_VERSION: %u\n", __func__, module.version); + + if (ep11_data->target_list.length == 0) { + /* APQN_ANY: Create an empty module group */ +- rc = dll_m_add_module(&module, &ep11_data->target); ++ rc = dll_m_add_module(&module, &target_info->target); + if (rc != CKR_OK) { + TRACE_ERROR("%s dll_m_add_module (ANY) failed: rc=%ld\n", + __func__, rc); +@@ -11414,11 +11540,12 @@ static CK_RV ep11tok_setup_target(STDLL_TokData_t *tokdata) + XCPTGTMASK_SET_DOM(module.domainmask, + ep11_data->target_list.apqns[2 * i + 1]); + +- rc = dll_m_add_module(&module, &ep11_data->target); ++ rc = dll_m_add_module(&module, &target_info->target); + if (rc != CKR_OK) { + TRACE_ERROR("%s dll_m_add_module (%02x.%04x) failed: rc=%ld\n", + __func__, ep11_data->target_list.apqns[2 * i], + ep11_data->target_list.apqns[2 * i + 1], rc); ++ dll_m_rm_module(NULL, target_info->target); + return CKR_FUNCTION_FAILED; + } + } +@@ -11494,6 +11621,7 @@ CK_RV token_specific_set_attribute_values(STDLL_TokData_t *tokdata, OBJECT *obj, + CK_ULONG num_attributes = 0; + CK_ATTRIBUTE *attr; + CK_RV rc; ++ ep11_target_info_t* target_info; + + rc = template_attribute_get_ulong(obj->template, CKA_CLASS, &class); + if (rc != CKR_OK) { +@@ -11575,9 +11703,18 @@ CK_RV token_specific_set_attribute_values(STDLL_TokData_t *tokdata, OBJECT *obj, + goto out; + } + ++ target_info = get_target_info(tokdata); ++ if (target_info == NULL) { ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ + rc = dll_m_SetAttributeValue(ibm_opaque_attr->pValue, + ibm_opaque_attr->ulValueLen, attributes, +- num_attributes, ep11_data->target); ++ num_attributes, target_info->target); ++ ++ put_target_info(tokdata, target_info); ++ + if (rc != CKR_OK) { + rc = ep11_error_to_pkcs11_error(rc, NULL); + TRACE_ERROR("%s m_SetAttributeValue failed rc=0x%lx\n", +@@ -11601,3 +11738,233 @@ out: + return rc; + } + ++/* ++ * ATTENTION: This function is called in a separate thread. All actions ++ * performed by this function must be thread save and use locks to lock ++ * against concurrent access by other threads. ++ */ ++static CK_RV ep11tok_handle_apqn_event(STDLL_TokData_t *tokdata, ++ unsigned int event_type, ++ event_udev_apqn_data_t *apqn_data) ++{ ++ ep11_private_data_t *ep11_data = tokdata->private_data; ++ CK_BBOOL found = FALSE; ++ CK_RV rc = CKR_OK; ++ char name[20]; ++ int i; ++ ++ /* Is it one of the configured APQNs ?*/ ++ if (ep11_data->target_list.length > 0) { ++ /* APQN_WHITELIST is specified */ ++ for (i = 0; i < ep11_data->target_list.length; i++) { ++ if (ep11_data->target_list.apqns[2 * i] == apqn_data->card && ++ ep11_data->target_list.apqns[2 * i + 1] == apqn_data->domain) { ++ found = TRUE; ++ break; ++ } ++ } ++ } else { ++ /* APQN_ANY is specified */ ++ found = TRUE; ++ if (event_type == EVENT_TYPE_APQN_ADD) { ++ snprintf(name, sizeof(name), "card%02x", apqn_data->card); ++ if (is_card_ep11_and_online(name) != CKR_OK) ++ found = FALSE; /* Not an EP11 APQN */ ++ } ++ } ++ if (!found) ++ return CKR_OK; ++ ++ TRACE_DEVEL("%s Refreshing target infos due to event for APQN %02x.%04x\n", ++ __func__, apqn_data->card, apqn_data->domain); ++ ++ rc = refresh_target_info(tokdata); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s Failed to get the target infos (refresh_target_info " ++ "rc=0x%lx)\n", __func__, rc); ++ OCK_SYSLOG(LOG_ERR, "%s: Failed to get the target info rc=0x%lx\n", ++ __func__, rc); ++ return rc; ++ } ++ ++ return CKR_OK; ++} ++ ++/* ++ * Called by the event thread, on receipt of an event. ++ * ++ * ATTENTION: This function is called in a separate thread. All actions ++ * performed by this function must be thread save and use locks to lock ++ * against concurrent access by other threads. ++ */ ++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) ++{ ++ UNUSED(event_flags); ++ ++ switch (event_type) { ++ case EVENT_TYPE_APQN_ADD: ++ case EVENT_TYPE_APQN_REMOVE: ++ if (payload_len != sizeof(event_udev_apqn_data_t)) ++ return CKR_FUNCTION_FAILED; ++ return ep11tok_handle_apqn_event(tokdata, event_type, ++ (event_udev_apqn_data_t *)payload); ++ ++ default: ++ return CKR_FUNCTION_NOT_SUPPORTED; ++ } ++ ++ return CKR_OK; ++} ++ ++/* ++ * Refreshes the target info using the currently configured and available ++ * APQNs. Registers the newly allocated target info as the current one in a ++ * thread save way and gives back the previous one so that it is release when ++ * no longer used (i.e. by a concurrently running thread). ++ */ ++static CK_RV refresh_target_info(STDLL_TokData_t *tokdata) ++{ ++ ep11_private_data_t *ep11_data = tokdata->private_data; ++ volatile ep11_target_info_t *prev_info; ++ ep11_target_info_t *target_info; ++ CK_RV rc; ++ ++ target_info = calloc(1, sizeof(ep11_target_info_t)); ++ if (target_info == NULL) { ++ TRACE_ERROR("%s Memory allocation failed\n", __func__); ++ return CKR_HOST_MEMORY; ++ } ++ ++ target_info->ref_count = 1; ++ ++ /* Get the version info freshly with the current set of APQNs */ ++ rc = ep11tok_get_ep11_version(tokdata, target_info); ++ if (rc != 0) ++ goto error; ++ ++ /* Get the control points freshly with the current set of APQNs */ ++ target_info->control_points_len = sizeof(target_info->control_points); ++ rc = get_control_points(tokdata, target_info->control_points, ++ &target_info->control_points_len, ++ &target_info->max_control_point_index); ++ if (rc != 0) ++ goto error; ++ ++ /* Setup the group target freshly with the current set of APQNs */ ++ rc = ep11tok_setup_target(tokdata, target_info); ++ if (rc != CKR_OK) ++ goto error; ++ ++ /* Set the new one as the current one (locked against concurrent get's) */ ++ if (pthread_rwlock_wrlock(&ep11_data->target_rwlock) != 0) { ++ TRACE_DEVEL("Target Write-Lock failed.\n"); ++ rc = CKR_CANT_LOCK; ++ goto error; ++ } ++ ++ prev_info = ep11_data->target_info; ++ ep11_data->target_info = target_info; ++ ++ if (pthread_rwlock_unlock(&ep11_data->target_rwlock) != 0) { ++ TRACE_DEVEL("Target Unlock failed.\n"); ++ return CKR_CANT_LOCK; ++ } ++ ++ /* Release the previous one */ ++ if (prev_info != NULL) ++ put_target_info(tokdata, (ep11_target_info_t *)prev_info); ++ ++ return CKR_OK; ++ ++error: ++ free_card_versions(target_info->card_versions); ++ free((void *)target_info); ++ return rc; ++} ++ ++/* ++ * Get the current EP11 target info. ++ * Do NOT use the ep11_data->target_info directly, always get a copy using ++ * this function. This will increment the reference count of the target info, ++ * and return the current target info in a thread save way. ++ * When no longer needed, put it back using put_target_info(). ++ */ ++static ep11_target_info_t *get_target_info(STDLL_TokData_t *tokdata) ++{ ++ ep11_private_data_t *ep11_data = tokdata->private_data; ++ volatile ep11_target_info_t *target_info; ++#ifdef DEBUG ++ unsigned long ref_count; ++#endif ++ ++ /* ++ * Lock until we have obtained the current target info and have ++ * increased the reference counter ++ */ ++ if (pthread_rwlock_rdlock(&ep11_data->target_rwlock) != 0) { ++ TRACE_DEVEL("Target Read-Lock failed.\n"); ++ return NULL; ++ } ++ ++ target_info = *((void * volatile *)&ep11_data->target_info); ++ if (target_info == NULL) { ++ TRACE_ERROR("%s: target_info is NULL\n", __func__); ++ return NULL; ++ } ++ ++#ifdef DEBUG ++ ref_count = __sync_add_and_fetch(&target_info->ref_count, 1); ++ ++ TRACE_DEBUG("%s: target_info: %p ref_count: %lu\n", __func__, ++ (void *)target_info, ref_count); ++#else ++ __sync_add_and_fetch(&target_info->ref_count, 1); ++#endif ++ ++ if (pthread_rwlock_unlock(&ep11_data->target_rwlock) != 0) { ++ TRACE_DEVEL("Target Unlock failed.\n"); ++ return NULL; ++ } ++ ++ return (ep11_target_info_t *)target_info; ++} ++ ++/* ++ * Give back an EP11 target info. This will decrement the reference count, ++ * and will free it if the reference count reaches zero. ++ */ ++static void put_target_info(STDLL_TokData_t *tokdata, ++ ep11_target_info_t *target_info) ++{ ++ ep11_private_data_t *ep11_data = tokdata->private_data; ++ unsigned long ref_count; ++ ++ if (target_info == NULL) ++ return; ++ ++ if (target_info->ref_count > 0) { ++ ref_count = __sync_sub_and_fetch(&target_info->ref_count, 1); ++ ++ TRACE_DEBUG("%s: target_info: %p ref_count: %lu\n", __func__, ++ (void *)target_info, ref_count); ++ } else { ++ TRACE_WARNING("%s: target_info: %p ref_count already 0.\n", __func__, ++ (void *)target_info); ++ ref_count = 0; ++ } ++ ++ if (ref_count == 0 && target_info != ep11_data->target_info) { ++ TRACE_DEBUG("%s: target_info: %p is freed\n", __func__, ++ (void *)target_info); ++ ++ if (dll_m_rm_module != NULL) ++ dll_m_rm_module(NULL, target_info->target); ++ free_card_versions(target_info->card_versions); ++ free(target_info); ++ } ++} ++ +diff --git a/usr/lib/ep11_stdll/ep11_specific.h b/usr/lib/ep11_stdll/ep11_specific.h +index 55fc023c..343f4b3d 100644 +--- a/usr/lib/ep11_stdll/ep11_specific.h ++++ b/usr/lib/ep11_stdll/ep11_specific.h +@@ -161,7 +161,7 @@ CK_BBOOL ep11tok_libica_mech_available(STDLL_TokData_t *tokdata, + CK_MECHANISM_TYPE mech, + CK_OBJECT_HANDLE hKey); + +-void ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, ++CK_RV ep11tok_copy_firmware_info(STDLL_TokData_t *tokdata, + CK_TOKEN_INFO_PTR pInfo); + + CK_BBOOL ep11tok_pkey_usage_ok(STDLL_TokData_t *tokdata, SESSION *session, +diff --git a/usr/lib/ep11_stdll/new_host.c b/usr/lib/ep11_stdll/new_host.c +index 4e592363..cd12604e 100644 +--- a/usr/lib/ep11_stdll/new_host.c ++++ b/usr/lib/ep11_stdll/new_host.c +@@ -298,7 +298,7 @@ CK_RV SC_GetTokenInfo(STDLL_TokData_t *tokdata, CK_SLOT_ID sid, + goto done; + } + copy_token_contents_sensibly(pInfo, tokdata->nv_token_data); +- ep11tok_copy_firmware_info(tokdata, pInfo); ++ rc = ep11tok_copy_firmware_info(tokdata, pInfo); + + /* Set the time */ + now = time((time_t *) NULL); +diff --git a/usr/lib/ep11_stdll/tok_struct.h b/usr/lib/ep11_stdll/tok_struct.h +index 2c0af9cf..01268c67 100644 +--- a/usr/lib/ep11_stdll/tok_struct.h ++++ b/usr/lib/ep11_stdll/tok_struct.h +@@ -137,7 +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 ++ &token_specific_handle_event, + }; + + #endif diff --git a/opencryptoki-3.16.0-342dfbeb8275f5ea6ed52dd3f30126614ec1d037.patch b/opencryptoki-3.16.0-342dfbeb8275f5ea6ed52dd3f30126614ec1d037.patch new file mode 100644 index 0000000..76ce00d --- /dev/null +++ b/opencryptoki-3.16.0-342dfbeb8275f5ea6ed52dd3f30126614ec1d037.patch @@ -0,0 +1,2159 @@ +commit 342dfbeb8275f5ea6ed52dd3f30126614ec1d037 +Author: Ingo Franzki +Date: Mon Feb 15 14:33:07 2021 +0100 + + Event support: pkcsslotd changes + + Signed-off-by: Ingo Franzki + +diff --git a/configure.ac b/configure.ac +index e0ae4a82..a0b098e1 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -234,6 +234,12 @@ AC_ARG_WITH([systemd], + AS_HELP_STRING([--with-systemd@<:@=DIR@:>@],[systemd system unit files location]), + [], + [with_systemd=no]) ++ ++dnl --- libudev development files ++AC_ARG_WITH([libudev], ++ AS_HELP_STRING([--with-libudev@<:@=DIR@:>@],[libudev development files location]), ++ [], ++ [with_libudev=check]) + + dnl --- + dnl --- +@@ -438,6 +444,46 @@ fi + AC_SUBST([XCRYPTOLINZ_CFLAGS]) + AC_SUBST([XCRYPTOLINZ_LIBS]) + ++dnl --- with_libudev ++LIBUDEV_CFLAGS= ++LIBUDEV_LIBS= ++if test "x$with_libudev" != "xno"; then ++ if test "x$with_libudev" != "xyes" -a "x$with_libudev" != "xcheck"; then ++ LIBUDEV_CFLAGS="-I$with_libudev" ++ LIBUDEV_LIBS="-L$with_libudev" ++ fi ++ old_cflags="$CFLAGS" ++ old_libs="$LIBS" ++ CFLAGS="$CFLAGS $LIBUDEV_CFLAGS" ++ LIBS="$LIBS $LIBUDEV_LIBS" ++ # Use libudev only on s390 platforms, only s390 emits AP related uevents ++ case $target in ++ *s390x* | *s390*) ++ CFLAGS="$CFLAGS -DWITH_LIBUDEV" ++ ;; ++ *) ++ if test "x$with_libudev" != "xyes"; then ++ with_libudev=no ++ echo "Default to 'with_libudev=no' on non-s390 platforms" ++ fi ++ ;; ++ esac ++ if test "x$with_libudev" != "xno"; then ++ AC_CHECK_HEADER([libudev.h], [with_libudev=yes], [ ++ AC_MSG_ERROR([Build with libudev requested but libudev headers couldn't be found]) ++ ]) ++ AC_CHECK_LIB([udev], [udev_monitor_new_from_netlink], [with_libudev=yes], [ ++ AC_MSG_ERROR([Build with libudev requested but libudev libraries couldn't be found]) ++ ]) ++ fi ++ if test "x$with_libudev" = "xno"; then ++ CFLAGS="$old_cflags" ++ LIBS="$old_libs" ++ fi ++fi ++AC_SUBST([LIBUDEV_CFLAGS]) ++AC_SUBST([LIBUDEV_LIBS]) ++AM_CONDITIONAL([HAVE_LIBUDEV], [test "x$with_libudev" = "xyes"]) + + dnl --- + dnl --- Now check enabled features, while making sure every required +@@ -649,6 +695,7 @@ echo " Daemon build: $enable_daemon" + echo " Library build: $enable_library" + echo " Systemd service: $enable_systemd" + echo " Build with locks: $enable_locks" ++echo " Build with libudev: $with_libudev" + echo " Build p11sak tool: $enable_p11sak" + echo " token migrate tool: $enable_pkcstok_migrate" + echo +diff --git a/usr/include/slotmgr.h b/usr/include/slotmgr.h +index 4d038435..e37368a5 100644 +--- a/usr/include/slotmgr.h ++++ b/usr/include/slotmgr.h +@@ -31,6 +31,7 @@ + #define OCK_API_LOCK_FILE LOCKDIR_PATH "/LCK..APIlock" + + #define PROC_SOCKET_FILE_PATH "/var/run/pkcsslotd.socket" ++#define ADMIN_SOCKET_FILE_PATH "/var/run/pkcsslotd.admin.socket" + + #define PID_FILE_PATH "/var/run/pkcsslotd.pid" + #define OCK_CONFIG OCK_CONFDIR "/opencryptoki.conf" +@@ -45,6 +46,7 @@ + + #define NUMBER_SLOTS_MANAGED 1024 + #define NUMBER_PROCESSES_ALLOWED 1000 ++#define NUMBER_ADMINS_ALLOWED 1000 + + // + // Per Process Data structure +diff --git a/usr/sbin/pkcsslotd/pkcsslotd.h b/usr/sbin/pkcsslotd/pkcsslotd.h +index 69eb59f3..d7edcb3c 100644 +--- a/usr/sbin/pkcsslotd/pkcsslotd.h ++++ b/usr/sbin/pkcsslotd/pkcsslotd.h +@@ -92,5 +92,8 @@ int init_socket_server(); + int term_socket_server(); + int init_socket_data(Slot_Mgr_Socket_t *sp); + int socket_connection_handler(int timeout_secs); ++#ifdef DEV ++void dump_socket_handler(); ++#endif + + #endif /* _SLOTMGR_H */ +diff --git a/usr/sbin/pkcsslotd/pkcsslotd.mk b/usr/sbin/pkcsslotd/pkcsslotd.mk +index 2d36b4a9..c574edf8 100644 +--- a/usr/sbin/pkcsslotd/pkcsslotd.mk ++++ b/usr/sbin/pkcsslotd/pkcsslotd.mk +@@ -8,6 +8,9 @@ CLEANFILES += usr/lib/common/parser.c usr/lib/common/parser.h \ + usr/lib/common/parser.output usr/lib/common/lexer.c + + usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS = -lpthread -lcrypto ++if HAVE_LIBUDEV ++usr_sbin_pkcsslotd_pkcsslotd_LDFLAGS += -ludev ++endif + + usr_sbin_pkcsslotd_pkcsslotd_CFLAGS = -DPROGRAM_NAME=\"$(@)\" \ + -I${srcdir}/usr/include -I${srcdir}/usr/lib/common \ +diff --git a/usr/sbin/pkcsslotd/signal.c b/usr/sbin/pkcsslotd/signal.c +index 49482a2f..17167632 100644 +--- a/usr/sbin/pkcsslotd/signal.c ++++ b/usr/sbin/pkcsslotd/signal.c +@@ -21,7 +21,7 @@ + extern BOOL IsValidProcessEntry(pid_t_64 pid, time_t_64 RegTime); + + static int SigsToIntercept[] = { +- SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, ++ SIGHUP, SIGINT, SIGQUIT, SIGALRM, + SIGTERM, SIGTSTP, SIGTTIN, + SIGTTOU, SIGUSR1, SIGUSR2, SIGPROF + }; +@@ -32,8 +32,11 @@ static int SigsToIntercept[] = { + /* SIGCHLD - Don't want to exit. Should never receive, but we do, apparently + * when something tries to cancel the GC Thread */ + ++/* SIGPIPE - Don't want to exit. May happen when a connection to an admin ++ * event sender or a process is closed before all events are delivered. */ ++ + static int SigsToIgnore[] = { +- SIGCHLD, ++ SIGCHLD, SIGPIPE, + }; + + +@@ -71,6 +74,10 @@ void slotdGenericSignalHandler(int Signal) + CheckForGarbage(shmp); + #endif + ++#ifdef DEV ++ dump_socket_handler(); ++#endif ++ + for (procindex = 0; (procindex < NUMBER_PROCESSES_ALLOWED); procindex++) { + + Slot_Mgr_Proc_t_64 *pProc = &(shmp->proc_table[procindex]); +diff --git a/usr/sbin/pkcsslotd/socket_server.c b/usr/sbin/pkcsslotd/socket_server.c +index 1fae0b95..41408670 100644 +--- a/usr/sbin/pkcsslotd/socket_server.c ++++ b/usr/sbin/pkcsslotd/socket_server.c +@@ -1,4 +1,6 @@ + /* ++ * COPYRIGHT (c) International Business Machines Corp. 2013, 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 +@@ -12,6 +14,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -19,32 +23,1225 @@ + #include + #include + #include ++#include ++ ++#if defined(__GNUC__) && __GNUC__ >= 7 || defined(__clang__) && __clang_major__ >= 12 ++ #define FALL_THROUGH __attribute__ ((fallthrough)) ++#else ++ #define FALL_THROUGH ((void)0) ++#endif ++ ++#ifdef WITH_LIBUDEV ++#include ++#endif + + #include "log.h" + #include "slotmgr.h" + #include "pkcsslotd.h" + #include "apictl.h" ++#include "dlist.h" ++#include "events.h" ++ ++#define MAX_EPOLL_EVENTS 128 ++ ++#ifdef WITH_LIBUDEV ++#define UDEV_RECV_BUFFFER_SIZE 512 * 1024 ++#define UDEV_SUBSYSTEM_AP "ap" ++#define UDEV_ACTION_BIND "bind" ++#define UDEV_ACTION_UNBIND "unbind" ++#define UDEV_ACTION_DEVTYPE_APQN "ap_queue" ++#define UDEV_PROERTY_DEVTYPE "DEV_TYPE" ++#endif ++ ++struct epoll_info { ++ int (* notify)(int events, void *private); ++ void (* free)(void *private); ++ void *private; ++ unsigned long ref_count; ++}; ++ ++struct listener_info { ++ int socket; ++ const char *file_path; ++ int (* new_conn)(int socket, struct listener_info *listener); ++ struct epoll_info ep_info; ++ unsigned long num_clients; ++ unsigned long max_num_clients; ++}; ++ ++enum xfer_state { ++ XFER_IDLE = 0, ++ XFER_RECEIVE = 1, ++ XFER_SEND = 2, ++}; ++ ++struct client_info { ++ int socket; ++ int (* xfer_complete)(void *client); ++ void (* hangup)(void *client); ++ void (* free)(void *client); ++ void *client; ++ struct epoll_info ep_info; ++ enum xfer_state xfer_state; ++ char *xfer_buffer; ++ size_t xfer_size; ++ size_t xfer_offset; ++}; ++ ++enum proc_state { ++ PROC_INITIAL_SEND = 0, ++ PROC_WAIT_FOR_EVENT = 1, ++ PROC_SEND_EVENT = 2, ++ PROC_SEND_PAYLOAD = 3, ++ PROC_RECEIVE_REPLY = 4, ++ PROC_HANGUP = 5, ++}; ++ ++struct proc_conn_info { ++ struct client_info client_info; ++ enum proc_state state; ++ DL_NODE *events; ++ struct event_info *event; ++ event_reply_t reply; ++}; ++ ++enum admin_state { ++ ADMIN_RECEIVE_EVENT = 0, ++ ADMIN_RECEIVE_PAYLOAD = 1, ++ ADMIN_EVENT_DELIVERED = 2, ++ ADMIN_SEND_REPLY = 3, ++ ADMIN_WAIT_FOR_EVENT_LIMIT = 4, ++ ADMIN_HANGUP = 5, ++}; ++ ++struct admin_conn_info { ++ struct client_info client_info; ++ enum admin_state state; ++ struct event_info *event; ++}; ++ ++#ifdef WITH_LIBUDEV ++struct udev_mon { ++ struct udev *udev; ++ struct udev_monitor *mon; ++ int socket; ++ struct epoll_info ep_info; ++ struct event_info *delayed_event; ++}; ++#endif ++ ++struct event_info { ++ event_msg_t event; ++ char *payload; ++ event_reply_t reply; ++ unsigned long proc_ref_count; /* # of processes using this event */ ++ struct admin_conn_info *admin_ref; /* Admin connection to send reply back */ ++}; ++ ++static int epoll_fd = -1; ++static struct listener_info proc_listener; ++static DL_NODE *proc_connections = NULL; ++static struct listener_info admin_listener; ++static DL_NODE *admin_connections = NULL; ++#ifdef WITH_LIBUDEV ++static struct udev_mon udev_mon; ++#endif ++static DL_NODE *pending_events = NULL; ++static unsigned long pending_events_count = 0; ++ ++#define MAX_PENDING_EVENTS 1024 ++ ++/* ++ * Iterate over all connections in a safe way. Before actually iterating, ++ * increment the ref count of ALL connections, because any processing may ++ * cause any of the connections to be hang-up, and thus freed and removed ++ * from the list. We need to make sure that while we are iterating over the ++ * connections, none of them gets removed from the list. ++ */ ++#define FOR_EACH_CONN_SAFE_BEGIN(list, conn) { \ ++ DL_NODE *_node, *_next; \ ++ _node = dlist_get_first(list); \ ++ while (_node != NULL) { \ ++ conn = _node->data; \ ++ _next = dlist_next(_node); \ ++ client_socket_get(&(conn)->client_info); \ ++ _node = _next; \ ++ } \ ++ _node = dlist_get_first(list); \ ++ while (_node != NULL) { \ ++ conn = _node->data; \ ++ _next = dlist_next(_node); ++ ++#define FOR_EACH_CONN_SAFE_END(list, conn) \ ++ _node = _next; \ ++ } \ ++ _node = dlist_get_first(list); \ ++ while (_node != NULL) { \ ++ conn = _node->data; \ ++ _next = dlist_next(_node); \ ++ client_socket_put(&(conn)->client_info); \ ++ _node = _next; \ ++ } \ ++ } ++ ++ ++ ++static void listener_socket_close(int socketfd, const char *file_path); ++static int listener_client_hangup(struct listener_info *listener); ++static void event_delivered(struct event_info *event); ++static int client_socket_notify(int events, void *private); ++static void client_socket_free(void *private); ++static int proc_xfer_complete(void *client); ++static int proc_start_deliver_event(struct proc_conn_info *conn); ++static int proc_deliver_event(struct proc_conn_info *conn, ++ struct event_info *event); ++static int proc_event_delivered(struct proc_conn_info *conn, ++ struct event_info *event); ++static inline void proc_get(struct proc_conn_info *conn); ++static inline void proc_put(struct proc_conn_info *conn); ++static void proc_hangup(void *client); ++static void proc_free(void *client); ++static int admin_xfer_complete(void *client); ++static void admin_event_limit_underrun(struct admin_conn_info *conn); ++static int admin_event_delivered(struct admin_conn_info *conn, ++ struct event_info *event); ++static inline void admin_get(struct admin_conn_info *conn); ++static inline void admin_put(struct admin_conn_info *conn); ++static void admin_hangup(void *client); ++static void admin_free(void *client); ++#ifdef WITH_LIBUDEV ++static void udev_mon_term(struct udev_mon *udev_mon); ++static int udev_mon_notify(int events, void *private); ++#endif ++ ++static void epoll_info_init(struct epoll_info *epoll_info, ++ int (* notify)(int events, void *private), ++ void (* free_cb)(void *private), ++ void *private) ++{ ++ epoll_info->ref_count = 1; ++ epoll_info->notify = notify; ++ epoll_info->free = free_cb; ++ epoll_info->private = private; ++} ++ ++static void epoll_info_get(struct epoll_info *epoll_info) ++{ ++ epoll_info->ref_count++; ++ ++ DbgLog(DL3, "%s: private: %p, ref_count: %lu", __func__, ++ epoll_info->private, epoll_info->ref_count); ++} ++ ++static void epoll_info_put(struct epoll_info *epoll_info) ++{ ++ if (epoll_info->ref_count > 0) ++ epoll_info->ref_count--; ++ ++ DbgLog(DL3, "%s: private: %p, ref_count: %lu", __func__, ++ epoll_info->private, epoll_info->ref_count); ++ ++ if (epoll_info->ref_count == 0 && epoll_info->free != NULL) ++ epoll_info->free(epoll_info->private); ++} ++ ++static int client_socket_init(int socket, int (* xfer_complete)(void *client), ++ void (* hangup)(void *client), ++ void (* free_cb)(void *client), void *client, ++ struct client_info *client_info) ++{ ++ struct epoll_event evt; ++ int rc, err; ++ ++ if (xfer_complete == NULL || hangup == NULL) ++ return -EINVAL; ++ ++ epoll_info_init(&client_info->ep_info, client_socket_notify, ++ client_socket_free, client_info); ++ client_info->socket = socket; ++ client_info->xfer_complete = xfer_complete; ++ client_info->hangup = hangup; ++ client_info->free = free_cb; ++ client_info->client = client; ++ client_info->xfer_state = XFER_IDLE; ++ ++ rc = fcntl(socket, F_SETFL, O_NONBLOCK); ++ if (rc < 0) { ++ err = errno; ++ InfoLog("%s: Failed to set client socket %d to non-blocking, errno " ++ "%d (%s).", __func__, socket, err, strerror(err)); ++ return -err; ++ } ++ ++ evt.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLERR | EPOLLET; ++ evt.data.ptr = &client_info->ep_info; ++ rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, socket, &evt); ++ if (rc != 0) { ++ err = errno; ++ InfoLog("%s: Failed to add client socket %d to epoll, errno %d (%s).", ++ __func__, socket, err, strerror(err)); ++ close(socket); ++ return -err; ++ } ++ ++ return 0; ++} ++ ++static inline void client_socket_get(struct client_info *client_info) ++{ ++ epoll_info_get(&client_info->ep_info); ++} ++ ++static inline void client_socket_put(struct client_info *client_info) ++{ ++ epoll_info_put(&client_info->ep_info); ++} ++ ++static void client_socket_term(struct client_info *client_info) ++{ ++ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_info->socket, NULL); ++ close(client_info->socket); ++ client_info->socket = -1; ++} ++ ++static int client_socket_notify(int events, void *private) ++{ ++ struct client_info *client_info = private; ++ ssize_t num; ++ int rc, err, socket = client_info->socket; ++ ++ DbgLog(DL3, "%s: Epoll event on client %p socket %d: events: 0x%x xfer: %d", ++ __func__, client_info, socket, events, client_info->xfer_state); ++ ++ if (socket < 0) ++ return -ENOTCONN; ++ ++ if (events & (EPOLLHUP | EPOLLERR)) { ++ DbgLog(DL3, "EPOLLHUP | EPOLLERR"); ++ ++ client_info->hangup(client_info->client); ++ client_info = NULL; /* client_info may have been freed by now */ ++ return 0; ++ } ++ ++ if (client_info->xfer_state == XFER_RECEIVE && (events & EPOLLIN)) { ++ DbgLog(DL3, "%s: EPOLLIN: buffer: %p size: %lu ofs: %lu", __func__, ++ client_info->xfer_buffer, client_info->xfer_size, ++ client_info->xfer_offset); ++ ++ num = read(client_info->socket, ++ client_info->xfer_buffer + client_info->xfer_offset, ++ client_info->xfer_size - client_info->xfer_offset); ++ if (num <= 0) { ++ err = errno; ++ ++ DbgLog(DL3, "%s: read failed with: num: %d errno: %d (%s)", ++ __func__, num, num < 0 ? err : 0, ++ num < 0 ? strerror(err) : "none"); ++ ++ if (num < 0 && err == EWOULDBLOCK) ++ return 0; /* Will be continued when socket becomes readable */ ++ ++ /* assume connection closed by peer */ ++ client_info->hangup(client_info->client); ++ client_info = NULL; /* client_info may have been freed by now */ ++ return 0; ++ } else { ++ DbgLog(DL3, "%s: %lu bytes received", __func__, num); ++ ++ client_info->xfer_offset += num; ++ ++ DbgLog(DL3, "%s: %lu bytes left", __func__, ++ client_info->xfer_size - client_info->xfer_offset); ++ ++ if (client_info->xfer_offset >= client_info->xfer_size) { ++ client_info->xfer_state = XFER_IDLE; ++ client_info->xfer_buffer = NULL; ++ client_info->xfer_size = 0; ++ client_info->xfer_offset = 0; ++ ++ client_socket_get(client_info); ++ rc = client_info->xfer_complete(client_info->client); ++ if (rc != 0) { ++ InfoLog("%s: xfer_complete callback failed for client " ++ "socket %d, rc: %d", __func__, socket, ++ rc); ++ client_info->hangup(client_info->client); ++ } ++ client_socket_put(client_info); ++ client_info = NULL; /* client_info may have been freed by now */ ++ return rc; ++ } ++ return 0; ++ } ++ } ++ ++ if (client_info->xfer_state == XFER_SEND && (events & EPOLLOUT)) { ++ DbgLog(DL3, "%s: EPOLLOUT: buffer: %p size: %lu ofs: %lu", __func__, ++ client_info->xfer_buffer, client_info->xfer_size, ++ client_info->xfer_offset); ++ ++ num = write(client_info->socket, ++ client_info->xfer_buffer + client_info->xfer_offset, ++ client_info->xfer_size - client_info->xfer_offset); ++ if (num < 0) { ++ err = errno; ++ ++ DbgLog(DL3, "%s: write failed with: errno: %d (%s)", __func__, err, ++ strerror(err)); ++ ++ if (err == EWOULDBLOCK) ++ return 0; /* Will be continued when socket becomes writable */ ++ ++ /* assume connection closed by peer */ ++ client_info->hangup(client_info->client); ++ client_info = NULL; /* client_info may have been freed by now */ ++ return 0; ++ } else { ++ DbgLog(DL3, "%s: %lu bytes sent", __func__, num); ++ ++ client_info->xfer_offset += num; ++ ++ DbgLog(DL3, "%s: %lu bytes left", __func__, ++ client_info->xfer_size - client_info->xfer_offset); ++ ++ if (client_info->xfer_offset >= client_info->xfer_size) { ++ client_info->xfer_state = XFER_IDLE; ++ client_info->xfer_buffer = NULL; ++ client_info->xfer_size = 0; ++ client_info->xfer_offset = 0; ++ ++ client_socket_get(client_info); ++ rc = client_info->xfer_complete(client_info->client); ++ if (rc != 0) { ++ InfoLog("%s: xfer_complete callback failed for client " ++ "socket %d, rc: %d", __func__, socket, ++ rc); ++ client_info->hangup(client_info->client); ++ } ++ client_socket_put(client_info); ++ client_info = NULL; /* client_info may have been freed by now */ ++ return rc; ++ } ++ return 0; ++ } ++ } ++ ++ return 0; ++} ++ ++static void client_socket_free(void *private) ++{ ++ struct client_info *client_info = private; ++ ++ DbgLog(DL3, "%s: %p", __func__, client_info); ++ ++ if (client_info->free != NULL) ++ client_info->free(client_info->client); ++} ++ ++static int client_socket_receive(struct client_info *client_info, ++ void *buffer, size_t size) ++{ ++ if (client_info->socket < 0) ++ return -ENOTCONN; ++ ++ client_info->xfer_state = XFER_RECEIVE; ++ client_info->xfer_buffer = (char *)buffer; ++ client_info->xfer_size = size; ++ client_info->xfer_offset = 0; ++ ++ DbgLog(DL3, "%s: Start receive on client socket %d: buffer: %p size: %lu", ++ __func__, client_info->socket, buffer, size); ++ ++ return client_socket_notify(EPOLLIN, client_info); ++} ++ ++ ++static int client_socket_send(struct client_info *client_info, ++ void *buffer, size_t size) ++{ ++ if (client_info->socket < 0) ++ return -ENOTCONN; ++ ++ client_info->xfer_state = XFER_SEND; ++ client_info->xfer_buffer = (char *)buffer; ++ client_info->xfer_size = size; ++ client_info->xfer_offset = 0; ++ ++ DbgLog(DL3, "%s: Start send on client socket %d: buffer: %p size: %lu", ++ __func__, client_info->socket, buffer, size); ++ ++ return client_socket_notify(EPOLLOUT, client_info); ++} ++ ++static struct event_info *event_new(unsigned int payload_len, ++ struct admin_conn_info *admin_conn) ++{ ++ struct event_info *event; ++ ++ event = calloc(1, sizeof(struct event_info)); ++ if (event == NULL) { ++ ErrLog("%s: Failed to allocate the event", __func__); ++ return NULL; ++ } ++ ++ event->event.version = EVENT_VERSION_1; ++ event->event.payload_len = payload_len; ++ if (payload_len > 0) { ++ event->payload = malloc(payload_len); ++ if (event->payload == NULL) { ++ ErrLog("%s: Failed to allocate the event payload", __func__); ++ free(event); ++ return NULL; ++ } ++ } ++ ++ event->reply.version = EVENT_VERSION_1; ++ ++ if (admin_conn != NULL) ++ admin_get(admin_conn); ++ event->admin_ref = admin_conn; ++ ++ DbgLog(DL3, "%s: allocated event: %p", __func__, event); ++ return event; ++} ++ ++static void event_limit_underrun() ++{ ++ struct admin_conn_info *conn; ++ ++ DbgLog(DL3, "%s: pending_events_count: %lu", __func__, pending_events_count); ++ ++#ifdef WITH_LIBUDEV ++ /* Notify the udev monitor */ ++ udev_mon_notify(EPOLLIN, &udev_mon); ++#endif ++ ++ /* Notify all admin connections */ ++ FOR_EACH_CONN_SAFE_BEGIN(admin_connections, conn) { ++ admin_event_limit_underrun(conn); ++ } ++ FOR_EACH_CONN_SAFE_END(admin_connections, conn) ++} ++ ++static void event_free(struct event_info *event) ++{ ++ DbgLog(DL3, "%s: free event: %p", __func__, event); ++ ++ if (event->payload != NULL) ++ free(event->payload); ++ free(event); ++} ++ ++static int event_add_to_pending_list(struct event_info *event) ++{ ++ DL_NODE *list; ++ ++ list = dlist_add_as_last(pending_events, event); ++ if (list == NULL) { ++ ErrLog("%s: failed add event to list of pending events", __func__); ++ return -ENOMEM; ++ } ++ pending_events = list; ++ ++ pending_events_count++; ++ ++ return 0; ++} ++ ++static void event_remove_from_pending_list(struct event_info *event) ++{ ++ DL_NODE *node; ++ int trigger = 0; ++ ++ node = dlist_find(pending_events, event); ++ if (node != NULL) { ++ pending_events = dlist_remove_node(pending_events, node); ++ ++ if (pending_events_count >= MAX_PENDING_EVENTS) ++ trigger = 1; ++ ++ if (pending_events_count > 0) ++ pending_events_count--; ++ ++ if (trigger) ++ event_limit_underrun(); ++ } ++} ++ ++static int event_start_deliver(struct event_info *event) ++{ ++ struct proc_conn_info *conn; ++ int rc; ++ ++ DbgLog(DL3, "%s: event: %p", __func__, event); ++ ++ if (pending_events_count >= MAX_PENDING_EVENTS) { ++ InfoLog("%s: Max pending events reached", __func__); ++ return -ENOSPC; ++ } ++ ++ /* Add event of the list of pending events */ ++ rc = event_add_to_pending_list(event); ++ if (rc != 0) ++ return rc; ++ ++ /* ++ * Need to increment the event's ref count here, proc_deliver_event() may ++ * already complete the event delivery for one process, which then would ++ * free the event but it needs to be passed to other processes here, too. ++ */ ++ event->proc_ref_count++; ++ FOR_EACH_CONN_SAFE_BEGIN(proc_connections, conn) { ++ rc = proc_deliver_event(conn, event); ++ if (rc != 0) ++ proc_hangup(conn); ++ } ++ FOR_EACH_CONN_SAFE_END(proc_connections, conn) ++ event->proc_ref_count--; ++ ++ DbgLog(DL3, "%s: proc_ref_count: %u", __func__, event->proc_ref_count); ++ ++ if (event->proc_ref_count == 0) ++ event_delivered(event); ++ ++ return 0; ++} ++ ++static void event_delivered(struct event_info *event) ++{ ++ struct admin_conn_info *conn; ++ int rc; ++ ++ DbgLog(DL3, "%s: event: %p", __func__, event); ++ ++ event_remove_from_pending_list(event); ++ ++ /* Notify owning admin connection (if available), free otherwise */ ++ if (event->admin_ref != NULL) { ++ conn = event->admin_ref; ++ admin_get(conn); ++ rc = admin_event_delivered(conn, event); ++ if (rc != 0) { ++ admin_hangup(conn); ++ event_free(event); ++ } ++ admin_put(conn); ++ } else { ++ event_free(event); ++ } ++} ++ ++static int proc_new_conn(int socket, struct listener_info *listener) ++{ ++ struct proc_conn_info *conn; ++ struct event_info *event; ++ DL_NODE *list, *node; ++ int rc = 0; ++ ++ UNUSED(listener); ++ ++ DbgLog(DL0, "%s: Accepted connection from process: socket: %d", __func__, ++ socket); ++ ++ conn = calloc(1, sizeof(struct proc_conn_info)); ++ if (conn == NULL) { ++ ErrLog("%s: Failed to to allocate memory for the process connection", ++ __func__); ++ return -ENOMEM; ++ /* Caller will close socket */ ++ } ++ ++ DbgLog(DL3, "%s: process conn: %p", __func__, conn); ++ ++ /* Add currently pending events to this connection */ ++ node = dlist_get_first(pending_events); ++ while (node != NULL) { ++ event = (struct event_info *)node->data; ++ DbgLog(DL3, "%s: event: %p", __func__, event); ++ ++ list = dlist_add_as_last(conn->events, event); ++ if (list == NULL) { ++ ErrLog("%s: failed add event to list of process's pending events", ++ __func__); ++ rc = -ENOMEM; ++ goto out; ++ } ++ conn->events = list; ++ ++ event->proc_ref_count++; ++ ++ node = dlist_next(node); ++ } ++ ++ conn->state = PROC_INITIAL_SEND; ++ ++ rc = client_socket_init(socket, proc_xfer_complete, proc_hangup, proc_free, ++ conn, &conn->client_info); ++ if (rc != 0) ++ goto out; ++ ++ /* Add it to the process connections list */ ++ list = dlist_add_as_first(proc_connections, conn); ++ if (list == NULL) { ++ rc = -ENOMEM; ++ goto out; ++ } ++ proc_connections = list; ++ ++ proc_get(conn); ++ rc = client_socket_send(&conn->client_info, &socketData, ++ sizeof(socketData)); ++ proc_put(conn); ++ conn = NULL; /* conn may have been freed by now */ ++ ++out: ++ if (rc != 0 && conn != NULL) { ++ proc_hangup(conn); ++ rc = 0; /* Don't return an error, we have already handled it */ ++ } ++ ++ return rc; ++} ++ ++static int proc_xfer_complete(void *client) ++{ ++ struct proc_conn_info *conn = client; ++ int rc; ++ ++ DbgLog(DL0, "%s: Xfer completed: process: %p socket: %d state: %d", ++ __func__, conn, conn->client_info.socket, conn->state); ++ ++ /* ++ * A non-zero return code returned by this function causes the caller to ++ * call proc_hangup(). Thus, no need to call proc_hangup() ourselves. ++ */ ++ ++ switch (conn->state) { ++ case PROC_INITIAL_SEND: ++ conn->state = PROC_WAIT_FOR_EVENT; ++ rc = proc_start_deliver_event(conn); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++ ++ case PROC_WAIT_FOR_EVENT: ++ /* handled in proc_start_deliver_event */ ++ break; ++ ++ case PROC_SEND_EVENT: ++ if (conn->event == NULL) { ++ TraceLog("%s: No current event to handle", __func__); ++ return -EINVAL; ++ } ++ ++ if (conn->event->event.payload_len > 0) { ++ conn->state = PROC_SEND_PAYLOAD; ++ rc = client_socket_send(&conn->client_info, conn->event->payload, ++ conn->event->event.payload_len); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++ } ++ FALL_THROUGH; ++ /* fall through */ ++ ++ case PROC_SEND_PAYLOAD: ++ if (conn->event == NULL) { ++ TraceLog("%s: No current event to handle", __func__); ++ return -EINVAL; ++ } ++ ++ if (conn->event->event.flags & EVENT_FLAGS_REPLY_REQ) { ++ conn->state = PROC_RECEIVE_REPLY; ++ rc = client_socket_receive(&conn->client_info, &conn->reply, ++ sizeof(conn->reply)); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++ } ++ FALL_THROUGH; ++ /* fall through */ ++ ++ case PROC_RECEIVE_REPLY: ++ if (conn->event == NULL) { ++ TraceLog("%s: No current event to handle", __func__); ++ return -EINVAL; ++ } ++ ++ if (conn->event->event.flags & EVENT_FLAGS_REPLY_REQ) { ++ if (conn->reply.version != EVENT_VERSION_1) { ++ InfoLog("%s: Reply has a wrong version: %u", __func__, ++ conn->reply.version); ++ return -EINVAL; ++ } ++ ++ /* Update reply counters in event */ ++ conn->event->reply.positive_replies += conn->reply.positive_replies; ++ conn->event->reply.negative_replies += conn->reply.negative_replies; ++ conn->event->reply.nothandled_replies += ++ conn->reply.nothandled_replies; ++ } ++ ++ conn->state = PROC_WAIT_FOR_EVENT; ++ ++ rc = proc_event_delivered(conn, conn->event); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++ ++ case PROC_HANGUP: ++ break; ++ } ++ ++ return 0; ++} ++ ++static int proc_start_deliver_event(struct proc_conn_info *conn) ++{ ++ DL_NODE *node; ++ int rc; ++ ++ if (conn->state != PROC_WAIT_FOR_EVENT) ++ return 0; ++ ++ node = dlist_get_first(conn->events); ++ if (node == NULL) ++ return 0; ++ ++ conn->event = node->data; ++ memset(&conn->reply, 0, sizeof(conn->reply)); ++ ++ DbgLog(DL3, "%s: process: %p event: %p", __func__, conn, conn->event); ++ ++ conn->state = PROC_SEND_EVENT; ++ rc = client_socket_send(&conn->client_info, &conn->event->event, ++ sizeof(conn->event->event)); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++} ++ ++static int proc_deliver_event(struct proc_conn_info *conn, ++ struct event_info *event) ++{ ++ DL_NODE *list; ++ int rc; ++ ++ DbgLog(DL3, "%s: process: %p event: %p", __func__, conn, event); ++ ++ if (conn->state == PROC_HANGUP) ++ return 0; ++ ++ /* Add to process's event list and incr. reference count */ ++ list = dlist_add_as_last(conn->events, event); ++ if (list == NULL) { ++ ErrLog("%s: failed add event to list of process's pending events", ++ __func__); ++ return -ENOMEM; ++ } ++ conn->events = list; ++ ++ event->proc_ref_count++; ++ ++ rc = proc_start_deliver_event(conn); ++ return rc; ++} ++ ++static int proc_event_delivered(struct proc_conn_info *conn, ++ struct event_info *event) ++{ ++ DL_NODE *node; ++ int rc; ++ ++ DbgLog(DL3, "%s: process: %p event: %p", __func__, conn, event); ++ ++ conn->event = NULL; ++ ++ /* Remove from process's event list and decr. reference count */ ++ node = dlist_find(conn->events, event); ++ if (node != NULL) { ++ conn->events = dlist_remove_node(conn->events, node); ++ event->proc_ref_count--; ++ } ++ ++ DbgLog(DL3, "%s: proc_ref_count: %u", __func__, event->proc_ref_count); ++ ++ if (event->proc_ref_count == 0) ++ event_delivered(event); ++ ++ /* Deliver further pending events, if any */ ++ rc = proc_start_deliver_event(conn); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++} ++ ++static inline void proc_get(struct proc_conn_info *conn) ++{ ++ client_socket_get(&conn->client_info); ++} ++ ++static inline void proc_put(struct proc_conn_info *conn) ++{ ++ client_socket_put(&conn->client_info); ++} ++ ++static void proc_hangup(void *client) ++{ ++ struct proc_conn_info *conn = client; ++ struct event_info *event; ++ DL_NODE *node; ++ ++ DbgLog(DL0, "%s: process: %p socket: %d state: %d", __func__, conn, ++ conn->client_info.socket, conn->state); ++ ++ if (conn->state == PROC_HANGUP) ++ return; ++ conn->state = PROC_HANGUP; ++ ++ /* Unlink all pending events */ ++ while ((node = dlist_get_first(conn->events)) != NULL) { ++ event = node->data; ++ /* We did not handle this event */ ++ event->reply.nothandled_replies++; ++ proc_event_delivered(conn, event); ++ } ++ ++ client_socket_term(&conn->client_info); ++ proc_put(conn); ++} ++ ++static void proc_free(void *client) ++{ ++ struct proc_conn_info *conn = client; ++ DL_NODE *node; ++ ++ /* Remove it from the process connections list */ ++ node = dlist_find(proc_connections, conn); ++ if (node != NULL) { ++ proc_connections = dlist_remove_node(proc_connections, node); ++ listener_client_hangup(&proc_listener); ++ } ++ ++ DbgLog(DL0, "%s: process: %p", __func__, conn); ++ free(conn); ++} ++ ++static int admin_new_conn(int socket, struct listener_info *listener) ++{ ++ struct admin_conn_info *conn; ++ DL_NODE *list; ++ int rc = 0; ++ ++ UNUSED(listener); ++ ++ DbgLog(DL0, "%s: Accepted connection from admin: socket: %d", __func__, ++ socket); ++ ++ conn = calloc(1, sizeof(struct admin_conn_info)); ++ if (conn == NULL) { ++ ErrLog("%s: Failed to to allocate memory for the admin connection", ++ __func__); ++ return -ENOMEM; ++ /* Caller will close socket */ ++ } ++ ++ DbgLog(DL3, "%s: admin conn: %p", __func__, conn); ++ ++ conn->state = ADMIN_RECEIVE_EVENT; ++ ++ rc = client_socket_init(socket, admin_xfer_complete, admin_hangup, ++ admin_free, conn, &conn->client_info); ++ if (rc != 0) ++ goto out; ++ ++ conn->event = event_new(0, conn); ++ if (conn->event == NULL) { ++ ErrLog("%s: Failed to allocate a new event", __func__); ++ rc = -ENOMEM; ++ goto out; ++ } ++ ++ /* Add it to the admin connections list */ ++ list = dlist_add_as_first(admin_connections, conn); ++ if (list == NULL) { ++ ErrLog("%s: Failed to add connection to list of admin connections", ++ __func__); ++ rc = -ENOMEM; ++ goto out; ++ } ++ admin_connections = list; ++ ++ admin_get(conn); ++ rc = client_socket_receive(&conn->client_info, &conn->event->event, ++ sizeof(conn->event->event)); ++ admin_put(conn); ++ conn = NULL; /* conn may have been freed by now */ ++ ++out: ++ if (rc != 0 && conn != NULL) { ++ admin_hangup(conn); ++ rc = 0; /* Don't return an error, we have already handled it */ ++ } ++ ++ return rc; ++} ++ ++static int admin_xfer_complete(void *client) ++{ ++ struct admin_conn_info *conn = client; ++ int rc; ++ ++ DbgLog(DL0, "%s: Xfer completed: admin: %p socket: %d state: %d", ++ __func__, conn, conn->client_info.socket, conn->state); ++ ++ /* ++ * A non-zero return code returned by this function causes the caller to ++ * call admin_hangup(). Thus, no need to call admin_hangup() ourselves. ++ */ ++ ++ if (conn->event == NULL) { ++ TraceLog("%s: No current event", __func__); ++ return -EINVAL; ++ } ++ ++ switch (conn->state) { ++ case ADMIN_RECEIVE_EVENT: ++ /* We have received the event from the admin */ ++ DbgLog(DL3, "%s: Event version: %u", __func__, ++ conn->event->event.version); ++ DbgLog(DL3, "%s: Event type: 0x%08x", __func__, ++ conn->event->event.type); ++ DbgLog(DL3, "%s: Event flags: 0x%08x", __func__, ++ conn->event->event.flags); ++ DbgLog(DL3, "%s: Event token_type: 0x%08x", __func__, ++ conn->event->event.token_type); ++ DbgLog(DL3, "%s: Event token_name: '%.32s'", __func__, ++ conn->event->event.token_label); ++ DbgLog(DL3, "%s: Event process_id: %u", __func__, ++ conn->event->event.process_id); ++ DbgLog(DL3, "%s: Event payload_len: %u", __func__, ++ conn->event->event.payload_len); ++ ++ if (conn->event->event.version != EVENT_VERSION_1) { ++ InfoLog("%s: Admin event has invalid version: %d", __func__, ++ conn->event->event.version); ++ return -EINVAL; ++ } ++ if (conn->event->event.payload_len > EVENT_MAX_PAYLOAD_LENGTH) { ++ InfoLog("%s: Admin event payload is too large: %u", __func__, ++ conn->event->event.payload_len); ++ return -EMSGSIZE; ++ } ++ ++ if (conn->event->event.payload_len > 0) { ++ conn->event->payload = malloc(conn->event->event.payload_len); ++ if (conn->event->payload == NULL) { ++ ErrLog("%s: Failed to allocate the payload buffer", __func__); ++ return -ENOMEM; ++ } ++ ++ conn->state = ADMIN_RECEIVE_PAYLOAD; ++ rc = client_socket_receive(&conn->client_info, conn->event->payload, ++ conn->event->event.payload_len); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++ } ++ FALL_THROUGH; ++ /* fall through */ ++ ++ case ADMIN_RECEIVE_PAYLOAD: ++ /* We have received the payload (if any) from the admin */ ++ conn->state = ADMIN_EVENT_DELIVERED; ++ rc = event_start_deliver(conn->event); ++ if (rc != 0) { ++ if (rc == -ENOSPC) { ++ /* Event limit reached, delay */ ++ conn->state = ADMIN_WAIT_FOR_EVENT_LIMIT; ++ return 0; ++ } ++ return rc; ++ } ++ break; ++ ++ case ADMIN_WAIT_FOR_EVENT_LIMIT: ++ /* This state is handled in admin_event_limit_underrun() */ ++ break; ++ ++ case ADMIN_EVENT_DELIVERED: ++ /* This state is handled in admin_event_delivered() */ ++ break; ++ ++ case ADMIN_SEND_REPLY: ++ /* The reply has been sent to the admin */ ++ if (conn->event->admin_ref != NULL) ++ admin_put(conn->event->admin_ref); ++ conn->event->admin_ref = NULL; ++ event_free(conn->event); ++ ++ conn->event = event_new(0, conn); ++ if (conn->event == NULL) { ++ ErrLog("%s: Failed to allocate a new event", __func__); ++ return -ENOMEM; ++ } ++ ++ conn->state = ADMIN_RECEIVE_EVENT; ++ rc = client_socket_receive(&conn->client_info, &conn->event->event, ++ sizeof(conn->event->event)); ++ conn = NULL; /* conn may have been freed by now */ ++ return rc; ++ ++ case ADMIN_HANGUP: ++ break; ++ } ++ ++ return 0; ++} ++ ++static void admin_event_limit_underrun(struct admin_conn_info *conn) ++{ ++ int rc; ++ ++ DbgLog(DL3, "%s: admin: %p state: %d", __func__, conn, conn->state); ++ ++ if (conn->state != ADMIN_WAIT_FOR_EVENT_LIMIT) ++ return; ++ ++ conn->state = ADMIN_EVENT_DELIVERED; ++ ++ rc = event_start_deliver(conn->event); ++ if (rc != 0) { ++ if (rc == -ENOSPC) { ++ /* Event limit reached, delay */ ++ conn->state = ADMIN_WAIT_FOR_EVENT_LIMIT; ++ return; ++ } ++ admin_hangup(conn); ++ } ++} ++ ++static int admin_event_delivered(struct admin_conn_info *conn, ++ struct event_info *event) ++{ ++ int rc; ++ ++ DbgLog(DL3, "%s: admin: %p event: %p", __func__, conn, event); ++ ++ /* ++ * A non-zero return code returned by this function causes the caller to ++ * call admin_hangup(). Thus, no need to call admin_hangup() ourselves. ++ */ ++ ++ if (conn->state != ADMIN_EVENT_DELIVERED) { ++ TraceLog("%s: wrong state: %d", __func__, conn->state); ++ return -EINVAL; ++ } ++ ++ if (event->event.flags & EVENT_FLAGS_REPLY_REQ) { ++ if (conn->event != event) { ++ TraceLog("%s: event not the current event", __func__); ++ return -EINVAL; ++ } ++ ++ DbgLog(DL3, "%s: Reply version: %u", __func__, ++ event->reply.version); ++ DbgLog(DL3, "%s: Reply positive: %lu", __func__, ++ event->reply.positive_replies); ++ DbgLog(DL3, "%s: Reply negative: %lu", __func__, ++ event->reply.negative_replies); ++ DbgLog(DL3, "%s: Reply not-handled: %lu", __func__, ++ event->reply.nothandled_replies); ++ ++ conn->state = ADMIN_SEND_REPLY; ++ rc = client_socket_send(&conn->client_info, &event->reply, ++ sizeof(event->reply)); ++ return rc; ++ } ++ ++ /* No reply required, free the event, and receive the next one */ ++ if (event->admin_ref != NULL) ++ admin_put(event->admin_ref); ++ event->admin_ref = NULL; ++ event_free(event); ++ ++ conn->event = event_new(0, conn); ++ if (conn->event == NULL) { ++ ErrLog("%s: Failed to allocate a new event", __func__); ++ return -ENOMEM; ++ } ++ ++ conn->state = ADMIN_RECEIVE_EVENT; ++ rc = client_socket_receive(&conn->client_info, &conn->event->event, ++ sizeof(conn->event->event)); ++ return rc; ++} ++ ++static inline void admin_get(struct admin_conn_info *conn) ++{ ++ client_socket_get(&conn->client_info); ++} ++ ++static inline void admin_put(struct admin_conn_info *conn) ++{ ++ client_socket_put(&conn->client_info); ++} ++ ++static void admin_hangup(void *client) ++{ ++ struct admin_conn_info *conn = client; ++ ++ DbgLog(DL0, "%s: admin: %p socket: %d state: %d", __func__, conn, ++ conn->client_info.socket, conn->state); ++ ++ if (conn->state == ADMIN_HANGUP) ++ return; ++ conn->state = ADMIN_HANGUP; ++ ++ /* Unlink pending event (if any) */ ++ if (conn->event != NULL) { ++ if (conn->event->admin_ref != NULL) ++ admin_put(conn->event->admin_ref); ++ conn->event->admin_ref = NULL; ++ if (conn->event->proc_ref_count == 0) { ++ event_remove_from_pending_list(conn->event); ++ event_free(conn->event); ++ } ++ conn->event = NULL; ++ } ++ ++ client_socket_term(&conn->client_info); ++ admin_put(conn); ++} ++ ++static void admin_free(void *client) ++{ ++ struct admin_conn_info *conn = client; ++ DL_NODE *node; + +-int proc_listener_socket = -1; ++ /* Remove it from the admin connections list */ ++ node = dlist_find(admin_connections, conn); ++ if (node != NULL) { ++ admin_connections = dlist_remove_node(admin_connections, node); ++ listener_client_hangup(&admin_listener); ++ } + +-static void close_listener_socket(int socketfd, const char *file_path); ++ DbgLog(DL0, "%s: admin: %p", __func__, conn); ++ free(conn); ++} + +-// Creates the daemon's listener socket, to which clients will connect and +-// retrieve slot information through. Returns the file descriptor of the +-// created socket. +-static int create_listener_socket(const char *file_path) ++static int listener_socket_create(const char *file_path) + { + struct sockaddr_un address; + struct group *grp; +- int socketfd; ++ int listener_socket, err; + +- socketfd = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); +- if (socketfd < 0) { +- ErrLog("Failed to create listener socket, errno 0x%X.", errno); ++ listener_socket = socket(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); ++ if (listener_socket < 0) { ++ err = errno; ++ ErrLog("%s: Failed to create listener socket, errno %d (%s).", ++ __func__, err, strerror(err)); + return -1; + } + if (unlink(file_path) && errno != ENOENT) { +- ErrLog("Failed to unlink socket file, errno 0x%X.", errno); ++ err = errno; ++ ErrLog("%s: Failed to unlink socket file, errno %d (%s).", __func__, ++ err, strerror(err)); + goto error; + } + +@@ -52,50 +1249,389 @@ static int create_listener_socket(const char *file_path) + address.sun_family = AF_UNIX; + strcpy(address.sun_path, file_path); + +- if (bind(socketfd, ++ if (bind(listener_socket, + (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) { +- ErrLog("Failed to bind to socket, errno 0x%X.", errno); ++ err = errno; ++ ErrLog("%s: Failed to bind to socket, errno %d (%s).", __func__, err, ++ strerror(err)); + goto error; + } + // make socket file part of the pkcs11 group, and write accessable + // for that group + grp = getgrnam("pkcs11"); + if (!grp) { +- ErrLog("Group PKCS#11 does not exist"); ++ ErrLog("%s: Group PKCS#11 does not exist", __func__); + goto error; + } + if (chown(file_path, 0, grp->gr_gid)) { +- ErrLog("Could not change file group on socket, errno 0x%X.", errno); ++ err = errno; ++ ErrLog("%s: Could not change file group on socket, errno %d (%s).", ++ __func__, err, strerror(err)); + goto error; + } + if (chmod(file_path, +- S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP | S_IXUSR | S_IXGRP)) { +- ErrLog("Could not change file permissions on socket, errno 0x%X.", +- errno); ++ S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP)) { ++ err = errno; ++ ErrLog("%s: Could not change file permissions on socket, errno %d (%s).", ++ __func__, err, strerror(err)); + goto error; + } + +- if (listen(socketfd, 20) != 0) { +- ErrLog("Failed to listen to socket, errno 0x%X.", errno); ++ if (listen(listener_socket, 20) != 0) { ++ err = errno; ++ ErrLog("%s: Failed to listen to socket, errno %d (%s).", __func__, err, ++ strerror(err)); + goto error; + } + +- return socketfd; ++ return listener_socket; + + error: +- if (socketfd >= 0) +- close_listener_socket(socketfd, file_path); ++ if (listener_socket >= 0) ++ listener_socket_close(listener_socket, file_path); + + return -1; + } + + +-static void close_listener_socket(int socketfd, const char *file_path) ++static void listener_socket_close(int listener_socket, const char *file_path) + { +- close(socketfd); ++ close(listener_socket); + unlink(file_path); + } + ++ ++ ++static int listener_notify(int events, void *private) ++{ ++ struct listener_info *listener = private; ++ struct sockaddr_un address; ++ socklen_t address_length = sizeof(address); ++ int client_socket, rc, err; ++ ++ if ((events & EPOLLIN) == 0) ++ return 0; ++ ++ /* epoll is edge triggered. We must call accept until we get EWOULDBLOCK */ ++ while (listener->num_clients < listener->max_num_clients) { ++ client_socket = accept(listener->socket, (struct sockaddr *) &address, ++ &address_length); ++ if (client_socket < 0) { ++ err = errno; ++ if (err == EWOULDBLOCK) ++ break; ++ InfoLog("%s: Failed to accept connection on socket %d, errno %d (%s).", ++ __func__, listener->socket, err, strerror(err)); ++ return -err; ++ } ++ ++ rc = listener->new_conn(client_socket, listener); ++ if (rc != 0) { ++ TraceLog("%s: new_conn callback failed for client socket %d, rc: %d", ++ __func__, client_socket, rc); ++ close(client_socket); ++ continue; ++ } ++ ++ listener->num_clients++; ++ } ++ ++ return 0; ++} ++ ++static int listener_client_hangup(struct listener_info *listener) ++{ ++ int rc, trigger = 0; ++ ++ if (listener->num_clients >= listener->max_num_clients) ++ trigger = 1; /* We were at max clients, trigger accept now */ ++ ++ if (listener->num_clients > 0) ++ listener->num_clients--; ++ ++ if (trigger && listener->num_clients < listener->max_num_clients) { ++ rc = listener_notify(EPOLLIN, listener); ++ if (rc != 0) ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static int listener_create(const char *file_path, ++ struct listener_info *listener, ++ int (* new_conn)(int socket, ++ struct listener_info *listener), ++ unsigned long max_num_clients) ++{ ++ struct epoll_event evt; ++ int rc, err; ++ ++ if (listener == NULL || new_conn == NULL) ++ return FALSE; ++ ++ memset(listener, 0, sizeof(*listener)); ++ epoll_info_init(&listener->ep_info, listener_notify, NULL, listener); ++ listener->file_path = file_path; ++ listener->new_conn = new_conn; ++ listener->max_num_clients = max_num_clients; ++ ++ listener->socket = listener_socket_create(file_path); ++ if (listener->socket < 0) ++ return FALSE; ++ ++ evt.events = EPOLLIN | EPOLLET; ++ evt.data.ptr = &listener->ep_info; ++ rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listener->socket, &evt); ++ if (rc != 0) { ++ err = errno; ++ TraceLog("%s: Failed add listener socket %d to epoll, errno %d (%s).", ++ __func__, listener->socket, err, strerror(err)); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static void listener_term(struct listener_info *listener) ++{ ++ if (listener == NULL || listener->socket < 0) ++ return; ++ ++ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, listener->socket, NULL); ++ listener_socket_close(listener->socket, listener->file_path); ++} ++ ++#ifdef WITH_LIBUDEV ++ ++static int udev_mon_init(const char *subsystem, struct udev_mon *udev_mon) ++{ ++ struct epoll_event evt; ++ int rc, err; ++ ++ if (subsystem == NULL || udev_mon == NULL) ++ return FALSE; ++ ++ udev_mon->delayed_event = 0; ++ ++ udev_mon->udev = udev_new(); ++ if (udev_mon->udev == NULL) { ++ ErrLog("%s: udev_new failed", __func__); ++ goto error; ++ } ++ ++ udev_mon->mon = udev_monitor_new_from_netlink(udev_mon->udev, "udev"); ++ if (udev_mon->mon == NULL) { ++ ErrLog("%s: udev_monitor_new_from_netlink failed", __func__); ++ goto error; ++ } ++ ++ /* ++ * Try to increase the receive buffer size. This may fail if the required ++ * privileges are not given. Ignore if it fails. ++ */ ++ udev_monitor_set_receive_buffer_size(udev_mon->mon, UDEV_RECV_BUFFFER_SIZE); ++ ++ rc = udev_monitor_filter_add_match_subsystem_devtype(udev_mon->mon, ++ subsystem, NULL); ++ if (rc != 0) { ++ ErrLog("%s: udev_monitor_filter_add_match_subsystem_devtype failed: " ++ "rc=%d", __func__, rc); ++ goto error; ++ } ++ ++ rc = udev_monitor_enable_receiving(udev_mon->mon); ++ if (rc != 0) { ++ ErrLog("%s: udev_monitor_enable_receiving failed: rc=%d", __func__, rc); ++ goto error; ++ } ++ ++ udev_mon->socket = udev_monitor_get_fd(udev_mon->mon); ++ if (udev_mon->socket < 0) { ++ ErrLog("%s: udev_monitor_get_fd failed", __func__); ++ goto error; ++ } ++ ++ epoll_info_init(&udev_mon->ep_info, udev_mon_notify, NULL, udev_mon); ++ ++ evt.events = EPOLLIN | EPOLLET; ++ evt.data.ptr = &udev_mon->ep_info; ++ rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, udev_mon->socket, &evt); ++ if (rc != 0) { ++ err = errno; ++ ErrLog("%s: Failed add udev_mon socket %d to epoll, errno %d (%s).", ++ __func__, udev_mon->socket, err, strerror(err)); ++ goto error; ++ } ++ ++ /* Epoll is edge triggered, thus try to receive once */ ++ rc = udev_mon_notify(EPOLLIN, udev_mon); ++ if (rc != 0) ++ goto error; ++ ++ return TRUE; ++ ++error: ++ udev_mon_term(udev_mon); ++ return FALSE; ++} ++ ++ ++static int udev_mon_handle_device(struct udev_mon *udev_mon, ++ struct udev_device *dev) ++{ ++ const char *action, *devname, *devpath, *devtype, *dev_type_prop; ++ unsigned int card, domain, dev_type; ++ struct event_info *event; ++ event_udev_apqn_data_t *apqn_data; ++ int rc; ++ ++ UNUSED(udev_mon); ++ ++ action = udev_device_get_action(dev); ++ devname = udev_device_get_sysname(dev); ++ devpath = udev_device_get_devpath(dev); ++ devtype = udev_device_get_devtype(dev); ++ dev_type_prop = udev_device_get_property_value(dev, UDEV_PROERTY_DEVTYPE); ++ ++ if (action == NULL || devname == NULL || devpath == NULL || ++ devtype == NULL || dev_type_prop == NULL) ++ return 0; ++ ++ DbgLog(DL3, "%s: Uevent: ACTION=%s DEVNAME=%s DEVPATH=%s DEVTYPE=%s " ++ "DEV_TYPE=%s", __func__, action, devname, devpath, devtype, ++ dev_type_prop); ++ ++ /* We are only interested in bind and unbind events ... */ ++ if (strcmp(action, UDEV_ACTION_BIND) != 0 && ++ strcmp(action, UDEV_ACTION_UNBIND) != 0) ++ return 0; ++ ++ /* ... for an APQN device */ ++ if (strcmp(devtype, UDEV_ACTION_DEVTYPE_APQN) != 0) ++ return 0; ++ ++ if (sscanf(devname, "%x.%x", &card, &domain) != 2) { ++ TraceLog("%s: failed to parse APQN from DEVNAME: %s", __func__, devname); ++ return -EIO; ++ } ++ if (sscanf(dev_type_prop, "%x", &dev_type) != 1) { ++ TraceLog("%s: failed to parse DEV_TYPE: %s", __func__, dev_type_prop); ++ return -EIO; ++ } ++ ++ event = event_new(sizeof(event_udev_apqn_data_t), NULL); ++ if (event == NULL) { ++ ErrLog("%s: failed to allocate an event", __func__); ++ return -ENOMEM; ++ } ++ ++ if (strcmp(udev_device_get_action(dev), UDEV_ACTION_BIND) == 0) ++ event->event.type = EVENT_TYPE_APQN_ADD; ++ else ++ event->event.type = EVENT_TYPE_APQN_REMOVE; ++ event->event.flags = EVENT_FLAGS_NONE; ++ event->event.token_type = EVENT_TOK_TYPE_ALL; ++ memset(event->event.token_label, ' ', ++ sizeof(event->event.token_label)); ++ ++ apqn_data = (event_udev_apqn_data_t *)event->payload; ++ apqn_data->card = card; ++ apqn_data->domain = domain; ++ apqn_data->device_type = dev_type; ++ ++ DbgLog(DL3, "%s: Event version: %u", __func__, event->event.version); ++ DbgLog(DL3, "%s: Event type: 0x%08x", __func__, event->event.type); ++ DbgLog(DL3, "%s: Event flags: 0x%08x", __func__, event->event.flags); ++ DbgLog(DL3, "%s: Event token_type: 0x%08x", __func__, ++ event->event.token_type); ++ DbgLog(DL3, "%s: Event token_name: '%.32s'", __func__, ++ event->event.token_label); ++ DbgLog(DL3, "%s: Event process_id: %u", __func__, event->event.process_id); ++ DbgLog(DL3, "%s: Event payload_len: %u", __func__, ++ event->event.payload_len); ++ ++ DbgLog(DL3, "%s: Payload: card: %u", __func__, apqn_data->card); ++ DbgLog(DL3, "%s: Payload: domain: %u", __func__, apqn_data->domain); ++ DbgLog(DL3, "%s: Payload: dev.type: %u", __func__, apqn_data->device_type); ++ ++ rc = event_start_deliver(event); ++ if (rc != 0) { ++ if (rc == -ENOSPC) { ++ /* Event limit reached, delay event delivery */ ++ udev_mon->delayed_event = event; ++ return -ENOSPC; ++ } ++ event_free(event); ++ return rc; ++ } ++ ++ return 0; ++} ++ ++static int udev_mon_notify(int events, void *private) ++{ ++ struct udev_mon *udev_mon = private; ++ struct udev_device *dev; ++ struct event_info *event; ++ int rc; ++ ++ DbgLog(DL3, "%s: Epoll event on udev_mon socket %d: events: 0x%x", ++ __func__, udev_mon->socket, events); ++ ++ if (udev_mon->delayed_event != NULL) { ++ /* Deliver delayed event first */ ++ event = udev_mon->delayed_event; ++ udev_mon->delayed_event = NULL; ++ ++ rc = event_start_deliver(event); ++ if (rc != 0) { ++ if (rc == -ENOSPC) { ++ /* Event limit reached, delay event delivery */ ++ udev_mon->delayed_event = event; ++ return 0; ++ } ++ event_free(event); ++ return rc; ++ } ++ } ++ ++ while (1) { ++ dev = udev_monitor_receive_device(udev_mon->mon); ++ if (dev == NULL) ++ break; /* this is just like EWOULDBLOCK */ ++ ++ rc = udev_mon_handle_device(udev_mon, dev); ++ if (rc != 0) ++ TraceLog("%s: udev_mon_handle_device failed, rc: %d", __func__, rc); ++ ++ udev_device_unref(dev); ++ ++ /* If event limit reached, stop receiving more events */ ++ if (rc == -ENOSPC) ++ break; ++ }; ++ ++ return 0; ++} ++ ++static void udev_mon_term(struct udev_mon *udev_mon) ++{ ++ if (udev_mon == NULL) ++ return; ++ ++ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, udev_mon->socket, NULL); ++ if (udev_mon->udev != NULL) ++ udev_unref(udev_mon->udev); ++ if (udev_mon->mon != NULL) ++ udev_monitor_unref(udev_mon->mon); ++ ++ if (udev_mon->delayed_event != NULL) ++ event_free(udev_mon->delayed_event); ++} ++ ++#endif ++ + int init_socket_data(Slot_Mgr_Socket_t *socketData) + { + unsigned int processed = 0; +@@ -106,7 +1642,7 @@ int init_socket_data(Slot_Mgr_Socket_t *socketData) + + /* check that we read in correct amount of slots */ + if (processed != NumberSlotsInDB) { +- ErrLog("Failed to populate slot info.\n"); ++ ErrLog("%s: Failed to populate slot info.", __func__); + return FALSE; + } + +@@ -115,72 +1651,277 @@ int init_socket_data(Slot_Mgr_Socket_t *socketData) + + int socket_connection_handler(int timeout_secs) + { +- int returnVal; +- fd_set set; +- struct timeval timeout; +- +- FD_ZERO(&set); +- FD_SET(proc_listener_socket, &set); ++ struct epoll_event events[MAX_EPOLL_EVENTS]; ++ int num_events, i, rc, err; ++ struct epoll_info *info; + +- timeout.tv_sec = timeout_secs; +- timeout.tv_usec = 0; +- +- returnVal = select(proc_listener_socket + 1, &set, NULL, NULL, &timeout); +- if (returnVal == -1) { +- ErrLog("select failed on socket connection, errno 0x%X.", errno); +- return FALSE; +- } else if (returnVal == 0) { +- // select call timed out, return +- return FALSE; +- } else { +- struct sockaddr_un address; +- socklen_t address_length = sizeof(address); +- +- int connectionfd = accept(proc_listener_socket, +- (struct sockaddr *) &address, +- &address_length); +- if (connectionfd < 0) { +- if (errno != EAGAIN && errno != EWOULDBLOCK) { +- /* These errors are allowed since +- * socket is non-blocking +- */ +- ErrLog("Failed to accept socket connection, errno 0x%X.", +- errno); +- } ++ do { ++ num_events = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, ++ timeout_secs * 1000); ++ if (num_events < 0) { ++ err = errno; ++ if (err == EINTR) ++ continue; ++ ErrLog("%s: epoll_wait failed, errno %d (%s).", __func__, err, ++ strerror(err)); + return FALSE; + } + +- DbgLog(DL0, "Accepted connection from process: socket: %d", +- connectionfd); ++ /* ++ * Inc ref count of all epoll_infos returned by epoll before handling ++ * any of them via notify. The notify callback may hangup any of ++ * the connections associated with the returned epoll_infos, and we ++ * need to avoid them getting freed before we all handled them. ++ */ ++ for (i = 0; i < num_events; i++) ++ epoll_info_get(events[i].data.ptr); + +- if (write(connectionfd, &socketData, sizeof(socketData)) != +- sizeof(socketData)) { +- ErrLog("Failed to write socket data, errno 0x%X.", errno); +- close(connectionfd); +- return FALSE; ++ for (i = 0; i < num_events; i++) { ++ info = events[i].data.ptr; ++ if (info == NULL || info->notify == NULL) ++ continue; ++ ++ rc = info->notify(events[i].events, info->private); ++ if (rc != 0) ++ TraceLog("%s: notify callback failed, rc: %d", __func__, rc); ++ ++ epoll_info_put(info); + } +- close(connectionfd); +- return TRUE; +- } ++ } while (num_events > 0 && rc == 0); /* num_events = 0: timeout */ ++ ++ return TRUE; + } + + int init_socket_server() + { +- proc_listener_socket = create_listener_socket(PROC_SOCKET_FILE_PATH); +- if (proc_listener_socket < 0) ++ int err; ++ ++ epoll_fd = epoll_create1(0); ++ if (epoll_fd < 0) { ++ err = errno; ++ ErrLog("%s: Failed to open epoll socket, errno %d (%s).", __func__, err, ++ strerror(err)); ++ return FALSE; ++ } ++ ++ if (!listener_create(PROC_SOCKET_FILE_PATH, &proc_listener, ++ proc_new_conn, NUMBER_PROCESSES_ALLOWED)) { ++ term_socket_server(); ++ return FALSE; ++ } ++ ++ if (!listener_create(ADMIN_SOCKET_FILE_PATH, &admin_listener, ++ admin_new_conn, NUMBER_ADMINS_ALLOWED)) { ++ term_socket_server(); + return FALSE; ++ } ++ ++#ifdef WITH_LIBUDEV ++ if (!udev_mon_init(UDEV_SUBSYSTEM_AP, &udev_mon)) { ++ term_socket_server(); ++ return FALSE; ++ } ++#endif + +- DbgLog(DL0, "Socket server started"); ++ DbgLog(DL0, "%s: Socket server started", __func__); + + return TRUE; + } + + int term_socket_server() + { +- if (proc_listener_socket >= 0) +- close_listener_socket(proc_listener_socket, PROC_SOCKET_FILE_PATH); ++ DL_NODE *node, *next; ++ ++#ifdef WITH_LIBUDEV ++ udev_mon_term(&udev_mon); ++#endif ++ ++ listener_term(&proc_listener); ++ listener_term(&admin_listener); ++ ++ node = dlist_get_first(proc_connections); ++ while (node != NULL) { ++ next = dlist_next(node); ++ proc_hangup(node->data); ++ node = next; ++ } ++ dlist_purge(proc_connections); + +- DbgLog(DL0, "Socket server stopped"); ++ node = dlist_get_first(admin_connections); ++ while (node != NULL) { ++ next = dlist_next(node); ++ admin_hangup(node->data); ++ node = next; ++ } ++ dlist_purge(admin_connections); ++ ++ node = dlist_get_first(pending_events); ++ while (node != NULL) { ++ next = dlist_next(node); ++ event_free((struct event_info *)node->data); ++ node = next; ++ } ++ dlist_purge(pending_events); ++ ++ if (epoll_fd >= 0) ++ close(epoll_fd); ++ epoll_fd = -1; ++ ++ DbgLog(DL0, "%s: Socket server stopped", __func__); + + return TRUE; + } ++ ++#ifdef DEV ++ ++static void dump_listener(struct listener_info *listener) ++{ ++ DbgLog(DL0, " socket: %d", listener->socket); ++ DbgLog(DL0, " file_path: %s", listener->file_path); ++ DbgLog(DL0, " ep_info.ref_count: %lu", listener->ep_info.ref_count); ++ DbgLog(DL0, " num_clients: %lu", listener->num_clients); ++ DbgLog(DL0, " max_num_clients: %lu", listener->max_num_clients); ++} ++ ++static void dump_event_msg(event_msg_t *event, int indent) ++{ ++ DbgLog(DL0, "%*sevent version: %u", indent, "", event->version); ++ DbgLog(DL0, "%*sevent type: %08x", indent, "", event->type); ++ DbgLog(DL0, "%*sevent flags: %08x", indent, "", event->flags); ++ DbgLog(DL0, "%*sevent token_type: %08x", indent, "", event->token_type); ++ DbgLog(DL0, "%*sevent token_label: '%.32s'", indent, "", event->token_label); ++ DbgLog(DL0, "%*sevent process_id: %lu", indent, "", event->process_id); ++ DbgLog(DL0, "%*sevent payload_len: %u", indent, "", event->payload_len); ++} ++ ++static void dump_event_reply(event_reply_t *reply, int indent) ++{ ++ DbgLog(DL0, "%*sreply version: %u", indent, "", reply->version); ++ DbgLog(DL0, "%*sreply positive_replies: %u", indent, "", reply->positive_replies); ++ DbgLog(DL0, "%*sreply negative_replies: %u", indent, "", reply->negative_replies); ++ DbgLog(DL0, "%*sreply nothandled_replies: %u", indent, "", reply->nothandled_replies); ++} ++ ++static void dump_event_info(struct event_info *event, int indent) ++{ ++ dump_event_msg(&event->event, indent); ++ dump_event_reply(&event->reply, indent); ++ DbgLog(DL0, "%*sproc_ref_count: %lu", indent, "", event->proc_ref_count); ++ if (event->admin_ref != NULL) ++ DbgLog(DL0, "%*sadmin_ref: %p", indent, "", event->admin_ref); ++ else ++ DbgLog(DL0, "%*sadmin_ref: None", indent, ""); ++} ++ ++static void dump_proc_conn(struct proc_conn_info *proc_conn) ++{ ++ DL_NODE *node; ++ unsigned long i; ++ ++ DbgLog(DL0, " socket: %d", proc_conn->client_info.socket); ++ DbgLog(DL0, " state: %d", proc_conn->state); ++ DbgLog(DL0, " ref-count: %lu", proc_conn->client_info.ep_info.ref_count); ++ DbgLog(DL0, " xfer state: %d", proc_conn->client_info.xfer_state); ++ DbgLog(DL0, " xfer size: %d", proc_conn->client_info.xfer_size); ++ DbgLog(DL0, " xfer offset: %d", proc_conn->client_info.xfer_offset); ++ DbgLog(DL0, " pending events:"); ++ node = dlist_get_first(proc_conn->events); ++ i = 1; ++ while (node != NULL) { ++ DbgLog(DL0, " event %lu (%p):", i, node->data); ++ dump_event_info(node->data, 10); ++ node = dlist_next(node); ++ i++; ++ } ++ if (proc_conn->event != NULL) { ++ DbgLog(DL0, " current event:"); ++ dump_event_info(proc_conn->event, 8); ++ DbgLog(DL0, " current reply:"); ++ dump_event_reply(&proc_conn->reply, 8); ++ } else { ++ DbgLog(DL0, " current event: none"); ++ } ++} ++ ++static void dump_admin_conn(struct admin_conn_info *admin_conn) ++{ ++ DbgLog(DL0, " socket: %d", admin_conn->client_info.socket); ++ DbgLog(DL0, " state: %d", admin_conn->state); ++ DbgLog(DL0, " ref-count: %lu", admin_conn->client_info.ep_info.ref_count); ++ DbgLog(DL0, " xfer state: %d", admin_conn->client_info.xfer_state); ++ DbgLog(DL0, " xfer size: %d", admin_conn->client_info.xfer_size); ++ DbgLog(DL0, " xfer offset: %d", admin_conn->client_info.xfer_offset); ++ if (admin_conn->event != NULL) { ++ DbgLog(DL0, " current event (%p):", admin_conn->event); ++ dump_event_info(admin_conn->event, 8); ++ } else { ++ DbgLog(DL0, " current event: none"); ++ } ++} ++ ++#ifdef WITH_LIBUDEV ++void dump_udev_mon(struct udev_mon *udev_mon) ++{ ++ DbgLog(DL0, " socket: %d", udev_mon->socket); ++ DbgLog(DL0, " udev: %p", udev_mon->udev); ++ DbgLog(DL0, " mon: %p", udev_mon->mon); ++ DbgLog(DL0, " ep_info.ref_count: %lu", udev_mon->ep_info.ref_count); ++ if (udev_mon->delayed_event != NULL) { ++ DbgLog(DL0, " delayed_event (%p):", udev_mon->delayed_event); ++ dump_event_info(udev_mon->delayed_event, 6); ++ } else { ++ DbgLog(DL0, " delayed_event: node"); ++ } ++} ++#endif ++ ++void dump_socket_handler() ++{ ++ DL_NODE *node; ++ unsigned long i; ++ ++ DbgLog(DL0, "%s: Dump of socket handler data:", __func__); ++ DbgLog(DL0, " epoll_fd: %d", epoll_fd); ++ ++ DbgLog(DL0, " proc_listener (%p): ", &proc_listener); ++ dump_listener(&proc_listener); ++ ++ DbgLog(DL0, " proc_connections: "); ++ node = dlist_get_first(proc_connections); ++ i = 1; ++ while (node != NULL) { ++ DbgLog(DL0, " proc_connection %lu (%p): ", i, node->data); ++ dump_proc_conn(node->data); ++ i++; ++ node = dlist_next(node); ++ } ++ ++ DbgLog(DL0, " admin_listener (%p): ", &admin_listener); ++ dump_listener(&admin_listener); ++ ++ DbgLog(DL0, " admin_connections: "); ++ node = dlist_get_first(admin_connections); ++ i = 1; ++ while (node != NULL) { ++ DbgLog(DL0, " admin_connection %lu (%p): ", i, node->data); ++ dump_admin_conn(node->data); ++ i++; ++ node = dlist_next(node); ++ } ++ ++#ifdef WITH_LIBUDEV ++ DbgLog(DL0, " udev_mon (%p): ", &udev_mon); ++ dump_udev_mon(&udev_mon); ++#endif ++ ++ DbgLog(DL0, " pending events (%lu): ", pending_events_count); ++ node = dlist_get_first(pending_events); ++ i = 1; ++ while (node != NULL) { ++ DbgLog(DL0, " event %lu (%p): ", i, node->data); ++ dump_event_info(node->data, 6); ++ i++; ++ node = dlist_next(node); ++ } ++} ++#endif diff --git a/opencryptoki-3.16.0-4e3b43c3d8844402c04a66b55c6c940f965109f0.patch b/opencryptoki-3.16.0-4e3b43c3d8844402c04a66b55c6c940f965109f0.patch new file mode 100644 index 0000000..8a3d581 --- /dev/null +++ b/opencryptoki-3.16.0-4e3b43c3d8844402c04a66b55c6c940f965109f0.patch @@ -0,0 +1,47 @@ +commit 4e3b43c3d8844402c04a66b55c6c940f965109f0 +Author: Ingo Franzki +Date: Mon May 3 10:05:07 2021 +0200 + + SOFT: Check the EC Key on C_CreateObject and C_DeriveKey + + When constructing an OpenSSL EC public or private key from PKCS#11 + attributes or ECDH public data, check that the key is valid, i.e. that + the point is on the curve. + + This prevents one from creating an EC key object via C_CreateObject with + invalid key data. It also prevents C_DeriveKey to derive a secret using + ECDH with an EC public key (public data) that uses a different curve + or is invalid by other means. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/soft_stdll/soft_specific.c b/usr/lib/soft_stdll/soft_specific.c +index c30be1da..aeff39a9 100644 +--- a/usr/lib/soft_stdll/soft_specific.c ++++ b/usr/lib/soft_stdll/soft_specific.c +@@ -4365,6 +4365,12 @@ static CK_RV fill_ec_key_from_pubkey(EC_KEY *ec_key, const CK_BYTE *data, + goto out; + } + ++ if (!EC_KEY_check_key(ec_key)) { ++ TRACE_ERROR("EC_KEY_check_key failed\n"); ++ rc = CKR_PUBLIC_KEY_INVALID; ++ goto out; ++ } ++ + out: + if (allocated && ecpoint != NULL) + free(ecpoint); +@@ -4404,6 +4410,12 @@ static CK_RV fill_ec_key_from_privkey(EC_KEY *ec_key, const CK_BYTE *data, + goto out; + } + ++ if (!EC_KEY_check_key(ec_key)) { ++ TRACE_ERROR("EC_KEY_check_key failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ + out: + if (point != NULL) + EC_POINT_free(point); diff --git a/opencryptoki-3.16.0-69244a5e0d9dfec3ef534b19b89a541576bb17dc.patch b/opencryptoki-3.16.0-69244a5e0d9dfec3ef534b19b89a541576bb17dc.patch new file mode 100644 index 0000000..0494a35 --- /dev/null +++ b/opencryptoki-3.16.0-69244a5e0d9dfec3ef534b19b89a541576bb17dc.patch @@ -0,0 +1,23 @@ +commit 69244a5e0d9dfec3ef534b19b89a541576bb17dc +Author: Ingo Franzki +Date: Tue Feb 9 10:47:57 2021 +0100 + + TRACE: Use gettid() if SYS_gettid is not defined + + Also print the thread ID in the trace, if SYS_gettid is not defined. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/common/trace.c b/usr/lib/common/trace.c +index 678c0b96..bdc5256a 100644 +--- a/usr/lib/common/trace.c ++++ b/usr/lib/common/trace.c +@@ -33,6 +33,8 @@ + + #ifdef SYS_gettid + #define __gettid() syscall(SYS_gettid) ++#else ++#define __gettid() gettid() + #endif + + pthread_mutex_t tlmtx = PTHREAD_MUTEX_INITIALIZER; diff --git a/opencryptoki-3.16.0-7b7d83c571ceb3050969359817d4145600f14ae8.patch b/opencryptoki-3.16.0-7b7d83c571ceb3050969359817d4145600f14ae8.patch new file mode 100644 index 0000000..86ba3f0 --- /dev/null +++ b/opencryptoki-3.16.0-7b7d83c571ceb3050969359817d4145600f14ae8.patch @@ -0,0 +1,367 @@ +commit 7b7d83c571ceb3050969359817d4145600f14ae8 +Author: Ingo Franzki +Date: Fri Apr 9 17:07:31 2021 +0200 + + Check CKF_LIBRARY_CANT_CREATE_OS_THREADS at C_Initialize + + Fail if flag CKF_LIBRARY_CANT_CREATE_OS_THREADS is set at C_Initialize, + and event support is enabled (this is the default). We need to use pthreads + for the event thread, so we can't work if CKF_LIBRARY_CANT_CREATE_OS_THREADS + is set. Fail with CKR_NEED_TO_CREATE_THREADS if so. + + The event support can be globally disabled using keyword 'disable-event-support' + in opencryptoki.conf. This disables pkcsslots to accept admin connections, + and it does not monitor for AP UDEV events (on s390 platform). No event + thread is started in the opencryptoki processes, thus we can accept if flag + CKF_LIBRARY_CANT_CREATE_OS_THREADS is set in that case. + + Signed-off-by: Ingo Franzki + +diff --git a/man/man5/opencryptoki.conf.5.in b/man/man5/opencryptoki.conf.5.in +index 71218f79..7dc676ab 100644 +--- a/man/man5/opencryptoki.conf.5.in ++++ b/man/man5/opencryptoki.conf.5.in +@@ -10,8 +10,16 @@ pkcs#11 slots. At startup, the pkcsslotd daemon parses this file to + determine which slots will be made available. + + .SH SYNTAX +-This file is made up of slot descriptions. Each slot description +-is composed of a slot number, brackets and key-value pairs. ++This file is made up of optional global definitions, and slot descriptions. ++ ++The following global definitions are valid: ++ ++.TP ++.BR disable-event-support ++If this keyword is specified the openCryptoki event support is disabled. ++ ++.P ++Each slot description is composed of a slot number, brackets and key-value pairs. + + slot number + { +diff --git a/usr/include/slotmgr.h b/usr/include/slotmgr.h +index e37368a5..451a8cf1 100644 +--- a/usr/include/slotmgr.h ++++ b/usr/include/slotmgr.h +@@ -99,6 +99,7 @@ typedef struct { + LW_SHM_TYPE *shm_addr; // token specific shm address + } Slot_Info_t; + ++#define FLAG_EVENT_SUPPORT_DISABLED 0x01 + + #ifdef PKCS64 + +@@ -200,6 +201,7 @@ typedef struct { + + typedef struct { + uint8 num_slots; ++ uint8 flags; + CK_INFO_64 ck_info; + Slot_Info_t_64 slot_info[NUMBER_SLOTS_MANAGED]; + } Slot_Mgr_Socket_t; +@@ -214,6 +216,7 @@ typedef struct { + + typedef struct { + uint8 num_slots; ++ uint8 flags; + CK_INFO ck_info; + Slot_Info_t slot_info[NUMBER_SLOTS_MANAGED]; + } Slot_Mgr_Socket_t; +diff --git a/usr/lib/api/api_interface.c b/usr/lib/api/api_interface.c +index 2873a20a..6517ca6c 100644 +--- a/usr/lib/api/api_interface.c ++++ b/usr/lib/api/api_interface.c +@@ -308,7 +308,8 @@ void parent_fork_after() + return; + + /* Restart the event thread in the parent when fork is complete */ +- if (Anchor->event_thread == 0) ++ if ((Anchor->SocketDataP.flags & FLAG_EVENT_SUPPORT_DISABLED) == 0 && ++ Anchor->event_thread == 0) + start_event_thread(); + } + +@@ -2752,13 +2753,7 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) + goto error; + } + } +- // If we EVER need to create threads from this library we must +- // check the Flags for the Can_Create_OS_Threads flag +- // Right now the library DOES NOT create threads and therefore this +- // check is irrelavant. +- if (pArg->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) { +- TRACE_DEVEL("Can't create OS threads...This is OK\n"); +- } ++ + // Since this is an initialization path, we will be verbose in the + // code rather than efficient. + // +@@ -2848,7 +2843,21 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) + rc = CKR_FUNCTION_FAILED; + goto error_shm; + } +- // Initialize structure values ++ ++ if (pVoid != NULL) { ++ pArg = (CK_C_INITIALIZE_ARGS *) pVoid; ++ ++ if ((Anchor->SocketDataP.flags & FLAG_EVENT_SUPPORT_DISABLED) == 0 && ++ (pArg->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) != 0) { ++ TRACE_ERROR("Flag CKF_LIBRARY_CANT_CREATE_OS_THREADS is set and " ++ "event support is enabled\n"); ++ OCK_SYSLOG(LOG_ERR, "C_Initialize: Application specified that " ++ "library can't create OS threads. PKCS11 Module requires " ++ "to create threads when event support is enabled.\n"); ++ rc = CKR_NEED_TO_CREATE_THREADS; ++ goto error; ++ } ++ } + + //Register with pkcsslotd + if (!API_Register()) { +@@ -2867,7 +2876,8 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) + } + + /* Start event receiver thread */ +- if (start_event_thread() != 0) { ++ if ((Anchor->SocketDataP.flags & FLAG_EVENT_SUPPORT_DISABLED) == 0 && ++ start_event_thread() != 0) { + TRACE_ERROR("Failed to start event thread\n"); + + // unload all the STDLL's from the application +diff --git a/usr/lib/common/configparser.h b/usr/lib/common/configparser.h +index 13ca648d..b3c32496 100644 +--- a/usr/lib/common/configparser.h ++++ b/usr/lib/common/configparser.h +@@ -35,6 +35,7 @@ typedef int (*end_slot_f)(void *private); + typedef int (*key_str_f)(void *private, int tok, const char *val); + typedef int (*key_vers_f)(void *private, int tok, unsigned int vers); + typedef void (*eolcomment_f)(void *private, const char *comment); ++typedef void (*disab_event_supp_f)(void *private); + /* + * Report an error. If the error is not reported by the parser itself + * but via one of the parse functions, \c parsermsg will be \c NULL. +@@ -52,6 +53,7 @@ typedef void (*error_f)(void *private, int line, const char *parsermsg); + */ + struct parsefuncs { + ockversion_f version; ++ disab_event_supp_f disab_event_supp; + eol_f eol; + begin_slot_f begin_slot; + end_slot_f end_slot; +diff --git a/usr/lib/common/lexer.l b/usr/lib/common/lexer.l +index b35a0b72..38cbcb70 100644 +--- a/usr/lib/common/lexer.l ++++ b/usr/lib/common/lexer.l +@@ -69,6 +69,7 @@ extern char *configparse_strdup(const char *s); + + version return OCKVERSION; + slot return SLOT; ++disable-event-support return DISABLE_EVENT_SUPPORT; + + [^\"= \t\n]+ { + yylval.str = configparse_strdup(yytext); +diff --git a/usr/lib/common/parser.y b/usr/lib/common/parser.y +index 86806fcb..40c3994d 100644 +--- a/usr/lib/common/parser.y ++++ b/usr/lib/common/parser.y +@@ -65,7 +65,7 @@ int lookup_keyword(const char *key); + int err; + } + +-%token EQUAL DOT SLOT EOL OCKVERSION BEGIN_DEF END_DEF ++%token EQUAL DOT SLOT EOL OCKVERSION BEGIN_DEF END_DEF DISABLE_EVENT_SUPPORT + %token STRING + %token KEYWORD + %token INTEGER +@@ -81,6 +81,7 @@ config_file: + + sections: + version_def eolcomment ++ | disable_event_support_def eolcomment + | SLOT INTEGER BEGIN_DEF + { + if (parsefuncs->begin_slot && parsefuncs->begin_slot(parsedata, $2, 0)) { +@@ -125,6 +126,13 @@ version_def: + } + configparse_freestringsfrom($2); + } ++ ++disable_event_support_def: ++ DISABLE_EVENT_SUPPORT ++ { ++ if (parsefuncs->disab_event_supp) ++ parsefuncs->disab_event_supp(parsedata); ++ } + + line_def: + STRING EQUAL TOKVERSION +diff --git a/usr/sbin/pkcsslotd/pkcsslotd.h b/usr/sbin/pkcsslotd/pkcsslotd.h +index d7edcb3c..1dd0bac9 100644 +--- a/usr/sbin/pkcsslotd/pkcsslotd.h ++++ b/usr/sbin/pkcsslotd/pkcsslotd.h +@@ -88,7 +88,7 @@ int XProcLock(void); + int XProcUnLock(void); + int CreateXProcLock(void); + +-int init_socket_server(); ++int init_socket_server(int event_support_disabled); + int term_socket_server(); + int init_socket_data(Slot_Mgr_Socket_t *sp); + int socket_connection_handler(int timeout_secs); +diff --git a/usr/sbin/pkcsslotd/slotmgr.c b/usr/sbin/pkcsslotd/slotmgr.c +index efbfe8fd..3b328a6c 100644 +--- a/usr/sbin/pkcsslotd/slotmgr.c ++++ b/usr/sbin/pkcsslotd/slotmgr.c +@@ -34,6 +34,7 @@ int shmid; + key_t tok; + Slot_Info_t_64 sinfo[NUMBER_SLOTS_MANAGED]; + unsigned int NumberSlotsInDB = 0; ++int event_support_disabled = 0; + + Slot_Info_t_64 *psinfo; + +@@ -467,6 +468,13 @@ static int slotmgr_key_vers(void *private, int tok, unsigned int vers) + return 1; + } + ++static void slotmgr_disab_event_supp(void *private) ++{ ++ UNUSED(private); ++ ++ event_support_disabled = 1; ++} ++ + static void slotmgr_parseerror(void *private, int line, const char *parsermsg) + { + struct parse_data *d = (struct parse_data *)private; +@@ -480,6 +488,7 @@ static struct parsefuncs slotmgr_parsefuncs = { + .end_slot = slotmgr_end_slot, + .key_str = slotmgr_key_str, + .key_vers = slotmgr_key_vers, ++ .disab_event_supp = slotmgr_disab_event_supp, + .parseerror = slotmgr_parseerror + }; + +@@ -568,7 +577,7 @@ int main(int argc, char *argv[], char *envp[]) + if (!XProcUnLock()) + return 4; + +- if (!init_socket_server()) { ++ if (!init_socket_server(event_support_disabled)) { + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); +@@ -582,6 +591,8 @@ int main(int argc, char *argv[], char *envp[]) + DestroySharedMemory(); + return 6; + } ++ if (event_support_disabled) ++ socketData.flags |= FLAG_EVENT_SUPPORT_DISABLED; + + /* Create customized token directories */ + psinfo = &socketData.slot_info[0]; +diff --git a/usr/sbin/pkcsslotd/socket_server.c b/usr/sbin/pkcsslotd/socket_server.c +index 41408670..3aa40267 100644 +--- a/usr/sbin/pkcsslotd/socket_server.c ++++ b/usr/sbin/pkcsslotd/socket_server.c +@@ -139,12 +139,12 @@ struct event_info { + }; + + static int epoll_fd = -1; +-static struct listener_info proc_listener; ++static struct listener_info proc_listener = { .socket = -1 }; + static DL_NODE *proc_connections = NULL; +-static struct listener_info admin_listener; ++static struct listener_info admin_listener = { .socket = -1 }; + static DL_NODE *admin_connections = NULL; + #ifdef WITH_LIBUDEV +-static struct udev_mon udev_mon; ++static struct udev_mon udev_mon = { .socket = -1 }; + #endif + static DL_NODE *pending_events = NULL; + static unsigned long pending_events_count = 0; +@@ -1620,6 +1620,9 @@ static void udev_mon_term(struct udev_mon *udev_mon) + if (udev_mon == NULL) + return; + ++ if (udev_mon->socket < 0) ++ return; ++ + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, udev_mon->socket, NULL); + if (udev_mon->udev != NULL) + udev_unref(udev_mon->udev); +@@ -1636,6 +1639,7 @@ int init_socket_data(Slot_Mgr_Socket_t *socketData) + { + unsigned int processed = 0; + ++ socketData->flags = 0; + PopulateCKInfo(&(socketData->ck_info)); + socketData->num_slots = NumberSlotsInDB; + PopulateSlotInfo(socketData->slot_info, &processed); +@@ -1692,7 +1696,7 @@ int socket_connection_handler(int timeout_secs) + return TRUE; + } + +-int init_socket_server() ++int init_socket_server(int event_support_disabled) + { + int err; + +@@ -1710,18 +1714,20 @@ int init_socket_server() + return FALSE; + } + +- if (!listener_create(ADMIN_SOCKET_FILE_PATH, &admin_listener, +- admin_new_conn, NUMBER_ADMINS_ALLOWED)) { +- term_socket_server(); +- return FALSE; +- } ++ if (!event_support_disabled) { ++ if (!listener_create(ADMIN_SOCKET_FILE_PATH, &admin_listener, ++ admin_new_conn, NUMBER_ADMINS_ALLOWED)) { ++ term_socket_server(); ++ return FALSE; ++ } + + #ifdef WITH_LIBUDEV +- if (!udev_mon_init(UDEV_SUBSYSTEM_AP, &udev_mon)) { +- term_socket_server(); +- return FALSE; +- } ++ if (!udev_mon_init(UDEV_SUBSYSTEM_AP, &udev_mon)) { ++ term_socket_server(); ++ return FALSE; ++ } + #endif ++ } + + DbgLog(DL0, "%s: Socket server started", __func__); + +diff --git a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c +index 7c225730..94fd1196 100644 +--- a/usr/sbin/pkcstok_migrate/pkcstok_migrate.c ++++ b/usr/sbin/pkcstok_migrate/pkcstok_migrate.c +@@ -2066,6 +2066,13 @@ static int parseupdate_ockversion(void *private, const char *version) + return 0; + } + ++static void parseupdate_disab_event_supp(void *private) ++{ ++ struct parseupdate *u = (struct parseupdate *)private; ++ ++ fprintf(u->f, "disable-event-support"); ++} ++ + static void parseupdate_eol(void *private) + { + struct parseupdate *u = (struct parseupdate *)private; +@@ -2124,6 +2131,7 @@ static void parseupdate_eolcomment(void *private, const char *comment) + + static struct parsefuncs parseupdatefuncs = { + .version = parseupdate_ockversion, ++ .disab_event_supp = parseupdate_disab_event_supp, + .eol = parseupdate_eol, + .begin_slot = parseupdate_begin_slot, + .end_slot = parseupdate_end_slot, diff --git a/opencryptoki-3.16.0-b048be548508dd1958bb7271568f388d0f6cbcf8.patch b/opencryptoki-3.16.0-b048be548508dd1958bb7271568f388d0f6cbcf8.patch new file mode 100644 index 0000000..fd0c13c --- /dev/null +++ b/opencryptoki-3.16.0-b048be548508dd1958bb7271568f388d0f6cbcf8.patch @@ -0,0 +1,1023 @@ +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 + }; diff --git a/opencryptoki-3.16.0-b07505993dd8b2f367cf3b630f6da186e4e8550d.patch b/opencryptoki-3.16.0-b07505993dd8b2f367cf3b630f6da186e4e8550d.patch new file mode 100644 index 0000000..6936783 --- /dev/null +++ b/opencryptoki-3.16.0-b07505993dd8b2f367cf3b630f6da186e4e8550d.patch @@ -0,0 +1,37 @@ +commit b07505993dd8b2f367cf3b630f6da186e4e8550d +Author: Ingo Franzki +Date: Wed Feb 10 15:12:25 2021 +0100 + + Avoid deadlock in dlclose() after a fork + + Calling dlclose() in a atfork handler may cause a deadlock. + dlclose() may itself modify the atfork handler table to remove + any fork handlers that the to be unloaded library has registered. + Since the atfork handler table is currently locked when we are in + an atfork handler, this would produce a deadlock. + + Skip the dlclose() if we are in an atfork handler to avoid the deadlock. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/api/api_interface.c b/usr/lib/api/api_interface.c +index 3ccb6d41..f1ee9132 100644 +--- a/usr/lib/api/api_interface.c ++++ b/usr/lib/api/api_interface.c +@@ -1516,7 +1516,15 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) + } + } + +- DL_UnLoad(sltp, slotID); ++ /* ++ * Calling dlclose() in a atfork handler may cause a deadlock. ++ * dlclose() may itself modify the atfork handler table to remove ++ * any fork handlers that the to be unloaded library has registered. ++ * Since the atfork handler table is currently locked when we are in ++ * an atfork handler, this would produce a deadlock. ++ */ ++ if (!in_child_fork_initializer) ++ DL_UnLoad(sltp, slotID); + } + + // Un register from Slot D diff --git a/opencryptoki-3.16.0-bf812c652c49d7e248b115d121a4f7f6568941a2.patch b/opencryptoki-3.16.0-bf812c652c49d7e248b115d121a4f7f6568941a2.patch new file mode 100644 index 0000000..f5a7617 --- /dev/null +++ b/opencryptoki-3.16.0-bf812c652c49d7e248b115d121a4f7f6568941a2.patch @@ -0,0 +1,21 @@ +commit bf812c652c49d7e248b115d121a4f7f6568941a2 +Author: Ingo Franzki +Date: Tue Apr 6 13:41:55 2021 +0200 + + Update travis yaml file to install libudev development files + + Signed-off-by: Ingo Franzki + +diff --git a/.travis.yml b/.travis.yml +index d2907246..fd4092e3 100644 +--- a/.travis.yml ++++ b/.travis.yml +@@ -5,7 +5,7 @@ language: c + + before_install: + - sudo apt-get -qq update +- - sudo apt-get install -y expect trousers libldap2-dev libtspi-dev wget ++ - sudo apt-get install -y expect trousers libldap2-dev libtspi-dev wget libudev-dev + - sudo wget https://launchpad.net/ubuntu/+archive/primary/+files/libica3_3.4.0-0ubuntu1_s390x.deb + - sudo wget https://launchpad.net/ubuntu/+archive/primary/+files/libica-dev_3.4.0-0ubuntu1_s390x.deb + - sudo dpkg -i libica3_3.4.0-0ubuntu1_s390x.deb || true # icatok needs libica >= 3.3 diff --git a/opencryptoki-3.16.0-c79e899d77a5724635a9d4451a34a240e2c7e891.patch b/opencryptoki-3.16.0-c79e899d77a5724635a9d4451a34a240e2c7e891.patch new file mode 100644 index 0000000..d515e15 --- /dev/null +++ b/opencryptoki-3.16.0-c79e899d77a5724635a9d4451a34a240e2c7e891.patch @@ -0,0 +1,462 @@ +commit c79e899d77a5724635a9d4451a34a240e2c7e891 +Author: Ingo Franzki +Date: Fri Apr 16 13:41:41 2021 +0200 + + Fix potential deadlock situation with double read-locks + + Do not get and read-lock an object twice within the same thread via + function object_mgr_find_in_map1(), as this would read-lock the object + twice. + + This could cause a deadlock situation, when in-between the first + and the second call to object_mgr_find_in_map1() the token object is + modified by another process. The second object_mgr_find_in_map1() would + detect that the object has been modified (object_mgr_check_shm()), and + would try to re-load the object from the disk. For re-loading, the + object is unlocked once, and a write-lock is acquired instead. + However, if the current thread has read-locked the object twice, but + releases only one read-lock, then it will never get the write lock, + because it still owns the read lock itself. + + To avoid this situation, release the read-lock before calling another + function that also acquires the read lock of the object. That way, only + one read-lock is held by the current thread, and re-loading the object + will not cause a deadlock. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/common/decr_mgr.c b/usr/lib/common/decr_mgr.c +index 317ef995..9842302b 100644 +--- a/usr/lib/common/decr_mgr.c ++++ b/usr/lib/common/decr_mgr.c +@@ -540,6 +540,10 @@ CK_RV decr_mgr_init(STDLL_TokData_t *tokdata, + } + memset(ctx->context, 0x0, sizeof(AES_GCM_CONTEXT)); + ++ /* Release obj lock, token specific aes-gcm may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = aes_gcm_init(tokdata, sess, ctx, mech, key_handle, 0); + if (rc) { + TRACE_ERROR("Could not initialize AES_GCM parms.\n"); +diff --git a/usr/lib/common/encr_mgr.c b/usr/lib/common/encr_mgr.c +index d3ecdeee..3e85ceab 100644 +--- a/usr/lib/common/encr_mgr.c ++++ b/usr/lib/common/encr_mgr.c +@@ -537,6 +537,10 @@ CK_RV encr_mgr_init(STDLL_TokData_t *tokdata, + } + memset(ctx->context, 0x0, sizeof(AES_GCM_CONTEXT)); + ++ /* Release obj lock, token specific aes-gcm may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = aes_gcm_init(tokdata, sess, ctx, mech, key_handle, 1); + if (rc != CKR_OK) { + TRACE_ERROR("Could not initialize AES_GCM parms.\n"); +diff --git a/usr/lib/common/mech_rsa.c b/usr/lib/common/mech_rsa.c +index 1652f90a..e35b383c 100644 +--- a/usr/lib/common/mech_rsa.c ++++ b/usr/lib/common/mech_rsa.c +@@ -602,6 +602,10 @@ CK_RV rsa_oaep_crypt(STDLL_TokData_t *tokdata, SESSION *sess, + goto done; + } + ++ /* Release obj lock, token specific rsa-oaep may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = token_specific.t_rsa_oaep_encrypt(tokdata, ctx, in_data, + in_data_len, out_data, + out_data_len, hash, hlen); +@@ -625,6 +629,10 @@ CK_RV rsa_oaep_crypt(STDLL_TokData_t *tokdata, SESSION *sess, + goto done; + } + ++ /* Release obj lock, token specific rsa-oaep may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = token_specific.t_rsa_oaep_decrypt(tokdata, ctx, in_data, + in_data_len, out_data, + out_data_len, hash, hlen); +@@ -1331,6 +1339,10 @@ CK_RV rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess, + goto done; + } + ++ /* Release obj lock, token specific rsa_pss may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = token_specific.t_rsa_pss_sign(tokdata, sess, ctx, in_data, in_data_len, + out_data, out_data_len); + if (rc != CKR_OK) +@@ -1389,6 +1401,10 @@ CK_RV rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess, + goto done; + } + ++ /* Release obj lock, token specific rsa_pss may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = token_specific.t_rsa_pss_verify(tokdata, sess, ctx, in_data, + in_data_len, signature, sig_len); + if (rc != CKR_OK) +diff --git a/usr/lib/common/sign_mgr.c b/usr/lib/common/sign_mgr.c +index 937a371a..c7268e01 100644 +--- a/usr/lib/common/sign_mgr.c ++++ b/usr/lib/common/sign_mgr.c +@@ -424,6 +424,10 @@ CK_RV sign_mgr_init(STDLL_TokData_t *tokdata, + ctx->context_len = 0; + ctx->context = NULL; + ++ /* Release obj lock, token specific hmac-sign may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = hmac_sign_init(tokdata, sess, mech, key); + if (rc != CKR_OK) { + TRACE_ERROR("Failed to initialize hmac.\n"); +diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c +index 3ac3768a..52f95d7a 100644 +--- a/usr/lib/ep11_stdll/ep11_specific.c ++++ b/usr/lib/ep11_stdll/ep11_specific.c +@@ -6948,6 +6948,13 @@ CK_RV ep11tok_sign_init(STDLL_TokData_t * tokdata, SESSION * session, + rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); + switch (rc) { + case CKR_OK: ++ /* ++ * Release obj lock, sign_mgr_init or ep11tok_sign_verify_init_ibm_ed ++ * may re-acquire the lock ++ */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + /* Note that Edwards curves in general are not yet supported in + * opencryptoki. These two special IBM specific ED mechs are only + * supported by the ep11token, so let's keep them local here. */ +@@ -7029,11 +7036,16 @@ CK_RV ep11tok_sign(STDLL_TokData_t * tokdata, SESSION * session, + * opencryptoki. These two special IBM specific ED mechs are only + * supported by the ep11token, so let's keep them local here. */ + if (ctx->mech.mechanism == CKM_IBM_ED25519_SHA512 || +- ctx->mech.mechanism == CKM_IBM_ED448_SHA3) ++ ctx->mech.mechanism == CKM_IBM_ED448_SHA3) { + rc = pkey_ibm_ed_sign(key_obj, in_data, in_data_len, signature, sig_len); +- else ++ } else { ++ /* Release obj lock, sign_mgr_sign may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = sign_mgr_sign(tokdata, session, length_only, ctx, in_data, + in_data_len, signature, sig_len); ++ } + goto done; /* no ep11 fallback possible */ + } + +@@ -7071,6 +7083,11 @@ CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, + if (!in_data || !in_data_len) + return CKR_OK; + ++ if (ctx->pkey_active) { ++ rc = sign_mgr_sign_update(tokdata, session, ctx, in_data, in_data_len); ++ goto done; /* no ep11 fallback possible */ ++ } ++ + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { +@@ -7078,11 +7095,6 @@ CK_RV ep11tok_sign_update(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- if (ctx->pkey_active) { +- rc = sign_mgr_sign_update(tokdata, session, ctx, in_data, in_data_len); +- goto done; /* no ep11 fallback possible */ +- } +- + RETRY_START + rc = dll_m_SignUpdate(ctx->context, ctx->context_len, in_data, + in_data_len, ep11_data->target); +@@ -7115,6 +7127,11 @@ CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ++ if (ctx->pkey_active) { ++ rc = sign_mgr_sign_final(tokdata, session, length_only, ctx, signature, sig_len); ++ goto done; /* no ep11 fallback possible */ ++ } ++ + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { +@@ -7122,11 +7139,6 @@ CK_RV ep11tok_sign_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- if (ctx->pkey_active) { +- rc = sign_mgr_sign_final(tokdata, session, length_only, ctx, signature, sig_len); +- goto done; /* no ep11 fallback possible */ +- } +- + RETRY_START + rc = dll_m_SignFinal(ctx->context, ctx->context_len, signature, sig_len, + ep11_data->target); +@@ -7241,6 +7253,13 @@ CK_RV ep11tok_verify_init(STDLL_TokData_t * tokdata, SESSION * session, + rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); + switch (rc) { + case CKR_OK: ++ /* ++ * Release obj lock, verify_mgr_init or ep11tok_sign_verify_init_ibm_ed ++ * may re-acquire the lock ++ */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + /* Note that Edwards curves in general are not yet supported in + * opencryptoki. These two special IBM specific ED mechs are only + * supported by the ep11token, so let's keep them local here. */ +@@ -7320,12 +7339,17 @@ CK_RV ep11tok_verify(STDLL_TokData_t * tokdata, SESSION * session, + * opencryptoki. These two special IBM specific ED mechs are only + * supported by the ep11token, so let's keep them local here. */ + if (ctx->mech.mechanism == CKM_IBM_ED25519_SHA512 || +- ctx->mech.mechanism == CKM_IBM_ED448_SHA3) ++ ctx->mech.mechanism == CKM_IBM_ED448_SHA3) { + rc = pkey_ibm_ed_verify(key_obj, in_data, in_data_len, + signature, sig_len); +- else ++ } else { ++ /* Release obj lock, verify_mgr_verify may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + rc = verify_mgr_verify(tokdata, session, ctx, in_data, + in_data_len, signature, sig_len); ++ } + goto done; /* no ep11 fallback possible */ + } + +@@ -7363,6 +7387,11 @@ CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, + if (!in_data || !in_data_len) + return CKR_OK; + ++ if (ctx->pkey_active) { ++ rc = verify_mgr_verify_update(tokdata, session, ctx, in_data, in_data_len); ++ goto done; /* no ep11 fallback possible */ ++ } ++ + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { +@@ -7370,11 +7399,6 @@ CK_RV ep11tok_verify_update(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- if (ctx->pkey_active) { +- rc = verify_mgr_verify_update(tokdata, session, ctx, in_data, in_data_len); +- goto done; /* no ep11 fallback possible */ +- } +- + RETRY_START + rc = dll_m_VerifyUpdate(ctx->context, ctx->context_len, in_data, + in_data_len, ep11_data->target); +@@ -7406,6 +7430,11 @@ CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ++ if (ctx->pkey_active) { ++ rc = verify_mgr_verify_final(tokdata, session, ctx, signature, sig_len); ++ goto done; /* no ep11 fallback possible */ ++ } ++ + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { +@@ -7413,11 +7442,6 @@ CK_RV ep11tok_verify_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- if (ctx->pkey_active) { +- rc = verify_mgr_verify_final(tokdata, session, ctx, signature, sig_len); +- goto done; /* no ep11 fallback possible */ +- } +- + RETRY_START + rc = dll_m_VerifyFinal(ctx->context, ctx->context_len, signature, + sig_len, ep11_data->target); +@@ -7501,6 +7525,12 @@ CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ++ if (ctx->pkey_active) { ++ rc = decr_mgr_decrypt_final(tokdata, session, length_only, ++ ctx, output_part, p_output_part_len); ++ goto done; /* no ep11 fallback possible */ ++ } ++ + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { +@@ -7508,12 +7538,6 @@ CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- if (ctx->pkey_active) { +- rc = decr_mgr_decrypt_final(tokdata, session, length_only, +- ctx, output_part, p_output_part_len); +- goto done; /* no ep11 fallback possible */ +- } +- + RETRY_START + rc = dll_m_DecryptFinal(ctx->context, ctx->context_len, + output_part, p_output_part_len, +@@ -7548,13 +7572,6 @@ CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + +- rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, +- READ_LOCK); +- if (rc != CKR_OK) { +- TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); +- return rc; +- } +- + if (ctx->pkey_active) { + rc = decr_mgr_decrypt(tokdata, session, length_only, ctx, + input_data, input_data_len, output_data, +@@ -7562,6 +7579,13 @@ CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, + goto done; /* no ep11 fallback possible */ + } + ++ rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, ++ READ_LOCK); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); ++ return rc; ++ } ++ + RETRY_START + rc = dll_m_Decrypt(ctx->context, ctx->context_len, input_data, + input_data_len, output_data, p_output_data_len, +@@ -7602,13 +7626,6 @@ CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + return CKR_OK; /* nothing to update, keep context */ + } + +- rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, +- READ_LOCK); +- if (rc != CKR_OK) { +- TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); +- return rc; +- } +- + if (ctx->pkey_active) { + rc = decr_mgr_decrypt_update(tokdata, session, length_only, + ctx, input_part, input_part_len, +@@ -7616,6 +7633,13 @@ CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + goto done; /* no ep11 fallback possible */ + } + ++ rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, ++ READ_LOCK); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); ++ return rc; ++ } ++ + RETRY_START + rc = dll_m_DecryptUpdate(ctx->context, ctx->context_len, + input_part, input_part_len, output_part, +@@ -7695,6 +7719,12 @@ CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + ++ if (ctx->pkey_active) { ++ rc = encr_mgr_encrypt_final(tokdata, session, length_only, ++ ctx, output_part, p_output_part_len); ++ goto done; /* no ep11 fallback possible */ ++ } ++ + rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, + READ_LOCK); + if (rc != CKR_OK) { +@@ -7702,12 +7732,6 @@ CK_RV ep11tok_encrypt_final(STDLL_TokData_t * tokdata, SESSION * session, + return rc; + } + +- if (ctx->pkey_active) { +- rc = encr_mgr_encrypt_final(tokdata, session, length_only, +- ctx, output_part, p_output_part_len); +- goto done; /* no ep11 fallback possible */ +- } +- + RETRY_START + rc = dll_m_EncryptFinal(ctx->context, ctx->context_len, + output_part, p_output_part_len, +@@ -7742,13 +7766,6 @@ CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session, + CK_BYTE *keyblob; + OBJECT *key_obj = NULL; + +- rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, +- READ_LOCK); +- if (rc != CKR_OK) { +- TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); +- return rc; +- } +- + if (ctx->pkey_active) { + rc = encr_mgr_encrypt(tokdata, session, length_only, ctx, + input_data, input_data_len, output_data, +@@ -7756,6 +7773,13 @@ CK_RV ep11tok_encrypt(STDLL_TokData_t * tokdata, SESSION * session, + goto done; /* no ep11 fallback possible */ + } + ++ rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, ++ READ_LOCK); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); ++ return rc; ++ } ++ + RETRY_START + rc = dll_m_Encrypt(ctx->context, ctx->context_len, input_data, + input_data_len, output_data, p_output_data_len, +@@ -7796,13 +7820,6 @@ CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + return CKR_OK; /* nothing to update, keep context */ + } + +- rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, +- READ_LOCK); +- if (rc != CKR_OK) { +- TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); +- return rc; +- } +- + if (ctx->pkey_active) { + rc = encr_mgr_encrypt_update(tokdata, session, length_only, ctx, + input_part, input_part_len, output_part, +@@ -7810,6 +7827,13 @@ CK_RV ep11tok_encrypt_update(STDLL_TokData_t * tokdata, SESSION * session, + goto done; /* no ep11 fallback possible */ + } + ++ rc = h_opaque_2_blob(tokdata, ctx->key, &keyblob, &keyblobsize, &key_obj, ++ READ_LOCK); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("%s h_opaque_2_blob, rc=0x%lx\n", __func__, rc); ++ return rc; ++ } ++ + RETRY_START + rc = dll_m_EncryptUpdate(ctx->context, ctx->context_len, + input_part, input_part_len, output_part, +@@ -7921,6 +7945,10 @@ static CK_RV ep11_ende_crypt_init(STDLL_TokData_t * tokdata, SESSION * session, + rc = ep11tok_pkey_check(tokdata, session, key_obj, mech); + switch (rc) { + case CKR_OK: ++ /* Release obj lock, encr/decr_mgr_init may re-acquire the lock */ ++ object_put(tokdata, key_obj, TRUE); ++ key_obj = NULL; ++ + if (op == DECRYPT) { + rc = decr_mgr_init(tokdata, session, &session->decr_ctx, + OP_DECRYPT_INIT, mech, key); diff --git a/opencryptoki-3.16.0-d7de5092247a0efc2c397f12977a7c9925420143.patch b/opencryptoki-3.16.0-d7de5092247a0efc2c397f12977a7c9925420143.patch new file mode 100644 index 0000000..40a4962 --- /dev/null +++ b/opencryptoki-3.16.0-d7de5092247a0efc2c397f12977a7c9925420143.patch @@ -0,0 +1,239 @@ +commit d7de5092247a0efc2c397f12977a7c9925420143 +Author: Ingo Franzki +Date: Tue Feb 16 17:15:20 2021 +0100 + + TESTCASES: Add event support tests + + Signed-off-by: Ingo Franzki + +diff --git a/testcases/misc_tests/events.c b/testcases/misc_tests/events.c +new file mode 100644 +index 00000000..fecc7bfe +--- /dev/null ++++ b/testcases/misc_tests/events.c +@@ -0,0 +1,190 @@ ++/* ++ * 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 "event_client.h" ++#include "regress.h" ++#include "defs.h" ++ ++const char payload[20] = "12345678901234567890"; ++ ++static inline void init_event_destination(struct event_destination *dest, ++ unsigned int token_type, ++ const char *label, ++ pid_t process_id) ++{ ++ size_t len; ++ ++ dest->token_type = token_type; ++ dest->process_id = process_id; ++ ++ memset(dest->token_label, ' ', sizeof(dest->token_label)); ++ if (label != NULL) { ++ len = strlen(label); ++ memcpy(dest->token_label, label, len > sizeof(dest->token_label) ? ++ sizeof(dest->token_label) : len); ++ } ++} ++ ++int main(int argc, char **argv) ++{ ++ CK_C_INITIALIZE_ARGS cinit_args; ++ int rc, fd = -1, ret = 1; ++ struct event_destination dest; ++ struct event_reply reply; ++ ++ UNUSED(argc); ++ UNUSED(argv); ++ ++ rc = do_GetFunctionList(); ++ if (!rc) { ++ testcase_error("do_getFunctionList(), rc=%s", p11_get_ckr(rc)); ++ return rc; ++ } ++ ++ /* ++ * Initialize Opencryptoki in this process, so that at least one ++ * process is receiving the events. ++ */ ++ memset(&cinit_args, 0x0, sizeof(cinit_args)); ++ cinit_args.flags = CKF_OS_LOCKING_OK; ++ funcs->C_Initialize(&cinit_args); ++ ++ testcase_setup(0); ++ testcase_begin("Starting event tests"); ++ ++ // Test fork before C_Initialize ++ testcase_new_assertion(); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, NULL, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (simple, one-shot) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (simple, one-shot)"); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, sizeof(payload), payload, ++ NULL, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (payload, one-shot) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (payload, one-shot)"); ++ ++ init_event_destination(&dest, EVENT_TOK_TYPE_CCA, NULL, 0); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, &dest, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (token-type, one-shot) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (token-type, one-shot)"); ++ ++ init_event_destination(&dest, EVENT_TOK_TYPE_ALL, "cca", 0); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, &dest, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (token-label, one-shot) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (token-label, one-shot)"); ++ ++ init_event_destination(&dest, EVENT_TOK_TYPE_ALL, NULL, 12345); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_NONE, 0, NULL, &dest, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (pid, one-shot) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (pid, one-shot)"); ++ ++ memset(&reply, 0, sizeof(reply)); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_REPLY_REQ, 0, NULL, NULL, &reply); ++ if (rc != 0) { ++ testcase_fail("send_event (reply, one-shot) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ printf("Reply: positive_replies: %lu\n", reply.positive_replies); ++ printf(" negative_replies: %lu\n", reply.negative_replies); ++ printf(" nothandled_replies: %lu\n", reply.nothandled_replies); ++ if (reply.positive_replies + reply.negative_replies + ++ reply.nothandled_replies == 0) { ++ testcase_fail("send_event (reply, one-shot) replies all zero"); ++ goto out; ++ } ++ testcase_pass("send_event (reply, one-shot)"); ++ ++ ++ fd = init_event_client(); ++ if (fd < 0) { ++ testcase_fail("init_event_client rc = %d (%s)", fd, strerror(-fd)); ++ goto out; ++ } ++ testcase_pass("init_event_client()"); ++ ++ rc = send_event(fd, 0x12345, EVENT_FLAGS_NONE, 0, NULL, NULL, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (simple) rc = %d (%s)", rc, strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (simple)"); ++ ++ rc = send_event(fd, 0x12345, EVENT_FLAGS_NONE, sizeof(payload), payload, ++ NULL, NULL); ++ if (rc != 0) { ++ testcase_fail("send_event (payload) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ testcase_pass("send_event (payload)"); ++ ++ memset(&reply, 0, sizeof(reply)); ++ ++ rc = send_event(-1, 0x12345, EVENT_FLAGS_REPLY_REQ, 0, NULL, NULL, &reply); ++ if (rc != 0) { ++ testcase_fail("send_event (reply) rc = %d (%s)", rc, ++ strerror(-rc)); ++ goto out; ++ } ++ printf("Reply: positive_replies: %lu\n", reply.positive_replies); ++ printf(" negative_replies: %lu\n", reply.negative_replies); ++ printf(" nothandled_replies: %lu\n", reply.nothandled_replies); ++ if (reply.positive_replies + reply.negative_replies + ++ reply.nothandled_replies == 0) { ++ testcase_fail("send_event (reply) replies all zero"); ++ goto out; ++ } ++ testcase_pass("send_event (reply)"); ++ ++ term_event_client(fd); ++ fd = -1; ++ ++ ret = 0; ++ ++out: ++ if (fd >= 0) ++ term_event_client(fd); ++ ++ funcs->C_Finalize(NULL); ++ ++ testcase_print_result(); ++ return ret; ++} +diff --git a/testcases/misc_tests/misc_tests.mk b/testcases/misc_tests/misc_tests.mk +index 3de11ebe..fb7cc0a1 100644 +--- a/testcases/misc_tests/misc_tests.mk ++++ b/testcases/misc_tests/misc_tests.mk +@@ -7,7 +7,8 @@ noinst_PROGRAMS += \ + testcases/misc_tests/fork testcases/misc_tests/multi_instance \ + testcases/misc_tests/obj_lock testcases/misc_tests/tok2tok_transport \ + testcases/misc_tests/obj_lock testcases/misc_tests/reencrypt \ +- testcases/misc_tests/cca_export_import_test ++ testcases/misc_tests/cca_export_import_test \ ++ testcases/misc_tests/events + + testcases_misc_tests_obj_mgmt_tests_CFLAGS = ${testcases_inc} + testcases_misc_tests_obj_mgmt_tests_LDADD = \ +@@ -73,3 +74,8 @@ testcases_misc_tests_cca_export_import_test_LDADD = \ + testcases/common/libcommon.la + testcases_misc_tests_cca_export_import_test_SOURCES = \ + testcases/misc_tests/cca_export_import_test.c ++ ++testcases_misc_tests_events_CFLAGS = ${testcases_inc} ++testcases_misc_tests_events_LDADD = testcases/common/libcommon.la ++testcases_misc_tests_events_SOURCES = testcases/misc_tests/events.c \ ++ usr/lib/common/event_client.c +diff --git a/testcases/ock_tests.sh.in b/testcases/ock_tests.sh.in +index 64c77a7d..6558b031 100755 +--- a/testcases/ock_tests.sh.in ++++ b/testcases/ock_tests.sh.in +@@ -53,6 +53,7 @@ OCK_TESTS+=" pkcs11/findobjects pkcs11/generate_keypair" + OCK_TESTS+=" pkcs11/get_interface pkcs11/getobjectsize pkcs11/sess_opstate" + OCK_TESTS+=" misc_tests/fork misc_tests/obj_mgmt_tests" + OCK_TESTS+=" misc_tests/obj_mgmt_lock_tests misc_tests/reencrypt" ++OCK_TESTS+=" misc_tests/events" + OCK_TEST="" + OCK_BENCHS="pkcs11/*bench" + diff --git a/opencryptoki-3.16.0-d929fe8470e99f4dcbbd889e7aa87e147d0d5b48.patch b/opencryptoki-3.16.0-d929fe8470e99f4dcbbd889e7aa87e147d0d5b48.patch new file mode 100644 index 0000000..5e9a346 --- /dev/null +++ b/opencryptoki-3.16.0-d929fe8470e99f4dcbbd889e7aa87e147d0d5b48.patch @@ -0,0 +1,619 @@ +commit d929fe8470e99f4dcbbd889e7aa87e147d0d5b48 +Author: Ingo Franzki +Date: Fri Feb 12 11:25:21 2021 +0100 + + Externalize linked list functions + + Externalize the linked list functions (dlist_xxx), so that they + can also be used on pkcsslotd. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/cca_stdll/cca_stdll.mk b/usr/lib/cca_stdll/cca_stdll.mk +index bd230b9f..c5e86fa7 100644 +--- a/usr/lib/cca_stdll/cca_stdll.mk ++++ b/usr/lib/cca_stdll/cca_stdll.mk +@@ -35,7 +35,8 @@ opencryptoki_stdll_libpkcs11_cca_la_SOURCES = \ + usr/lib/common/mech_ssl3.c usr/lib/common/verify_mgr.c \ + usr/lib/common/p11util.c usr/lib/common/sw_crypt.c \ + usr/lib/common/shared_memory.c usr/lib/common/profile_obj.c \ +- usr/lib/cca_stdll/cca_specific.c usr/lib/common/attributes.c ++ usr/lib/cca_stdll/cca_specific.c usr/lib/common/attributes.c \ ++ usr/lib/common/dlist.c + + if ENABLE_LOCKS + opencryptoki_stdll_libpkcs11_cca_la_SOURCES += \ +diff --git a/usr/lib/common/dlist.c b/usr/lib/common/dlist.c +new file mode 100644 +index 00000000..1fee1ea9 +--- /dev/null ++++ b/usr/lib/common/dlist.c +@@ -0,0 +1,218 @@ ++/* ++ * 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 ++#include ++ ++#include "dlist.h" ++#include "host_defs.h" ++#include "h_extern.h" ++ ++ ++// Function: dlist_add_as_first() ++// ++// Adds the specified node to the start of the list ++// ++// Returns: pointer to the start of the list ++// ++DL_NODE *dlist_add_as_first(DL_NODE *list, void *data) ++{ ++ DL_NODE *node = NULL; ++ ++ if (!data) ++ return list; ++ ++ node = (DL_NODE *) malloc(sizeof(DL_NODE)); ++ if (!node) ++ return NULL; ++ ++ node->data = data; ++ node->prev = NULL; ++ node->next = list; ++ if (list) ++ list->prev = node; ++ ++ return node; ++} ++ ++// Function: dlist_add_as_last() ++// ++// Adds the specified node to the end of the list ++// ++// Returns: pointer to the start of the list ++// ++DL_NODE *dlist_add_as_last(DL_NODE *list, void *data) ++{ ++ DL_NODE *node = NULL; ++ ++ if (!data) ++ return list; ++ ++ node = (DL_NODE *) malloc(sizeof(DL_NODE)); ++ if (!node) ++ return NULL; ++ ++ node->data = data; ++ node->next = NULL; ++ ++ if (!list) { ++ node->prev = NULL; ++ return node; ++ } else { ++ DL_NODE *temp = dlist_get_last(list); ++ temp->next = node; ++ node->prev = temp; ++ ++ return list; ++ } ++} ++ ++// Function: dlist_find() ++// ++DL_NODE *dlist_find(DL_NODE *list, void *data) ++{ ++ DL_NODE *node = list; ++ ++ while (node && node->data != data) ++ node = node->next; ++ ++ return node; ++} ++ ++// Function: dlist_get_first() ++// ++// Returns the last node in the list or NULL if list is empty ++// ++DL_NODE *dlist_get_first(DL_NODE *list) ++{ ++ DL_NODE *temp = list; ++ ++ if (!list) ++ return NULL; ++ ++ while (temp->prev != NULL) ++ temp = temp->prev; ++ ++ return temp; ++} ++ ++// Function: dlist_get_last() ++// ++// Returns the last node in the list or NULL if list is empty ++// ++DL_NODE *dlist_get_last(DL_NODE *list) ++{ ++ DL_NODE *temp = list; ++ ++ if (!list) ++ return NULL; ++ ++ while (temp->next != NULL) ++ temp = temp->next; ++ ++ return temp; ++} ++ ++// ++// ++CK_ULONG dlist_length(DL_NODE *list) ++{ ++ DL_NODE *temp = list; ++ CK_ULONG len = 0; ++ ++ while (temp) { ++ len++; ++ temp = temp->next; ++ } ++ ++ return len; ++} ++ ++// ++// ++DL_NODE *dlist_next(DL_NODE *node) ++{ ++ if (!node) ++ return NULL; ++ ++ return node->next; ++} ++ ++// ++// ++DL_NODE *dlist_prev(DL_NODE *node) ++{ ++ if (!node) ++ return NULL; ++ ++ return node->prev; ++} ++ ++// ++// ++void dlist_purge(DL_NODE *list) ++{ ++ DL_NODE *node; ++ ++ if (!list) ++ return; ++ ++ do { ++ node = list->next; ++ free(list); ++ list = node; ++ } while (list); ++} ++ ++// Function: dlist_remove_node() ++// ++// Attempts to remove the specified node from the list. The caller is ++// responsible for freeing the data associated with the node prior to ++// calling this routine ++// ++DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node) ++{ ++ DL_NODE *temp = list; ++ ++ if (!list || !node) ++ return NULL; ++ ++ // special case: removing head of the list ++ // ++ if (list == node) { ++ temp = list->next; ++ if (temp) ++ temp->prev = NULL; ++ ++ free(list); ++ return temp; ++ } ++ // we have no guarantee that the node is in the list ++ // so search through the list to find it ++ // ++ while ((temp != NULL) && (temp->next != node)) ++ temp = temp->next; ++ ++ if (temp != NULL) { ++ DL_NODE *next = node->next; ++ ++ temp->next = next; ++ if (next) ++ next->prev = temp; ++ ++ free(node); ++ } ++ ++ return list; ++} +diff --git a/usr/lib/common/dlist.h b/usr/lib/common/dlist.h +new file mode 100644 +index 00000000..eda4af9c +--- /dev/null ++++ b/usr/lib/common/dlist.h +@@ -0,0 +1,32 @@ ++/* ++ * 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 ++ */ ++ ++ ++ ++#ifndef _DLIST_H_ ++#define _DLIST_H_ ++ ++#include "pkcs11types.h" ++#include "defs.h" ++ ++// linked-list routines ++// ++DL_NODE *dlist_add_as_first(DL_NODE *list, void *data); ++DL_NODE *dlist_add_as_last(DL_NODE *list, void *data); ++DL_NODE *dlist_find(DL_NODE *list, void *data); ++DL_NODE *dlist_get_first(DL_NODE *list); ++DL_NODE *dlist_get_last(DL_NODE *list); ++CK_ULONG dlist_length(DL_NODE *list); ++DL_NODE *dlist_next(DL_NODE *list); ++DL_NODE *dlist_prev(DL_NODE *list); ++void dlist_purge(DL_NODE *list); ++DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node); ++ ++#endif +diff --git a/usr/lib/common/h_extern.h b/usr/lib/common/h_extern.h +index 63aff79f..5e251d95 100644 +--- a/usr/lib/common/h_extern.h ++++ b/usr/lib/common/h_extern.h +@@ -24,6 +24,7 @@ + #define _H_EXTERN_H + + #include ++#include "dlist.h" + + // global variables + // +@@ -1759,19 +1760,6 @@ int ec_point_from_public_data(const CK_BYTE *data, CK_ULONG data_len, + CK_BBOOL *allocated, CK_BYTE **ec_point, + CK_ULONG *ec_point_len); + +-// linked-list routines +-// +-DL_NODE *dlist_add_as_first(DL_NODE *list, void *data); +-DL_NODE *dlist_add_as_last(DL_NODE *list, void *data); +-DL_NODE *dlist_find(DL_NODE *list, void *data); +-DL_NODE *dlist_get_first(DL_NODE *list); +-DL_NODE *dlist_get_last(DL_NODE *list); +-CK_ULONG dlist_length(DL_NODE *list); +-DL_NODE *dlist_next(DL_NODE *list); +-DL_NODE *dlist_prev(DL_NODE *list); +-void dlist_purge(DL_NODE *list); +-DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node); +- + CK_RV attach_shm(STDLL_TokData_t *tokdata, CK_SLOT_ID slot_id); + CK_RV detach_shm(STDLL_TokData_t *tokdata, CK_BBOOL ignore_ref_count); + +diff --git a/usr/lib/common/utility.c b/usr/lib/common/utility.c +index 38d8d959..b2c6ee50 100644 +--- a/usr/lib/common/utility.c ++++ b/usr/lib/common/utility.c +@@ -40,203 +40,6 @@ + #include + #include + +-// Function: dlist_add_as_first() +-// +-// Adds the specified node to the start of the list +-// +-// Returns: pointer to the start of the list +-// +-DL_NODE *dlist_add_as_first(DL_NODE *list, void *data) +-{ +- DL_NODE *node = NULL; +- +- if (!data) +- return list; +- +- node = (DL_NODE *) malloc(sizeof(DL_NODE)); +- if (!node) +- return NULL; +- +- node->data = data; +- node->prev = NULL; +- node->next = list; +- if (list) +- list->prev = node; +- +- return node; +-} +- +-// Function: dlist_add_as_last() +-// +-// Adds the specified node to the end of the list +-// +-// Returns: pointer to the start of the list +-// +-DL_NODE *dlist_add_as_last(DL_NODE *list, void *data) +-{ +- DL_NODE *node = NULL; +- +- if (!data) +- return list; +- +- node = (DL_NODE *) malloc(sizeof(DL_NODE)); +- if (!node) +- return NULL; +- +- node->data = data; +- node->next = NULL; +- +- if (!list) { +- node->prev = NULL; +- return node; +- } else { +- DL_NODE *temp = dlist_get_last(list); +- temp->next = node; +- node->prev = temp; +- +- return list; +- } +-} +- +-// Function: dlist_find() +-// +-DL_NODE *dlist_find(DL_NODE *list, void *data) +-{ +- DL_NODE *node = list; +- +- while (node && node->data != data) +- node = node->next; +- +- return node; +-} +- +-// Function: dlist_get_first() +-// +-// Returns the last node in the list or NULL if list is empty +-// +-DL_NODE *dlist_get_first(DL_NODE *list) +-{ +- DL_NODE *temp = list; +- +- if (!list) +- return NULL; +- +- while (temp->prev != NULL) +- temp = temp->prev; +- +- return temp; +-} +- +-// Function: dlist_get_last() +-// +-// Returns the last node in the list or NULL if list is empty +-// +-DL_NODE *dlist_get_last(DL_NODE *list) +-{ +- DL_NODE *temp = list; +- +- if (!list) +- return NULL; +- +- while (temp->next != NULL) +- temp = temp->next; +- +- return temp; +-} +- +-// +-// +-CK_ULONG dlist_length(DL_NODE *list) +-{ +- DL_NODE *temp = list; +- CK_ULONG len = 0; +- +- while (temp) { +- len++; +- temp = temp->next; +- } +- +- return len; +-} +- +-// +-// +-DL_NODE *dlist_next(DL_NODE *node) +-{ +- if (!node) +- return NULL; +- +- return node->next; +-} +- +-// +-// +-DL_NODE *dlist_prev(DL_NODE *node) +-{ +- if (!node) +- return NULL; +- +- return node->prev; +-} +- +-// +-// +-void dlist_purge(DL_NODE *list) +-{ +- DL_NODE *node; +- +- if (!list) +- return; +- +- do { +- node = list->next; +- free(list); +- list = node; +- } while (list); +-} +- +-// Function: dlist_remove_node() +-// +-// Attempts to remove the specified node from the list. The caller is +-// responsible for freeing the data associated with the node prior to +-// calling this routine +-// +-DL_NODE *dlist_remove_node(DL_NODE *list, DL_NODE *node) +-{ +- DL_NODE *temp = list; +- +- if (!list || !node) +- return NULL; +- +- // special case: removing head of the list +- // +- if (list == node) { +- temp = list->next; +- if (temp) +- temp->prev = NULL; +- +- free(list); +- return temp; +- } +- // we have no guarantee that the node is in the list +- // so search through the list to find it +- // +- while ((temp != NULL) && (temp->next != node)) +- temp = temp->next; +- +- if (temp != NULL) { +- DL_NODE *next = node->next; +- +- temp->next = next; +- if (next) +- next->prev = temp; +- +- free(node); +- } +- +- return list; +-} +- + CK_RV CreateXProcLock(char *tokname, STDLL_TokData_t *tokdata) + { + char lockfile[PATH_MAX]; +diff --git a/usr/lib/ep11_stdll/ep11_stdll.mk b/usr/lib/ep11_stdll/ep11_stdll.mk +index bc617124..b5574d9e 100644 +--- a/usr/lib/ep11_stdll/ep11_stdll.mk ++++ b/usr/lib/ep11_stdll/ep11_stdll.mk +@@ -36,7 +36,7 @@ opencryptoki_stdll_libpkcs11_ep11_la_SOURCES = \ + usr/lib/common/utility.c usr/lib/common/trace.c \ + usr/lib/common/mech_list.c usr/lib/common/shared_memory.c \ + usr/lib/common/attributes.c usr/lib/common/sw_crypt.c \ +- usr/lib/common/profile_obj.c \ ++ usr/lib/common/profile_obj.c usr/lib/common/dlist.c \ + usr/lib/common/pkey_utils.c \ + usr/lib/ep11_stdll/new_host.c usr/lib/ep11_stdll/ep11_specific.c + +diff --git a/usr/lib/ica_s390_stdll/ica_s390_stdll.mk b/usr/lib/ica_s390_stdll/ica_s390_stdll.mk +index d8448486..8f467e11 100644 +--- a/usr/lib/ica_s390_stdll/ica_s390_stdll.mk ++++ b/usr/lib/ica_s390_stdll/ica_s390_stdll.mk +@@ -34,7 +34,7 @@ opencryptoki_stdll_libpkcs11_ica_la_SOURCES = \ + usr/lib/common/verify_mgr.c usr/lib/common/trace.c \ + usr/lib/common/mech_list.c usr/lib/common/shared_memory.c \ + usr/lib/common/profile_obj.c usr/lib/common/attributes.c \ +- usr/lib/ica_s390_stdll/ica_specific.c ++ usr/lib/ica_s390_stdll/ica_specific.c usr/lib/common/dlist.c + + if ENABLE_LOCKS + opencryptoki_stdll_libpkcs11_ica_la_SOURCES += \ +diff --git a/usr/lib/icsf_stdll/icsf_stdll.mk b/usr/lib/icsf_stdll/icsf_stdll.mk +index 788478c2..21c64f9a 100644 +--- a/usr/lib/icsf_stdll/icsf_stdll.mk ++++ b/usr/lib/icsf_stdll/icsf_stdll.mk +@@ -43,7 +43,7 @@ opencryptoki_stdll_libpkcs11_icsf_la_SOURCES = \ + usr/lib/common/mech_ssl3.c usr/lib/common/verify_mgr.c \ + usr/lib/common/mech_list.c usr/lib/common/shared_memory.c \ + usr/lib/common/attributes.c usr/lib/icsf_stdll/new_host.c \ +- usr/lib/common/profile_obj.c \ ++ usr/lib/common/profile_obj.c usr/lib/common/dlist.c \ + usr/lib/icsf_stdll/pbkdf.c usr/lib/icsf_stdll/icsf_specific.c \ + usr/lib/icsf_stdll/icsf_config_parse.y \ + usr/lib/icsf_stdll/icsf_config_lexer.l \ +diff --git a/usr/lib/soft_stdll/soft_stdll.mk b/usr/lib/soft_stdll/soft_stdll.mk +index cea802b5..ac401539 100644 +--- a/usr/lib/soft_stdll/soft_stdll.mk ++++ b/usr/lib/soft_stdll/soft_stdll.mk +@@ -32,7 +32,8 @@ opencryptoki_stdll_libpkcs11_sw_la_SOURCES = \ + usr/lib/common/utility.c usr/lib/common/verify_mgr.c \ + usr/lib/common/trace.c usr/lib/common/mech_list.c \ + usr/lib/common/shared_memory.c usr/lib/common/profile_obj.c \ +- usr/lib/soft_stdll/soft_specific.c usr/lib/common/attributes.c ++ usr/lib/soft_stdll/soft_specific.c usr/lib/common/attributes.c \ ++ usr/lib/common/dlist.c + + if ENABLE_LOCKS + opencryptoki_stdll_libpkcs11_sw_la_SOURCES += \ +diff --git a/usr/lib/tpm_stdll/tpm_stdll.mk b/usr/lib/tpm_stdll/tpm_stdll.mk +index f199a103..0e0eb024 100644 +--- a/usr/lib/tpm_stdll/tpm_stdll.mk ++++ b/usr/lib/tpm_stdll/tpm_stdll.mk +@@ -34,7 +34,8 @@ opencryptoki_stdll_libpkcs11_tpm_la_SOURCES = \ + usr/lib/common/verify_mgr.c usr/lib/common/mech_list.c \ + usr/lib/common/shared_memory.c usr/lib/common/profile_obj.c \ + usr/lib/tpm_stdll/tpm_specific.c usr/lib/common/attributes.c \ +- usr/lib/tpm_stdll/tpm_openssl.c usr/lib/tpm_stdll/tpm_util.c ++ usr/lib/tpm_stdll/tpm_openssl.c usr/lib/tpm_stdll/tpm_util.c \ ++ usr/lib/common/dlist.c + + if ENABLE_LOCKS + opencryptoki_stdll_libpkcs11_tpm_la_SOURCES += \ +diff --git a/usr/sbin/pkcscca/pkcscca.mk b/usr/sbin/pkcscca/pkcscca.mk +index a223265f..cc40f819 100644 +--- a/usr/sbin/pkcscca/pkcscca.mk ++++ b/usr/sbin/pkcscca/pkcscca.mk +@@ -36,7 +36,7 @@ usr_sbin_pkcscca_pkcscca_SOURCES = \ + usr/lib/common/p11util.c usr/lib/common/sw_crypt.c \ + usr/lib/common/shared_memory.c usr/lib/common/profile_obj.c \ + usr/lib/common/attributes.c usr/lib/common/mech_rng.c \ +- usr/lib/common/pkcs_utils.c \ ++ usr/lib/common/pkcs_utils.c usr/lib/common/dlist.c \ + usr/sbin/pkcscca/pkcscca.c + + +diff --git a/usr/sbin/pkcsslotd/pkcsslotd.mk b/usr/sbin/pkcsslotd/pkcsslotd.mk +index 4f0e3c56..2d36b4a9 100644 +--- a/usr/sbin/pkcsslotd/pkcsslotd.mk ++++ b/usr/sbin/pkcsslotd/pkcsslotd.mk +@@ -21,5 +21,6 @@ usr_sbin_pkcsslotd_pkcsslotd_SOURCES = \ + usr/sbin/pkcsslotd/socket_server.c + + nodist_usr_sbin_pkcsslotd_pkcsslotd_SOURCES = \ +- usr/lib/common/parser.h usr/lib/common/parser.c usr/lib/common/lexer.c ++ usr/lib/common/parser.h usr/lib/common/parser.c usr/lib/common/lexer.c \ ++ usr/lib/common/dlist.c + usr/sbin/pkcsslotd/slotmgr.$(OBJEXT): usr/lib/common/parser.h diff --git a/opencryptoki-3.16.0-e9548127edae313da7840bcb87fd0afd04549c2e.patch b/opencryptoki-3.16.0-e9548127edae313da7840bcb87fd0afd04549c2e.patch new file mode 100644 index 0000000..8e81324 --- /dev/null +++ b/opencryptoki-3.16.0-e9548127edae313da7840bcb87fd0afd04549c2e.patch @@ -0,0 +1,310 @@ +commit e9548127edae313da7840bcb87fd0afd04549c2e +Author: Ingo Franzki +Date: Mon Feb 8 15:26:23 2021 +0100 + + pkcsslotd: Refactoring in preparation for event support + + No functional change so far, just making things a bit bore clearer. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/include/slotmgr.h b/usr/include/slotmgr.h +index 3950a9a3..4d038435 100644 +--- a/usr/include/slotmgr.h ++++ b/usr/include/slotmgr.h +@@ -30,7 +30,7 @@ + #define TOK_PATH SBIN_PATH "/pkcsslotd" + #define OCK_API_LOCK_FILE LOCKDIR_PATH "/LCK..APIlock" + +-#define SOCKET_FILE_PATH "/var/run/pkcsslotd.socket" ++#define PROC_SOCKET_FILE_PATH "/var/run/pkcsslotd.socket" + + #define PID_FILE_PATH "/var/run/pkcsslotd.pid" + #define OCK_CONFIG OCK_CONFDIR "/opencryptoki.conf" +diff --git a/usr/lib/api/api_interface.c b/usr/lib/api/api_interface.c +index b74b763f..2873a20a 100644 +--- a/usr/lib/api/api_interface.c ++++ b/usr/lib/api/api_interface.c +@@ -2831,7 +2831,7 @@ CK_RV C_Initialize(CK_VOID_PTR pVoid) + TRACE_DEBUG("Shared memory %p \n", Anchor->SharedMemP); + + /* Connect to slot daemon and retrieve slot infos */ +- Anchor->socketfd = connect_socket(SOCKET_FILE_PATH); ++ Anchor->socketfd = connect_socket(PROC_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 " +diff --git a/usr/sbin/pkcsslotd/pkcsslotd.h b/usr/sbin/pkcsslotd/pkcsslotd.h +index 813db9f4..69eb59f3 100644 +--- a/usr/sbin/pkcsslotd/pkcsslotd.h ++++ b/usr/sbin/pkcsslotd/pkcsslotd.h +@@ -61,7 +61,6 @@ extern key_t tok; + extern Slot_Info_t_64 sinfo[NUMBER_SLOTS_MANAGED]; + extern unsigned int NumberSlotsInDB; + +-extern int socketfd; + extern Slot_Mgr_Socket_t socketData; + + +@@ -89,9 +88,9 @@ int XProcLock(void); + int XProcUnLock(void); + int CreateXProcLock(void); + +-int CreateListenerSocket(void); +-int InitSocketData(Slot_Mgr_Socket_t *sp); +-int SocketConnectionHandler(int socketfd, int timeout_secs); +-void DetachSocketListener(int socketfd); ++int init_socket_server(); ++int term_socket_server(); ++int init_socket_data(Slot_Mgr_Socket_t *sp); ++int socket_connection_handler(int timeout_secs); + + #endif /* _SLOTMGR_H */ +diff --git a/usr/sbin/pkcsslotd/signal.c b/usr/sbin/pkcsslotd/signal.c +index cf7b9087..49482a2f 100644 +--- a/usr/sbin/pkcsslotd/signal.c ++++ b/usr/sbin/pkcsslotd/signal.c +@@ -101,7 +101,7 @@ void slotdGenericSignalHandler(int Signal) + + InfoLog("Exiting on %s (%d; %#x)", SignalConst(Signal), Signal, Signal); + +- DetachSocketListener(socketfd); ++ term_socket_server(); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); +diff --git a/usr/sbin/pkcsslotd/slotmgr.c b/usr/sbin/pkcsslotd/slotmgr.c +index ea5c86f5..94288f13 100644 +--- a/usr/sbin/pkcsslotd/slotmgr.c ++++ b/usr/sbin/pkcsslotd/slotmgr.c +@@ -37,7 +37,6 @@ unsigned int NumberSlotsInDB = 0; + + Slot_Info_t_64 *psinfo; + +-int socketfd; + Slot_Mgr_Socket_t socketData; + + struct dircheckinfo_s { +@@ -569,15 +568,15 @@ int main(int argc, char *argv[], char *envp[]) + if (!XProcUnLock()) + return 4; + +- if ((socketfd = CreateListenerSocket()) < 0) { ++ if (!init_socket_server()) { + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); + return 5; + } + +- if (!InitSocketData(&socketData)) { +- DetachSocketListener(socketfd); ++ if (!init_socket_data(&socketData)) { ++ term_socket_server(); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); +@@ -598,7 +597,7 @@ int main(int argc, char *argv[], char *envp[]) + if (Daemon) { + pid_t pid; + if ((pid = fork()) < 0) { +- DetachSocketListener(socketfd); ++ term_socket_server(); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); +@@ -643,7 +642,7 @@ int main(int argc, char *argv[], char *envp[]) + * the daemonization process redefines our handler for (at least) SIGTERM + */ + if (!SetupSignalHandlers()) { +- DetachSocketListener(socketfd); ++ term_socket_server(); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); +@@ -664,7 +663,7 @@ int main(int argc, char *argv[], char *envp[]) + printf("Start garbage \n"); + /* start garbage collection thread */ + if (!StartGCThread(shmp)) { +- DetachSocketListener(socketfd); ++ term_socket_server(); + DestroyMutexes(); + DetachFromSharedMemory(); + DestroySharedMemory(); +@@ -684,7 +683,7 @@ int main(int argc, char *argv[], char *envp[]) + #if !(THREADED) && !(NOGARBAGE) + CheckForGarbage(shmp); + #endif +- SocketConnectionHandler(socketfd, 10); ++ socket_connection_handler(10); + } + + /************************************************************* +diff --git a/usr/sbin/pkcsslotd/socket_server.c b/usr/sbin/pkcsslotd/socket_server.c +index ae0eff92..1fae0b95 100644 +--- a/usr/sbin/pkcsslotd/socket_server.c ++++ b/usr/sbin/pkcsslotd/socket_server.c +@@ -25,10 +25,14 @@ + #include "pkcsslotd.h" + #include "apictl.h" + ++int proc_listener_socket = -1; ++ ++static void close_listener_socket(int socketfd, const char *file_path); ++ + // Creates the daemon's listener socket, to which clients will connect and + // retrieve slot information through. Returns the file descriptor of the + // created socket. +-int CreateListenerSocket(void) ++static int create_listener_socket(const char *file_path) + { + struct sockaddr_un address; + struct group *grp; +@@ -39,53 +43,60 @@ int CreateListenerSocket(void) + ErrLog("Failed to create listener socket, errno 0x%X.", errno); + return -1; + } +- if (unlink(SOCKET_FILE_PATH) && errno != ENOENT) { ++ if (unlink(file_path) && errno != ENOENT) { + ErrLog("Failed to unlink socket file, errno 0x%X.", errno); +- close(socketfd); +- return -1; ++ goto error; + } + + memset(&address, 0, sizeof(struct sockaddr_un)); + address.sun_family = AF_UNIX; +- strcpy(address.sun_path, SOCKET_FILE_PATH); ++ strcpy(address.sun_path, file_path); + + if (bind(socketfd, + (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) { + ErrLog("Failed to bind to socket, errno 0x%X.", errno); +- close(socketfd); +- return -1; ++ goto error; + } + // make socket file part of the pkcs11 group, and write accessable + // for that group + grp = getgrnam("pkcs11"); + if (!grp) { + ErrLog("Group PKCS#11 does not exist"); +- DetachSocketListener(socketfd); +- return -1; ++ goto error; + } +- if (chown(SOCKET_FILE_PATH, 0, grp->gr_gid)) { ++ if (chown(file_path, 0, grp->gr_gid)) { + ErrLog("Could not change file group on socket, errno 0x%X.", errno); +- DetachSocketListener(socketfd); +- return -1; ++ goto error; + } +- if (chmod(SOCKET_FILE_PATH, ++ if (chmod(file_path, + S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP | S_IXUSR | S_IXGRP)) { + ErrLog("Could not change file permissions on socket, errno 0x%X.", + errno); +- DetachSocketListener(socketfd); +- return -1; ++ goto error; + } + + if (listen(socketfd, 20) != 0) { + ErrLog("Failed to listen to socket, errno 0x%X.", errno); +- DetachSocketListener(socketfd); +- return -1; ++ goto error; + } + + return socketfd; ++ ++error: ++ if (socketfd >= 0) ++ close_listener_socket(socketfd, file_path); ++ ++ return -1; ++} ++ ++ ++static void close_listener_socket(int socketfd, const char *file_path) ++{ ++ close(socketfd); ++ unlink(file_path); + } + +-int InitSocketData(Slot_Mgr_Socket_t *socketData) ++int init_socket_data(Slot_Mgr_Socket_t *socketData) + { + unsigned int processed = 0; + +@@ -102,19 +113,19 @@ int InitSocketData(Slot_Mgr_Socket_t *socketData) + return TRUE; + } + +-int SocketConnectionHandler(int socketfd, int timeout_secs) ++int socket_connection_handler(int timeout_secs) + { + int returnVal; + fd_set set; + struct timeval timeout; + + FD_ZERO(&set); +- FD_SET(socketfd, &set); ++ FD_SET(proc_listener_socket, &set); + + timeout.tv_sec = timeout_secs; + timeout.tv_usec = 0; + +- returnVal = select(socketfd + 1, &set, NULL, NULL, &timeout); ++ returnVal = select(proc_listener_socket + 1, &set, NULL, NULL, &timeout); + if (returnVal == -1) { + ErrLog("select failed on socket connection, errno 0x%X.", errno); + return FALSE; +@@ -125,7 +136,7 @@ int SocketConnectionHandler(int socketfd, int timeout_secs) + struct sockaddr_un address; + socklen_t address_length = sizeof(address); + +- int connectionfd = accept(socketfd, ++ int connectionfd = accept(proc_listener_socket, + (struct sockaddr *) &address, + &address_length); + if (connectionfd < 0) { +@@ -138,6 +149,10 @@ int SocketConnectionHandler(int socketfd, int timeout_secs) + } + return FALSE; + } ++ ++ DbgLog(DL0, "Accepted connection from process: socket: %d", ++ connectionfd); ++ + if (write(connectionfd, &socketData, sizeof(socketData)) != + sizeof(socketData)) { + ErrLog("Failed to write socket data, errno 0x%X.", errno); +@@ -149,8 +164,23 @@ int SocketConnectionHandler(int socketfd, int timeout_secs) + } + } + +-void DetachSocketListener(int socketfd) ++int init_socket_server() + { +- close(socketfd); +- unlink(SOCKET_FILE_PATH); ++ proc_listener_socket = create_listener_socket(PROC_SOCKET_FILE_PATH); ++ if (proc_listener_socket < 0) ++ return FALSE; ++ ++ DbgLog(DL0, "Socket server started"); ++ ++ return TRUE; ++} ++ ++int term_socket_server() ++{ ++ if (proc_listener_socket >= 0) ++ close_listener_socket(proc_listener_socket, PROC_SOCKET_FILE_PATH); ++ ++ DbgLog(DL0, "Socket server stopped"); ++ ++ return TRUE; + } diff --git a/opencryptoki-3.16.0-fa94a16116d8382a987ddf9e8cdd88027dd1f647.patch b/opencryptoki-3.16.0-fa94a16116d8382a987ddf9e8cdd88027dd1f647.patch new file mode 100644 index 0000000..30a506a --- /dev/null +++ b/opencryptoki-3.16.0-fa94a16116d8382a987ddf9e8cdd88027dd1f647.patch @@ -0,0 +1,287 @@ +commit fa94a16116d8382a987ddf9e8cdd88027dd1f647 +Author: Ingo Franzki +Date: Tue Feb 16 17:13:34 2021 +0100 + + Event support: Add event client + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/common/common.mk b/usr/lib/common/common.mk +index 2178ad45..882c84f4 100644 +--- a/usr/lib/common/common.mk ++++ b/usr/lib/common/common.mk +@@ -4,7 +4,7 @@ noinst_HEADERS += \ + usr/lib/common/shared_memory.h usr/lib/common/tok_spec_struct.h \ + usr/lib/common/trace.h usr/lib/common/h_extern.h \ + usr/lib/common/sw_crypt.h usr/lib/common/defs.h \ +- usr/lib/common/p11util.h \ ++ usr/lib/common/p11util.h usr/lib/common/event_client.h \ + usr/lib/common/list.h usr/lib/common/tok_specific.h + + usr/lib/common/lexer.c: usr/lib/common/parser.h +diff --git a/usr/lib/common/event_client.c b/usr/lib/common/event_client.c +new file mode 100644 +index 00000000..86117b84 +--- /dev/null ++++ b/usr/lib/common/event_client.c +@@ -0,0 +1,215 @@ ++/* ++ * 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 ++#include ++#include ++#include ++#include ++ ++#include "slotmgr.h" ++#include "event_client.h" ++ ++static int connect_socket(const char *file_path) ++{ ++ int socketfd; ++ struct sockaddr_un daemon_address; ++ struct stat file_info; ++ struct group *grp; ++ int rc; ++ ++ if (stat(file_path, &file_info)) ++ return -errno; ++ ++ grp = getgrnam("pkcs11"); ++ if (!grp) ++ return -errno; ++ ++ if (file_info.st_uid != 0 || file_info.st_gid != grp->gr_gid) ++ return -EPERM; ++ ++ if ((socketfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) ++ return -errno; ++ ++ memset(&daemon_address, 0, sizeof(struct sockaddr_un)); ++ daemon_address.sun_family = AF_UNIX; ++ strcpy(daemon_address.sun_path, file_path); ++ ++ if (connect(socketfd, (struct sockaddr *) &daemon_address, ++ sizeof(struct sockaddr_un)) != 0) { ++ rc = -errno; ++ goto error; ++ } ++ ++ return socketfd; ++ ++error: ++ close(socketfd); ++ return rc; ++} ++ ++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; ++ return -errno; ++ } ++ if (n == 0) ++ break; ++ ++ bytes_received += n; ++ } ++ ++ return bytes_received; ++} ++ ++static ssize_t send_all(int socketfd, char *buffer, size_t size) ++{ ++ size_t bytes_sent = 0; ++ ssize_t n; ++ ++ 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; ++ ++ bytes_sent += n; ++ } ++ ++ return bytes_sent; ++} ++ ++/* ++ * Initialize an admin connection to the pkcsslotd. ++ * Returns a file descriptor representing the connection, or a negative errno ++ * in case of an error. ++ */ ++int init_event_client() ++{ ++ int fd; ++ ++ fd = connect_socket(ADMIN_SOCKET_FILE_PATH); ++ ++ return fd; ++} ++ ++/* ++ * Send an event though the admin connection to the pkcsslotd, and thus to ++ * all active token instances. ++ * If parameter fd is < 0, then a connection to pkcsslotd is established ++ * inside the function and closed before return. This is for a one shot event. ++ * Otherwise, pass a file descriptor received from init_event_client(). This ++ * is to send multiple events. ++ * Event type is mandatory, flags can be zero. ++ * The event payload is optional, if payload_len is non-zero, then payload must ++ * point to a buffer containing the payload to send with the event. ++ * The event destination can be used to selectively send the event to certain ++ * token instances only. If destination is NULL, it is sent to all token ++ * instances. ++ * If flag EVENT_FLAGS_REPLY_REQ is on in the flags parameter, then it is waited ++ * until all active token instances have replied. The combined result of the ++ * replies from the token instances is returned in the reply structure. ++ * Parameter reply must be non-NULL if flag EVENT_FLAGS_REPLY_REQ is set. ++ * Returns zero for success, or a negative errno in case of an error. In most ++ * error cases the connection to the pkcsslotd is out of sequence and can no ++ * longer be used to send further events. ++ */ ++int send_event(int fd, unsigned int type, unsigned int flags, ++ unsigned int payload_len, const char *payload, ++ const struct event_destination *destination, ++ struct event_reply *reply) ++{ ++ event_msg_t event_msg; ++ event_reply_t event_reply; ++ int rc, term = 0; ++ ++ if (payload_len > 0 && payload == NULL) ++ return -EINVAL; ++ if ((flags & EVENT_FLAGS_REPLY_REQ) && reply == NULL) ++ return -EINVAL; ++ if (payload_len > EVENT_MAX_PAYLOAD_LENGTH) ++ return -EMSGSIZE; ++ ++ if (fd < 0) { ++ fd = init_event_client(); ++ if (fd < 0) ++ return fd; ++ term = 1; ++ } ++ ++ memset(&event_msg, 0, sizeof(event_msg)); ++ event_msg.version = EVENT_VERSION_1; ++ event_msg.type = type; ++ event_msg.flags = flags; ++ if (destination != NULL) { ++ event_msg.token_type = destination->token_type; ++ memcpy(event_msg.token_label, destination->token_label, ++ sizeof(event_msg.token_label)); ++ event_msg.process_id = destination->process_id; ++ } else { ++ memset(event_msg.token_label, ' ', sizeof(event_msg.token_label)); ++ } ++ event_msg.payload_len = payload_len; ++ ++ rc = send_all(fd, (char *)&event_msg, sizeof(event_msg)); ++ if (rc < 0) ++ goto out; ++ ++ if (payload_len > 0) { ++ rc = send_all(fd, (char *)payload, payload_len); ++ if (rc < 0) ++ goto out; ++ } ++ ++ if (flags & EVENT_FLAGS_REPLY_REQ) { ++ rc = read_all(fd, (char *)&event_reply, sizeof(event_reply)); ++ if (rc < 0) ++ goto out; ++ ++ reply->positive_replies = event_reply.positive_replies; ++ reply->negative_replies = event_reply.negative_replies; ++ reply->nothandled_replies = event_reply.nothandled_replies; ++ } ++ ++ rc = 0; ++ ++out: ++ if (term) ++ term_event_client(fd); ++ ++ return rc; ++} ++ ++/* ++ * Terminate the admin connection to the pkcsslotd. ++ */ ++void term_event_client(int fd) ++{ ++ if (fd >= 0) ++ close(fd); ++} ++ +diff --git a/usr/lib/common/event_client.h b/usr/lib/common/event_client.h +new file mode 100644 +index 00000000..2e4917b0 +--- /dev/null ++++ b/usr/lib/common/event_client.h +@@ -0,0 +1,39 @@ ++/* ++ * 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 ++ */ ++ ++ ++#ifndef _EVENT_CLIENT_H_ ++#define _EVENT_CLIENT_H_ ++ ++#include "events.h" ++ ++struct event_destination { ++ unsigned int token_type; /* Destination token type: EVENT_TOK_TYPE_xxx */ ++ char token_label[member_size(event_msg_t, token_label)]; ++ /* Label of destination token (or blanks) */ ++ pid_t process_id; /* Process ID of destination process (or 0) */ ++}; ++ ++struct event_reply { ++ unsigned long positive_replies; ++ unsigned long negative_replies; ++ unsigned long nothandled_replies; ++}; ++ ++int init_event_client(); ++ ++int send_event(int fd, unsigned int type, unsigned int flags, ++ unsigned int payload_len, const char *payload, ++ const struct event_destination *destination, ++ struct event_reply *reply); ++ ++void term_event_client(int fd); ++ ++#endif diff --git a/opencryptoki.spec b/opencryptoki.spec index 3878ae2..e84c64b 100644 --- a/opencryptoki.spec +++ b/opencryptoki.spec @@ -1,7 +1,7 @@ Name: opencryptoki Summary: Implementation of the PKCS#11 (Cryptoki) specification v2.11 Version: 3.16.0 -Release: 2%{?dist} +Release: 3%{?dist} License: CPL URL: https://github.com/opencryptoki/opencryptoki Source0: https://github.com/opencryptoki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz @@ -15,6 +15,22 @@ Patch1: opencryptoki-3.11.0-lockdir.patch # Use --no-undefined to debug missing symbols #Patch100: %%{name}-3.2-no-undefined.patch +# upstream patches +Patch200: opencryptoki-3.16.0-4e3b43c3d8844402c04a66b55c6c940f965109f0.patch +Patch201: opencryptoki-3.16.0-c79e899d77a5724635a9d4451a34a240e2c7e891.patch +Patch202: opencryptoki-3.16.0-69244a5e0d9dfec3ef534b19b89a541576bb17dc.patch +Patch203: opencryptoki-3.16.0-b07505993dd8b2f367cf3b630f6da186e4e8550d.patch +Patch204: opencryptoki-3.16.0-b048be548508dd1958bb7271568f388d0f6cbcf8.patch +Patch205: opencryptoki-3.16.0-e9548127edae313da7840bcb87fd0afd04549c2e.patch +Patch206: opencryptoki-3.16.0-d929fe8470e99f4dcbbd889e7aa87e147d0d5b48.patch +Patch207: opencryptoki-3.16.0-19f56d12b302b87e1dacf613cc61a063ad209d15.patch +Patch208: opencryptoki-3.16.0-342dfbeb8275f5ea6ed52dd3f30126614ec1d037.patch +Patch209: opencryptoki-3.16.0-fa94a16116d8382a987ddf9e8cdd88027dd1f647.patch +Patch210: opencryptoki-3.16.0-d7de5092247a0efc2c397f12977a7c9925420143.patch +Patch211: opencryptoki-3.16.0-1fdd0e4497b0078e73e0004e3492db647c7c458b.patch +Patch212: opencryptoki-3.16.0-bf812c652c49d7e248b115d121a4f7f6568941a2.patch +Patch213: opencryptoki-3.16.0-7b7d83c571ceb3050969359817d4145600f14ae8.patch + Requires(pre): coreutils BuildRequires: gcc BuildRequires: gcc-c++ @@ -320,6 +336,10 @@ fi %changelog +* Mon May 17 2021 Than Ngo - 3.16.0-3 +- Resolves: #1959894, Soft token does not check if an EC key is valid +- Resolves: #1924120, Event Notification Support + * Fri Apr 16 2021 Mohan Boddu - 3.16.0-2 - Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937