|
|
/* ----------------------------------------------------------------------
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 ----------- */
|