|
|
// Interfaces.cpp : Implementation of TSUserExInterfaces class.
#include "stdafx.h"
#if 1 //POST_BETA_3
#include <sspi.h>
#include <secext.h>
#include <dsgetdc.h>
#endif //POST_BETA_3
//#include "ConfigDlg.h" // for CTSUserProperties
#include "tsusrsht.h"
//#include "logmsg.h"
#include "limits.h" // USHRT_MAX
#ifdef _RTM_
#include <ntverp.h> // VER_PRODUCTVERSION_DW
#endif
#include <winsta.h>
//#include "ntdsapi.h" // enbable for "having some fun macro"
// clipboard format to retreive the machine name and account name associated
// with a data object created by local user manager
#define CCF_LOCAL_USER_MANAGER_MACHINE_NAME TEXT("Local User Manager Machine Focus Name")
#define ByteOffset(base, offset) (((LPBYTE)base)+offset)
BOOL g_bPagesHaveBeenInvoked = FALSE; /////////////////////////////////////////////////////////////////////////////
// IExtendPropertySheet implementation
HRESULT GetMachineAndUserName(IDataObject *pDataObject, LPWSTR pMachineName, LPWSTR pUserName , PBOOL pbDSAType , PSID *ppUserSid ) { ASSERT_(pUserName); ASSERT_(pMachineName); ASSERT_(pDataObject != NULL );
// register the display formats.
// first 2 formats supported by local user manager snapin
static UINT s_cfMachineName = RegisterClipboardFormat(CCF_LOCAL_USER_MANAGER_MACHINE_NAME); static UINT s_cfDisplayName = RegisterClipboardFormat(CCF_DISPLAY_NAME);; static UINT s_cfDsObjectNames = RegisterClipboardFormat(CFSTR_DSOBJECTNAMES); // this format is supported by dsadmin snapin.
ASSERT_(s_cfMachineName); ASSERT_(s_cfDisplayName); ASSERT_(s_cfDsObjectNames);
FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium = { TYMED_HGLOBAL, NULL, NULL };
HRESULT hr = S_OK;
ASSERT_(USHRT_MAX > s_cfDsObjectNames);
// first we will try dsdataobject format. This means we are running in context of dsadmin
fmte.cfFormat = ( USHORT )s_cfDsObjectNames;
hr = pDataObject->GetData(&fmte, &medium);
if( SUCCEEDED( hr ) ) { // CFSTR_DSOBJECTNAMES is supported.
// It means we are dealing with dsadmin
// lets get username, and domain name from the dsadmin.
LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)medium.hGlobal;
*pbDSAType = TRUE;
if( pDsObjectNames->cItems < 1 ) { ODS( L"TSUSEREX : @GetMachineAndUserName DS Object names < 1\n" );
return E_FAIL; }
LPWSTR pwszObjName = ( LPWSTR )ByteOffset( pDsObjectNames , pDsObjectNames->aObjects[0].offsetName );
KdPrint( ( "TSUSEREX : adspath is %ws\n" , pwszObjName ) );
// first stage get the server name from the adspath
// since IADsPathname does not live off a normal IADs Directory object
// so me must cocreate the object set the path and then retrieve the server name
// hey this saves us wire-tripping
// IADsPathname *pPathname = NULL;
IADsObjectOptions *pADsOptions = NULL;
IADs *pADs = NULL;
hr = ADsGetObject( pwszObjName, IID_IADs, (void**)&pADs );
if( FAILED( hr ) ) { KdPrint( ( "TSUSEREX : no means of binding to adspath -- hresult = 0x%x\n" , hr ) );
return hr; }
VARIANT varServerName;
VariantInit(&varServerName);
hr = pADs->QueryInterface( IID_IADsObjectOptions , ( void ** )&pADsOptions );
KdPrint( ( "TSUSEREX : binded to adsobject queried for IID_IADsObjectOptions returned 0x%x\n" , hr ) );
if( SUCCEEDED( hr ) ) { hr = pADsOptions->GetOption( ADS_OPTION_SERVERNAME, &varServerName);
pADsOptions->Release( );
KdPrint( ( "TSUSEREX: GetOption returned 0x%x\n" , hr ) ) ; }
if( SUCCEEDED( hr ) ) { lstrcpy( pMachineName , V_BSTR( &varServerName ) );
KdPrint( ( "TSUSEREX: Server name is %ws\n" , pMachineName ) ) ; }
VariantClear( &varServerName );
if( FAILED( hr ) ) { // ADS_FORMAT_SERVER is not supported this could mean we're dealing with an WinNT format
// or a DS Provider that is poorly implemented
KdPrint( ( "IADsPathname could not obtain server name 0x%x\n" , hr ) );
// let's go wire tapping to get the server name
VARIANT v;
LPTSTR szDName = NULL;
ULONG ulDName = 0;
VariantInit(&v);
hr = pADs->Get(L"distinguishedName", &v);
if( FAILED( hr ) ) { KdPrint( ( "TSUSEREX : pADs->Get( DN ) returned 0x%x\n", hr ) );
pADs->Release(); return hr; }
ASSERT_( V_VT( &v ) == VT_BSTR );
if( !TranslateNameW( V_BSTR(&v), NameFullyQualifiedDN, NameCanonical, szDName, &ulDName) ) { KdPrint( ( "TSUSEREX : TranslateNameW failed with 0x%x\n", GetLastError( ) ) );
pADs->Release(); return E_FAIL; }
szDName = ( LPTSTR )new TCHAR[ ulDName + 1 ];
if( szDName == NULL ) { KdPrint( ( "TSUSEREX : could not allocate space for szDName\n" ) );
pADs->Release(); return E_OUTOFMEMORY; }
if( !TranslateNameW( V_BSTR(&v), NameFullyQualifiedDN, NameCanonical, szDName, &ulDName) ) { KdPrint( ( "TSUSEREX : TranslateNameW failed 2nd pass with 0x%x\n", GetLastError( ) ) );
delete[] szDName; pADs->Release(); return E_FAIL; }
// perform LEFT$( szDName , up to '/' )
KdPrint( ( "TSUSEREX : TranslateNameW cracked the name to %ws\n" , szDName ) );
LPTSTR pszTemp = szDName;
while( pszTemp != NULL ) { if( *pszTemp == L'/' ) { *pszTemp = 0;
break; }
pszTemp++; }
KdPrint( ("TranslateName with my LEFT$ returned %ws\n",szDName ) );
// get the domaincontroller name of the remote machine
DOMAIN_CONTROLLER_INFO *pdinfo;
DWORD dwStatus = DsGetDcName( NULL , szDName , NULL , NULL , 0 , &pdinfo );
KdPrint( ( "TSUSEREX : DsGetDcName: %ws returned 0x%x\n", pdinfo->DomainControllerName , dwStatus ) );
if( dwStatus == NO_ERROR ) { lstrcpy( pMachineName , pdinfo->DomainControllerName );
NetApiBufferFree( pdinfo ); }
if( szDName != NULL ) { delete[] szDName; }
VariantClear( &v );
} // END else
pADs->Release( );
IADsUser *pADsUser = NULL;
hr = ADsGetObject( pwszObjName, IID_IADsUser, (void**)&pADsUser);
if( FAILED( hr ) ) { KdPrint( ( "TSUSEREX: ADsGetObject failed to get the user object 0x%x\n",hr ) );
return hr; }
VARIANT var; VARIANT varSid;
VariantInit(&var); VariantInit(&varSid);
hr = pADsUser->Get(L"ObjectSid", &varSid);
if( FAILED( hr ) ) { ODS( L"TSUSEREX : IADsUser::Get( ObjectSid ) failed \n" ); pADsUser->Release(); return hr; }
if( !( varSid.vt & VT_ARRAY) ) { ODS( L"TSUSEREX : Object SID is not a VT_ARRAY\n" );
pADsUser->Release(); return E_FAIL; }
PSID pSid = NULL;
PSID pUserSid = NULL;
SafeArrayAccessData( varSid.parray, &pSid );
if( !IsValidSid( pSid ) ) { ODS( L"TSUSEREX : pSid is invalid\n" );
pADsUser->Release(); return E_FAIL; }
DWORD dwSidSize = GetLengthSid( pSid );
pUserSid = new BYTE[ dwSidSize ];
if( pUserSid == NULL ) { ODS( L"TSUSEREX : failed to allocate pUserSid\n" );
pADsUser->Release(); return E_FAIL; }
CopySid( dwSidSize , pUserSid , pSid );
*ppUserSid = pUserSid;
SafeArrayUnaccessData( varSid.parray );
VariantClear( &varSid );
hr = pADsUser->Get( L"samAccountName" , &var );
pADsUser->Release();
if( FAILED( hr ) ) { KdPrint( ( "TSUSEREX : ADsUser::Get( name ) failed 0x%x\n", hr ) );
return hr; }
ASSERT_( V_VT( &var ) == VT_BSTR );
lstrcpy( pUserName , V_BSTR( &var ) );
KdPrint( ( "TSUSEREX : Server name %ws user name is %ws\n" , pMachineName , pUserName ) );
VariantClear( &var );
ReleaseStgMedium(&medium); } else { // CFSTR_DSOBJECTNAMES is NOT supported.
// It means we are dealing with local user manager.
// we must be able to get
// Allocate medium for GetDataHere.
medium.hGlobal = GlobalAlloc(GMEM_SHARE, MAX_PATH * sizeof(WCHAR));
if( !medium.hGlobal ) { ODS( L"TSUSEREX : GlobalAlloc failed in GetMachineAndUserName\n" );
return E_OUTOFMEMORY; }
*pbDSAType = FALSE;
// since we are doing data conversion.
// check for possible data loss.
ASSERT_(USHRT_MAX > s_cfMachineName);
// request the machine name from the dataobject.
fmte.cfFormat = (USHORT)s_cfMachineName;
hr = pDataObject->GetDataHere(&fmte, &medium);
if( FAILED( hr ) ) { ODS( L"TSUSEREX : @GetMachineAndUserName GetDataHere for s_cfMachineName failed\n" );
return hr; }
// copy the machine name into our buffer
if( ( LPWSTR )medium.hGlobal != NULL && pMachineName != NULL ) { wcscpy(pMachineName, (LPWSTR)medium.hGlobal ); }
// administer local accounts only for Terminal Servers
SERVER_INFO_101 *psi101; HANDLE hTServer = NULL;
DWORD dwNetStatus = NetServerGetInfo( pMachineName , 101 , ( LPBYTE * )&psi101 );
if( dwNetStatus != NERR_Success ) { KdPrint( ( "TSUSEREX:GetMachineAndUserName -- NetServerGetInfo failed with 0x%x\n", dwNetStatus ) );
return E_FAIL; }
if( psi101 == NULL ) { KdPrint( ( "TSUSEREX:GetMachineAndUserName -- NetServerGetInfo failed getting sinfo101 0x%x\n",dwNetStatus ) );
return E_FAIL; } KdPrint( ("TSUSEREX:NetServerGetInfo server bits returnd 0x%x and nttype is 0x%x\n", psi101->sv101_type , SV_TYPE_SERVER_NT ) );
BOOL fServer = ( BOOL )( psi101->sv101_type & ( DWORD )SV_TYPE_SERVER_NT );
NetApiBufferFree( ( LPVOID )psi101 );
if( !fServer ) {
KdPrint( ( "TSUSEREX : viewing local account on non-TS ( exiting )\n" ) );
return E_FAIL; }
hTServer = WinStationOpenServer( pMachineName ); if( hTServer == NULL ) { KdPrint( ( "TSUSEREX: This OS does not support terminal services\n" ) ) ; return E_FAIL; } WinStationCloseServer( hTServer );
// since we are doing data conversion.
// check for possible data loss.
ASSERT_(USHRT_MAX > s_cfDisplayName);
// request data about user name.
fmte.cfFormat = (USHORT)s_cfDisplayName;
hr = pDataObject->GetDataHere( &fmte , &medium );
if( FAILED( hr ) ) { ODS( L"TSUSEREX : @GetMachineAndUserName GetDataHere for s_cfDisplayName failed\n" );
return hr; }
// copy the user name into our buffer and release the medium.
if( ( LPWSTR )medium.hGlobal != NULL && pUserName != NULL ) { wcscpy( pUserName , ( LPWSTR )medium.hGlobal ); }
ReleaseStgMedium( &medium ); }
return S_OK; }
//-----------------------------------------------------------------------------------------------------
TSUserExInterfaces::TSUserExInterfaces() { // LOGMESSAGE0(_T("TSUserExInterfaces::TSUserExInterfaces()..."));
// m_pUserConfigPage = NULL;
m_pTSUserSheet = NULL;
m_pDsadataobj = NULL; }
//-----------------------------------------------------------------------------------------------------
TSUserExInterfaces::~TSUserExInterfaces() { ODS( L"Good bye\n" ); }
//-----------------------------------------------------------------------------------------------------
HRESULT TSUserExInterfaces::CreatePropertyPages( LPPROPERTYSHEETCALLBACK lpProvider, // pointer to the callback interface
LONG_PTR , // handle for routing notification
LPDATAOBJECT lpIDataObject) // pointer to the data object);
{ //
// Test for valid parameters
//
if( lpIDataObject == NULL || IsBadReadPtr( lpIDataObject , sizeof( LPDATAOBJECT ) ) ) { ODS( L"TSUSEREX : @ CreatePropertyPages IDataObject is invalid\n " );
return E_INVALIDARG; }
if( lpProvider == NULL ) { ODS( L"TSUSEREX @ CreatePropertyPages LPPROPERTYSHEETCALLBACK is invalid\n" );
return E_INVALIDARG; }
WCHAR wUserName[ MAX_PATH ];
WCHAR wMachineName[ MAX_PATH ];
BOOL bDSAType;
if( g_bPagesHaveBeenInvoked ) { ODS( L"TSUSEREX : TSUserExInterfaces::CreatePropertyPages pages have been invoked\n" );
return E_FAIL; }
PSID pUserSid = NULL;
if( FAILED( GetMachineAndUserName( lpIDataObject , wMachineName , wUserName , &bDSAType , &pUserSid ) ) ) { ODS( L"TSUSEREX : GetMachineAndUserName failed @CreatePropertyPages \n" );
return E_FAIL; }
//
// Test to see if we are being called twice
//
if( m_pTSUserSheet != NULL ) { return E_FAIL; }
//
// MMC likes to release IEXtendPropertySheet ( this object )
// so we cannot free CTSUserSheet in TSUserExInterfaces::dtor
// CTSUserSheet must release itself!!!
//
m_pTSUserSheet = new CTSUserSheet( );
if( m_pTSUserSheet != NULL ) { ODS( L"TSUSEREX : CreatePropertyPages mem allocation succeeded\n" );
m_pTSUserSheet->SetDSAType( bDSAType );
VERIFY_S( TRUE , m_pTSUserSheet->SetServerAndUser( &wMachineName[0] , &wUserName[0] ) );
m_pTSUserSheet->CopyUserSid( pUserSid );
VERIFY_S( S_OK , m_pTSUserSheet->AddPagesToPropSheet( lpProvider ) ); }
return S_OK;
}
//-----------------------------------------------------------------------------------------------------
HRESULT TSUserExInterfaces::QueryPagesFor( LPDATAOBJECT /* lpDataObject */ ) { return S_OK; }
//-----------------------------------------------------------------------------------------------------
// this has not been checked in yet!!!
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::GetHelpTopic( LPOLESTR *ppszHelp ) { ODS( L"TSUSEREX : GetHelpTopic\n" );
if( ppszHelp == NULL ) { return E_INVALIDARG; }
TCHAR tchHelpFile[ 80 ];
VERIFY_E( 0 , LoadString( _Module.GetResourceInstance( ) , IDS_TSUSERHELP , tchHelpFile , sizeof( tchHelpFile ) / sizeof( TCHAR ) ) );
// mmc will call CoTaskMemFree
*ppszHelp = ( LPOLESTR )CoTaskMemAlloc( sizeof( TCHAR ) * MAX_PATH );
if( *ppszHelp != NULL ) { if( GetSystemWindowsDirectory( *ppszHelp , MAX_PATH ) != 0 ) { lstrcat( *ppszHelp , tchHelpFile ); } else { lstrcpy( *ppszHelp , tchHelpFile ); }
ODS( *ppszHelp );
ODS( L"\n" );
return S_OK; }
return E_OUTOFMEMORY; }
//-----------------------------------------------------------------------------------------------------
// IShellExtInit
STDMETHODIMP TSUserExInterfaces::Initialize( LPCITEMIDLIST , LPDATAOBJECT lpdobj, HKEY ) { m_pDsadataobj = lpdobj;
return S_OK; }
//-----------------------------------------------------------------------------------------------------
// IShellPropSheetExt - this interface is used only for dsadmin based tools
// for this reason the DSAType flag is set to true.
STDMETHODIMP TSUserExInterfaces::AddPages( LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam ) { //
// Test for valid parameters
//
if( m_pDsadataobj == NULL ) { ODS( L"TSUSEREX : @ AddPages IDataObject is invalid\n " );
return E_INVALIDARG; }
if( lpfnAddPage == NULL ) { ODS( L"TSUSEREX @ AddPages LPFNADDPROPSHEETPAGE is invalid\n" );
return E_INVALIDARG; }
WCHAR wUserName[ MAX_PATH ];
WCHAR wMachineName[ MAX_PATH ];
BOOL bDSAType;
PSID pUserSid = NULL;
if( FAILED( GetMachineAndUserName( m_pDsadataobj , wMachineName , wUserName , &bDSAType , &pUserSid ) ) ) { ODS( L"TSUSEREX : GetMachineAndUserName @AddPages failed \n" );
return E_FAIL; }
ODS( L"TSUSEREX : DSATYPE in AddPages\n" );
g_bPagesHaveBeenInvoked = TRUE;
//
// Test to see if we are being called twice
//
if( m_pTSUserSheet != NULL ) { return E_FAIL; }
//
// MMC likes to release IEXtendPropertySheet ( this object )
// so we cannot free CTSUserSheet in TSUserExInterfaces::dtor
// CTSUserSheet must release itself!!!
//
m_pTSUserSheet = new CTSUserSheet( );
if( m_pTSUserSheet != NULL ) { ODS( L"TSUSEREX : AddPages mem allocation succeeded\n" );
m_pTSUserSheet->SetDSAType( bDSAType );
m_pTSUserSheet->CopyUserSid( pUserSid );
VERIFY_S( TRUE , m_pTSUserSheet->SetServerAndUser( &wMachineName[0] , &wUserName[0] ) );
VERIFY_S( S_OK , m_pTSUserSheet->AddPagesToDSAPropSheet( lpfnAddPage , lParam ) ); } return S_OK; }
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::ReplacePage( UINT , LPFNADDPROPSHEETPAGE , LPARAM ) { return E_FAIL; }
#ifdef _RTM_ // add ISnapinAbout
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::GetSnapinDescription( LPOLESTR *ppOlestr ) { TCHAR tchMessage[] = TEXT("This extension allows the administrator to configure Terminal Services user properties. This extension is only enabled on Terminal Servers.");
ODS( L"TSUSEREX: GetSnapinDescription called\n" );
*ppOlestr = ( LPOLESTR )CoTaskMemAlloc( ( lstrlen( tchMessage ) + 1 ) * sizeof( TCHAR ) );
if( *ppOlestr != NULL ) { lstrcpy( *ppOlestr , tchMessage );
return S_OK; }
return E_OUTOFMEMORY; }
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::GetProvider( LPOLESTR *ppOlestr ) { TCHAR tchMessage[] = TEXT("Microsoft Corporation");
ODS( L"TSUSEREX: GetProvider called\n" );
*ppOlestr = ( LPOLESTR )CoTaskMemAlloc( ( lstrlen( tchMessage ) + 1 ) * sizeof( TCHAR ) );
if( *ppOlestr != NULL ) { lstrcpy( *ppOlestr , tchMessage );
return S_OK; }
return E_OUTOFMEMORY;
}
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::GetSnapinVersion( LPOLESTR *ppOlestr ) { char chMessage[ 32 ] = VER_PRODUCTVERSION_STR;
TCHAR tchMessage[32];
ODS( L"TSUSEREX: GetSnapinVersion called\n" );
int iCharCount = MultiByteToWideChar( CP_ACP , 0 , chMessage , sizeof( chMessage ) , tchMessage , sizeof( tchMessage ) / sizeof( TCHAR ) );
//wsprintf( tchMessage , TEXT( "%d" ) , VER_PRODUCTVERSION_DW );
*ppOlestr = ( LPOLESTR )CoTaskMemAlloc( ( iCharCount + 1 ) * sizeof( TCHAR ) );
if( *ppOlestr != NULL ) { lstrcpy( *ppOlestr , tchMessage );
return S_OK; }
return E_OUTOFMEMORY; }
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::GetSnapinImage( HICON * ) { return E_NOTIMPL; }
//-----------------------------------------------------------------------------------------------------
STDMETHODIMP TSUserExInterfaces::GetStaticFolderImage( /* [out] */ HBITMAP *, /* [out] */ HBITMAP *, /* [out] */ HBITMAP *, /* [out] */ COLORREF *) { return E_NOTIMPL; }
#endif //_RTM_
|