Blame src/p11_atfork.c

Packit Service 2ea82d
/* libp11, a simple layer on to of PKCS#11 API
Packit Service 2ea82d
 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
Packit Service 2ea82d
 * Copyright (C) 2014 Red Hat
Packit Service 2ea82d
 * Copyright (C) 2018 MichaƂ Trojnara <Michal.Trojnara@stunnel.org>
Packit Service 2ea82d
 *
Packit Service 2ea82d
 * Author: Nikos Mavrogiannopoulos
Packit Service 2ea82d
 *
Packit Service 2ea82d
 * This is free software; you can redistribute it and/or
Packit Service 2ea82d
 * modify it under the terms of the GNU Lesser General Public License
Packit Service 2ea82d
 * as published by the Free Software Foundation; either version 2.1 of
Packit Service 2ea82d
 * the License, or (at your option) any later version.
Packit Service 2ea82d
 *
Packit Service 2ea82d
 * This library is distributed in the hope that it will be useful, but
Packit Service 2ea82d
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2ea82d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 2ea82d
 * Lesser General Public License for more details.
Packit Service 2ea82d
 *
Packit Service 2ea82d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 2ea82d
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
Packit Service 2ea82d
 *
Packit Service 2ea82d
 */
Packit Service 2ea82d
Packit Service 2ea82d
#include "libp11-int.h"
Packit Service 2ea82d
Packit Service 2ea82d
#ifndef _WIN32
Packit Service 2ea82d
Packit Service 2ea82d
#ifndef __STDC_VERSION__
Packit Service 2ea82d
/* older than C90 */
Packit Service 2ea82d
#define inline
Packit Service 2ea82d
#endif /* __STDC_VERSION__ */
Packit Service 2ea82d
Packit Service 2ea82d
#ifdef HAVE___REGISTER_ATFORK
Packit Service 2ea82d
Packit Service 2ea82d
#ifdef __sun
Packit Service 2ea82d
#pragma fini(lib_deinit)
Packit Service 2ea82d
#pragma init(lib_init)
Packit Service 2ea82d
#define _CONSTRUCTOR
Packit Service 2ea82d
#define _DESTRUCTOR
Packit Service 2ea82d
#else /* __sun */
Packit Service 2ea82d
#define _CONSTRUCTOR __attribute__((constructor))
Packit Service 2ea82d
#define _DESTRUCTOR __attribute__((destructor))
Packit Service 2ea82d
#endif /* __sun */
Packit Service 2ea82d
Packit Service 2ea82d
static unsigned int P11_forkid = 0;
Packit Service 2ea82d
Packit Service 2ea82d
inline static unsigned int _P11_get_forkid(void)
Packit Service 2ea82d
{
Packit Service 2ea82d
	return P11_forkid;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
inline static int _P11_detect_fork(unsigned int forkid)
Packit Service 2ea82d
{
Packit Service 2ea82d
	if (forkid == P11_forkid)
Packit Service 2ea82d
		return 0;
Packit Service 2ea82d
	return 1;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
static void fork_handler(void)
Packit Service 2ea82d
{
Packit Service 2ea82d
	P11_forkid++;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *);
Packit Service 2ea82d
extern void *__dso_handle;
Packit Service 2ea82d
Packit Service 2ea82d
_CONSTRUCTOR
Packit Service 2ea82d
int _P11_register_fork_handler(void)
Packit Service 2ea82d
{
Packit Service 2ea82d
	if (__register_atfork(0, 0, fork_handler, __dso_handle) != 0)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	return 0;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
#else /* HAVE___REGISTER_ATFORK */
Packit Service 2ea82d
Packit Service 2ea82d
inline static unsigned int _P11_get_forkid(void)
Packit Service 2ea82d
{
Packit Service 2ea82d
	return getpid();
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
inline static int _P11_detect_fork(unsigned int forkid)
Packit Service 2ea82d
{
Packit Service 2ea82d
	if (getpid() == forkid)
Packit Service 2ea82d
		return 0;
Packit Service 2ea82d
	return 1;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
#endif /* HAVE___REGISTER_ATFORK */
Packit Service 2ea82d
Packit Service 2ea82d
#else /* !_WIN32 */
Packit Service 2ea82d
Packit Service 2ea82d
#define _P11_get_forkid() 0
Packit Service 2ea82d
#define _P11_detect_fork(x) 0
Packit Service 2ea82d
Packit Service 2ea82d
#endif /* !_WIN32 */
Packit Service 2ea82d
Packit Service 2ea82d
unsigned int get_forkid()
Packit Service 2ea82d
{
Packit Service 2ea82d
	return _P11_get_forkid();
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * PKCS#11 reinitialization after fork
Packit Service 2ea82d
 * It wipes out the internal state of the PKCS#11 library
Packit Service 2ea82d
 * Any libp11 references to this state are no longer valid
Packit Service 2ea82d
 */
Packit Service 2ea82d
static int check_fork_int(PKCS11_CTX *ctx)
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
Packit Service 2ea82d
Packit Service 2ea82d
	if (_P11_detect_fork(cpriv->forkid)) {
Packit Service 2ea82d
		if (pkcs11_CTX_reload(ctx) < 0)
Packit Service 2ea82d
			return -1;
Packit Service 2ea82d
		cpriv->forkid = _P11_get_forkid();
Packit Service 2ea82d
	}
Packit Service 2ea82d
	return 0;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * PKCS#11 reinitialization after fork
Packit Service 2ea82d
 * Also relogins and reopens the session if needed
Packit Service 2ea82d
 */
Packit Service 2ea82d
static int check_slot_fork_int(PKCS11_SLOT *slot)
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit Service 2ea82d
	PKCS11_CTX *ctx = SLOT2CTX(slot);
Packit Service 2ea82d
	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
Packit Service 2ea82d
Packit Service 2ea82d
	if (check_fork_int(SLOT2CTX(slot)) < 0)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	if (spriv->forkid != cpriv->forkid) {
Packit Service 2ea82d
		if (spriv->loggedIn) {
Packit Service 2ea82d
			int saved = spriv->haveSession;
Packit Service 2ea82d
			spriv->haveSession = 0;
Packit Service 2ea82d
			spriv->loggedIn = 0;
Packit Service 2ea82d
			if (pkcs11_relogin(slot) < 0)
Packit Service 2ea82d
				return -1;
Packit Service 2ea82d
			spriv->haveSession = saved;
Packit Service 2ea82d
		}
Packit Service 2ea82d
		if (spriv->haveSession) {
Packit Service 2ea82d
			spriv->haveSession = 0;
Packit Service 2ea82d
			if (pkcs11_reopen_session(slot) < 0)
Packit Service 2ea82d
				return -1;
Packit Service 2ea82d
		}
Packit Service 2ea82d
		spriv->forkid = cpriv->forkid;
Packit Service 2ea82d
	}
Packit Service 2ea82d
	return 0;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * PKCS#11 reinitialization after fork
Packit Service 2ea82d
 * Also reloads the key
Packit Service 2ea82d
 */
Packit Service 2ea82d
static int check_key_fork_int(PKCS11_KEY *key)
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_SLOT *slot = KEY2SLOT(key);
Packit Service 2ea82d
	PKCS11_KEY_private *kpriv = PRIVKEY(key);
Packit Service 2ea82d
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit Service 2ea82d
Packit Service 2ea82d
	if (check_slot_fork_int(slot) < 0)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	if (spriv->forkid != kpriv->forkid) {
Packit Service 2ea82d
		pkcs11_reload_key(key);
Packit Service 2ea82d
		kpriv->forkid = spriv->forkid;
Packit Service 2ea82d
	}
Packit Service 2ea82d
	return 0;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * Locking interface to check_fork_int()
Packit Service 2ea82d
 */
Packit Service 2ea82d
int check_fork(PKCS11_CTX *ctx)
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_CTX_private *cpriv;
Packit Service 2ea82d
	int rv;
Packit Service 2ea82d
Packit Service 2ea82d
	if (ctx == NULL)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	cpriv = PRIVCTX(ctx);
Packit Service 2ea82d
	CRYPTO_THREAD_write_lock(cpriv->rwlock);
Packit Service 2ea82d
	rv = check_fork_int(ctx);
Packit Service 2ea82d
	CRYPTO_THREAD_unlock(cpriv->rwlock);
Packit Service 2ea82d
	return rv;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * Locking interface to check_slot_fork_int()
Packit Service 2ea82d
 */
Packit Service 2ea82d
int check_slot_fork(PKCS11_SLOT *slot)
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_CTX_private *cpriv;
Packit Service 2ea82d
	int rv;
Packit Service 2ea82d
Packit Service 2ea82d
	if (slot == NULL)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	cpriv = PRIVCTX(SLOT2CTX(slot));
Packit Service 2ea82d
	CRYPTO_THREAD_write_lock(cpriv->rwlock);
Packit Service 2ea82d
	rv = check_slot_fork_int(slot);
Packit Service 2ea82d
	CRYPTO_THREAD_unlock(cpriv->rwlock);
Packit Service 2ea82d
	return rv;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * Reinitialize token (just its slot)
Packit Service 2ea82d
 */
Packit Service 2ea82d
int check_token_fork(PKCS11_TOKEN *token)
Packit Service 2ea82d
{
Packit Service 2ea82d
	if (token == NULL)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	return check_slot_fork(TOKEN2SLOT(token));
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * Locking interface to check_key_fork_int()
Packit Service 2ea82d
 */
Packit Service 2ea82d
int check_key_fork(PKCS11_KEY *key)
Packit Service 2ea82d
{
Packit Service 2ea82d
	PKCS11_CTX_private *cpriv;
Packit Service 2ea82d
	int rv;
Packit Service 2ea82d
Packit Service 2ea82d
	if (key == NULL)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	cpriv = PRIVCTX(KEY2CTX(key));
Packit Service 2ea82d
	CRYPTO_THREAD_write_lock(cpriv->rwlock);
Packit Service 2ea82d
	rv = check_key_fork_int(key);
Packit Service 2ea82d
	CRYPTO_THREAD_unlock(cpriv->rwlock);
Packit Service 2ea82d
	return rv;
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/*
Packit Service 2ea82d
 * Reinitialize cert (just its token)
Packit Service 2ea82d
 */
Packit Service 2ea82d
int check_cert_fork(PKCS11_CERT *cert)
Packit Service 2ea82d
{
Packit Service 2ea82d
	if (cert == NULL)
Packit Service 2ea82d
		return -1;
Packit Service 2ea82d
	return check_token_fork(CERT2TOKEN(cert));
Packit Service 2ea82d
}
Packit Service 2ea82d
Packit Service 2ea82d
/* vim: set noexpandtab: */