Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

647 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. menu.c
  5. Abstract:
  6. This module contains the code to process OS Chooser message
  7. for the BINL server.
  8. Author:
  9. Adam Barr (adamba) 9-Jul-1997
  10. Geoff Pease (gpease) 10-Nov-1997
  11. Environment:
  12. User Mode - Win32
  13. Revision History:
  14. --*/
  15. #include "binl.h"
  16. #pragma hdrstop
  17. BOOL
  18. IsIncompatibleRiprepSIF(
  19. PCHAR Path,
  20. PCLIENT_STATE clientState
  21. )
  22. {
  23. CHAR HalName[32];
  24. CHAR ImageType[32];
  25. PCHAR DetectedHalName;
  26. BOOL RetVal;
  27. ImageType[0] = '\0';
  28. HalName[0] = '\0';
  29. //
  30. // if it's not an RIPREP image, then just bail out.
  31. //
  32. GetPrivateProfileStringA(
  33. OSCHOOSER_SIF_SECTIONA,
  34. "ImageType",
  35. "",
  36. ImageType,
  37. sizeof(ImageType)/sizeof(ImageType[0]),
  38. Path );
  39. if (0 != StrCmpIA(ImageType,"SYSPREP")) {
  40. RetVal = FALSE;
  41. goto exit;
  42. }
  43. //
  44. // retrieve the hal name from the SIF file
  45. //
  46. GetPrivateProfileStringA(
  47. OSCHOOSER_SIF_SECTIONA,
  48. "HalName",
  49. "",
  50. HalName,
  51. sizeof(HalName)/sizeof(HalName[0]),
  52. Path );
  53. //
  54. // if the hal name isn't present, assume it's an old SIF that
  55. // doesn't have the hal type in it, and so we just return success
  56. //
  57. if (*HalName == '\0') {
  58. RetVal = FALSE;
  59. goto exit;
  60. }
  61. //
  62. // retrieve the detected HAL type from earlier
  63. //
  64. DetectedHalName = OscFindVariableA( clientState, "HALTYPE" );
  65. if (StrCmpIA(HalName,DetectedHalName)==0) {
  66. RetVal = FALSE;
  67. goto exit;
  68. }
  69. //
  70. // if we got this far, the SIF file is incompatible
  71. //
  72. RetVal = TRUE;
  73. exit:
  74. return(RetVal);
  75. }
  76. DWORD
  77. OscAppendTemplatesMenus(
  78. PCHAR *GeneratedScreen,
  79. PDWORD dwGeneratedSize,
  80. PCHAR DirToEnum,
  81. PCLIENT_STATE clientState,
  82. BOOLEAN RecoveryOptionsOnly
  83. )
  84. {
  85. DWORD Error = ERROR_SUCCESS;
  86. WIN32_FIND_DATA FindData;
  87. HANDLE hFind;
  88. int x = 1;
  89. CHAR Path[MAX_PATH];
  90. WCHAR UnicodePath[MAX_PATH];
  91. DWORD dwGeneratedCurrentLength;
  92. TraceFunc("OscAppendTemplatesMenus( )\n");
  93. BinlAssert( *GeneratedScreen != NULL );
  94. //
  95. // The incoming size is the current length of the buffer
  96. //
  97. dwGeneratedCurrentLength = *dwGeneratedSize;
  98. // Resulting string should be something like:
  99. // "D:\RemoteInstall\English\Images\nt50.wks\i386\Templates\*.sif"
  100. if ( _snprintf( Path,
  101. sizeof(Path) / sizeof(Path[0]),
  102. "%s\\%s\\Templates\\*.sif",
  103. DirToEnum,
  104. OscFindVariableA( clientState, "MACHINETYPE" )
  105. ) == -1 ) {
  106. Error = ERROR_BAD_PATHNAME;
  107. goto Cleanup;
  108. }
  109. mbstowcs( UnicodePath, Path, strlen(Path) + 1 );
  110. BinlPrintDbg(( DEBUG_OSC, "Enumerating: %s\n", Path ));
  111. hFind = FindFirstFile( UnicodePath, (LPVOID) &FindData );
  112. if ( hFind != INVALID_HANDLE_VALUE )
  113. {
  114. DWORD dwPathLen;
  115. dwPathLen = strlen( Path );
  116. do {
  117. //
  118. // If it is not a directory, try to open it
  119. //
  120. if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  121. {
  122. CHAR Description[DESCRIPTION_SIZE];
  123. CHAR HelpLines[HELPLINES_SIZE];
  124. PCHAR NewScreen; // temporary points to newly generated screen
  125. DWORD dwErr;
  126. DWORD dwFileNameLen;
  127. CHAR NewItems[ MAX_PATH * 2 + 512 ]; // arbitrary size
  128. DWORD dwNewItemsLength;
  129. BOOLEAN IsCmdConsSif;
  130. BOOLEAN IsASRSif;
  131. BOOLEAN IsRecoveryOption;
  132. //
  133. // Resulting string should be something like:
  134. // "D:\RemoteInstall\English\Images\nt50.wks\i386\Templates\Winnt.Sif"
  135. dwFileNameLen = wcslen(FindData.cFileName);
  136. if (dwPathLen + dwFileNameLen - 4 > sizeof(Path) / sizeof(Path[0])) {
  137. continue; // path too long, skip it
  138. }
  139. wcstombs( &Path[dwPathLen - 5], FindData.cFileName, dwFileNameLen + 1 );
  140. BinlPrintDbg(( DEBUG_OSC, "Found SIF File: %s\n", Path ));
  141. //
  142. // Check that the image is the type we are looking for
  143. //
  144. IsCmdConsSif = OscSifIsCmdConsA(Path);
  145. IsASRSif = OscSifIsASR(Path);
  146. IsRecoveryOption = ( IsCmdConsSif || IsASRSif )
  147. ? TRUE
  148. : FALSE;
  149. if ((RecoveryOptionsOnly && !IsRecoveryOption) ||
  150. (!RecoveryOptionsOnly && IsRecoveryOption)) {
  151. continue; // not readable, skip it
  152. }
  153. if (IsIncompatibleRiprepSIF(Path,clientState)) {
  154. //
  155. // skip it
  156. //
  157. BinlPrintDbg((
  158. DEBUG_OSC,
  159. "Skipping %s because it's an incompatible RIPREP SIF\n",
  160. Path ));
  161. continue;
  162. }
  163. //
  164. // Retrieve the description
  165. //
  166. dwErr = GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
  167. "Description",
  168. "",
  169. Description,
  170. DESCRIPTION_SIZE,
  171. Path
  172. );
  173. if ( dwErr == 0 || Description[0] == L'\0' )
  174. continue; // not readible, skip it
  175. //
  176. // Retrieve the help lines
  177. //
  178. dwErr = GetPrivateProfileStringA(OSCHOOSER_SIF_SECTIONA,
  179. "Help",
  180. "",
  181. HelpLines,
  182. HELPLINES_SIZE,
  183. Path
  184. );
  185. //
  186. // Create the new item that look like this:
  187. // <OPTION VALUE="sif_filename.ext" TIP="Help_Lines"> Description\r\n
  188. //
  189. if ( _snprintf( NewItems,
  190. sizeof(NewItems) / sizeof(NewItems[0]),
  191. "<OPTION VALUE=\"%s\" TIP=\"%s\"> %s\r\n",
  192. Path,
  193. HelpLines,
  194. Description
  195. ) == -1 ) {
  196. continue; // path too long, skip it
  197. }
  198. dwNewItemsLength = strlen( NewItems );
  199. //
  200. // Check to see if we have to grow the buffer...
  201. //
  202. if ( dwNewItemsLength + dwGeneratedCurrentLength >= *dwGeneratedSize )
  203. {
  204. //
  205. // Grow the buffer (add in some slop too)...
  206. //
  207. NewScreen = BinlAllocateMemory( dwNewItemsLength + dwGeneratedCurrentLength + GENERATED_SCREEN_GROW_SIZE );
  208. if( NewScreen == NULL ) {
  209. return ERROR_NOT_ENOUGH_SERVER_MEMORY;
  210. }
  211. memcpy( NewScreen, *GeneratedScreen, *dwGeneratedSize );
  212. BinlFreeMemory(*GeneratedScreen);
  213. *GeneratedScreen = NewScreen;
  214. *dwGeneratedSize = dwNewItemsLength + dwGeneratedCurrentLength + GENERATED_SCREEN_GROW_SIZE;
  215. }
  216. //
  217. // Add the new items to the screen
  218. //
  219. strcat( *GeneratedScreen, NewItems );
  220. dwGeneratedCurrentLength += dwNewItemsLength;
  221. x++; // move to next line
  222. }
  223. } while (FindNextFile( hFind, (LPVOID) &FindData ));
  224. FindClose( hFind );
  225. }
  226. else
  227. {
  228. OscCreateWin32SubError( clientState, GetLastError( ) );
  229. Error = ERROR_BINL_FAILED_TO_GENERATE_SCREEN;
  230. }
  231. //
  232. // We do this so that we only transmitted what is needed
  233. //
  234. // *dwGeneratedSize = dwGeneratedCurrentLength + 1; // plus 1 for the NULL character
  235. Cleanup:
  236. return Error;
  237. }
  238. //
  239. // SearchAndGenerateOSMenu()
  240. //
  241. DWORD
  242. SearchAndGenerateOSMenu(
  243. PCHAR *GeneratedScreen,
  244. PDWORD dwGeneratedSize,
  245. PCHAR DirToEnum,
  246. PCLIENT_STATE clientState )
  247. {
  248. DWORD Error = ERROR_SUCCESS;
  249. DWORD err; // not a return value
  250. WIN32_FIND_DATA FindData;
  251. HANDLE hFind;
  252. int x = 1;
  253. CHAR Path[MAX_PATH];
  254. WCHAR UnicodePath[MAX_PATH];
  255. BOOLEAN SearchingCmdCons;
  256. TraceFunc("SearchAndGenerateOSMenu( )\n");
  257. BinlAssert( *GeneratedScreen != NULL );
  258. Error = ImpersonateSecurityContext( &clientState->ServerContextHandle );
  259. if ( Error != STATUS_SUCCESS ) {
  260. BinlPrintDbg(( DEBUG_OSC_ERROR, "ImpersonateSecurityContext: 0x%08x\n", Error ));
  261. if ( !NT_SUCCESS(Error)) {
  262. return Error;
  263. }
  264. }
  265. //
  266. // Resulting string should be something like:
  267. // "D:\RemoteInstall\Setup\English\Images\*"
  268. //
  269. // We special case the CMDCONS directive to search in the Images directory.
  270. //
  271. SearchingCmdCons = (BOOLEAN)(!_stricmp(DirToEnum, "CMDCONS"));
  272. if ( _snprintf( Path,
  273. sizeof(Path) / sizeof(Path[0]),
  274. "%s\\Setup\\%s\\%s\\*",
  275. IntelliMirrorPathA,
  276. OscFindVariableA( clientState, "LANGUAGE" ),
  277. SearchingCmdCons ? REMOTE_INSTALL_IMAGE_DIR_A :
  278. DirToEnum
  279. ) == -1 ) {
  280. Error = ERROR_BAD_PATHNAME;
  281. goto Cleanup;
  282. }
  283. mbstowcs( UnicodePath, Path, strlen(Path) + 1 );
  284. hFind = FindFirstFile( UnicodePath, (LPVOID) &FindData );
  285. if ( hFind != INVALID_HANDLE_VALUE )
  286. {
  287. DWORD dwPathLen = strlen( Path );
  288. //
  289. // Loop enumerating each subdirectory's MachineType\Templates for
  290. // SIF files.
  291. //
  292. do {
  293. //
  294. // Ignore current and parent directories, but search other
  295. // directories.
  296. //
  297. if (wcscmp(FindData.cFileName, L".") &&
  298. wcscmp(FindData.cFileName, L"..") &&
  299. (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ))
  300. {
  301. DWORD dwFileNameLen;
  302. //
  303. // Add the sub-directory to the path
  304. //
  305. dwFileNameLen = wcslen( FindData.cFileName );
  306. if (dwPathLen + dwFileNameLen > sizeof(Path)/sizeof(Path[0])) {
  307. continue; // path too long, skip it
  308. }
  309. wcstombs( &Path[dwPathLen - 1] , FindData.cFileName, dwFileNameLen + 1);
  310. BinlPrintDbg(( DEBUG_OSC, "Found OS Directory: %s\n", Path ));
  311. //
  312. // Then enumerate the templates and add them to the menu screen
  313. //
  314. OscAppendTemplatesMenus( GeneratedScreen,
  315. dwGeneratedSize,
  316. Path,
  317. clientState,
  318. SearchingCmdCons
  319. );
  320. }
  321. } while (FindNextFile( hFind, (LPVOID) &FindData ));
  322. FindClose( hFind );
  323. }
  324. else
  325. {
  326. OscCreateWin32SubError( clientState, GetLastError( ) );
  327. Error = ERROR_BINL_FAILED_TO_GENERATE_SCREEN;
  328. }
  329. Cleanup:
  330. err = RevertSecurityContext( &clientState->ServerContextHandle );
  331. if ( err != STATUS_SUCCESS ) {
  332. BinlPrintDbg(( DEBUG_OSC_ERROR, "RevertSecurityContext: 0x%08x\n", Error ));
  333. OscCreateWin32SubError( clientState, err );
  334. Error = ERROR_BINL_FAILED_TO_GENERATE_SCREEN;
  335. }
  336. return Error;
  337. }
  338. //
  339. // FilterFormOptions() - for every option in this form, scan the GPO
  340. // list for oscfilter.ini, in each one see if there is an entry in
  341. // section [SectionName] that indicates if each option should be
  342. // filtered out.
  343. //
  344. #define MAX_INI_SECTION_SIZE 512
  345. typedef struct _FORM_OPTION {
  346. ULONG Result;
  347. PCHAR ValueName;
  348. PCHAR TagStart;
  349. ULONG TagLength;
  350. struct _FORM_OPTION * Next;
  351. } FORM_OPTION, *PFORM_OPTION;
  352. DWORD
  353. FilterFormOptions(
  354. PCHAR OutMessage,
  355. PCHAR FilterStart,
  356. PULONG OutMessageLength,
  357. PCHAR SectionName,
  358. PCLIENT_STATE ClientState )
  359. {
  360. PCHAR OptionStart, OptionEnd, ValueStart, ValueEnd, CurLoc;
  361. PCHAR ValueName, EqualSign;
  362. PFORM_OPTION Options = NULL, TmpOption;
  363. PCHAR IniSection = NULL;
  364. ULONG ValueLen;
  365. BOOLEAN Impersonating = FALSE;
  366. CHAR IniPath[MAX_PATH];
  367. PGROUP_POLICY_OBJECT pGPOList = NULL, tmpGPO;
  368. DWORD Error, BytesRead, i;
  369. DWORD OptionCount = 0;
  370. //
  371. // First scan the form and find all the OPTION tags. For each one,
  372. // we save a point to the value name, the location and length of the
  373. // tag, and a place to store the current result for that tag (if
  374. // the result is 1, then the tag stays, otherwise it is deleted).
  375. //
  376. CurLoc = FilterStart;
  377. while (TRUE) {
  378. //
  379. // Find the next option/end-of-option/value/end-of-value
  380. //
  381. if (!(OptionStart = StrStrIA(CurLoc, "<OPTION ")) ||
  382. !(OptionEnd = StrChrA(OptionStart+1, '<' )) ||
  383. !(ValueStart = StrStrIA(OptionStart, "VALUE=\""))) {
  384. break;
  385. }
  386. ValueStart += sizeof("VALUE=\"") - sizeof("");
  387. if (!(ValueEnd = StrChrA(ValueStart, '\"'))) {
  388. break;
  389. }
  390. ValueLen = (ULONG)(ValueEnd - ValueStart);
  391. //
  392. // Allocate and fill in a FORM_OPTION for this option.
  393. //
  394. TmpOption = BinlAllocateMemory(sizeof(FORM_OPTION));
  395. if (!TmpOption) {
  396. break;
  397. }
  398. TmpOption->ValueName = BinlAllocateMemory(ValueLen + 1);
  399. if (!TmpOption->ValueName) {
  400. BinlFreeMemory(TmpOption);
  401. break;
  402. }
  403. TmpOption->Result = 1;
  404. strncpy(TmpOption->ValueName, ValueStart, ValueLen);
  405. TmpOption->ValueName[ValueLen] = '\0';
  406. TmpOption->TagStart = OptionStart;
  407. TmpOption->TagLength = (ULONG)(OptionEnd - OptionStart);
  408. ++OptionCount;
  409. //
  410. // Now link it at the head of Options.
  411. //
  412. TmpOption->Next = Options;
  413. Options = TmpOption;
  414. //
  415. // Continue looking for options.
  416. //
  417. CurLoc = OptionEnd;
  418. }
  419. if (!Options) {
  420. goto Cleanup; // didn't find any, so don't bother filtering
  421. }
  422. //
  423. // Now scan the GPO list.
  424. //
  425. Error = OscImpersonate(ClientState);
  426. if (Error != ERROR_SUCCESS) {
  427. BinlPrintDbg((DEBUG_ERRORS,
  428. "FilterFormOptions: OscImpersonate failed %lx\n", Error));
  429. goto Cleanup;
  430. }
  431. Impersonating = TRUE;
  432. if (!GetGPOList(ClientState->UserToken, NULL, NULL, NULL, 0, &pGPOList)) {
  433. BinlPrintDbg((DEBUG_ERRORS,
  434. "FilterFormOptions: GetGPOList failed %lx\n", GetLastError()));
  435. goto Cleanup;
  436. }
  437. IniSection = BinlAllocateMemory(MAX_INI_SECTION_SIZE);
  438. if (!IniSection) {
  439. BinlPrintDbg((DEBUG_ERRORS,
  440. "FilterFormOptions: Allocate %d failed\n", MAX_INI_SECTION_SIZE));
  441. goto Cleanup;
  442. }
  443. for (tmpGPO = pGPOList; tmpGPO != NULL; tmpGPO = tmpGPO->pNext) {
  444. //
  445. // Try to open our .ini file. We read the whole section so
  446. // that we only go over the network once.
  447. //
  448. #define OSCFILTER_INI_PATH "\\Microsoft\\RemoteInstall\\oscfilter.ini"
  449. wcstombs(IniPath, tmpGPO->lpFileSysPath, wcslen(tmpGPO->lpFileSysPath) + 1);
  450. if (strlen(IniPath) + sizeof(OSCFILTER_INI_PATH) > sizeof(IniPath)/sizeof(IniPath[0])) {
  451. continue; // path too long, skip it
  452. }
  453. strcat(IniPath, OSCFILTER_INI_PATH);
  454. memset( IniSection, '\0', MAX_INI_SECTION_SIZE );
  455. BytesRead = GetPrivateProfileSectionA(
  456. SectionName,
  457. IniSection,
  458. MAX_INI_SECTION_SIZE,
  459. IniPath);
  460. if (BytesRead == 0) {
  461. BinlPrintDbg((DEBUG_POLICY,
  462. "FilterFormOptions: Could not read [%s] section in %s\n", SectionName, IniPath));
  463. continue;
  464. }
  465. BinlPrintDbg((DEBUG_POLICY,
  466. "FilterFormOptions: Found [%s] section in %s\n", SectionName, IniPath));
  467. //
  468. // GetPrivateProfileSectionA puts a NULL character after every
  469. // option, but in fact we don't want that since we use StrStrIA
  470. // below.
  471. //
  472. for (i = 0; i < BytesRead; i++) {
  473. if (IniSection[i] == '\0') {
  474. IniSection[i] = ' ';
  475. }
  476. }
  477. //
  478. // We have the section, now walk the list of options seeing if this
  479. // section has something for that value name.
  480. //
  481. for (TmpOption = Options; TmpOption != NULL; TmpOption = TmpOption->Next) {
  482. if ((ValueName = StrStrIA(IniSection, TmpOption->ValueName)) &&
  483. (EqualSign = StrChrA(ValueName, '='))) {
  484. TmpOption->Result = strtol(EqualSign+1, NULL, 10);
  485. BinlPrintDbg((DEBUG_POLICY,
  486. "FilterFormOptions: Found %s = %d\n", TmpOption->ValueName, TmpOption->Result));
  487. }
  488. }
  489. }
  490. //
  491. // Now we have figured out the results for all the options in the
  492. // form, clean up the file if needed.
  493. //
  494. // NOTE: We rely on the fact that the option list is sorted from
  495. // last option to first, so that when we remove an option and
  496. // slide the rest of the file up, we don't affect any of the
  497. // TmpOption->TagStart values that we have not yet processed.
  498. //
  499. for (TmpOption = Options; TmpOption != NULL; TmpOption = TmpOption->Next) {
  500. if (TmpOption->Result == 0) {
  501. *OutMessageLength -= TmpOption->TagLength;
  502. memmove(
  503. TmpOption->TagStart,
  504. TmpOption->TagStart + TmpOption->TagLength,
  505. *OutMessageLength - (size_t)(TmpOption->TagStart - OutMessage));
  506. --OptionCount;
  507. }
  508. }
  509. Cleanup:
  510. if (pGPOList) {
  511. FreeGPOList(pGPOList);
  512. }
  513. if (IniSection) {
  514. BinlFreeMemory(IniSection);
  515. }
  516. //
  517. // Free the options chain.
  518. //
  519. while (Options) {
  520. TmpOption = Options->Next;
  521. BinlFreeMemory(Options->ValueName);
  522. BinlFreeMemory(Options);
  523. Options = TmpOption;
  524. }
  525. if (Impersonating) {
  526. OscRevert(ClientState);
  527. }
  528. return OptionCount;
  529. }