You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
356 lines
7.9 KiB
356 lines
7.9 KiB
//--------------------------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) Microsoft Corporation, 1996
|
|
//
|
|
// Description:
|
|
//
|
|
// Microsoft LDAP SSPI Support
|
|
//
|
|
// Authors:
|
|
//
|
|
// davidsan 05/08/96 hacked to pieces and started over
|
|
//
|
|
//--------------------------------------------------------------------------------------------
|
|
|
|
#include "ldappch.h"
|
|
#include "ldapsspi.h"
|
|
#include "lclilist.h"
|
|
#include "lclixd.h"
|
|
|
|
HRESULT g_hrInitSSPI;
|
|
HINSTANCE g_hinstSecDll = NULL;
|
|
PSecurityFunctionTable g_ptblpfnSec;
|
|
|
|
//$ TODO: Possibly return more descriptive errors so clients know why SSPI
|
|
//$ isn't working
|
|
HRESULT
|
|
HrInitializeSSPI()
|
|
{
|
|
char *szDll;
|
|
OSVERSIONINFO ovi;
|
|
INIT_SECURITY_INTERFACE pfnISI = NULL;
|
|
|
|
if (g_ptblpfnSec)
|
|
return NOERROR;
|
|
|
|
Assert(!g_hinstSecDll);
|
|
|
|
ovi.dwOSVersionInfoSize = sizeof(ovi);
|
|
if (!GetVersionEx(&ovi))
|
|
return E_FAIL;
|
|
|
|
if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
szDll = "security.dll";
|
|
else if (ovi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
szDll = "secur32.dll";
|
|
else
|
|
return E_FAIL;
|
|
|
|
g_hinstSecDll = LoadLibrary(szDll);
|
|
|
|
pfnISI = (INIT_SECURITY_INTERFACE)GetProcAddress(g_hinstSecDll, SECURITY_ENTRYPOINT);
|
|
if (!pfnISI)
|
|
{
|
|
LBail:
|
|
FreeLibrary(g_hinstSecDll);
|
|
g_hinstSecDll = NULL;
|
|
return LDAP_E_AUTHNOTAVAIL;
|
|
}
|
|
g_ptblpfnSec = (*pfnISI)();
|
|
if (!g_ptblpfnSec)
|
|
goto LBail;
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT
|
|
HrTerminateSSPI()
|
|
{
|
|
g_ptblpfnSec = NULL;
|
|
if (g_hinstSecDll)
|
|
FreeLibrary(g_hinstSecDll);
|
|
g_hinstSecDll = NULL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT
|
|
CLdapClient::HrGetCredentials(char *szUser, char *szPass)
|
|
{
|
|
HRESULT hr;
|
|
SECURITY_STATUS stat;
|
|
TimeStamp tsLifetime;
|
|
SEC_WINNT_AUTH_IDENTITY authdata;
|
|
|
|
if (FAILED(g_hrInitSSPI))
|
|
return g_hrInitSSPI;
|
|
|
|
Assert(g_ptblpfnSec);
|
|
if (!g_ptblpfnSec)
|
|
return LDAP_E_AUTHNOTAVAIL;
|
|
|
|
::EnterCriticalSection(&m_cs);
|
|
if (m_fHasCred)
|
|
{
|
|
::LeaveCriticalSection(&m_cs);
|
|
return NOERROR;
|
|
}
|
|
|
|
if (szUser && szPass)
|
|
{
|
|
authdata.User = (BYTE *)szUser;
|
|
authdata.UserLength = lstrlen(szUser);
|
|
authdata.Password = (BYTE *)szPass;
|
|
authdata.PasswordLength = lstrlen(szPass);
|
|
authdata.Domain = (BYTE *)"";
|
|
authdata.DomainLength = 0;
|
|
authdata.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
|
|
}
|
|
|
|
stat =
|
|
(*g_ptblpfnSec->AcquireCredentialsHandle)
|
|
(NULL,
|
|
"MSN", //$ does this ever change?
|
|
SECPKG_CRED_OUTBOUND,
|
|
NULL,
|
|
((szUser && szPass) ? &authdata : NULL),
|
|
NULL,
|
|
NULL,
|
|
&m_hCred,
|
|
&tsLifetime);
|
|
if (stat == SEC_E_OK)
|
|
{
|
|
m_fHasCred = TRUE;
|
|
hr = NOERROR;
|
|
}
|
|
else
|
|
hr = LDAP_E_AUTHNOTAVAIL;
|
|
|
|
::LeaveCriticalSection(&m_cs);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CLdapClient::HrSendSSPINegotiate(char *szDN, char *szUser, char *szPass, BOOL fPrompt, PXID pxid)
|
|
{
|
|
HRESULT hr;
|
|
SECURITY_STATUS stat;
|
|
DWORD fContextAttrib;
|
|
TimeStamp tsExpireTime;
|
|
SecBufferDesc outSecDesc;
|
|
SecBuffer outSecBuffer;
|
|
DWORD grfReq = ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
|
|
PXD pxd;
|
|
BYTE rgb[512];
|
|
|
|
pxd = g_xl.PxdNewXaction(xtypeBindSSPINegotiate);
|
|
if (!pxd)
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (FAILED(hr = this->HrGetCredentials(szUser, szPass)))
|
|
return hr;
|
|
|
|
outSecDesc.ulVersion = 0;
|
|
outSecDesc.cBuffers = 1;
|
|
outSecDesc.pBuffers = &outSecBuffer;
|
|
outSecBuffer.cbBuffer = sizeof(rgb);
|
|
outSecBuffer.BufferType = SECBUFFER_TOKEN;
|
|
outSecBuffer.pvBuffer = rgb;
|
|
|
|
if (szUser && szPass)
|
|
grfReq |= ISC_REQ_USE_SUPPLIED_CREDS;
|
|
else
|
|
grfReq |= ISC_REQ_PROMPT_FOR_CREDS;
|
|
|
|
stat =
|
|
(*g_ptblpfnSec->InitializeSecurityContext)
|
|
(&m_hCred,
|
|
NULL, // phCurrContext
|
|
NULL, // pszTargetName
|
|
grfReq,
|
|
0L,
|
|
SECURITY_NATIVE_DREP,
|
|
NULL,
|
|
0L,
|
|
&m_hCtxt,
|
|
&outSecDesc,
|
|
&fContextAttrib,
|
|
&tsExpireTime);
|
|
|
|
if (FAILED(stat))
|
|
{
|
|
//$ TODO: determine what errors InitializeSecurityContext can return and
|
|
//$ return appropriate errors to client
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_fHasCtxt = TRUE;
|
|
hr = HrSendBindMsg(
|
|
pxd->Xid(),
|
|
szDN,
|
|
BIND_SSPI_NEGOTIATE,
|
|
outSecBuffer.pvBuffer,
|
|
outSecBuffer.cbBuffer
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
*pxid = pxd->Xid();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CLdapClient::HrGetSSPIChallenge(XID xid, BYTE *pbBuf, int cbBuf, int *pcbChallenge, DWORD timeout)
|
|
{
|
|
PXD pxd;
|
|
BOOL fDel;
|
|
HRESULT hr = NOERROR;
|
|
BYTE *pbData;
|
|
int cbData;
|
|
LBER lber;
|
|
ULONG ulTag;
|
|
LONG lResult;
|
|
|
|
pxd = g_xl.PxdForXid(xid);
|
|
if (!pxd)
|
|
return LDAP_E_INVALIDXID;
|
|
if (pxd->Xtype() != xtypeBindSSPINegotiate)
|
|
return LDAP_E_INVALIDXTYPE;
|
|
if (pxd->FCancelled())
|
|
return LDAP_E_CANCELLED;
|
|
if (pxd->FOOM())
|
|
return E_OUTOFMEMORY;
|
|
|
|
if (pxd->FHasData())
|
|
fDel = TRUE;
|
|
else
|
|
{
|
|
if (FAILED(hr = this->HrWaitForPxd(pxd, timeout, &fDel)))
|
|
goto LBail;
|
|
}
|
|
if (!pxd->FGetBuffer(&pbData, &cbData))
|
|
{
|
|
//$ what's the right error here?
|
|
hr = LDAP_E_UNEXPECTEDDATA;
|
|
goto LBail;
|
|
}
|
|
VERIFY(lber.HrLoadBer(pbData, cbData));
|
|
|
|
VERIFY(lber.HrStartReadSequence(LDAP_BIND_RES | BER_FORM_CONSTRUCTED | BER_CLASS_APPLICATION));
|
|
VERIFY(lber.HrPeekTag(&ulTag));
|
|
if (ulTag == BER_SEQUENCE)
|
|
{
|
|
Assert(FALSE); // i want to see if any server returns explicit sequences
|
|
VERIFY(lber.HrStartReadSequence());
|
|
}
|
|
VERIFY(lber.HrGetEnumValue(&lResult));
|
|
if (!lResult)
|
|
{
|
|
// we have 0 for success--the matchedDN field is the server's challenge.
|
|
VERIFY(lber.HrGetStringLength(pcbChallenge));
|
|
if (*pcbChallenge > cbBuf)
|
|
{
|
|
hr = LDAP_E_BUFFERTOOSMALL;
|
|
goto LBail;
|
|
}
|
|
VERIFY(lber.HrGetBinaryValue(pbBuf, cbBuf));
|
|
}
|
|
if (ulTag == BER_SEQUENCE)
|
|
{
|
|
VERIFY(lber.HrEndReadSequence());
|
|
}
|
|
VERIFY(lber.HrEndReadSequence());
|
|
|
|
hr = this->HrFromLdapResult(lResult);
|
|
|
|
LBail:
|
|
if (fDel)
|
|
g_xl.RemovePxd(pxd);
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CLdapClient::HrSendSSPIResponse(BYTE *pbChallenge, int cbChallenge, PXID pxid)
|
|
{
|
|
HRESULT hr;
|
|
SECURITY_STATUS stat;
|
|
DWORD fContextAttrib;
|
|
TimeStamp tsExpireTime;
|
|
SecBufferDesc inSecDesc, outSecDesc;
|
|
SecBuffer inSecBuffer, outSecBuffer;
|
|
DWORD grfReq = ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY;
|
|
PXD pxd;
|
|
BYTE rgb[512];
|
|
|
|
if (!m_fHasCtxt || !m_fHasCred)
|
|
return LDAP_E_OUTOFSEQUENCE;
|
|
|
|
pxd = g_xl.PxdNewXaction(xtypeBind);
|
|
if (!pxd)
|
|
return E_OUTOFMEMORY;
|
|
|
|
inSecDesc.ulVersion = 0;
|
|
inSecDesc.cBuffers = 1;
|
|
inSecDesc.pBuffers = &inSecBuffer;
|
|
|
|
inSecBuffer.cbBuffer = cbChallenge;
|
|
inSecBuffer.BufferType = SECBUFFER_TOKEN;
|
|
inSecBuffer.pvBuffer = (PVOID)pbChallenge;
|
|
|
|
outSecDesc.ulVersion = 0;
|
|
outSecDesc.cBuffers = 1;
|
|
outSecDesc.pBuffers = &outSecBuffer;
|
|
outSecBuffer.cbBuffer = sizeof(rgb);
|
|
outSecBuffer.BufferType = SECBUFFER_TOKEN;
|
|
outSecBuffer.pvBuffer = rgb;
|
|
|
|
stat =
|
|
(*g_ptblpfnSec->InitializeSecurityContext)
|
|
(&m_hCred,
|
|
&m_hCtxt,
|
|
NULL, // pszTargetName
|
|
ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY,
|
|
0L,
|
|
SECURITY_NATIVE_DREP,
|
|
&inSecDesc,
|
|
0L,
|
|
&m_hCtxt,
|
|
&outSecDesc,
|
|
&fContextAttrib,
|
|
&tsExpireTime);
|
|
|
|
if (FAILED(stat))
|
|
{
|
|
//$ TODO: determine what errors InitializeSecurityContext can return and
|
|
//$ return appropriate errors to client
|
|
return E_FAIL;
|
|
}
|
|
|
|
m_fHasCtxt = TRUE;
|
|
hr = HrSendBindMsg(
|
|
pxd->Xid(),
|
|
"",
|
|
BIND_SSPI_RESPONSE,
|
|
outSecBuffer.pvBuffer,
|
|
outSecBuffer.cbBuffer
|
|
);
|
|
if (SUCCEEDED(hr))
|
|
*pxid = pxd->Xid();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CLdapClient::HrBindSSPI(char *szDN, char *szUser, char *szPass, BOOL fPrompt, DWORD timeout)
|
|
{
|
|
XID xid;
|
|
HRESULT hr;
|
|
BYTE rgb[512];
|
|
int cbChallenge;
|
|
|
|
if (FAILED(hr = this->HrSendSSPINegotiate(szDN, szUser, szPass, fPrompt, &xid)))
|
|
return hr;
|
|
if (FAILED(hr = this->HrGetSSPIChallenge(xid, rgb, sizeof(rgb), &cbChallenge, timeout)))
|
|
return hr;
|
|
if (FAILED(hr = this->HrSendSSPIResponse(rgb, cbChallenge, &xid)))
|
|
return hr;
|
|
|
|
return this->HrGetBindResponse(xid, timeout);
|
|
}
|