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.

647 lines
21 KiB

  1. //
  2. // ldapconn.h -- This file contains the class definitions for:
  3. // CLdapConnection
  4. // CLdapConnectionCache
  5. //
  6. // Created:
  7. // Dec 31, 1996 -- Milan Shah (milans)
  8. //
  9. // Changes:
  10. //
  11. #ifndef _LDAPCONN_H_
  12. #define _LDAPCONN_H_
  13. #include <transmem.h>
  14. #include "winldap.h"
  15. #include "rwex.h"
  16. #include "spinlock.h"
  17. #include "catperf.h"
  18. #include "catdefs.h"
  19. //
  20. // Timeout value (in seconds) to pass into ldap_result
  21. //
  22. #define LDAPCONN_DEFAULT_RESULT_TIMEOUT (2*60) // 2 Minutes
  23. #define DEFAULT_LDAP_REQUEST_TIME_LIMIT (10*60) // 10 minutes
  24. #define LDAPCONN_RESULT_TIMEOUT_KEY "System\\CurrentControlSet\\Services\\SMTPSVC\\Parameters"
  25. #define LDAPCONN_RESULT_TIMEOUT_VALUE "LdapResultTimeout"
  26. #define LDAP_REQUEST_TIME_LIMIT_VALUE "LdapRequestTimeLimit"
  27. typedef VOID LDAPRESULT;
  28. typedef PVOID PLDAPRESULT;
  29. typedef VOID LDAPENTRY;
  30. typedef PVOID PLDAPENTRY;
  31. enum LDAP_BIND_TYPE {
  32. BIND_TYPE_NONE,
  33. BIND_TYPE_SIMPLE,
  34. BIND_TYPE_GENERIC,
  35. BIND_TYPE_CURRENTUSER
  36. };
  37. class CLdapConnection;
  38. typedef VOID (*LPLDAPCOMPLETION)(
  39. LPVOID ctx,
  40. DWORD dwNumResults,
  41. ICategorizerItemAttributes **rgpICatItemAttrs,
  42. HRESULT hr,
  43. BOOL fFinalCompletion);
  44. DWORD WINAPI LdapCompletionThread(LPVOID ctx);
  45. VOID LogLdapError(
  46. IN ISMTPServerEx *pISMTPServerEx,
  47. IN ULONG ulLdapErr,
  48. IN LPSTR pszHost,
  49. IN LPSTR pszCall);
  50. CatDebugClass(CLdapConnection)
  51. {
  52. public:
  53. virtual HRESULT HrInitialize();
  54. virtual DWORD AddRef()
  55. {
  56. return InterlockedIncrement((PLONG)&m_dwRefCount);
  57. }
  58. virtual DWORD Release();
  59. virtual VOID ReleaseAndWaitForDestruction();
  60. virtual VOID FinalRelease();
  61. virtual DWORD GetRefCount()
  62. {
  63. return m_dwRefCount;
  64. }
  65. virtual LPSTR GetNamingContext() { // Return the naming context
  66. return( m_szNamingContext ); // of the connection
  67. }
  68. virtual LPWSTR GetNamingContextW() {
  69. return( m_wszNamingContext );
  70. }
  71. virtual LPSTR GetHostName() {
  72. return( m_szHost );
  73. }
  74. virtual DWORD GetPort() {
  75. return( m_dwPort );
  76. }
  77. virtual LPSTR GetAccount() {
  78. return( m_szAccount );
  79. }
  80. virtual LPSTR GetPassword() {
  81. return( m_szPassword );
  82. }
  83. virtual LDAP_BIND_TYPE GetBindType() {
  84. return( m_bt );
  85. }
  86. virtual HRESULT Search( // Look up objects matching
  87. LPCSTR szBaseDN, // specified criteria in the
  88. int nScope, // DS
  89. LPCSTR szFilter,
  90. LPCSTR *rgszAttributes,
  91. PLDAPRESULT *ppResult);
  92. virtual HRESULT AsyncSearch( // Asynchronously look up
  93. LPCWSTR szBaseDN, // objects matching specified
  94. int nScope, // criteria in the DS. The
  95. LPCWSTR szFilter, // results are passed to
  96. LPCWSTR szAttributes[], // fnCompletion when they
  97. DWORD dwPageSize, // Optinal page size
  98. LPLDAPCOMPLETION fnCompletion, // become available.
  99. LPVOID ctxCompletion);
  100. //
  101. // Same as above with UTF8 search filter
  102. //
  103. virtual HRESULT AsyncSearch(
  104. LPCWSTR szBaseDN, // objects matching specified
  105. int nScope, // criteria in the DS. The
  106. LPCSTR szFilterUTF8, // results are passed to
  107. LPCWSTR szAttributes[], // fnCompletion when they
  108. DWORD dwPageSize, // Optinal page size
  109. LPLDAPCOMPLETION fnCompletion, // become available.
  110. LPVOID ctxCompletion);
  111. //
  112. // Same as above with UTF8 search filter and base DN
  113. //
  114. virtual HRESULT AsyncSearch(
  115. LPCSTR szBaseDN, // objects matching specified
  116. int nScope, // criteria in the DS. The
  117. LPCSTR szFilterUTF8, // results are passed to
  118. LPCWSTR szAttributes[], // fnCompletion when they
  119. DWORD dwPageSize, // Optinal page size
  120. LPLDAPCOMPLETION fnCompletion, // become available.
  121. LPVOID ctxCompletion);
  122. virtual VOID CancelAllSearches( // Cancels all pending searches
  123. HRESULT hr = HRESULT_FROM_WIN32(ERROR_CANCELLED),
  124. ISMTPServer *pISMTPServer = NULL);
  125. VOID ProcessAsyncResult( // Method to process results
  126. PLDAPMessage pres, // of AsyncSearch requests
  127. DWORD dwLdapError,
  128. BOOL *pfTerminateIndicator);
  129. friend DWORD WINAPI LdapCompletionThread(// Friend function to
  130. LPVOID ctx); // handle AsyncSearch
  131. // completions.
  132. virtual HRESULT GetFirstEntry( // Get first entry from the
  133. PLDAPRESULT pResult, // search result returned
  134. PLDAPENTRY *ppEntry); // by ::Search
  135. virtual HRESULT GetNextEntry( // Get the next entry from
  136. PLDAPRESULT pResult, // the search result
  137. PLDAPENTRY *ppEntry);
  138. virtual HRESULT GetAttributeValues( // Get an entry's attribute
  139. PLDAPENTRY pEntry, // values
  140. LPCSTR szAttribute,
  141. LPSTR *prgszValues[]);
  142. static VOID FreeResult( // Free a search result
  143. PLDAPRESULT pResult);
  144. virtual VOID FreeValues( // Free values returned by
  145. LPSTR rgszValues[]); // ::GetAttributeValues
  146. virtual HRESULT Add( // Add a set of new
  147. LPCSTR szDN, // attributes to an existing
  148. LPCSTR *rgszAttributes, // object in the DS
  149. LPCSTR *rgrgszValues[]) {
  150. return ( ModifyAttributes(
  151. LDAP_MOD_ADD,
  152. szDN,
  153. rgszAttributes,
  154. rgrgszValues) );
  155. }
  156. virtual HRESULT Delete( // Delete attributes from
  157. LPCSTR szDN, // an existing object in the
  158. LPCSTR *rgszAttributes) { // DS
  159. return ( ModifyAttributes(
  160. LDAP_MOD_DELETE,
  161. szDN,
  162. rgszAttributes,
  163. NULL) );
  164. }
  165. virtual HRESULT Update( // Update attributes on an
  166. LPCSTR szDN, // existing object in the DS
  167. LPCSTR rgszAttributes[],
  168. LPCSTR *rgrgszValues[]) {
  169. return ( ModifyAttributes(
  170. LDAP_MOD_REPLACE,
  171. szDN,
  172. rgszAttributes,
  173. rgrgszValues) );
  174. }
  175. //
  176. // Returns an ISMTPServerEx interface for logging events or
  177. // NULL if none are available
  178. //
  179. virtual ISMTPServerEx * GetISMTPServerEx() = 0;
  180. LPSTR SzHost()
  181. {
  182. return m_szHost;
  183. }
  184. static VOID GlobalInit()
  185. {
  186. //
  187. // initialize LDAP perf block
  188. //
  189. ZeroMemory(&g_LDAPPerfBlock, sizeof(g_LDAPPerfBlock));
  190. m_ldaptimeout.tv_sec = LDAPCONN_DEFAULT_RESULT_TIMEOUT;
  191. m_ldaptimeout.tv_usec = 0;
  192. m_dwLdapRequestTimeLimit = DEFAULT_LDAP_REQUEST_TIME_LIMIT;
  193. //
  194. // read configurable static members from the registry
  195. //
  196. InitializeFromRegistry();
  197. }
  198. static VOID InitializeFromRegistry();
  199. protected:
  200. CLdapConnection( // The constructor and
  201. LPSTR szHost, // destructor are protected
  202. DWORD dwPort,
  203. LPSTR szNamingContext, // since only derived classes
  204. LPSTR szAccount, // can create/delete these
  205. LPSTR szPassword,
  206. LDAP_BIND_TYPE BindType);
  207. virtual ~CLdapConnection();
  208. virtual HRESULT Connect(); // Create/Delete connection
  209. // to LDAP host
  210. virtual VOID Disconnect();
  211. virtual VOID Invalidate();
  212. virtual BOOL IsValid();
  213. virtual DWORD BindToHost(
  214. PLDAP pldap,
  215. LPSTR szAccount,
  216. LPSTR szPassword);
  217. virtual BOOL IsEqual( // Return true if the
  218. LPSTR szHost, // object member variables
  219. DWORD dwPort,
  220. LPSTR szNamingContext, // match the passed in
  221. LPSTR szAccount, // values
  222. LPSTR szPassword,
  223. LDAP_BIND_TYPE BindType);
  224. virtual HRESULT ModifyAttributes( // Helper function for
  225. int nOperation, // ::Add, ::Delete, and
  226. LPCSTR szDN, // ::Update public functions
  227. LPCSTR rgszAttributes[],
  228. LPCSTR *rgrgszValues[]);
  229. virtual HRESULT LdapErrorToHr(
  230. DWORD dwLdapError);
  231. VOID SetTerminateIndicatorTrue()
  232. {
  233. BOOL *pfTerminate;
  234. m_fTerminating = TRUE;
  235. pfTerminate = (BOOL *) InterlockedExchangePointer(
  236. (PVOID *) &m_pfTerminateCompletionThreadIndicator,
  237. NULL);
  238. if(pfTerminate)
  239. *pfTerminate = TRUE;
  240. }
  241. VOID CancelExpiredSearches(HRESULT hr);
  242. ULONG GetDefaultNamingContext(); // Helper function to
  243. // get the default
  244. // naming context from
  245. // the server we are
  246. // connected to.
  247. static LDAP_TIMEVAL m_ldaptimeout;
  248. static DWORD m_dwLdapRequestTimeLimit;
  249. DWORD m_dwPort;
  250. char m_szHost[CAT_MAX_DOMAIN];
  251. char m_szNamingContext[CAT_MAX_DOMAIN];
  252. WCHAR m_wszNamingContext[CAT_MAX_DOMAIN];
  253. char m_szAccount[CAT_MAX_LOGIN];
  254. char m_szPassword[CAT_MAX_PASSWORD];
  255. #define SIGNATURE_LDAPCONN ((DWORD) 'CadL')
  256. #define SIGNATURE_LDAPCONN_INVALID ((DWORD) 'XadL')
  257. DWORD m_dwSignature;
  258. DWORD m_dwRefCount;
  259. DWORD m_dwDestructionWaiters;
  260. HANDLE m_hShutdownEvent;
  261. LDAP_BIND_TYPE m_bt;
  262. PLDAP GetPLDAP()
  263. {
  264. if(m_pCPLDAPWrap)
  265. return m_pCPLDAPWrap->GetPLDAP();
  266. else
  267. return NULL;
  268. }
  269. CPLDAPWrap *m_pCPLDAPWrap;
  270. BOOL m_fDefaultNamingContext;
  271. //
  272. // Unfortunately, our RFC1823 LDAP API provides no access to the
  273. // socket handle which we can register with a completion port. So,
  274. // if one or more async search request is issued, we have to burn a
  275. // thread to await its completion.
  276. //
  277. //
  278. // This spin lock protects access to the pending request list as
  279. // well as m_dwStatusFlags
  280. //
  281. SPIN_LOCK m_spinlockCompletion;
  282. // CRITICAL_SECTION m_cs;
  283. //
  284. // jstamerj 980501 15:56:27:
  285. // Reader/writer lock so that we wait for all calls in
  286. // ldap_search_ext before cancelling all pending searches
  287. //
  288. CExShareLock m_ShareLock;
  289. DWORD m_idCompletionThread;
  290. HANDLE m_hCompletionThread;
  291. HANDLE m_hOutstandingRequests;
  292. BOOL *m_pfTerminateCompletionThreadIndicator;
  293. BOOL m_fTerminating;
  294. BOOL m_fValid;
  295. typedef struct _PendingRequest {
  296. int msgid;
  297. LPLDAPCOMPLETION fnCompletion;
  298. LPVOID ctxCompletion;
  299. LIST_ENTRY li;
  300. //
  301. // Parameters for paged searches
  302. //
  303. DWORD dwPageSize;
  304. PLDAPSearch pldap_search;
  305. DWORD dwTickCount;
  306. } PENDING_REQUEST, *PPENDING_REQUEST;
  307. LIST_ENTRY m_listPendingRequests;
  308. BOOL m_fCancel;
  309. //
  310. // The following three functions must be called inside an external
  311. // lock (m_spinlockcompletion)
  312. //
  313. VOID NotifyCancel()
  314. {
  315. m_fCancel = TRUE;
  316. }
  317. VOID ClearCancel()
  318. {
  319. m_fCancel = FALSE;
  320. }
  321. BOOL CancelOccured()
  322. {
  323. return m_fCancel;
  324. }
  325. VOID SetPort(DWORD dwPort)
  326. {
  327. m_dwPort = (dwPort != 0) ? dwPort : LDAP_PORT;
  328. }
  329. BOOL fIsPortEqual(DWORD dwPort)
  330. {
  331. return (m_dwPort == ((dwPort != 0) ? dwPort : LDAP_PORT));
  332. }
  333. virtual HRESULT CreateCompletionThreadIfNeeded();
  334. virtual VOID SetTerminateCompletionThreadIndicator(
  335. BOOL *pfTerminateCompletionThreadIndicator);
  336. virtual VOID InsertPendingRequest(
  337. PPENDING_REQUEST preq);
  338. virtual VOID RemovePendingRequest(
  339. PPENDING_REQUEST preq);
  340. virtual VOID CallCompletion(
  341. PPENDING_REQUEST preq,
  342. PLDAPMessage pres,
  343. HRESULT hrStatus,
  344. BOOL fFinalCompletion);
  345. VOID AbandonRequest(
  346. PPENDING_REQUEST preq)
  347. {
  348. ldap_abandon(
  349. GetPLDAP(),
  350. preq->msgid);
  351. if(preq->pldap_search)
  352. ldap_search_abandon_page(
  353. GetPLDAP(),
  354. preq->pldap_search);
  355. INCREMENT_LDAP_COUNTER(AbandonedSearches);
  356. DECREMENT_LDAP_COUNTER(PendingSearches);
  357. }
  358. VOID LogLdapError(
  359. IN ULONG ulLdapErr,
  360. IN LPSTR pszFormatString,
  361. ...);
  362. static VOID LogLdapError(
  363. IN ISMTPServerEx *pISMTPServerEx,
  364. IN ULONG ulLdapErr,
  365. IN LPSTR pszFormatString,
  366. ...);
  367. };
  368. //
  369. // For the hash function to work correctly, the table size must be a power of
  370. // two. This is just an efficiency trick; there is nothing fundamentally
  371. // wrong with using some other size, except that the hash function would have
  372. // to use an expensive MODULO operator instead of a cheap AND.
  373. //
  374. #define LDAP_CONNECTION_CACHE_TABLE_SIZE 256
  375. #define MAX_LDAP_CONNECTIONS_PER_HOST_KEY "System\\CurrentControlSet\\Services\\SMTPSVC\\Parameters"
  376. #define MAX_LDAP_CONNECTIONS_PER_HOST_VALUE "MaxLdapConnections"
  377. class CLdapConnectionCache
  378. {
  379. public:
  380. CLdapConnectionCache(
  381. ISMTPServerEx *pISMTPServerEx); // Constructor
  382. ~CLdapConnectionCache(); // Destructor
  383. HRESULT GetConnection( // Given LDAP config info,
  384. CLdapConnection **ppConn,
  385. LPSTR szHost, // retrieve a connection to
  386. DWORD dwPort,
  387. LPSTR szNamingContext, // the LDAP host.
  388. LPSTR szAccount,
  389. LPSTR szPassword,
  390. LDAP_BIND_TYPE bt,
  391. PVOID pCreateContext = NULL);
  392. VOID CancelAllConnectionSearches(
  393. ISMTPServer *pISMTPServer = NULL);
  394. //
  395. // It is intended for there to be a single, global, instance of
  396. // a CLdapConnectionCache object, serving multiple instances of
  397. // CEmailIDLdapStore. Each instance of CEmailIDLdapStore needs to
  398. // call AddRef() and Release() in its constructor/destructor, so that
  399. // the connection cache knows to clean up connections in the cache
  400. // when the ref count goes to 0.
  401. //
  402. VOID AddRef();
  403. VOID Release();
  404. private:
  405. //
  406. // An internally utility function to release a connection
  407. //
  408. VOID ReleaseConnectionInternal(
  409. CLdapConnection *pConnection,
  410. BOOL fLockRequired);
  411. LONG m_cRef;
  412. protected:
  413. class CCachedLdapConnection : public CLdapConnection {
  414. public:
  415. CCachedLdapConnection(
  416. LPSTR szHost,
  417. DWORD dwPort,
  418. LPSTR szNamingContext,
  419. LPSTR szAccount,
  420. LPSTR szPassword,
  421. LDAP_BIND_TYPE bt,
  422. CLdapConnectionCache *pCache) :
  423. CLdapConnection(
  424. szHost,
  425. dwPort,
  426. szNamingContext,
  427. szAccount,
  428. szPassword,
  429. bt)
  430. {
  431. m_pCache = pCache;
  432. }
  433. HRESULT Connect() {
  434. return( CLdapConnection::Connect() );
  435. }
  436. VOID Disconnect() {
  437. CLdapConnection::Disconnect();
  438. }
  439. VOID Invalidate() {
  440. CLdapConnection::Invalidate();
  441. }
  442. BOOL IsValid() {
  443. return( CLdapConnection::IsValid() );
  444. }
  445. BOOL IsEqual(
  446. LPSTR szHost,
  447. DWORD dwPort,
  448. LPSTR szNamingContext,
  449. LPSTR szAccount,
  450. LPSTR szPassword,
  451. LDAP_BIND_TYPE BindType) {
  452. return( CLdapConnection::IsEqual(
  453. szHost, dwPort, szNamingContext, szAccount,
  454. szPassword, BindType) );
  455. }
  456. ISMTPServerEx *GetISMTPServerEx()
  457. {
  458. return (m_pCache) ? m_pCache->GetISMTPServerEx() : NULL;
  459. }
  460. DWORD Release();
  461. LIST_ENTRY li;
  462. CLdapConnectionCache *m_pCache;
  463. };
  464. virtual VOID RemoveFromCache(
  465. CCachedLdapConnection *pConn);
  466. virtual CCachedLdapConnection *CreateCachedLdapConnection(
  467. LPSTR szHost,
  468. DWORD dwPort,
  469. LPSTR szNamingContext,
  470. LPSTR szAccount,
  471. LPSTR szPassword,
  472. LDAP_BIND_TYPE bt,
  473. PVOID pCreateContext)
  474. {
  475. CCachedLdapConnection *pret;
  476. pret = new CCachedLdapConnection(
  477. szHost,
  478. dwPort,
  479. szNamingContext,
  480. szAccount,
  481. szPassword,
  482. bt,
  483. this);
  484. if(pret)
  485. if(FAILED(pret->HrInitialize())) {
  486. pret->Release();
  487. pret = NULL;
  488. }
  489. return pret;
  490. }
  491. ISMTPServerEx *GetISMTPServerEx()
  492. {
  493. return m_pISMTPServerEx;
  494. }
  495. private:
  496. //
  497. // We want to support multiple connections per host, up to a maximum
  498. // of m_cMaxHostConnections. We achieve this in a simple way by
  499. // keeping a per-cache m_nConnectionSkipCount. Every time we are
  500. // searching for a cached connection to a host in, we skip
  501. // m_nNextConnectionSkipCount cached connections. Every time we
  502. // find a cached connection, we bump up
  503. // m_nNextCachedConnectionSkipCount by 1 modulo m_cMaxHostConnections.
  504. // This means we'll round robin through m_cMaxHostConnections
  505. // connections per host.
  506. //
  507. ISMTPServerEx *m_pISMTPServerEx;
  508. LONG m_nNextConnectionSkipCount;
  509. LONG m_cMaxHostConnections;
  510. LONG m_cCachedConnections;
  511. LIST_ENTRY m_rgCache[ LDAP_CONNECTION_CACHE_TABLE_SIZE ];
  512. CExShareLock m_rgListLocks[ LDAP_CONNECTION_CACHE_TABLE_SIZE ];
  513. LONG m_rgcCachedConnections[ LDAP_CONNECTION_CACHE_TABLE_SIZE ];
  514. VOID InitializeFromRegistry();
  515. unsigned short Hash(
  516. LPSTR szConnectionName);
  517. friend class CLdapConnectionCache::CCachedLdapConnection;
  518. friend class CBatchLdapConnection;
  519. };
  520. #endif // _LDAPCONN_H_