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.

783 lines
18 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. apicli.c
  5. Abstract:
  6. Windows File Protection client side APIs.
  7. Author:
  8. Wesley Witt (wesw) 27-May-1999
  9. Revision History:
  10. Andrew Ritz (andrewr) 5-Jul-1999 : added comments
  11. --*/
  12. #include "sfcp.h"
  13. #pragma hdrstop
  14. #define STRSAFE_NO_DEPRECATE
  15. #include <strsafe.h>
  16. //
  17. // global RPC binding handle because some client API's don't require you to
  18. // specify an RPC handle
  19. //
  20. HANDLE _pRpcHandle;
  21. //
  22. // these macros are used by each client side api to
  23. // ensure that we have a valid rpc handle. if the
  24. // calling application chooses to not call SfcConnectToServer
  25. // they connect to the local server and save the handle
  26. // in a global for future use.
  27. //
  28. #define EnsureGoodConnectionHandleStatus(_h)\
  29. if (_h == NULL) {\
  30. if (_pRpcHandle == NULL) {\
  31. _pRpcHandle = SfcConnectToServer( NULL );\
  32. if (_pRpcHandle == NULL) {\
  33. return RPC_S_SERVER_UNAVAILABLE;\
  34. }\
  35. }\
  36. _h = _pRpcHandle;\
  37. }
  38. #define EnsureGoodConnectionHandleBool(_h)\
  39. if (_h == NULL) {\
  40. if (_pRpcHandle == NULL) {\
  41. _pRpcHandle = SfcConnectToServer( NULL );\
  42. if (_pRpcHandle == NULL) {\
  43. SetLastError(RPC_S_SERVER_UNAVAILABLE);\
  44. return FALSE;\
  45. }\
  46. }\
  47. _h = _pRpcHandle;\
  48. }
  49. void
  50. ClientApiInit(
  51. void
  52. )
  53. {
  54. #ifndef _WIN64
  55. SfcInitPathTranslator();
  56. #endif // _WIN64
  57. }
  58. void
  59. ClientApiCleanup(
  60. void
  61. )
  62. /*++
  63. Routine Description:
  64. RPC cleanup wrapper routine called by client side when done with server side
  65. connection that was previously established with SfcConnectToServer().
  66. Arguments:
  67. None
  68. Return Value:
  69. none.
  70. --*/
  71. {
  72. if (_pRpcHandle) {
  73. SfcClose( _pRpcHandle );
  74. _pRpcHandle = NULL;
  75. }
  76. #ifndef _WIN64
  77. SfcCleanupPathTranslator(TRUE);
  78. #endif // _WIN64
  79. }
  80. HANDLE
  81. WINAPI
  82. SfcConnectToServer(
  83. IN PCWSTR ServerName
  84. )
  85. /*++
  86. Routine Description:
  87. RPC attachment routine.
  88. Arguments:
  89. ServerName - NULL terminated unicode string specifying server to connect to
  90. Return Value:
  91. an RPC binding handle on success, else NULL.
  92. --*/
  93. {
  94. RPC_STATUS Status;
  95. RPC_BINDING_HANDLE RpcHandle = NULL;
  96. PWSTR szStringBinding = NULL;
  97. RPC_SECURITY_QOS qos;
  98. PWSTR szPrincName = NULL;
  99. PSID pSid = NULL;
  100. if (ServerName) {
  101. Status = ERROR_CALL_NOT_IMPLEMENTED;
  102. goto exit;
  103. }
  104. //
  105. // We need to get the name of the local system account for mutual authentication to the server
  106. //
  107. Status = SfcCreateSid(WinLocalSystemSid, &pSid);
  108. if(Status != ERROR_SUCCESS) {
  109. goto exit;
  110. }
  111. Status = SfcGetSidName(pSid, &szPrincName);
  112. if(Status != ERROR_SUCCESS) {
  113. goto exit;
  114. }
  115. //
  116. // Compose a binding string using LRPC protocol and WFP's endpoint name
  117. //
  118. Status = RpcStringBindingCompose(
  119. NULL,
  120. L"ncalrpc",
  121. NULL,
  122. SFC_RPC_ENDPOINT,
  123. NULL,
  124. &szStringBinding
  125. );
  126. if(Status != RPC_S_OK) {
  127. szStringBinding = NULL;
  128. goto exit;
  129. }
  130. //
  131. // Connect and get the binding handle
  132. //
  133. Status = RpcBindingFromStringBinding(szStringBinding, &RpcHandle);
  134. if(Status != RPC_S_OK) {
  135. RpcHandle = NULL;
  136. goto exit;
  137. }
  138. //
  139. // Make RPC use mutual authentication
  140. //
  141. RtlZeroMemory(&qos, sizeof(qos));
  142. qos.Version = RPC_C_SECURITY_QOS_VERSION;
  143. qos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  144. qos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  145. qos.ImpersonationType = RPC_C_IMP_LEVEL_IDENTIFY;
  146. Status = RpcBindingSetAuthInfoEx(
  147. RpcHandle,
  148. szPrincName,
  149. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // used anyway with ncalrpc
  150. RPC_C_AUTHN_WINNT,
  151. NULL, // current process credentials
  152. RPC_C_AUTHZ_NONE,
  153. &qos
  154. );
  155. if(Status != RPC_S_OK) {
  156. RpcBindingFree(&RpcHandle);
  157. RpcHandle = NULL;
  158. goto exit;
  159. }
  160. exit:
  161. if(szStringBinding != NULL) {
  162. RpcStringFree(&szStringBinding);
  163. }
  164. MemFree(szPrincName);
  165. MemFree(pSid);
  166. SetLastError(Status);
  167. return RpcHandle;
  168. }
  169. VOID
  170. SfcClose(
  171. IN HANDLE RpcHandle
  172. )
  173. /*++
  174. Routine Description:
  175. RPC cleanup routine.
  176. Arguments:
  177. RpcHandle - RPC binding handle to the SFC server
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. RpcBindingFree(&RpcHandle);
  183. }
  184. DWORD
  185. WINAPI
  186. SfcFileException(
  187. IN HANDLE RpcHandle,
  188. IN PCWSTR FileName,
  189. IN DWORD ExpectedChangeType
  190. )
  191. /*++
  192. Routine Description:
  193. Routine to exempt a given file from the specified file change. This
  194. routine is used by certain clients to allow files to be deleted from
  195. the system, etc.
  196. Arguments:
  197. RpcHandle - RPC binding handle to the SFC server
  198. FileName - NULL terminated unicode string specifying full filename of the
  199. file to be exempted
  200. ExpectedChangeType - SFC_ACTION_* mask listing the file changes to exempt
  201. Return Value:
  202. Win32 error code indicating outcome.
  203. --*/
  204. {
  205. #ifndef _WIN64
  206. DWORD dwError = ERROR_SUCCESS;
  207. UNICODE_STRING Path = { 0 };
  208. NTSTATUS Status;
  209. if(NULL == FileName || 0 == FileName[0]) {
  210. dwError = ERROR_INVALID_PARAMETER;
  211. goto exit;
  212. }
  213. EnsureGoodConnectionHandleStatus( RpcHandle );
  214. Status = SfcRedirectPath(FileName, &Path);
  215. if(!NT_SUCCESS(Status))
  216. {
  217. dwError = RtlNtStatusToDosError(Status);
  218. goto exit;
  219. }
  220. ASSERT(Path.Buffer != NULL);
  221. dwError = SfcCli_FileException( RpcHandle, Path.Buffer, ExpectedChangeType );
  222. exit:
  223. MemFree(Path.Buffer);
  224. return dwError;
  225. #else // _WIN64
  226. EnsureGoodConnectionHandleStatus( RpcHandle );
  227. return SfcCli_FileException( RpcHandle, FileName, ExpectedChangeType );
  228. #endif // _WIN64
  229. }
  230. DWORD
  231. WINAPI
  232. SfcInitiateScan(
  233. IN HANDLE RpcHandle,
  234. IN DWORD ScanWhen
  235. )
  236. /*++
  237. Routine Description:
  238. Routine to start some sort scan on the system.
  239. Arguments:
  240. RpcHandle - RPC binding handle to the SFC server
  241. ScanWhen - flag indicating when to scan. This parameter is currently
  242. unused.
  243. Return Value:
  244. Win32 error code indicating outcome.
  245. --*/
  246. {
  247. UNREFERENCED_PARAMETER(ScanWhen);
  248. EnsureGoodConnectionHandleStatus( RpcHandle );
  249. return SfcCli_InitiateScan( RpcHandle, ScanWhen );
  250. }
  251. BOOL
  252. WINAPI
  253. SfcInstallProtectedFiles(
  254. IN HANDLE RpcHandle,
  255. IN PCWSTR FileNames,
  256. IN BOOL AllowUI,
  257. IN PCWSTR ClassName,
  258. IN PCWSTR WindowName,
  259. IN PSFCNOTIFICATIONCALLBACK SfcNotificationCallback,
  260. IN DWORD_PTR Context OPTIONAL
  261. )
  262. /*++
  263. Routine Description:
  264. Routine to install one or more protected system files onto the system at
  265. the protected location. A client can use this API to request that WFP
  266. install the specified operating system files as appropriate (instead of the
  267. client redistributing the operating system files!) The caller specifies a
  268. callback routine and a context structure that is called once per file.
  269. Arguments:
  270. RpcHandle - RPC binding handle to the SFC server
  271. FileNames - a list of NULL seperated unicode strings, terminated by two
  272. NULL characters
  273. AllowUI - a BOOL indicating whether UI is allowed or not. If this value
  274. is TRUE, then any prompts for UI cause the API call to fail.
  275. ClassName - NULL terminated unicode string indicating the window classname
  276. for the parent window
  277. WindowName - NULL terminated unicode string indicating the window name for
  278. the parent window for any UI that may be displayed
  279. SfcNotificationCallback - pointer to a callback routine that is called once
  280. per file.
  281. Context - opaque pointer to caller defined context structure that is
  282. passed through to the callback routine.
  283. Return Value:
  284. TRUE for success, FALSE for error. last error code contains a Win32 error
  285. code on failure.
  286. --*/
  287. {
  288. DWORD rVal = ERROR_SUCCESS;
  289. PCWSTR fname;
  290. ULONG cnt = 0, cntold = 0;
  291. ULONG sz = 0;
  292. PFILEINSTALL_STATUS cs = NULL;
  293. DWORD StatusSize = 0;
  294. UNICODE_STRING Path = { 0 };
  295. #ifndef _WIN64
  296. //
  297. // must translate the paths
  298. //
  299. PWSTR szTranslatedFiles = NULL;
  300. #endif
  301. //
  302. // parameter validation
  303. //
  304. if((SfcNotificationCallback == NULL) ||
  305. (FileNames == NULL)) {
  306. rVal = ERROR_INVALID_PARAMETER;
  307. goto exit;
  308. }
  309. //
  310. // 1. if a windowname is specified, a classname should be specified
  311. // 2. if a classname is specified, a windowname should be specified
  312. // 3. if we don't allow UI, then windowname and classname should both be
  313. // NULL.
  314. //
  315. if ((WindowName && !ClassName)
  316. || (ClassName && !WindowName)
  317. || (!AllowUI && (ClassName || WindowName))) {
  318. rVal = ERROR_INVALID_PARAMETER;
  319. goto exit;
  320. }
  321. //
  322. // validate RPC handle
  323. //
  324. EnsureGoodConnectionHandleBool( RpcHandle );
  325. //
  326. // check out how large of a buffer to send over
  327. //
  328. try {
  329. #ifdef _WIN64
  330. for(fname = FileNames; *fname; ++cntold) {
  331. DWORD StringLength;
  332. StringLength = wcslen(fname) + 1;
  333. sz += StringLength * sizeof(WCHAR);
  334. fname += StringLength;
  335. }
  336. #else
  337. //
  338. // must translate paths before calling the server
  339. //
  340. PWSTR szNewBuf = NULL;
  341. for(fname = FileNames; *fname; fname += wcslen(fname) + 1, ++cntold) {
  342. NTSTATUS Status;
  343. Status = SfcRedirectPath(fname, &Path);
  344. if(!NT_SUCCESS(Status))
  345. {
  346. rVal = RtlNtStatusToDosError(Status);
  347. goto exit;
  348. }
  349. if(NULL == szTranslatedFiles)
  350. {
  351. szNewBuf = (PWSTR) MemAlloc(Path.Length + 2 * sizeof(WCHAR));
  352. }
  353. else
  354. {
  355. szNewBuf = (PWSTR) MemReAlloc(sz + Path.Length + 2 * sizeof(WCHAR), szTranslatedFiles);
  356. }
  357. if(szNewBuf != NULL)
  358. {
  359. szTranslatedFiles = szNewBuf;
  360. RtlCopyMemory((PCHAR) szTranslatedFiles + sz, Path.Buffer, Path.Length + sizeof(WCHAR));
  361. sz += Path.Length + sizeof(WCHAR);
  362. }
  363. MemFree(Path.Buffer);
  364. RtlZeroMemory(&Path, sizeof(Path));
  365. if(NULL == szNewBuf)
  366. {
  367. rVal = ERROR_NOT_ENOUGH_MEMORY;
  368. goto exit;
  369. }
  370. }
  371. //
  372. //set the last null
  373. //
  374. if(szTranslatedFiles != NULL)
  375. {
  376. szTranslatedFiles[sz / sizeof(WCHAR)] = L'\0';
  377. }
  378. #endif
  379. } except (EXCEPTION_EXECUTE_HANDLER) {
  380. rVal = RtlNtStatusToDosError(GetExceptionCode());
  381. goto exit;
  382. }
  383. if(0 == cntold)
  384. {
  385. //
  386. // not files to install
  387. //
  388. rVal = ERROR_INVALID_PARAMETER;
  389. goto exit;
  390. }
  391. //
  392. // for terminating NULL
  393. //
  394. sz+=sizeof(WCHAR);
  395. //
  396. // make the RPC call to install the files
  397. //
  398. rVal = SfcCli_InstallProtectedFiles(
  399. RpcHandle,
  400. #ifdef _WIN64
  401. (LPBYTE)FileNames,
  402. #else
  403. (LPBYTE)szTranslatedFiles,
  404. #endif
  405. sz,
  406. (LPBYTE*)&cs,
  407. &StatusSize,
  408. &cnt,
  409. AllowUI,
  410. ClassName,
  411. WindowName
  412. );
  413. if (rVal != ERROR_SUCCESS) {
  414. goto exit;
  415. }
  416. //
  417. // we should have gotten back the same amount of status information as the
  418. // number of files that we passed in
  419. //
  420. ASSERT(cnt == cntold);
  421. //
  422. // call the callback function once for each file, now that we've completed
  423. // copying the files in the list. We pass the caller a structure which
  424. // indicates the success of copying each individual file in the list.
  425. //
  426. for (fname = FileNames, sz=0; sz<cnt; sz++, fname += wcslen(fname) + 1) {
  427. LPEXCEPTION_POINTERS ExceptionPointers = NULL;
  428. try {
  429. NTSTATUS Status;
  430. BOOL b;
  431. //
  432. // don't use the (possibly reditected) file names returned from the server
  433. //
  434. Status = SfcAllocUnicodeStringFromPath(fname, &Path);
  435. if(!NT_SUCCESS(Status))
  436. {
  437. rVal = RtlNtStatusToDosError(Status);
  438. goto exit;
  439. }
  440. cs[sz].FileName = Path.Buffer;
  441. b = SfcNotificationCallback( &cs[sz], Context );
  442. MemFree(Path.Buffer);
  443. RtlZeroMemory(&Path, sizeof(Path));
  444. if (!b) {
  445. //
  446. // return FALSE if the callback fails for any reason
  447. //
  448. rVal = ERROR_CANCELLED;
  449. goto exit;
  450. }
  451. } except (ExceptionPointers = GetExceptionInformation(),
  452. EXCEPTION_EXECUTE_HANDLER) {
  453. //
  454. // we hit an exception calling the callback...return exception code
  455. //
  456. DebugPrint3( LVL_VERBOSE,
  457. L"SIPF hit exception %x while calling callback routine %x at address %x\n",
  458. ExceptionPointers->ExceptionRecord->ExceptionCode,
  459. SfcNotificationCallback,
  460. ExceptionPointers->ExceptionRecord->ExceptionAddress
  461. );
  462. rVal = RtlNtStatusToDosError(ExceptionPointers->ExceptionRecord->ExceptionCode);
  463. goto exit;
  464. }
  465. }
  466. exit:
  467. MemFree(Path.Buffer);
  468. if(cs != NULL)
  469. {
  470. midl_user_free( cs );
  471. }
  472. #ifndef _WIN64
  473. MemFree(szTranslatedFiles);
  474. #endif
  475. SetLastError(rVal);
  476. return rVal == ERROR_SUCCESS;
  477. }
  478. BOOL
  479. WINAPI
  480. SfcGetNextProtectedFile(
  481. IN HANDLE RpcHandle,
  482. IN PPROTECTED_FILE_DATA ProtFileData
  483. )
  484. /*++
  485. Routine Description:
  486. Routine to retrieve the next protected file in the list.
  487. Arguments:
  488. RpcHandle - RPC binding handle to the SFC server
  489. ProtFileData - pointer to a PROTECTED_FILE_DATA structure to be filled
  490. in by function.
  491. Return Value:
  492. TRUE for success, FALSE for failure. If there are no more files, the last
  493. error code will be set to ERROR_NO_MORE_FILES.
  494. --*/
  495. {
  496. DWORD rVal;
  497. LPWSTR FileName = NULL;
  498. DWORD FileNameSize = 0;
  499. BOOL bReturn = FALSE;
  500. DWORD FileNumber;
  501. //
  502. // validate parameters
  503. //
  504. if (ProtFileData == NULL) {
  505. SetLastError(ERROR_INVALID_PARAMETER);
  506. return(FALSE);
  507. }
  508. try {
  509. FileNumber = ProtFileData->FileNumber;
  510. } except (EXCEPTION_EXECUTE_HANDLER) {
  511. SetLastError(ERROR_INVALID_DATA);
  512. return(FALSE);
  513. }
  514. //
  515. // If this is not an internal client, then RpcHandle must be NULL.
  516. //
  517. EnsureGoodConnectionHandleBool( RpcHandle );
  518. //
  519. // call the server API
  520. //
  521. rVal = SfcCli_GetNextProtectedFile(
  522. RpcHandle,
  523. FileNumber,
  524. (LPBYTE*)&FileName,
  525. &FileNameSize
  526. );
  527. if (rVal != ERROR_SUCCESS) {
  528. SetLastError(rVal);
  529. goto exit;
  530. }
  531. bReturn = TRUE;
  532. //
  533. // copy into the caller supplied buffer
  534. //
  535. try {
  536. (void) StringCchCopy(ProtFileData->FileName, UnicodeChars(ProtFileData->FileName), FileName);
  537. ProtFileData->FileNumber += 1;
  538. } except (EXCEPTION_EXECUTE_HANDLER) {
  539. SetLastError(RtlNtStatusToDosError(GetExceptionCode()));
  540. bReturn = FALSE;
  541. }
  542. midl_user_free( FileName );
  543. exit:
  544. return(bReturn);
  545. }
  546. BOOL
  547. WINAPI
  548. SfcIsFileProtected(
  549. IN HANDLE RpcHandle,
  550. IN LPCWSTR ProtFileName
  551. )
  552. /*++
  553. Routine Description:
  554. Routine to determine if the specified file is protected.
  555. Arguments:
  556. RpcHandle - RPC binding handle to the SFC server
  557. ProtFileName - NULL terminated unicode string indicating fully qualified
  558. filename to query
  559. Return Value:
  560. TRUE if file is protected, FALSE if it isn't. last error code contains a
  561. Win32 error code on failure.
  562. --*/
  563. {
  564. DWORD rVal;
  565. DWORD dwAttributes, dwSize;
  566. WCHAR Buffer[MAX_PATH];
  567. //
  568. // parameter validation
  569. //
  570. if (ProtFileName == NULL) {
  571. SetLastError(ERROR_INVALID_PARAMETER);
  572. return FALSE;
  573. }
  574. //
  575. // if this is not an internal client, then RpcHandle must be NULL.
  576. //
  577. EnsureGoodConnectionHandleBool( RpcHandle );
  578. //
  579. // check whether this file is sxs-wfp first, which could be done on client-side only
  580. //
  581. //
  582. // check whether it begins with "%SystemRoot%\\WinSxS\\"
  583. //
  584. dwSize = ExpandEnvironmentStrings( L"%SystemRoot%\\WinSxS\\", Buffer, UnicodeChars(Buffer));
  585. if(0 == dwSize)
  586. {
  587. DebugPrint1( LVL_MINIMAL, L"SFC : ExpandEnvironmentStrings failed with lastError = 0x%x", GetLastError());
  588. return FALSE;
  589. }
  590. if(dwSize > UnicodeChars(Buffer)) {
  591. SetLastError(ERROR_BUFFER_OVERFLOW);
  592. return FALSE;
  593. }
  594. --dwSize;
  595. try {
  596. if ((wcslen(ProtFileName) > dwSize) &&
  597. (_wcsnicmp(Buffer, ProtFileName, dwSize) == 0)) // if they're equal, this could be a protected file
  598. {
  599. dwAttributes = GetFileAttributesW(ProtFileName);
  600. if (dwAttributes == 0xFFFFFFFF)
  601. return FALSE;
  602. if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  603. SetLastError(ERROR_INVALID_PARAMETER);
  604. return FALSE;
  605. }
  606. return TRUE;
  607. }
  608. } except(EXCEPTION_EXECUTE_HANDLER) {
  609. SetLastError(ERROR_INVALID_PARAMETER);
  610. return FALSE;
  611. }
  612. //
  613. // call server to determine if file is protected
  614. //
  615. rVal = SfcCli_IsFileProtected( RpcHandle, (PWSTR)ProtFileName );
  616. if (rVal != ERROR_SUCCESS) {
  617. SetLastError(rVal);
  618. return FALSE;
  619. }
  620. return TRUE;
  621. }