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.

1008 lines
20 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. efs.c
  5. Abstract:
  6. EFS (Encrypting File System) API Interfaces
  7. Author:
  8. Robert Reichel (RobertRe)
  9. Robert Gu (RobertG)
  10. Environment:
  11. Revision History:
  12. --*/
  13. #undef WIN32_LEAN_AND_MEAN
  14. #include "advapi.h"
  15. #include <windows.h>
  16. #include <feclient.h>
  17. #define FE_CLIENT_DLL L"feclient.dll"
  18. //
  19. // Global Variables
  20. //
  21. LPFE_CLIENT_INFO FeClientInfo = NULL;
  22. HMODULE FeClientModule = NULL;
  23. CRITICAL_SECTION FeClientLoadCritical;
  24. LPWSTR
  25. GetFeClientDll(
  26. VOID
  27. )
  28. /*++
  29. Routine Description:
  30. This routine obtains the name of the currently installed client
  31. encryption dll (which is currently hardcoded).
  32. Arguments:
  33. None.
  34. Return Value:
  35. Returns the name of the current DLL, or NULL on error.
  36. --*/
  37. {
  38. return( FE_CLIENT_DLL );
  39. }
  40. BOOL
  41. LoadAndInitFeClient(
  42. VOID
  43. )
  44. /*++
  45. Routine Description:
  46. This routine finds the name of the proper client dll (by some as of
  47. yet unspecified means) and proceeds to load it and initialize it.
  48. Arguments:
  49. None.
  50. Return Value:
  51. TRUE on success, FALSE on failure. Callers may call GetLastError()
  52. for more error information.
  53. --*/
  54. {
  55. LPWSTR FeClientDllName;
  56. LPFEAPI_CLIENT_INITIALIZE ClientInitRoutine;
  57. BOOL Inited;
  58. //
  59. // GetFeClientDll returns a hard coded name.
  60. // If we get this name dynamically later, we will
  61. // need to free FeClientDllName.
  62. //
  63. FeClientDllName = GetFeClientDll();
  64. EnterCriticalSection(&FeClientLoadCritical);
  65. if (FeClientInfo) {
  66. LeaveCriticalSection(&FeClientLoadCritical);
  67. return( TRUE );
  68. }
  69. if (FeClientDllName) {
  70. FeClientModule = LoadLibraryW( FeClientDllName );
  71. if (FeClientModule == NULL) {
  72. DbgPrint("Unable to load client dll, error = %d\n",GetLastError());
  73. LeaveCriticalSection(&FeClientLoadCritical);
  74. return( FALSE );
  75. }
  76. }
  77. ClientInitRoutine = (LPFEAPI_CLIENT_INITIALIZE) GetProcAddress( FeClientModule, (LPCSTR)"FeClientInitialize");
  78. if (NULL == ClientInitRoutine) {
  79. FreeLibrary( FeClientModule );
  80. DbgPrint("Unable to locate init routine, error = %d\n",GetLastError());
  81. LeaveCriticalSection(&FeClientLoadCritical);
  82. return( FALSE );
  83. }
  84. Inited = (*ClientInitRoutine)( FE_REVISION_1_0, &FeClientInfo );
  85. LeaveCriticalSection(&FeClientLoadCritical);
  86. if (!Inited) {
  87. FreeLibrary( FeClientModule );
  88. return( FALSE );
  89. }
  90. return( TRUE );
  91. }
  92. BOOL
  93. WINAPI
  94. EncryptFileA (
  95. LPCSTR lpFileName
  96. )
  97. /*++
  98. Routine Description:
  99. ANSI Stub to EncryptFileW
  100. Arguments:
  101. lpFileName - The name of the file to be encrypted.
  102. Return Value:
  103. TRUE on success, FALSE on failure. Callers may call GetLastError()
  104. for more information.
  105. --*/
  106. {
  107. UNICODE_STRING Unicode;
  108. WCHAR UnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  109. ANSI_STRING AnsiString;
  110. NTSTATUS Status;
  111. Unicode.Length = 0;
  112. Unicode.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof( WCHAR );
  113. Unicode.Buffer = UnicodeBuffer;
  114. RtlInitAnsiString(&AnsiString,lpFileName);
  115. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  116. if ( !NT_SUCCESS(Status) ) {
  117. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  118. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  119. } else {
  120. BaseSetLastNTError(Status);
  121. }
  122. return FALSE;
  123. }
  124. return ( EncryptFileW( Unicode.Buffer ));
  125. }
  126. BOOL
  127. WINAPI
  128. EncryptFileW (
  129. LPCWSTR lpFileName
  130. )
  131. /*++
  132. Routine Description:
  133. Win32 EncryptFile API
  134. Arguments:
  135. lpFileName - Supplies the name of the file to be encrypted.
  136. Return Value:
  137. TRUE on success, FALSE on failure. Callers may call GetLastError()
  138. for more information.
  139. --*/
  140. {
  141. BOOL rc;
  142. DWORD Result;
  143. //
  144. // See if the module has been loaded, and if not, load it into this
  145. // process.
  146. //
  147. if (FeClientInfo == NULL) {
  148. rc = LoadAndInitFeClient();
  149. if (!rc) {
  150. return(rc);
  151. }
  152. }
  153. Result = FeClientInfo->lpServices->EncryptFile( lpFileName );
  154. if (ERROR_SUCCESS != Result) {
  155. SetLastError( Result );
  156. return( FALSE );
  157. }
  158. return( TRUE );
  159. }
  160. BOOL
  161. WINAPI
  162. DecryptFileA (
  163. IN LPCSTR lpFileName,
  164. IN DWORD dwRecovery
  165. )
  166. /*++
  167. Routine Description:
  168. ANSI Stub for the DecryptFileW API
  169. Arguments:
  170. lpFileName - Supplies the name of the file to be decrypted.
  171. dwRecover - Supplies whether this is a recovery operation or a
  172. normal decryption operation.
  173. Return Value:
  174. TRUE on success, FALSE on failure. Callers may call GetLastError()
  175. for more information.
  176. --*/
  177. {
  178. UNICODE_STRING Unicode;
  179. WCHAR UnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  180. ANSI_STRING AnsiString;
  181. NTSTATUS Status;
  182. Unicode.Length = 0;
  183. Unicode.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof( WCHAR );
  184. Unicode.Buffer = UnicodeBuffer;
  185. RtlInitAnsiString(&AnsiString,lpFileName);
  186. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  187. if ( !NT_SUCCESS(Status) ) {
  188. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  189. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  190. } else {
  191. BaseSetLastNTError(Status);
  192. }
  193. return FALSE;
  194. }
  195. return ( DecryptFileW( Unicode.Buffer, dwRecovery ));
  196. }
  197. BOOL
  198. WINAPI
  199. DecryptFileW (
  200. IN LPCWSTR lpFileName,
  201. IN DWORD dwRecovery
  202. )
  203. /*++
  204. Routine Description:
  205. Win32 DecryptFile API
  206. Arguments:
  207. lpFileName - Supplies the name of the file to be encrypted.
  208. Return Value:
  209. TRUE on success, FALSE on failure. Callers may call GetLastError()
  210. for more information.
  211. --*/
  212. {
  213. BOOL rc;
  214. DWORD Result;
  215. //
  216. // See if the module has been loaded, and if not, load it into this
  217. // process.
  218. //
  219. if (FeClientInfo == NULL) {
  220. rc = LoadAndInitFeClient();
  221. if (!rc) {
  222. return(rc);
  223. }
  224. }
  225. Result = FeClientInfo->lpServices->DecryptFile( lpFileName, dwRecovery );
  226. if (ERROR_SUCCESS != Result) {
  227. SetLastError( Result );
  228. return( FALSE );
  229. }
  230. return( TRUE );
  231. }
  232. BOOL
  233. WINAPI
  234. FileEncryptionStatusA (
  235. LPCSTR lpFileName,
  236. LPDWORD lpStatus
  237. )
  238. /*++
  239. Routine Description:
  240. ANSI Stub to FileEncryptionStatusW
  241. Arguments:
  242. lpFileName - The name of the file to be checked.
  243. lpStatus - The status of the file.
  244. Return Value:
  245. TRUE on success, FALSE on failure. Callers may call GetLastError() for more information.
  246. --*/
  247. {
  248. ANSI_STRING AnsiString;
  249. NTSTATUS Status;
  250. UNICODE_STRING Unicode;
  251. WCHAR UnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  252. Unicode.Length = 0;
  253. Unicode.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof( WCHAR );
  254. Unicode.Buffer = UnicodeBuffer;
  255. RtlInitAnsiString(&AnsiString,lpFileName);
  256. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  257. if ( !NT_SUCCESS(Status) ) {
  258. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  259. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  260. } else {
  261. BaseSetLastNTError(Status);
  262. }
  263. return FALSE;
  264. }
  265. return ( FileEncryptionStatusW( Unicode.Buffer, lpStatus ));
  266. }
  267. BOOL
  268. WINAPI
  269. FileEncryptionStatusW (
  270. LPCWSTR lpFileName,
  271. LPDWORD lpStatus
  272. )
  273. /*++
  274. Routine Description:
  275. Win32 FileEncryptionStatus API
  276. Arguments:
  277. lpFileName - Supplies the name of the file to be encrypted.
  278. lpStatus - The status of the file.
  279. Return Value:
  280. TRUE on success, FALSE on failure. Callers may call GetLastError()
  281. for more information.
  282. --*/
  283. {
  284. BOOL rc;
  285. DWORD Result;
  286. //
  287. // See if the module has been loaded, and if not, load it into this
  288. // process.
  289. //
  290. if (FeClientInfo == NULL) {
  291. rc = LoadAndInitFeClient();
  292. if (!rc) {
  293. return(rc);
  294. }
  295. }
  296. return (FeClientInfo->lpServices->FileEncryptionStatus( lpFileName, lpStatus ));
  297. }
  298. DWORD
  299. WINAPI
  300. OpenEncryptedFileRawA(
  301. LPCSTR lpFileName,
  302. ULONG Flags,
  303. PVOID * Context
  304. )
  305. {
  306. ANSI_STRING AnsiString;
  307. NTSTATUS Status;
  308. UNICODE_STRING Unicode;
  309. WCHAR UnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  310. Unicode.Length = 0;
  311. Unicode.MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof( WCHAR );
  312. Unicode.Buffer = UnicodeBuffer;
  313. RtlInitAnsiString(&AnsiString,lpFileName);
  314. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  315. if ( !NT_SUCCESS(Status) ) {
  316. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  317. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  318. } else {
  319. BaseSetLastNTError(Status);
  320. }
  321. return FALSE;
  322. }
  323. return ( OpenEncryptedFileRawW( Unicode.Buffer, Flags, Context ));
  324. }
  325. DWORD
  326. WINAPI
  327. OpenEncryptedFileRawW(
  328. LPCWSTR lpFileName,
  329. ULONG Flags,
  330. PVOID * Context
  331. )
  332. {
  333. BOOL rc;
  334. DWORD Result;
  335. //
  336. // See if the module has been loaded, and if not, load it into this
  337. // process.
  338. //
  339. if (FeClientInfo == NULL) {
  340. rc = LoadAndInitFeClient();
  341. if (!rc) {
  342. return(GetLastError());
  343. }
  344. }
  345. return (FeClientInfo->lpServices->OpenFileRaw( lpFileName, Flags, Context ));
  346. }
  347. DWORD
  348. WINAPI
  349. ReadEncryptedFileRaw(
  350. PFE_EXPORT_FUNC ExportCallback,
  351. PVOID CallbackContext,
  352. PVOID Context
  353. )
  354. {
  355. //
  356. // It doesn't make sense to call this before calling OpenRaw, so don't
  357. // bother checking to see if the module is loaded or not. We'll fault
  358. // in the user process if it isn't.
  359. //
  360. return (FeClientInfo->lpServices->ReadFileRaw( ExportCallback, CallbackContext, Context ));
  361. }
  362. DWORD
  363. WINAPI
  364. WriteEncryptedFileRaw(
  365. PFE_IMPORT_FUNC ImportCallback,
  366. PVOID CallbackContext,
  367. PVOID Context
  368. )
  369. {
  370. //
  371. // It doesn't make sense to call this before calling OpenRaw, so don't
  372. // bother checking to see if the module is loaded or not. We'll fault
  373. // in the user process if it isn't.
  374. //
  375. return (FeClientInfo->lpServices->WriteFileRaw( ImportCallback, CallbackContext, Context ));
  376. }
  377. VOID
  378. WINAPI
  379. CloseEncryptedFileRaw(
  380. PVOID Context
  381. )
  382. {
  383. FeClientInfo->lpServices->CloseFileRaw( Context );
  384. return;
  385. }
  386. DWORD
  387. QueryUsersOnEncryptedFile(
  388. IN LPCWSTR lpFileName,
  389. OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pUsers
  390. )
  391. /*++
  392. Routine Description:
  393. Win32 interface for adding users to an encrypted file.
  394. Arguments:
  395. lpFileName - Supplies the name of the file to be modified.
  396. pUsers - Returns a list of users on the file. This parameter
  397. must be passed to FreeEncryptionCertificateHashList() when
  398. no longer needed.
  399. Return Value:
  400. Win32 error.
  401. --*/
  402. {
  403. DWORD rc;
  404. //
  405. // See if the module has been loaded, and if not, load it into this
  406. // process.
  407. //
  408. if (FeClientInfo == NULL) {
  409. rc = LoadAndInitFeClient();
  410. if (!rc) {
  411. return(rc);
  412. }
  413. }
  414. if ((lpFileName != NULL) && (pUsers != NULL)) {
  415. return(FeClientInfo->lpServices->QueryUsers( lpFileName, pUsers ));
  416. } else {
  417. return( ERROR_INVALID_PARAMETER );
  418. }
  419. }
  420. VOID
  421. FreeEncryptionCertificateHashList(
  422. IN PENCRYPTION_CERTIFICATE_HASH_LIST pUsers
  423. )
  424. /*++
  425. Routine Description:
  426. Frees a certificate hash list as returned by QueryUsersOnEncryptedFile()
  427. and QueryRecoveryAgentsOnEncryptedFile().
  428. Arguments:
  429. Supplies a list of users returned from QueryUsersOnEncryptedFile().
  430. Return Value:
  431. Win32 error.
  432. --*/
  433. {
  434. //
  435. // It is probably safe to assume that feclient.dll is loaded,
  436. // since we wouldn't have one of these structures to free
  437. // if it weren't.
  438. //
  439. if (pUsers != NULL) {
  440. FeClientInfo->lpServices->FreeCertificateHashList( pUsers );
  441. } else {
  442. //
  443. // nothing to do
  444. //
  445. }
  446. return;
  447. }
  448. DWORD
  449. QueryRecoveryAgentsOnEncryptedFile(
  450. IN LPCWSTR lpFileName,
  451. OUT PENCRYPTION_CERTIFICATE_HASH_LIST * pRecoveryAgents
  452. )
  453. /*++
  454. Routine Description:
  455. This routine returns a list of recovery agents on an encrypted
  456. file.
  457. Arguments:
  458. lpFileName - Supplies the name of the file to be examined.
  459. pRecoveryAgents - Returns a list of recovery agents, represented
  460. by certificate hashes on the file. This list should be freed
  461. by calling FreeEncryptionCertificateHashList().
  462. Return Value:
  463. return-value - Description of conditions needed to return value. - or -
  464. None.
  465. --*/
  466. {
  467. DWORD rc;
  468. //
  469. // See if the module has been loaded, and if not, load it into this
  470. // process.
  471. //
  472. if (FeClientInfo == NULL) {
  473. rc = LoadAndInitFeClient();
  474. if (!rc) {
  475. return(rc);
  476. }
  477. }
  478. if ((lpFileName != NULL) && (pRecoveryAgents != NULL)) {
  479. return(FeClientInfo->lpServices->QueryRecoveryAgents( lpFileName, pRecoveryAgents ));
  480. } else {
  481. return( ERROR_INVALID_PARAMETER );
  482. }
  483. }
  484. DWORD
  485. RemoveUsersFromEncryptedFile(
  486. IN LPCWSTR lpFileName,
  487. IN PENCRYPTION_CERTIFICATE_HASH_LIST pHashes
  488. )
  489. /*++
  490. Routine Description:
  491. Takes a list of certificate hashes to be removed
  492. from the passed file. Any that are found are removed,
  493. the rest are ignored with no error return.
  494. Arguments:
  495. lpFileName - Supplies the name of the file to be modified.
  496. pHashes - Supplies the list of hashes to be removed.
  497. Return Value:
  498. Win32 Error
  499. --*/
  500. {
  501. DWORD rc;
  502. //
  503. // See if the module has been loaded, and if not, load it into this
  504. // process.
  505. //
  506. if (FeClientInfo == NULL) {
  507. rc = LoadAndInitFeClient();
  508. if (!rc) {
  509. return(rc);
  510. }
  511. }
  512. if ((lpFileName != NULL) && (pHashes != NULL)) {
  513. return(FeClientInfo->lpServices->RemoveUsers( lpFileName, pHashes ));
  514. } else {
  515. return( ERROR_INVALID_PARAMETER );
  516. }
  517. }
  518. DWORD
  519. AddUsersToEncryptedFile(
  520. IN LPCWSTR lpFileName,
  521. IN PENCRYPTION_CERTIFICATE_LIST pEncryptionCertificates
  522. )
  523. /*++
  524. Routine Description:
  525. This routine adds user keys to the passed encrypted file.
  526. Arguments:
  527. lpFileName - Supplies the name of the file to be encrypted.
  528. pEncryptionCertificates - Supplies the list of certificates for
  529. new users to be added to the file.
  530. Return Value:
  531. Win32 Error
  532. --*/
  533. {
  534. DWORD rc;
  535. //
  536. // See if the module has been loaded, and if not, load it into this
  537. // process.
  538. //
  539. if (FeClientInfo == NULL) {
  540. rc = LoadAndInitFeClient();
  541. if (!rc) {
  542. return(rc);
  543. }
  544. }
  545. if ((lpFileName != NULL) && (pEncryptionCertificates != NULL)) {
  546. return(FeClientInfo->lpServices->AddUsers( lpFileName, pEncryptionCertificates ));
  547. } else {
  548. return( ERROR_INVALID_PARAMETER );
  549. }
  550. }
  551. DWORD
  552. SetUserFileEncryptionKey(
  553. PENCRYPTION_CERTIFICATE pEncryptionCertificate
  554. )
  555. /*++
  556. Routine Description:
  557. This routine will set the user's current EFS key to the one
  558. contained in the passed certificate. If no certificate is
  559. passed, a new key will be generated automatically.
  560. Arguments:
  561. pEncryptionCertificate - Optionally supplies the certificate
  562. containing the new public key.
  563. Return Value:
  564. Win32 error
  565. --*/
  566. {
  567. DWORD rc;
  568. //
  569. // See if the module has been loaded, and if not, load it into this
  570. // process.
  571. //
  572. if (FeClientInfo == NULL) {
  573. rc = LoadAndInitFeClient();
  574. if (!rc) {
  575. return(rc);
  576. }
  577. }
  578. return(FeClientInfo->lpServices->SetKey( pEncryptionCertificate ));
  579. /*
  580. if (pEncryptionCertificate != NULL) {
  581. return(FeClientInfo->lpServices->SetKey( pEncryptionCertificate ));
  582. } else {
  583. return( ERROR_INVALID_PARAMETER );
  584. }*/
  585. }
  586. DWORD
  587. DuplicateEncryptionInfoFile(
  588. IN LPCWSTR SrcFileName,
  589. IN LPCWSTR DstFileName,
  590. IN DWORD dwCreationDistribution,
  591. IN DWORD dwAttributes,
  592. IN CONST LPSECURITY_ATTRIBUTES lpSecurityAttributes
  593. )
  594. /*++
  595. Routine Description:
  596. This routine duplicates the encryption information from the source file to the
  597. destination file. Destination file will be created if not existing.
  598. The destination file is overwritten.
  599. Arguments:
  600. SrcFileName - Supplies the source of the encryption information.
  601. DstFileName - Supplies the target file, exclusive open is required on this file.
  602. dwCreationDistribution - Create options.
  603. If dwCreationDistribution != CREATE_NEW, dwCreationDistribution = CREATE_ALWAYS
  604. dwAttributes - File attributes.
  605. lpSecurityAttributes - Security attributes.
  606. Return Value:
  607. Win32 error on failure.
  608. --*/
  609. {
  610. DWORD rc;
  611. if (FeClientModule == NULL) {
  612. rc = LoadAndInitFeClient();
  613. if (!rc) {
  614. return(rc);
  615. }
  616. }
  617. if (SrcFileName && DstFileName) {
  618. return(FeClientInfo->lpServices->DuplicateEncryptionInfo( SrcFileName,
  619. DstFileName,
  620. dwCreationDistribution,
  621. dwAttributes,
  622. lpSecurityAttributes
  623. ));
  624. } else {
  625. return( ERROR_INVALID_PARAMETER );
  626. }
  627. }
  628. BOOL
  629. WINAPI
  630. EncryptionDisable(
  631. IN LPCWSTR DirPath,
  632. IN BOOL Disable
  633. )
  634. /*++
  635. Routine Description:
  636. This routine disable and enable EFS in the directory DirPath.
  637. Arguments:
  638. DirPath - Directory path.
  639. Disable - TRUE to disable
  640. Return Value:
  641. TRUE for SUCCESS
  642. --*/
  643. {
  644. DWORD rc;
  645. //
  646. // See if the module has been loaded, and if not, load it into this
  647. // process.
  648. //
  649. if (FeClientInfo == NULL) {
  650. rc = LoadAndInitFeClient();
  651. if (!rc) {
  652. return(rc);
  653. }
  654. }
  655. return(FeClientInfo->lpServices->DisableDir( DirPath, Disable ));
  656. }
  657. WINADVAPI
  658. DWORD
  659. WINAPI
  660. EncryptedFileKeyInfo(
  661. IN LPCWSTR lpFileName,
  662. IN DWORD InfoClass,
  663. OUT PEFS_RPC_BLOB * KeyInfo
  664. )
  665. /*++
  666. Routine Description:
  667. Win32 interface for adding users to an encrypted file.
  668. Arguments:
  669. lpFileName - Supplies the name of the file to be modified.
  670. InfoClass - Information requested. Only support 1 for now.
  671. KeyInfo - Returns Key info
  672. Return Value:
  673. Win32 error.
  674. --*/
  675. {
  676. DWORD rc;
  677. //
  678. // See if the module has been loaded, and if not, load it into this
  679. // process.
  680. //
  681. if (FeClientInfo == NULL) {
  682. rc = LoadAndInitFeClient();
  683. if (!rc) {
  684. return(rc);
  685. }
  686. }
  687. if ((lpFileName != NULL) && (KeyInfo != NULL)) {
  688. return(FeClientInfo->lpServices->GetKeyInfo( lpFileName, InfoClass, KeyInfo ));
  689. } else {
  690. return( ERROR_INVALID_PARAMETER );
  691. }
  692. }
  693. WINADVAPI
  694. VOID
  695. WINAPI
  696. FreeEncryptedFileKeyInfo(
  697. IN PEFS_RPC_BLOB pKeyInfo
  698. )
  699. /*++
  700. Routine Description:
  701. Frees a KeyInfo as returned by EncryptedFileKeyInfo();
  702. Arguments:
  703. pKeyInfo - Supplies a KeyInfo returned from EncryptedFileKeyInfo().
  704. Return Value:
  705. No.
  706. --*/
  707. {
  708. //
  709. // It is probably safe to assume that feclient.dll is loaded,
  710. // since we wouldn't have one of these structures to free
  711. // if it weren't.
  712. //
  713. if (pKeyInfo != NULL) {
  714. FeClientInfo->lpServices->FreeKeyInfo( pKeyInfo );
  715. } else {
  716. //
  717. // nothing to do
  718. //
  719. }
  720. return;
  721. }