Ejemplo n.º 1
0
void
pkcs11_terminate() {
    dmsg(
        D_PKCS11_DEBUG,
        "PKCS#11: pkcs11_terminate - entered"
        );

    pkcs11h_terminate();

    dmsg(
        D_PKCS11_DEBUG,
        "PKCS#11: pkcs11_terminate - return"
        );
}
Ejemplo n.º 2
0
static
void
__pkcs11h_threading_atfork_child (void) {
	if (_g_pkcs11h_data != NULL && _g_pkcs11h_data->initialized) {
		_pkcs1h_threading_mutexReleaseAll ();
		if (_g_pkcs11h_data->safefork) {
			__pkcs11h_forkFixup (TRUE);
		}
		else {
			__pkcs11h_forkFixup (FALSE);
			pkcs11h_terminate ();
		}
	}
}
Ejemplo n.º 3
0
void
show_pkcs11_ids(
    const char *const provider,
    bool cert_private
    ) {
    struct gc_arena gc = gc_new();
    pkcs11h_certificate_id_list_t user_certificates = NULL;
    pkcs11h_certificate_id_list_t current = NULL;
    CK_RV rv = CKR_FUNCTION_FAILED;

    if ((rv = pkcs11h_initialize()) != CKR_OK)
    {
        msg(M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage(rv));
        goto cleanup;
    }

    if ((rv = pkcs11h_setLogHook(_pkcs11_openvpn_log, NULL)) != CKR_OK)
    {
        msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv));
        goto cleanup;
    }

    pkcs11h_setLogLevel(_pkcs11_msg_openvpn2pkcs11(get_debug_level()));

    if ((rv = pkcs11h_setProtectedAuthentication(TRUE)) != CKR_OK)
    {
        msg(M_FATAL, "PKCS#11: Cannot set protected authentication %ld-'%s'", rv, pkcs11h_getMessage(rv));
        goto cleanup;
    }

    if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_show_pkcs11_ids_pin_prompt, NULL)) != CKR_OK)
    {
        msg(M_FATAL, "PKCS#11: Cannot set PIN hook %ld-'%s'", rv, pkcs11h_getMessage(rv));
        goto cleanup;
    }

    if (
        (rv = pkcs11h_addProvider(
             provider,
             provider,
             TRUE,
             0,
             FALSE,
             0,
             cert_private ? TRUE : FALSE
             )) != CKR_OK
        )
    {
        msg(M_FATAL, "PKCS#11: Cannot add provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage(rv));
        goto cleanup;
    }

    if (
        (rv = pkcs11h_certificate_enumCertificateIds(
             PKCS11H_ENUM_METHOD_CACHE_EXIST,
             NULL,
             PKCS11H_PROMPT_MASK_ALLOW_ALL,
             NULL,
             &user_certificates
             )) != CKR_OK
        )
    {
        msg(M_FATAL, "PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, pkcs11h_getMessage(rv));
        goto cleanup;
    }

    msg(
        M_INFO|M_NOPREFIX|M_NOLF,
        (
            "\n"
            "The following objects are available for use.\n"
            "Each object shown below may be used as parameter to\n"
            "--pkcs11-id option please remember to use single quote mark.\n"
        )
        );
    for (current = user_certificates; current != NULL; current = current->next) {
        pkcs11h_certificate_t certificate = NULL;
        char *dn = NULL;
        char serial[1024] = {0};
        char *ser = NULL;
        size_t ser_len = 0;

        if (
            (rv = pkcs11h_certificate_serializeCertificateId(
                 NULL,
                 &ser_len,
                 current->certificate_id
                 )) != CKR_OK
            )
        {
            msg(M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
            goto cleanup1;
        }

        if (
            rv == CKR_OK
            && (ser = (char *)malloc(ser_len)) == NULL
            )
        {
            msg(M_FATAL, "PKCS#11: Cannot allocate memory");
            goto cleanup1;
        }

        if (
            (rv = pkcs11h_certificate_serializeCertificateId(
                 ser,
                 &ser_len,
                 current->certificate_id
                 )) != CKR_OK
            )
        {
            msg(M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
            goto cleanup1;
        }

        if (
            (rv = pkcs11h_certificate_create(
                 current->certificate_id,
                 NULL,
                 PKCS11H_PROMPT_MASK_ALLOW_ALL,
                 PKCS11H_PIN_CACHE_INFINITE,
                 &certificate
                 ))
            )
        {
            msg(M_FATAL, "PKCS#11: Cannot create certificate %ld-'%s'", rv, pkcs11h_getMessage(rv));
            goto cleanup1;
        }

        if (
            (dn = pkcs11_certificate_dn(
                 certificate,
                 &gc
                 )) == NULL
            )
        {
            goto cleanup1;
        }

        if (
            (pkcs11_certificate_serial(
                 certificate,
                 serial,
                 sizeof(serial)
                 ))
            )
        {
            goto cleanup1;
        }

        msg(
            M_INFO|M_NOPREFIX|M_NOLF,
            (
                "\n"
                "Certificate\n"
                "       DN:             %s\n"
                "       Serial:         %s\n"
                "       Serialized id:  %s\n"
            ),
            dn,
            serial,
            ser
            );

cleanup1:

        if (certificate != NULL)
        {
            pkcs11h_certificate_freeCertificate(certificate);
            certificate = NULL;
        }

        if (ser != NULL)
        {
            free(ser);
            ser = NULL;
        }
    }

cleanup:
    if (user_certificates != NULL)
    {
        pkcs11h_certificate_freeCertificateIdList(user_certificates);
        user_certificates = NULL;
    }

    pkcs11h_terminate();
    gc_free(&gc);
}
Ejemplo n.º 4
0
int main () {
	pkcs11h_certificate_id_list_t issuers, certs, temp;
	pkcs11h_certificate_t cert;
	CK_RV rv;

	printf ("Initializing pkcs11-helper\n");

	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
		fatal ("pkcs11h_initialize failed", rv);
	}

	printf ("Registering pkcs11-helper hooks\n");

	if ((rv = pkcs11h_setLogHook (_pkcs11h_hooks_log, NULL)) != CKR_OK) {
		fatal ("pkcs11h_setLogHook failed", rv);
	}

	pkcs11h_setLogLevel (TEST_LOG_LEVEL);

	if ((rv = pkcs11h_setTokenPromptHook (_pkcs11h_hooks_token_prompt, NULL)) != CKR_OK) {
		fatal ("pkcs11h_setTokenPromptHook failed", rv);
	}

	if ((rv = pkcs11h_setPINPromptHook (_pkcs11h_hooks_pin_prompt, NULL)) != CKR_OK) {
		fatal ("pkcs11h_setPINPromptHook failed", rv);
	}

	printf ("Adding provider '%s'\n", TEST_PROVIDER);

	if (
		(rv = pkcs11h_addProvider (
			TEST_PROVIDER,
			TEST_PROVIDER,
			FALSE,
			PKCS11H_PRIVATEMODE_MASK_AUTO,
			PKCS11H_SLOTEVENT_METHOD_AUTO,
			0,
			FALSE
		)) != CKR_OK
	) {
		fatal ("pkcs11h_addProvider failed", rv);
	}

	mypause ("Please remove all tokens, press <Enter>: ");

	printf ("Enumerating token certificate (list should be empty, no prompt)\n");

	if (
		(rv = pkcs11h_certificate_enumCertificateIds (
			PKCS11H_ENUM_METHOD_CACHE,
			NULL,
			PKCS11H_PROMPT_MASK_ALLOW_ALL,
			&issuers,
			&certs
		)) != CKR_OK
	) {
		fatal ("pkcs11h_certificate_enumCertificateIds failed", rv);
	}

	if (issuers != NULL || certs != NULL) {
		fatal ("No certificates should be found", rv);
	}

	mypause ("Please insert token, press <Enter>: ");

	printf ("Getting certificate cache, should be available certificates\n");

	if (
		(rv = pkcs11h_certificate_enumCertificateIds (
			PKCS11H_ENUM_METHOD_CACHE,
			NULL,
			PKCS11H_PROMPT_MASK_ALLOW_ALL,
			&issuers,
			&certs
		)) != CKR_OK
	) {
		fatal ("pkcs11h_certificate_enumCertificateIds failed", rv);
	}

	for (temp = issuers;temp != NULL;temp = temp->next) {
		printf ("Issuer: %s\n", temp->certificate_id->displayName);
	}
	for (temp = certs;temp != NULL;temp = temp->next) {
		printf ("Certificate: %s\n", temp->certificate_id->displayName);
	}

	if (certs == NULL) {
		fatal ("No certificates found", rv);
	}

	pkcs11h_certificate_freeCertificateIdList (issuers);
	pkcs11h_certificate_freeCertificateIdList (certs);

	mypause ("Please remove token, press <Enter>: ");

	printf ("Getting certificate cache, should be similar to last\n");

	if (
		(rv = pkcs11h_certificate_enumCertificateIds (
			PKCS11H_ENUM_METHOD_CACHE,
			NULL,
			PKCS11H_PROMPT_MASK_ALLOW_ALL,
			&issuers,
			&certs
		)) != CKR_OK
	) {
		fatal ("pkcs11h_certificate_enumCertificateIds failed", rv);
	}

	for (temp = issuers;temp != NULL;temp = temp->next) {
		printf ("Issuer: %s\n", temp->certificate_id->displayName);
	}
	for (temp = certs;temp != NULL;temp = temp->next) {
		printf ("Certificate: %s\n", temp->certificate_id->displayName);
	}

	if (certs == NULL) {
		fatal ("No certificates found", rv);
	}

	printf ("Creating certificate context\n");

	if (
		(rv = pkcs11h_certificate_create (
			certs->certificate_id,
			NULL,
			PKCS11H_PROMPT_MASK_ALLOW_ALL,
			PKCS11H_PIN_CACHE_INFINITE,
			&cert
		)) != CKR_OK
	) {
		fatal ("pkcs11h_certificate_create failed", rv);
	}

	printf ("Perforing signature #1 (you should be prompt for token and PIN)\n");

	sign_test (cert);

	printf ("Perforing signature #2 (you should NOT be prompt for anything)\n");

	sign_test (cert);

	mypause ("Please remove and insert token, press <Enter>: ");

	printf ("Perforing signature #3 (you should be prompt only for PIN)\n");

	sign_test (cert);

	printf ("Perforing signature #4 (you should NOT be prompt for anything)\n");

	if ((rv = pkcs11h_certificate_freeCertificate (cert)) != CKR_OK) {
		fatal ("pkcs11h_certificate_free failed", rv);
	}

	if (
		(rv = pkcs11h_certificate_create (
			certs->certificate_id,
			NULL,
			PKCS11H_PROMPT_MASK_ALLOW_ALL,
			PKCS11H_PIN_CACHE_INFINITE,
			&cert
		)) != CKR_OK
	) {
		fatal ("pkcs11h_certificate_create failed", rv);
	}

	sign_test (cert);

	printf ("Terminating pkcs11-helper\n");

	if ((rv = pkcs11h_certificate_freeCertificate (cert)) != CKR_OK) {
		fatal ("pkcs11h_certificate_free failed", rv);
	}

	pkcs11h_certificate_freeCertificateIdList (issuers);
	pkcs11h_certificate_freeCertificateIdList (certs);

	if ((rv = pkcs11h_terminate ()) != CKR_OK) {
		fatal ("pkcs11h_terminate failed", rv);
	}

	exit (0);
	return 0;
}
Ejemplo n.º 5
0
CK_RV
pkcs11h_initialize (void) {
#if defined(ENABLE_PKCS11H_THREADING)
	PKCS11H_BOOL has_mutex_global = FALSE;
	PKCS11H_BOOL has_mutex_cache = FALSE;
	PKCS11H_BOOL has_mutex_session = FALSE;
#endif

	CK_RV rv = CKR_FUNCTION_FAILED;

	_pkcs11h_data_t data = NULL;
	_PKCS11H_DEBUG (
		PKCS11H_LOG_DEBUG2,
		"PKCS#11: pkcs11h_initialize entry"
	);

	pkcs11h_terminate ();

	if ((rv = _pkcs11h_mem_malloc ((void*)&data, sizeof (struct _pkcs11h_data_s))) != CKR_OK) {
		goto cleanup;
	}

	if (_g_pkcs11h_crypto_engine.initialize == NULL) {
		if ((rv = pkcs11h_engine_setCrypto (PKCS11H_ENGINE_CRYPTO_AUTO)) != CKR_OK) {
			goto cleanup;
		}
	}

	if (!_g_pkcs11h_crypto_engine.initialize (_g_pkcs11h_crypto_engine.global_data)) {
		_PKCS11H_DEBUG (
			PKCS11H_LOG_ERROR,
			"PKCS#11: Cannot initialize crypto engine"
		);

		rv = CKR_FUNCTION_FAILED;
		goto cleanup;
	}

#if defined(ENABLE_PKCS11H_THREADING)
	if ((rv = _pkcs11h_threading_mutexInit (&data->mutexes.global)) != CKR_OK) {
		goto cleanup;
	}
	has_mutex_global = TRUE;
	if ((rv = _pkcs11h_threading_mutexInit (&data->mutexes.cache)) != CKR_OK) {
		goto cleanup;
	}
	has_mutex_cache = TRUE;
	if ((rv = _pkcs11h_threading_mutexInit (&data->mutexes.session)) != CKR_OK) {
		goto cleanup;
	}
	has_mutex_session = TRUE;
#if !defined(_WIN32)
	if (
		pthread_atfork (
			__pkcs11h_threading_atfork_prepare,
			__pkcs11h_threading_atfork_parent,
			__pkcs11h_threading_atfork_child
		)
	) {
		rv = CKR_FUNCTION_FAILED;
		goto cleanup;
	}
#endif
#endif

	data->max_retries = _PKCS11H_DEFAULT_MAX_LOGIN_RETRY;
	data->allow_protected_auth = TRUE;
	data->pin_cache_period = _PKCS11H_DEFAULT_PIN_CACHE_PERIOD;
	data->initialized = TRUE;

	_g_pkcs11h_data = data;
	data = NULL;

	pkcs11h_setLogHook (__pkcs11h_hooks_default_log, NULL);
	pkcs11h_setTokenPromptHook (__pkcs11h_hooks_default_token_prompt, NULL);
	pkcs11h_setPINPromptHook (__pkcs11h_hooks_default_pin_prompt, NULL);

	rv = CKR_OK;

cleanup:

	if (data != NULL) {
#if defined(ENABLE_PKCS11H_THREADING)
		if (has_mutex_global) {
			_pkcs11h_threading_mutexFree (&data->mutexes.global);
			has_mutex_global = FALSE;
		}
		if (has_mutex_cache) {
			_pkcs11h_threading_mutexFree (&data->mutexes.cache);
			has_mutex_cache = FALSE;
		}
		if (has_mutex_session) {
			_pkcs11h_threading_mutexFree (&data->mutexes.session); 
			has_mutex_session = FALSE;
		}
#endif
		_pkcs11h_mem_free ((void *)&data);
		data = NULL;
	}

	_PKCS11H_DEBUG (
		PKCS11H_LOG_DEBUG2,
		"PKCS#11: pkcs11h_initialize return rv=%lu-'%s'",
		rv,
		pkcs11h_getMessage (rv)
	);

	return rv;
}
Ejemplo n.º 6
0
int main (int argc, char *argv[])
{
	enum {
		OPT_SERVER,
		OPT_MUTLI_SERVER,
		OPT_DAEMON,
		OPT_VERBOSE,
		OPT_QUIET,
		OPT_SH,
		OPT_CSH,
		OPT_OPTIONS,
		OPT_NO_DETACH,
		OPT_LOG_FILE,
		OPT_VERSION,
		OPT_HELP
	};

	static struct option long_options[] = {
		{ "server", no_argument, NULL, OPT_SERVER },
		{ "multi-server", no_argument, NULL, OPT_MUTLI_SERVER },
		{ "daemon", no_argument, NULL, OPT_DAEMON },
		{ "verbose", no_argument, NULL, OPT_VERBOSE },
		{ "quiet", no_argument, NULL, OPT_QUIET },
		{ "sh", no_argument, NULL, OPT_SH },
		{ "csh", no_argument, NULL, OPT_CSH },
		{ "options", required_argument, NULL, OPT_OPTIONS },
		{ "no-detach", no_argument, NULL, OPT_NO_DETACH },
		{ "log-file", required_argument, NULL, OPT_LOG_FILE },
		{ "version", no_argument, NULL, OPT_VERSION },
		{ "help", no_argument, NULL, OPT_HELP },
		{ NULL, 0, NULL, 0 }
	};
	int long_options_ret;
	int base_argc = 1;

	int usage_ok = 1;
	enum {
		RUN_MODE_NONE,
		RUN_MODE_SERVER,
		RUN_MODE_MULTI_SERVER,
		RUN_MODE_DAEMON
	} run_mode = RUN_MODE_NONE;
	int env_is_csh = 0;
	int log_verbose = 0;
	int log_quiet = 0;
	int no_detach = 0;
	char *config_file = NULL;
	char *log_file = NULL;
	char *home_dir = NULL;
	int have_at_least_one_provider=0;
	FILE *fp_log = NULL;
	int i;
	CK_RV rv;

	dconfig_data_t config;

	const char * CONFIG_SUFFIX = ".conf";
	char *default_config_file = NULL;

#if !defined(HAVE_W32_SYSTEM)
	s_parent_pid = getpid ();
#endif

	if ((default_config_file = (char *)malloc (strlen (PACKAGE)+strlen (CONFIG_SUFFIX)+1)) == NULL) {
		common_log (LOG_FATAL, "malloc failed");
	}
	sprintf (default_config_file, "%s%s", PACKAGE, CONFIG_SUFFIX);

	common_set_log_stream (stderr);

	while ((long_options_ret = getopt_long (argc, argv, "vqsc", long_options, NULL)) != -1) {
		base_argc++;

		switch (long_options_ret) {
			case OPT_SERVER:
				run_mode = RUN_MODE_SERVER;
			break;
			case OPT_MUTLI_SERVER:
				run_mode = RUN_MODE_MULTI_SERVER;
			break;
			case OPT_DAEMON:
				run_mode = RUN_MODE_DAEMON;
			break;
			case OPT_VERBOSE:
			case 'v':
				log_verbose = 1;
			break;
			case OPT_QUIET:
			case 'q':
				log_quiet = 1;
			break;
			case OPT_SH:
			case 's':
			break;
			case OPT_CSH:
			case 'c':
				env_is_csh = 1;
			break;
			case OPT_OPTIONS:
				base_argc++;
				config_file = strdup (optarg);
			break;
			case OPT_NO_DETACH:
				no_detach = 1;
			break;
			case OPT_LOG_FILE:
				base_argc++;
				log_file = strdup (optarg);
			break;
			case OPT_VERSION:
				printf (
					"%s %s\n"
					"\n"
					"Copyright (c) 2006-2007 Zeljko Vrba <*****@*****.**>\n"
					"Copyright (c) 2006-2011 Alon Bar-Lev <*****@*****.**>\n"
					"\n"
					"This is free software; see the source for copying conditions.\n"
					"There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
					PACKAGE,
					PACKAGE_VERSION
				);
				exit (1);
			break;
			case OPT_HELP:
				usage_ok = 0;
			break;
			default:
				usage_ok = 0;
			break;
		}
	}

	if (base_argc < argc) {
		if (!strcmp (argv[base_argc], "--")) {
			base_argc++;
		}
	}

	if (!usage_ok) {
		usage (argv[0]);
	}

	if (run_mode == RUN_MODE_NONE) {
		common_log (LOG_FATAL, "please use the option `--daemon' to run the program in the background");
	}

#if defined(HAVE_W32_SYSTEM)
	if (run_mode == RUN_MODE_DAEMON) {
		common_log (LOG_FATAL, "daemon mode is not supported");
	}
#endif

	home_dir = get_home_dir ();

	if (config_file == NULL) {
		if ((config_file = (char *)malloc (strlen (home_dir) + strlen (default_config_file)+2)) == NULL) {
			common_log (LOG_FATAL, "malloc failed");
		}
		sprintf (config_file, "%s%c%s", home_dir, CONFIG_PATH_SEPARATOR, default_config_file);
	}

	if (
		!dconfig_read (config_file, &config) &&
		!dconfig_read (CONFIG_SYSTEM_CONFIG, &config)
	) {
		common_log (LOG_FATAL, "Cannot open configuration file");
	}

	if (log_file != NULL) {
		if (config.log_file != NULL) {
			free (config.log_file);
		}
		if ((config.log_file = strdup (log_file)) == NULL) {
			common_log (LOG_FATAL, "strdup failed");
		}
	}

	if (log_verbose) {
		config.verbose = 1;
	}

#if !defined(HAVE_W32_SYSTEM)
	signal (SIGPIPE, SIG_IGN);
	signal (SIGINT, on_signal);
	signal (SIGTERM, on_signal);
	signal (SIGABRT, on_signal);
	signal (SIGHUP, on_signal);
#endif

	if (log_file != NULL) {
		if (strcmp (log_file, "stderr")) {
			if ((fp_log = fopen (log_file, "a")) != NULL) {
				common_set_log_stream (fp_log);
			}
		}
	}
	else if (config.log_file != NULL) {
		if (strcmp (config.log_file, "stderr")) {
			if ((fp_log = fopen (config.log_file, "a")) != NULL) {
				common_set_log_stream (fp_log);
			}
		}
	}

	if (config.debug) {
		common_log (LOG_DEBUG, "version: %s", PACKAGE_VERSION);
		dconfig_print (&config);
		common_log (LOG_DEBUG, "run_mode: %d", run_mode);
		common_log (LOG_DEBUG, "crypto: %s",
#if defined(ENABLE_OPENSSL)
			"openssl"
#elif defined(ENABLE_GNUTLS)
			"gnutls"
#else
			"invalid"
#endif
		);
	}

#if !defined(HAVE_W32_SYSTEM)
	if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) {
		server_socket_create_name ();
	}

	/*
	 * fork before doing PKCS#11 stuff
	 * some providers don't behave well
	 */
	if (run_mode == RUN_MODE_DAEMON) {
		pid_t pid;

		pid = fork ();

		if (pid == -1) {
			common_log (LOG_FATAL, "fork failed");
		}

		if (pid != 0) {
			static const char *key = "SCDAEMON_INFO";
			char env[1024];
			snprintf (env, sizeof (env), "%s:%lu:1", s_socket_name, (unsigned long)pid);

			if (argc - base_argc > 0) {
				setenv(key, env, 1);
				execvp (argv[base_argc], &(argv[base_argc]));
				kill (pid, SIGTERM);
				exit (1);
			}
			else {
				if (env_is_csh) {
					*strchr (env, '=') = ' ';
					printf ("setenv %s %s\n", key, env);
				}
				else {
					printf ("%s=%s; export %s\n", key, env, key);
				}
				exit (0);
			}
		}

		if (!no_detach) {
			int i;

			for (i=0;i<3;i++) {
				if (fileno (common_get_log_stream ()) != i) {
					close (i);
				}
			}

			if (setsid () == -1) {
				common_log (LOG_FATAL, "setsid failed");
			}
		}

		if (chdir ("/") == -1) {
			common_log (LOG_FATAL, "chdir failed");
		}

		if (argc - base_argc > 0) {
			struct sigaction sa;

			memset (&sa, 0, sizeof (sa));
			sigemptyset (&sa.sa_mask);
#if defined(SA_INTERRUPT)
			sa.sa_flags |= SA_INTERRUPT;
#endif
			sa.sa_handler = on_alarm;
			sigaction (SIGALRM, &sa, NULL);
			alarm (10);
		}
	}
#endif				/* HAVE_W32_SYSTEM */

	assuan_set_assuan_log_prefix (PACKAGE);
	assuan_set_assuan_log_stream (common_get_log_stream ());

#if defined(USE_GNUTLS)
	if (gnutls_global_init () != GNUTLS_E_SUCCESS) {
		common_log (LOG_FATAL, "Cannot initialize gnutls");
	}
#endif

	if ((rv = pkcs11h_initialize ()) != CKR_OK) {
		common_log (LOG_FATAL, "Cannot initialize PKCS#11: %s", pkcs11h_getMessage (rv));
	}

	pkcs11h_setLogLevel (config.verbose ? PKCS11H_LOG_DEBUG2 : PKCS11H_LOG_INFO);
	pkcs11h_setLogHook (pkcs11_log_hook, NULL);
	pkcs11h_setTokenPromptHook (pkcs11_token_prompt_hook, NULL);
	pkcs11h_setPINPromptHook (pkcs11_pin_prompt_hook, NULL);
	pkcs11h_setProtectedAuthentication (TRUE);

	for (i=0;i<DCONFIG_MAX_PROVIDERS;i++) {
		if (
			config.providers[i].name != NULL &&
			config.providers[i].library != NULL
		) {
			if (
				(rv = pkcs11h_addProvider (
					config.providers[i].name,
					config.providers[i].library,
					config.providers[i].allow_protected,
					config.providers[i].private_mask,
					PKCS11H_SLOTEVENT_METHOD_POLL,
					0,
					config.providers[i].cert_is_private
				)) != CKR_OK
			) {
				common_log (LOG_WARNING, "Cannot add PKCS#11 provider '%s': %ld-'%s'", config.providers[i].name, rv, pkcs11h_getMessage (rv));
			}
			else {
				have_at_least_one_provider = 1;
			}
		}
	}

	if (!have_at_least_one_provider) {
		common_log (LOG_FATAL, "Could not load any provider");
	}

#if defined(HAVE_W32_SYSTEM)
	command_handler (-1, &config);
#else
{
	pthread_t accept_thread = 0;
	int accept_socket = -1;

	if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) {
		accept_socket = server_socket_create ();

		server_socket_accept (accept_socket, &accept_thread, &config);
	}

	if (run_mode == RUN_MODE_DAEMON) {
		/*
		 * Emulate assuan behavior
		 */
		int fds[2];
		char c;
		if (pipe (fds)==-1) {
			common_log (LOG_FATAL, "Could not create pipe");
		}
		close (0);
		dup2 (fds[0], 0);
		close (fds[0]);
		while (read (0, &c, 1) == -1 && errno == EINTR);
		close (fds[1]);
	}
	else {
		command_handler (-1, &config);
	}

	if (run_mode == RUN_MODE_DAEMON || run_mode == RUN_MODE_MULTI_SERVER) {
		server_socket_accept_terminate (accept_thread);
		server_socket_close (accept_socket);
	}
}
#endif

	pkcs11h_terminate ();

#if defined(USE_GNUTLS)
	gnutls_global_deinit ();
#endif

	dconfig_free (&config);

	if (log_file != NULL) {
		free (log_file);
		log_file = NULL;
	}

	if (config_file != NULL) {
		free (config_file);
		config_file = NULL;
	}

	if (default_config_file != NULL) {
		free (default_config_file);
		default_config_file = NULL;
	}

	if (home_dir != NULL) {
		free (home_dir);
		home_dir = NULL;
	}

	if (fp_log != NULL) {
		fclose (fp_log);
		fp_log = NULL;
	}

	return 0;
}