|
Packit |
1fb8d4 |
/**
|
|
Packit |
1fb8d4 |
* FreeRDP: A Remote Desktop Protocol Client
|
|
Packit |
1fb8d4 |
* Kerberos Auth Protocol
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Copyright 2015 ANSSI, Author Thomas Calderon
|
|
Packit |
1fb8d4 |
* Copyright 2017 Dorian Ducournau <dorian.ducournau@gmail.com>
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
Packit |
1fb8d4 |
* you may not use this file except in compliance with the License.
|
|
Packit |
1fb8d4 |
* You may obtain a copy of the License at
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
1fb8d4 |
*
|
|
Packit |
1fb8d4 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
1fb8d4 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
1fb8d4 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
1fb8d4 |
* See the License for the specific language governing permissions and
|
|
Packit |
1fb8d4 |
* limitations under the License.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
1fb8d4 |
#include "config.h"
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <stdio.h>
|
|
Packit |
1fb8d4 |
#include <stdlib.h>
|
|
Packit |
1fb8d4 |
#include <string.h>
|
|
Packit |
1fb8d4 |
#include <errno.h>
|
|
Packit |
1fb8d4 |
#include <fcntl.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include <winpr/crt.h>
|
|
Packit |
1fb8d4 |
#include <winpr/sspi.h>
|
|
Packit |
1fb8d4 |
#include <winpr/print.h>
|
|
Packit |
1fb8d4 |
#include <winpr/sysinfo.h>
|
|
Packit |
1fb8d4 |
#include <winpr/registry.h>
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "kerberos.h"
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef WITH_GSSAPI_HEIMDAL
|
|
Packit |
1fb8d4 |
#include <krb5-protos.h>
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#include "../sspi.h"
|
|
Packit |
1fb8d4 |
#include "../../log.h"
|
|
Packit |
1fb8d4 |
#define TAG WINPR_TAG("sspi.Kerberos")
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
struct _KRB_CONTEXT
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
CtxtHandle context;
|
|
Packit |
1fb8d4 |
SSPI_CREDENTIALS* credentials;
|
|
Packit |
1fb8d4 |
SEC_WINNT_AUTH_IDENTITY identity;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* GSSAPI */
|
|
Packit |
1fb8d4 |
UINT32 major_status;
|
|
Packit |
1fb8d4 |
UINT32 minor_status;
|
|
Packit |
1fb8d4 |
UINT32 actual_time;
|
|
Packit |
1fb8d4 |
sspi_gss_cred_id_t cred;
|
|
Packit |
1fb8d4 |
sspi_gss_ctx_id_t gss_ctx;
|
|
Packit |
1fb8d4 |
sspi_gss_name_t target_name;
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static const char* KRB_PACKAGE_NAME = "Kerberos";
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
const SecPkgInfoA KERBEROS_SecPkgInfoA =
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
0x000F3BBF, /* fCapabilities */
|
|
Packit |
1fb8d4 |
1, /* wVersion */
|
|
Packit |
1fb8d4 |
0x0010, /* wRPCID */
|
|
Packit |
1fb8d4 |
0x0000BB80, /* cbMaxToken : 48k bytes maximum for Windows Server 2012 */
|
|
Packit |
1fb8d4 |
"Kerberos", /* Name */
|
|
Packit |
1fb8d4 |
"Kerberos Security Package" /* Comment */
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static WCHAR KERBEROS_SecPkgInfoW_Name[] = { 'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', '\0' };
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static WCHAR KERBEROS_SecPkgInfoW_Comment[] =
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
'K', 'e', 'r', 'b', 'e', 'r', 'o', 's', ' ',
|
|
Packit |
1fb8d4 |
'S', 'e', 'c', 'u', 'r', 'i', 't', 'y', ' ',
|
|
Packit |
1fb8d4 |
'P', 'a', 'c', 'k', 'a', 'g', 'e', '\0'
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
const SecPkgInfoW KERBEROS_SecPkgInfoW =
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
0x000F3BBF, /* fCapabilities */
|
|
Packit |
1fb8d4 |
1, /* wVersion */
|
|
Packit |
1fb8d4 |
0x0010, /* wRPCID */
|
|
Packit |
1fb8d4 |
0x0000BB80, /* cbMaxToken : 48k bytes maximum for Windows Server 2012 */
|
|
Packit |
1fb8d4 |
KERBEROS_SecPkgInfoW_Name, /* Name */
|
|
Packit |
1fb8d4 |
KERBEROS_SecPkgInfoW_Comment /* Comment */
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static sspi_gss_OID_desc g_SSPI_GSS_C_SPNEGO_KRB5 = { 9, (void*) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
|
|
Packit |
1fb8d4 |
static sspi_gss_OID SSPI_GSS_C_SPNEGO_KRB5 = &g_SSPI_GSS_C_SPNEGO_KRB5;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static KRB_CONTEXT* kerberos_ContextNew(void)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
KRB_CONTEXT* context;
|
|
Packit |
1fb8d4 |
context = (KRB_CONTEXT*) calloc(1, sizeof(KRB_CONTEXT));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
return NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
context->minor_status = 0;
|
|
Packit |
1fb8d4 |
context->major_status = 0;
|
|
Packit |
1fb8d4 |
context->gss_ctx = SSPI_GSS_C_NO_CONTEXT;
|
|
Packit |
1fb8d4 |
context->cred = SSPI_GSS_C_NO_CREDENTIAL;
|
|
Packit |
1fb8d4 |
return context;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static void kerberos_ContextFree(KRB_CONTEXT* context)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
UINT32 minor_status;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
return;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (context->target_name)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
sspi_gss_release_name(&minor_status, &context->target_name);
|
|
Packit |
1fb8d4 |
context->target_name = NULL;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (context->gss_ctx)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
sspi_gss_delete_sec_context(&minor_status, &context->gss_ctx, SSPI_GSS_C_NO_BUFFER);
|
|
Packit |
1fb8d4 |
context->gss_ctx = SSPI_GSS_C_NO_CONTEXT;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
free(context);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal,
|
|
Packit |
1fb8d4 |
SEC_WCHAR* pszPackage,
|
|
Packit |
1fb8d4 |
ULONG fCredentialUse, void* pvLogonID, void* pAuthData,
|
|
Packit |
1fb8d4 |
SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument,
|
|
Packit |
1fb8d4 |
PCredHandle phCredential, PTimeStamp ptsExpiry)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal,
|
|
Packit |
1fb8d4 |
SEC_CHAR* pszPackage,
|
|
Packit |
1fb8d4 |
ULONG fCredentialUse, void* pvLogonID, void* pAuthData,
|
|
Packit |
1fb8d4 |
SEC_GET_KEY_FN pGetKeyFn, void* pvGetKeyArgument,
|
|
Packit |
1fb8d4 |
PCredHandle phCredential, PTimeStamp ptsExpiry)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_FreeCredentialsHandle(PCredHandle phCredential)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SSPI_CREDENTIALS* credentials;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!phCredential)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_HANDLE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!credentials)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_HANDLE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
sspi_CredentialsFree(credentials);
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesW(PCredHandle phCredential,
|
|
Packit |
1fb8d4 |
ULONG ulAttribute, void* pBuffer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return SEC_E_UNSUPPORTED_FUNCTION;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_QueryCredentialsAttributesA(PCredHandle phCredential,
|
|
Packit |
1fb8d4 |
ULONG ulAttribute, void* pBuffer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return kerberos_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextW(PCredHandle phCredential,
|
|
Packit |
1fb8d4 |
PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1,
|
|
Packit |
1fb8d4 |
ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
|
|
Packit |
1fb8d4 |
PCtxtHandle phNewContext, PSecBufferDesc pOutput,
|
|
Packit |
1fb8d4 |
ULONG* pfContextAttr, PTimeStamp ptsExpiry)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_UNSUPPORTED_FUNCTION;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int kerberos_SetContextServicePrincipalNameA(KRB_CONTEXT* context,
|
|
Packit |
1fb8d4 |
SEC_CHAR* ServicePrincipalName)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
char* p;
|
|
Packit |
1fb8d4 |
UINT32 major_status;
|
|
Packit |
1fb8d4 |
UINT32 minor_status;
|
|
Packit |
1fb8d4 |
char* gss_name = NULL;
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc name_buffer;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!ServicePrincipalName)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
context->target_name = NULL;
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* GSSAPI expects a SPN of type <service>@FQDN, let's construct it */
|
|
Packit |
1fb8d4 |
gss_name = _strdup(ServicePrincipalName);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!gss_name)
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
p = strchr(gss_name, '/');
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (p)
|
|
Packit |
1fb8d4 |
*p = '@';
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
name_buffer.value = gss_name;
|
|
Packit |
1fb8d4 |
name_buffer.length = strlen(gss_name) + 1;
|
|
Packit |
1fb8d4 |
major_status = sspi_gss_import_name(&minor_status, &name_buffer,
|
|
Packit |
1fb8d4 |
SSPI_GSS_C_NT_HOSTBASED_SERVICE, &(context->target_name));
|
|
Packit |
1fb8d4 |
free(gss_name);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (SSPI_GSS_ERROR(major_status))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error: gss_import_name failed");
|
|
Packit |
1fb8d4 |
return -1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return 1;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef WITH_GSSAPI
|
|
Packit |
1fb8d4 |
static krb5_error_code KRB5_CALLCONV
|
|
Packit |
1fb8d4 |
acquire_cred(krb5_context ctx, krb5_principal client, const char* password)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
krb5_error_code ret;
|
|
Packit |
1fb8d4 |
krb5_creds creds;
|
|
Packit |
1fb8d4 |
krb5_deltat starttime = 0;
|
|
Packit |
1fb8d4 |
krb5_get_init_creds_opt* options = NULL;
|
|
Packit |
1fb8d4 |
krb5_ccache ccache;
|
|
Packit |
1fb8d4 |
krb5_init_creds_context init_ctx = NULL;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Get default ccache */
|
|
Packit |
1fb8d4 |
if ((ret = krb5_cc_default(ctx, &ccache)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error while getting default ccache");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((ret = krb5_cc_initialize(ctx, ccache, client)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error: could not initialize ccache");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
memset(&creds, 0, sizeof(creds));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((ret = krb5_get_init_creds_opt_alloc(ctx, &options)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error while allocating options");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Set default options */
|
|
Packit |
1fb8d4 |
krb5_get_init_creds_opt_set_forwardable(options, 0);
|
|
Packit |
1fb8d4 |
krb5_get_init_creds_opt_set_proxiable(options, 0);
|
|
Packit |
1fb8d4 |
#ifdef WITH_GSSAPI_MIT
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* for MIT we specify ccache output using an option */
|
|
Packit |
1fb8d4 |
if ((ret = krb5_get_init_creds_opt_set_out_ccache(ctx, options, ccache)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error while setting ccache output");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((ret = krb5_init_creds_init(ctx, client, NULL, NULL, starttime, options, &init_ctx)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error krb5_init_creds_init failed");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if ((ret = krb5_init_creds_set_password(ctx, init_ctx, password)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error krb5_init_creds_set_password failed");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Get credentials */
|
|
Packit |
1fb8d4 |
if ((ret = krb5_init_creds_get(ctx, init_ctx)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error while getting credentials");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Retrieve credentials */
|
|
Packit |
1fb8d4 |
if ((ret = krb5_init_creds_get_creds(ctx, init_ctx, &creds)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error while retrieving credentials");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#ifdef WITH_GSSAPI_HEIMDAL
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* For Heimdal, we use this function to store credentials */
|
|
Packit |
1fb8d4 |
if ((ret = krb5_init_creds_store(ctx, init_ctx, ccache)))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error while storing credentials");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
cleanup:
|
|
Packit |
1fb8d4 |
krb5_free_cred_contents(ctx, &creds);
|
|
Packit |
1fb8d4 |
#ifdef HAVE_AT_LEAST_KRB_V1_13
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* MIT Kerberos version 1.13 at minimum.
|
|
Packit |
1fb8d4 |
* For releases 1.12 and previous, krb5_get_init_creds_opt structure
|
|
Packit |
1fb8d4 |
* is freed in krb5_init_creds_free() */
|
|
Packit |
1fb8d4 |
if (options)
|
|
Packit |
1fb8d4 |
krb5_get_init_creds_opt_free(ctx, options);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (init_ctx)
|
|
Packit |
1fb8d4 |
krb5_init_creds_free(ctx, init_ctx);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ccache)
|
|
Packit |
1fb8d4 |
krb5_cc_close(ctx, ccache);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return ret;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static int init_creds(LPCWSTR username, size_t username_len, LPCWSTR password, size_t password_len)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
krb5_error_code ret = 0;
|
|
Packit |
1fb8d4 |
krb5_context ctx = NULL;
|
|
Packit |
1fb8d4 |
krb5_principal principal = NULL;
|
|
Packit |
1fb8d4 |
char* krb_name = NULL;
|
|
Packit |
1fb8d4 |
char* lusername = NULL;
|
|
Packit |
1fb8d4 |
char* lrealm = NULL;
|
|
Packit |
1fb8d4 |
char* lpassword = NULL;
|
|
Packit |
1fb8d4 |
int flags = 0;
|
|
Packit |
1fb8d4 |
char* pstr = NULL;
|
|
Packit |
1fb8d4 |
size_t krb_name_len = 0;
|
|
Packit |
1fb8d4 |
size_t lrealm_len = 0;
|
|
Packit |
1fb8d4 |
size_t lusername_len = 0;
|
|
Packit |
1fb8d4 |
int status = 0;
|
|
Packit |
1fb8d4 |
status = ConvertFromUnicode(CP_UTF8, 0, username,
|
|
Packit |
1fb8d4 |
username_len, &lusername, 0, NULL, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (status <= 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to convert username");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
status = ConvertFromUnicode(CP_UTF8, 0, password,
|
|
Packit |
1fb8d4 |
password_len, &lpassword, 0, NULL, NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (status <= 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Failed to convert password");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Could call krb5_init_secure_context, but it disallows user overrides */
|
|
Packit |
1fb8d4 |
ret = krb5_init_context(&ctx;;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ret)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error: while initializing Kerberos 5 library");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
ret = krb5_get_default_realm(ctx, &lrealm);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ret)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_WARN(TAG, "could not get Kerberos default realm");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
lrealm_len = strlen(lrealm);
|
|
Packit |
1fb8d4 |
lusername_len = strlen(lusername);
|
|
Packit |
1fb8d4 |
krb_name_len = lusername_len + lrealm_len + 1; // +1 for '@'
|
|
Packit |
1fb8d4 |
krb_name = calloc(krb_name_len + 1, sizeof(char));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!krb_name)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "could not allocate memory for string rep of principal\n");
|
|
Packit |
1fb8d4 |
ret = -1;
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Set buffer */
|
|
Packit |
1fb8d4 |
_snprintf(krb_name, krb_name_len + 1, "%s@%s", lusername, lrealm);
|
|
Packit |
1fb8d4 |
#ifdef WITH_DEBUG_NLA
|
|
Packit |
1fb8d4 |
WLog_DBG(TAG, "copied string is %s\n", krb_name);
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
pstr = strchr(lusername, '@');
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (pstr != NULL)
|
|
Packit |
1fb8d4 |
flags = KRB5_PRINCIPAL_PARSE_ENTERPRISE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* Use the specified principal name. */
|
|
Packit |
1fb8d4 |
ret = krb5_parse_name_flags(ctx, krb_name, flags,
|
|
Packit |
1fb8d4 |
&principal);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ret)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "could not convert %s to principal", krb_name);
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
ret = acquire_cred(ctx, principal, lpassword);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ret)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Kerberos credentials not found and could not be acquired");
|
|
Packit |
1fb8d4 |
goto cleanup;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
cleanup:
|
|
Packit |
1fb8d4 |
free(lusername);
|
|
Packit |
1fb8d4 |
free(lpassword);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (krb_name)
|
|
Packit |
1fb8d4 |
free(krb_name);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (lrealm)
|
|
Packit |
1fb8d4 |
krb5_free_default_realm(ctx, lrealm);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (principal)
|
|
Packit |
1fb8d4 |
krb5_free_principal(ctx, principal);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ctx)
|
|
Packit |
1fb8d4 |
krb5_free_context(ctx);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return ret;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_InitializeSecurityContextA(PCredHandle phCredential,
|
|
Packit |
1fb8d4 |
PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1,
|
|
Packit |
1fb8d4 |
ULONG TargetDataRep, PSecBufferDesc pInput, ULONG Reserved2,
|
|
Packit |
1fb8d4 |
PCtxtHandle phNewContext, PSecBufferDesc pOutput,
|
|
Packit |
1fb8d4 |
ULONG* pfContextAttr, PTimeStamp ptsExpiry)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
KRB_CONTEXT* context;
|
|
Packit |
1fb8d4 |
SSPI_CREDENTIALS* credentials;
|
|
Packit |
1fb8d4 |
PSecBuffer input_buffer = NULL;
|
|
Packit |
1fb8d4 |
PSecBuffer output_buffer = NULL;
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc input_tok = { 0 };
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc output_tok = { 0 };
|
|
Packit |
1fb8d4 |
sspi_gss_OID actual_mech;
|
|
Packit |
1fb8d4 |
sspi_gss_OID desired_mech;
|
|
Packit |
1fb8d4 |
UINT32 actual_services;
|
|
Packit |
1fb8d4 |
input_tok.length = 0;
|
|
Packit |
1fb8d4 |
output_tok.length = 0;
|
|
Packit |
1fb8d4 |
desired_mech = SSPI_GSS_C_SPNEGO_KRB5;
|
|
Packit |
1fb8d4 |
context = (KRB_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
context = kerberos_ContextNew();
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
return SEC_E_INSUFFICIENT_MEMORY;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
|
Packit |
1fb8d4 |
context->credentials = credentials;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (kerberos_SetContextServicePrincipalNameA(context, pszTargetName) < 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
kerberos_ContextFree(context);
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
|
Packit |
1fb8d4 |
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) KRB_PACKAGE_NAME);
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!pInput)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
#if defined(WITH_GSSAPI)
|
|
Packit |
1fb8d4 |
context->major_status = sspi_gss_init_sec_context(&(context->minor_status),
|
|
Packit |
1fb8d4 |
context->cred, &(context->gss_ctx), context->target_name,
|
|
Packit |
1fb8d4 |
desired_mech, SSPI_GSS_C_MUTUAL_FLAG | SSPI_GSS_C_DELEG_FLAG,
|
|
Packit |
1fb8d4 |
SSPI_GSS_C_INDEFINITE, SSPI_GSS_C_NO_CHANNEL_BINDINGS,
|
|
Packit |
1fb8d4 |
&input_tok, &actual_mech, &output_tok, &actual_services, &(context->actual_time));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (SSPI_GSS_ERROR(context->major_status))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* GSSAPI failed because we do not have credentials */
|
|
Packit |
1fb8d4 |
if (context->major_status & SSPI_GSS_S_NO_CRED)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Then let's try to acquire credentials using login and password,
|
|
Packit |
1fb8d4 |
* and only those two, means not with a smartcard.
|
|
Packit |
1fb8d4 |
* If we use smartcard-logon, the credentials have already
|
|
Packit |
1fb8d4 |
* been acquired by pkinit process. If not, returned error previously.
|
|
Packit |
1fb8d4 |
*/
|
|
Packit |
1fb8d4 |
if (init_creds(context->credentials->identity.User,
|
|
Packit |
1fb8d4 |
context->credentials->identity.UserLength,
|
|
Packit |
1fb8d4 |
context->credentials->identity.Password,
|
|
Packit |
1fb8d4 |
context->credentials->identity.PasswordLength))
|
|
Packit |
1fb8d4 |
return SEC_E_NO_CREDENTIALS;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
WLog_INFO(TAG, "Authenticated to Kerberos v5 via login/password");
|
|
Packit |
1fb8d4 |
/* retry GSSAPI call */
|
|
Packit |
1fb8d4 |
context->major_status = sspi_gss_init_sec_context(&(context->minor_status),
|
|
Packit |
1fb8d4 |
context->cred, &(context->gss_ctx), context->target_name,
|
|
Packit |
1fb8d4 |
desired_mech, SSPI_GSS_C_MUTUAL_FLAG | SSPI_GSS_C_DELEG_FLAG,
|
|
Packit |
1fb8d4 |
SSPI_GSS_C_INDEFINITE, SSPI_GSS_C_NO_CHANNEL_BINDINGS,
|
|
Packit |
1fb8d4 |
&input_tok, &actual_mech, &output_tok, &actual_services, &(context->actual_time));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (SSPI_GSS_ERROR(context->major_status))
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* We can't use Kerberos */
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "Init GSS security context failed : can't use Kerberos");
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
#endif
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (context->major_status & SSPI_GSS_S_CONTINUE_NEEDED)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (output_tok.length != 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!pOutput)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (pOutput->cBuffers < 1)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!output_buffer)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (output_buffer->cbBuffer < 1)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
CopyMemory(output_buffer->pvBuffer, output_tok.value, output_tok.length);
|
|
Packit |
1fb8d4 |
output_buffer->cbBuffer = output_tok.length;
|
|
Packit |
1fb8d4 |
sspi_gss_release_buffer(&(context->minor_status), &output_tok);
|
|
Packit |
1fb8d4 |
return SEC_I_CONTINUE_NEEDED;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!input_buffer)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (input_buffer->cbBuffer < 1)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
input_tok.value = input_buffer->pvBuffer;
|
|
Packit |
1fb8d4 |
input_tok.length = input_buffer->cbBuffer;
|
|
Packit |
1fb8d4 |
context->major_status = sspi_gss_init_sec_context(&(context->minor_status),
|
|
Packit |
1fb8d4 |
context->cred, &(context->gss_ctx), context->target_name,
|
|
Packit |
1fb8d4 |
desired_mech, SSPI_GSS_C_MUTUAL_FLAG | SSPI_GSS_C_DELEG_FLAG,
|
|
Packit |
1fb8d4 |
SSPI_GSS_C_INDEFINITE, SSPI_GSS_C_NO_CHANNEL_BINDINGS,
|
|
Packit |
1fb8d4 |
&input_tok, &actual_mech, &output_tok, &actual_services, &(context->actual_time));
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (SSPI_GSS_ERROR(context->major_status))
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (output_tok.length == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
/* Free output_buffer to detect second call in NLA */
|
|
Packit |
1fb8d4 |
output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN);
|
|
Packit |
1fb8d4 |
sspi_SecBufferFree(output_buffer);
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
else
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_DeleteSecurityContext(PCtxtHandle phContext)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
KRB_CONTEXT* context;
|
|
Packit |
1fb8d4 |
context = (KRB_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_HANDLE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
kerberos_ContextFree(context);
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesW(PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
ULONG ulAttribute,
|
|
Packit |
1fb8d4 |
void* pBuffer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_QueryContextAttributesA(PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
ULONG ulAttribute,
|
|
Packit |
1fb8d4 |
void* pBuffer)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (!phContext)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_HANDLE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!pBuffer)
|
|
Packit |
1fb8d4 |
return SEC_E_INSUFFICIENT_MEMORY;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (ulAttribute == SECPKG_ATTR_SIZES)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer;
|
|
Packit |
1fb8d4 |
/* The MaxTokenSize by default is 12,000 bytes. This has been the default value
|
|
Packit |
1fb8d4 |
* since Windows 2000 SP2 and still remains in Windows 7 and Windows 2008 R2.
|
|
Packit |
1fb8d4 |
* For Windows Server 2012, the default value of the MaxTokenSize registry
|
|
Packit |
1fb8d4 |
* entry is 48,000 bytes.*/
|
|
Packit |
1fb8d4 |
ContextSizes->cbMaxToken = KERBEROS_SecPkgInfoA.cbMaxToken;
|
|
Packit |
1fb8d4 |
ContextSizes->cbMaxSignature = 0; /* means verify not supported */
|
|
Packit |
1fb8d4 |
ContextSizes->cbBlockSize = 0; /* padding not used */
|
|
Packit |
1fb8d4 |
ContextSizes->cbSecurityTrailer = 60; /* gss_wrap adds additional 60 bytes for encrypt message */
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
return SEC_E_UNSUPPORTED_FUNCTION;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
|
|
Packit |
1fb8d4 |
PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int index;
|
|
Packit |
1fb8d4 |
int conf_state;
|
|
Packit |
1fb8d4 |
UINT32 major_status;
|
|
Packit |
1fb8d4 |
UINT32 minor_status;
|
|
Packit |
1fb8d4 |
KRB_CONTEXT* context;
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc input;
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc output;
|
|
Packit |
1fb8d4 |
PSecBuffer data_buffer = NULL;
|
|
Packit |
1fb8d4 |
context = (KRB_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_HANDLE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
for (index = 0; index < (int) pMessage->cBuffers; index++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
|
|
Packit |
1fb8d4 |
data_buffer = &pMessage->pBuffers[index];
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!data_buffer)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
input.value = data_buffer->pvBuffer;
|
|
Packit |
1fb8d4 |
input.length = data_buffer->cbBuffer;
|
|
Packit |
1fb8d4 |
major_status = sspi_gss_wrap(&minor_status, context->gss_ctx, TRUE,
|
|
Packit |
1fb8d4 |
SSPI_GSS_C_QOP_DEFAULT, &input, &conf_state, &output);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (SSPI_GSS_ERROR(major_status))
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (conf_state == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error: gss_wrap confidentiality was not applied");
|
|
Packit |
1fb8d4 |
sspi_gss_release_buffer(&minor_status, &output);
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
CopyMemory(data_buffer->pvBuffer, output.value, output.length);
|
|
Packit |
1fb8d4 |
sspi_gss_release_buffer(&minor_status, &output);
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_DecryptMessage(PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
int index;
|
|
Packit |
1fb8d4 |
int conf_state;
|
|
Packit |
1fb8d4 |
UINT32 major_status;
|
|
Packit |
1fb8d4 |
UINT32 minor_status;
|
|
Packit |
1fb8d4 |
KRB_CONTEXT* context;
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc input_data;
|
|
Packit |
1fb8d4 |
sspi_gss_buffer_desc output;
|
|
Packit |
1fb8d4 |
PSecBuffer data_buffer_to_unwrap = NULL;
|
|
Packit |
1fb8d4 |
context = (KRB_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!context)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_HANDLE;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
for (index = 0; index < (int) pMessage->cBuffers; index++)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
if (pMessage->pBuffers[index].BufferType == SECBUFFER_DATA)
|
|
Packit |
1fb8d4 |
data_buffer_to_unwrap = &pMessage->pBuffers[index];
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (!data_buffer_to_unwrap)
|
|
Packit |
1fb8d4 |
return SEC_E_INVALID_TOKEN;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
/* unwrap encrypted TLS key AND its signature */
|
|
Packit |
1fb8d4 |
input_data.value = data_buffer_to_unwrap->pvBuffer;
|
|
Packit |
1fb8d4 |
input_data.length = data_buffer_to_unwrap->cbBuffer;
|
|
Packit |
1fb8d4 |
major_status = sspi_gss_unwrap(&minor_status, context->gss_ctx, &input_data, &output, &conf_state,
|
|
Packit |
1fb8d4 |
NULL);
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (SSPI_GSS_ERROR(major_status))
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
if (conf_state == 0)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
WLog_ERR(TAG, "error: gss_unwrap confidentiality was not applied");
|
|
Packit |
1fb8d4 |
sspi_gss_release_buffer(&minor_status, &output);
|
|
Packit |
1fb8d4 |
return SEC_E_INTERNAL_ERROR;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
CopyMemory(data_buffer_to_unwrap->pvBuffer, output.value, output.length);
|
|
Packit |
1fb8d4 |
sspi_gss_release_buffer(&minor_status, &output);
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_MakeSignature(PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
static SECURITY_STATUS SEC_ENTRY kerberos_VerifySignature(PCtxtHandle phContext,
|
|
Packit |
1fb8d4 |
PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
return SEC_E_OK;
|
|
Packit |
1fb8d4 |
}
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
const SecurityFunctionTableA KERBEROS_SecurityFunctionTableA =
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
1, /* dwVersion */
|
|
Packit |
1fb8d4 |
NULL, /* EnumerateSecurityPackages */
|
|
Packit |
1fb8d4 |
kerberos_QueryCredentialsAttributesA, /* QueryCredentialsAttributes */
|
|
Packit |
1fb8d4 |
kerberos_AcquireCredentialsHandleA, /* AcquireCredentialsHandle */
|
|
Packit |
1fb8d4 |
kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved2 */
|
|
Packit |
1fb8d4 |
kerberos_InitializeSecurityContextA, /* InitializeSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* AcceptSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* CompleteAuthToken */
|
|
Packit |
1fb8d4 |
kerberos_DeleteSecurityContext, /* DeleteSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* ApplyControlToken */
|
|
Packit |
1fb8d4 |
kerberos_QueryContextAttributesA, /* QueryContextAttributes */
|
|
Packit |
1fb8d4 |
NULL, /* ImpersonateSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* RevertSecurityContext */
|
|
Packit |
1fb8d4 |
kerberos_MakeSignature, /* MakeSignature */
|
|
Packit |
1fb8d4 |
kerberos_VerifySignature, /* VerifySignature */
|
|
Packit |
1fb8d4 |
NULL, /* FreeContextBuffer */
|
|
Packit |
1fb8d4 |
NULL, /* QuerySecurityPackageInfo */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved3 */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved4 */
|
|
Packit |
1fb8d4 |
NULL, /* ExportSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* ImportSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* AddCredentials */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved8 */
|
|
Packit |
1fb8d4 |
NULL, /* QuerySecurityContextToken */
|
|
Packit |
1fb8d4 |
kerberos_EncryptMessage, /* EncryptMessage */
|
|
Packit |
1fb8d4 |
kerberos_DecryptMessage, /* DecryptMessage */
|
|
Packit |
1fb8d4 |
NULL, /* SetContextAttributes */
|
|
Packit |
1fb8d4 |
};
|
|
Packit |
1fb8d4 |
|
|
Packit |
1fb8d4 |
const SecurityFunctionTableW KERBEROS_SecurityFunctionTableW =
|
|
Packit |
1fb8d4 |
{
|
|
Packit |
1fb8d4 |
1, /* dwVersion */
|
|
Packit |
1fb8d4 |
NULL, /* EnumerateSecurityPackages */
|
|
Packit |
1fb8d4 |
kerberos_QueryCredentialsAttributesW, /* QueryCredentialsAttributes */
|
|
Packit |
1fb8d4 |
kerberos_AcquireCredentialsHandleW, /* AcquireCredentialsHandle */
|
|
Packit |
1fb8d4 |
kerberos_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved2 */
|
|
Packit |
1fb8d4 |
kerberos_InitializeSecurityContextW, /* InitializeSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* AcceptSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* CompleteAuthToken */
|
|
Packit |
1fb8d4 |
kerberos_DeleteSecurityContext, /* DeleteSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* ApplyControlToken */
|
|
Packit |
1fb8d4 |
kerberos_QueryContextAttributesW, /* QueryContextAttributes */
|
|
Packit |
1fb8d4 |
NULL, /* ImpersonateSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* RevertSecurityContext */
|
|
Packit |
1fb8d4 |
kerberos_MakeSignature, /* MakeSignature */
|
|
Packit |
1fb8d4 |
kerberos_VerifySignature, /* VerifySignature */
|
|
Packit |
1fb8d4 |
NULL, /* FreeContextBuffer */
|
|
Packit |
1fb8d4 |
NULL, /* QuerySecurityPackageInfo */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved3 */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved4 */
|
|
Packit |
1fb8d4 |
NULL, /* ExportSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* ImportSecurityContext */
|
|
Packit |
1fb8d4 |
NULL, /* AddCredentials */
|
|
Packit |
1fb8d4 |
NULL, /* Reserved8 */
|
|
Packit |
1fb8d4 |
NULL, /* QuerySecurityContextToken */
|
|
Packit |
1fb8d4 |
kerberos_EncryptMessage, /* EncryptMessage */
|
|
Packit |
1fb8d4 |
kerberos_DecryptMessage, /* DecryptMessage */
|
|
Packit |
1fb8d4 |
NULL, /* SetContextAttributes */
|
|
Packit |
1fb8d4 |
};
|