/*++ 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 #include #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 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 pComputer; HRESULT hr = S_OK; LPWSTR pszUserName = NULL; LPWSTR pszPassword = NULL; DWORD dwAuthFlags = 0; CComPtr pDomain; CComBSTR Version; hr = ADsOpenObject(ServerName, NULL, NULL, 0, __uuidof(IADsComputer), reinterpret_cast (&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; iGetElement(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(&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(&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(&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(&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(&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; } }