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.

2231 lines
49 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. util.c
  5. Abstract:
  6. Implementation of general utility functions.
  7. Author:
  8. Wesley Witt (wesw) 18-Dec-1998
  9. Revision History:
  10. Andrew Ritz (andrewr) 6-Jul-1999 : added comments
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. //
  15. // use this define to force path redirections
  16. //
  17. //#define SFC_REDIRECTOR_TEST
  18. #define CONST_UNICODE_STRING(sz) { sizeof(sz) - 1, sizeof(sz), sz }
  19. #ifndef _WIN64
  20. typedef struct _SFC_EXPAND_TRANSLATION_ENTRY
  21. {
  22. LPCWSTR Src; // full path to translate from (does not end in \\)
  23. LPCWSTR Dest; // full path to translate to
  24. ULONG ExceptionCount; // count of elements in Exceptions
  25. const UNICODE_STRING* Exceptions; // array of excepted paths, relative to Src (begins with \\ but does not end in \\)
  26. }
  27. SFC_EXPAND_TRANSLATION_ENTRY;
  28. typedef struct _SFC_TRANSLATION_ENTRY
  29. {
  30. UNICODE_STRING Src;
  31. UNICODE_STRING Dest;
  32. }
  33. SFC_TRANSLATION_ENTRY;
  34. //
  35. // exception lists; relative paths with no environment variables
  36. //
  37. static const UNICODE_STRING SfcSystem32Exceptions[] =
  38. {
  39. CONST_UNICODE_STRING(L"\\drivers\\etc"),
  40. CONST_UNICODE_STRING(L"\\spool"),
  41. CONST_UNICODE_STRING(L"\\catroot"),
  42. CONST_UNICODE_STRING(L"\\catroot2")
  43. };
  44. //
  45. // translation table that is expanded into SfcTranslations
  46. //
  47. static const SFC_EXPAND_TRANSLATION_ENTRY SfcExpandTranslations[] =
  48. {
  49. { L"%windir%\\system32", L"%windir%\\syswow64", ARRAY_LENGTH(SfcSystem32Exceptions), SfcSystem32Exceptions },
  50. { L"%windir%\\ime", L"%windir%\\ime (x86)", 0, NULL },
  51. { L"%windir%\\regedit.exe", L"%windir%\\syswow64\\regedit.exe", 0, NULL }
  52. };
  53. //
  54. // translation table with expanded strings
  55. //
  56. static SFC_TRANSLATION_ENTRY* SfcTranslations = NULL;
  57. //
  58. // this guards the initialization of SfcTranslations
  59. //
  60. static RTL_CRITICAL_SECTION SfcTranslatorCs;
  61. static BOOL SfcNeedTranslation = FALSE;
  62. static BOOL SfcIsTranslatorInitialized = FALSE;
  63. #endif // _WIN64
  64. PVOID
  65. SfcGetProcAddress(
  66. HMODULE hModule,
  67. LPSTR ProcName
  68. )
  69. /*++
  70. Routine Description:
  71. Gets the address of the specified function.
  72. Arguments:
  73. hModule - Module handle returned from LdrLoadDll.
  74. ProcName - Procedure name
  75. Return Value:
  76. NULL if the function does not exist.
  77. Valid address is the function is found.
  78. --*/
  79. {
  80. NTSTATUS Status;
  81. PVOID ProcedureAddress;
  82. STRING ProcedureName;
  83. ASSERT((hModule != NULL) && (ProcName != NULL));
  84. RtlInitString(&ProcedureName,ProcName);
  85. Status = LdrGetProcedureAddress(
  86. hModule,
  87. &ProcedureName,
  88. 0,
  89. &ProcedureAddress
  90. );
  91. if (!NT_SUCCESS(Status)) {
  92. DebugPrint2( LVL_MINIMAL, L"GetProcAddress failed for %S, ec=%lx", ProcName, Status );
  93. return NULL;
  94. }
  95. return ProcedureAddress;
  96. }
  97. HMODULE
  98. SfcLoadLibrary(
  99. IN PCWSTR LibFileName
  100. )
  101. /*++
  102. Routine Description:
  103. Loads the specified DLL into session manager's
  104. address space and return the loaded DLL's address.
  105. Arguments:
  106. LibFileName - Name of the desired DLL
  107. Return Value:
  108. NULL if the DLL cannot be loaded.
  109. Valid address is the DLL is loaded.
  110. --*/
  111. {
  112. NTSTATUS Status;
  113. HMODULE hModule;
  114. UNICODE_STRING DllName_U;
  115. ASSERT(LibFileName);
  116. RtlInitUnicodeString( &DllName_U, LibFileName );
  117. Status = LdrLoadDll(
  118. NULL,
  119. NULL,
  120. &DllName_U,
  121. (PVOID *)&hModule
  122. );
  123. if (!NT_SUCCESS( Status )) {
  124. DebugPrint2( LVL_MINIMAL, L"LoadDll failed for %ws, ec=%lx", LibFileName, Status );
  125. return NULL;
  126. }
  127. return hModule;
  128. }
  129. PVOID
  130. MemAlloc(
  131. SIZE_T AllocSize
  132. )
  133. /*++
  134. Routine Description:
  135. Allocates the specified number of bytes using the default process heap.
  136. Arguments:
  137. AllocSize - size in bytes of memory to be allocated
  138. Return Value:
  139. pointer to allocated memory or NULL for failure.
  140. --*/
  141. {
  142. return RtlAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, AllocSize );
  143. }
  144. PVOID
  145. MemReAlloc(
  146. SIZE_T AllocSize,
  147. PVOID OrigPtr
  148. )
  149. /*++
  150. Routine Description:
  151. ReAllocates the specified number of bytes using the default process heap.
  152. Arguments:
  153. AllocSize - size in bytes of memory to be reallocated
  154. OrigPtr - original heap memory pointer
  155. Return Value:
  156. pointer to allocated memory or NULL for failure.
  157. --*/
  158. {
  159. PVOID ptr;
  160. ptr = RtlReAllocateHeap( RtlProcessHeap(), HEAP_ZERO_MEMORY, OrigPtr, AllocSize );
  161. if (!ptr) {
  162. DebugPrint1( LVL_MINIMAL, L"MemReAlloc [%d bytes] failed", AllocSize );
  163. }
  164. return(ptr);
  165. }
  166. VOID
  167. MemFree(
  168. PVOID MemPtr
  169. )
  170. /*++
  171. Routine Description:
  172. Free's the memory at the specified location from the default process heap.
  173. Arguments:
  174. MemPtr - pointer to memory to be freed. If NULL, no action is taken.
  175. Return Value:
  176. none.
  177. --*/
  178. {
  179. if (MemPtr) {
  180. RtlFreeHeap( RtlProcessHeap(), 0, MemPtr );
  181. }
  182. }
  183. void
  184. SfcWriteDebugLog(
  185. IN LPCSTR String,
  186. IN ULONG Length OPTIONAL
  187. )
  188. {
  189. NTSTATUS Status;
  190. OBJECT_ATTRIBUTES Attrs;
  191. UNICODE_STRING FileName;
  192. IO_STATUS_BLOCK iosb;
  193. HANDLE hFile;
  194. ASSERT(String != NULL);
  195. if(RtlDosPathNameToNtPathName_U(g_szLogFile, &FileName, NULL, NULL))
  196. {
  197. InitializeObjectAttributes(&Attrs, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
  198. Status = NtCreateFile(
  199. &hFile,
  200. FILE_APPEND_DATA | SYNCHRONIZE,
  201. &Attrs,
  202. &iosb,
  203. NULL,
  204. FILE_ATTRIBUTE_NORMAL,
  205. FILE_SHARE_READ,
  206. FILE_OPEN_IF,
  207. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY,
  208. NULL,
  209. 0
  210. );
  211. MemFree(FileName.Buffer);
  212. if(!NT_SUCCESS(Status))
  213. {
  214. #if DBG
  215. DbgPrint("Could not open the log file.\r\n");
  216. #endif
  217. return;
  218. }
  219. if(0 == Length)
  220. Length = strlen(String);
  221. Status = NtWriteFile(hFile, NULL, NULL, NULL, &iosb, (PVOID) String, Length, NULL, NULL);
  222. NtClose(hFile);
  223. #if DBG
  224. if(!NT_SUCCESS(Status))
  225. DbgPrint("Could not write the log file.\r\n");
  226. #endif
  227. }
  228. }
  229. #define CHECK_DEBUG_LEVEL(var, l) ((var) != LVL_SILENT && (l) <= (var))
  230. void
  231. dprintf(
  232. IN ULONG Level,
  233. IN PCWSTR FileName,
  234. IN ULONG LineNumber,
  235. IN PCWSTR FormatStr,
  236. IN ...
  237. )
  238. /*++
  239. Routine Description:
  240. Main debugger output routine. Callers should use the DebugPrintX macro,
  241. which is compiled out in the retail version of the product
  242. Arguments:
  243. Level - indicates a LVL_ severity level so the amount of output can be
  244. controlled.
  245. FileName - string indicating the filename the debug comes from
  246. LineNumber - indicates the line number of the debug output.
  247. FormatStr - indicates the data to be output
  248. Return Value:
  249. none.
  250. --*/
  251. {
  252. static WCHAR buf[4096];
  253. static CHAR str[4096];
  254. va_list arg_ptr;
  255. ULONG Bytes;
  256. PWSTR p;
  257. SYSTEMTIME CurrTime;
  258. #if DBG
  259. if(!CHECK_DEBUG_LEVEL(SFCDebugDump, Level) && !CHECK_DEBUG_LEVEL(SFCDebugLog, Level))
  260. return;
  261. #else
  262. if(!CHECK_DEBUG_LEVEL(SFCDebugLog, Level))
  263. return;
  264. #endif
  265. GetLocalTime( &CurrTime );
  266. try {
  267. p = buf + swprintf( buf, L"SFC: %02d:%02d:%02d.%03d ",
  268. CurrTime.wHour,
  269. CurrTime.wMinute,
  270. CurrTime.wSecond,
  271. CurrTime.wMilliseconds
  272. );
  273. #if DBG
  274. if (FileName && LineNumber) {
  275. PWSTR s;
  276. s = wcsrchr( FileName, L'\\' );
  277. if (s) {
  278. p += swprintf( p, L"%12s @ %4d ", s+1, LineNumber );
  279. }
  280. }
  281. #else
  282. //
  283. // put only the line number in output
  284. //
  285. p += swprintf(p, L"@ %4d ", LineNumber);
  286. #endif
  287. va_start( arg_ptr, FormatStr );
  288. p += _vsnwprintf( p, 2048, FormatStr, arg_ptr );
  289. va_end( arg_ptr );
  290. wcscpy( p, L"\r\n" );
  291. p += wcslen(p);
  292. } except(EXCEPTION_EXECUTE_HANDLER) {
  293. return;
  294. }
  295. Bytes = (ULONG)(p - buf);
  296. WideCharToMultiByte(
  297. CP_ACP,
  298. 0,
  299. buf,
  300. Bytes + 1, // include the null
  301. str,
  302. sizeof(str),
  303. NULL,
  304. NULL
  305. );
  306. #if DBG
  307. if(CHECK_DEBUG_LEVEL(SFCDebugDump, Level))
  308. DbgPrint( str );
  309. if(CHECK_DEBUG_LEVEL(SFCDebugLog, Level))
  310. SfcWriteDebugLog(str, Bytes);
  311. #else
  312. SfcWriteDebugLog(str, Bytes);
  313. #endif
  314. }
  315. #if DBG
  316. UCHAR HandleBuffer[1024*64];
  317. VOID
  318. PrintHandleCount(
  319. PCWSTR str
  320. )
  321. /*++
  322. Routine Description:
  323. Outputs the handle count for the current process to the debugger. Use
  324. this call before and after a function to look for handle leaks (the input
  325. string can help you identify where you are checking the handle count.)
  326. Arguments:
  327. str - null terminated unicode string that prefaces the debug spew
  328. Return Value:
  329. none. Debug routine only.
  330. --*/
  331. {
  332. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  333. NTSTATUS Status;
  334. ULONG TotalOffset;
  335. //
  336. // get the system process information
  337. //
  338. Status = NtQuerySystemInformation(
  339. SystemProcessInformation,
  340. HandleBuffer,
  341. sizeof(HandleBuffer),
  342. NULL
  343. );
  344. if (NT_SUCCESS(Status)) {
  345. //
  346. // find our process and spew the handle count
  347. //
  348. TotalOffset = 0;
  349. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)HandleBuffer;
  350. while(1) {
  351. if ((DWORD_PTR)ProcessInfo->UniqueProcessId == (ULONG_PTR)NtCurrentTeb()->ClientId.UniqueProcess) {
  352. DebugPrint2( LVL_MINIMAL, L"%ws: handle count = %d", str, ProcessInfo->HandleCount );
  353. break;
  354. }
  355. if (ProcessInfo->NextEntryOffset == 0) {
  356. break;
  357. }
  358. TotalOffset += ProcessInfo->NextEntryOffset;
  359. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&HandleBuffer[TotalOffset];
  360. }
  361. }
  362. }
  363. #endif
  364. DWORD
  365. MyMessageBox(
  366. HWND hwndParent, OPTIONAL
  367. DWORD ResId,
  368. DWORD MsgBoxType,
  369. ...
  370. )
  371. /*++
  372. Routine Description:
  373. Messagebox wrapper that retreives a string table resource id and creates a
  374. popup for the given message.
  375. Arguments:
  376. hwndParent - handle to parent window
  377. ResId - resource id of string to be loaded
  378. MsgBoxType - MB_* constant
  379. Return Value:
  380. Win32 error code indicating outcome
  381. --*/
  382. {
  383. static WCHAR Title[128] = { L"\0" };
  384. WCHAR Tmp1[MAX_PATH*2];
  385. WCHAR Tmp2[MAX_PATH*2];
  386. PWSTR Text = NULL;
  387. PWSTR s;
  388. va_list arg_ptr;
  389. int Size;
  390. //
  391. // SFCNoPopUps is a policy setting that can be set
  392. //
  393. if (SFCNoPopUps) {
  394. return(0);
  395. }
  396. //
  397. // load the title string
  398. //
  399. if (!Title[0]) {
  400. Size = LoadString(
  401. SfcInstanceHandle,
  402. IDS_TITLE,
  403. Title,
  404. UnicodeChars(Title)
  405. );
  406. if (Size == 0) {
  407. return(0);
  408. }
  409. }
  410. //
  411. // load the message string
  412. //
  413. Size = LoadString(
  414. SfcInstanceHandle,
  415. ResId,
  416. Tmp1,
  417. UnicodeChars(Tmp1)
  418. );
  419. if (Size == 0) {
  420. return(0);
  421. }
  422. //
  423. // inplace substitution can occur here
  424. //
  425. s = wcschr( Tmp1, L'%' );
  426. if (s) {
  427. va_start( arg_ptr, MsgBoxType );
  428. _vsnwprintf( Tmp2, sizeof(Tmp2)/sizeof(WCHAR), Tmp1, arg_ptr );
  429. va_end( arg_ptr );
  430. Text = Tmp2;
  431. } else {
  432. Text = Tmp1;
  433. }
  434. //
  435. // actually call messagebox now
  436. //
  437. return MessageBox(
  438. hwndParent,
  439. Text,
  440. Title,
  441. (MsgBoxType | MB_TOPMOST) & ~MB_DEFAULT_DESKTOP_ONLY
  442. );
  443. }
  444. BOOL
  445. EnablePrivilege(
  446. IN PCTSTR PrivilegeName,
  447. IN BOOL Enable
  448. )
  449. /*++
  450. Routine Description:
  451. Enable or disable a given named privilege.
  452. Arguments:
  453. PrivilegeName - supplies the name of a system privilege.
  454. Enable - flag indicating whether to enable or disable the privilege.
  455. Return Value:
  456. Boolean value indicating whether the operation was successful.
  457. --*/
  458. {
  459. HANDLE Token;
  460. BOOL b;
  461. TOKEN_PRIVILEGES NewPrivileges;
  462. LUID Luid;
  463. if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
  464. return(FALSE);
  465. }
  466. if(!LookupPrivilegeValue(NULL,PrivilegeName,&Luid)) {
  467. CloseHandle(Token);
  468. return(FALSE);
  469. }
  470. NewPrivileges.PrivilegeCount = 1;
  471. NewPrivileges.Privileges[0].Luid = Luid;
  472. NewPrivileges.Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  473. b = AdjustTokenPrivileges(
  474. Token,
  475. FALSE,
  476. &NewPrivileges,
  477. 0,
  478. NULL,
  479. NULL
  480. );
  481. CloseHandle(Token);
  482. return(b);
  483. }
  484. void
  485. MyLowerString(
  486. IN PWSTR String,
  487. IN ULONG StringLength // in characters
  488. )
  489. /*++
  490. Routine Description:
  491. lowercase the specified string.
  492. Arguments:
  493. String - supplies string to lowercase
  494. StringLength - length in chars of string to be lowercased
  495. Return Value:
  496. none.
  497. --*/
  498. {
  499. ULONG i;
  500. ASSERT(String != NULL);
  501. for (i=0; i<StringLength; i++) {
  502. String[i] = towlower(String[i]);
  503. }
  504. }
  505. #ifdef SFCLOGFILE
  506. void
  507. SfcLogFileWrite(
  508. IN DWORD StrId,
  509. IN ...
  510. )
  511. /*++
  512. Routine Description:
  513. Output the string table resource id as specified to the sfc logfile.
  514. This logfile is used to record files that have been restored on the system.
  515. This way, an installer can know if packages are attempting to install
  516. system components.
  517. The logfile is a unicode text file of the format:
  518. <TIME> <FILENAME>
  519. We need to record the full path of the file plus the date for this to
  520. be more useful.
  521. Arguments:
  522. StrId - supplies resource id to load.
  523. Return Value:
  524. none.
  525. --*/
  526. {
  527. static WCHAR buf[4096];
  528. static HANDLE hFile = INVALID_HANDLE_VALUE;
  529. WCHAR str[128];
  530. va_list arg_ptr;
  531. ULONG Bytes;
  532. PWSTR p;
  533. SYSTEMTIME CurrTime;
  534. GetSystemTime( &CurrTime );
  535. if (hFile == INVALID_HANDLE_VALUE) {
  536. ExpandEnvironmentStrings( L"%systemroot%\\sfclog.txt", buf, UnicodeChars(buf) );
  537. hFile = CreateFile(
  538. buf,
  539. GENERIC_READ | GENERIC_WRITE,
  540. FILE_SHARE_READ,
  541. NULL,
  542. OPEN_ALWAYS,
  543. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
  544. NULL
  545. );
  546. if (hFile != INVALID_HANDLE_VALUE) {
  547. //
  548. // If the file is empty, write out a unicode tag to the front of
  549. // the file.
  550. //
  551. if (GetFileSize( hFile, NULL ) == 0) {
  552. buf[0] = 0xff;
  553. buf[1] = 0xfe;
  554. WriteFile( hFile, buf, 2, &Bytes, NULL );
  555. }
  556. }
  557. }
  558. if (hFile == INVALID_HANDLE_VALUE) {
  559. return;
  560. }
  561. try {
  562. p = buf;
  563. *p = 0;
  564. swprintf( p, L"%02d:%02d:%02d.%03d ",
  565. CurrTime.wHour,
  566. CurrTime.wMinute,
  567. CurrTime.wSecond,
  568. CurrTime.wMilliseconds
  569. );
  570. p += wcslen(p);
  571. LoadString( SfcInstanceHandle, StrId, str, UnicodeChars(str) );
  572. va_start( arg_ptr, StrId );
  573. _vsnwprintf( p, 2048, str, arg_ptr );
  574. va_end( arg_ptr );
  575. p += wcslen(p);
  576. wcscat( p, L"\r\n" );
  577. } except(EXCEPTION_EXECUTE_HANDLER) {
  578. buf[0] = 0;
  579. }
  580. if (buf[0] == 0) {
  581. return;
  582. }
  583. //
  584. // set file pointer to end of file so we don't overwrite data
  585. //
  586. SetFilePointer(hFile,0,0,FILE_END);
  587. WriteFile( hFile, buf, UnicodeLen(buf), &Bytes, NULL );
  588. return;
  589. }
  590. #endif
  591. int
  592. MyDialogBoxParam(
  593. IN DWORD RcId,
  594. IN DLGPROC lpDialogFunc, // pointer to dialog box procedure
  595. IN LPARAM dwInitParam // initialization value
  596. )
  597. /*++
  598. Routine Description:
  599. creates a dialog box on the user's desktop.
  600. Arguments:
  601. RcId - resource id of dialog to be created.
  602. lpDialogFunc - dialog proc for dialog
  603. dwInitParam - initial parameter that WM_INITDIALOG receives in dialogproc
  604. Return Value:
  605. 0 or -1 for failure, else the value from EndDialog.
  606. --*/
  607. {
  608. #if 0
  609. HDESK hDesk = OpenInputDesktop( 0, FALSE, MAXIMUM_ALLOWED );
  610. if ( hDesk ) {
  611. SetThreadDesktop( hDesk );
  612. CloseDesktop( hDesk );
  613. }
  614. #else
  615. SetThreadDesktop( hUserDesktop );
  616. #endif
  617. return (int) DialogBoxParam(
  618. SfcInstanceHandle,
  619. MAKEINTRESOURCE(RcId),
  620. NULL,
  621. lpDialogFunc,
  622. dwInitParam
  623. );
  624. }
  625. void
  626. CenterDialog(
  627. HWND hwnd
  628. )
  629. /*++
  630. Routine Description:
  631. centers the specified window around the middle of the screen..
  632. Arguments:
  633. HWND - handle to window.
  634. Return Value:
  635. none.
  636. --*/
  637. {
  638. RECT rcWindow;
  639. LONG x,y,w,h;
  640. LONG sx = GetSystemMetrics(SM_CXSCREEN),
  641. sy = GetSystemMetrics(SM_CYSCREEN);
  642. ASSERT(IsWindow(hwnd));
  643. GetWindowRect(hwnd,&rcWindow);
  644. w = rcWindow.right - rcWindow.left + 1;
  645. h = rcWindow.bottom - rcWindow.top + 1;
  646. x = (sx - w)/2;
  647. y = (sy - h)/2;
  648. MoveWindow(hwnd,x,y,w,h,FALSE);
  649. }
  650. BOOL
  651. MakeDirectory(
  652. PCWSTR Dir
  653. )
  654. /*++
  655. Routine Description:
  656. Attempt to create all of the directories in the given path.
  657. Arguments:
  658. Dir - Directory path to create
  659. Return Value:
  660. TRUE for success, FALSE on error
  661. --*/
  662. {
  663. LPTSTR p, NewDir;
  664. BOOL retval;
  665. NewDir = p = MemAlloc( (wcslen(Dir) + 1) *sizeof(WCHAR) );
  666. if (p) {
  667. wcscpy(p, Dir);
  668. } else {
  669. return(FALSE);
  670. }
  671. if (*p != '\\') p += 2;
  672. while( *++p ) {
  673. while(*p && *p != TEXT('\\')) p++;
  674. if (!*p) {
  675. retval = CreateDirectory( NewDir, NULL );
  676. retval = retval
  677. ? retval
  678. : (GetLastError() == ERROR_ALREADY_EXISTS) ;
  679. MemFree(NewDir);
  680. return(retval);
  681. }
  682. *p = 0;
  683. retval = CreateDirectory( NewDir, NULL );
  684. if (!retval && GetLastError() != ERROR_ALREADY_EXISTS) {
  685. MemFree(NewDir);
  686. return(retval);
  687. }
  688. *p = TEXT('\\');
  689. }
  690. MemFree( NewDir );
  691. return(TRUE);
  692. }
  693. BOOL
  694. BuildPathForFile(
  695. IN PCWSTR SourceRootPath,
  696. IN PCWSTR SubDirectoryPath, OPTIONAL
  697. IN PCWSTR FileName,
  698. IN BOOL IncludeSubDirectory,
  699. IN BOOL IncludeArchitectureSpecificSubDirectory,
  700. OUT PWSTR PathBuffer,
  701. IN DWORD PathBufferSize
  702. )
  703. /*++
  704. Routine Description:
  705. Builds the specified path into a buffer
  706. Arguments:
  707. SourceRootPath - Specifies the root path to look for.
  708. SubDirectoryPath - Specifies an optional subdirectory under the root
  709. path where the file is located
  710. FileName - Specifies the filename to look for.
  711. IncludeSubDirectory - If TRUE, specifies that the subdirectory
  712. specification should be used.
  713. IncludeArchitectureSpecificSubDirectory - If TRUE, specifies that the
  714. architecture specif subdir should be used.
  715. If FALSE, specifies that the architecture
  716. specific subdir should be filtered out.
  717. If IncludeSubDirectory is FALSE, this parameter
  718. is ignored
  719. PathBuffer - Specifies a buffer to receive the path
  720. PathBufferSize - Specifies the size of the buffer to receive the
  721. path, in characters
  722. Return Value:
  723. TRUE for success, FALSE on error
  724. --*/
  725. {
  726. WCHAR InternalBuffer[MAX_PATH];
  727. WCHAR InternalSubDirBuffer[MAX_PATH];
  728. PWSTR p;
  729. ASSERT( SourceRootPath != NULL );
  730. ASSERT( FileName != NULL );
  731. ASSERT( PathBuffer != NULL );
  732. wcscpy( InternalBuffer, SourceRootPath );
  733. if (IncludeSubDirectory) {
  734. if (SubDirectoryPath) {
  735. wcscpy( InternalSubDirBuffer, SubDirectoryPath );
  736. if (IncludeArchitectureSpecificSubDirectory) {
  737. p = InternalSubDirBuffer;
  738. } else {
  739. p = wcsstr( InternalSubDirBuffer, PLATFORM_NAME );
  740. if (p) {
  741. p += wcslen(PLATFORM_NAME) + 1;
  742. if (p > InternalSubDirBuffer + wcslen(InternalSubDirBuffer)) {
  743. p = NULL;
  744. }
  745. }
  746. }
  747. } else {
  748. p = NULL;
  749. }
  750. if (p) {
  751. pSetupConcatenatePaths( InternalBuffer, p, UnicodeChars(InternalBuffer), NULL );
  752. }
  753. }
  754. pSetupConcatenatePaths( InternalBuffer, FileName, UnicodeChars(InternalBuffer), NULL );
  755. if (wcslen(InternalBuffer) + 1 <= PathBufferSize) {
  756. wcscpy( PathBuffer, InternalBuffer );
  757. return(TRUE);
  758. }
  759. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  760. return(FALSE);
  761. }
  762. PWSTR
  763. SfcGetSourcePath(
  764. IN BOOL bServicePackSourcePath,
  765. IN OUT PWSTR Path
  766. )
  767. /*++
  768. Routine Description:
  769. Retreives the os source path or servicepack source path, taking into
  770. account group policy.
  771. Arguments:
  772. bServicePackSourcePath - if TRUE, indicates that the servicepack source
  773. path should be retreived.
  774. Path - Specifies the buffer to receive the path.
  775. Assume the buffer is at least
  776. MAX_PATH*sizeof(WCHAR) large.
  777. path where the file is located
  778. Return Value:
  779. if successful, returns back a pointer to Path, else NULL
  780. --*/
  781. {
  782. PWSTR p;
  783. MYASSERT(Path != NULL);
  784. // If running under setup then we need to use the path
  785. // to $WINNT$.~LS or whatever passed in by GUI-setup.
  786. if (SFCDisable == SFC_DISABLE_SETUP) {
  787. MYASSERT(ServicePackSourcePath != NULL && ServicePackSourcePath[0] != 0);
  788. MYASSERT(OsSourcePath != NULL && OsSourcePath[0] != 0);
  789. if(bServicePackSourcePath) {
  790. wcsncpy( Path, ServicePackSourcePath, MAX_PATH );
  791. } else {
  792. wcsncpy( Path, OsSourcePath, MAX_PATH );
  793. }
  794. return(Path);
  795. }
  796. p = SfcQueryRegStringWithAlternate(
  797. REGKEY_POLICY_SETUP,
  798. REGKEY_SETUP_FULL,
  799. bServicePackSourcePath
  800. ? REGVAL_SERVICEPACKSOURCEPATH
  801. : REGVAL_SOURCEPATH );
  802. if(p) {
  803. wcsncpy( Path, p, MAX_PATH );
  804. MemFree( p );
  805. }
  806. return((p != NULL)
  807. ? Path
  808. : NULL );
  809. }
  810. DWORD
  811. SfcCreateSid(
  812. IN WELL_KNOWN_SID_TYPE type,
  813. OUT PSID* ppSid
  814. )
  815. /*++
  816. Routine Description:
  817. Allocates and creates a well-known SID.
  818. Arguments:
  819. type - type of SID to create
  820. ppSid - receives a pointer to the newly-created SID
  821. Return Value:
  822. Win32 error code.
  823. --*/
  824. {
  825. DWORD dwError = ERROR_SUCCESS;
  826. PSID pSid = NULL;
  827. DWORD dwSize = SECURITY_MAX_SID_SIZE;
  828. *ppSid = NULL;
  829. pSid = (PSID) MemAlloc(dwSize);
  830. if(NULL == pSid) {
  831. dwError = ERROR_NOT_ENOUGH_MEMORY;
  832. goto exit;
  833. }
  834. if(!CreateWellKnownSid(type, NULL, pSid, &dwSize)) {
  835. dwError = GetLastError();
  836. goto exit;
  837. }
  838. *ppSid = pSid;
  839. pSid = NULL;
  840. exit:
  841. MemFree(pSid);
  842. return dwError;
  843. }
  844. DWORD
  845. SfcGetSidName(
  846. IN PSID pSid,
  847. OUT PWSTR* ppszName
  848. )
  849. /*++
  850. Routine Description:
  851. Gets the account name of a SID. The function allocates the buffer for the name.
  852. Arguments:
  853. pSid - pointer to the SID
  854. ppszName - receives a pointer to the allocated buffer that holds the account name
  855. Return Value:
  856. Win32 error code.
  857. --*/
  858. {
  859. DWORD dwError = ERROR_SUCCESS;
  860. PWSTR szName = NULL;
  861. PWSTR szDomain = NULL;
  862. DWORD dwNameSize;
  863. DWORD dwDomainSize;
  864. SID_NAME_USE use;
  865. *ppszName = NULL;
  866. dwNameSize = dwDomainSize = 256;
  867. szName = (PWSTR) MemAlloc(dwNameSize);
  868. szDomain = (PWSTR) MemAlloc(dwDomainSize);
  869. if(NULL == szName || NULL == szDomain) {
  870. dwError = ERROR_NOT_ENOUGH_MEMORY;
  871. goto exit;
  872. }
  873. if(!LookupAccountSid(NULL, pSid, szName, &dwNameSize, szDomain, &dwDomainSize, &use)) {
  874. dwError = GetLastError();
  875. goto exit;
  876. }
  877. *ppszName = szName;
  878. szName = NULL;
  879. exit:
  880. MemFree(szName);
  881. MemFree(szDomain);
  882. return dwError;
  883. }
  884. DWORD
  885. SfcIsUserAdmin(
  886. IN HANDLE hToken OPTIONAL,
  887. OUT PBOOL Result
  888. )
  889. /*++
  890. Routine Description:
  891. Verifies if an impersonation token is a member of the local administrators group.
  892. Arguments:
  893. hToken - handle to the impersonation token; if NULL, the current thread's impersonation token (or the process token if
  894. the thread is not impersonating) is used
  895. Result - receives a non-zero value if the token is a member of the administrators group, FALSE otherwise
  896. Return Value:
  897. Win32 error code.
  898. --*/
  899. {
  900. DWORD dwError = ERROR_SUCCESS;
  901. PSID pSid = NULL;
  902. *Result = FALSE;
  903. dwError = SfcCreateSid(WinBuiltinAdministratorsSid, &pSid);
  904. if(dwError != ERROR_SUCCESS) {
  905. goto exit;
  906. }
  907. if(!CheckTokenMembership(hToken, pSid, Result)) {
  908. dwError = GetLastError();
  909. goto exit;
  910. }
  911. exit:
  912. MemFree(pSid);
  913. return dwError;
  914. }
  915. DWORD
  916. SfcRpcPriviledgeCheck(
  917. IN HANDLE RpcHandle
  918. )
  919. /*++
  920. Routine Description:
  921. Check if the user has sufficient privilege to perform the requested action.
  922. Currently only administrators have privilege to do this.
  923. Arguments:
  924. RpcHandle - Rpc binding handle used for impersonating the client.
  925. Return Value:
  926. Win32 error code indicating outcome -- RPC_S_OK (ERROR_SUCCESS) indicates
  927. success.
  928. --*/
  929. {
  930. DWORD dwError;
  931. DWORD dwTemp;
  932. BOOL IsAdmin;
  933. //
  934. // impersonate the calling client
  935. //
  936. dwError = RpcImpersonateClient(RpcHandle);
  937. if (dwError != RPC_S_OK) {
  938. DebugPrint1( LVL_MINIMAL, L"RpcImpersonateClient failed, ec = %d",dwError );
  939. goto exit;
  940. }
  941. //
  942. // make sure the user has sufficient privilege
  943. //
  944. dwError = SfcIsUserAdmin(NULL, &IsAdmin);
  945. //
  946. // revert back to original context. if this fails, we must return failure.
  947. //
  948. dwTemp = RpcRevertToSelf();
  949. if (dwTemp != RPC_S_OK) {
  950. dwError = dwTemp;
  951. DebugPrint1( LVL_MINIMAL, L"RpcRevertToSelf failed, ec = 0x%08x", dwError );
  952. goto exit;
  953. }
  954. if(ERROR_SUCCESS == dwError && !IsAdmin) {
  955. dwError = ERROR_ACCESS_DENIED;
  956. }
  957. exit:
  958. return dwError;
  959. }
  960. PSFC_GET_FILES
  961. SfcLoadSfcFiles(
  962. BOOL bLoad
  963. )
  964. /*++
  965. Routine Description:
  966. Loads or unloads sfcfiles.dll and gets the address of SfcGetFiles function
  967. Arguments:
  968. bLoad: TRUE to load sfcfiles.dll, false otherwise.
  969. Return Value:
  970. If bLoad is TRUE and the function is successful, it returns the address of SfcGetFiles function, otherwise NULL
  971. --*/
  972. {
  973. static HMODULE h = NULL;
  974. PSFC_GET_FILES pfGetFiles = NULL;
  975. if(bLoad)
  976. {
  977. if(NULL == h)
  978. {
  979. h = SfcLoadLibrary(L"sfcfiles.dll");
  980. }
  981. if(h != NULL)
  982. {
  983. pfGetFiles = (PSFC_GET_FILES) GetProcAddress(h, "SfcGetFiles");
  984. }
  985. }
  986. if(NULL == pfGetFiles && h != NULL)
  987. {
  988. LdrUnloadDll(h);
  989. h = NULL;
  990. }
  991. return pfGetFiles;
  992. }
  993. #if DBG
  994. DWORD GetProcessOwner(PTOKEN_OWNER* ppto)
  995. {
  996. HANDLE hToken = NULL;
  997. DWORD dwSize = 100;
  998. DWORD dwError;
  999. ASSERT(ppto != NULL);
  1000. *ppto = (PTOKEN_OWNER) MemAlloc(dwSize);
  1001. if(NULL == *ppto)
  1002. {
  1003. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1004. goto lExit;
  1005. }
  1006. if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
  1007. {
  1008. dwError = GetLastError();
  1009. goto lExit;
  1010. }
  1011. if(!GetTokenInformation(hToken, TokenOwner, *ppto, dwSize, &dwSize))
  1012. {
  1013. PTOKEN_OWNER p;
  1014. dwError = GetLastError();
  1015. if(dwError != ERROR_INSUFFICIENT_BUFFER)
  1016. goto lExit;
  1017. p = (PTOKEN_OWNER) MemReAlloc(dwSize, *ppto);
  1018. if(NULL == p)
  1019. {
  1020. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1021. goto lExit;
  1022. }
  1023. *ppto = p;
  1024. if(!GetTokenInformation(hToken, TokenOwner, *ppto, dwSize, &dwSize))
  1025. {
  1026. dwError = GetLastError();
  1027. goto lExit;
  1028. }
  1029. }
  1030. dwError = ERROR_SUCCESS;
  1031. lExit:
  1032. if(dwError != ERROR_SUCCESS && *ppto != NULL)
  1033. {
  1034. MemFree(*ppto);
  1035. *ppto = NULL;
  1036. }
  1037. if(hToken != NULL)
  1038. CloseHandle(hToken);
  1039. return dwError;
  1040. }
  1041. DWORD CreateSd(PSECURITY_DESCRIPTOR* ppsd)
  1042. {
  1043. enum
  1044. {
  1045. AuthenticatedUsers,
  1046. MaxSids
  1047. };
  1048. PTOKEN_OWNER pto = NULL;
  1049. PSID psids[MaxSids] = { NULL };
  1050. const DWORD cdwAllowedAceLength = sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD);
  1051. SID_IDENTIFIER_AUTHORITY sidNtAuthority = SECURITY_NT_AUTHORITY;
  1052. PACL pacl;
  1053. DWORD dwAclSize;
  1054. DWORD dwError;
  1055. DWORD i;
  1056. ASSERT(ppsd != NULL);
  1057. *ppsd = NULL;
  1058. dwError = GetProcessOwner(&pto);
  1059. if(dwError != ERROR_SUCCESS)
  1060. goto lExit;
  1061. if(!AllocateAndInitializeSid(
  1062. &sidNtAuthority,
  1063. 1,
  1064. SECURITY_AUTHENTICATED_USER_RID,
  1065. 0,
  1066. 0,
  1067. 0,
  1068. 0,
  1069. 0,
  1070. 0,
  1071. 0,
  1072. psids + AuthenticatedUsers
  1073. ))
  1074. {
  1075. dwError = GetLastError();
  1076. goto lExit;
  1077. }
  1078. //
  1079. // compute the size of ACL
  1080. //
  1081. dwAclSize = sizeof(ACL) + cdwAllowedAceLength + GetLengthSid(pto->Owner);
  1082. for(i = 0; i < MaxSids; i++)
  1083. dwAclSize += cdwAllowedAceLength + GetLengthSid(psids[i]);
  1084. *ppsd = (PSECURITY_DESCRIPTOR) MemAlloc(SECURITY_DESCRIPTOR_MIN_LENGTH + dwAclSize);
  1085. if(NULL == *ppsd)
  1086. {
  1087. dwError = ERROR_NOT_ENOUGH_MEMORY;
  1088. goto lExit;
  1089. }
  1090. pacl = (PACL) ((LPBYTE) (*ppsd) + SECURITY_DESCRIPTOR_MIN_LENGTH);
  1091. if(
  1092. !InitializeAcl(pacl, dwAclSize, ACL_REVISION) ||
  1093. !AddAccessAllowedAce(pacl, ACL_REVISION, EVENT_ALL_ACCESS, pto->Owner) ||
  1094. !AddAccessAllowedAce(pacl, ACL_REVISION, EVENT_MODIFY_STATE, psids[AuthenticatedUsers]) ||
  1095. !InitializeSecurityDescriptor(*ppsd, SECURITY_DESCRIPTOR_REVISION) ||
  1096. !SetSecurityDescriptorDacl(*ppsd, TRUE, pacl, FALSE)
  1097. )
  1098. {
  1099. dwError = GetLastError();
  1100. goto lExit;
  1101. }
  1102. dwError = ERROR_SUCCESS;
  1103. lExit:
  1104. if(dwError != ERROR_SUCCESS && *ppsd != NULL)
  1105. {
  1106. MemFree(*ppsd);
  1107. *ppsd = NULL;
  1108. }
  1109. if(pto != NULL)
  1110. MemFree(pto);
  1111. for(i = 0; i < MaxSids; i++)
  1112. {
  1113. if(psids[i] != NULL)
  1114. FreeSid(psids[i]);
  1115. }
  1116. return dwError;
  1117. }
  1118. #endif
  1119. LRESULT CALLBACK DlgParentWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1120. /*++
  1121. Routine Description:
  1122. This is the window proc of the parent window for network authentication dialog
  1123. Arguments:
  1124. See Platform SDK docs
  1125. Return Value:
  1126. See Platform SDK docs
  1127. --*/
  1128. {
  1129. static PSFC_WINDOW_DATA pWndData = NULL;
  1130. switch(uMsg)
  1131. {
  1132. case WM_CREATE:
  1133. pWndData = pSfcCreateWindowDataEntry(hwnd);
  1134. if(NULL == pWndData)
  1135. {
  1136. return -1;
  1137. }
  1138. break;
  1139. case WM_WFPENDDIALOG:
  1140. //
  1141. // don't try to delete pWndData from the list when this message is sent because we'll deadlock;
  1142. // the entry will be removed by the thread that sent it
  1143. //
  1144. pWndData = NULL;
  1145. DestroyWindow(hwnd);
  1146. break;
  1147. case WM_DESTROY:
  1148. if(pWndData != NULL)
  1149. {
  1150. //
  1151. // delete pWndData from the list since this is not a consequence of receiving WM_WFPENDDIALOG
  1152. //
  1153. pSfcRemoveWindowDataEntry(pWndData);
  1154. }
  1155. break;
  1156. default:
  1157. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1158. }
  1159. return 0;
  1160. }
  1161. DWORD
  1162. CreateDialogParent(
  1163. OUT HWND* phwnd
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Creates the parent window for network authentication dialog
  1168. Arguments:
  1169. phwnd: receives the handle of the newly-created window
  1170. Return Value:
  1171. Win32 error code
  1172. --*/
  1173. {
  1174. DWORD dwError = ERROR_SUCCESS;
  1175. WNDCLASSW wc;
  1176. WCHAR szTitle[128];
  1177. ASSERT(phwnd != NULL);
  1178. RtlZeroMemory(&wc, sizeof(wc));
  1179. wc.lpszClassName = PARENT_WND_CLASS;
  1180. wc.hInstance = SfcInstanceHandle;
  1181. wc.lpfnWndProc = DlgParentWndProc;
  1182. //
  1183. // if the class is already registered, there will be no problems;
  1184. // if there's an error registering the class for the first time, it will show up in CreateWindow
  1185. //
  1186. RegisterClassW(&wc);
  1187. if(0 == LoadString(SfcInstanceHandle, IDS_TITLE, szTitle, ARRAY_LENGTH(szTitle))) {
  1188. szTitle[0] = 0;
  1189. }
  1190. *phwnd = CreateWindowW(
  1191. wc.lpszClassName,
  1192. szTitle,
  1193. WS_POPUP | WS_VISIBLE,
  1194. 0,
  1195. 0,
  1196. 0,
  1197. 0,
  1198. NULL,
  1199. NULL,
  1200. wc.hInstance,
  1201. NULL
  1202. );
  1203. if(NULL == *phwnd)
  1204. {
  1205. dwError = GetLastError();
  1206. DebugPrint1(LVL_VERBOSE, L"CreateDialogParent failed with the code %x", dwError);
  1207. goto exit;
  1208. }
  1209. //
  1210. // Make it topmost so it won't go unnoticed
  1211. //
  1212. SetWindowPos(*phwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  1213. exit:
  1214. return dwError;
  1215. }
  1216. NTSTATUS
  1217. SfcAllocUnicodeStringFromPath(
  1218. IN PCWSTR szPath,
  1219. OUT PUNICODE_STRING pString
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. Expands the environment variables in the input path. Allocates the output buffer.
  1224. Arguments:
  1225. szPath - a path that can contain environment variables
  1226. pString - receives the expanded path
  1227. Return value:
  1228. The error code.
  1229. --*/
  1230. {
  1231. ULONG uLength;
  1232. pString->Length = pString->MaximumLength = 0;
  1233. pString->Buffer = NULL;
  1234. uLength = ExpandEnvironmentStringsW(szPath, NULL, 0);
  1235. if(0 == uLength || uLength > MAXSHORT)
  1236. {
  1237. return STATUS_INVALID_PARAMETER;
  1238. }
  1239. pString->Buffer = (PWSTR) MemAlloc(uLength * sizeof(WCHAR));
  1240. if(NULL == pString->Buffer)
  1241. {
  1242. return STATUS_NO_MEMORY;
  1243. }
  1244. if(0 == ExpandEnvironmentStringsW(szPath, pString->Buffer, uLength)) {
  1245. return STATUS_INVALID_PARAMETER;
  1246. }
  1247. pString->MaximumLength = (USHORT) (uLength * sizeof(WCHAR));
  1248. pString->Length = pString->MaximumLength - sizeof(WCHAR);
  1249. return STATUS_SUCCESS;
  1250. }
  1251. #ifndef _WIN64
  1252. VOID
  1253. SfcCleanupPathTranslator(
  1254. IN BOOL FinalCleanup
  1255. )
  1256. /*++
  1257. Routine Description:
  1258. Frees the memory used in the translation table and optionally the critical section used to access it.
  1259. Arguments:
  1260. FinalCleanup - if TRUE, the critical section is also deleted
  1261. Return value:
  1262. none
  1263. --*/
  1264. {
  1265. if(SfcNeedTranslation)
  1266. {
  1267. if(SfcTranslations != NULL)
  1268. {
  1269. ULONG i;
  1270. for(i = 0; i < ARRAY_LENGTH(SfcExpandTranslations); ++i)
  1271. {
  1272. MemFree(SfcTranslations[i].Src.Buffer);
  1273. MemFree(SfcTranslations[i].Dest.Buffer);
  1274. }
  1275. MemFree(SfcTranslations);
  1276. SfcTranslations = NULL;
  1277. }
  1278. if(FinalCleanup)
  1279. {
  1280. RtlDeleteCriticalSection(&SfcTranslatorCs);
  1281. }
  1282. }
  1283. }
  1284. VOID
  1285. SfcInitPathTranslator(
  1286. VOID
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. Initializes the path translator. Does not expand the table paths.
  1291. Arguments:
  1292. none
  1293. Return value:
  1294. none
  1295. --*/
  1296. {
  1297. #ifdef SFC_REDIRECTOR_TEST
  1298. SfcNeedTranslation = TRUE;
  1299. #else
  1300. SfcNeedTranslation = (GetSystemWow64DirectoryW(NULL, 0) != 0);
  1301. #endif
  1302. if(SfcNeedTranslation) {
  1303. RtlInitializeCriticalSection(&SfcTranslatorCs);
  1304. }
  1305. }
  1306. NTSTATUS
  1307. SfcExpandPathTranslator(
  1308. VOID
  1309. )
  1310. /*++
  1311. Routine Description:
  1312. Expands the translation table paths.
  1313. Arguments:
  1314. none
  1315. Return value:
  1316. The error code.
  1317. --*/
  1318. {
  1319. NTSTATUS Status = STATUS_SUCCESS;
  1320. ASSERT(SfcNeedTranslation);
  1321. RtlEnterCriticalSection(&SfcTranslatorCs);
  1322. if(!SfcIsTranslatorInitialized)
  1323. {
  1324. ULONG ulCount = ARRAY_LENGTH(SfcExpandTranslations);
  1325. ULONG i;
  1326. ASSERT(NULL == SfcTranslations);
  1327. SfcTranslations = (SFC_TRANSLATION_ENTRY*) MemAlloc(ulCount * sizeof(SFC_TRANSLATION_ENTRY));
  1328. if(NULL == SfcTranslations)
  1329. {
  1330. Status = STATUS_NO_MEMORY;
  1331. goto cleanup;
  1332. }
  1333. for(i = 0; i < ulCount; ++i)
  1334. {
  1335. Status = SfcAllocUnicodeStringFromPath(SfcExpandTranslations[i].Src, &SfcTranslations[i].Src);
  1336. if(!NT_SUCCESS(Status))
  1337. {
  1338. goto cleanup;
  1339. }
  1340. Status = SfcAllocUnicodeStringFromPath(SfcExpandTranslations[i].Dest, &SfcTranslations[i].Dest);
  1341. if(!NT_SUCCESS(Status))
  1342. {
  1343. goto cleanup;
  1344. }
  1345. }
  1346. //
  1347. // set this to TRUE only on success; in case of failure, the init will be tried later
  1348. //
  1349. SfcIsTranslatorInitialized = TRUE;
  1350. cleanup:
  1351. if(!NT_SUCCESS(Status))
  1352. {
  1353. SfcCleanupPathTranslator(FALSE);
  1354. DebugPrint(LVL_MINIMAL, L"Could not initialize the path translator");
  1355. }
  1356. }
  1357. RtlLeaveCriticalSection(&SfcTranslatorCs);
  1358. return Status;
  1359. }
  1360. NTSTATUS
  1361. SfcRedirectPath(
  1362. IN PCWSTR szPath,
  1363. OUT PUNICODE_STRING pPath
  1364. )
  1365. /*++
  1366. Routine Description:
  1367. Expands environment variables and translates a path from win32 to wow64. Allocates the output buffer.
  1368. Arguments:
  1369. szPath - the path to expand/translate
  1370. pPath - receives the processed (and possibly changed) path
  1371. Return value:
  1372. The error code.
  1373. --*/
  1374. {
  1375. NTSTATUS Status = STATUS_SUCCESS;
  1376. UNICODE_STRING Path = { 0 };
  1377. ULONG i;
  1378. ASSERT(szPath != NULL);
  1379. ASSERT(pPath != NULL);
  1380. RtlZeroMemory(pPath, sizeof(*pPath));
  1381. //
  1382. // first of all, expand environment strings
  1383. //
  1384. Status = SfcAllocUnicodeStringFromPath(szPath, &Path);
  1385. if(!NT_SUCCESS(Status))
  1386. {
  1387. goto exit;
  1388. }
  1389. if(!SfcNeedTranslation)
  1390. {
  1391. goto no_translation;
  1392. }
  1393. Status = SfcExpandPathTranslator();
  1394. if(!NT_SUCCESS(Status))
  1395. {
  1396. goto exit;
  1397. }
  1398. for(i = 0; i < ARRAY_LENGTH(SfcExpandTranslations); ++i)
  1399. {
  1400. PUNICODE_STRING pSrc = &SfcTranslations[i].Src;
  1401. PUNICODE_STRING pDest = &SfcTranslations[i].Dest;
  1402. if(Path.Length >= pSrc->Length && 0 == _wcsnicmp(Path.Buffer, pSrc->Buffer, pSrc->Length / sizeof(WCHAR)))
  1403. {
  1404. const UNICODE_STRING* pExcep = SfcExpandTranslations[i].Exceptions;
  1405. //
  1406. // test if this is an excluded path
  1407. //
  1408. for(i = SfcExpandTranslations[i].ExceptionCount; i--; ++pExcep)
  1409. {
  1410. if(Path.Length >= pSrc->Length + pExcep->Length &&
  1411. 0 == _wcsnicmp((PWCHAR) ((PCHAR) Path.Buffer + pSrc->Length), pExcep->Buffer, pExcep->Length / sizeof(WCHAR)))
  1412. {
  1413. goto no_translation;
  1414. }
  1415. }
  1416. DebugPrint1(LVL_VERBOSE, L"Redirecting \"%s\"", Path.Buffer);
  1417. //
  1418. // compute the new length, including the terminator
  1419. //
  1420. pPath->MaximumLength = Path.Length - pSrc->Length + pDest->Length + sizeof(WCHAR);
  1421. pPath->Buffer = (PWSTR) MemAlloc(pPath->MaximumLength);
  1422. if(NULL == pPath->Buffer)
  1423. {
  1424. Status = STATUS_NO_MEMORY;
  1425. goto exit;
  1426. }
  1427. RtlCopyMemory(pPath->Buffer, pDest->Buffer, pDest->Length);
  1428. //
  1429. // copy the reminder of the path (including terminator)
  1430. //
  1431. RtlCopyMemory((PCHAR) pPath->Buffer + pDest->Length, (PCHAR) Path.Buffer + pSrc->Length, Path.Length - pSrc->Length + sizeof(WCHAR));
  1432. pPath->Length = pPath->MaximumLength - sizeof(WCHAR);
  1433. DebugPrint1(LVL_VERBOSE, L"Path redirected to \"%s\"", pPath->Buffer);
  1434. goto exit;
  1435. }
  1436. }
  1437. no_translation:
  1438. DebugPrint1(LVL_VERBOSE, L"No translation required for \"%s\"", Path.Buffer);
  1439. //
  1440. // output the expanded string
  1441. //
  1442. *pPath = Path;
  1443. Path.Buffer = NULL;
  1444. exit:
  1445. MemFree(Path.Buffer);
  1446. if(!NT_SUCCESS(Status))
  1447. {
  1448. MemFree(pPath->Buffer);
  1449. RtlZeroMemory(pPath, sizeof(*pPath));
  1450. }
  1451. return Status;
  1452. }
  1453. #endif // _WIN64
  1454. NTSTATUS
  1455. SfcRpcStartServer(
  1456. VOID
  1457. )
  1458. /*++
  1459. Routine Description:
  1460. Initializes the RPC server and starts listening for calls.
  1461. Arguments:
  1462. none
  1463. Return Value:
  1464. NT status code.
  1465. --*/
  1466. {
  1467. RPC_STATUS Status;
  1468. //
  1469. // Use LRPC protocol and WFP's endpoint
  1470. //
  1471. Status = RpcServerUseProtseqEp(L"ncalrpc", 0, SFC_RPC_ENDPOINT, NULL);
  1472. if(Status != RPC_S_OK) {
  1473. goto exit;
  1474. }
  1475. //
  1476. // Register the RPC interface and start listening to calls
  1477. //
  1478. Status = RpcServerRegisterIfEx(
  1479. SfcSrv_sfcapi_ServerIfHandle,
  1480. NULL,
  1481. NULL,
  1482. RPC_IF_AUTOLISTEN,
  1483. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  1484. NULL
  1485. );
  1486. exit:
  1487. return I_RpcMapWin32Status(Status);
  1488. }
  1489. DWORD
  1490. SfcNtPathToDosPath(
  1491. IN LPCWSTR NtName,
  1492. OUT LPWSTR* DosName
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. Converts an NT file system path to a DOS path. Allocates the result using MemAlloc.
  1497. Arguments:
  1498. NtName -NT path to be converted
  1499. DosName -pointer that receives the converted DOS path (allocated)
  1500. Return Value:
  1501. Win32 error code.
  1502. --*/
  1503. {
  1504. NTSTATUS Status = STATUS_SUCCESS;
  1505. RTL_UNICODE_STRING_BUFFER Buffer;
  1506. UNICODE_STRING String;
  1507. ASSERT(DosName != NULL);
  1508. *DosName = NULL;
  1509. RtlInitUnicodeString(&String, NtName);
  1510. ASSERT(String.Length != 0);
  1511. if(String.Length != 0 && L'!' == String.Buffer[0]) {
  1512. ++String.Buffer;
  1513. String.Length -=2;
  1514. String.MaximumLength -= 2;
  1515. }
  1516. RtlInitUnicodeStringBuffer(&Buffer, NULL, 0);
  1517. Status = RtlAssignUnicodeStringBuffer(&Buffer, &String);
  1518. if(!NT_SUCCESS(Status)) {
  1519. goto exit;
  1520. }
  1521. Status = RtlNtPathNameToDosPathName(0, &Buffer, NULL, NULL);
  1522. if(!NT_SUCCESS(Status)) {
  1523. goto exit;
  1524. }
  1525. *DosName = MemAlloc(Buffer.String.Length + sizeof(WCHAR));
  1526. if(NULL == *DosName) {
  1527. Status = STATUS_NO_MEMORY;
  1528. goto exit;
  1529. }
  1530. RtlCopyMemory(*DosName, Buffer.String.Buffer, Buffer.String.Length);
  1531. (*DosName)[Buffer.String.Length / sizeof(WCHAR)] = 0;
  1532. exit:
  1533. RtlFreeUnicodeStringBuffer(&Buffer);
  1534. return RtlNtStatusToDosError(Status);
  1535. }
  1536. DWORD
  1537. ProcessDelayRenames(
  1538. VOID
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. Checks to see if delay-renames were pending during last reboot and
  1543. copies the affected files to dllcache
  1544. Arguments:
  1545. none
  1546. Return Value:
  1547. Win32 error code.
  1548. --*/
  1549. {
  1550. LONG Error = ERROR_SUCCESS;
  1551. HKEY RegKey = NULL;
  1552. LPWSTR DataPtr = NULL;
  1553. DWORD ValueType;
  1554. DWORD ValueSize;
  1555. UINT_PTR i;
  1556. Error = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REGKEY_WINLOGON_WIN32, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &RegKey);
  1557. if(Error != ERROR_SUCCESS) {
  1558. goto exit;
  1559. }
  1560. ValueSize = 0;
  1561. Error = RegQueryValueExW(RegKey, REGVAL_WFPPENDINGUPDATES, NULL, &ValueType, NULL, &ValueSize);
  1562. if(Error != ERROR_SUCCESS) {
  1563. if(ERROR_FILE_NOT_FOUND == Error) {
  1564. //
  1565. // No value means nothing to do here
  1566. //
  1567. Error = ERROR_SUCCESS;
  1568. }
  1569. goto exit;
  1570. }
  1571. if(ValueType != REG_MULTI_SZ) {
  1572. Error = ERROR_INVALID_DATA;
  1573. goto exit;
  1574. }
  1575. DataPtr = (LPWSTR) MemAlloc(ValueSize);
  1576. if(NULL == DataPtr) {
  1577. Error = ERROR_NOT_ENOUGH_MEMORY;
  1578. goto exit;
  1579. }
  1580. Error = RegQueryValueExW(RegKey, REGVAL_WFPPENDINGUPDATES, NULL, &ValueType, (LPBYTE) DataPtr, &ValueSize);
  1581. if(Error != ERROR_SUCCESS) {
  1582. goto exit;
  1583. }
  1584. ValueSize /= sizeof(WCHAR);
  1585. //
  1586. // Look for target files
  1587. //
  1588. for(i = 0; ; ) {
  1589. UINT_PTR Start = i;
  1590. //
  1591. // skip source path
  1592. //
  1593. for(; i < ValueSize && DataPtr[i] != 0; ++i);
  1594. if(i >= ValueSize) {
  1595. Error = ERROR_INVALID_DATA;
  1596. goto exit;
  1597. }
  1598. if(i == Start) {
  1599. //
  1600. // empty source path; this must be the end of the list
  1601. //
  1602. break;
  1603. }
  1604. //
  1605. // skip the terminator and store the target start
  1606. //
  1607. Start = (++i);
  1608. //
  1609. // search for the end of target
  1610. //
  1611. for(; i < ValueSize && DataPtr[i] != 0; ++i);
  1612. if(i >= ValueSize) {
  1613. Error = ERROR_INVALID_DATA;
  1614. goto exit;
  1615. }
  1616. if(i != Start) {
  1617. //
  1618. // This is a delay-rename; process it
  1619. //
  1620. LPWSTR DosPath = NULL;
  1621. Error = SfcNtPathToDosPath(DataPtr + Start, &DosPath);
  1622. if(STATUS_SUCCESS == Error) {
  1623. PNAME_NODE Node;
  1624. DWORD Size = wcslen(DosPath);
  1625. MyLowerString(DosPath, Size);
  1626. Node = SfcFindProtectedFile(DosPath, Size * sizeof(WCHAR));
  1627. MemFree(DosPath);
  1628. if(Node != NULL) {
  1629. //
  1630. // This one's protected. Blindly copy the file to dllcahe;
  1631. // if it's not signed, it will be like not being there at all.
  1632. // Also, we don't take into account the dllcache quota for simplicity.
  1633. //
  1634. NTSTATUS Status;
  1635. UNICODE_STRING FileNameOnMediaString;
  1636. PCWSTR FileNameOnMedia;
  1637. PSFC_REGISTRY_VALUE RegVal = (PSFC_REGISTRY_VALUE) Node->Context;
  1638. ASSERT(RegVal != NULL);
  1639. ASSERT(RegVal->DirHandle != NULL);
  1640. ASSERT(SfcProtectedDllFileDirectory != NULL);
  1641. FileNameOnMedia = FileNameOnMedia(RegVal);
  1642. ASSERT(FileNameOnMedia != NULL);
  1643. RtlInitUnicodeString(&FileNameOnMediaString, FileNameOnMedia);
  1644. Status = SfcCopyFile(
  1645. RegVal->DirHandle,
  1646. RegVal->DirName.Buffer,
  1647. SfcProtectedDllFileDirectory,
  1648. SfcProtectedDllPath.Buffer,
  1649. &FileNameOnMediaString,
  1650. &RegVal->FileName
  1651. );
  1652. if(!NT_SUCCESS(Status)) {
  1653. DebugPrint2(LVL_MEDIUM, L"Renamed file [%wZ] could not be copied to dllcache, error &lX", &RegVal->FileName, Status);
  1654. }
  1655. }
  1656. }
  1657. }
  1658. //
  1659. // Skip the null and move on
  1660. //
  1661. ++i;
  1662. }
  1663. //
  1664. // Delete the key so we don't process it the next boot
  1665. //
  1666. RegDeleteValue(RegKey, REGVAL_WFPPENDINGUPDATES);
  1667. exit:
  1668. if(RegKey != NULL) {
  1669. RegCloseKey(RegKey);
  1670. }
  1671. MemFree(DataPtr);
  1672. return Error;
  1673. }