windows-nt/Source/XPSP1/NT/base/remoteboot/riprep/serverdlg.cpp
2020-09-26 16:20:57 +08:00

675 lines
17 KiB
C++

/****************************************************************************
Copyright (c) Microsoft Corporation 1998
All rights reserved
File: SERVERDLG.CPP
***************************************************************************/
#include "pch.h"
#include "callback.h"
#include "utils.h"
#include <winver.h>
#include <sputils.h>
DEFINE_MODULE( "RIPREP" )
BOOLEAN
GetInstalledProductType(
OUT PDWORD ProductType,
OUT PDWORD ProductSuite
)
/*++
Routine Description:
retrieves the product type and suite from a running system
Arguments:
ProductType - receives a VER_NT_* constant.
ProductSuite - receives a VER_SUITE_* mask for the system.
Return Value:
TRUE indicates success
--*/
{
OSVERSIONINFOEX VersionInfo;
VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
if (GetVersionEx((OSVERSIONINFO *)&VersionInfo)) {
//
// make domain controllers and servers look the same
//
*ProductType = (VersionInfo.wProductType == VER_NT_DOMAIN_CONTROLLER)
? VER_NT_SERVER
: VersionInfo.wProductType;
//
// we only care about suites that have a SKU associated with them.
//
*ProductSuite = (VersionInfo.wSuiteMask
& (VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER | VER_SUITE_PERSONAL)) ;
return(TRUE);
}
return(FALSE);
}
BOOL
pSetupEnablePrivilegeW(
IN PCWSTR PrivilegeName,
IN BOOL Enable
)
/*++
Routine Description:
Enable or disable a given named privilege.
Arguments:
PrivilegeName - supplies the name of a system privilege.
Enable - flag indicating whether to enable or disable the privilege.
Return Value:
Boolean value indicating whether the operation was successful.
--*/
{
HANDLE Token;
BOOL b;
TOKEN_PRIVILEGES NewPrivileges;
LUID Luid;
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
return(FALSE);
}
if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
CloseHandle(Token);
return(FALSE);
}
NewPrivileges.PrivilegeCount = 1;
NewPrivileges.Privileges[0].Luid = Luid;
NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
b = AdjustTokenPrivileges(
Token,
FALSE,
&NewPrivileges,
0,
NULL,
NULL
);
CloseHandle(Token);
return(b);
}
GetSuiteMaskFromPath(
IN PCWSTR PathToSearch,
OUT PDWORD SuiteMask
)
{
#define HIVENAME L"riprepsetupreg"
TCHAR lpszSetupReg[MAX_PATH] = HIVENAME L"\\ControlSet001\\Services\\setupdd";
WCHAR Path[MAX_PATH];
WCHAR DestPath[MAX_PATH];
LONG rslt;
HKEY hKey;
DWORD Type;
DWORD Buffer[4];
DWORD BufferSize = sizeof(Buffer);
DWORD i;
BOOLEAN RetVal = FALSE;
GetTempPath(ARRAYSIZE(Path),Path);
GetTempFileName( Path, L"ripr", 0, DestPath);
wcscpy(Path, PathToSearch);
wcscat(Path, L"\\setupreg.hiv");
if (!CopyFile(Path,DestPath,FALSE)) {
goto e0;
}
SetFileAttributes(DestPath,FILE_ATTRIBUTE_NORMAL);
//
// need SE_RESTORE_NAME priviledge to call this API!
//
pSetupEnablePrivilegeW( SE_RESTORE_NAME, TRUE );
//
// try to unload this first in case we faulted or something and the key is still loaded
//
RegUnLoadKey( HKEY_LOCAL_MACHINE, HIVENAME );
rslt = RegLoadKey( HKEY_LOCAL_MACHINE, HIVENAME, DestPath );
if (rslt != ERROR_SUCCESS) {
goto e1;
}
rslt = RegOpenKey(HKEY_LOCAL_MACHINE,lpszSetupReg,&hKey);
if (rslt != ERROR_SUCCESS) {
goto e2;
}
rslt = RegQueryValueEx(hKey, NULL, NULL, &Type, (LPBYTE) Buffer, &BufferSize);
if (rslt != ERROR_SUCCESS || Type != REG_BINARY) {
goto e3;
}
*SuiteMask=Buffer[3];
RetVal = TRUE;
e3:
RegCloseKey( hKey );
e2:
RegUnLoadKey( HKEY_LOCAL_MACHINE, HIVENAME );
e1:
if (GetFileAttributes(DestPath) != 0xFFFFFFFF) {
SetFileAttributes(DestPath,FILE_ATTRIBUTE_NORMAL);
DeleteFile(DestPath);
wcscat(DestPath, L".LOG");
SetFileAttributes(DestPath,FILE_ATTRIBUTE_NORMAL);
DeleteFile(DestPath);
}
pSetupEnablePrivilegeW( SE_RESTORE_NAME, FALSE );
e0:
return(RetVal);
}
BOOLEAN
GetProductTypeFromPath(
OUT PDWORD ProductType,
OUT PDWORD ProductSuite,
IN PCWSTR PathToSearch )
/*++
Routine Description:
retrieves the product type and suite by looking in txtsetup.sif
Arguments:
ProductType - receives a VER_NT_* constant.
ProductSuite - receives a VER_SUITE_* mask for the system.
PathToSearch - specifies the path to the txtsetup.sif to be searched
Return Value:
TRUE indicates success
--*/
{
WCHAR Path[MAX_PATH];
UINT DontCare;
HINF hInf;
WCHAR Type[20];
BOOLEAN RetVal = TRUE;
INFCONTEXT Context;
wcscpy(Path, PathToSearch);
wcscat(Path, L"\\txtsetup.sif");
hInf = SetupOpenInfFile( Path, NULL, INF_STYLE_WIN4, &DontCare );
if (hInf != INVALID_HANDLE_VALUE) {
if (SetupFindFirstLine( hInf, L"SetupData", L"ProductType", &Context) &&
SetupGetStringField( &Context, 1, Type, ARRAYSIZE(Type), NULL)) {
switch (Type[0]) {
case L'0':
*ProductType = VER_NT_WORKSTATION;
*ProductSuite = 0;
break;
case L'1':
*ProductType = VER_NT_SERVER;
//
// HACK alert: we have to call this API because txtsetup.sif
// didn't have the correct product type in it in win2k.
// So we do it the hard way.
//
if (!GetSuiteMaskFromPath( PathToSearch, ProductSuite)) {
*ProductSuite = 0;
}
break;
case L'2':
*ProductType = VER_NT_SERVER;
*ProductSuite = VER_SUITE_ENTERPRISE;
break;
case L'3':
*ProductType = VER_NT_SERVER;
*ProductSuite = VER_SUITE_ENTERPRISE | VER_SUITE_DATACENTER;
break;
case L'4':
*ProductType = VER_NT_WORKSTATION;
*ProductSuite = VER_SUITE_PERSONAL;
break;
default:
ASSERT( FALSE && L"Unknown type in txtsetup.sif ProductType" );
RetVal = FALSE;
break;
}
}
SetupCloseInfFile(hInf);
} else {
RetVal = FALSE;
}
return(RetVal);
}
//
// GetNtVersionInfo( )
//
// Retrieves the build version from the kernel
//
BOOLEAN
GetNtVersionInfo(
PULONGLONG Version,
PWCHAR SearchDir
)
{
DWORD Error = ERROR_SUCCESS;
DWORD FileVersionInfoSize;
DWORD VersionHandle;
ULARGE_INTEGER TmpVersion;
PVOID VersionInfo;
VS_FIXEDFILEINFO * FixedFileInfo;
UINT FixedFileInfoLength;
WCHAR Path[MAX_PATH];
BOOLEAN fResult = FALSE;
TraceFunc("GetNtVersionInfo( )\n");
// Resulting string should be something like:
// "\\server\reminst\Setup\English\Images\nt50.wks\i386\ntoskrnl.exe"
if (!SearchDir) {
goto e0;
}
wcscpy(Path, SearchDir);
wcscat(Path, L"\\ntoskrnl.exe");
FileVersionInfoSize = GetFileVersionInfoSize(Path, &VersionHandle);
if (FileVersionInfoSize == 0)
goto e0;
VersionInfo = LocalAlloc( LPTR, FileVersionInfoSize );
if (VersionInfo == NULL)
goto e0;
if (!GetFileVersionInfo(
Path,
VersionHandle,
FileVersionInfoSize,
VersionInfo))
goto e1;
if (!VerQueryValue(
VersionInfo,
L"\\",
(LPVOID*)&FixedFileInfo,
&FixedFileInfoLength))
goto e1;
TmpVersion.HighPart = FixedFileInfo->dwFileVersionMS;
TmpVersion.LowPart = FixedFileInfo->dwFileVersionLS;
*Version = TmpVersion.QuadPart;
fResult = TRUE;
e1:
LocalFree( VersionInfo );
e0:
RETURN(fResult);
}
//
// VerifyMatchingFlatImage( )
//
BOOLEAN
VerifyMatchingFlatImage(
PULONGLONG VersionNeeded OPTIONAL
)
{
TraceFunc( "VerifyMatchingFlatImage( )\n" );
BOOLEAN fResult = FALSE; // assume failure
DWORD dwLen;
WCHAR szPath[ MAX_PATH ];
WIN32_FIND_DATA fd;
HANDLE hFind;
ULONGLONG OurVersion;
DWORD OurProductType = 0, OurProductSuiteMask = 0;
GetSystemDirectory( szPath, ARRAYSIZE( szPath ));
GetNtVersionInfo( &OurVersion, szPath );
GetInstalledProductType( &OurProductType, &OurProductSuiteMask );
if (VersionNeeded) {
*VersionNeeded = OurVersion;
}
DebugMsg(
"Our NTOSKRNL verion: %u.%u:%u.%u Type: %d Suite: %d\n",
HIWORD(((PULARGE_INTEGER)&OurVersion)->HighPart),
LOWORD(((PULARGE_INTEGER)&OurVersion)->HighPart),
HIWORD(((PULARGE_INTEGER)&OurVersion)->LowPart),
LOWORD(((PULARGE_INTEGER)&OurVersion)->LowPart),
OurProductType,
OurProductSuiteMask);
wsprintf( szPath,
L"\\\\%s\\REMINST\\Setup\\%s\\%s\\",
g_ServerName,
g_Language,
REMOTE_INSTALL_IMAGE_DIR_W );
dwLen = wcslen( szPath );
wcscat( szPath, L"*" );
hFind = FindFirstFile( szPath, &fd );
if ( hFind != INVALID_HANDLE_VALUE )
{
do {
if ( (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
&& StrCmp( fd.cFileName, L"." ) != 0
&& StrCmp( fd.cFileName, L".." ) != 0 )
{
ULONGLONG Version;
DWORD ProductType = 0, ProductSuiteMask = 0;
wsprintf( &szPath[dwLen],
L"%s\\%s",
fd.cFileName,
g_Architecture );
if ( GetNtVersionInfo( &Version, szPath ) &&
GetProductTypeFromPath(
&ProductType,
&ProductSuiteMask,
szPath ))
{
DebugMsg(
"%s's verion: %u.%u:%u.%u Type: %d Suite: %d\n",
fd.cFileName,
HIWORD(((PULARGE_INTEGER)&Version)->HighPart),
LOWORD(((PULARGE_INTEGER)&Version)->HighPart),
HIWORD(((PULARGE_INTEGER)&Version)->LowPart),
LOWORD(((PULARGE_INTEGER)&Version)->LowPart),
ProductType,
ProductSuiteMask);
if ( OurVersion == Version &&
OurProductType == ProductType &&
OurProductSuiteMask == ProductSuiteMask )
{
wcscpy( g_ImageName, szPath );
fResult = TRUE;
break;
}
}
}
} while ( FindNextFile( hFind, &fd ) );
}
FindClose( hFind );
RETURN(fResult);
}
//
// VerifyServerName( )
//
// Check to see if the server is a Remote Installation Server by
// checking for the existance of the "REMINST" share.
//
DWORD
VerifyServerName( )
{
TraceFunc( "VerifyServerName( )\n" );
NET_API_STATUS netStatus;
SHARE_INFO_0 * psi;
HCURSOR oldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
netStatus = NetShareGetInfo( g_ServerName, L"REMINST", 0, (LPBYTE *) &psi );
if ( netStatus == NERR_Success )
{
NetApiBufferFree( psi );
}
SetCursor( oldCursor );
RETURN(netStatus);
}
BOOL
VerifyServerAccess(
PCWSTR ServerShareName,
PCWSTR ServerLanguage
)
/*++
Routine Description:
Checks permissions on the RIPREP server machine by trying to create a file on the
server. The temp file is then deleted.
Arguments:
ServerShareName - path that we want to check permissions on.
ServerLanguage - indicates the language subdirectory to check for access in.
Return value:
TRUE if the user has access to the server, FALSE otherwise.
--*/
{
TraceFunc( "VerifyServerAccess( )\n" );
WCHAR FileName[MAX_PATH];
WCHAR FilePath[MAX_PATH];
BOOL RetVal;
HCURSOR oldCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
wsprintf(FilePath,
L"\\\\%s\\reminst\\Setup\\%s\\Images",
ServerShareName,
ServerLanguage );
RetVal = GetTempFileName( FilePath , L"ACC", 0, FileName );
if (RetVal) {
//
// delete the file, we don't want to leave turds on the server
//
DeleteFile(FileName);
RetVal = TRUE;
} else if (GetLastError() == ERROR_ACCESS_DENIED) {
RetVal = FALSE;
} else {
//
// GetTempFileName failed, but not because of an access problem, so
// return success
//
RetVal = TRUE;
}
SetCursor( oldCursor );
RETURN(RetVal);
}
//
// ServerDlgCheckNextButtonActivation( )
//
VOID
ServerDlgCheckNextButtonActivation(
HWND hDlg )
{
TraceFunc( "ServerDlgCheckNextButtonActivation( )\n" );
WCHAR szName[ MAX_PATH ];
GetDlgItemText( hDlg, IDC_E_SERVER, szName, ARRAYSIZE(szName));
PropSheet_SetWizButtons( GetParent( hDlg ), PSWIZB_BACK | (wcslen(szName) ? PSWIZB_NEXT : 0 ) );
TraceFuncExit( );
}
//
// ServerDlgProc()
//
INT_PTR CALLBACK
ServerDlgProc(
HWND hDlg,
UINT uMsg,
WPARAM wParam,
LPARAM lParam )
{
ULARGE_INTEGER ImageVersion;
WCHAR szTemp[ 1024 ];
WCHAR szCaption[ 1024 ];
WCHAR ErrorText[ 1024 ];
DWORD dw;
switch (uMsg)
{
default:
return FALSE;
case WM_INITDIALOG:
CenterDialog( GetParent( hDlg ) );
return FALSE;
case WM_COMMAND:
switch ( LOWORD( wParam ) )
{
case IDC_E_SERVER:
if ( HIWORD( wParam ) == EN_CHANGE )
{
ServerDlgCheckNextButtonActivation( hDlg );
}
break;
}
break;
case WM_NOTIFY:
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, FALSE );
LPNMHDR lpnmhdr = (LPNMHDR) lParam;
switch ( lpnmhdr->code )
{
case PSN_WIZNEXT:
{
GetDlgItemText( hDlg, IDC_E_SERVER, g_ServerName, ARRAYSIZE(g_ServerName) );
//remove the wackwack if found
if ( g_ServerName[0] == L'\\' && g_ServerName[1] == L'\\' )
{
wcscpy( g_ServerName, &g_ServerName[2] );
}
Assert( wcslen( g_ServerName ) );
DWORD dwErr = VerifyServerName( );
if ( dwErr != ERROR_SUCCESS )
{
switch (dwErr)
{
case NERR_NetNameNotFound:
MessageBoxFromStrings( hDlg, IDS_NOT_A_BINL_SERVER_TITLE, IDS_NOT_A_BINL_SERVER_TEXT, MB_OK );
break;
default:
dw = LoadString( g_hinstance, IDS_FAILED_TO_CONTACT_SERVER_TITLE, szTemp, ARRAYSIZE(szTemp) );
Assert( dw );
MessageBoxFromError( hDlg, szTemp, dwErr, NULL, MB_OK );
break;
}
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, -1 ); // don't go on
break;
}
BOOL fFoundMatchingFlatImage = VerifyMatchingFlatImage( (PULONGLONG)&ImageVersion );
if ( !fFoundMatchingFlatImage )
{
dw = LoadString( g_hinstance, IDS_MISSING_BACKING_FLAT_IMAGE_TEXT, szTemp, ARRAYSIZE(szTemp) );
ASSERT(dw);
dw = LoadString( g_hinstance, IDS_MISSING_BACKING_FLAT_IMAGE_TITLE, szCaption, ARRAYSIZE(szCaption) );
ASSERT(dw);
wsprintf(
ErrorText,
szTemp,
HIWORD(ImageVersion.HighPart),
LOWORD(ImageVersion.HighPart),
HIWORD(ImageVersion.LowPart),
g_Language );
MessageBox( hDlg, ErrorText, szCaption, MB_OK );
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, -1 ); // don't go on
break;
}
if (!VerifyServerAccess(g_ServerName,g_Language)) {
dw = LoadString( g_hinstance, IDS_SERVER_ACCESS_DESC, ErrorText, ARRAYSIZE(ErrorText) );
ASSERT(dw);
dw = LoadString( g_hinstance, IDS_SERVER_ACCESS, szCaption, ARRAYSIZE(szCaption) );
ASSERT(dw);
MessageBox( hDlg, ErrorText, szCaption, MB_OK );
SetWindowLongPtr( hDlg, DWLP_MSGRESULT, -1 ); // don't go on
break;
}
}
break;
case PSN_QUERYCANCEL:
return VerifyCancel( hDlg );
case PSN_SETACTIVE:
SetDlgItemText( hDlg, IDC_E_SERVER, g_ServerName );
ServerDlgCheckNextButtonActivation( hDlg );
ClearMessageQueue( );
break;
}
break;
}
return TRUE;
}