static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
    SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
    void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
    PTimeStamp ptsExpiry)
{
#ifdef WITH_GSSAPI
	SEC_WINNT_AUTH_IDENTITY* identity = pAuthData;
	SEC_WINPR_KERBEROS_SETTINGS* krb_settings = NULL;
	KRB_CREDENTIALS* credentials = NULL;
	krb5_error_code rv;
	krb5_context ctx = NULL;
	krb5_ccache ccache = NULL;
	krb5_keytab keytab = NULL;
	krb5_get_init_creds_opt* gic_opt = NULL;
	krb5_deltat start_time = 0;
	krb5_principal principal = NULL;
	krb5_init_creds_context creds_ctx = NULL;
	BOOL is_unicode = FALSE;
	char* domain = NULL;
	char* username = NULL;
	char* password = NULL;
	const char* fallback_ccache = "MEMORY:";

	if (identity)
	{
		if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_EXTENDED)
			krb_settings = &((SEC_WINNT_AUTH_IDENTITY_WINPR*)identity)->kerberosSettings;

		if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
		{
			is_unicode = TRUE;
			ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)identity->Domain, identity->DomainLength,
			                   &domain, 0, NULL, NULL);
			ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)identity->User, identity->UserLength, &username,
			                   0, NULL, NULL);
			ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)identity->Password, identity->PasswordLength,
			                   &password, 0, NULL, NULL);
		}
		else
		{
			domain = (char*)identity->Domain;
			username = (char*)identity->User;
			password = (char*)identity->Password;
		}

		if (!pszPrincipal)
			pszPrincipal = username;
	}

	if ((rv = krb5_init_context(&ctx)))
		goto cleanup;

	if (domain)
	{
		CharUpperA(domain);
		/* Will use domain if realm is not specified in username */
		if ((rv = krb5_set_default_realm(ctx, domain)))
			goto cleanup;
	}

	if (pszPrincipal)
	{
		/* Find realm component if included and convert to uppercase */
		char* p = strchr(pszPrincipal, '@');
		CharUpperA(p);

		if ((rv = krb5_parse_name(ctx, pszPrincipal, &principal)))
			goto cleanup;
	}

	if (krb_settings && krb_settings->cache)
	{
		if ((rv = krb5_cc_set_default_name(ctx, krb_settings->cache)))
			goto cleanup;
		fallback_ccache = krb_settings->cache;
	}

	if (principal)
	{
		/* Use the default cache if it's initialized with the right principal */
		if (krb5_cc_cache_match(ctx, principal, &ccache) == KRB5_CC_NOTFOUND)
		{
			if ((rv = krb5_cc_resolve(ctx, fallback_ccache, &ccache)))
				goto cleanup;
			if ((rv = krb5_cc_initialize(ctx, ccache, principal)))
				goto cleanup;
		}
	}
	else if (fCredentialUse & SECPKG_CRED_OUTBOUND)
	{
		/* Use the default cache with it's default principal */
		if ((rv = krb5_cc_default(ctx, &ccache)))
			goto cleanup;
		if ((rv = krb5_cc_get_principal(ctx, ccache, &principal)))
			goto cleanup;
	}
	else
	{
		if ((rv = krb5_cc_resolve(ctx, fallback_ccache, &ccache)))
			goto cleanup;
	}

	if (krb_settings && krb_settings->keytab)
	{
		if ((rv = krb5_kt_resolve(ctx, krb_settings->keytab, &keytab)))
			goto cleanup;
	}
	else
	{
		if (fCredentialUse & SECPKG_CRED_INBOUND)
			if ((rv = krb5_kt_default(ctx, &keytab)))
				goto cleanup;
	}

	/* Get initial credentials if required */
	if (fCredentialUse & SECPKG_CRED_OUTBOUND)
	{
		if ((rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt)))
			goto cleanup;

		krb5_get_init_creds_opt_set_forwardable(gic_opt, 0);
		krb5_get_init_creds_opt_set_proxiable(gic_opt, 0);

		if (krb_settings)
		{
			if (krb_settings->startTime)
				start_time = krb_settings->startTime;
			kerberos_set_krb_opts(ctx, gic_opt, krb_settings);
		}

#ifdef WITH_GSSAPI_MIT
		krb5_get_init_creds_opt_set_out_ccache(ctx, gic_opt, ccache);
		krb5_get_init_creds_opt_set_in_ccache(ctx, gic_opt, ccache);
#endif

		if ((rv = krb5_init_creds_init(ctx, principal, krb5_prompter, password, start_time, gic_opt,
		                               &creds_ctx)))
			goto cleanup;

		if ((rv = krb5_init_creds_get(ctx, creds_ctx)))
			goto cleanup;

#ifdef WITH_GSSAPI_HEIMDAL
		{
			krb5_creds creds;
			if ((rv = krb5_init_creds_get_creds(ctx, creds_ctx, &creds)))
				goto cleanup;
			if (rv = krb5_cc_store_cred(ctx, ccache, &creds))
				goto cleanup;
		}
#endif
	}

	credentials = calloc(1, sizeof(KRB_CREDENTIALS));
	if (!credentials)
		goto cleanup;
	credentials->ccache = ccache;
	credentials->keytab = keytab;

cleanup:

	if (rv)
		kerberos_log_msg(ctx, rv);

	if (is_unicode)
	{
		if (domain)
			free(domain);
		if (username)
			free(username);
		if (password)
			free(password);
	}
	if (principal)
		krb5_free_principal(ctx, principal);
	if (creds_ctx)
		krb5_init_creds_free(ctx, creds_ctx);
#ifdef HAVE_AT_LEAST_KRB_V1_13
	if (gic_opt)
		krb5_get_init_creds_opt_free(ctx, gic_opt);
#endif
	if (ctx)
		krb5_free_context(ctx);

	/* If we managed to get credentials set the output */
	if (credentials)
	{
		sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
		sspi_SecureHandleSetUpperPointer(phCredential, (void*)KERBEROS_SSP_NAME);
		return SEC_E_OK;
	}

	return SEC_E_NO_CREDENTIALS;
#else
	return SEC_E_UNSUPPORTED_FUNCTION;
#endif
}
static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(
    SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage, ULONG fCredentialUse, void* pvLogonID,
    void* pAuthData, SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument, PCredHandle phCredential,
    PTimeStamp ptsExpiry)
{
#ifdef WITH_GSSAPI
	SEC_WINNT_AUTH_IDENTITY* identity = pAuthData;
	SEC_WINPR_KERBEROS_SETTINGS* krb_settings = NULL;
	KRB_CREDENTIALS* credentials = NULL;
	krb5_error_code rv;
	krb5_context ctx = NULL;
	krb5_ccache ccache = NULL;
	krb5_keytab keytab = NULL;
	krb5_get_init_creds_opt* gic_opt = NULL;
	krb5_deltat start_time = 0;
	krb5_principal principal = NULL;
	krb5_init_creds_context creds_ctx = NULL;
	BOOL is_unicode = FALSE;
	char* domain = NULL;
	char* username = NULL;
	char* password = NULL;
	const char* fallback_ccache = "MEMORY:";

	if (identity)
	{
		if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_EXTENDED)
			krb_settings = &((SEC_WINNT_AUTH_IDENTITY_WINPR*)identity)->kerberosSettings;

		if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
		{
			is_unicode = TRUE;
			ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)identity->Domain, identity->DomainLength,
			                   &domain, 0, NULL, NULL);
			ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)identity->User, identity->UserLength, &username,
			                   0, NULL, NULL);
			ConvertFromUnicode(CP_UTF8, 0, (WCHAR*)identity->Password, identity->PasswordLength,
			                   &password, 0, NULL, NULL);
		}
		else
		{
			domain = (char*)identity->Domain;
			username = (char*)identity->User;
			password = (char*)identity->Password;
		}

		if (!pszPrincipal)
			pszPrincipal = username;
	}

	if ((rv = krb5_init_context(&ctx)))
		goto cleanup;

	if (domain)
	{
		CharUpperA(domain);
		 
		if ((rv = krb5_set_default_realm(ctx, domain)))
			goto cleanup;
	}

	if (pszPrincipal)
	{
		 
		char* p = strchr(pszPrincipal, '@');
		CharUpperA(p);

		if ((rv = krb5_parse_name(ctx, pszPrincipal, &principal)))
			goto cleanup;
	}

	if (krb_settings && krb_settings->cache)
	{
		if ((rv = krb5_cc_set_default_name(ctx, krb_settings->cache)))
			goto cleanup;
		fallback_ccache = krb_settings->cache;
	}

	if (principal)
	{
		 
		if (krb5_cc_cache_match(ctx, principal, &ccache) == KRB5_CC_NOTFOUND)
		{
			if ((rv = krb5_cc_resolve(ctx, fallback_ccache, &ccache)))
				goto cleanup;
			if ((rv = krb5_cc_initialize(ctx, ccache, principal)))
				goto cleanup;
		}
	}
	else if (fCredentialUse & SECPKG_CRED_OUTBOUND)
	{
		 
		if ((rv = krb5_cc_default(ctx, &ccache)))
			goto cleanup;
		if ((rv = krb5_cc_get_principal(ctx, ccache, &principal)))
			goto cleanup;
	}
	else
	{
		if ((rv = krb5_cc_resolve(ctx, fallback_ccache, &ccache)))
			goto cleanup;
	}

	if (krb_settings && krb_settings->keytab)
	{
		if ((rv = krb5_kt_resolve(ctx, krb_settings->keytab, &keytab)))
			goto cleanup;
	}
	else
	{
		if (fCredentialUse & SECPKG_CRED_INBOUND)
			if ((rv = krb5_kt_default(ctx, &keytab)))
				goto cleanup;
	}

	 
	if (fCredentialUse & SECPKG_CRED_OUTBOUND)
	{
		if ((rv = krb5_get_init_creds_opt_alloc(ctx, &gic_opt)))
			goto cleanup;

		krb5_get_init_creds_opt_set_forwardable(gic_opt, 0);
		krb5_get_init_creds_opt_set_proxiable(gic_opt, 0);

		if (krb_settings)
		{
			if (krb_settings->startTime)
				start_time = krb_settings->startTime;
			kerberos_set_krb_opts(ctx, gic_opt, krb_settings);
		}

#ifdef WITH_GSSAPI_MIT
		krb5_get_init_creds_opt_set_out_ccache(ctx, gic_opt, ccache);
		krb5_get_init_creds_opt_set_in_ccache(ctx, gic_opt, ccache);
#endif

		if ((rv = krb5_init_creds_init(ctx, principal, krb5_prompter, password, start_time, gic_opt,
		                               &creds_ctx)))
			goto cleanup;

		if ((rv = krb5_init_creds_get(ctx, creds_ctx)))
			goto cleanup;

#ifdef WITH_GSSAPI_HEIMDAL
		{
			krb5_creds creds;
			if ((rv = krb5_init_creds_get_creds(ctx, creds_ctx, &creds)))
				goto cleanup;
			if (rv = krb5_cc_store_cred(ctx, ccache, &creds))
				goto cleanup;
		}
#endif
	}

	credentials = calloc(1, sizeof(KRB_CREDENTIALS));
	if (!credentials)
		goto cleanup;
	credentials->ccache = ccache;
	credentials->keytab = keytab;

cleanup:

	if (rv)
		kerberos_log_msg(ctx, rv);

	if (is_unicode)
	{
		if (domain)
			free(domain);
		if (username)
			free(username);
		if (password)
			free(password);
	}
	if (principal)
		krb5_free_principal(ctx, principal);
	if (creds_ctx)
		krb5_init_creds_free(ctx, creds_ctx);
#ifdef HAVE_AT_LEAST_KRB_V1_13
	if (gic_opt)
		krb5_get_init_creds_opt_free(ctx, gic_opt);
#endif
	if (ctx)
		krb5_free_context(ctx);

	 
	if (credentials)
	{
		sspi_SecureHandleSetLowerPointer(phCredential, (void*)credentials);
		sspi_SecureHandleSetUpperPointer(phCredential, (void*)KERBEROS_SSP_NAME);
		return SEC_E_OK;
	}

	return SEC_E_NO_CREDENTIALS;
#else
	return SEC_E_UNSUPPORTED_FUNCTION;
#endif
}