Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

447 lines
8.6 KiB

/* ----------------------------------------------------------------------
Module: ULS.DLL (Service Provider)
File: spconn.cpp
Content: This file contains the ldap connection object.
History:
10/15/96 Chu, Lon-Chan [lonchanc]
Created.
Copyright (c) Microsoft Corporation 1996-1997
---------------------------------------------------------------------- */
#include "ulsp.h"
#include "spinc.h"
#include "rpcdce.h"
const TCHAR c_szRTPerson[] = TEXT ("RTPerson");
const TCHAR c_szRTConf[] = TEXT ("Conference");
const TCHAR c_szDefClientBaseDN[] = TEXT ("objectClass=RTPerson");
const TCHAR c_szDefMtgBaseDN[] = TEXT ("objectClass=Conference");
const TCHAR c_szDefO[] = TEXT ("Microsoft");
const TCHAR c_szEmptyString[] = TEXT ("");
SP_CSessionContainer *g_pSessionContainer = NULL;
/* ---------- public methods ----------- */
SP_CSession::
SP_CSession ( VOID ) :
m_cRefs (0),
m_dwSignature (0),
m_ld (NULL),
m_fUsed (FALSE)
{
::ZeroMemory (&m_ServerInfo, sizeof (m_ServerInfo));
}
SP_CSession::
~SP_CSession ( VOID )
{
InternalCleanup ();
}
/* ---------- public methods ----------- */
HRESULT SP_CSession::
Disconnect ( VOID )
{
// if a connection is available, then simply the existing one
if (m_dwSignature != LDAP_CONN_SIGNATURE)
{
return ILS_E_HANDLE;
}
MyAssert (m_cRefs > 0);
HRESULT hr = S_OK;
if (::InterlockedDecrement (&m_cRefs) == 0)
{
// m_cRefs == 0 now
MyAssert (m_ld != NULL);
InternalCleanup ();
hr = S_OK;
}
return hr;
}
/* ---------- protected methods ----------- */
VOID SP_CSession::
FillAuthIdentity ( SEC_WINNT_AUTH_IDENTITY *pai )
{
// Clean it up
//
::ZeroMemory (pai, sizeof (*pai));
// Fill in NT auth identity
//
if ((pai->User = (BYTE *) m_ServerInfo.pszLogonName) != NULL)
pai->UserLength = lstrlen (m_ServerInfo.pszLogonName);
if ((pai->Domain = (BYTE *) m_ServerInfo.pszDomain) != NULL)
pai->DomainLength = lstrlen (m_ServerInfo.pszDomain);
if ((pai->Password = (BYTE *) m_ServerInfo.pszLogonPassword) != NULL)
pai->PasswordLength = lstrlen (m_ServerInfo.pszLogonPassword);
#ifdef _UNICODE
pai->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
pai->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif
}
HRESULT SP_CSession::
Bind ( BOOL fAbortable )
{
ULONG uLdapAuthMethod = LDAP_AUTH_SIMPLE;
TCHAR *pszLogonName = m_ServerInfo.pszLogonName;
TCHAR *pszLogonPassword = m_ServerInfo.pszLogonPassword;
SEC_WINNT_AUTH_IDENTITY ai;
BOOL fSyncBind = TRUE;
HRESULT hr = S_OK;
switch (m_ServerInfo.AuthMethod)
{
default:
MyAssert (FALSE);
// Fall through...
case ILS_AUTH_ANONYMOUS:
fSyncBind = FALSE;
uLdapAuthMethod = LDAP_AUTH_SIMPLE;
pszLogonName = STR_EMPTY;
pszLogonPassword = STR_EMPTY;
break;
case ILS_AUTH_CLEAR_TEXT:
fSyncBind = FALSE;
uLdapAuthMethod = LDAP_AUTH_SIMPLE;
break;
case ILS_AUTH_NTLM:
uLdapAuthMethod = LDAP_AUTH_NTLM;
FillAuthIdentity (&ai);
pszLogonName = NULL;
pszLogonPassword = (TCHAR *) &ai;
break;
case ILS_AUTH_DPA:
uLdapAuthMethod = LDAP_AUTH_DPA;
break;
case ILS_AUTH_MSN:
uLdapAuthMethod = LDAP_AUTH_MSN;
break;
case ILS_AUTH_SICILY:
uLdapAuthMethod = LDAP_AUTH_SICILY;
break;
case ILS_AUTH_SSPI:
uLdapAuthMethod = LDAP_AUTH_SSPI;
break;
}
if (fSyncBind)
{
INT nRetCode = ::ldap_bind_s (m_ld, pszLogonName,
pszLogonPassword,
uLdapAuthMethod);
hr = (nRetCode == LDAP_SUCCESS) ? S_OK : ILS_E_BIND;
}
else
{
INT uMsgID = ::ldap_bind (m_ld, pszLogonName,
pszLogonPassword,
uLdapAuthMethod);
INT ResultType;
LDAP_TIMEVAL TimeVal;
LDAPMessage *pMsg;
LONG i, nTimeoutInSecond;
nTimeoutInSecond = GetServerTimeoutInSecond ();
for (i = 0; i < nTimeoutInSecond; i++)
{
TimeVal.tv_usec = 0;
TimeVal.tv_sec = 1;
pMsg = NULL;
ResultType = ::ldap_result (m_ld, uMsgID, LDAP_MSG_ALL, &TimeVal, &pMsg);
if (ResultType == LDAP_RES_BIND)
{
break;
}
else
{
// deal with timeout or error
if (ResultType == 0)
{
MyAssert (g_pReqQueue != NULL);
if (fAbortable && g_pReqQueue != NULL &&
g_pReqQueue->IsCurrentRequestCancelled ())
{
hr = ILS_E_ABORT;
}
else
{
continue;
}
}
else
if (ResultType == -1)
{
hr = ILS_E_BIND;
}
else
{
// lonchanc: AndyHe said the return value
// can be anything. Thus, removed the assertion.
hr = ILS_E_FAIL;
}
::ldap_abandon (m_ld, uMsgID);
::ldap_unbind (m_ld);
m_ld = NULL;
return hr;
}
}
// Check if it times out
//
if (i >= nTimeoutInSecond)
{
hr = ILS_E_TIMEOUT;
::ldap_abandon (m_ld, uMsgID);
::ldap_unbind (m_ld);
m_ld = NULL;
return hr;
}
MyAssert (pMsg != NULL);
::ldap_msgfree (pMsg);
hr = S_OK;
}
return hr;
}
HRESULT SP_CSession::
Connect (
SERVER_INFO *pInfo,
ULONG cConns,
BOOL fAbortable )
{
// If a connection is available,
// then simply the existing one
//
if (m_dwSignature == LDAP_CONN_SIGNATURE)
{
m_cRefs += cConns;
return S_OK;
}
// We need to create a new connection
// let's cache the server info
//
HRESULT hr = ::IlsCopyServerInfo (&m_ServerInfo, pInfo);
if (hr != S_OK)
return hr;
// Connect to ldap server
//
ULONG ulPort = LDAP_PORT;
LPTSTR pszServerName = My_strdup(m_ServerInfo.pszServerName);
if (NULL == pszServerName)
{
return E_OUTOFMEMORY;
}
LPTSTR pszSeparator = My_strchr(pszServerName, _T(':'));
if (NULL != pszSeparator)
{
*pszSeparator = _T('\0');
ulPort = GetStringLong(pszSeparator + 1);
}
m_ld = ::ldap_open (pszServerName, ulPort);
MemFree(pszServerName);
if (m_ld == NULL)
{
// We need to know why ldap_open() failed.
// Is it because server name is not valid?
// Or is it because server does not support LDAP?
//
// hr = (gethostbyname (m_ServerInfo.pszServerName) != NULL) ?
// Winsock will set ERROR_OPEN_FAILED, but wldap32.dll sets ERROR_HOST_UNREACHABLE
// The down side is that when the server was down, the client will try ULP.
//
DWORD dwErr = ::GetLastError ();
MyDebugMsg ((ZONE_REQ, "ULS: ldap_open failed, err=%lu)\r\n", dwErr));
hr = (dwErr == ERROR_OPEN_FAILED || dwErr == ERROR_HOST_UNREACHABLE) ?
ILS_E_SERVER_SERVICE : ILS_E_SERVER_NAME;
goto MyExit;
}
// Do the bind
//
hr = Bind (fAbortable);
if (hr == S_OK)
{
// remember the handle and increment the reference count
m_cRefs = cConns;
m_dwSignature = LDAP_CONN_SIGNATURE;
}
MyExit:
MyDebugMsg ((ZONE_CONN, "ILS: Connect: hr=0x%p, m_ld=0x%p, server=%s\r\n", (DWORD) hr, m_ld, m_ServerInfo.pszServerName));
if (hr != S_OK)
{
InternalCleanup ();
}
return hr;
}
/* ---------- private methods ----------- */
VOID SP_CSession::
InternalCleanup ( VOID )
{
if (IsUsed ())
{
MyDebugMsg ((ZONE_CONN, "ILS: InternalCleanup: m_ld=0x%p, server=%s\r\n", m_ld, m_ServerInfo.pszServerName));
// Clean up these two ASAP because ldap_unbind may delay
//
m_dwSignature = 0;
::IlsFreeServerInfo (&m_ServerInfo);
// Free the ldap infor
//
if (m_ld != NULL)
{
ldap_unbind (m_ld);
m_ld = NULL;
}
// Clear it out
//
ClearUsed ();
}
}
/* ==================== container ========================= */
/* ---------- public methods ----------- */
SP_CSessionContainer::
SP_CSessionContainer ( VOID ) :
m_cEntries (0),
m_aConns (NULL)
{
::MyInitializeCriticalSection (&m_csSessContainer);
}
SP_CSessionContainer::
~SP_CSessionContainer ( VOID )
{
::MyDeleteCriticalSection (&m_csSessContainer);
m_cEntries = 0;
delete [] m_aConns;
}
HRESULT SP_CSessionContainer::
Initialize (
ULONG cEntries,
SP_CSession *ConnArr )
{
m_cEntries = cEntries;
m_aConns = new SP_CSession[cEntries];
return ((m_aConns != NULL) ? S_OK : ILS_E_MEMORY);
}
HRESULT SP_CSessionContainer::
GetSession (
SP_CSession **ppConn,
SERVER_INFO *pInfo,
ULONG cConns,
BOOL fAbortable )
{
MyAssert (ppConn != NULL);
MyAssert (pInfo != NULL);
*ppConn = NULL;
HRESULT hr;
WriteLock ();
// The first pass is to see any existing connection
//
for (ULONG i = 0; i < m_cEntries; i++)
{
if (m_aConns[i].IsUsed ())
{
if (m_aConns[i].SameServerInfo (pInfo))
{
*ppConn = &m_aConns[i];
hr = m_aConns[i].Connect (pInfo, cConns, fAbortable);
goto MyExit;
}
}
}
// The second pass is to see any empty slot
//
for (i = 0; i < m_cEntries; i++)
{
if (! m_aConns[i].IsUsed ())
{
m_aConns[i].SetUsed ();
*ppConn = &m_aConns[i];
hr = m_aConns[i].Connect (pInfo, cConns, fAbortable);
goto MyExit;
}
}
hr = ILS_E_MEMORY;
MyExit:
WriteUnlock ();
return hr;
}
/* ---------- protected methods ----------- */
/* ---------- private methods ----------- */