/**********************************************************************/ /** Microsoft Windows NT **/ /** Copyright(c) Microsoft Corp., 2001 **/ /**********************************************************************/ #ifndef __ADIO_HXX__ #define __ADIO_HXX__ /* adio.hxx Class definition for module to manage access to Active Directory. FILE HISTORY: RobSol 17-May-2001 Created. */ //------------------------------------------------------------------------------------------ // // this class maintains caching of a LDAP connections. One instance per LDAP connection // //------------------------------------------------------------------------------------------ class LdapCacheItem { friend class LDAP_CONN_CACHE; private: // // used by the linked list routines // LIST_ENTRY m_Link; // // name of domain for which LDAP connection established // StatStr m_strDomainName; // // Distingushed Name of domain - needed for the ldap_search routine // StatStr m_strForestDN; // // cached LDAP connection // LDAP *m_ldapConnection; // // reference count of users of this instance // LONG m_RefCount; DWORD Forest2DN( PCSTR pszForest); public: LdapCacheItem( const STR & DomainName, const STR & strUser, const STR & strDomain, const STR & strPassword); ~LdapCacheItem(); VOID AddRef() { InterlockedIncrement( &m_RefCount ); } VOID Release() { if (InterlockedDecrement( &m_RefCount ) > 0) { return; } delete this; } BOOL IsDomainNameMatch( const STR & DomainName) const { return m_strDomainName.Equ( DomainName ); } LDAP *QueryConnection() const { return m_ldapConnection; } PCHAR QueryForestDN() const { return m_strForestDN.QueryStr(); } }; typedef LdapCacheItem *PLdapCacheItem; //------------------------------------------------------------------------------------------ // // this class interfaces and manages caching of all LDAP connection cache objects for a // single server instance. it maintains the connection credentials for that server instance. // //------------------------------------------------------------------------------------------ class LDAP_CONN_CACHE { private: // // linked list head for LdapCacheItem instances // LIST_ENTRY m_ConnList; // // critical section to control access to the list. // CRITICAL_SECTION m_cs; // // name domain and password for user to authenticate LDAP connections. // StatStr m_User; StatStr m_Domain; StatStr m_Pass; inline VOID Lock() { ::EnterCriticalSection( &m_cs ); } inline VOID Unlock() { ::LeaveCriticalSection( &m_cs ); } public: LDAP_CONN_CACHE(); ~LDAP_CONN_CACHE(); DWORD Configure( const STR & strUser, const STR & strDomain, const STR & strPassword); PLdapCacheItem QueryLdapConnection( const STR & Domain ); }; typedef LDAP_CONN_CACHE *PLDAP_CONN_CACHE; //------------------------------------------------------------------------------------------ // // anonymous user AD property cache. one instance per site // refreshes itself after a global timeout // //------------------------------------------------------------------------------------------ class ADIO_ANONYM_CACHE { private: // // indicates whether the instance is valid. Set to TRUE when object initialized // successfully, set to FALSE when shuting down // BOOL m_Valid; // // reference count of usage. One count for the AD_IO object that points to this instance, // and one more for each query while the content is refreshed with data from AD or until // the ceched data is copied. // DWORD m_Reference; // // time when object has last been refreshed. // ULONGLONG m_TimeStamp; // // name and domain of user impersonating the anonymous ftp user // StatStr m_User; StatStr m_Domain; // // cached home directory path for the anonymous user // StatStr m_Path; // // critical section to lock the instance when reconfidured or the cached data updated. // CRITICAL_SECTION m_cs; VOID Lock() { ::EnterCriticalSection( &m_cs ); } VOID Unlock() { ::LeaveCriticalSection( &m_cs ); } public: ADIO_ANONYM_CACHE(); ~ADIO_ANONYM_CACHE(); DWORD Configure( IN PCSTR pszUser, IN PCSTR pszDomain); BOOL Reference(); VOID Release( BOOL Shutdown = FALSE); DWORD GetCachedPath( STR & TargetPath, PLDAP_CONN_CACHE pConnCache); }; typedef ADIO_ANONYM_CACHE *LPADIO_ANONYM_CACHE; //------------------------------------------------------------------------------------------ // // Asynchronous IO to the Active Directory // //------------------------------------------------------------------------------------------ // // states for an asynchronously serviced request. // typedef enum _eState { RequestStateInitial = 0, RequestStateRetrieve, RequestStateDone } eAdioAsyncState; typedef VOID (*tpAdioAsyncCallback)( HANDLE Ctx, DWORD Result ); class ADIO_ASYNC { private: // STATIC (GLOBAL) DATA // // critical section to lock access to the static members of the ADIO_ASYNC service // (lists, etc) // static CRITICAL_SECTION m_cs; // // total allocated request objects // static volatile LONG m_NumTotalAlloc; // // total request objects in the free list cache // static volatile LONG m_NumTotalFree; // // list head for active (pending) requests // static LIST_ENTRY m_WorkListHead; // // list head for free request object cache // static LIST_ENTRY m_FreeListHead; // // number of threads started to service async requests // static LONG m_ActiveThreads; // // handles to active threads // static HANDLE m_Threads[]; // // array of events the async service threads sleep on // static HANDLE m_Events[]; // PER INSTANCE DATA // // status of last operation on the instance // DWORD m_Status; // // next state of processing for this instance // eAdioAsyncState m_State; // // handle of the ldap connection cache // PLDAP_CONN_CACHE m_pConnCache; // // pointer to the DLAP cache item with the ldap connection for the current user domain // PLdapCacheItem m_pLdapCacheItem; // // reference number to the ldap asynchronous request // ULONG m_AsyncMsgNum; // // account name of current user // StatStr m_strUser; // // domain name of current user // StatStr m_strDomain; // // pointer to buffer where path name will be stored // STR *m_pstrTarget; // // ldap message pointer // LDAPMessage *m_pLdapMsg; // // ldap message type // ULONG m_LdapMsgType; // // pointer to callback routine where client is notified when request completed // tpAdioAsyncCallback m_pfnClientCallback; // // client context user passed back with callback routine // HANDLE m_hClientCtx; // // link this instance into the global lists // LIST_ENTRY m_Link; static inline VOID Lock() { ::EnterCriticalSection( &m_cs ); } static inline VOID Unlock() { ::LeaveCriticalSection( &m_cs ); } static ADIO_ASYNC *Alloc(); static VOID Free( ADIO_ASYNC *pReq); static BOOL FetchRequest( ADIO_ASYNC **ppRec ); VOID QueueWork( VOID ) { Lock(); InsertTailList( &m_WorkListHead, &m_Link ); Unlock(); } static DWORD WorkerThread( LPVOID pParam); BOOL IsResultReady(); VOID Reset( VOID ); BOOL ProcessSearch(BOOL fSyncSearch = FALSE); BOOL ProcessRetrieve(); VOID ProcessComplete(); public: ADIO_ASYNC() {} ~ADIO_ASYNC() {} static BOOL Initialize(); static BOOL Terminate(); static DWORD QueryRootDir( const STR & strUser, const STR & strDomain, PLDAP_CONN_CACHE pConnCache, STR * pstrTarget, ADIO_ASYNC ** ppadioReqCtx, tpAdioAsyncCallback pfnCallback, HANDLE hClientCtx); static DWORD QueryRootDir_Sync( const STR & strUser, const STR & strDomain, PLDAP_CONN_CACHE pConnCache, STR & strTarget); VOID EndRequest(); }; typedef ADIO_ASYNC *PADIO_ASYNC; //------------------------------------------------------------------------------------------ // // The AD_IO class is the interface to the active directory. It provides these services // - dynamically load ldap libraries and binds to the needed functions // - maintains reference and unloads ldap libs when no longer needed // - interfaces the LDAP connection cache // - interfaces the anonymous user property cache // //------------------------------------------------------------------------------------------ // // function pointers for dynamic binding // to avoid the overhead of loading AD DLLs when not in enterprise isolation mode, we load // these DLLs dynamically when needed. For normal product build, *DO NOT* define the constant // USE_STATIC_FUNCTION_BINDING. Defining the constant allows compiling the source code with // the system defined function prototypes, to validate no changes have been made to the lib // functions. // // #define USE_STATIC_FUNCTION_BINDING 1 #if defined( USE_STATIC_FUNCTION_BINDING ) #define pfn_DsGetDcName DsGetDcNameA #define pfn_NetApiBufferFree NetApiBufferFree #define pfn_ldap_init ldap_init #define pfn_ldap_set_option ldap_set_option #define pfn_ldap_bind_s ldap_bind_s #define pfn_ldap_unbind ldap_unbind #define pfn_ldap_search ldap_search #define pfn_ldap_search_s ldap_search_s #define pfn_ldap_first_entry ldap_first_entry #define pfn_ldap_get_values ldap_get_values #define pfn_ldap_value_free ldap_value_free #define pfn_ldap_msgfree ldap_msgfree #define pfn_ldap_abandon ldap_abandon #define pfn_ldap_result ldap_result #define pfn_ldap_parse_result ldap_parse_result #define pfn_LdapGetLastError LdapGetLastError #else // USE_STATIC_FUNCTION_BINDING #define pfn_DsGetDcName AD_IO::_pfn_DsGetDcName #define pfn_NetApiBufferFree AD_IO::_pfn_NetApiBufferFree #define pfn_ldap_init AD_IO::_pfn_ldap_init #define pfn_ldap_set_option AD_IO::_pfn_ldap_set_option #define pfn_ldap_bind_s AD_IO::_pfn_ldap_bind_s #define pfn_ldap_unbind AD_IO::_pfn_ldap_unbind #define pfn_ldap_search AD_IO::_pfn_ldap_search #define pfn_ldap_search_s AD_IO::_pfn_ldap_search_s #define pfn_ldap_first_entry AD_IO::_pfn_ldap_first_entry #define pfn_ldap_get_values AD_IO::_pfn_ldap_get_values #define pfn_ldap_value_free AD_IO::_pfn_ldap_value_free #define pfn_ldap_msgfree AD_IO::_pfn_ldap_msgfree #define pfn_ldap_abandon AD_IO::_pfn_ldap_abandon #define pfn_ldap_result AD_IO::_pfn_ldap_result #define pfn_ldap_parse_result AD_IO::_pfn_ldap_parse_result #define pfn_LdapGetLastError AD_IO::_pfn_LdapGetLastError // // functions in NETAPI32.DLL // these prototypes must match the corresponding function prototypes in the system header files // typedef DWORD (WINAPI *type_DsGetDcName)( LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG, PDOMAIN_CONTROLLER_INFOA *); typedef NET_API_STATUS (NET_API_FUNCTION *type_NetApiBufferFree)( LPVOID); // // functions in WLDAP32.DLL // typedef LDAP * (LDAPAPI *type_ldap_init)( PCHAR HostName, ULONG PortNumber); typedef ULONG (LDAPAPI *type_ldap_set_option)( LDAP *ld, int option, const void *invalue); typedef ULONG (LDAPAPI *type_ldap_bind_s)( LDAP *ld, PCHAR dn, PCHAR cred, ULONG method); typedef ULONG (LDAPAPI *type_ldap_unbind)( LDAP *ld); typedef ULONG (LDAPAPI *type_ldap_search)( LDAP *ld, PCHAR base, ULONG scope, PCHAR filter, PCHAR attrs[], ULONG attrsonly); typedef ULONG (LDAPAPI *type_ldap_search_s)( LDAP *ld, PCHAR base, ULONG scope, PCHAR filter, PCHAR attrs[], ULONG attrsonly, LDAPMessage **res); typedef ULONG (LDAPAPI *type_ldap_search_ext)( LDAP *ld, PCHAR base, ULONG scope, PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *ServerControls, PLDAPControlA *ClientControls, ULONG TimeLimit, ULONG SizeLimit, ULONG *MessageNumber); typedef ULONG (LDAPAPI *type_ldap_search_ext_s)( LDAP *ld, PCHAR base, ULONG scope, PCHAR filter, PCHAR attrs[], ULONG attrsonly, PLDAPControlA *ServerControls, PLDAPControlA *ClientControls, struct l_timeval *timeout, ULONG SizeLimit, LDAPMessage **res); typedef LDAPMessage * (LDAPAPI *type_ldap_first_entry)( LDAP *ld, LDAPMessage *res); typedef PCHAR * (LDAPAPI *type_ldap_get_values)( LDAP *ld, LDAPMessage *entry, const PCHAR attr); typedef ULONG (LDAPAPI *type_ldap_result)( LDAP *ld, ULONG msgid, ULONG all, struct l_timeval *timeout, LDAPMessage **res); typedef ULONG (LDAPAPI *type_ldap_parse_result)( LDAP *Connection, LDAPMessage *ResultMessage, ULONG *ReturnCode OPTIONAL, PCHAR *MatchedDNs OPTIONAL, PCHAR *ErrorMessage OPTIONAL, PCHAR **Referrals OPTIONAL, PLDAPControlA **ServerControls OPTIONAL, BOOLEAN Freeit); typedef ULONG (LDAPAPI *type_ldap_abandon)( LDAP *ld, ULONG msgid); typedef ULONG (LDAPAPI *type_ldap_value_free)( PCHAR *vals); typedef ULONG (LDAPAPI *type_ldap_msgfree)( LDAPMessage *res); typedef ULONG (LDAPAPI *type_LdapGetLastError)( VOID); #endif // USE_STATIC_FUNCTION_BINDING class AD_IO { public: #if !defined( USE_STATIC_FUNCTION_BINDING ) static HMODULE hNetApi32; static type_DsGetDcName _pfn_DsGetDcName; static type_NetApiBufferFree _pfn_NetApiBufferFree; static HMODULE hWLdap32; static type_ldap_init _pfn_ldap_init; static type_ldap_set_option _pfn_ldap_set_option; static type_ldap_bind_s _pfn_ldap_bind_s; static type_ldap_unbind _pfn_ldap_unbind; static type_ldap_search _pfn_ldap_search; static type_ldap_search_s _pfn_ldap_search_s; static type_ldap_first_entry _pfn_ldap_first_entry; static type_ldap_get_values _pfn_ldap_get_values; static type_ldap_abandon _pfn_ldap_abandon; static type_ldap_result _pfn_ldap_result; static type_ldap_parse_result _pfn_ldap_parse_result; static type_ldap_value_free _pfn_ldap_value_free; static type_ldap_msgfree _pfn_ldap_msgfree; static type_LdapGetLastError _pfn_LdapGetLastError; #endif private: // // global service refcount to AD_IO. when > 0, libs loaded, and all ldap interfaces // initialized. when dropped to 0, all ldap interfaces shut down. // static DWORD m_dwRefCount; // // critical section to control access to the global members // static CRITICAL_SECTION m_cs; // // indicates when the AD_IO global services have been properly initialized // static BOOL m_fLibsInitOK; // // credentials for connecting to the Active Directory // StatStr m_User; StatStr m_Domain; StatStr m_Pass; // // LDAP connection cache // PLDAP_CONN_CACHE m_pConnCache; // // cache of anonymous user properties // LPADIO_ANONYM_CACHE m_pAnonymCache; inline VOID Lock() { ::EnterCriticalSection( &m_cs ); } inline VOID Unlock() { ::LeaveCriticalSection( &m_cs ); } public: static VOID Initialize() { INITIALIZE_CRITICAL_SECTION( &m_cs ); m_dwRefCount = 0; } static VOID Terminate() { DeleteCriticalSection( &m_cs ); } AD_IO(); ~AD_IO(); DWORD Configure( const STR & strADAccUser, const STR & strADAccDomain, const STR & strADAccPass, PCSTR pszAnonUser, PCSTR pszAnonDomain); DWORD GetUserHomeDir( const STR & strUser, const STR & strDomain, STR * pstrTarget, ADIO_ASYNC ** ppadioReqCtx, tpAdioAsyncCallback pfnCallback, HANDLE hCLientCtx); DWORD GetAnonymHomeDir( STR & strTarget) const { return m_pAnonymCache ? m_pAnonymCache->GetCachedPath( strTarget, m_pConnCache) : ERROR_BAD_CONFIGURATION; } }; typedef AD_IO *LPAD_IO; #endif // __ADIO_HXX__