windows-nt/Source/XPSP1/NT/ds/adsi/winnt/cdomain.cxx
2020-09-26 16:20:57 +08:00

1177 lines
25 KiB
C++

//---------------------------------------------------------------------------
//
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995
//
// File: cdomain.cxx
//
// Contents: Windows NT 3.5
//
//
// History: 01-30-95 krishnag Created.
//
//----------------------------------------------------------------------------
#include "winnt.hxx"
#pragma hdrstop
DECLARE_INFOLEVEL( Domain );
DECLARE_DEBUG( Domain );
#define DomainDebugOut(x) DomainInlineDebugOut x
// Class CWinNTDomain
DEFINE_IDispatch_ExtMgr_Implementation(CWinNTDomain)
DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTDomain)
DEFINE_IADs_TempImplementation(CWinNTDomain)
DEFINE_IADs_PutGetImplementation(CWinNTDomain, DomainClass, gdwDomainTableSize)
DEFINE_IADsPropertyList_Implementation(CWinNTDomain, DomainClass, gdwDomainTableSize)
HRESULT
MoveUserGroupObject(
THIS_ BSTR SourceName,
BSTR NewName,
BSTR bstrParentADsPath,
CWinNTCredentials& Credentials,
IDispatch * FAR* ppObject
);
CWinNTDomain::CWinNTDomain() :
_pDispMgr(NULL),
_pExtMgr(NULL),
_pPropertyCache(NULL)
{
VariantInit(&_vFilter);
ENLIST_TRACKING(CWinNTDomain);
}
HRESULT
CWinNTDomain::CreateDomain(
BSTR Parent,
BSTR DomainName,
DWORD dwObjectState,
REFIID riid,
CWinNTCredentials& Credentials,
void **ppvObj
)
{
CWinNTDomain FAR * pDomain = NULL;
NET_API_STATUS nasStatus;
HRESULT hr = S_OK;
hr = AllocateDomainObject(&pDomain);
BAIL_ON_FAILURE(hr);
ADsAssert(pDomain->_pDispMgr);
hr = pDomain->InitializeCoreObject(
Parent,
DomainName,
DOMAIN_CLASS_NAME,
DOMAIN_SCHEMA_NAME,
CLSID_WinNTDomain,
dwObjectState
);
BAIL_ON_FAILURE(hr);
pDomain->_Credentials = Credentials;
hr = pDomain->_Credentials.RefDomain(DomainName);
BAIL_ON_FAILURE(hr);
//
// Load ext mgr and extensions
//
hr = ADSILoadExtensionManager(
DOMAIN_CLASS_NAME,
(IADsDomain *) pDomain,
pDomain->_pDispMgr,
Credentials,
&pDomain->_pExtMgr
);
BAIL_ON_FAILURE(hr);
ADsAssert(pDomain->_pExtMgr);
// 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(1 == pDomain->_dwNumComponents)
pDomain->_CompClasses[0] = L"Domain";
else
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = pDomain->InitUmiObject(
pDomain->_Credentials,
DomainClass,
gdwDomainTableSize,
pDomain->_pPropertyCache,
(IUnknown *) (INonDelegatingUnknown *) pDomain,
pDomain->_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 = pDomain->QueryInterface(riid, ppvObj);
BAIL_ON_FAILURE(hr);
pDomain->Release();
RRETURN(hr);
error:
delete pDomain;
RRETURN_EXP_IF_ERR(hr);
}
CWinNTDomain::~CWinNTDomain( )
{
VariantClear(&_vFilter);
delete _pExtMgr; // created last, destroyed first
delete _pDispMgr;
delete _pPropertyCache;
}
//----------------------------------------------------------------------------
// 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 CWinNTDomain::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) CWinNTDomain::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) CWinNTDomain::Release(void)
{
if(_pUnkOuter != NULL)
RRETURN(_pUnkOuter->Release());
RRETURN(NonDelegatingRelease());
}
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTDomain::NonDelegatingQueryInterface(
REFIID iid,
LPVOID FAR* ppv
)
{
HRESULT hr = S_OK;
if (ppv == NULL) {
RRETURN(E_POINTER);
}
if (IsEqualIID(iid, IID_IUnknown))
{
*ppv = (IADsDomain FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsDomain))
{
*ppv = (IADsDomain FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsContainer))
{
*ppv = (IADsContainer FAR *) this;
}
else if (IsEqualIID(iid, IID_IADs))
{
*ppv = (IADs FAR *) this;
}
else if (IsEqualIID(iid, IID_IADsPropertyList))
{
*ppv = (IADsPropertyList FAR *) this;
}
else if (IsEqualIID(iid, IID_IDispatch))
{
*ppv = (IADs 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
CWinNTDomain::InterfaceSupportsErrorInfo(
THIS_ REFIID riid
)
{
if (IsEqualIID(riid, IID_IADs) ||
IsEqualIID(riid, IID_IADsContainer) ||
IsEqualIID(riid, IID_IADsPropertyList) ||
IsEqualIID(riid, IID_IADsDomain)) {
RRETURN(S_OK);
} else {
RRETURN(S_FALSE);
}
}
STDMETHODIMP
CWinNTDomain::SetInfo(THIS)
{
HRESULT hr;
hr = SetInfo(0);
hr = SetInfo(2);
hr = SetInfo(3);
if(SUCCEEDED(hr))
_pPropertyCache->ClearModifiedFlags();
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::GetInfo(THIS)
{
HRESULT hr;
_pPropertyCache->flushpropcache();
hr = GetInfo(0, TRUE);
hr = GetInfo(2, TRUE);
hr = GetInfo(3, TRUE);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::ImplicitGetInfo(THIS)
{
HRESULT hr;
hr = GetInfo(0, FALSE);
hr = GetInfo(2, FALSE);
hr = GetInfo(3, FALSE);
RRETURN_EXP_IF_ERR(hr);
}
/* IADsContainer methods */
STDMETHODIMP
CWinNTDomain::get_Count(long FAR* retval)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CWinNTDomain::get_Filter(THIS_ VARIANT FAR* pVar)
{
HRESULT hr;
VariantInit(pVar);
hr = VariantCopy(pVar, &_vFilter);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::put_Filter(THIS_ VARIANT Var)
{
HRESULT hr;
hr = VariantCopy(&_vFilter, &Var);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::put_Hints(THIS_ VARIANT Var)
{
RRETURN_EXP_IF_ERR( E_NOTIMPL);
}
STDMETHODIMP
CWinNTDomain::get_Hints(THIS_ VARIANT FAR* pVar)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CWinNTDomain::GetObject(
THIS_ BSTR ClassName,
BSTR RelativeName,
IDispatch * FAR* ppObject
)
{
WCHAR szBuffer[MAX_PATH];
DWORD dwLength = 0;
HRESULT hr = S_OK;
if (!RelativeName || !*RelativeName) {
RRETURN_EXP_IF_ERR(E_ADS_UNKNOWN_OBJECT);
}
//
// Verify that the lenght of the string will not cause overflow.
// +2 for / and \0
//
dwLength = wcslen(_ADsPath) + wcslen(RelativeName) + 2;
if (dwLength > MAX_PATH) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
wcscpy(szBuffer, _ADsPath);
wcscat(szBuffer, L"/");
wcscat(szBuffer, RelativeName);
if (ClassName) {
//
// +1 for the ",".
//
dwLength += wcslen(ClassName) + 1;
//
// Check for buffer overflow again.
//
if (dwLength > MAX_PATH) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
wcscat(szBuffer,L",");
wcscat(szBuffer, ClassName);
}
hr = ::GetObject(
szBuffer,
(LPVOID *)ppObject,
_Credentials
);
BAIL_ON_FAILURE(hr);
error:
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::get__NewEnum(
THIS_ IUnknown * FAR* retval
)
{
HRESULT hr;
IUnknown FAR* punkEnum=NULL;
IEnumVARIANT * penum = NULL;
*retval = NULL;
hr = CWinNTDomainEnum::Create(
(CWinNTDomainEnum **)&penum,
_ADsPath,
_Name,
_vFilter,
_Credentials
);
BAIL_ON_FAILURE(hr);
hr = penum->QueryInterface(
IID_IUnknown,
(VOID FAR* FAR*)retval
);
BAIL_ON_FAILURE(hr);
if (penum) {
penum->Release();
}
RRETURN(NOERROR);
error:
if (penum) {
delete penum;
}
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::Create(
THIS_ BSTR ClassName,
BSTR RelativeName,
IDispatch * FAR* ppObject
)
{
ULONG ObjectType = 0;
HRESULT hr;
POBJECTINFO pObjectInfo = NULL;
hr = GetObjectType(
gpFilters,
gdwMaxFilters,
ClassName,
(PDWORD)&ObjectType
);
BAIL_ON_FAILURE(hr);
switch (ObjectType) {
case WINNT_USER_ID:
hr = CWinNTUser::CreateUser(
_ADsPath,
WINNT_DOMAIN_ID,
_Name,
NULL,
RelativeName,
ADS_OBJECT_UNBOUND,
IID_IDispatch,
_Credentials,
(void **)ppObject
);
break;
case WINNT_GROUP_ID:
hr = CWinNTGroup::CreateGroup(
_ADsPath,
WINNT_DOMAIN_ID,
_Name,
NULL,
RelativeName,
WINNT_GROUP_GLOBAL,
ADS_OBJECT_UNBOUND,
IID_IDispatch,
_Credentials,
(void **)ppObject
);
break;
case WINNT_COMPUTER_ID:
hr = CWinNTComputer::CreateComputer(
_ADsPath,
_Name,
RelativeName,
ADS_OBJECT_UNBOUND,
IID_IDispatch,
_Credentials,
(void **)ppObject
);
break;
default:
hr = E_ADS_UNKNOWN_OBJECT;
break;
}
BAIL_ON_FAILURE(hr);
error:
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::Delete(
BSTR bstrClassName,
BSTR bstrSourceName
)
{
ULONG ObjectType = 0;
POBJECTINFO pObjectInfo = NULL;
BOOL fStatus = FALSE;
HRESULT hr = S_OK;
WCHAR szUncServerName[MAX_PATH];
// Make sure input parameters are valid
if (bstrClassName == NULL || bstrSourceName == NULL) {
BAIL_ON_FAILURE(hr = E_ADS_BAD_PARAMETER);
}
hr = GetObjectType(gpFilters,
gdwMaxFilters,
bstrClassName,
(PDWORD)&ObjectType
);
BAIL_ON_FAILURE(hr);
hr = BuildObjectInfo(
_ADsPath,
bstrSourceName,
&pObjectInfo
);
BAIL_ON_FAILURE(hr);
switch (ObjectType) {
case WINNT_USER_ID:
hr = WinNTDeleteUser(pObjectInfo, _Credentials);
break;
case WINNT_GROUP_ID:
//
// for backward compatablity: allow user to delete by classname "group"
//
hr = WinNTDeleteGroup(pObjectInfo, WINNT_GROUP_EITHER, _Credentials);
break;
//
// Global Group and LocalGroup ID's will now goto default
//
case WINNT_COMPUTER_ID:
hr = WinNTDeleteComputer(pObjectInfo, _Credentials);
break;
default:
hr = E_ADS_UNKNOWN_OBJECT;
break;
}
error:
if (pObjectInfo) {
FreeObjectInfo(pObjectInfo);
}
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTDomain::CopyHere(
THIS_ BSTR SourceName,
BSTR NewName,
IDispatch * FAR* ppObject
)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
STDMETHODIMP
CWinNTDomain::MoveHere(
THIS_ BSTR SourceName,
BSTR NewName,
IDispatch * FAR* ppObject
)
{
return MoveUserGroupObject(SourceName,
NewName,
_ADsPath,
_Credentials,
ppObject);
}
/* IADsDomain methods */
STDMETHODIMP
CWinNTDomain::get_IsWorkgroup(THIS_ VARIANT_BOOL FAR* retval)
{
RRETURN_EXP_IF_ERR(E_NOTIMPL);
}
HRESULT
CWinNTDomain::AllocateDomainObject(
CWinNTDomain ** ppDomain
)
{
CWinNTDomain FAR * pDomain = NULL;
CAggregatorDispMgr FAR * pDispMgr = NULL;
CPropertyCache FAR * pPropertyCache = NULL;
HRESULT hr = S_OK;
pDomain = new CWinNTDomain();
if (pDomain == 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_IADsDomain,
(IADsDomain *)pDomain,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(
pDispMgr,
LIBID_ADs,
IID_IADsContainer,
(IADsContainer *)pDomain,
DISPID_NEWENUM
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(
pDispMgr,
LIBID_ADs,
IID_IADsPropertyList,
(IADsPropertyList *)pDomain,
DISPID_VALUE
);
BAIL_ON_FAILURE(hr);
hr = CPropertyCache::createpropertycache(
DomainClass,
gdwDomainTableSize,
(CCoreADsObject *)pDomain,
&pPropertyCache
);
BAIL_ON_FAILURE(hr);
pDispMgr->RegisterPropertyCache(
pPropertyCache
);
pDomain->_pPropertyCache = pPropertyCache;
pDomain->_pDispMgr = pDispMgr;
*ppDomain = pDomain;
RRETURN(hr);
error:
delete pPropertyCache;
delete pDispMgr;
delete pDomain;
RRETURN(hr);
}
STDMETHODIMP
CWinNTDomain::GetInfo(
THIS_ DWORD dwApiLevel,
BOOL fExplicit
)
{
NET_API_STATUS nasStatus;
LPBYTE lpBuffer = NULL;
HRESULT hr;
WCHAR szPDCName[MAX_PATH];
hr = WinNTGetCachedDCName(
_Name,
szPDCName,
_Credentials.GetFlags()
);
BAIL_ON_FAILURE(hr);
nasStatus = NetUserModalsGet(
szPDCName,
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
CWinNTDomain::UnMarshall(
LPBYTE lpBuffer,
DWORD dwApiLevel,
BOOL fExplicit
)
{
HRESULT hr;
ADsAssert(lpBuffer);
switch (dwApiLevel) {
case 0:
hr = UnMarshall_Level0(fExplicit, (LPUSER_MODALS_INFO_0)lpBuffer);
break;
case 2:
hr = UnMarshall_Level2(fExplicit, (LPUSER_MODALS_INFO_2)lpBuffer);
break;
case 3:
hr = UnMarshall_Level3(fExplicit, (LPUSER_MODALS_INFO_3)lpBuffer);
break;
default:
hr = E_FAIL;
}
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
CWinNTDomain::UnMarshall_Level0(
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
);
hr = SetLPTSTRPropertyInCache(
_pPropertyCache,
TEXT("Name"),
_Name,
fExplicit
);
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
CWinNTDomain::UnMarshall_Level2(
BOOL fExplicit,
LPUSER_MODALS_INFO_2 pUserInfo2
)
{
RRETURN(S_OK);
}
HRESULT
CWinNTDomain::UnMarshall_Level3(
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_EXP_IF_ERR(S_OK);
}
STDMETHODIMP
CWinNTDomain::SetInfo(THIS_ DWORD dwApiLevel)
{
NET_API_STATUS nasStatus;
HRESULT hr;
LPBYTE lpBuffer = NULL;
DWORD dwParamErr = 0;
WCHAR szPDCName[MAX_PATH];
hr = WinNTGetCachedDCName(
_Name,
szPDCName,
_Credentials.GetFlags()
);
BAIL_ON_FAILURE(hr);
nasStatus = NetUserModalsGet(
szPDCName,
dwApiLevel,
&lpBuffer
);
hr = HRESULT_FROM_WIN32(nasStatus);
BAIL_ON_FAILURE(hr);
hr = MarshallAndSet(szPDCName, lpBuffer, dwApiLevel);
BAIL_ON_FAILURE(hr);
error:
if (lpBuffer) {
NetApiBufferFree(lpBuffer);
}
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
CWinNTDomain::MarshallAndSet(
LPWSTR szServerName,
LPBYTE lpBuffer,
DWORD dwApiLevel
)
{
ADsAssert(lpBuffer);
switch (dwApiLevel) {
case 0:
RRETURN(Marshall_Set_Level0(
szServerName,
(LPUSER_MODALS_INFO_0)lpBuffer
));
break;
case 2:
RRETURN(Marshall_Set_Level2(
szServerName,
(LPUSER_MODALS_INFO_2)lpBuffer
));
break;
case 3:
RRETURN(Marshall_Set_Level3(
szServerName,
(LPUSER_MODALS_INFO_3)lpBuffer
));
break;
default:
RRETURN(E_FAIL);
}
}
HRESULT
CWinNTDomain::Marshall_Set_Level0(
LPWSTR szServerName,
LPUSER_MODALS_INFO_0 pUserInfo0)
{
NET_API_STATUS nasStatus;
DWORD dwParamErr = 0;
HRESULT hr = S_OK;
DWORD dwMinPasswdLen = 0;
DWORD dwMaxPasswdAge = 0;
DWORD dwMinPasswdAge = 0;
DWORD dwPasswdHistLen = 0;
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("MinPasswordLength"),
&dwMinPasswdLen
);
if (SUCCEEDED(hr)) {
pUserInfo0->usrmod0_min_passwd_len = dwMinPasswdLen;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("MaxPasswordAge"),
&dwMaxPasswdAge
);
if (SUCCEEDED(hr)) {
pUserInfo0->usrmod0_max_passwd_age = dwMaxPasswdAge;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("MinPasswordAge"),
&dwMinPasswdAge
);
if (SUCCEEDED(hr)) {
pUserInfo0->usrmod0_min_passwd_age = dwMinPasswdAge;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("PasswordHistoryLength"),
&dwPasswdHistLen
);
if (SUCCEEDED(hr)) {
pUserInfo0->usrmod0_password_hist_len = dwPasswdHistLen;
}
//
// Now Set this Data. Remember that the property store
// returns to us data in its own format. It is the caller's
// responsibility to free all buffers for bstrs, variants
// etc
//
nasStatus = NetUserModalsSet(
szServerName,
0,
(LPBYTE)pUserInfo0,
&dwParamErr
);
hr = HRESULT_FROM_WIN32(nasStatus);
BAIL_ON_FAILURE(hr);
error:
RRETURN(hr);
}
HRESULT
CWinNTDomain::Marshall_Set_Level2(
LPWSTR szServerName,
LPUSER_MODALS_INFO_2 pUserInfo2
)
{
RRETURN(S_OK);
}
HRESULT
CWinNTDomain::Marshall_Set_Level3(
LPWSTR szServerName,
LPUSER_MODALS_INFO_3 pUserInfo3
)
{
NET_API_STATUS nasStatus;
HRESULT hr;
DWORD dwParamErr = 0;
DWORD dwAutoUnlockIntrvl = 0;
DWORD dwLockoutObsIntrvl = 0;
DWORD dwMaxBadPasswdsAllowed = 0;
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("AutoUnlockInterval"),
&dwAutoUnlockIntrvl
);
if (SUCCEEDED(hr)) {
pUserInfo3->usrmod3_lockout_duration = dwAutoUnlockIntrvl;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("LockoutObservationInterval"),
&dwLockoutObsIntrvl
);
if (SUCCEEDED(hr)) {
pUserInfo3->usrmod3_lockout_observation_window = dwLockoutObsIntrvl;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("MaxBadPasswordsAllowed"),
&dwMaxBadPasswdsAllowed
);
if (SUCCEEDED(hr)) {
pUserInfo3->usrmod3_lockout_threshold = dwMaxBadPasswdsAllowed;
}
//
// Now Set this Data. Remember that the property store
// returns to us data in its own format. It is the caller's
// responsibility to free all buffers for bstrs, variants
// etc
//
nasStatus = NetUserModalsSet(
szServerName,
3,
(LPBYTE)pUserInfo3,
&dwParamErr
);
hr = HRESULT_FROM_WIN32(nasStatus);
BAIL_ON_FAILURE(hr);
error:
RRETURN(hr);
}