/*++ Copyright (c) 1990 Microsoft Corporation Module Name: ccred.cxx Abstract: This module abstracts user credentials for the multiple credential support. Author: Blake Jones (t-blakej) 08-08-1997 Revision History: --*/ #include "winnt.hxx" extern "C" { #include "winnetwk.h" } #pragma hdrstop // // The resource to bind to on remote machines. // static const PWSTR g_pszResourceName = TEXT("IPC$"); // // The error to return from CCred::ref when a bind to a different server // is attempted. The caller (should be CWinNTCredentials::RefServer) // should catch this and dispense with it appropriately. // // This should be an error other than E_OUTOFMEMORY or anything that // WNetAddConnection2 can return. This is pretty much a bogus error, // but I'm appropriating it just for RefServer. // static const HRESULT dwRebindErr = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS); ////////////////////////////////////////////////////////////////////////////// // // Internal class declarations: // //+--------------------------------------------------------------------------- // ____ _ _ ____ _ // / ___|_ __(_) |_/ ___| ___ ___| |_ // | | | '__| | __\___ \ / _ \/ __| __| // | |___| | | | |_ ___) | __/ (__| |_ // \____|_| |_|\__|____/ \___|\___|\__| // // Class CritSect -- C++ wrapper around an NT critical section object. // // Constructors: // CritSect() - initialize the NT object // // Public methods: // Lock - enter the critical section // Locked - whether we're in the crit. sect. // Unlock - leave the critical section // //---------------------------------------------------------------------------- class CritSect { public: CritSect() { InitializeCriticalSection(&m_cs); m_bLocked = FALSE; } void Lock() { EnterCriticalSection(&m_cs); m_bLocked = TRUE; } BOOL Locked() { return m_bLocked; } void Unlock() { LeaveCriticalSection(&m_cs); m_bLocked = FALSE; } ~CritSect() { DeleteCriticalSection(&m_cs); } private: CRITICAL_SECTION m_cs; BOOL m_bLocked; }; //+--------------------------------------------------------------------------- // ____ ____ _ _____ _ _ // / ___/ ___|_ __ ___ __| |_ _|_ _| |__ | | ___ // | | | | | '__/ _ \/ _` | | |/ _` | '_ \| |/ _ \ // | |__| |___| | | __/ (_| | | | (_| | |_) | | __/ // \____\____|_| \___|\__,_| |_|\__,_|_.__/|_|\___| // // Class CCredTable -- performs the authentication requests for the CCred // objects, and keeps a mapping for deregistration of objects. // // Constructors: // CCredTable() - make an empty credential table // // Public methods: // AddCred - try to obtain a credential; // if successful, add it to the table // DelCred - remove a credential from the table // //---------------------------------------------------------------------------- class CCredTable { public: CCredTable(); ~CCredTable(); HRESULT AddCred(PWSTR pszUserName, PWSTR pszPassword, PWSTR pszServer, DWORD *dwIndex); HRESULT DelCred(DWORD dwIndex); private: HRESULT GrowTable(void); // // The type used for storing credential->resource name mappings // for deregistration. // struct cred { PWSTR m_pResource; BOOL m_bUsed; DWORD m_dwCount; BOOL m_fAlreadyConnected; // was net use already established }; cred *m_pCredentials; // the cred->resource name table DWORD m_dwAlloc; // # table entries allocated DWORD m_dwUsed; // # table entries used CritSect m_cs; // to guard table access }; //+--------------------------------------------------------------------------- // ____ ____ _ // / ___/ ___|_ __ ___ __| | // | | | | | '__/ _ \/ _` | // | |__| |___| | | __/ (_| | // \____\____|_| \___|\__,_| // // Class CCred - encapsulates the reference-countable parts of the // WinNT authentication object. // // Constructors: // CCred() - create an empty CCred // CCred(PWSTR pszUserName, - create a CCred with a username // PWSTR pszPassword) and password. This does not bind // to a server yet. // // Public methods: // GetUserName - get the username of the credentials // SetUserName - set the username of the credentials // GetPassword - get the password of the credentials // SetPassword - set the password of the credentials // ref - add a reference to this object // deref - remove a reference from this object // //---------------------------------------------------------------------------- class CCred { // so it can call the copy ctor friend class CWinNTCredentials; public: CCred(); CCred(PWSTR pszUserName, PWSTR pszPassword); ~CCred(); HRESULT ref(PWSTR pszServer); HRESULT deref(); HRESULT GetUserName(PWSTR *ppszUserName); HRESULT GetPassword(PWSTR *ppszPassword); DWORD m_dwUsageCount; // this object's usage count private: CCred(const CCred& other); // only called by CWinNTCredentials CCred& operator=(const CCred&); // deliberately not implemented // // Used for storing the password encrypted. // enum { NW_ENCODE_SEED3 = 0x83 }; PWSTR m_pszUserName; // username PWSTR m_pszPassword; // password DWORD m_dwPasswdLen; // #bytes allocated for password PWSTR m_pszServer; // server on which we have credentials DWORD m_dwIndex; // index in the CredTable DWORD m_dwRefCount; // this object's reference count static CCredTable g_CredTable; // the table }; // // The table. // CCredTable CCred::g_CredTable; ////////////////////////////////////////////////////////////////////////////// // // Class definitions: // ///--------------------------------------------------------------------------- // ____ ____ _ // / ___/ ___|_ __ ___ __| | // | | | | | '__/ _ \/ _` | // | |__| |___| | | __/ (_| | definitions // \____\____|_| \___|\__,_| // ///--------------------------------------------------------------------------- //+--------------------------------------------------------------------------- // // CCred constructor // // Create an empty credential object. // //---------------------------------------------------------------------------- CCred::CCred() : m_pszUserName(NULL), m_pszPassword(NULL), m_pszServer(NULL), m_dwIndex((DWORD) -1), m_dwRefCount(0), m_dwUsageCount(1), m_dwPasswdLen(0) { } //+--------------------------------------------------------------------------- // // CCred constructor // // Create a credential object with a username and a password. // This doesn't increase the reference count, since it doesn't make any // connections to the server. // // Arguments: // [pszUserName] - username // [pszPassword] - password // //---------------------------------------------------------------------------- CCred::CCred(PWSTR pszUserName, PWSTR pszPassword) : m_pszUserName(NULL), m_pszPassword(NULL), m_pszServer(NULL), m_dwIndex((DWORD) -1), m_dwRefCount(0), m_dwUsageCount(1), m_dwPasswdLen(0) { // // NTRAID#NTBUG9-67020-2000-7-26-AjayR. We need a way to fail // on the constructor. // m_pszUserName = pszUserName ? AllocADsStr(pszUserName) : NULL; if (pszPassword) { UNICODE_STRING Password; UCHAR Seed = NW_ENCODE_SEED3; m_dwPasswdLen = (wcslen(pszPassword) + 1)*sizeof(WCHAR) + (DES_BLOCKLEN -1); m_pszPassword = (PWSTR) AllocADsMem(m_dwPasswdLen); ADsAssert(m_pszPassword != NULL); if (m_pszPassword) { wcscpy(m_pszPassword, pszPassword); RtlInitUnicodeString(&Password, m_pszPassword); if(NULL == g_pRtlEncryptMemory) RtlRunEncodeUnicodeString(&Seed, &Password); else { DWORD extra = 0; NTSTATUS ntStatus = 0; if(extra = (Password.MaximumLength % DES_BLOCKLEN)) Password.MaximumLength += (DES_BLOCKLEN - extra); ntStatus = g_pRtlEncryptMemory( Password.Buffer, Password.MaximumLength, 0 ); ADsAssert(ntStatus == STATUS_SUCCESS); m_dwPasswdLen = Password.MaximumLength; } } } else { m_dwPasswdLen = 0; m_pszPassword = NULL; } } //+--------------------------------------------------------------------------- // // CCred constructor // // Create a credential object with a username and a password. // This doesn't copy the reference count of the "other" object, nor the // server nor the server connection index. This is used to create // credentials with the same user/pass on a different server. // This should only be used by CWinNTCredentials::RefServer. // // Arguments: // [other] - credentials to copy // //---------------------------------------------------------------------------- CCred::CCred(const CCred& other) : m_pszServer(NULL), m_dwIndex((DWORD) -1), m_dwRefCount(0), m_dwUsageCount(1) { m_pszUserName = other.m_pszUserName ? AllocADsStr(other.m_pszUserName) : NULL; if(other.m_pszPassword != NULL) { m_pszPassword = (PWSTR) AllocADsMem(other.m_dwPasswdLen); ADsAssert(m_pszPassword != NULL); if(m_pszPassword != NULL) { memcpy(m_pszPassword, other.m_pszPassword, other.m_dwPasswdLen); m_dwPasswdLen = other.m_dwPasswdLen; } else m_dwPasswdLen = 0; } else { m_dwPasswdLen = 0; m_pszPassword = NULL; } } //+--------------------------------------------------------------------------- // // CCred destructor // // Doesn't lower the reference count. // The object is really deleted in deref(). // It will release the underlying info only if the // there are no outstanding references // -- AjayR modified on 6-24-98. // //---------------------------------------------------------------------------- CCred::~CCred() { // // Clean up only if the usageCount and refCount are 0 // Any other case means someone has a pointer to this // if (m_dwUsageCount == 0 && m_dwRefCount == 0) { if (m_pszUserName) FreeADsStr(m_pszUserName); if (m_pszPassword) FreeADsMem(m_pszPassword); if (m_pszServer) FreeADsStr(m_pszServer); } } //+--------------------------------------------------------------------------- // // CCred::ref // // Adds a reference to this credential object, and if necessary, binds // to the specified server. If this is already bound to the given server, // the reference count is simply increased. // // Arguments: // [pszServer] - server to bind to // // Returns: // S_OK - if we bound to the server, or are already bound to // the given server. // E_FAIL - if this object is bound, and "pszServer" is not the // same server as we are bound to. // E_OUTOFMEMORY - if we run out of memory. // Other error codes resulting from WNetAddConnection2. // //---------------------------------------------------------------------------- HRESULT CCred::ref(PWSTR pszServer) { HRESULT hr = S_OK; PWSTR pszPassword = NULL; if (!m_pszServer) { hr = GetPassword(&pszPassword); BAIL_ON_FAILURE(hr); hr = g_CredTable.AddCred(m_pszUserName, pszPassword, pszServer, &m_dwIndex); // // Zero out the memory holding the password, now we have finished // with it. // SecureZeroMemory(pszPassword, wcslen(pszPassword) * sizeof(WCHAR)); if (SUCCEEDED(hr)) { m_dwRefCount++; m_pszServer = AllocADsStr(pszServer); } else // Don't set m_pszServer, since we didn't bind. m_dwIndex = (DWORD) -1; } else { if (_wcsicmp(m_pszServer, pszServer) == 0) m_dwRefCount++; else // // Don't rebind to another server. Let the caller do it // explicitly, if desired. // hr = dwRebindErr; } error: if (pszPassword) FreeADsStr(pszPassword); RRETURN(hr); } //+--------------------------------------------------------------------------- // // CCred::deref // // Removes a reference from this credential object. When the reference count // drops to zero, it unbinds from the associated server and deletes itself. // After the caller calls deref(), it shouldn't touch this object ever again. // // Returns: // S_OK - deref occurred okay. // Other error codes resulting from WNetCancelConnection2. // //---------------------------------------------------------------------------- HRESULT CCred::deref(void) { HRESULT hr = S_OK; ADsAssert(m_dwRefCount > 0); m_dwRefCount--; if (m_dwRefCount == 0) { hr = g_CredTable.DelCred(m_dwIndex); // Reset the index and free server to play extra safe m_dwIndex = (DWORD) -1; if (m_pszServer) { FreeADsStr(m_pszServer); m_pszServer = NULL; } #if DBG if (hr == E_INVALIDARG) ADsAssert(FALSE && "Invalid table index in CCred::deref()!"); #endif } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CCred::GetUserName // // Retrieves the username represented by this credentials object. // // Arguments: // [ppszUserName] - address of a PWSTR to receive a // pointer to the username. // Returns: // S_OK - on success // E_OUTOFMEMORY - if we run out of memory. // //---------------------------------------------------------------------------- HRESULT CCred::GetUserName(PWSTR *ppszUserName) { if (!m_pszUserName) *ppszUserName = NULL; else { *ppszUserName = AllocADsStr(m_pszUserName); if (!*ppszUserName) RRETURN(E_OUTOFMEMORY); } RRETURN(S_OK); } //+--------------------------------------------------------------------------- // // CCred::GetPassword // // Retrieves the password represented by this credentials object. // // Arguments: // [ppszPassword] - address of a PWSTR to receive a // pointer to the password. // Returns: // S_OK - on success // E_OUTOFMEMORY - if we run out of memory. // //---------------------------------------------------------------------------- HRESULT CCred::GetPassword(PWSTR * ppszPassword) { UNICODE_STRING Password; PWSTR pTempPassword = NULL; UCHAR Seed = NW_ENCODE_SEED3; Password.Length = 0; if (!m_pszPassword) *ppszPassword = NULL; else { pTempPassword = (PWSTR) AllocADsMem(m_dwPasswdLen); if (!pTempPassword) RRETURN(E_OUTOFMEMORY); memcpy(pTempPassword, m_pszPassword, m_dwPasswdLen); if(NULL == g_pRtlDecryptMemory) { RtlInitUnicodeString(&Password, pTempPassword); RtlRunDecodeUnicodeString(Seed, &Password); } else { NTSTATUS ntStatus = 0; ntStatus = g_pRtlDecryptMemory(pTempPassword, m_dwPasswdLen, 0); if(ntStatus != STATUS_SUCCESS) RRETURN(E_FAIL); } *ppszPassword = pTempPassword; } RRETURN(S_OK); } ///--------------------------------------------------------------------------- // ____ ____ _ _____ _ _ // / ___/ ___|_ __ ___ __| |_ _|_ _| |__ | | ___ // | | | | | '__/ _ \/ _` | | |/ _` | '_ \| |/ _ \ // | |__| |___| | | __/ (_| | | | (_| | |_) | | __/ definitions // \____\____|_| \___|\__,_| |_|\__,_|_.__/|_|\___| // ///--------------------------------------------------------------------------- //+--------------------------------------------------------------------------- // // CCredTable constructor // // Creates an empty CCredTable. // //---------------------------------------------------------------------------- CCredTable::CCredTable() : m_pCredentials(NULL), m_dwAlloc(0), m_dwUsed(0) { } //+--------------------------------------------------------------------------- // // CCredTable destructor // // Destroys the CCredTable. If there are entries still in use at dtor // time, it will print a debug message. (Maybe it should assert?) // //---------------------------------------------------------------------------- CCredTable::~CCredTable() { for (DWORD dw = 0; dw < m_dwUsed; ++dw) { if (m_pCredentials[dw].m_bUsed) { // the share name could be up to MAX_PATH. #if 0 WCHAR pszMessage[64 + MAX_PATH]; wsprintf(pszMessage, TEXT("Credential %d (\"%s\") not free!"), dw, m_pCredentials[dw].m_pResource); OutputDebugString(pszMessage); #endif } // // Try to cancel the connection, so we don't have lots left // lying around, but don't complain if we can't disconnect. // DelCred(dw); } if (m_pCredentials) FreeADsMem(m_pCredentials); } //+--------------------------------------------------------------------------- // // CCredTable::AddCred // // Tries to get credentials for a server's "IPC$" resource. If the // credentials are gained, an entry is added to the resource table. // The "index" returned allows the caller to delete the resource // when it's done with it. // // Arguments: // [pszUserName] - username to use // [pszPassword] - password to use // [pszServer] - server to connect to // [pdwIndex] - address of a DWORD to receive // the table index of this resource. // Returns: // S_OK - if we bound to the server. // E_OUTOFMEMORY - if we run out of memory. // Other error codes resulting from WNetAddConnection2. // //---------------------------------------------------------------------------- HRESULT CCredTable::AddCred(PWSTR pszUserName, PWSTR pszPassword, PWSTR pszServer, DWORD *pdwIndex) { HRESULT hr = S_OK; BOOL fAlreadyInTable = FALSE; DWORD dwCtr = 0; NET_API_STATUS nasStatus = 0; USE_INFO_1 *pUseInfo = NULL; BOOL fConnectionAdded = FALSE; BOOL fInCritSect = FALSE; *pdwIndex = (DWORD) -1; // // Open a connection to IPC$ on the server. // NETRESOURCE NetResource; memset(&NetResource, 0, sizeof(NETRESOURCE)); NetResource.dwType = RESOURCETYPE_ANY; NetResource.lpLocalName = NULL; NetResource.lpProvider = NULL; WCHAR RemoteName[MAX_PATH]; if( (wcslen(pszServer) + wcslen(g_pszResourceName) + 4) > MAX_PATH) { BAIL_ON_FAILURE(hr = E_INVALIDARG); } wsprintf(RemoteName, TEXT("\\\\%ls\\%ls"), pszServer, g_pszResourceName); NetResource.lpRemoteName = RemoteName; // // WNetAddConnection2 ignores the other members of NETRESOURCE. // DWORD dwResult; dwResult = WNetAddConnection2(&NetResource, pszPassword, pszUserName, 0); BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwResult)); fConnectionAdded = TRUE; m_cs.Lock(); fInCritSect = TRUE; // // At this point, we know that the NetUse call succeeded. // We are not going to see if we need to add this to the // table or not. If we already have a net use to the same // resource then we need not add this to the table and // instead we should bump up the refCount and return the // index of the already stored resource. // for (dwCtr = 0; (dwCtr < m_dwUsed) && !fAlreadyInTable; dwCtr++) { if (m_pCredentials[dwCtr].m_bUsed && m_pCredentials[dwCtr].m_pResource) { #ifdef WIN95 if (_wcsicmp( m_pCredentials[dwCtr].m_pResource, RemoteName ) == 0 ) { #else if (CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, m_pCredentials[dwCtr].m_pResource, -1, RemoteName, -1 ) == CSTR_EQUAL ) { #endif *pdwIndex = dwCtr; fAlreadyInTable = TRUE; m_pCredentials[dwCtr].m_dwCount++; } } } // // Index will not be -1 if we found a match in the table. // if (!fAlreadyInTable) { if (m_dwUsed == m_dwAlloc) hr = GrowTable(); BAIL_ON_FAILURE(hr); ADsAssert(m_dwUsed < m_dwAlloc); m_pCredentials[m_dwUsed].m_pResource = AllocADsStr(RemoteName); if (!m_pCredentials[m_dwUsed].m_pResource) BAIL_ON_FAILURE(hr = E_OUTOFMEMORY); m_pCredentials[m_dwUsed].m_bUsed = TRUE; m_pCredentials[m_dwUsed].m_dwCount = 1; // // check to see if there was already a net use connection existing at // the time WNetAddConnection2 was called. // nasStatus = NetUseGetInfo( NULL, RemoteName, 1, // level (LPBYTE *) &pUseInfo ); BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus)); ADsAssert(pUseInfo != NULL); if(pUseInfo->ui1_usecount == 1) { // only this process has an open connection m_pCredentials[m_dwUsed].m_fAlreadyConnected = FALSE; } else { m_pCredentials[m_dwUsed].m_fAlreadyConnected = TRUE; } // do this last thing. *pdwIndex = m_dwUsed++; } m_cs.Unlock(); fInCritSect = FALSE; if(pUseInfo != NULL) NetApiBufferFree(pUseInfo); RRETURN(hr); error: if (m_dwUsed != m_dwAlloc && m_pCredentials[m_dwUsed].m_pResource != NULL) { FreeADsStr(m_pCredentials[m_dwUsed].m_pResource); m_pCredentials[m_dwUsed].m_pResource = NULL; } if (fInCritSect) m_cs.Unlock(); if (fConnectionAdded) (void) WNetCancelConnection2(RemoteName, 0, FALSE); if(pUseInfo != NULL) NetApiBufferFree(pUseInfo); RRETURN(hr); } //+--------------------------------------------------------------------------- // // CCredTable::DelCred // // Disconnects from the "ADMIN$" resource specified by the table entry // with index "dwIndex". // // Arguments: // [DWORD dwIndex] - index of table entry to delete // // Returns: // S_OK - deref occurred okay. // E_INVALIDARG - the table index is invalid. // Other error codes resulting from WNetCancelConnection2. // //---------------------------------------------------------------------------- HRESULT CCredTable::DelCred(DWORD dwIndex) { HRESULT hr = S_OK; DWORD dwResult; m_cs.Lock(); if (((LONG)dwIndex) < 0 || dwIndex >= m_dwUsed) hr = E_INVALIDARG; else if (m_pCredentials[dwIndex].m_bUsed == FALSE) hr = S_OK; else { ADsAssert(m_pCredentials[dwIndex].m_dwCount); // // Delete only if the refCount is zero. // if (--m_pCredentials[dwIndex].m_dwCount == 0) { // // cancel connection only if if it was not already present at the // time we did WNetAddConnection2 // if(m_pCredentials[dwIndex].m_fAlreadyConnected == FALSE) { dwResult = WNetCancelConnection2( m_pCredentials[dwIndex].m_pResource, 0, FALSE); BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(dwResult)); } FreeADsStr(m_pCredentials[dwIndex].m_pResource); m_pCredentials[dwIndex].m_pResource = NULL; m_pCredentials[dwIndex].m_bUsed = FALSE; m_pCredentials[dwIndex].m_dwCount = 0; m_pCredentials[dwIndex].m_fAlreadyConnected = FALSE; } else { hr = S_OK; } } error: m_cs.Unlock(); RRETURN(hr); } //+--------------------------------------------------------------------------- // // CCredTable::GrowTable // // Increase the size of the CredTable by a fixed amount. Private method. // // Returns: // S_OK - deref occurred okay. // E_OUTOFMEMORY - we ran out of memory. // //---------------------------------------------------------------------------- HRESULT CCredTable::GrowTable(void) { ADsAssert(m_cs.Locked()); cred *pCredentials = (cred *)ReallocADsMem(m_pCredentials, m_dwAlloc * sizeof(cred), (m_dwAlloc + 10) * sizeof(cred)); if (!pCredentials) RRETURN(E_OUTOFMEMORY); m_pCredentials = pCredentials; for (DWORD dw = m_dwAlloc; dw < m_dwAlloc + 10; dw++) { m_pCredentials[dw].m_bUsed = FALSE; m_pCredentials[dw].m_pResource = NULL; m_pCredentials[dw].m_dwCount = 0; m_pCredentials[dw].m_fAlreadyConnected = FALSE; } m_dwAlloc += 10; RRETURN(S_OK); } ////////////////////////////////////////////////////////////////////////////// // _____ ___ _ _ _____ ___ _ _ _ _ // / __\ \ / (_)_ _ | \| |_ _/ __|_ _ ___ __| |___ _ _| |_(_)__ _| |___ // | (__ \ \/\/ /| | ' \| .` | | || (__| '_/ -_) _` / -_) ' \ _| / _` | (_-< // \___| \_/\_/ |_|_||_|_|\_| |_| \___|_| \___\__,_\___|_||_\__|_\__,_|_/__/ // definitions // ////////////////////////////////////////////////////////////////////////////// //+--------------------------------------------------------------------------- // // CWinNTCredentials constructor // // Creates an empty CWinNTCredentials object. // //---------------------------------------------------------------------------- CWinNTCredentials::CWinNTCredentials(): m_cRefAdded(0), m_pCred(NULL), m_dwFlags(0) { } //+--------------------------------------------------------------------------- // // CWinNTCredentials constructor // // Creates a CWinNTCredentials object for a given username/password. // // Arguments: // [pszUserName] - username // [pszPassword] - password // //---------------------------------------------------------------------------- CWinNTCredentials::CWinNTCredentials(PWSTR pszUserName, PWSTR pszPassword, DWORD dwFlags) : m_cRefAdded(0), m_pCred(NULL), m_dwFlags(dwFlags) { // // If both username and password are NULL or "", don't create a cred. // if ((pszUserName && *pszUserName) || (pszPassword && *pszPassword)) m_pCred = new CCred(pszUserName, pszPassword); } //+--------------------------------------------------------------------------- // // CWinNTCredentials copy constructor // // Copies a CWinNTCredentials object from another. // This sets the "referenced" flag to FALSE, and doesn't increase the // reference count. That should be done explicitly with ref(). // // Arguments: // [other] - credentials to copy // //---------------------------------------------------------------------------- CWinNTCredentials::CWinNTCredentials(const CWinNTCredentials& other) : m_cRefAdded(0), m_pCred(other.m_pCred), m_dwFlags(other.m_dwFlags) { } //+--------------------------------------------------------------------------- // // CWinNTCredentials destructor // // Dereferences the credentials. If the reference count drops to zero, // the internal refcounted credentials object goes away. // //---------------------------------------------------------------------------- CWinNTCredentials::~CWinNTCredentials() { Clear_pCredObject(); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::Clear_pCredObject // // Dereferences the credentials. If the reference count drops to zero, // the internal refcounted credentials object goes away. // This is a private member function as this needs to be called // in different places and therefore the destructor is not the // right place - AjayR 6-25-98. // //---------------------------------------------------------------------------- void CWinNTCredentials::Clear_pCredObject() { if (m_cRefAdded) { m_pCred->deref(); m_cRefAdded--; } if (m_pCred) { m_pCred->m_dwUsageCount--; if (m_pCred->m_dwUsageCount == 0) { delete m_pCred; m_pCred = NULL; } } } //+--------------------------------------------------------------------------- // // CWinNTCredentials copy operator // // Copies a CWinNTCredentials object from another. This dereferences // the old object, and doesn't increase the reference count of the // new object. That should be done explicitly with ref(). // // Arguments: // [other] - credentials to copy // //---------------------------------------------------------------------------- const CWinNTCredentials& CWinNTCredentials::operator=(const CWinNTCredentials& other) { if (&other != this) { // Clean up the current m_pCred Clear_pCredObject(); m_dwFlags = other.m_dwFlags; m_pCred = other.m_pCred; if (m_pCred) { m_pCred->m_dwUsageCount++; } m_cRefAdded = 0; // Don't addref here. } return *this; } //+--------------------------------------------------------------------------- // // CWinNTCredentials::RefServer // // Increments the credentials object's reference count, and if necessary, // attempts to connect to the server's "ADMIN$" resource. // // Arguments: // [pszServer] - server to establish credentials with // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::RefServer(PWSTR pszServer, BOOL fAllowRebinding) { HRESULT hr = S_OK; if (m_pCred) { ADsAssert(pszServer && *pszServer); hr = m_pCred->ref(pszServer); // // We usually don't want to allow rebinding, to catch coding mistakes. // The only time we want to is when we open a Computer object from a // Domain, which has been opened via OpenDSObject. // if (hr == dwRebindErr && fAllowRebinding) { // Copy the username and password, and try again. CCred * pCCred = new CCred(*m_pCred); // clear the m_pCred object Clear_pCredObject(); // // assign the m_pCred object to the copy and try // and rebind if the new CCred object is not null // m_pCred = pCCred; // // m_cRefAdded is this CWinNTCredentials object's contribution // to the refcount of m_pCred. Since we have a new CCred object, // set m_cRefAdded to 0. // m_cRefAdded = 0; if (m_pCred) hr = m_pCred->ref(pszServer); else hr = E_OUTOFMEMORY; } if (SUCCEEDED(hr)) m_cRefAdded++; } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::DeRefServer // // Call this only in special cases, when you know that the credentials // object is being passed around will have to RefServer/RefDomain // more than once as we are in the process of validating/finding // the object as opposed to actually creating the adsi object. // AjayR added on 6-24-98. // // Arguments: // [pszServer] - server to deref // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::DeRefServer() { HRESULT hr = S_OK; if (m_pCred && m_cRefAdded) { hr = m_pCred->deref(); m_cRefAdded--; } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::RefDomain // // Increments the credentials object's reference count, and if necessary, // attempts to connect to the server's "ADMIN$" resource. // // Arguments: // [pszDomain] - domain to establish credentials with // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::RefDomain(PWSTR pszDomain) { HRESULT hr = S_OK; // Don't take the hit of WinNTGetCachedDCName if we have null creds. if (m_pCred) { WCHAR szDCName[MAX_PATH]; ADsAssert(pszDomain && *pszDomain); hr = WinNTGetCachedDCName(pszDomain, szDCName, m_dwFlags); if (SUCCEEDED(hr)) // +2 for the initial "\\" hr = RefServer(szDCName + 2); } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::DeRefDomain // // Call this only in special cases, when you know that the credentials // object is being passed around will have to RefServer/RefDomain // more than once as we are in the process of validating/finding // the object as opposed to actually creating the adsi object. // AjayR added on 6-24-98. // // Arguments: // [pszServer] - server to deref // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::DeRefDomain() { HRESULT hr = S_OK; // // Call DeRefServer - since we just want to whack the ref // hr = DeRefServer(); RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::Ref // // Increments the credentials object's reference count, and if necessary, // attempts to connect to the server's "ADMIN$" resource. // // This takes both a server and a domain; since several objects are created // with both server and domain as arguments (which one is used depends on // what the object's ADs parent is), this is a commonly used bit of code. // // Arguments: // [pszServer] - server to bind to // [pszDomain] - domain of the PDC to bind to // [dwType] - WINNT_DOMAIN_ID or WINNT_COMPUTER_ID // // Returns: // S_OK - if we bound to the server, or are already bound to // the given server. // E_FAIL - if this object is bound, and the specified server // is not the same server as we are bound to. // E_OUTOFMEMORY - if we run out of memory. // Other error codes resulting from WNetAddConnection2 and from // WinNTGetCachedDCName. // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::Ref(PWSTR pszServer, PWSTR pszDomain, DWORD dwType) { HRESULT hr = S_OK; ADsAssert(dwType == WINNT_DOMAIN_ID || dwType == WINNT_COMPUTER_ID); // Don't take the hit of WinNTGetCachedDCName if we have null creds. if (m_pCred) { if (dwType == WINNT_DOMAIN_ID) hr = RefDomain(pszDomain); else hr = RefServer(pszServer); } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::GetUserName // // Retrieves the username represented by this credentials object. // // Arguments: // [ppszUserName] - address of a PWSTR to receive a // pointer to the username. // Returns: // S_OK - on success // E_OUTOFMEMORY - if we run out of memory. // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::GetUserName(PWSTR *ppszUserName) { HRESULT hr; if (!ppszUserName) RRETURN(E_ADS_BAD_PARAMETER); // // Based on the rest of the codes, if UserName & Password are both "", // no CCred is created & m_pCred = NULL. (See Constructor). Before we // can hit CCred::GetUserName and get back *ppszUserName=NULL with hr = // S_OK, we will have AV already. So need to check if m_pCred 1st. // if (m_pCred) { hr = m_pCred->GetUserName(ppszUserName); } else { *ppszUserName = NULL; hr = S_OK; } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::GetPassword // // Retrieves the password represented by this credentials object. // // Arguments: // [ppszPassword] - address of a PWSTR to receive a // pointer to the password. // Returns: // S_OK - on success // E_OUTOFMEMORY - if we run out of memory. // //---------------------------------------------------------------------------- HRESULT CWinNTCredentials::GetPassword(PWSTR * ppszPassword) { HRESULT hr; if (!ppszPassword) RRETURN(E_ADS_BAD_PARAMETER); // // Based on the rest of the codes, if UserName & Password are both "", // no CCred is created & m_pCred = NULL. (See Constructor). Before we // can hit CCred::GetUserName and get back *ppszPassword=NULL with hr = // S_OK, we will have AV already. So need to check if m_pCred 1st. // if (m_pCred) { hr = m_pCred->GetPassword(ppszPassword); } else { *ppszPassword = NULL; hr = S_OK; } RRETURN(hr); } //+--------------------------------------------------------------------------- // // CWinNTCredentials::Bound // // Returns TRUE iff this object has a reference to a server. // //---------------------------------------------------------------------------- BOOL CWinNTCredentials::Bound() { RRETURN(m_cRefAdded != 0); } void CWinNTCredentials::SetFlags(DWORD dwFlags) { m_dwFlags = dwFlags; } DWORD CWinNTCredentials::GetFlags() const { RRETURN(m_dwFlags); } void CWinNTCredentials::SetUmiFlag(void) { m_dwFlags |= ADS_AUTH_RESERVED; } void CWinNTCredentials::ResetUmiFlag(void) { m_dwFlags &= (~ADS_AUTH_RESERVED); }