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.

446 lines
8.6 KiB

  1. /* ----------------------------------------------------------------------
  2. Module: ULS.DLL (Service Provider)
  3. File: spconn.cpp
  4. Content: This file contains the ldap connection object.
  5. History:
  6. 10/15/96 Chu, Lon-Chan [lonchanc]
  7. Created.
  8. Copyright (c) Microsoft Corporation 1996-1997
  9. ---------------------------------------------------------------------- */
  10. #include "ulsp.h"
  11. #include "spinc.h"
  12. #include "rpcdce.h"
  13. const TCHAR c_szRTPerson[] = TEXT ("RTPerson");
  14. const TCHAR c_szRTConf[] = TEXT ("Conference");
  15. const TCHAR c_szDefClientBaseDN[] = TEXT ("objectClass=RTPerson");
  16. const TCHAR c_szDefMtgBaseDN[] = TEXT ("objectClass=Conference");
  17. const TCHAR c_szDefO[] = TEXT ("Microsoft");
  18. const TCHAR c_szEmptyString[] = TEXT ("");
  19. SP_CSessionContainer *g_pSessionContainer = NULL;
  20. /* ---------- public methods ----------- */
  21. SP_CSession::
  22. SP_CSession ( VOID ) :
  23. m_cRefs (0),
  24. m_dwSignature (0),
  25. m_ld (NULL),
  26. m_fUsed (FALSE)
  27. {
  28. ::ZeroMemory (&m_ServerInfo, sizeof (m_ServerInfo));
  29. }
  30. SP_CSession::
  31. ~SP_CSession ( VOID )
  32. {
  33. InternalCleanup ();
  34. }
  35. /* ---------- public methods ----------- */
  36. HRESULT SP_CSession::
  37. Disconnect ( VOID )
  38. {
  39. // if a connection is available, then simply the existing one
  40. if (m_dwSignature != LDAP_CONN_SIGNATURE)
  41. {
  42. return ILS_E_HANDLE;
  43. }
  44. MyAssert (m_cRefs > 0);
  45. HRESULT hr = S_OK;
  46. if (::InterlockedDecrement (&m_cRefs) == 0)
  47. {
  48. // m_cRefs == 0 now
  49. MyAssert (m_ld != NULL);
  50. InternalCleanup ();
  51. hr = S_OK;
  52. }
  53. return hr;
  54. }
  55. /* ---------- protected methods ----------- */
  56. VOID SP_CSession::
  57. FillAuthIdentity ( SEC_WINNT_AUTH_IDENTITY *pai )
  58. {
  59. // Clean it up
  60. //
  61. ::ZeroMemory (pai, sizeof (*pai));
  62. // Fill in NT auth identity
  63. //
  64. if ((pai->User = (BYTE *) m_ServerInfo.pszLogonName) != NULL)
  65. pai->UserLength = lstrlen (m_ServerInfo.pszLogonName);
  66. if ((pai->Domain = (BYTE *) m_ServerInfo.pszDomain) != NULL)
  67. pai->DomainLength = lstrlen (m_ServerInfo.pszDomain);
  68. if ((pai->Password = (BYTE *) m_ServerInfo.pszLogonPassword) != NULL)
  69. pai->PasswordLength = lstrlen (m_ServerInfo.pszLogonPassword);
  70. #ifdef _UNICODE
  71. pai->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  72. #else
  73. pai->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  74. #endif
  75. }
  76. HRESULT SP_CSession::
  77. Bind ( BOOL fAbortable )
  78. {
  79. ULONG uLdapAuthMethod = LDAP_AUTH_SIMPLE;
  80. TCHAR *pszLogonName = m_ServerInfo.pszLogonName;
  81. TCHAR *pszLogonPassword = m_ServerInfo.pszLogonPassword;
  82. SEC_WINNT_AUTH_IDENTITY ai;
  83. BOOL fSyncBind = TRUE;
  84. HRESULT hr = S_OK;
  85. switch (m_ServerInfo.AuthMethod)
  86. {
  87. default:
  88. MyAssert (FALSE);
  89. // Fall through...
  90. case ILS_AUTH_ANONYMOUS:
  91. fSyncBind = FALSE;
  92. uLdapAuthMethod = LDAP_AUTH_SIMPLE;
  93. pszLogonName = STR_EMPTY;
  94. pszLogonPassword = STR_EMPTY;
  95. break;
  96. case ILS_AUTH_CLEAR_TEXT:
  97. fSyncBind = FALSE;
  98. uLdapAuthMethod = LDAP_AUTH_SIMPLE;
  99. break;
  100. case ILS_AUTH_NTLM:
  101. uLdapAuthMethod = LDAP_AUTH_NTLM;
  102. FillAuthIdentity (&ai);
  103. pszLogonName = NULL;
  104. pszLogonPassword = (TCHAR *) &ai;
  105. break;
  106. case ILS_AUTH_DPA:
  107. uLdapAuthMethod = LDAP_AUTH_DPA;
  108. break;
  109. case ILS_AUTH_MSN:
  110. uLdapAuthMethod = LDAP_AUTH_MSN;
  111. break;
  112. case ILS_AUTH_SICILY:
  113. uLdapAuthMethod = LDAP_AUTH_SICILY;
  114. break;
  115. case ILS_AUTH_SSPI:
  116. uLdapAuthMethod = LDAP_AUTH_SSPI;
  117. break;
  118. }
  119. if (fSyncBind)
  120. {
  121. INT nRetCode = ::ldap_bind_s (m_ld, pszLogonName,
  122. pszLogonPassword,
  123. uLdapAuthMethod);
  124. hr = (nRetCode == LDAP_SUCCESS) ? S_OK : ILS_E_BIND;
  125. }
  126. else
  127. {
  128. INT uMsgID = ::ldap_bind (m_ld, pszLogonName,
  129. pszLogonPassword,
  130. uLdapAuthMethod);
  131. INT ResultType;
  132. LDAP_TIMEVAL TimeVal;
  133. LDAPMessage *pMsg;
  134. LONG i, nTimeoutInSecond;
  135. nTimeoutInSecond = GetServerTimeoutInSecond ();
  136. for (i = 0; i < nTimeoutInSecond; i++)
  137. {
  138. TimeVal.tv_usec = 0;
  139. TimeVal.tv_sec = 1;
  140. pMsg = NULL;
  141. ResultType = ::ldap_result (m_ld, uMsgID, LDAP_MSG_ALL, &TimeVal, &pMsg);
  142. if (ResultType == LDAP_RES_BIND)
  143. {
  144. break;
  145. }
  146. else
  147. {
  148. // deal with timeout or error
  149. if (ResultType == 0)
  150. {
  151. MyAssert (g_pReqQueue != NULL);
  152. if (fAbortable && g_pReqQueue != NULL &&
  153. g_pReqQueue->IsCurrentRequestCancelled ())
  154. {
  155. hr = ILS_E_ABORT;
  156. }
  157. else
  158. {
  159. continue;
  160. }
  161. }
  162. else
  163. if (ResultType == -1)
  164. {
  165. hr = ILS_E_BIND;
  166. }
  167. else
  168. {
  169. // lonchanc: AndyHe said the return value
  170. // can be anything. Thus, removed the assertion.
  171. hr = ILS_E_FAIL;
  172. }
  173. ::ldap_abandon (m_ld, uMsgID);
  174. ::ldap_unbind (m_ld);
  175. m_ld = NULL;
  176. return hr;
  177. }
  178. }
  179. // Check if it times out
  180. //
  181. if (i >= nTimeoutInSecond)
  182. {
  183. hr = ILS_E_TIMEOUT;
  184. ::ldap_abandon (m_ld, uMsgID);
  185. ::ldap_unbind (m_ld);
  186. m_ld = NULL;
  187. return hr;
  188. }
  189. MyAssert (pMsg != NULL);
  190. ::ldap_msgfree (pMsg);
  191. hr = S_OK;
  192. }
  193. return hr;
  194. }
  195. HRESULT SP_CSession::
  196. Connect (
  197. SERVER_INFO *pInfo,
  198. ULONG cConns,
  199. BOOL fAbortable )
  200. {
  201. // If a connection is available,
  202. // then simply the existing one
  203. //
  204. if (m_dwSignature == LDAP_CONN_SIGNATURE)
  205. {
  206. m_cRefs += cConns;
  207. return S_OK;
  208. }
  209. // We need to create a new connection
  210. // let's cache the server info
  211. //
  212. HRESULT hr = ::IlsCopyServerInfo (&m_ServerInfo, pInfo);
  213. if (hr != S_OK)
  214. return hr;
  215. // Connect to ldap server
  216. //
  217. ULONG ulPort = LDAP_PORT;
  218. LPTSTR pszServerName = My_strdup(m_ServerInfo.pszServerName);
  219. if (NULL == pszServerName)
  220. {
  221. return E_OUTOFMEMORY;
  222. }
  223. LPTSTR pszSeparator = My_strchr(pszServerName, _T(':'));
  224. if (NULL != pszSeparator)
  225. {
  226. *pszSeparator = _T('\0');
  227. ulPort = GetStringLong(pszSeparator + 1);
  228. }
  229. m_ld = ::ldap_open (pszServerName, ulPort);
  230. MemFree(pszServerName);
  231. if (m_ld == NULL)
  232. {
  233. // We need to know why ldap_open() failed.
  234. // Is it because server name is not valid?
  235. // Or is it because server does not support LDAP?
  236. //
  237. // hr = (gethostbyname (m_ServerInfo.pszServerName) != NULL) ?
  238. // Winsock will set ERROR_OPEN_FAILED, but wldap32.dll sets ERROR_HOST_UNREACHABLE
  239. // The down side is that when the server was down, the client will try ULP.
  240. //
  241. DWORD dwErr = ::GetLastError ();
  242. MyDebugMsg ((ZONE_REQ, "ULS: ldap_open failed, err=%lu)\r\n", dwErr));
  243. hr = (dwErr == ERROR_OPEN_FAILED || dwErr == ERROR_HOST_UNREACHABLE) ?
  244. ILS_E_SERVER_SERVICE : ILS_E_SERVER_NAME;
  245. goto MyExit;
  246. }
  247. // Do the bind
  248. //
  249. hr = Bind (fAbortable);
  250. if (hr == S_OK)
  251. {
  252. // remember the handle and increment the reference count
  253. m_cRefs = cConns;
  254. m_dwSignature = LDAP_CONN_SIGNATURE;
  255. }
  256. MyExit:
  257. MyDebugMsg ((ZONE_CONN, "ILS: Connect: hr=0x%p, m_ld=0x%p, server=%s\r\n", (DWORD) hr, m_ld, m_ServerInfo.pszServerName));
  258. if (hr != S_OK)
  259. {
  260. InternalCleanup ();
  261. }
  262. return hr;
  263. }
  264. /* ---------- private methods ----------- */
  265. VOID SP_CSession::
  266. InternalCleanup ( VOID )
  267. {
  268. if (IsUsed ())
  269. {
  270. MyDebugMsg ((ZONE_CONN, "ILS: InternalCleanup: m_ld=0x%p, server=%s\r\n", m_ld, m_ServerInfo.pszServerName));
  271. // Clean up these two ASAP because ldap_unbind may delay
  272. //
  273. m_dwSignature = 0;
  274. ::IlsFreeServerInfo (&m_ServerInfo);
  275. // Free the ldap infor
  276. //
  277. if (m_ld != NULL)
  278. {
  279. ldap_unbind (m_ld);
  280. m_ld = NULL;
  281. }
  282. // Clear it out
  283. //
  284. ClearUsed ();
  285. }
  286. }
  287. /* ==================== container ========================= */
  288. /* ---------- public methods ----------- */
  289. SP_CSessionContainer::
  290. SP_CSessionContainer ( VOID ) :
  291. m_cEntries (0),
  292. m_aConns (NULL)
  293. {
  294. ::MyInitializeCriticalSection (&m_csSessContainer);
  295. }
  296. SP_CSessionContainer::
  297. ~SP_CSessionContainer ( VOID )
  298. {
  299. ::MyDeleteCriticalSection (&m_csSessContainer);
  300. m_cEntries = 0;
  301. delete [] m_aConns;
  302. }
  303. HRESULT SP_CSessionContainer::
  304. Initialize (
  305. ULONG cEntries,
  306. SP_CSession *ConnArr )
  307. {
  308. m_cEntries = cEntries;
  309. m_aConns = new SP_CSession[cEntries];
  310. return ((m_aConns != NULL) ? S_OK : ILS_E_MEMORY);
  311. }
  312. HRESULT SP_CSessionContainer::
  313. GetSession (
  314. SP_CSession **ppConn,
  315. SERVER_INFO *pInfo,
  316. ULONG cConns,
  317. BOOL fAbortable )
  318. {
  319. MyAssert (ppConn != NULL);
  320. MyAssert (pInfo != NULL);
  321. *ppConn = NULL;
  322. HRESULT hr;
  323. WriteLock ();
  324. // The first pass is to see any existing connection
  325. //
  326. for (ULONG i = 0; i < m_cEntries; i++)
  327. {
  328. if (m_aConns[i].IsUsed ())
  329. {
  330. if (m_aConns[i].SameServerInfo (pInfo))
  331. {
  332. *ppConn = &m_aConns[i];
  333. hr = m_aConns[i].Connect (pInfo, cConns, fAbortable);
  334. goto MyExit;
  335. }
  336. }
  337. }
  338. // The second pass is to see any empty slot
  339. //
  340. for (i = 0; i < m_cEntries; i++)
  341. {
  342. if (! m_aConns[i].IsUsed ())
  343. {
  344. m_aConns[i].SetUsed ();
  345. *ppConn = &m_aConns[i];
  346. hr = m_aConns[i].Connect (pInfo, cConns, fAbortable);
  347. goto MyExit;
  348. }
  349. }
  350. hr = ILS_E_MEMORY;
  351. MyExit:
  352. WriteUnlock ();
  353. return hr;
  354. }
  355. /* ---------- protected methods ----------- */
  356. /* ---------- private methods ----------- */
  357.