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.

1100 lines
28 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. apisrv.c
  5. Abstract:
  6. Windows File Protection server side APIs. Note that these server side APIs
  7. all run in the context of the winlogon process, so special care must be
  8. taken to validate all parameters.
  9. Author:
  10. Wesley Witt (wesw) 27-May-1999
  11. Revision History:
  12. Andrew Ritz (andrewr) 5-Jul-1999 : added comments
  13. --*/
  14. #include "sfcp.h"
  15. #pragma hdrstop
  16. DWORD
  17. WINAPI
  18. SfcSrv_FileException(
  19. IN HANDLE RpcHandle,
  20. IN PCWSTR FileName,
  21. IN DWORD ExpectedChangeType
  22. )
  23. /*++
  24. Routine Description:
  25. Routine to exempt a given file from the specified file change. This
  26. routine is used by certain clients to allow files to be deleted from
  27. the system, etc. Server side counterpart to SfcFileException API.
  28. Arguments:
  29. RpcHandle - RPC binding handle to the SFC server
  30. FileName - NULL terminated unicode string specifying full
  31. filename of the file to be exempted
  32. ExpectedChangeType - SFC_ACTION_* mask listing the file changes to exempt
  33. Return Value:
  34. Win32 error code indicating outcome.
  35. --*/
  36. {
  37. #define BUFSZ (MAX_PATH*2)
  38. PNAME_NODE Node;
  39. PSFC_REGISTRY_VALUE RegVal;
  40. WCHAR Buffer[BUFSZ];
  41. DWORD sz;
  42. DWORD retval;
  43. //
  44. // do an access check to make sure the caller is allowed to perform this
  45. // action.
  46. //
  47. retval = SfcRpcPriviledgeCheck( RpcHandle );
  48. if (retval != ERROR_SUCCESS) {
  49. goto exit;
  50. }
  51. //
  52. // expand any environment variables...this also serves to probe the client
  53. // buffer
  54. //
  55. if (FileName == NULL) {
  56. retval = ERROR_INVALID_PARAMETER;
  57. } else {
  58. sz = ExpandEnvironmentStrings( FileName, Buffer, UnicodeChars(Buffer) );
  59. if (sz == 0 || sz > BUFSZ) {
  60. retval = GetLastError();
  61. }
  62. }
  63. if (retval != ERROR_SUCCESS) {
  64. return(retval);
  65. }
  66. //
  67. // our internal structures all assume the strings are in lower case. we
  68. // must convert our search string to lowercase as well.
  69. //
  70. MyLowerString( Buffer, wcslen(Buffer) );
  71. DebugPrint2( LVL_MINIMAL, L"S_FE: [%ws], [%d]", Buffer, ExpectedChangeType );
  72. //
  73. // search for the file in our list.
  74. //
  75. Node = SfcFindProtectedFile( Buffer, UnicodeLen(Buffer) );
  76. if (Node == NULL) {
  77. retval = ERROR_FILE_NOT_FOUND;
  78. goto exit;
  79. }
  80. //
  81. // get pointer to file registry value for file
  82. //
  83. RegVal = (PSFC_REGISTRY_VALUE)Node->Context;
  84. RtlEnterCriticalSection( &ErrorCs );
  85. //
  86. // If the exemption flags are not valid anymore, reset them all
  87. //
  88. if(!SfcAreExemptionFlagsValid(TRUE)) {
  89. ZeroMemory(IgnoreNextChange, SfcProtectedDllCount * sizeof(ULONG));
  90. }
  91. //
  92. // OR the new flags into the current ones
  93. //
  94. SfcSetExemptionFlags(RegVal, ExpectedChangeType);
  95. RtlLeaveCriticalSection( &ErrorCs );
  96. exit:
  97. return(retval);
  98. }
  99. DWORD
  100. WINAPI
  101. SfcSrv_InitiateScan(
  102. IN HANDLE hBinding,
  103. IN DWORD ScanWhen
  104. )
  105. /*++
  106. Routine Description:
  107. Routine to start some sort scan on the system.
  108. Arguments:
  109. RpcHandle - RPC binding handle to the SFC server
  110. ScanWhen - flag indicating when to scan.
  111. Return Value:
  112. Win32 error code indicating outcome.
  113. --*/
  114. {
  115. HANDLE hThread;
  116. PSCAN_PARAMS ScanParams;
  117. DWORD retval = ERROR_SUCCESS;
  118. //
  119. // do an access check to make sure the caller is allowed to perform this
  120. // action.
  121. //
  122. retval = SfcRpcPriviledgeCheck( hBinding );
  123. if (retval != ERROR_SUCCESS) {
  124. goto exit;
  125. }
  126. switch( ScanWhen ) {
  127. case SFC_SCAN_NORMAL:
  128. case SFC_SCAN_ALWAYS:
  129. case SFC_SCAN_ONCE:
  130. retval = SfcWriteRegDword( REGKEY_WINLOGON, REGVAL_SFCSCAN, ScanWhen );
  131. break;
  132. case SFC_SCAN_IMMEDIATE:
  133. //
  134. // a user must be logged on for this API to be called since it can bring up
  135. // UI (if the user need to insert media to restore files, etc.) we could
  136. // succeed this and let the SfcScanProtectedDlls thread wait for a user to
  137. // log on if we wanted to.
  138. //
  139. if (!UserLoggedOn) {
  140. DebugPrint( LVL_MINIMAL, L"SfcSrv_InitiateScan: User not logged on" );
  141. retval = ERROR_NOT_LOGGED_ON;
  142. goto exit;
  143. }
  144. ScanParams = MemAlloc( sizeof(SCAN_PARAMS) );
  145. if (!ScanParams) {
  146. retval = ERROR_NOT_ENOUGH_MEMORY;
  147. goto exit;
  148. }
  149. //
  150. // set the progress window to null so we force ourselves to show UI
  151. //
  152. ScanParams->ProgressWindow = NULL;
  153. ScanParams->AllowUI = !SFCNoPopUps;
  154. ScanParams->FreeMemory = TRUE;
  155. //
  156. // start off another thread to do the scan.
  157. //
  158. hThread = CreateThread(
  159. NULL,
  160. 0,
  161. (LPTHREAD_START_ROUTINE)SfcScanProtectedDlls,
  162. ScanParams,
  163. 0,
  164. NULL
  165. );
  166. if (hThread) {
  167. CloseHandle( hThread );
  168. } else {
  169. MemFree(ScanParams);
  170. retval = GetLastError();
  171. }
  172. break;
  173. default:
  174. retval = ERROR_INVALID_PARAMETER;
  175. break;
  176. }
  177. exit:
  178. return(retval);
  179. }
  180. DWORD
  181. WINAPI
  182. SfcSrv_InstallProtectedFiles(
  183. IN HANDLE hBinding,
  184. IN const LPBYTE FileNamesBuffer,
  185. IN DWORD FileNamesSize,
  186. OUT LPBYTE *InstallStatusBuffer,
  187. OUT LPDWORD InstallStatusBufferSize,
  188. OUT LPDWORD InstallStatusCount,
  189. IN BOOL AllowUI,
  190. IN PCWSTR ClassName,
  191. IN PCWSTR WindowName
  192. )
  193. /*++
  194. Routine Description:
  195. Routine to install one or more protected system files onto the system at
  196. the protected location. A client can use this API to request that WFP
  197. install the specified operating system files as appropriate (instead of the
  198. client redistributing the operating system files!)
  199. The routine works by building up a file queue of the files specified by the
  200. caller, then it commits the queue.
  201. Arguments:
  202. RpcHandle - RPC binding handle to the SFC server
  203. FileNamesBuffer - a list of NULL seperated unicode strings, terminated by
  204. two NULL characters.
  205. FileNamesSize - DWORD indicating the size of the string buffer above.
  206. InstallStatusBuffer - receives an array of FILEINSTALL_STATUS structures
  207. InstallStatusBufferSize - receives the size of InstallStatusBuffer
  208. InstallStatusCount - receives the number of files processed
  209. AllowUI - a BOOL indicating whether UI is allowed or not. If this value
  210. is TRUE, then any prompts for UI cause the API call to fail.
  211. ClassName - NULL terminated unicode string indicating the window classname
  212. for the parent window
  213. WindowName - NULL terminated unicode string indicating the window name for
  214. the parent window for any UI that may be displayed
  215. Return Value:
  216. Win32 error code indicating outcome.
  217. --*/
  218. {
  219. WCHAR buf[MAX_PATH*2];
  220. HSPFILEQ hFileQ = INVALID_HANDLE_VALUE;
  221. PVOID MsgHandlerContext = NULL;
  222. DWORD rVal = ERROR_SUCCESS;
  223. NTSTATUS Status;
  224. DWORD ScanResult;
  225. FILE_COPY_INFO fci;
  226. PSFC_REGISTRY_VALUE RegVal;
  227. PWSTR fname;
  228. PNAME_NODE Node;
  229. ULONG cnt = 0,tmpcnt;
  230. ULONG sz = 0;
  231. PFILEINSTALL_STATUS cs = NULL;
  232. BOOL b;
  233. PWSTR s;
  234. PSOURCE_INFO si = NULL;
  235. PWSTR FileNamesScratchBuffer = NULL, FileNamesScratchBufferStart;
  236. PWSTR ClientBufferCopy = NULL;
  237. HCATADMIN hCatAdmin = NULL;
  238. UNREFERENCED_PARAMETER( hBinding );
  239. UNREFERENCED_PARAMETER( FileNamesSize );
  240. if(NULL == FileNamesBuffer || 0 == FileNamesSize || NULL == InstallStatusBuffer)
  241. {
  242. return ERROR_INVALID_PARAMETER;
  243. }
  244. if(*InstallStatusBuffer != NULL || *InstallStatusBufferSize != 0)
  245. {
  246. return ERROR_INVALID_DATA;
  247. }
  248. ZeroMemory( &fci, sizeof(FILE_COPY_INFO) );
  249. if (ClassName && *ClassName && WindowName && *WindowName) {
  250. fci.hWnd = FindWindow( ClassName, WindowName );
  251. }
  252. fci.AllowUI = AllowUI;
  253. //
  254. // create the file queue
  255. //
  256. hFileQ = SetupOpenFileQueue();
  257. if (hFileQ == INVALID_HANDLE_VALUE) {
  258. rVal = GetLastError();
  259. DebugPrint1( LVL_VERBOSE, L"SetupOpenFileQueue failed, ec=%d", rVal );
  260. goto exit;
  261. }
  262. //
  263. // find out how much space we'll need for the FILEINSTALL_STATUS array
  264. //
  265. try {
  266. ClientBufferCopy = MemAlloc( FileNamesSize );
  267. if (ClientBufferCopy) {
  268. RtlCopyMemory( ClientBufferCopy, FileNamesBuffer, FileNamesSize );
  269. fname = ClientBufferCopy;
  270. while (*fname) {
  271. ExpandEnvironmentStrings( fname, buf, UnicodeChars(buf) );
  272. DebugPrint1(LVL_VERBOSE, L"S_IPF [%ws]", buf);
  273. //
  274. // size = old size
  275. // + 8 (unicode null + slop)
  276. // + size of current string
  277. // + size of FILEINSTALL_STATUS for this entry
  278. //
  279. sz = sz + 8 + UnicodeLen(buf) + sizeof(FILEINSTALL_STATUS);
  280. cnt += 1;
  281. fname += (wcslen(fname) + 1);
  282. }
  283. } else {
  284. rVal = ERROR_NOT_ENOUGH_MEMORY;
  285. }
  286. } except (EXCEPTION_EXECUTE_HANDLER) {
  287. rVal = RtlNtStatusToDosError(GetExceptionCode());
  288. DebugPrint1(LVL_VERBOSE, L"S_IPF: exception occured while parsing client file buffer, ec=0x%08x", rVal);
  289. }
  290. if (rVal != ERROR_SUCCESS) {
  291. goto exit;
  292. }
  293. //
  294. // extra unicode NULL to size for termination is included in slop above
  295. //
  296. //
  297. // allocate and zero out the memory for the array
  298. //
  299. cs = (PFILEINSTALL_STATUS) midl_user_allocate( sz );
  300. if (cs == NULL) {
  301. rVal = ERROR_OUTOFMEMORY;
  302. goto exit;
  303. }
  304. ZeroMemory( cs, sz );
  305. *InstallStatusBuffer = (LPBYTE) cs;
  306. *InstallStatusBufferSize = sz;
  307. *InstallStatusCount = cnt;
  308. //
  309. // also create a scratch buffer for our files for later
  310. //
  311. FileNamesScratchBufferStart
  312. = FileNamesScratchBuffer
  313. = (PWSTR) MemAlloc(cnt * MAX_PATH * 2 * sizeof(WCHAR));
  314. if (!FileNamesScratchBuffer) {
  315. rVal = GetLastError();
  316. DebugPrint1( LVL_VERBOSE,
  317. L"S_IPF: MemAlloc (%d) failed",
  318. FileNamesSize );
  319. goto exit;
  320. }
  321. //
  322. // create an array of sourceinfo pointers (and an array of source_info
  323. // structures) so that the commital callback routine can find out about
  324. // the status of each file
  325. //
  326. fci.CopyStatus = cs;
  327. fci.FileCount = cnt;
  328. fci.si = (PSOURCE_INFO *)MemAlloc( cnt * sizeof(PSOURCE_INFO) );
  329. if (!fci.si) {
  330. DebugPrint1( LVL_VERBOSE,
  331. L"S_IPF: MemAlloc (%d) failed",
  332. cnt* sizeof(PSOURCE_INFO) );
  333. rVal = ERROR_OUTOFMEMORY;
  334. goto exit;
  335. }
  336. si = MemAlloc( cnt * sizeof(SOURCE_INFO) );
  337. if (!si) {
  338. DebugPrint1( LVL_VERBOSE,
  339. L"S_IPF: MemAlloc (%d) failed",
  340. cnt* sizeof(SOURCE_INFO) );
  341. rVal = ERROR_OUTOFMEMORY;
  342. goto exit;
  343. }
  344. fname = ClientBufferCopy;
  345. //
  346. // now build up the FILEINSTALL_STATUS array
  347. //
  348. //
  349. // First set a string pointer to the end of the FILEINSTALL_STATUS
  350. // array. We will later copy strings after the array of structures.
  351. //
  352. s = (PWSTR)((LPBYTE)cs + (cnt * sizeof(FILEINSTALL_STATUS)));
  353. tmpcnt = 0;
  354. //
  355. // Second, for each member in the caller supplied list,
  356. // - copy the filename to the end of the array
  357. // - save off the pointer to the filename in the proper FILEINSTALL_STATUS
  358. // member
  359. // - point to the next file in the list
  360. //
  361. while (*fname) {
  362. DWORD StringLength;
  363. ExpandEnvironmentStrings( fname, buf, UnicodeChars(buf) );
  364. StringLength = wcslen(buf);
  365. MyLowerString(buf, StringLength);
  366. wcsncpy(&FileNamesScratchBuffer[MAX_PATH*2*tmpcnt],buf,MAX_PATH);
  367. cs->FileName = s;
  368. wcscpy( s, &FileNamesScratchBuffer[MAX_PATH*2*tmpcnt] );
  369. s += StringLength + 1;
  370. cs += 1;
  371. tmpcnt += 1;
  372. fname += (wcslen(fname) + 1);
  373. ASSERT(tmpcnt <= cnt);
  374. }
  375. //
  376. // we're finally ready to queue files
  377. // - determine where the file comes from
  378. // - add the file to the queue using the appropriate filename if the file
  379. // is renamed
  380. //
  381. cs = fci.CopyStatus;
  382. FileNamesScratchBuffer = FileNamesScratchBufferStart;
  383. //
  384. //initialize crypto
  385. //
  386. Status = LoadCrypto();
  387. if(!NT_SUCCESS(Status))
  388. {
  389. rVal = RtlNtStatusToDosError(Status);
  390. goto exit;
  391. }
  392. if(!CryptCATAdminAcquireContext(&hCatAdmin, &DriverVerifyGuid, 0)) {
  393. rVal = GetLastError();
  394. DebugPrint1( LVL_MINIMAL, L"CCAAC() failed, ec = 0x%08x", rVal);
  395. goto exit;
  396. }
  397. //
  398. // Flush the Cache once before we start any Crypto operations
  399. //
  400. SfcFlushCryptoCache();
  401. //
  402. // Refresh exception packages info
  403. //
  404. SfcRefreshExceptionInfo();
  405. tmpcnt=0;
  406. while (tmpcnt < cnt) {
  407. Node = SfcFindProtectedFile( (PWSTR)&FileNamesScratchBuffer[MAX_PATH*2*tmpcnt], UnicodeLen(&FileNamesScratchBuffer[MAX_PATH*2*tmpcnt]) );
  408. if (Node) {
  409. HANDLE FileHandle;
  410. NTSTATUS Status;
  411. BOOL QueuedFromCache;
  412. IMAGE_VALIDATION_DATA SignatureData;
  413. UNICODE_STRING tmpPath;
  414. WCHAR InfFileName[MAX_PATH];
  415. BOOL ExcepPackFile;
  416. RegVal = (PSFC_REGISTRY_VALUE)Node->Context;
  417. ASSERT(RegVal != NULL);
  418. //
  419. // get the inf name here
  420. //
  421. ExcepPackFile = SfcGetInfName(RegVal, InfFileName);
  422. //
  423. // Setup the SOURCE_INFO structure so we can record where each file in
  424. // the list is coming from (ie., golden media, driver cabinet,
  425. // service pack, etc.)
  426. //
  427. fci.si[tmpcnt] = &si[tmpcnt];
  428. if (!SfcGetSourceInformation( RegVal->SourceFileName.Length ? RegVal->SourceFileName.Buffer : RegVal->FileName.Buffer, InfFileName, ExcepPackFile, &si[tmpcnt] )) {
  429. rVal = GetLastError();
  430. DebugPrint2(LVL_VERBOSE, L"S_IPF failed SfcGetSourceInformation() on %ws, ec = %x",
  431. RegVal->SourceFileName.Length ? RegVal->SourceFileName.Buffer : RegVal->FileName.Buffer,
  432. rVal
  433. );
  434. goto exit;
  435. }
  436. //
  437. // If the file is in the dllcache and it's valid, then queue up the
  438. // file to be copied from the dllcache instead of the installation
  439. // source.
  440. //
  441. // First we check the signature of the file in the dllcache. Then
  442. // we try to queue up the file from the cache if the signature is
  443. // valid. If anything goes wrong, we just queue from the regular
  444. // install media
  445. //
  446. QueuedFromCache = FALSE;
  447. RtlInitUnicodeString( &tmpPath, FileNameOnMedia( RegVal ) );
  448. if (!SfcGetValidationData(
  449. &tmpPath,
  450. &SfcProtectedDllPath,
  451. SfcProtectedDllFileDirectory,
  452. hCatAdmin,
  453. &SignatureData)) {
  454. DebugPrint1( LVL_MINIMAL,
  455. L"SfcGetValidationData() failed, ec = 0x%08x",
  456. GetLastError() );
  457. } else if (SignatureData.SignatureValid) {
  458. //
  459. // The file is valid, so queue it up.
  460. //
  461. // We have to munge some of the SOURCE_INFO members to make
  462. // this function do what we want. Remember these members
  463. // in case the queuing fails. Then we can at least try to
  464. // queue the files for installation from media.
  465. //
  466. WCHAR SourcePathOld;
  467. SourcePathOld = si[tmpcnt].SourcePath[0];
  468. si[tmpcnt].SourcePath[0] = L'\0';
  469. b = SfcAddFileToQueue(
  470. hFileQ,
  471. RegVal->FileName.Buffer,
  472. RegVal->FileName.Buffer,
  473. RegVal->DirName.Buffer,
  474. FileNameOnMedia( RegVal ),
  475. SfcProtectedDllPath.Buffer,
  476. InfFileName,
  477. ExcepPackFile,
  478. &si[tmpcnt]
  479. );
  480. if (!b) {
  481. //
  482. // put the source path back
  483. //
  484. si[tmpcnt].SourcePath[0] = SourcePathOld;
  485. //
  486. // print out an error but continue.
  487. //
  488. rVal = GetLastError();
  489. DebugPrint2(
  490. LVL_VERBOSE,
  491. L"S_IPF failed SfcAddFileToQueue(DLLCACHE) on %ws, ec = %x",
  492. RegVal->FileName.Buffer,
  493. rVal );
  494. } else {
  495. //
  496. // successfully queued from cache. remember this and continue
  497. //
  498. QueuedFromCache = TRUE;
  499. }
  500. }
  501. //
  502. // add the file to the queue if we haven't already
  503. //
  504. if (!QueuedFromCache) {
  505. b = SfcAddFileToQueue(
  506. hFileQ,
  507. RegVal->FileName.Buffer,
  508. RegVal->FileName.Buffer,
  509. RegVal->DirName.Buffer,
  510. FileNameOnMedia( RegVal ),
  511. NULL,
  512. InfFileName,
  513. ExcepPackFile,
  514. &si[tmpcnt]
  515. );
  516. if (!b) {
  517. rVal = GetLastError();
  518. DebugPrint2(
  519. LVL_VERBOSE,
  520. L"S_IPF failed SfcAddFileToQueue() on %ws, ec = %x",
  521. RegVal->FileName.Buffer,
  522. rVal );
  523. goto exit;
  524. }
  525. }
  526. //
  527. // see if the file is already present so we can save off the file
  528. // version. If we copy in a new file, we will update the file
  529. // version at that time. But if the file is already present and
  530. // signed, we will not copy the file and we must save off the file
  531. // version in that case.
  532. //
  533. Status = SfcOpenFile( &RegVal->FileName, RegVal->DirHandle, SHARE_ALL, &FileHandle);
  534. if (NT_SUCCESS(Status)) {
  535. SfcGetFileVersion( FileHandle, &cs->Version, NULL, NULL);
  536. NtClose( FileHandle );
  537. }
  538. } else {
  539. //
  540. // File is not in protected list. We'll just mark the file as not
  541. // found and continue committing the rest of the files
  542. //
  543. DebugPrint1(LVL_VERBOSE,
  544. L"S_IPF failed to find %ws in protected file list",
  545. &FileNamesScratchBuffer[MAX_PATH*2*tmpcnt] );
  546. cs->Win32Error = ERROR_FILE_NOT_FOUND;
  547. }
  548. cs += 1;
  549. tmpcnt+=1;
  550. }
  551. cs = fci.CopyStatus;
  552. fci.Flags |= FCI_FLAG_INSTALL_PROTECTED;
  553. //
  554. // setup the default queue callback with the popups disabled
  555. //
  556. MsgHandlerContext = SetupInitDefaultQueueCallbackEx( NULL, INVALID_HANDLE_VALUE, 0, 0, 0 );
  557. if (MsgHandlerContext == NULL) {
  558. rVal = GetLastError();
  559. DebugPrint1( LVL_VERBOSE, L"SetupInitDefaultQueueCallbackEx failed, ec=%d", rVal );
  560. goto exit;
  561. }
  562. fci.MsgHandlerContext = MsgHandlerContext;
  563. //
  564. // see if the files in the queue are already present and valid. If they
  565. // are, then we don't have to copy anything
  566. //
  567. b = SetupScanFileQueue(
  568. hFileQ,
  569. SPQ_SCAN_FILE_VALIDITY | SPQ_SCAN_PRUNE_COPY_QUEUE,
  570. fci.hWnd,
  571. NULL,
  572. NULL,
  573. &ScanResult);
  574. //
  575. // if SetupScanFileQueue succeeds, ScanResult = 1 and we don't have to copy
  576. // anything at all. If it failed (it shouldn't), then we just commit the
  577. // queue anyway.
  578. //
  579. if (!b) {
  580. ScanResult = 0;
  581. }
  582. if (ScanResult == 1) {
  583. b = TRUE;
  584. } else {
  585. //
  586. // commit the file queue
  587. //
  588. b = SetupCommitFileQueue(
  589. NULL,
  590. hFileQ,
  591. SfcQueueCallback,
  592. &fci
  593. );
  594. if (!b) {
  595. DebugPrint1( LVL_VERBOSE, L"SetupCommitFileQueue failed, ec=%d", GetLastError() );
  596. rVal = GetLastError();
  597. goto exit;
  598. }
  599. }
  600. //
  601. // now that the queue is committed, we need to turn the filename pointers
  602. // from actual filename pointers into offsets to the filename so that RPC
  603. // can send the data back to the clients
  604. //
  605. for (sz=0; sz<cnt; sz++) {
  606. cs[sz].FileName = (PWSTR)((DWORD_PTR)cs[sz].FileName - (DWORD_PTR)fci.CopyStatus);
  607. }
  608. exit:
  609. //
  610. // cleanup and exit
  611. //
  612. if (hCatAdmin) {
  613. CryptCATAdminReleaseContext(hCatAdmin,0);
  614. }
  615. if (MsgHandlerContext) {
  616. SetupTermDefaultQueueCallback( MsgHandlerContext );
  617. }
  618. if (hFileQ != INVALID_HANDLE_VALUE) {
  619. SetupCloseFileQueue( hFileQ );
  620. }
  621. if (FileNamesScratchBuffer) {
  622. MemFree(FileNamesScratchBuffer);
  623. }
  624. if (si) {
  625. MemFree( si );
  626. }
  627. if (fci.si) {
  628. MemFree( fci.si );
  629. }
  630. if (ClientBufferCopy) {
  631. MemFree( ClientBufferCopy );
  632. }
  633. if (rVal != ERROR_SUCCESS) {
  634. if (cs) midl_user_free(cs);
  635. *InstallStatusBuffer = NULL;
  636. *InstallStatusBufferSize = 0;
  637. *InstallStatusCount = 0;
  638. }
  639. return rVal;
  640. }
  641. DWORD
  642. WINAPI
  643. SfcSrv_GetNextProtectedFile(
  644. IN HANDLE RpcHandle,
  645. IN DWORD FileNumber,
  646. IN LPBYTE *FileName,
  647. IN LPDWORD FileNameSize
  648. )
  649. /*++
  650. Routine Description:
  651. Routine to retrieve the next protected file in the list.
  652. Arguments:
  653. RpcHandle - RPC binding handle to the SFC server
  654. FileNumer - 1-based number of file to be retrieved
  655. FileName - receives file name string
  656. FileNameSize - size of file name string
  657. Return Value:
  658. win32 error code indicating success.
  659. --*/
  660. {
  661. LPWSTR szName;
  662. LPBYTE pBuffer;
  663. DWORD dwSize;
  664. UNREFERENCED_PARAMETER( RpcHandle );
  665. if(NULL == FileName)
  666. {
  667. return ERROR_INVALID_PARAMETER;
  668. }
  669. if(*FileName != NULL || *FileNameSize != 0)
  670. {
  671. return ERROR_INVALID_DATA;
  672. }
  673. //
  674. // The filenumber is zero based, and we return "no more files" to
  675. // signify that they've enumerated all of the files
  676. //
  677. if (FileNumber >= SfcProtectedDllCount) {
  678. return ERROR_NO_MORE_FILES;
  679. }
  680. //
  681. // get the proper file from the list, allocate a buffer, and copy the
  682. // filename into the buffer
  683. //
  684. szName = SfcProtectedDllsList[FileNumber].FullPathName.Buffer;
  685. dwSize = UnicodeLen(szName) + sizeof(WCHAR);
  686. pBuffer = (LPBYTE) midl_user_allocate( dwSize );
  687. if(NULL == pBuffer)
  688. return ERROR_NOT_ENOUGH_MEMORY;
  689. RtlCopyMemory( pBuffer, szName, dwSize);
  690. *FileName = pBuffer;
  691. *FileNameSize = dwSize;
  692. return ERROR_SUCCESS;
  693. }
  694. DWORD
  695. WINAPI
  696. SfcSrv_IsFileProtected(
  697. IN HANDLE RpcHandle,
  698. IN PCWSTR ProtFileName
  699. )
  700. /*++
  701. Routine Description:
  702. Routine to determine if the specified file is protected.
  703. Arguments:
  704. RpcHandle - RPC binding handle to the SFC server
  705. ProtFileName - NULL terminated unicode string indicating fully qualified
  706. filename to query
  707. Return Value:
  708. Win32 error code indicating outcome.
  709. --*/
  710. {
  711. WCHAR buf[MAX_PATH];
  712. DWORD dwSize;
  713. UNREFERENCED_PARAMETER( RpcHandle );
  714. if (!ProtFileName)
  715. return ERROR_INVALID_PARAMETER;
  716. //
  717. // our internal structures all assume the strings are in lower case. we
  718. // must convert our search string to lowercase as well.
  719. //
  720. if (!*ProtFileName)
  721. return ERROR_INVALID_DATA;
  722. dwSize = ExpandEnvironmentStrings( ProtFileName, buf, UnicodeChars(buf));
  723. if(0 == dwSize)
  724. {
  725. DWORD retval = GetLastError();
  726. DebugPrint1( LVL_MINIMAL, L"ExpandEnvironmentStrings failed, ec = 0x%x", retval);
  727. return retval;
  728. }
  729. if(dwSize > UnicodeChars(buf))
  730. {
  731. //
  732. // expandenvironmentstrings must have encountered a buffer that was
  733. // too large
  734. //
  735. DebugPrint(LVL_MINIMAL, L"ExpandEnvironmentStrings failed with STATUS_BUFFER_TOO_SMALL");
  736. return ERROR_INSUFFICIENT_BUFFER;
  737. }
  738. MyLowerString( buf, wcslen(buf) );
  739. if (!SfcFindProtectedFile( buf, UnicodeLen(buf) ))
  740. return ERROR_FILE_NOT_FOUND;
  741. return ERROR_SUCCESS;
  742. }
  743. DWORD
  744. WINAPI
  745. SfcSrv_PurgeCache(
  746. IN HANDLE hBinding
  747. )
  748. /*++
  749. Routine Description:
  750. Routine to purge the contents of the dllcache.
  751. Arguments:
  752. RpcHandle - RPC binding handle to the SFC server
  753. Return Value:
  754. Win32 error code indicating outcome.
  755. --*/
  756. {
  757. DWORD retval = ERROR_SUCCESS, DeleteError = ERROR_SUCCESS;
  758. WCHAR CacheDir[MAX_PATH];
  759. WIN32_FIND_DATA FindFileData;
  760. HANDLE hFind;
  761. PWSTR p;
  762. //
  763. // do an access check to make sure the caller is allowed to perform this
  764. // action.
  765. //
  766. retval = SfcRpcPriviledgeCheck( hBinding );
  767. if (retval != ERROR_SUCCESS) {
  768. goto exit;
  769. }
  770. ASSERT(SfcProtectedDllPath.Buffer != NULL);
  771. wcscpy( CacheDir, SfcProtectedDllPath.Buffer);
  772. pSetupConcatenatePaths( CacheDir, L"*", MAX_PATH, NULL );
  773. //
  774. // save pointer to directory
  775. //
  776. p = wcsrchr( CacheDir, L'\\' );
  777. if (!p) {
  778. ASSERT(FALSE);
  779. retval = ERROR_INVALID_DATA;
  780. goto exit;
  781. }
  782. p += 1;
  783. hFind = FindFirstFile( CacheDir, &FindFileData );
  784. if (hFind == INVALID_HANDLE_VALUE) {
  785. retval = GetLastError();
  786. goto exit;
  787. }
  788. do {
  789. if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
  790. wcscpy( p, FindFileData.cFileName );
  791. SetFileAttributes( CacheDir, FILE_ATTRIBUTE_NORMAL );
  792. if (!DeleteFile( CacheDir )) {
  793. DeleteError = GetLastError();
  794. }
  795. }
  796. } while(FindNextFile( hFind, &FindFileData ));
  797. FindClose( hFind );
  798. retval = DeleteError;
  799. exit:
  800. return(retval);
  801. }
  802. DWORD
  803. WINAPI
  804. SfcSrv_SetDisable(
  805. IN HANDLE hBinding,
  806. IN DWORD NewValue
  807. )
  808. /*++
  809. Routine Description:
  810. Routine to set the disable flag in the registry.
  811. Arguments:
  812. RpcHandle - RPC binding handle to the SFC server
  813. NewValue - value of SFCDisable key in registry.
  814. Return Value:
  815. Win32 error code indicating outcome.
  816. --*/
  817. {
  818. DWORD retval = ERROR_SUCCESS;
  819. //
  820. // do an access check to make sure the caller is allowed to perform this
  821. // action.
  822. //
  823. retval = SfcRpcPriviledgeCheck( hBinding );
  824. if (retval != ERROR_SUCCESS) {
  825. goto exit;
  826. }
  827. switch( NewValue ) {
  828. case SFC_DISABLE_SETUP:
  829. case SFC_DISABLE_QUIET:
  830. retval = ERROR_INVALID_PARAMETER;
  831. break;
  832. case SFC_DISABLE_ONCE:
  833. case SFC_DISABLE_NOPOPUPS:
  834. case SFC_DISABLE_ASK:
  835. case SFC_DISABLE_NORMAL:
  836. retval = SfcWriteRegDword( REGKEY_WINLOGON, REGVAL_SFCDISABLE, NewValue );
  837. //
  838. // Issue: it would be nice if we made this "realtime", and shutdown
  839. // WFP if the caller requested.
  840. //
  841. // InterlockedExchange( &SFCDisable, NewValue );
  842. break;
  843. }
  844. exit:
  845. return(retval);
  846. }
  847. DWORD
  848. WINAPI
  849. SfcSrv_SetCacheSize(
  850. IN HANDLE hBinding,
  851. IN DWORD NewValue
  852. )
  853. /*++
  854. Routine Description:
  855. Routine to set the dllcache quota size.
  856. Arguments:
  857. RpcHandle - RPC binding handle to the SFC server
  858. NewValue - value of SFCQuota key in registry.
  859. Return Value:
  860. Win32 error code indicating outcome.
  861. --*/
  862. {
  863. DWORD retval = ERROR_SUCCESS;
  864. ULONGLONG tmp;
  865. //
  866. // do an access check to make sure the caller is allowed to perform this
  867. // action.
  868. //
  869. retval = SfcRpcPriviledgeCheck( hBinding );
  870. if (retval != ERROR_SUCCESS) {
  871. goto exit;
  872. }
  873. if( NewValue == SFC_QUOTA_ALL_FILES ) {
  874. tmp = (ULONGLONG)-1;
  875. } else {
  876. tmp = NewValue * (1024*1024);
  877. }
  878. SFCQuota = tmp;
  879. retval = SfcWriteRegDword( REGKEY_WINLOGON, REGVAL_SFCQUOTA, NewValue );
  880. exit:
  881. return(retval);
  882. }