/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright (c) Likewise Software. All rights Reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewise.com
*/
/*
* Copyright (C) Likewise Software. All rights reserved.
*
* Module Name:
*
* gssntlm.c
*
* Abstract:
*
* GSS wrapper functions for NTLM implementation.
*
* Authors: Marc Guy (mguy@likewisesoftware.com)
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
UINT32 ntlm_gss_duplicate_oid(
UINT32 MinorStatus,
const gss_OID_desc *const Oid,
gss_OID *NewOid
);
gss_OID_desc gGssNtlmOidDesc = {
.length = GSS_MECH_NTLM_LEN,
.elements = GSS_MECH_NTLM
};
gss_OID gGssNtlmOid = &gGssNtlmOidDesc;
gss_OID_desc gGssCredOptionPasswordOidDesc = {
.length = GSS_CRED_OPT_PW_LEN,
.elements = GSS_CRED_OPT_PW
};
gss_OID gGssCredOptionPasswordOid = &gGssCredOptionPasswordOidDesc;
//
// Since there is no GSSAPI mech plugin header, this must be kept in sync with
// gss_mechanism in krb5/src/lib/gssapi/mglueP.h.
//
typedef struct _GSS_MECH_CONFIG
{
gss_OID_desc MechType;
PVOID pContext;
OM_uint32
(*gss_acquire_cred)(
OM_uint32*,
gss_name_t,
OM_uint32,
gss_OID_set,
INT,
gss_cred_id_t*,
gss_OID_set*,
OM_uint32*
);
OM_uint32
(*gss_release_cred)(
OM_uint32*,
gss_cred_id_t*
);
OM_uint32
(*gss_init_sec_cred)(
OM_uint32*,
gss_cred_id_t,
gss_ctx_id_t*,
gss_name_t,
gss_OID,
OM_uint32,
OM_uint32,
gss_channel_bindings_t,
gss_buffer_t,
gss_OID*,
gss_buffer_t,
OM_uint32*,
OM_uint32*
);
OM_uint32
(*gss_accept_sec_context)(
OM_uint32*,
gss_ctx_id_t*,
gss_cred_id_t,
gss_buffer_t,
gss_channel_bindings_t,
gss_name_t*,
gss_OID*,
gss_buffer_t,
OM_uint32*,
OM_uint32*,
gss_cred_id_t*
);
OM_uint32
(*gss_process_context_token)(
OM_uint32*,
gss_ctx_id_t,
gss_buffer_t
);
OM_uint32
(*gss_delete_sec_context)(
OM_uint32*,
gss_ctx_id_t*,
gss_buffer_t
);
OM_uint32
(*gss_context_time)(
OM_uint32*,
gss_ctx_id_t,
OM_uint32*
);
OM_uint32
(*gss_get_mic)(
OM_uint32*,
gss_ctx_id_t,
gss_qop_t,
gss_buffer_t,
gss_buffer_t
);
OM_uint32
(*gss_verify_mic)(
OM_uint32*,
gss_ctx_id_t,
gss_buffer_t,
gss_buffer_t,
gss_qop_t*
);
OM_uint32
(*gss_wrap)(
OM_uint32*,
gss_ctx_id_t,
INT,
gss_qop_t,
gss_buffer_t,
PINT,
gss_buffer_t
);
OM_uint32
(*gss_unwrap)(
OM_uint32*,
gss_ctx_id_t,
gss_buffer_t,
gss_buffer_t,
PINT,
gss_qop_t*
);
OM_uint32
(*gss_display_status)(
OM_uint32*,
OM_uint32,
INT,
gss_OID,
OM_uint32*,
gss_buffer_t
);
OM_uint32
(*gss_indicate_mechs)(
OM_uint32*,
gss_OID_set*
);
OM_uint32
(*gss_compare_name)(
OM_uint32*,
gss_name_t,
gss_name_t,
PINT);
OM_uint32
(*gss_display_name)(
OM_uint32*,
gss_name_t,
gss_buffer_t,
gss_OID*
);
OM_uint32
(*gss_import_name)(
OM_uint32*,
gss_buffer_t,
gss_OID,
gss_name_t*
);
OM_uint32
(*gss_release_name)(
OM_uint32*,
gss_name_t*);
OM_uint32
(*gss_inquire_cred)(
OM_uint32*,
gss_cred_id_t,
gss_name_t*,
OM_uint32*,
PINT,
gss_OID_set*
);
OM_uint32
(*gss_add_cred)(
OM_uint32*,
gss_cred_id_t,
gss_name_t,
gss_OID,
gss_cred_usage_t,
OM_uint32,
OM_uint32,
gss_cred_id_t*,
gss_OID_set*,
OM_uint32*,
OM_uint32*
);
OM_uint32
(*gss_export_sec_context)(
OM_uint32,
gss_ctx_id_t*,
gss_buffer_t
);
OM_uint32
(*gss_import_sec_context)(
OM_uint32,
gss_buffer_t,
gss_ctx_id_t*
);
OM_uint32
(*gss_inquire_cred_by_mech)(
OM_uint32*,
gss_cred_id_t,
gss_OID,
gss_name_t*,
OM_uint32*,
OM_uint32*,
gss_cred_usage_t*
);
OM_uint32
(*gss_inquire_names_for_mech)(
OM_uint32,
gss_OID,
gss_OID_set*
);
OM_uint32
(*gss_inquire_context)(
OM_uint32*,
gss_ctx_id_t,
gss_name_t*,
gss_name_t*,
OM_uint32*,
gss_OID*,
OM_uint32*,
PINT,
PINT
);
OM_uint32
(*gss_internal_release_oid)(
OM_uint32*,
gss_OID*
);
OM_uint32
(*gss_wrap_size_limit)(
OM_uint32*,
gss_ctx_id_t,
INT,
gss_qop_t,
OM_uint32,
OM_uint32*
);
OM_uint32
(*gss_export_name)(
OM_uint32*,
const gss_name_t,
gss_buffer_t
);
OM_uint32
(*gss_store_cred)(
OM_uint32*,
const gss_cred_id_t,
gss_cred_usage_t,
const gss_OID,
OM_uint32,
OM_uint32,
gss_OID_set*,
gss_cred_usage_t*
);
OM_uint32
(*gss_inquire_sec_context_by_oid)(
OM_uint32*,
const gss_ctx_id_t,
const gss_OID,
gss_buffer_set_t*
);
OM_uint32
(*gss_inquire_cred_by_oid)(
OM_uint32*,
const gss_cred_id_t,
const gss_OID,
gss_buffer_set_t*
);
OM_uint32
(*gss_set_sec_context_option)(
OM_uint32*,
gss_ctx_id_t*,
const gss_OID,
const gss_buffer_t
);
OM_uint32
(*gssspi_set_cred_option)(
OM_uint32*,
gss_cred_id_t,
const gss_OID,
const gss_buffer_t
);
OM_uint32
(*gssspi_mech_invoke)(
OM_uint32*,
const gss_OID,
const gss_OID,
gss_buffer_t
);
OM_uint32
(*gss_wrap_aead)(
OM_uint32*,
gss_ctx_id_t,
INT,
gss_qop_t,
gss_buffer_t,
gss_buffer_t,
PINT,
gss_buffer_t
);
OM_uint32
(*gss_unwrap_aead)(
OM_uint32*,
gss_ctx_id_t,
gss_buffer_t,
gss_buffer_t,
gss_buffer_t,
PINT,
gss_qop_t*);
OM_uint32
(*gss_wrap_iov)(
OM_uint32*,
gss_ctx_id_t,
INT,
gss_qop_t,
PINT,
gss_iov_buffer_desc*,
INT
);
OM_uint32
(*gss_unwrap_iov)(
OM_uint32*,
gss_ctx_id_t,
PINT,
gss_qop_t*,
gss_iov_buffer_desc*,
INT
);
OM_uint32
(*gss_wrap_iov_length)(
OM_uint32*,
gss_ctx_id_t,
INT,
gss_qop_t,
PINT,
gss_iov_buffer_desc*,
INT
);
OM_uint32
(*gss_complete_auth_token)(
OM_uint32*,
const gss_ctx_id_t,
gss_buffer_t
);
OM_uint32
(*gss_acquire_cred_impersonate_name)(
OM_uint32 *,
const gss_cred_id_t,
const gss_name_t,
OM_uint32,
const gss_OID_set,
gss_cred_usage_t,
gss_cred_id_t *,
gss_OID_set *,
OM_uint32 *
);
OM_uint32
(*gss_add_cred_impersonate_name)(
OM_uint32 *,
gss_cred_id_t,
const gss_cred_id_t,
const gss_name_t,
const gss_OID,
gss_cred_usage_t,
OM_uint32,
OM_uint32,
gss_cred_id_t *,
gss_OID_set *,
OM_uint32 *,
OM_uint32 *
);
OM_uint32
(*gss_display_name_ext)(
OM_uint32 *,
gss_name_t,
gss_OID,
gss_buffer_t
);
OM_uint32
(*gss_inquire_name)(
OM_uint32 *,
gss_name_t,
int *,
gss_OID *,
gss_buffer_set_t *
);
OM_uint32
(*gss_get_name_attribute)(
OM_uint32 *,
gss_name_t,
gss_buffer_t,
int *,
int *,
gss_buffer_t,
gss_buffer_t,
int *
);
OM_uint32
(*gss_set_name_attribute)(
OM_uint32 *,
gss_name_t,
int,
gss_buffer_t,
gss_buffer_t
);
OM_uint32
(*gss_delete_name_attribute)(
OM_uint32 *,
gss_name_t,
gss_buffer_t
);
OM_uint32
(*gss_export_name_composite)(
OM_uint32 *,
gss_name_t,
gss_buffer_t
);
OM_uint32
(*gss_map_name_to_any)(
OM_uint32 *,
gss_name_t,
int,
gss_buffer_t,
gss_any_t *
);
OM_uint32
(*gss_release_any_name_mapping)(
OM_uint32 *,
gss_name_t,
gss_buffer_t,
gss_any_t *
);
} GSS_MECH_CONFIG, *PGSS_MECH_CONFIG;
typedef struct _NTLM_GSS_NAME
{
// This always points to a static global structure
gss_OID NameType;
PSTR pszName;
NTLM_CONTEXT_HANDLE hContext;
} NTLM_GSS_NAME, *PNTLM_GSS_NAME;
typedef struct _NTLM_GSS_CREDS
{
PSTR pszUserName;
DWORD fCredentialUse;
TimeStamp tsExpiry;
NTLM_CRED_HANDLE CredHandle;
} NTLM_GSS_CREDS, *PNTLM_GSS_CREDS;
//
// Prototypes
//
PGSS_MECH_CONFIG
gss_mech_initialize(
void
);
//
// Globals
//
static GSS_MECH_CONFIG gNtlmMech =
{
{GSS_MECH_NTLM_LEN, GSS_MECH_NTLM},
NULL,
ntlm_gss_acquire_cred,
ntlm_gss_release_cred,
ntlm_gss_init_sec_context,
ntlm_gss_accept_sec_context,
NULL, //ntlm_gss_process_context_token,
ntlm_gss_delete_sec_context,
NULL, //ntlm_gss_context_time,
ntlm_gss_get_mic,
ntlm_gss_verify_mic,
ntlm_gss_wrap,
ntlm_gss_unwrap,
ntlm_gss_display_status,
NULL, //ntlm_gss_indicate_mechs,
NULL, //ntlm_gss_compare_name,
ntlm_gss_display_name,
ntlm_gss_import_name,
ntlm_gss_release_name,
ntlm_gss_inquire_cred,
NULL, //ntlm_gss_add_cred,
NULL, //ntlm_gss_export_sec_context,
NULL, //ntlm_gss_import_sec_context,
NULL, //ntlm_gss_inquire_cred_by_mech,
NULL, //ntlm_gss_inquire_names_for_mech,
ntlm_gss_inquire_context,
ntlm_gss_release_oid,
NULL, //ntlm_gss_wrap_size_limit,
NULL, //ntlm_gss_export_name,
NULL, //ntlm_gss_store_cred,
ntlm_gss_inquire_sec_context_by_oid,
NULL, //ntlm_gss_inquire_cred_by_oid,
NULL, //ntlm_gss_set_sec_context_option,
ntlm_gssspi_set_cred_option,
NULL, //ntlm_gssspi_mech_invoke,
NULL, //ntlm_gss_wrap_aead,
NULL, //ntlm_gss_unwrap_aead,
ntlm_gss_wrap_iov,
ntlm_gss_unwrap_iov,
NULL, //ntlm_gss_wrap_iov_length,
NULL, //ntlm_gss_complete_auth_token,
NULL, //ntlm_gss_inquire_context2
.gss_get_name_attribute = ntlm_gss_get_name_attribute
};
//
// Function Definitions
//
OM_uint32
ntlm_gss_acquire_cred(
OM_uint32* pMinorStatus,
const gss_name_t hDesiredName,
OM_uint32 nTimeReq,
const gss_OID_set pDesiredMechs,
gss_cred_usage_t CredUsage,
gss_cred_id_t* pOutputCredHandle,
gss_OID_set* pActualMechs,
OM_uint32 *pTimeRec
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
PNTLM_GSS_CREDS pCreds = NULL;
DWORD fCredentialUse = 0;
PNTLM_GSS_NAME pDesiredName = (PNTLM_GSS_NAME)hDesiredName;
BOOLEAN bIsUserName = TRUE;
PCSTR pszName = NULL;
OM_uint32 timeRec = (OM_uint32)-1;
if (pActualMechs)
{
*pActualMechs = NULL;
}
if (pTimeRec)
{
*pTimeRec = 0;
}
switch(CredUsage)
{
case GSS_C_ACCEPT:
fCredentialUse = NTLM_CRED_INBOUND;
break;
case GSS_C_INITIATE:
fCredentialUse = NTLM_CRED_OUTBOUND;
break;
default:
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (pDesiredName)
{
MajorStatus = ntlm_gss_compare_oid(
&MinorStatus,
pDesiredName->NameType,
GSS_C_NT_USER_NAME,
&bIsUserName);
BAIL_ON_LSA_ERROR(MinorStatus);
if (!bIsUserName)
{
MajorStatus = GSS_S_BAD_NAMETYPE;
MinorStatus = LW_ERROR_BAD_NAMETYPE;
BAIL_ON_LSA_ERROR(MinorStatus);
}
pszName = pDesiredName->pszName;
}
MinorStatus = LwAllocateMemory(
sizeof(*pCreds),
OUT_PPVOID(&pCreds));
BAIL_ON_LSA_ERROR(MinorStatus);
MinorStatus = LwStrDupOrNull(
pszName,
&pCreds->pszUserName);
BAIL_ON_LSA_ERROR(MinorStatus);
pCreds->fCredentialUse = fCredentialUse;
MinorStatus = NtlmClientAcquireCredentialsHandle(
pCreds->pszUserName,
"NTLM",
pCreds->fCredentialUse,
NULL,
NULL,
&pCreds->CredHandle,
&pCreds->tsExpiry
);
if (MinorStatus == LW_ERROR_NO_CRED)
{
// Return a valid credentials handle anyway. Hopefully the caller will
// call gssspi_set_cred_option for the credentials to be fully
// initialized.
MinorStatus = 0;
}
else
{
BAIL_ON_LSA_ERROR(MinorStatus);
timeRec = pCreds->tsExpiry;
}
*pOutputCredHandle = (gss_cred_id_t)pCreds;
cleanup:
*pMinorStatus = MinorStatus;
if (pActualMechs)
{
*pActualMechs = NULL;
}
if (pTimeRec)
{
*pTimeRec = timeRec;
}
return MajorStatus;
error:
*pOutputCredHandle = NULL;
ntlm_gss_release_cred(
NULL,
(gss_cred_id_t*)&pCreds);
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
if (pTimeRec)
{
*pTimeRec = 0;
}
goto cleanup;
}
OM_uint32
ntlm_gss_release_cred(
OM_uint32* pMinorStatus,
gss_cred_id_t* pCredHandle
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
PNTLM_GSS_CREDS pCreds = NULL;
if (!pCredHandle)
{
MajorStatus = GSS_S_NO_CRED;
MinorStatus = LW_ERROR_NO_CRED;
BAIL_ON_LSA_ERROR(MinorStatus);
}
pCreds = (PNTLM_GSS_CREDS)*pCredHandle;
if (!pCreds)
{
MajorStatus = GSS_S_NO_CRED;
MinorStatus = LW_ERROR_NO_CRED;
BAIL_ON_LSA_ERROR(MinorStatus);
}
MinorStatus = NtlmClientFreeCredentialsHandle(
&pCreds->CredHandle
);
// Ignore this error until all the data is freed. Be careful not to
// overwrite MinorStatus.
LW_SAFE_FREE_MEMORY(pCreds->pszUserName);
LW_SAFE_FREE_MEMORY(pCreds);
*pCredHandle = NULL;
BAIL_ON_LSA_ERROR(MinorStatus);
cleanup:
if (pMinorStatus)
{
*pMinorStatus = MinorStatus;
}
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_init_sec_context(
OM_uint32* pMinorStatus,
const gss_cred_id_t InitiatorCredHandle,
gss_ctx_id_t* pContextHandle,
const gss_name_t pTargetName,
const gss_OID pMechType,
OM_uint32 nReqFlags,
OM_uint32 nTimeReq,
const gss_channel_bindings_t pInputChanBindings,
const gss_buffer_t pInputToken,
gss_OID* pActualMechType,
gss_buffer_t pOutputToken,
OM_uint32* pRetFlags,
OM_uint32* pTimeRec
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE hContext = NULL;
NTLM_CONTEXT_HANDLE hNewContext = NULL;
TimeStamp tsExpiry = 0;
SecBufferDesc InputBuffer = {0};
SecBufferDesc OutputBuffer = {0};
SecBuffer InputToken = {0};
SecBuffer OutputToken = {0};
NTLM_CRED_HANDLE CredHandle = NULL;
TimeStamp Expiry = 0;
DWORD dwNtlmFlags = NTLM_FLAG_NEGOTIATE_DEFAULT;
DWORD dwOutNtlmFlags = 0;
OM_uint32 RetFlags = 0;
InputBuffer.cBuffers = 1;
InputBuffer.pBuffers = &InputToken;
OutputBuffer.cBuffers = 1;
OutputBuffer.pBuffers = &OutputToken;
InputToken.BufferType = SECBUFFER_TOKEN;
if(pInputToken)
{
InputToken.cbBuffer = pInputToken->length;
InputToken.pvBuffer = pInputToken->value;
}
if( pContextHandle)
{
hContext = (NTLM_CONTEXT_HANDLE)*pContextHandle;
}
// if no credentials are passed in, create default creds
if (GSS_C_NO_CREDENTIAL == InitiatorCredHandle)
{
MinorStatus = NtlmClientAcquireCredentialsHandle(
NULL,
"NTLM",
NTLM_CRED_OUTBOUND,
NULL,
NULL,
&CredHandle,
&Expiry
);
BAIL_ON_LSA_ERROR(MinorStatus);
}
else
{
CredHandle = ((PNTLM_GSS_CREDS)InitiatorCredHandle)->
CredHandle;
if(CredHandle == NULL)
{
// This means ntlm_gss_acquire_cred was called, but not default
// credentials were available. The user should have called
// ntlm_gssspi_set_cred_option to supply a password, but they did
// not.
MajorStatus = GSS_S_NO_CRED;
MinorStatus = LW_ERROR_NO_CRED;
BAIL_ON_LSA_ERROR(MinorStatus);
}
}
// NTLM supports only signing and sealing (both at the same time)
if ((nReqFlags & GSS_C_INTEG_FLAG) ||
(nReqFlags & GSS_C_CONF_FLAG))
{
dwNtlmFlags |= (NTLM_FLAG_SIGN | NTLM_FLAG_SEAL);
}
MinorStatus = NtlmClientInitializeSecurityContext(
&CredHandle,
&hContext,
(SEC_CHAR*)pTargetName,
dwNtlmFlags,
0, // Reserved
NTLM_NATIVE_DATA_REP,
&InputBuffer,
0, // Reserved
&hNewContext,
&OutputBuffer,
&dwOutNtlmFlags,
&tsExpiry
);
if (MinorStatus == LW_WARNING_CONTINUE_NEEDED)
{
MajorStatus = GSS_S_CONTINUE_NEEDED;
}
else
{
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (dwOutNtlmFlags & NTLM_FLAG_SIGN)
{
RetFlags |= GSS_C_INTEG_FLAG;
}
if (dwOutNtlmFlags & NTLM_FLAG_SEAL)
{
RetFlags |= GSS_C_CONF_FLAG;
}
cleanup:
*pMinorStatus = MinorStatus;
if (GSS_C_NO_CREDENTIAL == InitiatorCredHandle && CredHandle)
{
NtlmClientFreeCredentialsHandle(&CredHandle);
}
if (pOutputToken)
{
pOutputToken->length = OutputToken.cbBuffer;
pOutputToken->value = OutputToken.pvBuffer;
}
if (pActualMechType)
{
*pActualMechType = gGssNtlmOid;
}
if (pRetFlags)
{
*pRetFlags = RetFlags;
}
if (pTimeRec)
{
*pTimeRec = GSS_C_INDEFINITE;
}
if (pContextHandle)
{
*pContextHandle = (gss_ctx_id_t)hNewContext;
}
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_accept_sec_context(
OM_uint32* pMinorStatus,
gss_ctx_id_t *pContextHandle,
const gss_cred_id_t AcceptorCredHandle,
const gss_buffer_t pInputTokenBuffer,
const gss_channel_bindings_t pInputChanBindings,
gss_name_t* ppSrcName,
gss_OID* pMechType,
gss_buffer_t pOutputToken,
OM_uint32* pRetFlags,
OM_uint32* pTimeRec,
gss_cred_id_t* pDelegatedCredHandle
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
DWORD dwRetFlags = 0;
DWORD dwFinalFlags = 0;
SecBufferDesc InputBuffer = {0};
SecBufferDesc OutputBuffer = {0};
SecBuffer InputToken = {0};
SecBuffer OutputToken = {0};
TimeStamp tsExpiry = 0;
gss_name_t pSrcName = NULL;
NTLM_CONTEXT_HANDLE NewCtxtHandle = NULL;
gss_cred_id_t LocalCreds = NULL;
// Do not free
gss_cred_id_t PassAcceptorCredHandle = NULL;
*pMinorStatus = LW_ERROR_SUCCESS;
if (ppSrcName)
{
*ppSrcName = NULL;
}
if (pMechType)
{
*pMechType = NULL;
}
if (pTimeRec)
{
*pTimeRec = 0;
}
if (pDelegatedCredHandle)
{
*pDelegatedCredHandle = NULL;
}
if (pRetFlags)
{
dwRetFlags = *pRetFlags;
}
if (AcceptorCredHandle)
{
PassAcceptorCredHandle = AcceptorCredHandle;
}
else
{
MajorStatus = ntlm_gss_acquire_cred(
&MinorStatus,
NULL,
0,
NULL,
GSS_C_ACCEPT,
&LocalCreds,
NULL,
NULL);
BAIL_ON_LSA_ERROR(MinorStatus);
PassAcceptorCredHandle = LocalCreds;
}
#if 0
// convert
switch (dwRetFlags)
{
case GSS_C_DELEG_FLAG:
break;
case GSS_C_MUTUAL_FLAG:
break;
case GSS_C_REPLAY_FLAG:
break;
case GSS_C_SEQUENCE_FLAG:
break;
case GSS_C_CONF_FLAG:
break;
case GSS_C_INTEG_FLAG:
break;
case GSS_C_ANON_FLAG:
break;
case GSS_C_PROT_READY_FLAG:
break;
case GSS_C_TRANS_FLAG:
break;
}
#endif
memset(pOutputToken, 0, sizeof(*pOutputToken));
InputBuffer.cBuffers = 1;
InputBuffer.pBuffers = &InputToken;
OutputBuffer.cBuffers = 1;
OutputBuffer.pBuffers = &OutputToken;
InputToken.BufferType = SECBUFFER_TOKEN;
InputToken.cbBuffer = pInputTokenBuffer->length;
InputToken.pvBuffer = pInputTokenBuffer->value;
MinorStatus = NtlmClientAcceptSecurityContext(
&((PNTLM_GSS_CREDS)PassAcceptorCredHandle)->CredHandle,
(PNTLM_CONTEXT_HANDLE)pContextHandle,
&InputBuffer,
dwFinalFlags,
NTLM_NATIVE_DATA_REP,
&NewCtxtHandle,
&OutputBuffer,
pTimeRec,
&tsExpiry);
if (MinorStatus == LW_WARNING_CONTINUE_NEEDED)
{
MajorStatus = GSS_S_CONTINUE_NEEDED;
}
else
{
BAIL_ON_LSA_ERROR(MinorStatus);
dwRetFlags |= GSS_C_CONF_FLAG;
dwRetFlags |= GSS_C_INTEG_FLAG;
MajorStatus = ntlm_gss_inquire_context(
&MinorStatus,
(gss_ctx_id_t)NewCtxtHandle,
&pSrcName,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
);
BAIL_ON_LSA_ERROR(MinorStatus);
}
cleanup:
*pMinorStatus = MinorStatus;
if (pOutputToken)
{
pOutputToken->length = OutputToken.cbBuffer;
pOutputToken->value = OutputToken.pvBuffer;
}
*pContextHandle = (gss_ctx_id_t)NewCtxtHandle;
ntlm_gss_release_cred(
NULL,
&LocalCreds);
if (pMechType)
{
*pMechType = gGssNtlmOid;
}
if (ppSrcName)
{
*ppSrcName = pSrcName;
}
if (pRetFlags)
{
*pRetFlags = dwRetFlags;
}
if (pTimeRec)
{
*pTimeRec = GSS_C_INDEFINITE;
}
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
ntlm_gss_release_name(NULL, &pSrcName);
goto cleanup;
}
OM_uint32
ntlm_gss_delete_sec_context(
OM_uint32* pMinorStatus,
gss_ctx_id_t* pContextHandle,
gss_buffer_t OutputToken
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = NULL;
if (OutputToken)
{
OutputToken = GSS_C_NO_BUFFER;
}
if (!pContextHandle || !*pContextHandle)
{
MajorStatus = GSS_S_NO_CONTEXT;
MinorStatus = LW_ERROR_NO_CONTEXT;
BAIL_ON_LSA_ERROR(MinorStatus);
}
ContextHandle = (NTLM_CONTEXT_HANDLE)*pContextHandle;
MinorStatus = NtlmClientDeleteSecurityContext(
&ContextHandle
);
BAIL_ON_LSA_ERROR(MinorStatus);
cleanup:
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_get_mic(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
gss_qop_t Qop,
gss_buffer_t Message,
gss_buffer_t Token
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecBufferDesc NtlmMessage = {0};
SecBuffer NtlmBuffer[2];
PBYTE pNtlmToken = NULL;
SecPkgContext_Sizes spcSizes = {0};
if(Qop != GSS_C_QOP_DEFAULT)
{
MajorStatus = GSS_S_BAD_QOP;
BAIL_ON_LSA_ERROR(MajorStatus);
}
MinorStatus = NtlmClientQueryContextAttributes(
&ContextHandle,
SECPKG_ATTR_SIZES,
&spcSizes
);
BAIL_ON_LSA_ERROR(MinorStatus);
NtlmMessage.cBuffers = 2;
NtlmMessage.pBuffers = NtlmBuffer;
MinorStatus = LwAllocateMemory(
spcSizes.cbMaxSignature,
OUT_PPVOID(&pNtlmToken));
BAIL_ON_LSA_ERROR(MinorStatus);
NtlmBuffer[0].BufferType = SECBUFFER_DATA;
NtlmBuffer[0].cbBuffer = Message->length;
NtlmBuffer[0].pvBuffer = Message->value;
NtlmBuffer[1].BufferType = SECBUFFER_TOKEN;
NtlmBuffer[1].cbBuffer = spcSizes.cbMaxSignature;
NtlmBuffer[1].pvBuffer = pNtlmToken;
MinorStatus = NtlmClientMakeSignature(
&ContextHandle,
0,
&NtlmMessage,
0
);
BAIL_ON_LSA_ERROR(MinorStatus);
Token->value = NtlmBuffer[1].pvBuffer;
Token->length = NtlmBuffer[1].cbBuffer;
cleanup:
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
LW_SAFE_FREE_MEMORY(pNtlmToken);
Token->value = NULL;
Token->length = 0;
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_verify_mic(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
gss_buffer_t Message,
gss_buffer_t Token,
gss_qop_t* pQop
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecBufferDesc NtlmMessage = {0};
SecBuffer NtlmBuffer[2];
PNTLM_SIGNATURE pSignature = NULL;
DWORD dwQop = GSS_C_QOP_DEFAULT;
NtlmMessage.cBuffers = 2;
NtlmMessage.pBuffers = NtlmBuffer;
NtlmBuffer[0].BufferType = SECBUFFER_DATA;
NtlmBuffer[0].cbBuffer = Message->length;
NtlmBuffer[0].pvBuffer = Message->value;
NtlmBuffer[1].BufferType = SECBUFFER_TOKEN;
NtlmBuffer[1].cbBuffer = Token->length;
NtlmBuffer[1].pvBuffer = Token->value;
MinorStatus = NtlmClientVerifySignature(
&ContextHandle,
&NtlmMessage,
0,
&dwQop
);
if (MinorStatus)
{
MajorStatus = GSS_S_BAD_SIG;
}
BAIL_ON_LSA_ERROR(MinorStatus);
pSignature = (PNTLM_SIGNATURE)Token->value;
if (pSignature->dwVersion == NTLM_VERSION &&
pSignature->v1.encrypted.dwCounterValue == 0 &&
pSignature->v1.encrypted.dwCrc32 == 0 &&
pSignature->v1.encrypted.dwMsgSeqNum == 0)
{
dwQop = GSS_C_QOP_DUMMY_SIG;
}
cleanup:
if(pQop)
{
*pQop = (gss_qop_t)dwQop;
}
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
dwQop = GSS_C_QOP_DEFAULT;
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_wrap(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
INT nEncrypt,
gss_qop_t Qop,
gss_buffer_t InputMessage,
PINT pEncrypted,
gss_buffer_t OutputMessage
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecBufferDesc Message = {0};
SecBuffer NtlmBuffer[2];
SecPkgContext_Sizes Sizes = {0};
DWORD dwBufferSize = 0;
PBYTE pBuffer = NULL;
INT nEncrypted = 0;
Message.cBuffers = 2;
Message.pBuffers = NtlmBuffer;
memset(NtlmBuffer, 0, sizeof(SecBuffer) * Message.cBuffers);
if(Qop != GSS_C_QOP_DEFAULT)
{
MajorStatus = GSS_S_BAD_QOP;
BAIL_ON_LSA_ERROR(MajorStatus);
}
// Since every encrypted message gets a signature, we need to get the size
MinorStatus = NtlmClientQueryContextAttributes(
&ContextHandle,
SECPKG_ATTR_SIZES,
&Sizes
);
BAIL_ON_LSA_ERROR(MinorStatus);
dwBufferSize += Sizes.cbMaxSignature; // Token
dwBufferSize += InputMessage->length; // Data
// We only need the padding for the duration of this operation, it should
// not be returned with the rest of the data.
dwBufferSize += Sizes.cbSecurityTrailer; // Padding
MinorStatus = LwAllocateMemory(dwBufferSize, OUT_PPVOID(&pBuffer));
BAIL_ON_LSA_ERROR(MinorStatus);
NtlmBuffer[0].BufferType = SECBUFFER_TOKEN;
NtlmBuffer[0].cbBuffer = Sizes.cbMaxSignature;
NtlmBuffer[0].pvBuffer = pBuffer;
NtlmBuffer[1].BufferType = SECBUFFER_DATA;
NtlmBuffer[1].cbBuffer = InputMessage->length;
NtlmBuffer[1].pvBuffer =
(PBYTE)NtlmBuffer[0].pvBuffer + NtlmBuffer[0].cbBuffer;
memcpy(
NtlmBuffer[1].pvBuffer,
InputMessage->value,
NtlmBuffer[1].cbBuffer);
if (nEncrypt)
{
MinorStatus = NtlmClientEncryptMessage(
&ContextHandle,
TRUE,
&Message,
0);
}
else
{
MinorStatus = NtlmClientMakeSignature(
&ContextHandle,
Qop,
&Message,
0);
}
BAIL_ON_LSA_ERROR(MinorStatus);
// As noted above, we'll trim the size down to exclude the padding
dwBufferSize -= Sizes.cbSecurityTrailer;
if (nEncrypt)
{
nEncrypted = 1;
}
cleanup:
OutputMessage->value = pBuffer;
OutputMessage->length = dwBufferSize;
if (pEncrypted)
{
*pEncrypted = nEncrypted;
}
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
LW_SAFE_FREE_MEMORY(pBuffer);
dwBufferSize = 0;
nEncrypted = 0;
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_wrap_iov(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
INT nEncrypt,
gss_qop_t Qop,
PINT pEncrypted,
gss_iov_buffer_desc* pBuffers,
int cBuffers
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecBufferDesc Message = {0};
SecBuffer NtlmBuffer[2];
SecPkgContext_Sizes Sizes = {0};
INT nEncrypted = 0;
Message.cBuffers = 2;
Message.pBuffers = NtlmBuffer;
memset(NtlmBuffer, 0, sizeof(SecBuffer) * Message.cBuffers);
if (Qop != GSS_C_QOP_DEFAULT)
{
MajorStatus = GSS_S_BAD_QOP;
BAIL_ON_LSA_ERROR(MajorStatus);
}
if (cBuffers != 2)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
// Since every encrypted message gets a signature, we need to get the size
MinorStatus = NtlmClientQueryContextAttributes(
&ContextHandle,
SECPKG_ATTR_SIZES,
&Sizes
);
BAIL_ON_LSA_ERROR(MinorStatus);
if (GSS_IOV_BUFFER_TYPE(pBuffers[0].type) != GSS_IOV_BUFFER_TYPE_HEADER)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (GSS_IOV_BUFFER_FLAGS(pBuffers[0].type) & GSS_IOV_BUFFER_FLAG_ALLOCATE)
{
pBuffers[0].buffer.length = Sizes.cbMaxSignature;
MinorStatus = LwAllocateMemory(
pBuffers[0].buffer.length,
OUT_PPVOID(&pBuffers[0].buffer.value));
BAIL_ON_LSA_ERROR(MinorStatus);
pBuffers[0].type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
}
NtlmBuffer[0].BufferType = SECBUFFER_TOKEN;
NtlmBuffer[0].cbBuffer = pBuffers[0].buffer.length;
NtlmBuffer[0].pvBuffer = pBuffers[0].buffer.value;
if (pBuffers[1].type != GSS_IOV_BUFFER_TYPE_DATA)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
NtlmBuffer[1].BufferType = SECBUFFER_DATA;
NtlmBuffer[1].cbBuffer = pBuffers[1].buffer.length;
NtlmBuffer[1].pvBuffer = pBuffers[1].buffer.value;
MinorStatus = NtlmClientEncryptMessage(
&ContextHandle,
nEncrypt ? TRUE : FALSE,
&Message,
0
);
BAIL_ON_LSA_ERROR(MinorStatus);
if (nEncrypt)
{
nEncrypted = 1;
}
cleanup:
if (pEncrypted)
{
*pEncrypted = nEncrypted;
}
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
nEncrypted = 0;
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_unwrap(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
gss_buffer_t InputMessage,
gss_buffer_t OutputMessage,
PINT pEncrypted,
gss_qop_t* pQop
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecBufferDesc Message;
SecBuffer NtlmBuffer[2];
PVOID pBuffer = NULL;
DWORD dwBufferSize = 0;
BOOLEAN bEncrypted = FALSE;
SecPkgContext_Sizes Sizes = {0};
DWORD dwNtlmFlags = 0;
DWORD dwQop = GSS_C_QOP_DEFAULT;
LW_ASSERT(InputMessage);
Message.cBuffers = 2;
Message.pBuffers = NtlmBuffer;
memset(NtlmBuffer, 0, sizeof(SecBuffer) * Message.cBuffers);
// Since every encrypted message gets a signature, we need to get the size
MinorStatus = NtlmClientQueryContextAttributes(
&ContextHandle,
SECPKG_ATTR_SIZES,
&Sizes
);
BAIL_ON_LSA_ERROR(MinorStatus);
LW_ASSERT(InputMessage->length >= Sizes.cbMaxSignature);
// Check the negotiated flags to find out if the message is expected
// to be encrypted or signed only.
MinorStatus = NtlmClientQueryContextAttributes(
&ContextHandle,
SECPKG_ATTR_FLAGS,
&dwNtlmFlags);
BAIL_ON_LSA_ERROR(MinorStatus);
// Here we are taking out the signature, but adding back in for the
// padding. The padding is only needed for the duration of the operation
// and will be ignored afterwards.
dwBufferSize =
InputMessage->length - Sizes.cbMaxSignature + Sizes.cbSecurityTrailer;
MinorStatus = LwAllocateMemory(
dwBufferSize,
OUT_PPVOID(&pBuffer));
BAIL_ON_LSA_ERROR(MinorStatus);
// Reduce the size to exclude the padding trailer
dwBufferSize -= Sizes.cbSecurityTrailer;
// Copy the input into our buffer... making sure to skip past the signature
memcpy(
pBuffer,
(PBYTE)InputMessage->value + Sizes.cbMaxSignature,
dwBufferSize);
// We should be getting in a blob containing a signature and data... no size
// information. We place these values into a SECBUFFER_TOKEN and a
// SECBUFFER_DATA (see ntlm_gss_wrap for how these get packaged
// together). Then we send them to the decryptor.
NtlmBuffer[0].BufferType = SECBUFFER_TOKEN;
NtlmBuffer[0].cbBuffer = Sizes.cbMaxSignature;
NtlmBuffer[0].pvBuffer = InputMessage->value;
NtlmBuffer[1].BufferType = SECBUFFER_DATA;
NtlmBuffer[1].cbBuffer = dwBufferSize;
NtlmBuffer[1].pvBuffer = pBuffer;
if (dwNtlmFlags & (NTLM_FLAG_SEAL | NTLM_FLAG_SIGN))
{
MinorStatus = NtlmClientDecryptMessage(
&ContextHandle,
&Message,
0,
&bEncrypted
);
}
else if (dwNtlmFlags & NTLM_FLAG_SIGN)
{
MinorStatus = NtlmClientVerifySignature(
&ContextHandle,
&Message,
0,
&dwQop
);
}
else
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
}
BAIL_ON_LSA_ERROR(MinorStatus);
if (pQop)
{
*pQop = (gss_qop_t)dwQop;
}
OutputMessage->value = pBuffer;
OutputMessage->length = dwBufferSize;
cleanup:
if (pEncrypted)
{
*pEncrypted = bEncrypted;
}
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
LW_SAFE_FREE_MEMORY(pBuffer);
OutputMessage->value = NULL;
OutputMessage->length = 0;
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_unwrap_iov(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
PINT pEncrypted,
gss_qop_t* pQop,
gss_iov_buffer_desc* pBuffers,
int cBuffers
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE ContextHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecBufferDesc Message;
SecBuffer NtlmBuffer[2];
BOOLEAN bEncrypted = FALSE;
Message.cBuffers = 2;
Message.pBuffers = NtlmBuffer;
memset(NtlmBuffer, 0, sizeof(SecBuffer) * Message.cBuffers);
if (cBuffers != 2)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (pBuffers[0].type != GSS_IOV_BUFFER_TYPE_HEADER)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
NtlmBuffer[0].BufferType = SECBUFFER_TOKEN;
NtlmBuffer[0].cbBuffer = pBuffers[0].buffer.length;
NtlmBuffer[0].pvBuffer = pBuffers[0].buffer.value;
if (pBuffers[1].type != GSS_IOV_BUFFER_TYPE_DATA)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
NtlmBuffer[1].BufferType = SECBUFFER_DATA;
NtlmBuffer[1].cbBuffer = pBuffers[1].buffer.length;
NtlmBuffer[1].pvBuffer = pBuffers[1].buffer.value;
MinorStatus = NtlmClientDecryptMessage(
&ContextHandle,
&Message,
0,
&bEncrypted
);
BAIL_ON_LSA_ERROR(MinorStatus);
cleanup:
if (pEncrypted)
{
*pEncrypted = bEncrypted;
}
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_display_status(
OM_uint32* pMinorStatus,
OM_uint32 dwConvertStatus,
INT dwStatusType,
gss_OID pMechType,
OM_uint32* pdwContinueNeeded,
gss_buffer_t pMsg
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
PCSTR pszCommonStr = NULL;
if (pdwContinueNeeded)
{
*pdwContinueNeeded = 0;
}
if (pMechType != GSS_C_NULL_OID)
{
BOOLEAN bEqual = FALSE;
MajorStatus = ntlm_gss_compare_oid(
&MinorStatus,
pMechType,
gGssNtlmOid,
&bEqual);
BAIL_ON_LSA_ERROR(MinorStatus);
if (!bEqual)
{
MinorStatus = LW_ERROR_BAD_MECH;
MajorStatus = GSS_S_BAD_MECH;
BAIL_ON_LSA_ERROR(MinorStatus);
}
}
if (dwStatusType != GSS_C_MECH_CODE)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
MajorStatus = GSS_S_BAD_MECH;
BAIL_ON_LSA_ERROR(MinorStatus);
}
pszCommonStr = LwWin32ExtErrorToName(dwConvertStatus);
if (!pszCommonStr)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
MajorStatus = GSS_S_UNAVAILABLE;
}
if (!pMsg)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
MajorStatus = GSS_S_FAILURE;
BAIL_ON_LSA_ERROR(MinorStatus);
}
MinorStatus = LwAllocateString(
pszCommonStr,
(PSTR*)(PSTR)(&pMsg->value));
BAIL_ON_LSA_ERROR(MinorStatus);
pMsg->length = strlen(pszCommonStr);
cleanup:
if (*pMinorStatus)
{
*pMinorStatus = MinorStatus;
}
return MajorStatus;
error:
if (pMsg)
{
LW_SAFE_FREE_STRING(pMsg->value);
pMsg->length = 0;
}
if (!MajorStatus)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_display_name(
OM_uint32* pMinorStatus,
gss_name_t pGssName,
gss_buffer_t pOutputName,
gss_OID* ppNameType
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
PNTLM_GSS_NAME pName = (PNTLM_GSS_NAME)pGssName;
if (!pName)
{
MajorStatus = GSS_S_BAD_NAME;
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (pOutputName)
{
MinorStatus = LwAllocateString(
pName->pszName,
(PSTR*)(PSTR)(&pOutputName->value));
BAIL_ON_LSA_ERROR(MinorStatus);
pOutputName->length = strlen(pOutputName->value);
}
if (ppNameType)
{
// The caller assumes that *ppNameType is static read only memory
*ppNameType = pName->NameType;
}
cleanup:
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
if (pOutputName)
{
LW_SAFE_FREE_STRING(pOutputName->value);
pOutputName->length = 0;
}
if (ppNameType)
{
*ppNameType = NULL;
}
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_compare_oid(
OM_uint32* pMinorStatus,
const gss_OID a,
const gss_OID b,
BOOLEAN *bIsEqual
)
{
*pMinorStatus = 0;
if (a->length != b->length)
{
*bIsEqual = FALSE;
return 0;
}
if (!a->elements)
{
*bIsEqual = !b->elements;
return 0;
}
*bIsEqual = !memcmp(a->elements, b->elements, a->length);
return 0;
}
OM_uint32
ntlm_gss_import_name(
OM_uint32* pMinorStatus,
const gss_buffer_t InputNameBuffer,
const gss_OID InputNameType,
gss_name_t* pOutputName
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
PNTLM_GSS_NAME pResult = NULL;
BOOLEAN bIsUserName = FALSE;
BOOLEAN bIsHostService = FALSE;
BOOLEAN bIsKrbPrinc = FALSE;
MinorStatus = LwAllocateMemory(
sizeof(*pResult),
OUT_PPVOID(&pResult));
BAIL_ON_LSA_ERROR(MinorStatus);
ntlm_gss_compare_oid(
&MinorStatus,
InputNameType,
GSS_C_NT_USER_NAME,
&bIsUserName);
BAIL_ON_LSA_ERROR(MinorStatus);
ntlm_gss_compare_oid(
&MinorStatus,
InputNameType,
GSS_C_NT_HOSTBASED_SERVICE,
&bIsHostService);
BAIL_ON_LSA_ERROR(MinorStatus);
ntlm_gss_compare_oid(
&MinorStatus,
InputNameType,
(gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
&bIsKrbPrinc);
BAIL_ON_LSA_ERROR(MinorStatus);
if (bIsUserName)
{
pResult->NameType = GSS_C_NT_USER_NAME;
}
else if(bIsHostService)
{
pResult->NameType = GSS_C_NT_HOSTBASED_SERVICE;
}
else if(bIsKrbPrinc)
{
pResult->NameType = (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME;
}
else
{
MajorStatus = GSS_S_BAD_NAMETYPE;
MinorStatus = LW_ERROR_BAD_NAMETYPE;
BAIL_ON_LSA_ERROR(MinorStatus);
}
MinorStatus = LwStrndup(
InputNameBuffer->value,
InputNameBuffer->length,
&pResult->pszName);
BAIL_ON_LSA_ERROR(MinorStatus);
*pOutputName = (gss_name_t)pResult;
cleanup:
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
*pOutputName = NULL;
ntlm_gss_release_name(NULL, (gss_name_t *)&pResult);
goto cleanup;
}
OM_uint32
ntlm_gss_release_name(
OM_uint32* pMinorStatus,
gss_name_t* ppName
)
{
PNTLM_GSS_NAME pName = (PNTLM_GSS_NAME)*ppName;
if (pName)
{
LW_SAFE_FREE_STRING(pName->pszName);
LW_SAFE_FREE_MEMORY(pName);
*ppName = NULL;
}
if (pMinorStatus)
{
*pMinorStatus = LW_ERROR_SUCCESS;
}
return GSS_S_COMPLETE;
}
OM_uint32
ntlm_gss_inquire_cred(
OM_uint32* pMinorStatus,
const gss_cred_id_t CredHandle,
gss_name_t* pName,
OM_uint32* pLifeTime,
gss_cred_usage_t* pCredUsage,
gss_OID_set* pMechs
)
{
if (pName)
{
*pName = GSS_C_NO_NAME;
}
if (pLifeTime)
{
*pLifeTime = 0;
}
if (pCredUsage)
{
*pCredUsage = 0;
}
if (pMechs)
{
*pMechs = GSS_C_NO_OID_SET;
}
return GSS_S_COMPLETE;
}
OM_uint32
ntlm_gss_inquire_context(
OM_uint32* pMinorStatus,
gss_ctx_id_t GssCtxtHandle,
gss_name_t* ppSourceName,
gss_name_t* ppTargetName,
OM_uint32* pLifeTime,
gss_OID* pMechType,
OM_uint32* pCtxtFlags,
PINT pLocal,
PINT pOpen
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
NTLM_CONTEXT_HANDLE NtlmCtxtHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
DWORD dwNtlmFlags = 0;
SecPkgContext_Names Names = { 0 };
gss_name_t pSourceName = NULL;
PNTLM_GSS_NAME pUserName = NULL;
if (pLocal || pOpen)
{
MinorStatus = LW_ERROR_NOT_SUPPORTED;
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (pCtxtFlags)
{
MinorStatus = NtlmClientQueryContextAttributes(
&NtlmCtxtHandle,
SECPKG_ATTR_FLAGS,
&dwNtlmFlags);
BAIL_ON_LSA_ERROR(MinorStatus);
if (dwNtlmFlags & NTLM_FLAG_SIGN)
{
*pCtxtFlags |= GSS_C_INTEG_FLAG;
}
if (dwNtlmFlags & NTLM_FLAG_SEAL)
{
*pCtxtFlags |= GSS_C_CONF_FLAG;
}
}
if (ppTargetName)
{
*ppTargetName = GSS_C_NO_NAME;
}
if (ppSourceName)
{
MinorStatus = NtlmClientQueryContextAttributes(
&NtlmCtxtHandle,
SECPKG_ATTR_NAMES,
&Names);
BAIL_ON_LSA_ERROR(MinorStatus);
MinorStatus = LwAllocateMemory(
sizeof(*pUserName),
OUT_PPVOID(&pUserName));
BAIL_ON_LSA_ERROR(MinorStatus);
pUserName->NameType = GSS_C_NT_USER_NAME;
pUserName->hContext = NtlmCtxtHandle;
MinorStatus = LwAllocateString(
Names.pUserName,
(PSTR*)(PSTR)(&pUserName->pszName));
BAIL_ON_LSA_ERROR(MinorStatus);
pSourceName = (gss_name_t)pUserName;
pUserName = NULL;
}
cleanup:
*pMinorStatus = MinorStatus;
if(Names.pUserName)
{
NtlmFreeContextBuffer(Names.pUserName);
}
if (pUserName)
{
ntlm_gss_release_name(NULL, (gss_name_t *)&pUserName);
}
if (ppSourceName)
{
*ppSourceName = pSourceName;
}
if (pLifeTime)
{
*pLifeTime = GSS_C_INDEFINITE;
}
if (pMechType)
{
*pMechType = gGssNtlmOid;
}
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
ntlm_gss_release_name(NULL, &pSourceName);
goto cleanup;
}
OM_uint32
ntlm_gss_inquire_sec_context_by_oid(
OM_uint32* pMinorStatus,
const gss_ctx_id_t GssCtxtHandle,
const gss_OID Attrib,
gss_buffer_set_t* ppBufferSet
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
gss_OID SessionKeyOid = GSS_C_INQ_SSPI_SESSION_KEY;
gss_OID NamesOid = GSS_C_NT_STRING_UID_NAME;
NTLM_CONTEXT_HANDLE NtlmCtxtHandle = (NTLM_CONTEXT_HANDLE)GssCtxtHandle;
SecPkgContext_SessionKey SessionKey = {0};
SecPkgContext_Names Names = {0};
gss_buffer_set_t pBufferSet = NULL;
gss_buffer_t pBuffer = NULL;
MinorStatus = LwAllocateMemory(
sizeof(*pBufferSet),
OUT_PPVOID(&pBufferSet));
BAIL_ON_LSA_ERROR(MinorStatus);
MinorStatus = LwAllocateMemory(
sizeof(*pBuffer),
OUT_PPVOID(&pBuffer));
BAIL_ON_LSA_ERROR(MinorStatus);
if (Attrib->length == SessionKeyOid->length &&
!memcmp(Attrib->elements, SessionKeyOid->elements, Attrib->length))
{
MinorStatus = NtlmClientQueryContextAttributes(
&NtlmCtxtHandle,
SECPKG_ATTR_SESSION_KEY,
&SessionKey);
BAIL_ON_LSA_ERROR(MinorStatus);
pBuffer->value = SessionKey.pSessionKey;
pBuffer->length = SessionKey.SessionKeyLength;
}
else if (Attrib->length == NamesOid->length &&
!memcmp(Attrib->elements, NamesOid->elements, Attrib->length))
{
MinorStatus = NtlmClientQueryContextAttributes(
&NtlmCtxtHandle,
SECPKG_ATTR_NAMES,
&Names);
BAIL_ON_LSA_ERROR(MinorStatus);
pBuffer->value = Names.pUserName;
pBuffer->length = strlen(pBuffer->value);
}
else
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
pBufferSet->count = 1;
pBufferSet->elements = pBuffer;
cleanup:
*pMinorStatus = MinorStatus;
*ppBufferSet = pBufferSet;
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
LW_SAFE_FREE_MEMORY(pBuffer);
LW_SAFE_FREE_MEMORY(pBufferSet);
goto cleanup;
}
OM_uint32
ntlm_gss_get_name_attribute(
OM_uint32* pMinorStatus,
gss_name_t pName,
gss_buffer_t pAttr,
int* pAuthenticate,
int* pComplete,
gss_buffer_t pValue,
gss_buffer_t pDisplayValue,
int* pMore
)
{
OM_uint32 MajorStatus = GSS_S_COMPLETE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
SecPkgContext_PacLogonInfo LogonInfo = {0};
PNTLM_GSS_NAME pUserName = (PNTLM_GSS_NAME) pName;
if (pMore && *pMore != -1)
{
MinorStatus = ERROR_NO_MORE_ITEMS;
BAIL_ON_LSA_ERROR(MinorStatus);
}
if (!strncmp("urn:mspac:logon-info", (char*) pAttr->value, pAttr->length))
{
if (pValue)
{
MinorStatus = NtlmClientQueryContextAttributes(
&pUserName->hContext,
SECPKG_ATTR_PAC_LOGON_INFO,
&LogonInfo);
BAIL_ON_LSA_ERROR(MinorStatus);
pValue->value = LogonInfo.pLogonInfo;
pValue->length = LogonInfo.LogonInfoLength;
}
if (pAuthenticate)
{
*pAuthenticate = 1;
}
if (pComplete)
{
*pComplete = 1;
}
if (pMore)
{
*pMore = 0;
}
}
else
{
MinorStatus = LW_ERROR_NO_SUCH_ATTRIBUTE;
BAIL_ON_LSA_ERROR(MinorStatus);
}
cleanup:
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
PGSS_MECH_CONFIG
gss_mech_initialize(void)
{
return &gNtlmMech;
}
OM_uint32
ntlm_gssspi_set_cred_option(
OM_uint32* pMinorStatus,
gss_cred_id_t GssCredHandle,
const gss_OID OptionOid,
const gss_buffer_t Buffer
)
{
OM_uint32 MajorStatus = GSS_S_UNAVAILABLE;
OM_uint32 MinorStatus = LW_ERROR_SUCCESS;
PNTLM_GSS_CREDS pCreds = (PNTLM_GSS_CREDS)GssCredHandle;
PSEC_WINNT_AUTH_IDENTITY pAuthData = NULL;
if (OptionOid->length == gGssCredOptionPasswordOid->length &&
!memcmp(
OptionOid->elements,
gGssCredOptionPasswordOid->elements,
OptionOid->length))
{
MajorStatus = GSS_S_COMPLETE;
if (!Buffer || Buffer->length != sizeof(SEC_WINNT_AUTH_IDENTITY) ||
!Buffer->value)
{
MinorStatus = LW_ERROR_INVALID_PARAMETER;
BAIL_ON_LSA_ERROR(MinorStatus);
}
pAuthData = (PSEC_WINNT_AUTH_IDENTITY)Buffer->value;
if (pCreds->CredHandle)
{
MinorStatus = NtlmClientFreeCredentialsHandle(
&pCreds->CredHandle
);
BAIL_ON_LSA_ERROR(MinorStatus);
}
MinorStatus = NtlmClientAcquireCredentialsHandle(
pCreds->pszUserName,
"NTLM",
pCreds->fCredentialUse,
NULL,
pAuthData,
&pCreds->CredHandle,
&pCreds->tsExpiry
);
BAIL_ON_LSA_ERROR(MinorStatus);
}
cleanup:
*pMinorStatus = MinorStatus;
return MajorStatus;
error:
if (MajorStatus == GSS_S_COMPLETE)
{
MajorStatus = GSS_S_FAILURE;
}
goto cleanup;
}
OM_uint32
ntlm_gss_release_oid(
OM_uint32* MinorStatus,
gss_OID *pOid
)
{
/* Don't free the global static OID */
if ((pOid &&
((*pOid == gGssNtlmOid) || (*pOid == GSS_C_NO_OID))))
{
*MinorStatus = 0;
return GSS_S_COMPLETE;
}
return GSS_S_FAILURE;
}
/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/