diff --git a/src/libopensc/ctx.c b/src/libopensc/ctx.c index 4670008..26f8bf5 100644 --- a/src/libopensc/ctx.c +++ b/src/libopensc/ctx.c @@ -791,19 +791,21 @@ int sc_wait_for_event(sc_context_t *ctx, unsigned int event_mask, sc_reader_t ** } -int sc_release_context(sc_context_t *ctx) +static +int __sc_release_context(sc_context_t *ctx, unsigned after_fork) { unsigned int i; assert(ctx != NULL); SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); + while (list_size(&ctx->readers)) { sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, 0); _sc_delete_reader(ctx, rdr); } if (ctx->reader_driver->ops->finish != NULL) - ctx->reader_driver->ops->finish(ctx); + ctx->reader_driver->ops->finish(ctx, after_fork); for (i = 0; ctx->card_drivers[i]; i++) { struct sc_card_driver *drv = ctx->card_drivers[i]; @@ -836,6 +838,16 @@ int sc_release_context(sc_context_t *ctx) return SC_SUCCESS; } +int sc_release_context(sc_context_t *ctx) +{ + return __sc_release_context(ctx, 0); +} + +int sc_terminate_context(sc_context_t *ctx) +{ + return __sc_release_context(ctx, 1); +} + int sc_set_card_driver(sc_context_t *ctx, const char *short_name) { int i = 0, match = 0; diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index cea8d42..ed84ffe 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -244,6 +244,7 @@ sc_put_data sc_read_binary sc_read_record sc_release_context +sc_terminate_context sc_reset sc_reset_retry_counter sc_restore_security_env diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index ad5405d..437a14d 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -374,7 +374,7 @@ struct sc_reader_operations { int (*init)(struct sc_context *ctx); /* Called when the driver is being unloaded. finish() has to * release any resources. */ - int (*finish)(struct sc_context *ctx); + int (*finish)(struct sc_context *ctx, unsigned after_fork); /* Called when library wish to detect new readers * should add only new readers. */ int (*detect_readers)(struct sc_context *ctx); @@ -752,6 +752,12 @@ int sc_context_create(sc_context_t **ctx, const sc_context_param_t *parm); int sc_release_context(sc_context_t *ctx); /** + * Releases an established OpenSC context without releasing any state that is shared with parent process + * @param ctx A pointer to the context structure to be released + */ +int sc_terminate_context(sc_context_t *ctx); + +/** * Detect new readers available on system. * @param ctx OpenSC context * @return SC_SUCCESS on success and an error code otherwise. diff --git a/src/libopensc/reader-ctapi.c b/src/libopensc/reader-ctapi.c index 919c3f0..e252a42 100644 --- a/src/libopensc/reader-ctapi.c +++ b/src/libopensc/reader-ctapi.c @@ -514,7 +514,7 @@ static int ctapi_init(sc_context_t *ctx) return 0; } -static int ctapi_finish(sc_context_t *ctx) +static int ctapi_finish(sc_context_t *ctx, unsigned after_fork) { struct ctapi_global_private_data *priv = (struct ctapi_global_private_data *) ctx->reader_drv_data; diff --git a/src/libopensc/reader-openct.c b/src/libopensc/reader-openct.c index a276d52..32871d0 100644 --- a/src/libopensc/reader-openct.c +++ b/src/libopensc/reader-openct.c @@ -29,7 +29,7 @@ /* function declarations */ static int openct_reader_init(sc_context_t *ctx); static int openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info); -static int openct_reader_finish(sc_context_t *ctx); +static int openct_reader_finish(sc_context_t *ctx, unsigned after_fork); static int openct_reader_release(sc_reader_t *reader); static int openct_reader_detect_card_presence(sc_reader_t *reader); static int openct_reader_connect(sc_reader_t *reader); @@ -137,7 +137,7 @@ openct_add_reader(sc_context_t *ctx, unsigned int num, ct_info_t *info) * Called when the driver is being unloaded. finish() has to * deallocate the private data and any resources. */ -static int openct_reader_finish(sc_context_t *ctx) +static int openct_reader_finish(sc_context_t *ctx, unsigned after_fork) { SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); return SC_SUCCESS; diff --git a/src/libopensc/reader-pcsc.c b/src/libopensc/reader-pcsc.c index 7382452..cf5890d 100644 --- a/src/libopensc/reader-pcsc.c +++ b/src/libopensc/reader-pcsc.c @@ -740,14 +740,14 @@ out: return ret; } -static int pcsc_finish(sc_context_t *ctx) +static int pcsc_finish(sc_context_t *ctx, unsigned after_fork) { struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) ctx->reader_drv_data; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL); if (gpriv) { - if (gpriv->pcsc_ctx != -1) + if (!after_fork && gpriv->pcsc_ctx != -1) gpriv->SCardReleaseContext(gpriv->pcsc_ctx); if (gpriv->dlhandle != NULL) sc_dlclose(gpriv->dlhandle); @@ -2096,7 +2096,7 @@ out: return ret; } -static int cardmod_finish(sc_context_t *ctx) +static int cardmod_finish(sc_context_t *ctx, unsigned after_fork) { struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) ctx->reader_drv_data; diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index ee6cf7c..886476e 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -40,6 +40,7 @@ list_t virtual_slots; pid_t initialized_pid = (pid_t)-1; #endif static int in_finalize = 0; +static CK_RV __sc_pkcs11_finalize(CK_VOID_PTR pReserved, unsigned after_fork); extern CK_FUNCTION_LIST pkcs11_function_list; #if defined(HAVE_PTHREAD) && defined(PKCS11_THREAD_LOCKING) @@ -205,7 +206,7 @@ CK_RV C_Initialize(CK_VOID_PTR pInitArgs) /* Handle fork() exception */ #if !defined(_WIN32) if (current_pid != initialized_pid) { - C_Finalize(NULL_PTR); + __sc_pkcs11_finalize(NULL_PTR, 1); } initialized_pid = current_pid; in_finalize = 0; @@ -271,7 +272,8 @@ out: return rv; } -CK_RV C_Finalize(CK_VOID_PTR pReserved) +static +CK_RV __sc_pkcs11_finalize(CK_VOID_PTR pReserved, unsigned after_fork) { int i; void *p; @@ -292,10 +294,14 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) /* cancel pending calls */ in_finalize = 1; - sc_cancel(context); - /* remove all cards from readers */ - for (i=0; i < (int)sc_ctx_get_reader_count(context); i++) - card_removed(sc_ctx_get_reader(context, i)); + + if (!after_fork) { + sc_cancel(context); + + /* remove all cards from readers */ + for (i=0; i < (int)sc_ctx_get_reader_count(context); i++) + card_removed(sc_ctx_get_reader(context, i)); + } while ((p = list_fetch(&sessions))) free(p); @@ -307,7 +313,10 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) } list_destroy(&virtual_slots); - sc_release_context(context); + if (after_fork) + sc_terminate_context(context); + else + sc_release_context(context); context = NULL; /* Release and destroy the mutex */ @@ -316,6 +325,17 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) return rv; } +CK_RV C_Finalize(CK_VOID_PTR pReserved) +{ +#if !defined(_WIN32) + pid_t current_pid = getpid(); + if (current_pid != initialized_pid) { + return __sc_pkcs11_finalize(NULL_PTR, 1); + } +#endif + return __sc_pkcs11_finalize(pReserved, 0); +} + CK_RV C_GetInfo(CK_INFO_PTR pInfo) { CK_RV rv = CKR_OK;