Windows2003-3790/termsrv/tsuserex/ads.cpp

1956 lines
52 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
ads.cpp
Abstract:
This module implements ADSI extension for Terminal Server User Properties.
Author:
Rashmi Patankar (RashmiP) 10-Aug-2001
Revision History:
--*/
#include "stdafx.h"
#include "ADsTSProps.h"
#include <ntsam.h>
#include <shlwapi.h>
#define MAX_STRING_SIZE 256
#define CTX_USER_PARAM_MAX_SIZE (3 * sizeof(USERCONFIG))
#define PARMS_SIZE 15520
#ifndef RETURN_ON_FAILURE
#define RETURN_ON_FAILURE(expr) { \
HRESULT HiddenHr = expr; if ( !SUCCEEDED(HiddenHr) ) { return HiddenHr; }\
}
#endif
#ifndef BREAK_ON_FAILURE
#define BREAK_ON_FAILURE(x) hr = x; if (!SUCCEEDED(hr)) break
#endif
#define RETURN_ON_INVALID_PARAMETER(x) if(x!=FALSE && x!=TRUE) {return E_ADS_BAD_PARAMETER;}
// Static variables
CComTypeInfoHolder ADsTSUserEx::m_StaticHolder =
{ &__uuidof(IADsTSUserEx), &LIBID_TSUSEREXLib, 1, 0, NULL, 0 };
SERVER_TO_MODE ADsTSUserEx::m_StaticServerMap;
CComPtr<IADsPathname> ADsTSUserEx::m_StaticpPath(NULL);
CComAutoCriticalSection ADsTSUserEx::m_StaticCritSec;
#define INMINUTES 60000
#define MAX_TIME_LIMIT 71580
#define ARRAYSIZE(A) ((sizeof(A))/sizeof(A[0]))
#define NCP_SET 0x02 /* Series of Object ID numbers, each 4
bytes long */
#define WIN_CFGPRESENT L"CfgPresent"
#define CFGPRESENT_VALUE 0xB00B1E55
#define F1MSK_INHERITAUTOLOGON 0x80000000
#define F1MSK_INHERITRESETBROKEN 0x40000000
#define F1MSK_INHERITRECONNECTSAME 0x20000000
#define F1MSK_INHERITINITIALPROGRAM 0x10000000
#define F1MSK_INHERITCALLBACK 0x08000000
#define F1MSK_INHERITCALLBACKNUMBER 0x04000000
#define F1MSK_INHERITSHADOW 0x02000000
#define F1MSK_INHERITMAXSESSIONTIME 0x01000000
#define F1MSK_INHERITMAXDISCONNECTIONTIME 0x00800000
#define F1MSK_INHERITMAXIDLETIME 0x00400000
#define F1MSK_INHERITAUTOCLIENT 0x00200000
#define F1MSK_INHERITSECURITY 0x00100000
#define F1MSK_PROMPTFORPASSWORD 0x00080000
#define F1MSK_RESETBROKEN 0x00040000
#define F1MSK_RECONNECTSAME 0x00020000
#define F1MSK_LOGONDISABLED 0x00010000
#define F1MSK_AUTOCLIENTDRIVES 0x00008000
#define F1MSK_AUTOCLIENTLPTS 0x00004000
#define F1MSK_FORCECLIENTLPTDEF 0x00002000
#define F1MSK_DISABLEENCRYPTION 0x00001000
#define F1MSK_HOMEDIRECTORYMAPROOT 0x00000800
#define F1MSK_USEDEFAULTGINA 0x00000400
#define F1MSK_DISABLECPM 0x00000200
#define F1MSK_DISABLECDM 0x00000100
#define F1MSK_DISABLECCM 0x00000080
#define F1MSK_DISABLELPT 0x00000040
#define F1MSK_DISABLECLIP 0x00000020
#define F1MSK_DISABLEEXE 0x00000010
#define F1MSK_WALLPAPERDISABLED 0x00000008
#define F1MSK_DISABLECAM 0x00000004
#define DEFAULTFLAGS (F1MSK_INHERITAUTOLOGON|F1MSK_INHERITINITIALPROGRAM|F1MSK_INHERITAUTOCLIENT|F1MSK_AUTOCLIENTDRIVES|F1MSK_AUTOCLIENTLPTS|F1MSK_FORCECLIENTLPTDEF|F1MSK_DISABLEENCRYPTION)
#define BAIL_IF_ERROR(hr) if (FAILED(hr)) { goto cleanup; }
namespace
{
const WCHAR OS_VERSION_4[] = L"4.0";
const WCHAR OS_VERSION_5[] = L"5.0";
const WCHAR OS_VERSION_51[] = L"5.1";
const WCHAR LDAP_PREFIX[] = L"LDAP://";
WCHAR LDAP_PARAMETERS_NAME[] = L"UserParameters";
WCHAR WINNT_PARAMETERS_NAME[] = L"Parameters";
WCHAR WIN_WFPROFILEPATH[] = L"WFProfilePath";
WCHAR WIN_WFHOMEDIR[] = L"WFHomeDir";
WCHAR WIN_WFHOMEDIRDRIVE[] = L"WFHomeDirDrive";
WCHAR WIN_NWLOGONSERVER[] = L"NWLogonServer";
WCHAR WIN_SHADOW[] = L"Shadow";
WCHAR WIN_MAXCONNECTIONTIME[] = L"MaxConnectionTime";
WCHAR WIN_MAXDISCONNECTIONTIME[] = L"MaxDisconnectionTime";
WCHAR WIN_MAXIDLETIME[] = L"MaxIdleTime";
WCHAR WIN_FLAGS1[] = L"CfgFlags1";
WCHAR WIN_INITIALPROGRAM[] = L"InitialProgram";
WCHAR WIN_WORKDIRECTORY[] = L"WorkDirectory";
}
typedef struct _USER_PROPERTY {
WCHAR PropertyLength; // length of property name
WCHAR ValueLength; // length of property value
WCHAR PropertyFlag; // type of property (1 = set, 2 = item)
WCHAR Property[1]; // start of property name, followed by value
} USER_PROPERTY, *PUSER_PROPERTY;
//
// This is the structure that maps the beginning of the user's Parameters
// field. It is only separate so that we can do a sizeof() without including
// the first property, which may or may not be there.
//
typedef struct _USER_PROPERTIES_HDR {
WCHAR BacklevelParms[48]; // RAS & Mac data stored here.
WCHAR PropertySignature; // signature that we can look for.
WCHAR PropertyCount; // number of properties present.
} USER_PROPERTIES_HDR, *PUSER_PROPERTIES_HDR;
//
// This structure maps out the whole of the user's Parameters field when
// the user properties structure is present and at least one property is
// defined.
//
typedef struct _USER_PROPERTIES {
USER_PROPERTIES_HDR Header;
USER_PROPERTY FirstProperty;
} USER_PROPERTIES, *PUSER_PROPERTIES;
ADsTSUserEx::ADsTSUserEx()
{
HRESULT hr = NULL;
ITypeLib *pITypeLib = NULL;
m_pTypeInfo = NULL;
m_vbIsLDAP = FALSE;
m_vbUpLevelAllowed = FALSE;
m_pOuterDispatch = NULL;
m_pADs = NULL;
hr = LoadRegTypeLib(LIBID_TSUSEREXLib,
1,
0,
PRIMARYLANGID(GetSystemDefaultLCID()),
&pITypeLib );
if ( SUCCEEDED(hr) )
{
hr = pITypeLib->GetTypeInfoOfGuid( IID_IADsTSUserEx, &m_pTypeInfo);
}
pITypeLib->Release();
}
ADsTSUserEx::~ADsTSUserEx()
{
if ( m_pTypeInfo )
{
m_pTypeInfo->Release();
}
}
/////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP ADsTSUserEx::InterfaceSupportsErrorInfo(REFIID riid) throw()
{
static const IID* arr[] =
{
&__uuidof(IADsTSUserEx),
};
for ( int i=0; i < sizeof(arr)/sizeof(arr[0]); ++i )
{
if (InlineIsEqualGUID(*arr[i],riid))
{
return S_OK;
}
}
return S_FALSE;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::InternalGetLong
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::InternalGetLong(/*in*/ BSTR bstrProperty,
/*out*/ LONG *lpVal) throw()
{
_ASSERT(lpVal);
HRESULT hr = S_OK;
LONG lVal = 0;
LONG UPLength = 0;
TCHAR * pTemp = NULL;
VARIANT Parms;
*lpVal = 0;
VariantInit(&Parms);
if( m_vbIsLDAP )
{
hr = m_pADs->Get(LDAP_PARAMETERS_NAME, &Parms);
}
else
{
hr = m_pADs->Get(WINNT_PARAMETERS_NAME, &Parms);
}
if(ERROR_SUCCESS != hr)
{
hr = S_OK;
goto cleanup;
}
UPLength = (SysStringLen(Parms.bstrVal ) +
CTX_USER_PARAM_MAX_SIZE+1) * sizeof(WCHAR);
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
if( SUCCEEDED(hr) )
{
if(m_vbUpLevelAllowed)
{
NTSTATUS ntstatus = UsrPropGetValue(bstrProperty, &lVal, sizeof(lVal), pTemp);
if( ntstatus == STATUS_SUCCESS )
{
*lpVal = lVal;
}
else if(ntstatus == STATUS_OBJECT_NAME_NOT_FOUND)
{
if(_wcsicmp(bstrProperty, L"Shadow") == 0)
{
*lpVal = 1;
}
}
else
{
hr = E_FAIL;
}
}
}
cleanup:
if(NULL != pTemp)
{
LocalFree(pTemp);
}
VariantClear(&Parms);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// InternalSetValue
//
// Most of the complexity of this dll is here.
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::InternalSetValue(/*[in]*/ WCHAR *wszProperty,
/*[in]*/ LONG lNewVal) throw()
{
HRESULT hr = S_OK;
ULONG UPLength = 0;
TCHAR* pTemp = NULL;
VARIANT Parms;
VARIANT var;
ULONG ulFlags = DEFAULTFLAGS;
ULONG CfgPresent = CFGPRESENT_VALUE;
VariantInit(&var);
///////////////////////////
// If the provider is LDAP
///////////////////////////
if(m_vbUpLevelAllowed)
{
if ( m_vbIsLDAP )
{
hr = m_pADs->Get(LDAP_PARAMETERS_NAME, &Parms);
if( ERROR_SUCCESS != hr )
{
Parms.bstrVal = SysAllocString(L"CtxCfgPresent");
UPLength = PARMS_SIZE;
}
UPLength = (SysStringLen(Parms.bstrVal) +
CTX_USER_PARAM_MAX_SIZE+1) *
sizeof(WCHAR);
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
hr = UsrPropGetValue( WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
pTemp ) ;
if( ERROR_SUCCESS != hr )
{
ulFlags = DEFAULTFLAGS;
UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pTemp,
UPLength );
UsrPropSetValue(WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
FALSE,
pTemp,
UPLength
);
}
hr = UsrPropSetValue(wszProperty,
&lNewVal,
sizeof(lNewVal),
FALSE,
pTemp,
UPLength
);
if( ERROR_SUCCESS != hr )
{
goto cleanup;
}
V_BSTR(&var) = SysAllocString(pTemp);
V_VT(&var) = VT_BSTR;
// Now set the info
hr = m_pADs->Put(LDAP_PARAMETERS_NAME, var);
}
else
{
hr = m_pADs->Get(WINNT_PARAMETERS_NAME, &Parms);
if( ERROR_SUCCESS != hr )
{
goto cleanup;
}
UPLength = (SysStringLen(Parms.bstrVal) +
CTX_USER_PARAM_MAX_SIZE+1) *
sizeof(WCHAR);
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
hr = UsrPropGetValue( WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
pTemp ) ;
if( ERROR_SUCCESS != hr )
{
ulFlags = DEFAULTFLAGS;
UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pTemp,
UPLength );
UsrPropSetValue(WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
FALSE,
pTemp,
UPLength
);
}
hr = UsrPropSetValue(wszProperty,
&lNewVal,
sizeof(lNewVal),
FALSE,
pTemp,
UPLength
);
if( ERROR_SUCCESS != hr )
{
goto cleanup;
}
V_BSTR(&var) = SysAllocString(pTemp);
V_VT(&var) = VT_BSTR;
hr = m_pADs->Put(WINNT_PARAMETERS_NAME, var);
}
}
cleanup:
if(NULL != pTemp)
{
LocalFree(pTemp);
}
VariantClear(&Parms);
VariantClear(&var);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// InternalSetString
//
// Most of the complexity of this dll is here.
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::InternalSetString(/*[in]*/ WCHAR* wszProperty,
/*[in]*/ BSTR bstrNewVal) throw()
{
if ( !bstrNewVal )
{
return E_INVALIDARG;
}
HRESULT hr = S_OK;
BOOL fDefaultValue = 0;
BOOL Update = FALSE;
ULONG UPLength = 0;
TCHAR* pTemp = NULL;
VARIANT Parms;
VARIANT var;
ULONG ulFlags = 0;
ULONG CfgPresent = CFGPRESENT_VALUE;
VariantInit(&var);
///////////////////////////
// If the provider is LDAP
///////////////////////////
if(wszProperty == NULL || (bstrNewVal && SysStringLen(bstrNewVal)> MAX_STRING_SIZE))
{
return E_ADS_BAD_PARAMETER;
}
if ((_wcsicmp(wszProperty, L"InitialProgram") == 0) || (_wcsicmp(wszProperty, L"WorkDirectory") == 0))
{
InternalSetLong(F1MSK_INHERITINITIALPROGRAM, FALSE);
}
if(m_vbUpLevelAllowed)
{
if ( m_vbIsLDAP )
{
hr = m_pADs->Get(LDAP_PARAMETERS_NAME, &Parms);
if( ERROR_SUCCESS != hr )
{
Parms.bstrVal = SysAllocString(L"CtxCfgPresent");
UPLength = PARMS_SIZE;
fDefaultValue = 0;
}
else
{
UPLength = (SysStringLen(Parms.bstrVal) +
CTX_USER_PARAM_MAX_SIZE+1) *
sizeof(WCHAR);
fDefaultValue = (V_BSTR(&Parms)==0) ? 1: 0 ;
}
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
hr = UsrPropGetValue( WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
pTemp ) ;
if( ERROR_SUCCESS != hr )
{
ulFlags = DEFAULTFLAGS;
UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pTemp,
UPLength );
UsrPropSetValue(WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
FALSE,
pTemp,
UPLength
);
}
hr = UsrPropSetString(wszProperty,
bstrNewVal,
pTemp,
UPLength,
fDefaultValue
);
if( ERROR_SUCCESS != hr )
{
goto cleanup;
}
V_BSTR(&var) = SysAllocString(pTemp);
V_VT(&var) = VT_BSTR;
hr = m_pADs->Put(LDAP_PARAMETERS_NAME, var);
}
else
{
hr = m_pADs->Get(WINNT_PARAMETERS_NAME, &Parms);
if( ERROR_SUCCESS != hr )
{
goto cleanup;
}
else
{
UPLength = (SysStringLen(Parms.bstrVal) +
CTX_USER_PARAM_MAX_SIZE+1) *
sizeof(WCHAR);
fDefaultValue = (V_BSTR(&Parms)==0) ? 1: 0 ;
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
hr = UsrPropGetValue( WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
pTemp ) ;
if( ERROR_SUCCESS != hr )
{
ulFlags = DEFAULTFLAGS;
UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pTemp,
UPLength );
UsrPropSetValue(WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
FALSE,
pTemp,
UPLength
);
}
hr = UsrPropSetString(wszProperty,
bstrNewVal,
pTemp,
UPLength,
fDefaultValue
);
}
if( ERROR_SUCCESS != hr )
{
goto cleanup;
}
V_BSTR(&var) = SysAllocString(pTemp);
V_VT(&var) = VT_BSTR;
hr = m_pADs->Put(WINNT_PARAMETERS_NAME, var);
}
}
cleanup:
if(NULL != pTemp)
{
LocalFree(pTemp);
}
VariantClear(&Parms);
VariantClear(&var);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// InternalSetLong
//
// Most of the complexity of this dll is here.
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::InternalSetLong(/*[in]*/ LONG lProperty,
/*[in]*/ LONG lNewVal) throw()
{
HRESULT hr = S_OK;
ULONG ulFlags = 0;
ULONG UPLength = 0;
TCHAR* pTemp = NULL;
VARIANT Parms;
VARIANT var;
VariantInit(&var);
ULONG CfgPresent = CFGPRESENT_VALUE;
///////////////////////////
// If the provider is LDAP
///////////////////////////
if(m_vbUpLevelAllowed)
{
if ( m_vbIsLDAP )
{
hr = m_pADs->Get(LDAP_PARAMETERS_NAME, &Parms);
if( ERROR_SUCCESS != hr )
{
Parms.bstrVal = SysAllocString(L"CtxCfgPresent");
UPLength = PARMS_SIZE;
}
UPLength = (sizeof(V_BSTR(&Parms)) +
CTX_USER_PARAM_MAX_SIZE) *
sizeof(WCHAR);
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
hr = UsrPropGetValue( WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
pTemp ) ;
if( ERROR_SUCCESS != hr )
{
ulFlags = DEFAULTFLAGS;
UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pTemp,
UPLength );
}
if(lNewVal == 0)
{
ulFlags &= (~(lProperty));
}
else
{
ulFlags |= lProperty;
}
hr = UsrPropSetValue(WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
FALSE,
pTemp,
UPLength
);
if( ERROR_SUCCESS != hr )
{
return hr;
}
V_BSTR(&var) = SysAllocString(pTemp);
V_VT(&var) = VT_BSTR;
hr = m_pADs->Put(LDAP_PARAMETERS_NAME, var);
}
else
{
hr = m_pADs->Get(WINNT_PARAMETERS_NAME, &Parms);
if( ERROR_SUCCESS != hr )
{
return hr;
}
UPLength = (sizeof(V_BSTR(&Parms)) +
CTX_USER_PARAM_MAX_SIZE) *
sizeof(WCHAR);
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
hr = UsrPropGetValue( WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
pTemp ) ;
if( ERROR_SUCCESS != hr )
{
ulFlags = DEFAULTFLAGS;
UsrPropSetValue( WIN_CFGPRESENT,
&CfgPresent,
sizeof(CfgPresent),
FALSE,
pTemp,
UPLength );
}
if(lNewVal == 0)
{
ulFlags &= (~(lProperty));
}
else
{
ulFlags |= lProperty;
}
hr = UsrPropSetValue(WIN_FLAGS1,
&ulFlags,
sizeof(ulFlags),
FALSE,
pTemp,
UPLength
);
if( ERROR_SUCCESS != hr )
{
return hr;
}
V_BSTR(&var) = SysAllocString(pTemp);
V_VT(&var) = VT_BSTR;
hr = m_pADs->Put(WINNT_PARAMETERS_NAME, var);
}
}
cleanup:
if(NULL != pTemp)
{
LocalFree(pTemp);
}
VariantClear(&Parms);
VariantClear(&var);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::InternalGetString
//
// Works with
// ProfilePath
// HomeDirectory
// HomeDrive
// WorkDirectory
// InitialProgram
//
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::InternalGetString(/*in*/ BSTR bstrProperty,
/*out*/ BSTR *pbstrVal
) throw()
{
_ASSERT(pbstrVal);
HRESULT hr = S_OK;
TCHAR tchbuf[MAX_STRING_SIZE+1] = L"";
TCHAR* pTemp = NULL;
LONG UPLength = 0;
VARIANT Parms;
*pbstrVal = NULL;
if( m_vbIsLDAP )
{
hr = m_pADs->Get(LDAP_PARAMETERS_NAME, &Parms);
}
else
{
hr = m_pADs->Get(WINNT_PARAMETERS_NAME, &Parms);
}
if( ERROR_SUCCESS == hr )
{
if (m_vbUpLevelAllowed)
{
UPLength = (SysStringLen(Parms.bstrVal) +
CTX_USER_PARAM_MAX_SIZE+1) *
sizeof(WCHAR);
pTemp = (TCHAR*)LocalAlloc(LPTR, UPLength);
if(NULL == pTemp)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
memcpy(pTemp, V_BSTR(&Parms), SysStringLen(Parms.bstrVal)*sizeof(WCHAR));
NTSTATUS ntstatus = UsrPropGetString(bstrProperty,
tchbuf,
sizeof(tchbuf),
pTemp
);
if( ntstatus == STATUS_SUCCESS )
{
*pbstrVal = SysAllocString(tchbuf);
}
else if ( ntstatus != STATUS_OBJECT_NAME_NOT_FOUND )
{
hr = E_FAIL;
}
}
} // else return the error.
if( (hr == E_ADS_PROPERTY_NOT_FOUND) || (hr == DISP_E_MEMBERNOTFOUND) )
{
hr = S_OK;
}
cleanup:
if(NULL != pTemp)
{
LocalFree(pTemp);
}
VariantClear(&Parms);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::GetInfoWinNTComputer
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::GetInfoWinNTComputer(LPWSTR ServerName) throw()
{
// This is a Computer, not a Domain that was used as a string
// now detect if that's a w2k standalone or a NT4
// Get the computer object to see what version of the
// OS is used
CComPtr<IADsComputer> pComputer;
HRESULT hr = S_OK;
LPWSTR pszUserName = NULL;
LPWSTR pszPassword = NULL;
DWORD dwAuthFlags = 0;
CComPtr<IADs> pDomain;
CComBSTR Version;
hr = ADsOpenObject(ServerName,
NULL,
NULL,
0,
__uuidof(IADsComputer),
reinterpret_cast<VOID**> (&pComputer));
BAIL_IF_ERROR(hr);
//Get the OperatingSystemVersion attribute
hr = pComputer->get_OperatingSystemVersion(&Version);
BAIL_IF_ERROR(hr);
LONG lVer = 0;
lVer = _wtol(Version);
if(lVer >= 4)
{
// Not a domain account and NT 5.1: standalone through WinNT
m_vbUpLevelAllowed = VARIANT_TRUE;
}
else
{
hr = E_FAIL;
}
cleanup:
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::GetInfoWinNT
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::GetInfoWinNT(IADsPathname* pPath) throw()
{
if (NULL == pPath)
return E_FAIL;
//////////////////////////////////////////////
// WinNT Provider: retrieve the server's name
//////////////////////////////////////////////
HRESULT hr = S_OK;
LONG NbElements;
CComBSTR Bstr;
RETURN_ON_FAILURE(pPath->GetNumElements( &NbElements ));
RETURN_ON_FAILURE(pPath->GetElement( 1, &Bstr ));
SERVER_TO_MODE::iterator MapIterator;
wstring TempString(Bstr);
MapIterator = m_StaticServerMap.find(TempString);
if ( MapIterator != m_StaticServerMap.end() )
{
// found in the map
m_vbUpLevelAllowed = MapIterator->second;
return hr;
}
CComBSTR ServerName = L"WinNT://";
ServerName.AppendBSTR(Bstr);
/////////////////////////
// Computer (not domain)
/////////////////////////
if ( NbElements == 3 ) // Computer (not domain)
{
hr = GetInfoWinNTComputer(ServerName.m_str);
}
else if ( NbElements == 2 ) // Domain
{
// WinNT Provider
// AND Domain Controller
// => No Upper-Level allowed stop there
hr = GetInfoWinNTComputer(ServerName.m_str);
hr = S_OK;
}
else
{
hr = E_FAIL;
}
m_StaticServerMap.insert(SERVER_TO_MODE::value_type(
TempString,
m_vbUpLevelAllowed
));
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// ExtractDCFromLDAP
//
// String assumed to be like
// "LDAP://DC=ntdev,DC=microsoft,DC=com" string (example)
//////////////////////////////////////////////////////////////////////////////
HRESULT ExtractDCFromLDAP(IADsPathname* pPath, CComBSTR& NewName) throw()
{
if (NULL == pPath)
return E_FAIL;
LONG Count;
RETURN_ON_FAILURE(pPath->GetNumElements(&Count));
NewName = LDAP_PREFIX;
CComBSTR Bstr;
for ( int i = 0; i<Count; ++i )
{
RETURN_ON_FAILURE(pPath->GetElement(i,&Bstr));
WCHAR Header[4];
lstrcpynW(Header,Bstr, 4); // 3 plus \0
if ( lstrcmpiW(Header, L"DC=") == 0 )
{
NewName.AppendBSTR(Bstr);
NewName.Append(L",");
}
Bstr.Empty();
}
NewName[NewName.Length()-1] = L'\0';
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::GetInfoLDAP
//////////////////////////////////////////////////////////////////////////////
HRESULT ADsTSUserEx::GetInfoLDAP(IADsPathname* pPath) throw()
{
if (NULL == pPath)
return E_FAIL;
// LDAP provider
CComBSTR ServerName;
HRESULT hr = S_OK;
DWORD dwAuthFlags = 0;
RETURN_ON_FAILURE(ExtractDCFromLDAP(pPath, ServerName));
SERVER_TO_MODE::iterator MapIterator;
wstring TempString(ServerName);
MapIterator = m_StaticServerMap.find(TempString);
if ( MapIterator != m_StaticServerMap.end() )
{
// found in the map
m_vbUpLevelAllowed = MapIterator->second;
return S_OK;
}
m_vbUpLevelAllowed = VARIANT_TRUE;
m_StaticServerMap.insert(SERVER_TO_MODE::value_type( TempString,
m_vbUpLevelAllowed
));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::Operate
//
// Parameters should be varUserName, varPassword, varAuthFlags. ignored here
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP ADsTSUserEx::Operate(ULONG Code,
VARIANT varData1,
VARIANT varData2,
VARIANT varData3) throw()
{
HRESULT hr = S_OK;
switch (Code)
{
case ADS_EXT_INITCREDENTIALS:
{
// Initialize the IADs smart pointer
// (member)
RETURN_ON_FAILURE(OuterQueryInterface(
__uuidof(IADs),
reinterpret_cast<void**>(&m_pADs)
));
///////////////////////////////////////////////////////
// Figure out the domain or server name using Pathname
///////////////////////////////////////////////////////
CComBSTR BstrPath;
hr = m_pADs->get_ADsPath(&BstrPath);
m_pADs.p->Release();
if (!SUCCEEDED(hr))
return hr;
CComBSTR BstrProvider;
m_StaticCritSec.Lock();
do
{
if ( !m_StaticpPath )
{
BREAK_ON_FAILURE(CoCreateInstance(
__uuidof(Pathname),
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IADsPathname),
reinterpret_cast<void**>(&m_StaticpPath )
));
}
/////////////////////////////////////////
// Get the provider used (WinNT or LDAP)
/////////////////////////////////////////
BREAK_ON_FAILURE(m_StaticpPath->Set(
BstrPath,
ADS_SETTYPE_FULL
));
BREAK_ON_FAILURE(m_StaticpPath->Retrieve(
ADS_FORMAT_PROVIDER,
&BstrProvider
));
// Check for "WinNT" and "LDAP"
// return E_FAIL for other providers
if ( lstrcmpW(BstrProvider,L"WinNT") == 0 )
{
m_vbIsLDAP = VARIANT_FALSE;
hr = GetInfoWinNT(m_StaticpPath );
}
else if ( lstrcmpW(BstrProvider,L"LDAP") == 0 )
{
m_vbIsLDAP = VARIANT_TRUE;
hr = GetInfoLDAP(m_StaticpPath );
}
else
{
hr = E_FAIL;
}
}
while (FALSE);
m_StaticCritSec.Unlock();
break;
}
case ADS_EXT_INITIALIZE_COMPLETE:
default:
{
// Default case should not fail
break;
}
}
return hr;
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::PrivateGetIDsOfNames
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP ADsTSUserEx::PrivateGetIDsOfNames(const struct _GUID &riid,
USHORT** rgszNames,
UINT cNames,
ULONG lcid,
LONG* rgdispid)
{
if ( !rgdispid )
{
return E_POINTER;
}
return m_StaticHolder.GetIDsOfNames(riid, rgszNames, cNames, lcid,
rgdispid);
}
//////////////////////////////////////////////////////////////////////////////
// ADsTSUserEx::PrivateInvoke
//////////////////////////////////////////////////////////////////////////////
STDMETHODIMP ADsTSUserEx::PrivateInvoke(LONG dispidMember,
const struct _GUID &riid,
ULONG lcid,
USHORT wFlags,
DISPPARAMS* pdispparams,
VARIANT* pvarResult,
EXCEPINFO* pexcepinfo,
UINT* puArgErr)
{
return m_StaticHolder.Invoke(this, dispidMember, riid, lcid, wFlags,
pdispparams, pvarResult, pexcepinfo,
puArgErr);
}
////////////////////////////////////////////////////
// Delegating IDispatch Methods to the aggregator
//////////////////////////////////////////////////////
STDMETHODIMP ADsTSUserEx::GetTypeInfoCount(UINT* pctinfo)
{
if ( !m_pOuterDispatch )
{
RETURN_ON_FAILURE(OuterQueryInterface(
__uuidof(IDispatch),
reinterpret_cast<void**>(&m_pOuterDispatch)
));
}
return m_pOuterDispatch->GetTypeInfoCount( pctinfo );
}
STDMETHODIMP ADsTSUserEx::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
{
if ( !m_pOuterDispatch )
{
RETURN_ON_FAILURE(OuterQueryInterface(
__uuidof(IDispatch),
reinterpret_cast<void**>(&m_pOuterDispatch)
));
}
return m_pOuterDispatch->GetTypeInfo( itinfo, lcid, pptinfo );
}
STDMETHODIMP ADsTSUserEx::GetIDsOfNames(REFIID riid,
LPOLESTR* rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgdispid)
{
if ( !m_pOuterDispatch )
{
RETURN_ON_FAILURE(OuterQueryInterface(
__uuidof(IDispatch),
reinterpret_cast<void**>(&m_pOuterDispatch)
));
}
return m_pOuterDispatch->GetIDsOfNames(riid, rgszNames, cNames, lcid,
rgdispid);
}
STDMETHODIMP ADsTSUserEx::Invoke(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT*
pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
IDispatch *pDisp;
HRESULT hr = S_OK;
hr = OuterQueryInterface( IID_IDispatch, (void**) &pDisp );
if ( SUCCEEDED(hr) )
{
hr = pDisp->Invoke( dispidMember, riid, lcid, wFlags,
pdispparams, pvarResult, pexcepinfo, puArgErr);
pDisp->Release();
}
return hr;
}
/////////////////////////////////////////////////////////////////////////
// End delegating IDispatch Methods
/////////////////////////////////////////////////////////////////////////
STDMETHODIMP ADsTSUserEx::get_TerminalServicesProfilePath(BSTR *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalGetString(WIN_WFPROFILEPATH, pVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_TerminalServicesProfilePath(BSTR pNewVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalSetString(WIN_WFPROFILEPATH, pNewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_TerminalServicesHomeDirectory(BSTR *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalGetString(WIN_WFHOMEDIR, pVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_TerminalServicesHomeDirectory(BSTR pNewVal) throw()
{
if (m_vbUpLevelAllowed)
{
BSTR bstrVal = NULL;
if(pNewVal && PathIsUNC(pNewVal))
{
//There sould be some value for HomeDrive
InternalGetString(WIN_WFHOMEDIRDRIVE, &bstrVal);
if(!bstrVal || !SysStringLen(bstrVal))
{
if(bstrVal)
{
SysFreeString(bstrVal);
}
bstrVal = SysAllocString(L"Z:");
if(bstrVal)
{
InternalSetString(WIN_WFHOMEDIRDRIVE, bstrVal);
SysFreeString(bstrVal);
bstrVal = NULL;
}
}
}
else
{
//Local path or empty path
//Reset HomeDrive.
bstrVal = SysAllocString(L"");
if(bstrVal)
{
InternalSetString(WIN_WFHOMEDIRDRIVE, bstrVal);
SysFreeString(bstrVal);
bstrVal = NULL;
}
}
return InternalSetString(WIN_WFHOMEDIR, pNewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_TerminalServicesHomeDrive(BSTR *pVal) throw()
{
HRESULT hr = S_OK;
if (m_vbUpLevelAllowed)
{
hr = InternalGetString(WIN_WFHOMEDIRDRIVE, pVal);
if(pVal && !SysStringLen(*pVal))
{
BSTR bstrVal = NULL;
InternalGetString(WIN_WFHOMEDIR, &bstrVal);
if(bstrVal && PathIsUNC(bstrVal))
{
*pVal = SysAllocString(L"Z:");
}
if(bstrVal)
{
SysFreeString(bstrVal);
bstrVal = NULL;
}
}
return hr;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_TerminalServicesHomeDrive(BSTR pNewVal) throw()
{
if (m_vbUpLevelAllowed)
{
if(!pNewVal || !SysStringLen(pNewVal))
{
return InternalSetString(WIN_WFHOMEDIRDRIVE, pNewVal);
}
if(SysStringLen(pNewVal) > 2)
{
return E_ADS_BAD_PARAMETER;
}
CharUpper( pNewVal );
if( *pNewVal >= 'C' && *pNewVal <= 'Z' && (_tcschr(pNewVal, _T(':'))!=NULL ))
{
return InternalSetString(WIN_WFHOMEDIRDRIVE, pNewVal);
}
else
{
return E_ADS_BAD_PARAMETER;
}
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_AllowLogon(LONG *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
HRESULT hr = S_OK;
LONG lLogon = 0;
hr = InternalGetLong(WIN_FLAGS1, &lLogon);
RETURN_ON_FAILURE(hr);
*pVal = (lLogon & F1MSK_LOGONDISABLED) ? 0 : 1;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_AllowLogon(LONG NewVal) throw()
{
RETURN_ON_INVALID_PARAMETER(NewVal);
NewVal = NewVal? 0 : 1;
if (m_vbUpLevelAllowed)
{
return InternalSetLong(F1MSK_LOGONDISABLED, NewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_EnableRemoteControl(LONG *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
HRESULT hr = S_OK;
LONG lShadow = 0;
hr = InternalGetLong(WIN_SHADOW, &lShadow);
RETURN_ON_FAILURE(hr);
*pVal = lShadow;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_EnableRemoteControl(LONG NewVal) throw()
{
if (m_vbUpLevelAllowed)
{
if(NewVal < 0 || NewVal > 4)
{
return E_ADS_BAD_PARAMETER;
}
else
{
return InternalSetValue(WIN_SHADOW, NewVal);
}
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_MaxDisconnectionTime(LONG *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
HRESULT hr = S_OK;
hr = InternalGetLong(WIN_MAXDISCONNECTIONTIME, pVal);
RETURN_ON_FAILURE(hr);
*pVal /= INMINUTES;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_MaxDisconnectionTime(LONG NewVal) throw()
{
if (m_vbUpLevelAllowed)
{
if(NewVal < 0 || NewVal > MAX_TIME_LIMIT )
{
return E_ADS_BAD_PARAMETER;
}
else
{
return InternalSetValue(WIN_MAXDISCONNECTIONTIME, NewVal*INMINUTES);
}
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_MaxConnectionTime(LONG *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
HRESULT hr = S_OK;
hr = InternalGetLong(WIN_MAXCONNECTIONTIME, pVal);
RETURN_ON_FAILURE(hr);
*pVal /= INMINUTES;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_MaxConnectionTime(LONG NewVal) throw()
{
if (m_vbUpLevelAllowed)
{
if(NewVal < 0 || NewVal > MAX_TIME_LIMIT )
{
return E_ADS_BAD_PARAMETER;
}
else
{
return InternalSetValue(WIN_MAXCONNECTIONTIME, NewVal*INMINUTES);
}
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_MaxIdleTime(LONG *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
HRESULT hr = S_OK;
hr = InternalGetLong(WIN_MAXIDLETIME, pVal);
RETURN_ON_FAILURE(hr);
*pVal /= INMINUTES;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_MaxIdleTime(LONG NewVal) throw()
{
if (m_vbUpLevelAllowed)
{
if(NewVal < 0 || NewVal > MAX_TIME_LIMIT )
{
return E_ADS_BAD_PARAMETER;
}
else
{
return InternalSetValue(WIN_MAXIDLETIME, NewVal*INMINUTES);
}
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_ReconnectionAction(LONG *pVal) throw()
{
LONG lDisconnect;
HRESULT hr = S_OK;
if (m_vbUpLevelAllowed)
{
hr = InternalGetLong(WIN_FLAGS1, &lDisconnect);
RETURN_ON_FAILURE(hr);
*pVal = (lDisconnect & F1MSK_RECONNECTSAME) ? 1 : 0;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_ReconnectionAction(LONG NewVal) throw()
{
RETURN_ON_INVALID_PARAMETER(NewVal);
if (m_vbUpLevelAllowed)
{
return InternalSetLong(F1MSK_RECONNECTSAME, NewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_BrokenConnectionAction(LONG *pVal) throw()
{
LONG lReconnect;
HRESULT hr = S_OK;
if (m_vbUpLevelAllowed)
{
hr = InternalGetLong(WIN_FLAGS1, &lReconnect);
RETURN_ON_FAILURE(hr);
*pVal = (lReconnect & F1MSK_RESETBROKEN) ? 1 : 0;
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_BrokenConnectionAction(LONG NewVal) throw()
{
RETURN_ON_INVALID_PARAMETER(NewVal);
if (m_vbUpLevelAllowed)
{
return InternalSetLong(F1MSK_RESETBROKEN, NewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_ConnectClientDrivesAtLogon(LONG *pVal) throw()
{
LONG lAutoClientDrives;
HRESULT hr = S_OK;
if (m_vbUpLevelAllowed)
{
hr = InternalGetLong(WIN_FLAGS1, &lAutoClientDrives);
RETURN_ON_FAILURE(hr);
if (lAutoClientDrives & F1MSK_AUTOCLIENTDRIVES)
{
*pVal = 1;
}
else
{
*pVal = 0;
}
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_ConnectClientDrivesAtLogon(LONG NewVal) throw()
{
RETURN_ON_INVALID_PARAMETER(NewVal);
if (m_vbUpLevelAllowed)
{
return InternalSetLong(F1MSK_AUTOCLIENTDRIVES, NewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_ConnectClientPrintersAtLogon(LONG *pVal) throw()
{
LONG lAutoClientPrinters;
HRESULT hr = S_OK;
if (m_vbUpLevelAllowed)
{
hr = InternalGetLong(WIN_FLAGS1, &lAutoClientPrinters);
RETURN_ON_FAILURE(hr);
if (lAutoClientPrinters & F1MSK_AUTOCLIENTLPTS)
{
*pVal = 1;
}
else
{
*pVal = 0;
}
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_ConnectClientPrintersAtLogon(LONG NewVal) throw()
{
RETURN_ON_INVALID_PARAMETER(NewVal);
if (m_vbUpLevelAllowed)
{
return InternalSetLong(F1MSK_AUTOCLIENTLPTS, NewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_DefaultToMainPrinter(LONG *pVal) throw()
{
LONG lDefaultPrinter;
HRESULT hr = S_OK;
if (m_vbUpLevelAllowed)
{
hr = InternalGetLong(WIN_FLAGS1, &lDefaultPrinter);
RETURN_ON_FAILURE(hr);
if (lDefaultPrinter & F1MSK_FORCECLIENTLPTDEF)
{
*pVal = 1;
}
else
{
*pVal = 0;
}
return S_OK;
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_DefaultToMainPrinter(LONG NewVal) throw()
{
RETURN_ON_INVALID_PARAMETER(NewVal);
if (m_vbUpLevelAllowed)
{
return InternalSetLong(F1MSK_FORCECLIENTLPTDEF, NewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_TerminalServicesWorkDirectory(BSTR *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalGetString(WIN_WORKDIRECTORY, pVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_TerminalServicesWorkDirectory(BSTR pNewVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalSetString(WIN_WORKDIRECTORY, pNewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::get_TerminalServicesInitialProgram(BSTR *pVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalGetString(WIN_INITIALPROGRAM, pVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}
STDMETHODIMP ADsTSUserEx::put_TerminalServicesInitialProgram(BSTR pNewVal) throw()
{
if (m_vbUpLevelAllowed)
{
return InternalSetString(WIN_INITIALPROGRAM, pNewVal);
}
else
{
return E_ADS_PROPERTY_NOT_FOUND;
}
}