mirror of https://github.com/tongzx/nt5src
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.
2012 lines
44 KiB
2012 lines
44 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1995
|
|
//
|
|
// File: cuser.cxx
|
|
//
|
|
// Contents: Host user object code
|
|
//
|
|
// History: 11-1-95 krishnag Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "winnt.hxx"
|
|
#pragma hdrstop
|
|
|
|
|
|
// Class CWinNTUser
|
|
|
|
DEFINE_IDispatch_ExtMgr_Implementation(CWinNTUser)
|
|
DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTUser)
|
|
DEFINE_IADs_TempImplementation(CWinNTUser)
|
|
DEFINE_IADs_PutGetImplementation(CWinNTUser,UserClass,gdwUserTableSize)
|
|
DEFINE_IADsPropertyList_Implementation(CWinNTUser,UserClass,gdwUserTableSize)
|
|
|
|
CWinNTUser::CWinNTUser():
|
|
_pDispMgr(NULL),
|
|
_pExtMgr(NULL),
|
|
_pPropertyCache(NULL),
|
|
_ParentType(0),
|
|
_DomainName(NULL),
|
|
_ServerName(NULL),
|
|
_fPasswordSet(FALSE),
|
|
_dwRasPermissions(0),
|
|
_pCCredentialsPwdHolder(NULL),
|
|
_fUseCacheForAcctLocked(TRUE),
|
|
_fComputerAcct(FALSE)
|
|
{
|
|
ENLIST_TRACKING(CWinNTUser);
|
|
}
|
|
|
|
HRESULT
|
|
CWinNTUser::CreateUser(
|
|
BSTR Parent,
|
|
ULONG ParentType,
|
|
BSTR DomainName,
|
|
BSTR ServerName,
|
|
BSTR UserName,
|
|
DWORD dwObjectState,
|
|
DWORD *pdwUserFlags, // OPTIONAL
|
|
LPWSTR szFullName, // OPTIONAL
|
|
LPWSTR szDescription, // OPTIONAL
|
|
PSID pSid, // OPTIONAL
|
|
REFIID riid,
|
|
CWinNTCredentials& Credentials,
|
|
void **ppvObj
|
|
)
|
|
{
|
|
CWinNTUser FAR * pUser = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = AllocateUserObject(&pUser);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
ADsAssert(pUser->_pDispMgr);
|
|
|
|
|
|
hr = pUser->InitializeCoreObject(
|
|
Parent,
|
|
UserName,
|
|
USER_CLASS_NAME,
|
|
USER_SCHEMA_NAME,
|
|
CLSID_WinNTUser,
|
|
dwObjectState
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
pUser->_Credentials = Credentials;
|
|
|
|
//
|
|
// The server name will be NULL only when we create a user
|
|
// by SID - WinNT://S-1-321-231-231. In this case we should
|
|
// not ref the server. Parent type is used as an extra check.
|
|
//
|
|
if (!((ParentType == WINNT_COMPUTER_ID)
|
|
&& !ServerName)) {
|
|
|
|
hr = pUser->_Credentials.Ref(ServerName, DomainName, ParentType);
|
|
if (hr == HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS)) {
|
|
//
|
|
// We had a rebind error.
|
|
// This will happen in the case where the credentials
|
|
// ref the current server which is a bdc, the users is
|
|
// a member of a global group we are going through and
|
|
// we end up trying to ref the PDC when we already have
|
|
// a connection to this comp.
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = ADsAllocString(DomainName, &pUser->_DomainName);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if (ParentType == WINNT_DOMAIN_ID)
|
|
{
|
|
pUser->_ParentType = WINNT_DOMAIN_ID;
|
|
|
|
ADsAssert(DomainName && DomainName[0]!=L'\0');
|
|
}
|
|
else
|
|
{
|
|
pUser->_ParentType = WINNT_COMPUTER_ID;
|
|
hr = ADsAllocString(ServerName, &pUser->_ServerName);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// Load ext mgr and extensions
|
|
//
|
|
|
|
hr = ADSILoadExtensionManager(
|
|
USER_CLASS_NAME,
|
|
(IADsUser *) pUser,
|
|
pUser->_pDispMgr,
|
|
Credentials,
|
|
&pUser->_pExtMgr
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
ADsAssert(pUser->_pExtMgr);
|
|
|
|
//
|
|
// Prepopulate the object
|
|
//
|
|
hr = pUser->Prepopulate(TRUE,
|
|
pdwUserFlags,
|
|
szFullName,
|
|
szDescription,
|
|
pSid);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
// check if the call is from UMI
|
|
if(Credentials.GetFlags() & ADS_AUTH_RESERVED) {
|
|
//
|
|
// we do not pass riid to InitUmiObject below. This is because UMI object
|
|
// does not support IDispatch. There are several places in ADSI code where
|
|
// riid passed into this function is defaulted to IID_IDispatch -
|
|
// IADsContainer::Create for example. To handle these cases, we always
|
|
// request IID_IUnknown from the UMI object. Subsequent code within UMI
|
|
// will QI for the appropriate interface.
|
|
//
|
|
if(3 == pUser->_dwNumComponents) {
|
|
pUser->_CompClasses[0] = L"Domain";
|
|
pUser->_CompClasses[1] = L"Computer";
|
|
pUser->_CompClasses[2] = L"User";
|
|
}
|
|
else if(2 == pUser->_dwNumComponents) {
|
|
if(NULL == DomainName) {
|
|
pUser->_CompClasses[0] = L"Computer";
|
|
pUser->_CompClasses[1] = L"User";
|
|
}
|
|
else if(NULL == ServerName) {
|
|
pUser->_CompClasses[0] = L"Domain";
|
|
pUser->_CompClasses[1] = L"User";
|
|
}
|
|
else
|
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
|
}
|
|
else
|
|
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
|
|
|
|
hr = pUser->InitUmiObject(
|
|
pUser->_Credentials,
|
|
UserClass,
|
|
gdwUserTableSize,
|
|
pUser->_pPropertyCache,
|
|
(IUnknown *) (INonDelegatingUnknown *) pUser,
|
|
pUser->_pExtMgr,
|
|
IID_IUnknown,
|
|
ppvObj
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// UMI object was created and the interface was obtained successfully.
|
|
// UMI object now has a reference to the inner unknown of IADs, since
|
|
// the call to Release() below is not going to be made in this case.
|
|
//
|
|
RRETURN(hr);
|
|
}
|
|
|
|
hr = pUser->QueryInterface(riid, ppvObj);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pUser->Release();
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
delete pUser;
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CWinNTUser::CreateUser(
|
|
BSTR Parent,
|
|
ULONG ParentType,
|
|
BSTR DomainName,
|
|
BSTR ServerName,
|
|
BSTR UserName,
|
|
DWORD dwObjectState,
|
|
REFIID riid,
|
|
CWinNTCredentials& Credentials,
|
|
void **ppvObj
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = CWinNTUser::CreateUser(
|
|
Parent,
|
|
ParentType,
|
|
DomainName,
|
|
ServerName,
|
|
UserName,
|
|
dwObjectState,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
riid,
|
|
Credentials,
|
|
ppvObj
|
|
);
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
CWinNTUser::~CWinNTUser( )
|
|
{
|
|
ADsFreeString(_DomainName);
|
|
ADsFreeString(_ServerName);
|
|
|
|
delete _pExtMgr; // created last, destroyed first
|
|
|
|
delete _pDispMgr;
|
|
|
|
delete _pPropertyCache;
|
|
|
|
if (_pCCredentialsPwdHolder) {
|
|
delete _pCCredentialsPwdHolder;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: QueryInterface
|
|
//
|
|
// Synopsis: If this object is aggregated within another object, then
|
|
// all calls will delegate to the outer object. Otherwise, the
|
|
// non-delegating QI is called
|
|
//
|
|
// Arguments:
|
|
//
|
|
// iid interface requested
|
|
// ppInterface Returns pointer to interface requested. NULL if interface
|
|
// is not supported.
|
|
//
|
|
// Returns: S_OK on success. Error code otherwise.
|
|
//
|
|
// Modifies: *ppInterface to return interface pointer
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP CWinNTUser::QueryInterface(
|
|
REFIID iid,
|
|
LPVOID *ppInterface
|
|
)
|
|
{
|
|
if(_pUnkOuter != NULL)
|
|
RRETURN(_pUnkOuter->QueryInterface(
|
|
iid,
|
|
ppInterface
|
|
));
|
|
|
|
RRETURN(NonDelegatingQueryInterface(
|
|
iid,
|
|
ppInterface
|
|
));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: AddRef
|
|
//
|
|
// Synopsis: IUnknown::AddRef. If this object is aggregated within
|
|
// another, all calls will delegate to the outer object.
|
|
// Otherwise, the non-delegating AddRef is called
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: New reference count
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CWinNTUser::AddRef(void)
|
|
{
|
|
if(_pUnkOuter != NULL)
|
|
RRETURN(_pUnkOuter->AddRef());
|
|
|
|
RRETURN(NonDelegatingAddRef());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function: Release
|
|
//
|
|
// Synopsis: IUnknown::Release. If this object is aggregated within
|
|
// another, all calls will delegate to the outer object.
|
|
// Otherwise, the non-delegating Release is called
|
|
//
|
|
// Arguments:
|
|
//
|
|
// None
|
|
//
|
|
// Returns: New reference count
|
|
//
|
|
// Modifies: Nothing
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CWinNTUser::Release(void)
|
|
{
|
|
if(_pUnkOuter != NULL)
|
|
RRETURN(_pUnkOuter->Release());
|
|
|
|
RRETURN(NonDelegatingRelease());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
STDMETHODIMP
|
|
CWinNTUser::NonDelegatingQueryInterface(
|
|
REFIID iid,
|
|
LPVOID FAR* ppv
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (ppv == NULL) {
|
|
RRETURN(E_POINTER);
|
|
}
|
|
|
|
if (IsEqualIID(iid, IID_IUnknown))
|
|
{
|
|
*ppv = (IADsUser FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_IADsUser))
|
|
{
|
|
*ppv = (IADsUser FAR *) this;
|
|
}
|
|
|
|
else if (IsEqualIID(iid, IID_IADs))
|
|
{
|
|
*ppv = (IADsUser FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_IADsPropertyList))
|
|
{
|
|
*ppv = (IADsPropertyList FAR *) this;
|
|
}
|
|
|
|
else if (IsEqualIID(iid, IID_IDispatch))
|
|
{
|
|
*ppv = (IADsUser FAR *) this;
|
|
}
|
|
else if (IsEqualIID(iid, IID_ISupportErrorInfo))
|
|
{
|
|
*ppv = (ISupportErrorInfo FAR *) this;
|
|
}
|
|
else if( (_pDispatch != NULL) &&
|
|
IsEqualIID(iid, IID_IADsExtension) )
|
|
{
|
|
*ppv = (IADsExtension *) this;
|
|
}
|
|
else if (_pExtMgr)
|
|
{
|
|
RRETURN(_pExtMgr->QueryInterface(iid,ppv));
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
/* ISupportErrorInfo method */
|
|
STDMETHODIMP
|
|
CWinNTUser::InterfaceSupportsErrorInfo(
|
|
THIS_ REFIID riid
|
|
)
|
|
{
|
|
if (IsEqualIID(riid, IID_IADs) ||
|
|
IsEqualIID(riid, IID_IADsPropertyList) ||
|
|
IsEqualIID(riid, IID_IADsUser)) {
|
|
RRETURN(S_OK);
|
|
} else {
|
|
RRETURN(S_FALSE);
|
|
}
|
|
}
|
|
|
|
/* IADs methods */
|
|
|
|
STDMETHODIMP
|
|
CWinNTUser::SetInfo(THIS)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NET_API_STATUS nasStatus;
|
|
WCHAR szPDCName[MAX_PATH];
|
|
WCHAR *pszPassword = NULL;
|
|
WCHAR *pszServerName = _ServerName;
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szPDCName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// + 2 skips the backslashes when calling create
|
|
//
|
|
pszServerName = szPDCName + 2;
|
|
}
|
|
|
|
|
|
if (!_fPasswordSet) {
|
|
|
|
|
|
hr = WinNTCreateUser(
|
|
pszServerName,
|
|
_Name
|
|
);
|
|
|
|
} else {
|
|
|
|
hr = getPrivatePassword(&pszPassword);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = WinNTCreateUser(
|
|
pszServerName,
|
|
_Name,
|
|
pszPassword
|
|
);
|
|
}
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
SetObjectState(ADS_OBJECT_BOUND);
|
|
}
|
|
|
|
|
|
hr = SetInfo(3);
|
|
|
|
if(SUCCEEDED(hr))
|
|
_pPropertyCache->ClearModifiedFlags();
|
|
|
|
error:
|
|
|
|
if (pszPassword) {
|
|
FreeADsStr(pszPassword);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CWinNTUser::GetInfo(THIS)
|
|
{
|
|
HRESULT hr;
|
|
|
|
_pPropertyCache->flushpropcache();
|
|
|
|
// USER_INFO
|
|
//
|
|
|
|
hr = GetInfo(
|
|
3,
|
|
TRUE
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// USER_MODAL_INFO0
|
|
//
|
|
|
|
hr = GetInfo(
|
|
10,
|
|
TRUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// USER_MODAL_INFO3
|
|
//
|
|
|
|
hr = GetInfo(
|
|
13,
|
|
TRUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
if(FALSE == _fComputerAcct) {
|
|
|
|
#ifndef WIN95
|
|
|
|
//
|
|
// Get the RAS permissions. Do this only for user accounts and
|
|
// not for machine accounts.
|
|
//
|
|
//
|
|
hr = GetInfo(21, TRUE);
|
|
BAIL_ON_FAILURE(hr);
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// objectSid. LookupAccountName fails for machine accounts on NT4, but
|
|
// works on Win2K. In order for an explicit GetInfo to succeed against NT4
|
|
// systems we do not check the error code returned below. If this call
|
|
// fails, a subsequent Get("ObjectSid") will return
|
|
// E_ADS_PROPERTY_NOT_FOUND.
|
|
//
|
|
|
|
GetInfo(
|
|
20,
|
|
TRUE
|
|
);
|
|
|
|
error :
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CWinNTUser::ImplicitGetInfo(THIS)
|
|
{
|
|
HRESULT hr;
|
|
|
|
#ifndef WIN95
|
|
|
|
//
|
|
// Get the RAS permissions first
|
|
//
|
|
//
|
|
hr = GetInfo(21, FALSE);
|
|
BAIL_ON_FAILURE(hr);
|
|
#endif
|
|
|
|
// USER_INFO
|
|
//
|
|
|
|
hr = GetInfo(
|
|
3,
|
|
FALSE
|
|
);
|
|
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// USER_MODAL_INFO0
|
|
//
|
|
|
|
hr = GetInfo(
|
|
10,
|
|
FALSE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// USER_MODAL_INFO3
|
|
//
|
|
|
|
hr = GetInfo(
|
|
13,
|
|
FALSE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// objectSid
|
|
//
|
|
|
|
hr = GetInfo(
|
|
20,
|
|
FALSE
|
|
);
|
|
|
|
error :
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::AllocateUserObject(
|
|
CWinNTUser ** ppUser
|
|
)
|
|
{
|
|
CWinNTUser FAR * pUser = NULL;
|
|
CAggregatorDispMgr FAR * pDispMgr = NULL;
|
|
CPropertyCache FAR * pPropertyCache = NULL;
|
|
HRESULT hr = S_OK;
|
|
|
|
pUser = new CWinNTUser();
|
|
if (pUser == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pDispMgr = new CAggregatorDispMgr;
|
|
if (pDispMgr == NULL) {
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LoadTypeInfoEntry(
|
|
pDispMgr,
|
|
LIBID_ADs,
|
|
IID_IADsUser,
|
|
(IADsUser *)pUser,
|
|
DISPID_REGULAR
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = LoadTypeInfoEntry(
|
|
pDispMgr,
|
|
LIBID_ADs,
|
|
IID_IADsPropertyList,
|
|
(IADsPropertyList *)pUser,
|
|
DISPID_VALUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = CPropertyCache::createpropertycache(
|
|
UserClass,
|
|
gdwUserTableSize,
|
|
(CCoreADsObject *)pUser,
|
|
&pPropertyCache
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
pDispMgr->RegisterPropertyCache(
|
|
pPropertyCache
|
|
);
|
|
|
|
|
|
pUser->_pPropertyCache = pPropertyCache;
|
|
pUser->_pDispMgr = pDispMgr;
|
|
*ppUser = pUser;
|
|
|
|
RRETURN(hr);
|
|
|
|
error:
|
|
|
|
delete pDispMgr;
|
|
delete pPropertyCache;
|
|
delete pUser;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
//
|
|
// For current implementation in clocgroup:
|
|
// If this function is called as a public function (ie. by another
|
|
// modual/class), fExplicit must be FALSE since the cache is NOT
|
|
// flushed in this function.
|
|
//
|
|
// External functions should ONLY call GetInfo(no param) for explicit
|
|
// GetInfo. This will flush the cache properly.
|
|
//
|
|
|
|
STDMETHODIMP
|
|
CWinNTUser::GetInfo(
|
|
THIS_ DWORD dwApiLevel,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
switch (dwApiLevel) {
|
|
|
|
// GetInfo(1 or 2, fExplicit) in ADSI codes should be modified
|
|
// to GetInfo(3, fExplicit) to minimize calls on wire.
|
|
|
|
case 3:
|
|
hr = GetStandardInfo(3, fExplicit);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
case 10:
|
|
hr = GetModalInfo(0, fExplicit);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
case 13:
|
|
hr = GetModalInfo(3, fExplicit);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
case 20:
|
|
hr = GetSidInfo(fExplicit);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
|
|
#ifndef WIN95
|
|
case 21:
|
|
hr = GetRasInfo(fExplicit);
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
#endif
|
|
|
|
default:
|
|
RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::GetStandardInfo(
|
|
THIS_ DWORD dwApiLevel,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
NET_API_STATUS nasStatus;
|
|
LPBYTE lpBuffer = NULL;
|
|
HRESULT hr;
|
|
WCHAR szHostServerName[MAX_PATH];
|
|
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
|
|
RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
|
|
}
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szHostServerName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = MakeUncName(
|
|
_ServerName,
|
|
szHostServerName
|
|
);
|
|
}
|
|
|
|
nasStatus = NetUserGetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
dwApiLevel,
|
|
&lpBuffer
|
|
);
|
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = UnMarshall(
|
|
lpBuffer,
|
|
dwApiLevel,
|
|
fExplicit
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
if (lpBuffer) {
|
|
NetApiBufferFree(lpBuffer);
|
|
}
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::UnMarshall(
|
|
LPBYTE lpBuffer,
|
|
DWORD dwApiLevel,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
VARIANT_BOOL fBool;
|
|
BSTR bstrData = NULL;
|
|
LONG lnData = 0L;
|
|
VARIANT vaData;
|
|
DATE daDate = 0;
|
|
|
|
ADsAssert(lpBuffer);
|
|
switch (dwApiLevel) {
|
|
|
|
// GetStandardInfo currently only be called with dwApiLevel=3. If
|
|
// dwApiLevel = 1 or 2 is used, modify ADSI codes to 3.
|
|
|
|
case 3:
|
|
RRETURN(UnMarshall_Level3(fExplicit, (LPUSER_INFO_3)lpBuffer));
|
|
break;
|
|
|
|
default:
|
|
RRETURN(E_FAIL);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::UnMarshall_Level3(
|
|
BOOL fExplicit,
|
|
LPUSER_INFO_3 pUserInfo3
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Begin Account Restrictions Properties
|
|
//
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("UserFlags"),
|
|
pUserInfo3->usri3_flags,
|
|
fExplicit
|
|
);
|
|
|
|
if(SUCCEEDED(hr)) {
|
|
_fUseCacheForAcctLocked = TRUE;
|
|
}
|
|
|
|
if( (pUserInfo3->usri3_flags & UF_WORKSTATION_TRUST_ACCOUNT) ||
|
|
(pUserInfo3->usri3_flags & UF_SERVER_TRUST_ACCOUNT) ||
|
|
(pUserInfo3->usri3_flags & UF_INTERDOMAIN_TRUST_ACCOUNT) ) {
|
|
_fComputerAcct = TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If usri3_acct_expires == TIMEQ_FOREVER, it means we need
|
|
// to ignore the acct expiration date, the account
|
|
// can never expire.
|
|
//
|
|
|
|
if (pUserInfo3->usri3_acct_expires != TIMEQ_FOREVER) {
|
|
|
|
hr = SetDATE70PropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("AccountExpirationDate"),
|
|
pUserInfo3->usri3_acct_expires,
|
|
fExplicit
|
|
);
|
|
|
|
}
|
|
|
|
hr = SetDelimitedStringPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("LoginWorkstations"),
|
|
pUserInfo3->usri3_workstations,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("MaxStorage"),
|
|
pUserInfo3->usri3_max_storage,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("PasswordAge"),
|
|
pUserInfo3->usri3_password_age,
|
|
fExplicit
|
|
);
|
|
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("PasswordExpired"),
|
|
pUserInfo3->usri3_password_expired,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetOctetPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("LoginHours"),
|
|
pUserInfo3->usri3_logon_hours,
|
|
21,
|
|
fExplicit
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Begin Business Info Properties
|
|
//
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("FullName"),
|
|
pUserInfo3->usri3_full_name,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("Description"),
|
|
pUserInfo3->usri3_comment,
|
|
fExplicit
|
|
);
|
|
|
|
//
|
|
// Begin Account Statistics Properties
|
|
//
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("BadPasswordAttempts"),
|
|
pUserInfo3->usri3_bad_pw_count,
|
|
fExplicit
|
|
);
|
|
|
|
//
|
|
// lasg_logon/off == 0 means user never logon/off or logon/off time unknown.
|
|
//
|
|
|
|
if (pUserInfo3->usri3_last_logon!=0) {
|
|
|
|
hr = SetDATE70PropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("LastLogin"),
|
|
pUserInfo3->usri3_last_logon,
|
|
fExplicit
|
|
);
|
|
}
|
|
|
|
|
|
if (pUserInfo3->usri3_last_logoff!=0) {
|
|
|
|
hr = SetDATE70PropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("LastLogoff"),
|
|
pUserInfo3->usri3_last_logoff,
|
|
fExplicit
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Begin Other Info Properties
|
|
//
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("HomeDirectory"),
|
|
pUserInfo3->usri3_home_dir,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("LoginScript"),
|
|
pUserInfo3->usri3_script_path,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("Profile"),
|
|
pUserInfo3->usri3_profile,
|
|
fExplicit
|
|
);
|
|
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("HomeDirDrive"),
|
|
pUserInfo3->usri3_home_dir_drive,
|
|
fExplicit
|
|
);
|
|
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("Parameters"),
|
|
pUserInfo3->usri3_parms,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("PrimaryGroupID"),
|
|
pUserInfo3->usri3_primary_group_id,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("Name"),
|
|
_Name,
|
|
fExplicit
|
|
);
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::Prepopulate(
|
|
BOOL fExplicit,
|
|
DWORD *pdwUserFlags, // OPTIONAL
|
|
LPWSTR szFullName, // OPTIONAL
|
|
LPWSTR szDescription, // OPTIONAL
|
|
PSID pSid // OPTIONAL
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwErr = 0;
|
|
DWORD dwSidLength = 0;
|
|
|
|
//
|
|
// Prepopulate the object with supplied info,
|
|
// if available
|
|
//
|
|
if (pdwUserFlags) {
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("UserFlags"),
|
|
*pdwUserFlags,
|
|
TRUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
//
|
|
// see comment on _fUseCacheForAcctLocked in cuser.hxx
|
|
//
|
|
_fUseCacheForAcctLocked = FALSE;
|
|
}
|
|
|
|
|
|
if (szFullName) {
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("FullName"),
|
|
szFullName,
|
|
TRUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
|
|
if (szDescription) {
|
|
hr = SetLPTSTRPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("Description"),
|
|
szDescription,
|
|
TRUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
if (pSid) {
|
|
|
|
//
|
|
// On NT4 for some reason GetLengthSID does not set lasterror to 0
|
|
//
|
|
SetLastError(NO_ERROR);
|
|
|
|
dwSidLength = GetLengthSid(pSid);
|
|
|
|
//
|
|
// This is an extra check to make sure that we have the
|
|
// correct length.
|
|
//
|
|
dwErr = GetLastError();
|
|
if (dwErr != NO_ERROR) {
|
|
hr = HRESULT_FROM_WIN32(dwErr);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
hr = SetOctetPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("objectSid"),
|
|
(PBYTE) pSid,
|
|
dwSidLength,
|
|
TRUE
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
|
|
}
|
|
|
|
HRESULT
|
|
CWinNTUser::GetSidInfo(
|
|
IN BOOL fExplicit
|
|
)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR szHostServerName[MAX_PATH];
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
|
|
//
|
|
// Get Server Name
|
|
//
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szHostServerName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = MakeUncName(
|
|
_ServerName,
|
|
szHostServerName
|
|
);
|
|
}
|
|
|
|
//
|
|
// Get Sid of this user account and store in cache if fExplicit.
|
|
//
|
|
|
|
hr = GetSidIntoCache(
|
|
szHostServerName,
|
|
_Name,
|
|
_pPropertyCache,
|
|
fExplicit
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::GetRasInfo(
|
|
IN BOOL fExplicit
|
|
)
|
|
{
|
|
#ifdef WIN95
|
|
RRETURN(E_NOTIMPL);
|
|
#else
|
|
HRESULT hr = E_FAIL;
|
|
WCHAR szHostServerName[MAX_PATH];
|
|
RAS_USER_0 RasUser0;
|
|
DWORD nasStatus = 0;
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
|
|
RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
|
|
}
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
|
|
//
|
|
// Get Server Name
|
|
//
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szHostServerName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = MakeUncName(
|
|
_ServerName,
|
|
szHostServerName
|
|
);
|
|
}
|
|
|
|
|
|
//
|
|
// Make Ras call to get permissions.
|
|
//
|
|
nasStatus = RasAdminUserGetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
&RasUser0
|
|
);
|
|
if (nasStatus) {
|
|
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
|
|
}
|
|
|
|
_dwRasPermissions = RasUser0.bfPrivilege;
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("RasPermissions"),
|
|
RasUser0.bfPrivilege,
|
|
fExplicit
|
|
);
|
|
|
|
error:
|
|
|
|
RRETURN(hr);
|
|
#endif
|
|
}
|
|
|
|
HRESULT
|
|
CWinNTUser::SetInfo(THIS_ DWORD dwApiLevel)
|
|
{
|
|
NET_API_STATUS nasStatus;
|
|
HRESULT hr;
|
|
LPBYTE lpBuffer = NULL;
|
|
DWORD dwParamErr = 0;
|
|
WCHAR szHostServerName[MAX_PATH];
|
|
#ifndef WIN95
|
|
RAS_USER_0 RasUser0;
|
|
DWORD dwRasPerms = 0;
|
|
#endif
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szHostServerName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
hr = MakeUncName(
|
|
_ServerName,
|
|
szHostServerName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}
|
|
|
|
#ifndef WIN95
|
|
//
|
|
// Since Ras stuff is the new addition do this first.
|
|
// There is a chance that we may fail after creating the
|
|
// user but I do not see anyway to avoid this.
|
|
// Check to see if the value is set in the cace and only
|
|
// if it is set and is different from the value we have
|
|
// do we try and change it.
|
|
//
|
|
hr = GetDWORDPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("RasPermissions"),
|
|
&dwRasPerms
|
|
);
|
|
|
|
if (SUCCEEDED(hr) && (dwRasPerms != _dwRasPermissions)) {
|
|
//
|
|
// Get the permissions and then set privelege as we
|
|
// do not want to change the callback number param.
|
|
//
|
|
nasStatus = RasAdminUserGetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
&RasUser0
|
|
);
|
|
if (nasStatus) {
|
|
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
|
|
}
|
|
|
|
RasUser0.bfPrivilege = (BYTE) dwRasPerms;
|
|
|
|
nasStatus = RasAdminUserSetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
&RasUser0
|
|
);
|
|
if (nasStatus) {
|
|
BAIL_ON_FAILURE(hr = HRESULT_FROM_WIN32(nasStatus));
|
|
}
|
|
} // Ras info.
|
|
|
|
#endif
|
|
|
|
nasStatus = NetUserGetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
dwApiLevel,
|
|
&lpBuffer
|
|
);
|
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
|
|
hr = MarshallAndSet(szHostServerName, lpBuffer, dwApiLevel);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (lpBuffer) {
|
|
NetApiBufferFree(lpBuffer);
|
|
}
|
|
|
|
|
|
RRETURN_EXP_IF_ERR(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CWinNTUser::MarshallAndSet(
|
|
LPWSTR szHostServerName,
|
|
LPBYTE lpBuffer,
|
|
DWORD dwApiLevel
|
|
)
|
|
{
|
|
ADsAssert(lpBuffer);
|
|
switch (dwApiLevel) {
|
|
|
|
//
|
|
// dwApiLevel = 1 or 2 should change to 3 in caller codes to min
|
|
// calls on wire
|
|
|
|
case 3:
|
|
RRETURN(Marshall_Set_Level3(szHostServerName, (LPUSER_INFO_3)lpBuffer));
|
|
break;
|
|
|
|
//
|
|
// caae 10:
|
|
// case 13:
|
|
// USER_MODAL_INFO should be set at domain level,
|
|
// Not at user level
|
|
//
|
|
|
|
//
|
|
// case 20:
|
|
// objectSid not writable
|
|
//
|
|
|
|
default:
|
|
RRETURN(E_FAIL);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::Marshall_Set_Level3(
|
|
LPWSTR szHostServerName,
|
|
LPUSER_INFO_3 pUserInfo3
|
|
)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DWORD dwFlags = 0;
|
|
DWORD dwAcctExpDate = 0;
|
|
LPWSTR pszDescription = NULL;
|
|
LPWSTR pszFullName = NULL;
|
|
DWORD dwBadPwCount = 0;
|
|
DWORD dwLastLogin = 0;
|
|
DWORD dwLastLogoff = 0;
|
|
LPWSTR pszHomeDir = NULL;
|
|
LPWSTR pszScript = NULL;
|
|
LPWSTR pszProfile = NULL;
|
|
LPWSTR pszLoginWorkstations = NULL;
|
|
DWORD dwMaxStorage = 0;
|
|
LPWSTR pszHomeDirDrive = NULL;
|
|
LPWSTR pszParameters = NULL;
|
|
DWORD dwPrimaryGroupId = 0;
|
|
DWORD dwPasswordExpired = 0;
|
|
OctetString octetString;
|
|
|
|
|
|
DWORD dwParmErr = 0;
|
|
NET_API_STATUS nasStatus;
|
|
|
|
hr = GetDWORDPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("UserFlags"),
|
|
&dwFlags
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_flags = dwFlags;
|
|
}
|
|
|
|
hr = GetDATE70PropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("AccountExpirationDate"),
|
|
&dwAcctExpDate
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
|
|
//
|
|
// Pick an easy to remeber date to represent "account never expires" :
|
|
// 1/1/70 at 0:00. (Range <= 86400 and >= 0xffffffff-86400 is +/- one
|
|
// day from 1/1/70 at 0:00 to take time localization into account.)
|
|
//
|
|
|
|
if (dwAcctExpDate <= 86400 || dwAcctExpDate >= (0xffffffff-86400)) {
|
|
pUserInfo3->usri3_acct_expires = TIMEQ_FOREVER;
|
|
}
|
|
else {
|
|
pUserInfo3->usri3_acct_expires = dwAcctExpDate;
|
|
}
|
|
}
|
|
|
|
hr = GetDWORDPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("PasswordExpired"),
|
|
&dwPasswordExpired
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_password_expired = dwPasswordExpired;
|
|
}
|
|
|
|
hr = GetDWORDPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("MaxStorage"),
|
|
&dwMaxStorage
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_max_storage = dwMaxStorage;
|
|
}
|
|
|
|
hr = GetDelimitedStringPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("LoginWorkstations"),
|
|
&pszLoginWorkstations
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_workstations = pszLoginWorkstations;
|
|
}
|
|
|
|
//
|
|
// Begin Business Information Properties
|
|
//
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("Description"),
|
|
&pszDescription
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_comment = pszDescription;
|
|
}
|
|
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("FullName"),
|
|
&pszFullName
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_full_name = pszFullName;
|
|
}
|
|
|
|
hr = GetOctetPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("LoginHours"),
|
|
&octetString
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
memcpy(pUserInfo3->usri3_logon_hours,
|
|
octetString.pByte,
|
|
octetString.dwSize);
|
|
FreeADsMem(octetString.pByte);
|
|
}
|
|
|
|
|
|
/*
|
|
//
|
|
// Begin Account Statistics Properties - should not be writable.
|
|
//
|
|
|
|
hr = GetDWORDPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("BadPasswordAttempts"),
|
|
&dwBadPwCount
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_bad_pw_count = dwBadPwCount;
|
|
}
|
|
|
|
hr = GetDATE70PropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("LastLogin"),
|
|
&dwLastLogin
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_last_logon = dwLastLogin;
|
|
}
|
|
|
|
hr = GetDATE70PropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("LastLogoff"),
|
|
&dwLastLogoff
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_last_logoff = dwLastLogoff;
|
|
}
|
|
*/
|
|
|
|
//
|
|
// Begin Other Info Properties
|
|
//
|
|
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("HomeDirectory"),
|
|
&pszHomeDir
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_home_dir = pszHomeDir;
|
|
}
|
|
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("LoginScript"),
|
|
&pszScript
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_script_path = pszScript;
|
|
}
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("Profile"),
|
|
&pszProfile
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_profile = pszProfile;
|
|
}
|
|
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("HomeDirDrive"),
|
|
&pszHomeDirDrive
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_home_dir_drive = pszHomeDirDrive;
|
|
}
|
|
|
|
|
|
hr = GetLPTSTRPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("Parameters"),
|
|
&pszParameters
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_parms = pszParameters;
|
|
}
|
|
|
|
hr = GetDWORDPropertyFromCache(
|
|
_pPropertyCache,
|
|
TEXT("PrimaryGroupID"),
|
|
&dwPrimaryGroupId
|
|
);
|
|
if(SUCCEEDED(hr)){
|
|
pUserInfo3->usri3_primary_group_id = dwPrimaryGroupId;
|
|
}
|
|
|
|
//
|
|
// Now perform the Set call.
|
|
//
|
|
|
|
nasStatus = NetUserSetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
3,
|
|
(LPBYTE)pUserInfo3,
|
|
&dwParmErr
|
|
);
|
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
|
|
if (pszDescription) {
|
|
FreeADsStr(pszDescription);
|
|
}
|
|
|
|
if (pszFullName) {
|
|
FreeADsStr(pszFullName);
|
|
}
|
|
|
|
if (pszHomeDir) {
|
|
FreeADsStr(pszHomeDir);
|
|
}
|
|
|
|
if (pszScript) {
|
|
FreeADsStr(pszScript);
|
|
}
|
|
|
|
if (pszProfile) {
|
|
FreeADsStr(pszProfile);
|
|
}
|
|
|
|
if (pszLoginWorkstations) {
|
|
FreeADsStr(pszLoginWorkstations);
|
|
}
|
|
|
|
if (pszParameters) {
|
|
FreeADsStr(pszParameters);
|
|
}
|
|
|
|
if (pszHomeDirDrive) {
|
|
FreeADsStr(pszHomeDirDrive);
|
|
}
|
|
|
|
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::Marshall_Create_Level1(
|
|
LPWSTR szHostServerName,
|
|
LPUSER_INFO_1 pUserInfo1
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NET_API_STATUS nasStatus;
|
|
DWORD dwParmErr;
|
|
|
|
pUserInfo1->usri1_name = _Name;
|
|
pUserInfo1->usri1_password = NULL;
|
|
pUserInfo1->usri1_password_age = DEF_MAX_PWAGE;
|
|
pUserInfo1->usri1_priv = 1;
|
|
pUserInfo1->usri1_home_dir = NULL;
|
|
pUserInfo1->usri1_comment = NULL;
|
|
pUserInfo1->usri1_flags = 0x00000201;
|
|
pUserInfo1->usri1_script_path = NULL;
|
|
|
|
nasStatus = NetUserAdd(
|
|
szHostServerName,
|
|
1,
|
|
(LPBYTE)pUserInfo1,
|
|
&dwParmErr
|
|
);
|
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::GetModalInfo(
|
|
THIS_ DWORD dwApiLevel,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
NET_API_STATUS nasStatus;
|
|
LPBYTE lpBuffer = NULL;
|
|
HRESULT hr;
|
|
WCHAR szPDCName[MAX_PATH];
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szPDCName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = MakeUncName(
|
|
_ServerName,
|
|
szPDCName
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
}
|
|
|
|
nasStatus = NetUserModalsGet(
|
|
szPDCName,
|
|
dwApiLevel,
|
|
&lpBuffer
|
|
);
|
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
hr = UnMarshallModalInfo(lpBuffer, dwApiLevel, fExplicit);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
error:
|
|
if (lpBuffer) {
|
|
NetApiBufferFree(lpBuffer);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::UnMarshallModalInfo(
|
|
LPBYTE lpBuffer,
|
|
DWORD dwApiLevel,
|
|
BOOL fExplicit
|
|
)
|
|
{
|
|
ADsAssert(lpBuffer);
|
|
switch (dwApiLevel) {
|
|
case 0:
|
|
RRETURN(UnMarshall_ModalLevel0(fExplicit, (LPUSER_MODALS_INFO_0)lpBuffer));
|
|
break;
|
|
|
|
case 2:
|
|
RRETURN(UnMarshall_ModalLevel2(fExplicit, (LPUSER_MODALS_INFO_2)lpBuffer));
|
|
break;
|
|
|
|
|
|
case 3:
|
|
RRETURN(UnMarshall_ModalLevel3(fExplicit, (LPUSER_MODALS_INFO_3)lpBuffer));
|
|
break;
|
|
|
|
default:
|
|
RRETURN(E_FAIL);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::UnMarshall_ModalLevel0(
|
|
BOOL fExplicit,
|
|
LPUSER_MODALS_INFO_0 pUserInfo0
|
|
)
|
|
{
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("MinPasswordLength"),
|
|
pUserInfo0->usrmod0_min_passwd_len,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("MaxPasswordAge"),
|
|
pUserInfo0->usrmod0_max_passwd_age,
|
|
fExplicit
|
|
);
|
|
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("MinPasswordAge"),
|
|
pUserInfo0->usrmod0_min_passwd_age,
|
|
fExplicit
|
|
);
|
|
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("PasswordHistoryLength"),
|
|
pUserInfo0->usrmod0_password_hist_len,
|
|
fExplicit
|
|
);
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::UnMarshall_ModalLevel2(
|
|
BOOL fExplicit,
|
|
LPUSER_MODALS_INFO_2 pUserInfo2
|
|
)
|
|
{
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CWinNTUser::UnMarshall_ModalLevel3(
|
|
BOOL fExplicit,
|
|
LPUSER_MODALS_INFO_3 pUserInfo3
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("AutoUnlockInterval"),
|
|
pUserInfo3->usrmod3_lockout_duration,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("LockoutObservationInterval"),
|
|
pUserInfo3->usrmod3_lockout_observation_window,
|
|
fExplicit
|
|
);
|
|
|
|
hr = SetDWORDPropertyInCache(
|
|
_pPropertyCache,
|
|
TEXT("MaxBadPasswordsAllowed"),
|
|
pUserInfo3->usrmod3_lockout_threshold,
|
|
fExplicit
|
|
);
|
|
|
|
RRETURN(S_OK);
|
|
}
|
|
|
|
|
|
//
|
|
// This method is meant to set the password, so that new users
|
|
// can be created, their password set and then SetInfo can be
|
|
// called. This is necessary to allow creation of users when there
|
|
// are restrictions such as passwd should be present.
|
|
//
|
|
HRESULT
|
|
CWinNTUser::setPrivatePassword(
|
|
PWSTR pszNewPassword
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
// CCred safely stores password for us
|
|
if (_pCCredentialsPwdHolder) {
|
|
|
|
hr = _pCCredentialsPwdHolder->SetPassword(pszNewPassword);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
} else
|
|
_pCCredentialsPwdHolder = new CCredentials(NULL, pszNewPassword, 0);
|
|
|
|
if (!_pCCredentialsPwdHolder) {
|
|
hr = E_OUTOFMEMORY;
|
|
} else
|
|
_fPasswordSet = TRUE;
|
|
|
|
error:
|
|
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
//
|
|
// This method is meant to set the password, so that new users
|
|
// can be created, their password set and then SetInfo can be
|
|
// called. This is necessary to allow creation of users when there
|
|
// are restrictions such as passwd should be present.
|
|
//
|
|
HRESULT
|
|
CWinNTUser::getPrivatePassword(
|
|
PWSTR * ppszPassword
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (_pCCredentialsPwdHolder && _fPasswordSet) {
|
|
hr = _pCCredentialsPwdHolder->GetPassword(ppszPassword);
|
|
} else
|
|
hr = E_FAIL;
|
|
|
|
RRETURN(hr);
|
|
}
|
|
|
|
HRESULT
|
|
CWinNTUser::GetUserFlags(
|
|
DWORD *pdwUserFlags
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
NET_API_STATUS nasStatus;
|
|
LPBYTE lpBuffer = NULL;
|
|
WCHAR szHostServerName[MAX_PATH];
|
|
|
|
ADsAssert(pdwUserFlags != NULL);
|
|
|
|
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
|
|
|
|
RRETURN_EXP_IF_ERR(E_ADS_OBJECT_UNBOUND);
|
|
}
|
|
|
|
//
|
|
// objects associated with invalid SIDs have neither a
|
|
// corresponding server nor domain
|
|
//
|
|
if ((!_DomainName) && (!_ServerName)) {
|
|
BAIL_ON_FAILURE(hr = E_ADS_INVALID_USER_OBJECT);
|
|
}
|
|
|
|
if (_ParentType == WINNT_DOMAIN_ID) {
|
|
|
|
hr = WinNTGetCachedDCName(
|
|
_DomainName,
|
|
szHostServerName,
|
|
_Credentials.GetFlags()
|
|
);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
}else {
|
|
|
|
hr = MakeUncName(
|
|
_ServerName,
|
|
szHostServerName
|
|
);
|
|
}
|
|
|
|
nasStatus = NetUserGetInfo(
|
|
szHostServerName,
|
|
_Name,
|
|
3,
|
|
&lpBuffer
|
|
);
|
|
hr = HRESULT_FROM_WIN32(nasStatus);
|
|
BAIL_ON_FAILURE(hr);
|
|
|
|
*pdwUserFlags = ((LPUSER_INFO_3)lpBuffer)->usri3_flags;
|
|
|
|
error:
|
|
if (lpBuffer) {
|
|
NetApiBufferFree(lpBuffer);
|
|
}
|
|
|
|
RRETURN(hr);
|
|
}
|