|
|
/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
menu.c
Abstract:
This module contains the code to process OS Chooser message for the BINL server.
Author:
Adam Barr (adamba) 9-Jul-1997 Geoff Pease (gpease) 10-Nov-1997
Environment:
User Mode - Win32
Revision History:
--*/
#include "binl.h"
#pragma hdrstop
BOOL IsIncompatibleRiprepSIF( PCHAR Path, PCLIENT_STATE clientState ) { CHAR HalName[32]; CHAR ImageType[32]; PCHAR DetectedHalName; BOOL RetVal;
ImageType[0] = '\0'; HalName[0] = '\0';
//
// if it's not an RIPREP image, then just bail out.
//
GetPrivateProfileStringA( OSCHOOSER_SIF_SECTIONA, "ImageType", "", ImageType, sizeof(ImageType)/sizeof(ImageType[0]), Path );
if (0 != _stricmp(ImageType,"SYSPREP")) { RetVal = FALSE; goto exit; } //
// retrieve the hal name from the SIF file
//
GetPrivateProfileStringA( OSCHOOSER_SIF_SECTIONA, "HalName", "", HalName, sizeof(HalName)/sizeof(HalName[0]), Path );
//
// if the hal name isn't present, assume it's an old SIF that
// doesn't have the hal type in it, and so we just return success
//
if (*HalName == '\0') { RetVal = FALSE; goto exit; }
//
// retrieve the detected HAL type from earlier
//
DetectedHalName = OscFindVariableA( clientState, "HALTYPE" ); if (_stricmp(HalName,DetectedHalName)==0) { RetVal = FALSE; goto exit; }
//
// if we got this far, the SIF file is incompatible
//
RetVal = TRUE;
exit: return(RetVal); }
DWORD OscAppendTemplatesMenus( PCHAR *GeneratedScreen, PDWORD dwGeneratedSize, PCHAR DirToEnum, PCLIENT_STATE clientState, BOOLEAN RecoveryOptionsOnly ) { DWORD Error = ERROR_SUCCESS; WIN32_FIND_DATA FindData; HANDLE hFind; int x = 1; CHAR Path[MAX_PATH]; WCHAR UnicodePath[MAX_PATH]; DWORD dwGeneratedCurrentLength; TraceFunc("OscAppendTemplatesMenus( )\n");
BinlAssert( *GeneratedScreen != NULL );
//
// The incoming size is the current length of the buffer
//
dwGeneratedCurrentLength = *dwGeneratedSize;
// Resulting string should be something like:
// "D:\RemoteInstall\English\Images\nt50.wks\i386\Templates\*.sif"
if ( _snprintf( Path, sizeof(Path) / sizeof(Path[0]), "%s\\%s\\Templates\\*.sif", DirToEnum, OscFindVariableA( clientState, "MACHINETYPE" ) ) < 0 ) { Error = ERROR_BAD_PATHNAME; goto Cleanup; }
if (!BinlAnsiToUnicode(Path, UnicodePath, MAX_PATH*sizeof(WCHAR))) { Error = ERROR_BAD_PATHNAME; goto Cleanup; } BinlPrintDbg(( DEBUG_OSC, "Enumerating: %s\n", Path ));
hFind = FindFirstFile( UnicodePath, (LPVOID) &FindData ); if ( hFind != INVALID_HANDLE_VALUE ) { DWORD dwPathLen;
dwPathLen = strlen( Path );
do { //
// If it is not a directory, try to open it
//
if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { CHAR Description[DESCRIPTION_SIZE]; CHAR HelpLines[HELPLINES_SIZE]; PCHAR NewScreen; // temporary points to newly generated screen
DWORD dwErr; DWORD dwFileNameLen; CHAR NewItems[ MAX_PATH * 2 + 512 ]; // arbitrary size
DWORD dwNewItemsLength; BOOLEAN IsCmdConsSif; BOOLEAN IsASRSif; BOOLEAN IsWinPESif; BOOLEAN IsRecoveryOption;
//
// Resulting string should be something like:
// "D:\RemoteInstall\English\Images\nt50.wks\i386\Templates\Winnt.Sif"
dwFileNameLen = wcslen(FindData.cFileName); if (dwPathLen + dwFileNameLen - 4 > sizeof(Path) / sizeof(Path[0])) { continue; // path too long, skip it
} if (!BinlUnicodeToAnsi(FindData.cFileName, &Path[dwPathLen - 5], (USHORT)(dwFileNameLen+1) )) { continue; }
BinlPrintDbg(( DEBUG_OSC, "Found SIF File: %s\n", Path ));
//
// Check that the image is the type we are looking for
//
IsCmdConsSif = OscSifIsCmdConsA(Path); IsASRSif = OscSifIsASR(Path); IsWinPESif = OscSifIsWinPE(Path);
IsRecoveryOption = ( IsCmdConsSif || IsASRSif || IsWinPESif) ? TRUE : FALSE; if ((RecoveryOptionsOnly && !IsRecoveryOption) || (!RecoveryOptionsOnly && IsRecoveryOption)) { continue; // not readable, skip it
}
if (IsIncompatibleRiprepSIF(Path,clientState)) { //
// skip it
//
BinlPrintDbg(( DEBUG_OSC, "Skipping %s because it's an incompatible RIPREP SIF\n", Path )); continue; }
//
// Retrieve the description
//
dwErr = GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA, "Description", "", Description, DESCRIPTION_SIZE, Path );
if ( dwErr == 0 || Description[0] == L'\0' ) continue; // not readible, skip it
//
// Retrieve the help lines
//
dwErr = GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA, "Help", "", HelpLines, HELPLINES_SIZE, Path ); //
// Create the new item that look like this:
// <OPTION VALUE="sif_filename.ext" TIP="Help_Lines"> Description\r\n
//
if ( _snprintf( NewItems, sizeof(NewItems), "<OPTION VALUE=\"%s\" TIP=\"%s\"> %s\r\n", Path, HelpLines, Description ) < 0 ) { continue; // path too long, skip it
} NewItems[sizeof(NewItems)-1] = '\0';
dwNewItemsLength = strlen( NewItems );
//
// Check to see if we have to grow the buffer...
//
if ( dwNewItemsLength + dwGeneratedCurrentLength >= *dwGeneratedSize ) { //
// Grow the buffer (add in some slop too)...
//
NewScreen = BinlAllocateMemory( dwNewItemsLength + dwGeneratedCurrentLength + GENERATED_SCREEN_GROW_SIZE ); if( NewScreen == NULL ) { return ERROR_NOT_ENOUGH_SERVER_MEMORY; } memcpy( NewScreen, *GeneratedScreen, *dwGeneratedSize ); BinlFreeMemory(*GeneratedScreen); *GeneratedScreen = NewScreen; *dwGeneratedSize = dwNewItemsLength + dwGeneratedCurrentLength + GENERATED_SCREEN_GROW_SIZE; }
//
// Add the new items to the screen
//
strcat( *GeneratedScreen, NewItems ); dwGeneratedCurrentLength += dwNewItemsLength;
x++; // move to next line
}
} while (FindNextFile( hFind, (LPVOID) &FindData ));
FindClose( hFind ); } else { OscCreateWin32SubError( clientState, GetLastError( ) ); Error = ERROR_BINL_FAILED_TO_GENERATE_SCREEN; }
//
// We do this so that we only transmitted what is needed
//
// *dwGeneratedSize = dwGeneratedCurrentLength + 1; // plus 1 for the NULL character
Cleanup:
return Error; }
//
// SearchAndGenerateOSMenu()
//
DWORD SearchAndGenerateOSMenu( PCHAR *GeneratedScreen, PDWORD dwGeneratedSize, PCHAR DirToEnum, PCLIENT_STATE clientState ) { DWORD Error = ERROR_SUCCESS; DWORD err; // not a return value
WIN32_FIND_DATA FindData; HANDLE hFind; int x = 1; CHAR Path[MAX_PATH]; WCHAR UnicodePath[MAX_PATH]; BOOLEAN SearchingCmdCons;
TraceFunc("SearchAndGenerateOSMenu( )\n");
BinlAssert( *GeneratedScreen != NULL );
Error = ImpersonateSecurityContext( &clientState->ServerContextHandle ); if ( Error != STATUS_SUCCESS ) { BinlPrintDbg(( DEBUG_OSC_ERROR, "ImpersonateSecurityContext: 0x%08x\n", Error )); if ( !NT_SUCCESS(Error)) { return Error; } }
//
// Resulting string should be something like:
// "D:\RemoteInstall\Setup\English\Images\*"
//
// We special case the CMDCONS directive to search in the Images directory.
//
SearchingCmdCons = (BOOLEAN)(!_stricmp(DirToEnum, "CMDCONS")); if ( _snprintf( Path, sizeof(Path) / sizeof(Path[0]), "%s\\Setup\\%s\\%s\\*", IntelliMirrorPathA, OscFindVariableA( clientState, "LANGUAGE" ), SearchingCmdCons ? REMOTE_INSTALL_IMAGE_DIR_A : DirToEnum ) < 0 ) { Error = ERROR_BAD_PATHNAME; goto Cleanup; }
if (!BinlAnsiToUnicode(Path,UnicodePath,MAX_PATH*sizeof(WCHAR))) { Error = ERROR_BAD_PATHNAME; goto Cleanup; }
hFind = FindFirstFile( UnicodePath, (LPVOID) &FindData ); if ( hFind != INVALID_HANDLE_VALUE ) { DWORD dwPathLen = strlen( Path );
//
// Loop enumerating each subdirectory's MachineType\Templates for
// SIF files.
//
do { //
// Ignore current and parent directories, but search other
// directories.
//
if (wcscmp(FindData.cFileName, L".") && wcscmp(FindData.cFileName, L"..") && (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )) { DWORD dwFileNameLen;
//
// Add the sub-directory to the path
//
dwFileNameLen = wcslen( FindData.cFileName ); if (dwPathLen + dwFileNameLen > sizeof(Path)/sizeof(Path[0])) { continue; // path too long, skip it
}
if (!BinlUnicodeToAnsi(FindData.cFileName, &Path[dwPathLen - 1], (USHORT)(dwFileNameLen+1))) { continue; // path too long, skip it
}
BinlPrintDbg(( DEBUG_OSC, "Found OS Directory: %s\n", Path )); //
// Then enumerate the templates and add them to the menu screen
//
OscAppendTemplatesMenus( GeneratedScreen, dwGeneratedSize, Path, clientState, SearchingCmdCons ); }
} while (FindNextFile( hFind, (LPVOID) &FindData ));
FindClose( hFind ); } else { OscCreateWin32SubError( clientState, GetLastError( ) ); Error = ERROR_BINL_FAILED_TO_GENERATE_SCREEN; }
Cleanup:
err = RevertSecurityContext( &clientState->ServerContextHandle ); if ( err != STATUS_SUCCESS ) { BinlPrintDbg(( DEBUG_OSC_ERROR, "RevertSecurityContext: 0x%08x\n", Error )); OscCreateWin32SubError( clientState, err ); Error = ERROR_BINL_FAILED_TO_GENERATE_SCREEN; }
return Error; }
//
// FilterFormOptions() - for every option in this form, scan the GPO
// list for oscfilter.ini, in each one see if there is an entry in
// section [SectionName] that indicates if each option should be
// filtered out.
//
#define MAX_INI_SECTION_SIZE 512
typedef struct _FORM_OPTION { ULONG Result; PCHAR ValueName; PCHAR TagStart; ULONG TagLength; struct _FORM_OPTION * Next; } FORM_OPTION, *PFORM_OPTION;
DWORD FilterFormOptions( PCHAR OutMessage, PCHAR FilterStart, PULONG OutMessageLength, PCHAR SectionName, PCLIENT_STATE ClientState ) { PCHAR OptionStart, OptionEnd, ValueStart, ValueEnd, CurLoc; PCHAR ValueName, EqualSign; PFORM_OPTION Options = NULL, TmpOption; PCHAR IniSection = NULL; ULONG ValueLen; BOOLEAN Impersonating = FALSE; CHAR IniPath[MAX_PATH]; PGROUP_POLICY_OBJECT pGPOList = NULL, tmpGPO; DWORD Error, BytesRead, i; DWORD OptionCount = 0;
//
// First scan the form and find all the OPTION tags. For each one,
// we save a point to the value name, the location and length of the
// tag, and a place to store the current result for that tag (if
// the result is 1, then the tag stays, otherwise it is deleted).
//
CurLoc = FilterStart;
while (TRUE) {
//
// Find the next option/end-of-option/value/end-of-value
//
if (!(OptionStart = strstr(CurLoc, "<OPTION ")) || !(OptionEnd = strchr(OptionStart+1, '<' )) || !(ValueStart = StrStrIA(OptionStart, "VALUE=\""))) { break; } ValueStart += sizeof("VALUE=\"") - sizeof(""); if (!(ValueEnd = strchr(ValueStart, '\"'))) { break; } ValueLen = (ULONG)(ValueEnd - ValueStart);
//
// Allocate and fill in a FORM_OPTION for this option.
//
TmpOption = BinlAllocateMemory(sizeof(FORM_OPTION)); if (!TmpOption) { break; } TmpOption->ValueName = BinlAllocateMemory(ValueLen + 1); if (!TmpOption->ValueName) { BinlFreeMemory(TmpOption); break; }
TmpOption->Result = 1; strncpy(TmpOption->ValueName, ValueStart, ValueLen); TmpOption->ValueName[ValueLen] = '\0'; TmpOption->TagStart = OptionStart; TmpOption->TagLength = (ULONG)(OptionEnd - OptionStart);
++OptionCount;
//
// Now link it at the head of Options.
//
TmpOption->Next = Options; Options = TmpOption;
//
// Continue looking for options.
//
CurLoc = OptionEnd;
}
if (!Options) { goto Cleanup; // didn't find any, so don't bother filtering
}
//
// Now scan the GPO list.
//
Error = OscImpersonate(ClientState); if (Error != ERROR_SUCCESS) { BinlPrintDbg((DEBUG_ERRORS, "FilterFormOptions: OscImpersonate failed %lx\n", Error)); goto Cleanup; }
Impersonating = TRUE;
if (!GetGPOList(ClientState->UserToken, NULL, NULL, NULL, 0, &pGPOList)) { BinlPrintDbg((DEBUG_ERRORS, "FilterFormOptions: GetGPOList failed %lx\n", GetLastError())); goto Cleanup;
}
IniSection = BinlAllocateMemory(MAX_INI_SECTION_SIZE); if (!IniSection) { BinlPrintDbg((DEBUG_ERRORS, "FilterFormOptions: Allocate %d failed\n", MAX_INI_SECTION_SIZE)); goto Cleanup; }
for (tmpGPO = pGPOList; tmpGPO != NULL; tmpGPO = tmpGPO->pNext) {
//
// Try to open our .ini file. We read the whole section so
// that we only go over the network once.
//
#define OSCFILTER_INI_PATH "\\Microsoft\\RemoteInstall\\oscfilter.ini"
if (!BinlUnicodeToAnsi(tmpGPO->lpFileSysPath,IniPath,MAX_PATH)) { continue; } if (strlen(IniPath) + sizeof(OSCFILTER_INI_PATH) > sizeof(IniPath)/sizeof(IniPath[0])) { continue; // path too long, skip it
} strcat(IniPath, OSCFILTER_INI_PATH);
memset( IniSection, '\0', MAX_INI_SECTION_SIZE );
BytesRead = GetPrivateProfileSectionA( SectionName, IniSection, MAX_INI_SECTION_SIZE, IniPath);
if (BytesRead == 0) { BinlPrintDbg((DEBUG_POLICY, "FilterFormOptions: Could not read [%s] section in %s\n", SectionName, IniPath)); continue; }
BinlPrintDbg((DEBUG_POLICY, "FilterFormOptions: Found [%s] section in %s\n", SectionName, IniPath));
//
// GetPrivateProfileSectionA puts a NULL character after every
// option, but in fact we don't want that since we use StrStrIA
// below.
//
for (i = 0; i < BytesRead; i++) { if (IniSection[i] == '\0') { IniSection[i] = ' '; } }
//
// We have the section, now walk the list of options seeing if this
// section has something for that value name.
//
for (TmpOption = Options; TmpOption != NULL; TmpOption = TmpOption->Next) {
if ((ValueName = StrStrIA(IniSection, TmpOption->ValueName)) && (EqualSign = strchr(ValueName, '='))) { TmpOption->Result = strtol(EqualSign+1, NULL, 10); BinlPrintDbg((DEBUG_POLICY, "FilterFormOptions: Found %s = %d\n", TmpOption->ValueName, TmpOption->Result)); } } }
//
// Now we have figured out the results for all the options in the
// form, clean up the file if needed.
//
// NOTE: We rely on the fact that the option list is sorted from
// last option to first, so that when we remove an option and
// slide the rest of the file up, we don't affect any of the
// TmpOption->TagStart values that we have not yet processed.
//
for (TmpOption = Options; TmpOption != NULL; TmpOption = TmpOption->Next) {
if (TmpOption->Result == 0) {
*OutMessageLength -= TmpOption->TagLength;
memmove( TmpOption->TagStart, TmpOption->TagStart + TmpOption->TagLength, *OutMessageLength - (size_t)(TmpOption->TagStart - OutMessage));
--OptionCount;
} }
Cleanup:
if (pGPOList) { FreeGPOList(pGPOList); }
if (IniSection) { BinlFreeMemory(IniSection); }
//
// Free the options chain.
//
while (Options) { TmpOption = Options->Next; BinlFreeMemory(Options->ValueName); BinlFreeMemory(Options); Options = TmpOption; }
if (Impersonating) { OscRevert(ClientState); }
return OptionCount;
}
|