Leaked source code of windows server 2003
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

//--------------------------------------------------------------------------------------------
//
// 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);
}