Leaked source code of windows server 2003
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.

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