|
|
/*++
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); }
|