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.

1629 lines
43 KiB

  1. /*++
  2. Copyright (c) 1996, 1997 Microsoft Corporation
  3. Module Name:
  4. keybckup.cpp
  5. Abstract:
  6. This module contains routines associated with client side Key Backup
  7. operations.
  8. Author:
  9. Scott Field (sfield) 16-Sep-97
  10. --*/
  11. #include <pch.cpp>
  12. #pragma hdrstop
  13. extern "C" {
  14. #include <dsgetdc.h>
  15. #include <msaudite.h>
  16. }
  17. #define DPAPI_SERVICE_NAME L"ProtectedStorage"
  18. typedef struct _WZR_RPC_BINDING_LIST
  19. {
  20. LPCWSTR pszProtSeq;
  21. LPCWSTR pszEndpoint;
  22. } WZR_RPC_BINDING_LIST;
  23. WZR_RPC_BINDING_LIST g_awzrBackupBindingList[] =
  24. {
  25. { DPAPI_LOCAL_PROT_SEQ, DPAPI_LOCAL_ENDPOINT },
  26. { DPAPI_BACKUP_PROT_SEQ, DPAPI_BACKUP_ENDPOINT},
  27. { DPAPI_LEGACY_BACKUP_PROT_SEQ, DPAPI_LEGACY_BACKUP_ENDPOINT}
  28. };
  29. DWORD g_cwzrBackupBindingList = sizeof(g_awzrBackupBindingList)/sizeof(g_awzrBackupBindingList[0]);
  30. DWORD
  31. WINAPI
  32. CPSGetDomainControllerName(
  33. IN OUT LPWSTR wszDomainControllerName,
  34. IN OUT DWORD *pcchDomainControllerName,
  35. IN BOOL fRediscover
  36. );
  37. BOOL
  38. GetDomainControllerNameByToken(
  39. IN HANDLE hToken,
  40. IN OUT LPWSTR wszDomainControllerName,
  41. IN OUT PDWORD pcchDomainControllerName,
  42. IN BOOL fRediscover
  43. );
  44. static const GUID guidRetrieve = BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID;
  45. static const GUID guidRestore = BACKUPKEY_RESTORE_GUID;
  46. static const GUID guidRestoreW2K = BACKUPKEY_RESTORE_GUID_W2K;
  47. static const GUID guidBackup = BACKUPKEY_BACKUP_GUID;
  48. DWORD
  49. BackupRestoreData(
  50. IN HANDLE hToken,
  51. IN PMASTERKEY_STORED phMasterKey,
  52. IN PBYTE pbDataIn,
  53. IN DWORD cbDataIn,
  54. OUT PBYTE *ppbDataOut,
  55. OUT DWORD *pcbDataOut,
  56. IN BOOL fBackup
  57. )
  58. {
  59. return LocalBackupRestoreData(hToken,
  60. phMasterKey,
  61. pbDataIn,
  62. cbDataIn,
  63. ppbDataOut,
  64. pcbDataOut,
  65. fBackup?&guidBackup:&guidRestore);
  66. }
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: LocalBackupRestoreData
  70. //
  71. // Synopsis: Connect to the user's DC and perform a master key backup or
  72. // recovery operation.
  73. //
  74. // Arguments: [hToken] -- Handle to user token. This is used when
  75. // generating audits.
  76. //
  77. // [phMasterKey] -- Master key that we're operating on.
  78. //
  79. // [pbDataIn] -- Input buffer. Only used for recovery
  80. // [cbDataIn] -- operations.
  81. //
  82. // [ppbDataOut] -- Output buffer.
  83. // [pcbDataOut] --
  84. //
  85. // [pguidAction] -- GUID describing operation to perform.
  86. //
  87. // Returns: ERROR_SUCCESS if the operation was successful, a Windows
  88. // error code otherwise.
  89. //
  90. // History:
  91. //
  92. // Notes: The caller of this function MUST be impersonating a client
  93. // user.
  94. //
  95. //----------------------------------------------------------------------------
  96. DWORD
  97. LocalBackupRestoreData(
  98. IN HANDLE hToken,
  99. IN PMASTERKEY_STORED phMasterKey,
  100. IN PBYTE pbDataIn,
  101. IN DWORD cbDataIn,
  102. OUT PBYTE *ppbDataOut,
  103. OUT DWORD *pcbDataOut,
  104. IN const GUID *pguidAction
  105. )
  106. {
  107. WCHAR FastBuffer[ 256 ];
  108. LPWSTR SlowBuffer = NULL;
  109. LPWSTR pszAuditComputerName = NULL;
  110. LPWSTR pszComputerName;
  111. DWORD cchComputerName;
  112. static DWORD dwLastFailTickCount; // time for failure on last access
  113. static LUID luidLastFailAuthId; // LUID associated with failed network
  114. DWORD dwCandidateTickCount;
  115. LUID luidCandidateAuthId; // LUID associated with client security context.
  116. BOOL fRediscoverDC = FALSE;
  117. DWORD dwLastError = ERROR_NETWORK_BUSY;
  118. D_DebugLog((DEB_TRACE_API, "LocalBackupRestoreData\n"));
  119. //
  120. // impersonate the user, so we may
  121. // 1. check the authentication ID to see if we've failed to hit the
  122. // net as this user.
  123. // 2. determine a domain controller computer name associated with
  124. // the user.
  125. // 3. backup or restore the requested material on behalf of the user.
  126. //
  127. if(!GetThreadAuthenticationId( GetCurrentThread(), &luidCandidateAuthId ))
  128. return ERROR_NO_TOKEN;
  129. //
  130. // now, see if the network was previously unavailable (recently)
  131. // for this user.
  132. //
  133. dwCandidateTickCount = GetTickCount();
  134. if(memcmp(&luidCandidateAuthId, &luidLastFailAuthId, sizeof(LUID)) == 0) {
  135. if( (dwLastFailTickCount + (5*1000*60)) > dwCandidateTickCount ) {
  136. //BUGBUG: return ERROR_NETWORK_BUSY;
  137. }
  138. }
  139. //
  140. // we got far enough along that we update the failed network cache
  141. // if something goes wrong from here.
  142. //
  143. network_call:
  144. //
  145. // get domain controller computer name associated with current
  146. // security context.
  147. // Try with fast static buffer first, fallback on dynamically allocated
  148. // buffer if not large enough.
  149. //
  150. pszComputerName = FastBuffer;
  151. cchComputerName = sizeof(FastBuffer) / sizeof( WCHAR );
  152. dwLastError = CPSGetDomainControllerName(
  153. pszComputerName,
  154. &cchComputerName,
  155. fRediscoverDC
  156. );
  157. if( dwLastError != ERROR_SUCCESS && (cchComputerName > (sizeof(FastBuffer) / sizeof(WCHAR) ))) {
  158. SlowBuffer = (LPWSTR) SSAlloc( cchComputerName * sizeof(WCHAR) );
  159. if( SlowBuffer ) {
  160. pszComputerName = SlowBuffer;
  161. dwLastError = CPSGetDomainControllerName(
  162. pszComputerName,
  163. &cchComputerName,
  164. fRediscoverDC
  165. );
  166. }
  167. }
  168. if( dwLastError == ERROR_SUCCESS ) {
  169. LPWSTR pszTargetMachine = pszComputerName;
  170. pszAuditComputerName = pszComputerName;
  171. // HACKHACK workaround picky RPC/Kerberos name format behavior that
  172. // would otherwise prevent Kerberos from being used.
  173. if( pszTargetMachine[ 0 ] == L'\\' && pszTargetMachine[ 1 ] == L'\\' )
  174. pszTargetMachine += 2;
  175. dwLastError = BackupKey(
  176. pszTargetMachine, // target computer.
  177. pguidAction,
  178. pbDataIn,
  179. cbDataIn,
  180. ppbDataOut,
  181. pcbDataOut,
  182. 0
  183. );
  184. }
  185. //
  186. // Audit success or failure
  187. //
  188. if((memcmp(pguidAction, &guidRestore, sizeof(GUID)) == 0) ||
  189. (memcmp(pguidAction, &guidRestoreW2K, sizeof(GUID)) == 0))
  190. {
  191. // Grab the recovery key id
  192. WCHAR wszBackupkeyGuid[MAX_GUID_SZ_CHARS];
  193. PBACKUPKEY_RECOVERY_BLOB pBackupBlob = (PBACKUPKEY_RECOVERY_BLOB)phMasterKey->pbBBK;
  194. wszBackupkeyGuid[0] = 0;
  195. if((pBackupBlob) && (phMasterKey->cbBBK > sizeof(BACKUPKEY_RECOVERY_BLOB)))
  196. {
  197. MyGuidToStringW(&pBackupBlob->guidKey, wszBackupkeyGuid);
  198. }
  199. CPSAudit(hToken,
  200. SE_AUDITID_DPAPI_RECOVERY,
  201. phMasterKey->wszguidMasterKey, // Key Identifier
  202. pszAuditComputerName, // Recovery Server
  203. 0, // Recovery Reason
  204. wszBackupkeyGuid, // Recovery Key ID
  205. dwLastError); // Failure Reason
  206. }
  207. else if(memcmp(pguidAction, &guidBackup, sizeof(GUID)) == 0)
  208. {
  209. // Attempting a remote backup
  210. // Grab the recovery key id
  211. WCHAR wszBackupkeyGuid[MAX_GUID_SZ_CHARS];
  212. PBACKUPKEY_RECOVERY_BLOB pBackupBlob = (PBACKUPKEY_RECOVERY_BLOB)*ppbDataOut;
  213. wszBackupkeyGuid[0] = 0;
  214. if(( dwLastError == ERROR_SUCCESS ) &&
  215. (pBackupBlob) &&
  216. (*pcbDataOut > sizeof(BACKUPKEY_RECOVERY_BLOB)))
  217. {
  218. MyGuidToStringW(&pBackupBlob->guidKey, wszBackupkeyGuid);
  219. }
  220. CPSAudit(hToken,
  221. SE_AUDITID_DPAPI_BACKUP,
  222. phMasterKey->wszguidMasterKey, // Key Identifier
  223. pszAuditComputerName, // Recovery Server
  224. 0,
  225. wszBackupkeyGuid, // Recovery Key ID
  226. dwLastError); // Failure Reason
  227. }
  228. if( SlowBuffer ) {
  229. SSFree( SlowBuffer );
  230. SlowBuffer = NULL;
  231. }
  232. //
  233. // common failure path is ERROR_ACCESS_DENIED for delegation scenarios
  234. // where target machine isn't trusted for delegation.
  235. // don't bother retry for this case.
  236. //
  237. if( dwLastError != ERROR_SUCCESS && dwLastError != ERROR_ACCESS_DENIED ) {
  238. //
  239. // if it failed, try once again and force DC re-discovery.
  240. //
  241. if( !fRediscoverDC ) {
  242. fRediscoverDC = TRUE;
  243. goto network_call;
  244. }
  245. //
  246. // one of the network operations failed, so update the
  247. // last failure variables so that we don't bang the network
  248. // over-and-over.
  249. //
  250. dwLastFailTickCount = dwCandidateTickCount;
  251. CopyMemory( &luidLastFailAuthId, &luidCandidateAuthId, sizeof(LUID));
  252. }
  253. D_DebugLog((DEB_TRACE_API, "LocalBackupRestoreData returned 0x%x\n", dwLastError));
  254. return dwLastError;
  255. }
  256. BOOL
  257. GetDomainControllerNameByToken(
  258. IN HANDLE hToken,
  259. IN OUT LPWSTR wszDomainControllerName,
  260. IN OUT PDWORD pcchDomainControllerName,
  261. IN BOOL fRediscover
  262. )
  263. /*++
  264. This routine obtains a domain controller computer name associated with
  265. the account related to the hToken access token.
  266. hToken should be opened for TOKEN_QUERY access.
  267. wszDomainControllerName should be of size (UNCLEN+1)
  268. --*/
  269. {
  270. PSID pSidUser = NULL; // sid of client user.
  271. WCHAR szUserName[ UNLEN + 1 ];
  272. DWORD cchUserName = sizeof(szUserName) / sizeof(WCHAR);
  273. WCHAR szDomainName[ DNLEN + 1]; // domain we want a controller for.
  274. DWORD cchDomainName = sizeof(szDomainName) / sizeof(WCHAR);
  275. SID_NAME_USE snu;
  276. PDOMAIN_CONTROLLER_INFOW pDomainInfo = NULL;
  277. LPWSTR wszQueryResult = NULL;
  278. NET_API_STATUS nas;
  279. DWORD dwGetDcFlags = 0;
  280. BOOL fSuccess = FALSE;
  281. if(wszDomainControllerName == NULL || pcchDomainControllerName == NULL)
  282. return FALSE;
  283. //
  284. // first, get the sid of the user associated with the specified access
  285. // token.
  286. //
  287. if(!GetTokenUserSid(hToken, &pSidUser))
  288. return FALSE;
  289. //
  290. // next, lookup the domain name associated with the specified account.
  291. //
  292. if(!LookupAccountSidW(
  293. NULL,
  294. pSidUser,
  295. szUserName,
  296. &cchUserName,
  297. szDomainName,
  298. &cchDomainName,
  299. &snu
  300. )) {
  301. SSFree(pSidUser);
  302. return FALSE;
  303. }
  304. if( fRediscover )
  305. dwGetDcFlags |= DS_FORCE_REDISCOVERY;
  306. nas = DsGetDcNameW(
  307. NULL,
  308. szDomainName,
  309. NULL,
  310. NULL,
  311. DS_DIRECTORY_SERVICE_REQUIRED | // make sure backend is NT5
  312. DS_IS_FLAT_NAME |
  313. DS_RETURN_DNS_NAME |
  314. dwGetDcFlags,
  315. &pDomainInfo
  316. );
  317. if( nas == ERROR_SUCCESS )
  318. wszQueryResult = pDomainInfo->DomainControllerName;
  319. //
  320. // if we made a successful query, copy it for the caller and indicate
  321. // success if appropriate.
  322. //
  323. if(wszQueryResult) {
  324. DWORD cchQueryResult = lstrlenW( wszQueryResult ) + 1;
  325. if( *pcchDomainControllerName >= cchQueryResult ) {
  326. CopyMemory(wszDomainControllerName, wszQueryResult, cchQueryResult * sizeof(WCHAR));
  327. fSuccess = TRUE;
  328. }
  329. *pcchDomainControllerName = cchQueryResult;
  330. }
  331. if(pDomainInfo)
  332. NetApiBufferFree(pDomainInfo);
  333. if(pSidUser)
  334. SSFree(pSidUser);
  335. return fSuccess;
  336. }
  337. DWORD
  338. WINAPI
  339. CPSGetDomainControllerName(
  340. IN OUT LPWSTR wszDomainControllerName,
  341. IN OUT DWORD *pcchDomainControllerName,
  342. IN BOOL fRediscover
  343. )
  344. /*++
  345. This routine collects a domain controller computer name associated
  346. with the current impersonated user (if one is being impersonated), or
  347. the user associated with the pvContext outstanding client call if the
  348. thread is not already impersonating a client.
  349. --*/
  350. {
  351. HANDLE hToken = NULL;
  352. DWORD dwLastError;
  353. if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken)) {
  354. return GetLastError();
  355. }
  356. if(!GetDomainControllerNameByToken(
  357. hToken,
  358. wszDomainControllerName,
  359. pcchDomainControllerName,
  360. fRediscover
  361. )) {
  362. dwLastError = ERROR_BAD_NET_RESP;
  363. goto cleanup;
  364. }
  365. dwLastError = ERROR_SUCCESS;
  366. cleanup:
  367. if(hToken)
  368. CloseHandle(hToken);
  369. return dwLastError;
  370. }
  371. #define BACKUP_KEY_PREFIX L"BK-"
  372. #define BACKUP_KEY_PREFIX_LEN 3
  373. #define BACKUP_PUBLIC_VERSION 1
  374. typedef struct _BACKUP_PUBLIC_KEY
  375. {
  376. DWORD dwVersion;
  377. DWORD cbPublic;
  378. DWORD cbSignature;
  379. } BACKUP_PUBLIC_KEY, *PBACKUP_PUBLIC_KEY;
  380. //+---------------------------------------------------------------------------
  381. //
  382. // Function: RetrieveBackupPublicKeyFromStorage
  383. //
  384. // Synopsis: Read in the domain backup public key from user profile.
  385. //
  386. // Arguments: [hToken] -- Handle to user token.
  387. //
  388. // [pSidUser] -- Pointer to user SID.
  389. //
  390. // [pszFilePath] -- Path to DPAPI user storage directory.
  391. // This is typically of the form:
  392. // %userprofile%\Application Data\Microsoft\
  393. // Protect\<user SID>.
  394. //
  395. // [ppbDataOut] -- Output buffer.
  396. // [pcbDataOut]
  397. //
  398. // Returns: ERROR_SUCCESS if the operation was successful, a Windows
  399. // error code otherwise.
  400. //
  401. // History:
  402. //
  403. // Notes: When this function completes successfully, the caller is
  404. // responsible for freeing the output buffer, via a call to
  405. // the SSFree function.
  406. //
  407. //----------------------------------------------------------------------------
  408. DWORD
  409. RetrieveBackupPublicKeyFromStorage(
  410. IN HANDLE hToken,
  411. IN PSID pSidUser,
  412. IN LPWSTR pszFilePath,
  413. OUT PBYTE *ppbDataOut,
  414. OUT DWORD *pcbDataOut)
  415. {
  416. DWORD dwLastError = ERROR_SUCCESS;
  417. WCHAR szUserName[ UNLEN + 1 ];
  418. DWORD cchUserName = sizeof(szUserName) / sizeof(WCHAR);
  419. WCHAR szDomainName[ BACKUP_KEY_PREFIX_LEN + DNLEN +1]; // domain we want a controller for.
  420. DWORD cchDomainName = sizeof(szDomainName) / sizeof(WCHAR);
  421. HANDLE hFile = NULL;
  422. HANDLE hMap = NULL;
  423. PBACKUP_PUBLIC_KEY pBackupPublic = NULL;
  424. DWORD dwFileSizeLow;
  425. SID_NAME_USE snu;
  426. //
  427. // Lookup the domain name associated with the specified account, and use
  428. // it to generate the filename, which will be of the form: BK-<domain>.
  429. //
  430. wcscpy(szDomainName, BACKUP_KEY_PREFIX);
  431. cchDomainName -= BACKUP_KEY_PREFIX_LEN;
  432. if(!LookupAccountSidW(
  433. NULL,
  434. pSidUser,
  435. szUserName,
  436. &cchUserName,
  437. szDomainName + BACKUP_KEY_PREFIX_LEN,
  438. &cchDomainName,
  439. &snu))
  440. {
  441. return GetLastError();
  442. }
  443. cchDomainName += BACKUP_KEY_PREFIX_LEN;
  444. //
  445. // Impersonate the user.
  446. //
  447. if(hToken)
  448. {
  449. if(!SetThreadToken(NULL, hToken))
  450. {
  451. return GetLastError();
  452. }
  453. }
  454. //
  455. // Attempt open the file.
  456. //
  457. dwLastError = OpenFileInStorageArea(
  458. NULL,
  459. GENERIC_READ,
  460. pszFilePath,
  461. szDomainName,
  462. &hFile
  463. );
  464. if(ERROR_SUCCESS != dwLastError)
  465. {
  466. goto error;
  467. }
  468. dwFileSizeLow = GetFileSize( hFile, NULL );
  469. if(dwFileSizeLow == INVALID_FILE_SIZE )
  470. {
  471. dwLastError = ERROR_INVALID_DATA;
  472. goto error;
  473. }
  474. __try
  475. {
  476. hMap = CreateFileMappingU(
  477. hFile,
  478. NULL,
  479. PAGE_READONLY,
  480. 0,
  481. 0,
  482. NULL
  483. );
  484. if(NULL == hMap)
  485. {
  486. dwLastError = GetLastError();
  487. goto error;
  488. }
  489. pBackupPublic = (PBACKUP_PUBLIC_KEY)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 );
  490. if(NULL == pBackupPublic)
  491. {
  492. dwLastError = GetLastError();
  493. goto error;
  494. }
  495. if((pBackupPublic->dwVersion != BACKUP_PUBLIC_VERSION) ||
  496. (dwFileSizeLow < sizeof(BACKUP_PUBLIC_KEY) + pBackupPublic->cbPublic + pBackupPublic->cbSignature))
  497. {
  498. dwLastError = ERROR_INVALID_DATA;
  499. goto error;
  500. }
  501. //
  502. // Verify the signature
  503. //
  504. dwLastError = LogonCredVerifySignature( NULL,
  505. (PBYTE)(pBackupPublic + 1) + pBackupPublic->cbSignature,
  506. pBackupPublic->cbPublic,
  507. NULL,
  508. (PBYTE)(pBackupPublic + 1),
  509. pBackupPublic->cbSignature);
  510. if(ERROR_SUCCESS != dwLastError)
  511. {
  512. goto error;
  513. }
  514. *ppbDataOut = (PBYTE)SSAlloc(pBackupPublic->cbPublic);
  515. if(NULL == ppbDataOut)
  516. {
  517. dwLastError = STATUS_OBJECT_NAME_NOT_FOUND;
  518. goto error;
  519. }
  520. CopyMemory(*ppbDataOut,
  521. (PBYTE)(pBackupPublic + 1) + pBackupPublic->cbSignature,
  522. pBackupPublic->cbPublic);
  523. *pcbDataOut = pBackupPublic->cbPublic;
  524. } __except (EXCEPTION_EXECUTE_HANDLER)
  525. {
  526. dwLastError = GetExceptionCode();
  527. }
  528. error:
  529. if(pBackupPublic)
  530. {
  531. UnmapViewOfFile(pBackupPublic);
  532. }
  533. if(hMap)
  534. {
  535. CloseHandle(hMap);
  536. }
  537. if(hFile)
  538. {
  539. CloseHandle(hFile);
  540. }
  541. if(hToken)
  542. {
  543. RevertToSelf();
  544. }
  545. return dwLastError;
  546. }
  547. DWORD
  548. WriteBackupPublicKeyToStorage(
  549. IN HANDLE hToken,
  550. IN PSID pSidUser,
  551. IN LPWSTR wszFilePath,
  552. IN PBYTE pbData,
  553. IN DWORD cbData)
  554. {
  555. DWORD dwLastError = ERROR_SUCCESS;
  556. WCHAR szUserName[ UNLEN + 1 ];
  557. DWORD cchUserName = sizeof(szUserName) / sizeof(WCHAR);
  558. WCHAR szDomainName[ BACKUP_KEY_PREFIX_LEN + DNLEN +1]; // domain we want a controller for.
  559. DWORD cchDomainName = sizeof(szDomainName) / sizeof(WCHAR);
  560. HANDLE hFile = NULL;
  561. HANDLE hMap = NULL;
  562. PBACKUP_PUBLIC_KEY pBackupPublic = NULL;
  563. DWORD dwFileSizeLow;
  564. SID_NAME_USE snu;
  565. PBYTE pbSignature = NULL;
  566. DWORD cbSignature;
  567. //
  568. // Lookup the domain name associated with the specified account, and use
  569. // it to generate the filename, which will be of the form: BK-<domain>.
  570. //
  571. wcscpy(szDomainName, BACKUP_KEY_PREFIX);
  572. cchDomainName -= BACKUP_KEY_PREFIX_LEN;
  573. if(!LookupAccountSidW(
  574. NULL,
  575. pSidUser,
  576. szUserName,
  577. &cchUserName,
  578. szDomainName + BACKUP_KEY_PREFIX_LEN,
  579. &cchDomainName,
  580. &snu))
  581. {
  582. return GetLastError();
  583. }
  584. cchDomainName += BACKUP_KEY_PREFIX_LEN;
  585. //
  586. // Impersonate the user.
  587. //
  588. if(hToken)
  589. {
  590. if(!SetThreadToken(NULL, hToken))
  591. {
  592. return GetLastError();
  593. }
  594. }
  595. //
  596. // Sign the public key, so that it can't be
  597. // spoofed.
  598. //
  599. dwLastError = LogonCredGenerateSignature(
  600. hToken,
  601. pbData,
  602. cbData,
  603. NULL,
  604. &pbSignature,
  605. &cbSignature);
  606. if(ERROR_SUCCESS != dwLastError)
  607. {
  608. goto error;
  609. }
  610. //
  611. // Write the public key data and signature out to disk.
  612. //
  613. dwFileSizeLow = sizeof(BACKUP_PUBLIC_KEY) + cbData + cbSignature;
  614. dwLastError = OpenFileInStorageArea(
  615. NULL,
  616. GENERIC_READ | GENERIC_WRITE,
  617. wszFilePath,
  618. szDomainName,
  619. &hFile
  620. );
  621. if(ERROR_SUCCESS != dwLastError)
  622. {
  623. goto error;
  624. }
  625. __try
  626. {
  627. hMap = CreateFileMappingU(
  628. hFile,
  629. NULL,
  630. PAGE_READWRITE,
  631. 0,
  632. dwFileSizeLow,
  633. NULL
  634. );
  635. if(NULL == hMap)
  636. {
  637. dwLastError = GetLastError();
  638. goto error;
  639. }
  640. pBackupPublic = (PBACKUP_PUBLIC_KEY)MapViewOfFile( hMap, FILE_MAP_WRITE , 0, 0, dwFileSizeLow );
  641. if(NULL == pBackupPublic)
  642. {
  643. dwLastError = GetLastError();
  644. goto error;
  645. }
  646. pBackupPublic->dwVersion = BACKUP_PUBLIC_VERSION;
  647. pBackupPublic->cbSignature = cbSignature;
  648. pBackupPublic->cbPublic = cbData;
  649. CopyMemory((PBYTE)(pBackupPublic+1), pbSignature, cbSignature);
  650. CopyMemory((PBYTE)(pBackupPublic+1) + cbSignature, pbData, cbData);
  651. } __except (EXCEPTION_EXECUTE_HANDLER)
  652. {
  653. dwLastError = GetExceptionCode();
  654. }
  655. error:
  656. if(pBackupPublic)
  657. {
  658. UnmapViewOfFile(pBackupPublic);
  659. }
  660. if(hMap)
  661. {
  662. CloseHandle(hMap);
  663. }
  664. if(hFile)
  665. {
  666. CloseHandle(hFile);
  667. }
  668. if(pbSignature)
  669. {
  670. SSFree(pbSignature);
  671. }
  672. if(hToken)
  673. {
  674. RevertToSelf();
  675. }
  676. return dwLastError;
  677. }
  678. //+---------------------------------------------------------------------------
  679. //
  680. // Function: AttemptLocalBackup
  681. //
  682. // Synopsis: Backup the specified master key using a domain public key.
  683. // Only connect to the DC if the fRetrieve parameter is set
  684. // to TRUE.
  685. //
  686. // Arguments: [fRetrieve] -- Whether to retrieve the domain public key
  687. // from the DC before performing the backup.
  688. //
  689. // [hToken] -- Handle to user token.
  690. //
  691. // [phMasterKey] -- Pointer to master key structure. This is
  692. // used when obtaining the path to the user
  693. // data directory and also for auditing.
  694. //
  695. // [pbMasterKey] -- Plaintext master key to backup.
  696. // [cbMasterKey]
  697. //
  698. // [pbLocalKey] -- Plaintext local key to backup. BUGBUG - It's
  699. // [cbLocalKey] still a bit of a mystery as to what this
  700. // field is used for, given that this is a
  701. // domain user account.
  702. //
  703. // [ppbBBK] -- Output buffer.
  704. // [pcbBBK]
  705. //
  706. // Returns: ERROR_SUCCESS if the operation was successful, a Windows
  707. // error code otherwise.
  708. //
  709. // History:
  710. //
  711. // Notes: When this function completes successfully, the caller is
  712. // responsible for freeing the output buffer, via a call to
  713. // the SSFree function.
  714. //
  715. //----------------------------------------------------------------------------
  716. DWORD
  717. AttemptLocalBackup(
  718. IN BOOL fRetrieve,
  719. IN HANDLE hToken,
  720. IN PMASTERKEY_STORED phMasterKey,
  721. IN PBYTE pbMasterKey,
  722. IN DWORD cbMasterKey,
  723. IN PBYTE pbLocalKey,
  724. IN DWORD cbLocalKey,
  725. OUT PBYTE * ppbBBK,
  726. OUT DWORD * pcbBBK)
  727. {
  728. DWORD dwLastError = ERROR_SUCCESS;
  729. PCCERT_CONTEXT pPublic = NULL;
  730. PBYTE pbPublic = NULL;
  731. DWORD cbPublic = 0;
  732. HCRYPTPROV hProv = NULL;
  733. HCRYPTKEY hPublicKey = NULL;
  734. PBYTE pbPayloadKey = NULL;;
  735. PBACKUPKEY_KEY_BLOB pKeyBlob = NULL;
  736. DWORD cbKeyBlobData = 0;
  737. DWORD cbKeyBlob = 0;
  738. PBACKUPKEY_INNER_BLOB pInnerBlob = NULL;
  739. DWORD cbInnerBlob = 0;
  740. DWORD cbInnerBlobData = 0;
  741. PBYTE pbData = NULL;
  742. DWORD cbTemp = 0;
  743. PBACKUPKEY_RECOVERY_BLOB pOuterBlob = NULL;
  744. DWORD cbOuterBlob = 0;
  745. PSID pSidUser = NULL; // sid of client user.
  746. DWORD cbSid = 0;
  747. WCHAR wszBackupKeyID[MAX_GUID_SZ_CHARS];
  748. BYTE rgbThumbprint[A_SHA_DIGEST_LEN];
  749. DWORD cbThumbprint;
  750. wszBackupKeyID[0] = 0;
  751. if(!GetTokenUserSid(hToken, &pSidUser))
  752. {
  753. dwLastError = GetLastError();
  754. goto error;
  755. }
  756. if(fRetrieve)
  757. {
  758. // Attempt to retrieve the public from
  759. // the DC.
  760. //
  761. // We impersonate when we do this
  762. //
  763. if (!SetThreadToken(NULL, hToken))
  764. {
  765. dwLastError = GetLastError();
  766. goto error;
  767. }
  768. dwLastError = LocalBackupRestoreData(hToken,
  769. phMasterKey,
  770. pbMasterKey,
  771. 0,
  772. &pbPublic,
  773. &cbPublic,
  774. &guidRetrieve);
  775. //
  776. // Revert back to ourself
  777. //
  778. if (!SetThreadToken(NULL, NULL))
  779. {
  780. if (ERROR_SUCCESS == dwLastError)
  781. {
  782. dwLastError = GetLastError();
  783. goto error;
  784. }
  785. }
  786. }
  787. else
  788. {
  789. //
  790. // We're attempting a backup, so first see if we have a local copy of
  791. // the public.
  792. //
  793. dwLastError = RetrieveBackupPublicKeyFromStorage(hToken,
  794. pSidUser,
  795. phMasterKey->szFilePath,
  796. &pbPublic,
  797. &cbPublic);
  798. }
  799. if(ERROR_SUCCESS == dwLastError)
  800. {
  801. pPublic = CertCreateCertificateContext(X509_ASN_ENCODING,
  802. pbPublic,
  803. cbPublic);
  804. if(NULL == pPublic)
  805. {
  806. dwLastError = GetLastError();
  807. }
  808. }
  809. if(dwLastError != ERROR_SUCCESS)
  810. {
  811. goto error;
  812. }
  813. if(sizeof(GUID) == pPublic->pCertInfo->SerialNumber.cbData)
  814. {
  815. MyGuidToStringW((GUID *)pPublic->pCertInfo->SerialNumber.pbData, wszBackupKeyID);
  816. }
  817. if(fRetrieve)
  818. {
  819. // Writing the public key to disk is not critical,
  820. // so we don't need to check for an error return.
  821. WriteBackupPublicKeyToStorage(hToken,
  822. pSidUser,
  823. phMasterKey->szFilePath,
  824. pbPublic,
  825. cbPublic);
  826. }
  827. if(!CryptAcquireContext(&hProv,
  828. NULL,
  829. NULL,
  830. PROV_RSA_FULL,
  831. CRYPT_VERIFYCONTEXT))
  832. {
  833. dwLastError = GetLastError();
  834. goto error;
  835. }
  836. if(!CryptImportPublicKeyInfoEx(hProv,
  837. pPublic->dwCertEncodingType,
  838. &pPublic->pCertInfo->SubjectPublicKeyInfo,
  839. CALG_RSA_KEYX,
  840. NULL,
  841. NULL,
  842. &hPublicKey))
  843. {
  844. dwLastError = GetLastError();
  845. goto error;
  846. }
  847. cbSid = GetLengthSid(pSidUser);
  848. cbInnerBlobData = sizeof(BACKUPKEY_INNER_BLOB) +
  849. cbLocalKey +
  850. cbSid +
  851. A_SHA_DIGEST_LEN;
  852. //
  853. // Round up to blocklen
  854. //
  855. cbInnerBlob = (cbInnerBlobData + (DES_BLOCKLEN - 1)) & ~(DES_BLOCKLEN-1);
  856. cbTemp = sizeof(cbKeyBlob);
  857. if(!CryptGetKeyParam(hPublicKey,
  858. KP_BLOCKLEN,
  859. (PBYTE)&cbKeyBlob,
  860. &cbTemp,
  861. 0))
  862. {
  863. dwLastError = GetLastError();
  864. goto error;
  865. }
  866. cbKeyBlob >>= 3; // convert from bits to bytes
  867. cbOuterBlob = sizeof(BACKUPKEY_RECOVERY_BLOB) +
  868. cbKeyBlob +
  869. cbInnerBlob;
  870. pOuterBlob = (PBACKUPKEY_RECOVERY_BLOB)SSAlloc(cbOuterBlob);
  871. if(NULL == pOuterBlob)
  872. {
  873. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  874. goto error;
  875. }
  876. pKeyBlob = (PBACKUPKEY_KEY_BLOB)(pOuterBlob+1);
  877. pInnerBlob = (PBACKUPKEY_INNER_BLOB)((PBYTE)pKeyBlob + cbKeyBlob);
  878. // Initialize the payload key
  879. cbKeyBlobData = sizeof(BACKUPKEY_KEY_BLOB) + cbMasterKey + DES3_KEYSIZE + DES_BLOCKLEN;
  880. pKeyBlob->cbMasterKey = cbMasterKey;
  881. pKeyBlob->cbPayloadKey = DES3_KEYSIZE + DES_BLOCKLEN;
  882. pbPayloadKey = (PBYTE)(pKeyBlob+1) + cbMasterKey;
  883. CopyMemory((PBYTE)(pKeyBlob+1), pbMasterKey, cbMasterKey);
  884. //
  885. // Generate a payload key
  886. //
  887. if(!RtlGenRandom(pbPayloadKey, pKeyBlob->cbPayloadKey))
  888. {
  889. dwLastError = GetLastError();
  890. goto error;
  891. }
  892. // Populate the payload
  893. pInnerBlob->dwPayloadVersion = BACKUPKEY_PAYLOAD_VERSION;
  894. pInnerBlob->cbLocalKey = cbLocalKey;
  895. pbData = (PBYTE)(pInnerBlob+1);
  896. CopyMemory(pbData, pbLocalKey, cbLocalKey);
  897. pbData += cbLocalKey;
  898. CopyMemory(pbData, pSidUser, cbSid);
  899. pbData += cbSid;
  900. // Pad
  901. if(cbInnerBlob > cbInnerBlobData)
  902. {
  903. if(!RtlGenRandom(pbData, cbInnerBlob - cbInnerBlobData))
  904. {
  905. dwLastError = GetLastError();
  906. goto error;
  907. }
  908. pbData += cbInnerBlob - cbInnerBlobData;
  909. }
  910. // Generate the payload MAC
  911. FMyPrimitiveSHA( (PBYTE)pInnerBlob,
  912. cbInnerBlob - A_SHA_DIGEST_LEN,
  913. pbData);
  914. //
  915. // Encrypt with 3DES CBC
  916. //
  917. {
  918. DES3TABLE s3DESKey;
  919. BYTE InputBlock[DES_BLOCKLEN];
  920. DWORD iBlock;
  921. DWORD cBlocks = cbInnerBlob/DES_BLOCKLEN;
  922. BYTE feedback[ DES_BLOCKLEN ];
  923. // initialize 3des key
  924. //
  925. if(cBlocks*DES_BLOCKLEN != cbInnerBlob)
  926. {
  927. // Master key must be a multiple of DES_BLOCKLEN
  928. dwLastError = NTE_BAD_KEY;
  929. goto error;
  930. }
  931. tripledes3key(&s3DESKey, pbPayloadKey);
  932. //
  933. // IV is derived from the DES_BLOCKLEN bytes of the calculated
  934. // rgbSymKey, after the 3des key
  935. CopyMemory(feedback, pbPayloadKey + DES3_KEYSIZE, DES_BLOCKLEN);
  936. for(iBlock=0; iBlock < cBlocks; iBlock++)
  937. {
  938. CopyMemory(InputBlock,
  939. ((PBYTE)pInnerBlob)+iBlock*DES_BLOCKLEN,
  940. DES_BLOCKLEN);
  941. CBC(tripledes,
  942. DES_BLOCKLEN,
  943. ((PBYTE)pInnerBlob)+iBlock*DES_BLOCKLEN,
  944. InputBlock,
  945. &s3DESKey,
  946. ENCRYPT,
  947. feedback);
  948. }
  949. }
  950. //
  951. // Encrypt master key and payload key to
  952. // the public key
  953. if(!CryptEncrypt(hPublicKey,
  954. NULL,
  955. TRUE,
  956. 0, // CRYPT_OAEP
  957. (PBYTE)pKeyBlob,
  958. &cbKeyBlobData,
  959. cbKeyBlob))
  960. {
  961. dwLastError = GetLastError();
  962. goto error;
  963. }
  964. if(cbKeyBlobData != cbKeyBlob)
  965. {
  966. CopyMemory((PBYTE)pKeyBlob + cbKeyBlobData,
  967. pInnerBlob,
  968. cbInnerBlob);
  969. cbOuterBlob -= cbKeyBlob - cbKeyBlobData;
  970. }
  971. pOuterBlob->dwVersion = BACKUPKEY_RECOVERY_BLOB_VERSION;
  972. pOuterBlob->cbEncryptedMasterKey = cbKeyBlobData;
  973. pOuterBlob->cbEncryptedPayload = cbInnerBlob;
  974. CopyMemory(&pOuterBlob->guidKey,
  975. pPublic->pCertInfo->SubjectUniqueId.pbData,
  976. sizeof(GUID));
  977. *ppbBBK = (PBYTE)pOuterBlob;
  978. *pcbBBK = cbOuterBlob;
  979. pOuterBlob = NULL;
  980. error:
  981. if((fRetrieve) || (ERROR_SUCCESS == dwLastError))
  982. {
  983. // Only audit if we're attempting to do the long backup.
  984. //SetThreadToken(NULL, hToken);
  985. CPSAudit(hToken,
  986. SE_AUDITID_DPAPI_BACKUP,
  987. phMasterKey->wszguidMasterKey, // Key Identifier
  988. L"", // Recovery Server
  989. 0,
  990. wszBackupKeyID, // Recovery Key ID
  991. dwLastError); // Failure Reason
  992. //SetThreadToken(NULL, NULL);
  993. }
  994. if(pPublic)
  995. {
  996. CertFreeCertificateContext(pPublic);
  997. }
  998. if(pbPublic)
  999. {
  1000. SSFree(pbPublic);
  1001. }
  1002. if(pOuterBlob)
  1003. {
  1004. SSFree(pOuterBlob);
  1005. }
  1006. if (pSidUser)
  1007. {
  1008. SSFree(pSidUser);
  1009. }
  1010. if(hPublicKey)
  1011. {
  1012. CryptDestroyKey(hPublicKey);
  1013. }
  1014. if(hProv)
  1015. {
  1016. CryptReleaseContext(hProv, 0);
  1017. }
  1018. return dwLastError;
  1019. }
  1020. BOOLEAN
  1021. CompareNameToDnsName(
  1022. LPCWSTR pszName,
  1023. LPCWSTR pszDnsName)
  1024. {
  1025. WCHAR szLocalName[MAX_COMPUTERNAME_LENGTH + 1];
  1026. UNICODE_STRING LocalName;
  1027. UNICODE_STRING Name;
  1028. PWSTR pszPeriod;
  1029. if(pszName == NULL && pszDnsName == NULL)
  1030. {
  1031. return TRUE;
  1032. }
  1033. if(pszName == NULL || pszDnsName == NULL)
  1034. {
  1035. return FALSE;
  1036. }
  1037. // Extract netbios name from dns name
  1038. wcsncpy(szLocalName, pszDnsName, MAX_COMPUTERNAME_LENGTH);
  1039. szLocalName[MAX_COMPUTERNAME_LENGTH] = L'\0';
  1040. if(pszPeriod = wcschr(szLocalName, L'.'))
  1041. {
  1042. *pszPeriod = L'\0';
  1043. }
  1044. // Compare strings.
  1045. RtlInitUnicodeString(&Name, pszName);
  1046. RtlInitUnicodeString(&LocalName, szLocalName);
  1047. return RtlEqualDomainName(&Name, &LocalName);
  1048. }
  1049. DWORD
  1050. WINAPI
  1051. BackupKey(
  1052. IN LPCWSTR pszComputerName,
  1053. IN const GUID *pguidActionAgent,
  1054. IN BYTE *pDataIn,
  1055. IN DWORD cbDataIn,
  1056. IN OUT BYTE **ppDataOut,
  1057. IN OUT DWORD *pcbDataOut,
  1058. IN DWORD dwParam
  1059. )
  1060. {
  1061. RPC_BINDING_HANDLE h = NULL;
  1062. WCHAR *pStringBinding = NULL;
  1063. BOOL fLocal = FALSE;
  1064. HANDLE hToken = NULL;
  1065. RPC_STATUS RpcStatus = RPC_S_OK;
  1066. DWORD dwRetVal = ERROR_INVALID_PARAMETER;
  1067. DWORD i;
  1068. WCHAR szLocalComputerName[MAX_COMPUTERNAME_LENGTH + 2];
  1069. DWORD BufSize = MAX_COMPUTERNAME_LENGTH + 2;
  1070. LPWSTR pszSPN = NULL;
  1071. #if DBG
  1072. D_DebugLog((DEB_TRACE, "BackupKey called\n"));
  1073. D_DebugLog((DEB_TRACE, " DC Name:%ls\n", pszComputerName));
  1074. if(memcmp(pguidActionAgent, &guidRetrieve, sizeof(GUID)) == 0)
  1075. {
  1076. D_DebugLog((DEB_TRACE, " Retrieve domain public key\n"));
  1077. }
  1078. else if(memcmp(pguidActionAgent, &guidRestore, sizeof(GUID)) == 0)
  1079. {
  1080. D_DebugLog((DEB_TRACE, " Restore master key\n"));
  1081. }
  1082. else if(memcmp(pguidActionAgent, &guidRestoreW2K, sizeof(GUID)) == 0)
  1083. {
  1084. D_DebugLog((DEB_TRACE, " Restore master key (Win2K)\n"));
  1085. }
  1086. else if(memcmp(pguidActionAgent, &guidBackup, sizeof(GUID)) == 0)
  1087. {
  1088. D_DebugLog((DEB_TRACE, " Backup master key (Win2K)\n"));
  1089. }
  1090. else
  1091. {
  1092. D_DebugLog((DEB_TRACE, " Unknown operation\n"));
  1093. }
  1094. #endif
  1095. *ppDataOut = NULL;
  1096. *pcbDataOut = 0;
  1097. //
  1098. // Is the user logged on locally--or alternatively, is this the
  1099. // user's recovery DC?
  1100. //
  1101. if (!(GetComputerNameW(szLocalComputerName, &BufSize)))
  1102. {
  1103. dwRetVal = GetLastError();
  1104. D_DebugLog((DEB_TRACE, "BackupKey returned 0x%x\n", dwRetVal));
  1105. return dwRetVal;
  1106. }
  1107. if(IsLocal())
  1108. {
  1109. // User is logged on locally.
  1110. fLocal = TRUE;
  1111. }
  1112. else
  1113. {
  1114. D_DebugLog((DEB_TRACE, "User is not logged on locally\n"));
  1115. if((pszComputerName == NULL) || CompareNameToDnsName(szLocalComputerName, pszComputerName))
  1116. {
  1117. D_DebugLog((DEB_TRACE, "This is the user's recovery DC\n"));
  1118. fLocal = TRUE;
  1119. }
  1120. }
  1121. //
  1122. // Build the SPN
  1123. //
  1124. pszSPN = (LPWSTR)LocalAlloc(LPTR, ( wcslen(pszComputerName) +
  1125. 1 +
  1126. wcslen(DPAPI_SERVICE_NAME) +
  1127. 1 ) * sizeof(WCHAR) );
  1128. if(pszSPN == NULL)
  1129. {
  1130. dwRetVal = ERROR_NOT_ENOUGH_MEMORY;
  1131. D_DebugLog((DEB_TRACE, "BackupKey returned 0x%x\n", dwRetVal));
  1132. return dwRetVal;
  1133. }
  1134. wcscpy(pszSPN, DPAPI_SERVICE_NAME);
  1135. wcscat(pszSPN, L"/");
  1136. wcscat(pszSPN, pszComputerName);
  1137. //
  1138. // Try all of the bindings
  1139. //
  1140. for (i = fLocal?0:1; i < g_cwzrBackupBindingList; i++)
  1141. {
  1142. RPC_SECURITY_QOS RpcQos;
  1143. if (RPC_S_OK != RpcNetworkIsProtseqValidW(
  1144. (unsigned short *)g_awzrBackupBindingList[i].pszProtSeq))
  1145. {
  1146. continue;
  1147. }
  1148. RpcStatus = RpcStringBindingComposeW(
  1149. NULL,
  1150. (unsigned short *)g_awzrBackupBindingList[i].pszProtSeq,
  1151. (unsigned short *)pszComputerName,
  1152. (unsigned short *)g_awzrBackupBindingList[i].pszEndpoint,
  1153. NULL,
  1154. &pStringBinding);
  1155. if (RPC_S_OK != RpcStatus)
  1156. {
  1157. continue;
  1158. }
  1159. RpcStatus = RpcBindingFromStringBindingW(
  1160. pStringBinding,
  1161. &h);
  1162. if (NULL != pStringBinding)
  1163. {
  1164. RpcStringFreeW(&pStringBinding);
  1165. }
  1166. if (RPC_S_OK != RpcStatus)
  1167. {
  1168. continue;
  1169. }
  1170. RpcStatus = RpcEpResolveBinding(
  1171. h,
  1172. BackupKey_v1_0_c_ifspec);
  1173. if (RPC_S_OK != RpcStatus)
  1174. {
  1175. continue;
  1176. }
  1177. //
  1178. // enable privacy and negotiated re-authentication.
  1179. // a fresh authentication is required in the event an existing connection
  1180. // to the target machine already existed which was made with non-default
  1181. // credentials.
  1182. //
  1183. ZeroMemory( &RpcQos, sizeof(RpcQos) );
  1184. RpcQos.Version = RPC_C_SECURITY_QOS_VERSION;
  1185. RpcQos.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH;
  1186. RpcQos.IdentityTracking = RPC_C_QOS_IDENTITY_DYNAMIC;
  1187. RpcQos.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE;
  1188. RpcStatus = RpcBindingSetAuthInfoExW(
  1189. h,
  1190. pszSPN,
  1191. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  1192. RPC_C_AUTHN_GSS_NEGOTIATE,
  1193. 0,
  1194. 0,
  1195. &RpcQos
  1196. );
  1197. if (RPC_S_OK != RpcStatus)
  1198. {
  1199. continue;
  1200. }
  1201. __try
  1202. {
  1203. dwRetVal = BackuprKey(
  1204. h,
  1205. (GUID*)pguidActionAgent,
  1206. pDataIn,
  1207. cbDataIn,
  1208. ppDataOut,
  1209. pcbDataOut,
  1210. dwParam
  1211. );
  1212. }
  1213. __except ( EXCEPTION_EXECUTE_HANDLER )
  1214. {
  1215. RpcStatus = _exception_code();
  1216. }
  1217. if (RPC_S_OK == RpcStatus)
  1218. {
  1219. break;
  1220. }
  1221. }
  1222. if((RPC_S_OK != RpcStatus) && (fLocal == FALSE))
  1223. {
  1224. //
  1225. // If we're going off machine, check to see if delegation is
  1226. // allowed. If it isn't, then this is probably the reason for the
  1227. // the failure, so return SEC_E_DELEGATION_REQUIRED.
  1228. //
  1229. LPUSER_INFO_1 pUserInfo = NULL;
  1230. wcscat(szLocalComputerName, L"$");
  1231. if((OpenThreadToken(GetCurrentThread(),
  1232. TOKEN_IMPERSONATE,
  1233. TRUE,
  1234. &hToken)) &&
  1235. SetThreadToken(NULL, NULL))
  1236. {
  1237. if (NERR_Success == NetUserGetInfo(
  1238. pszComputerName,
  1239. szLocalComputerName,
  1240. 1,
  1241. (PBYTE *)&pUserInfo
  1242. )) {
  1243. if (!(UF_TRUSTED_FOR_DELEGATION & pUserInfo->usri1_flags))
  1244. {
  1245. D_DebugLog((DEB_TRACE, "Server is not trusted for delegation\n"));
  1246. RpcStatus = SEC_E_DELEGATION_REQUIRED;
  1247. }
  1248. NetApiBufferFree(pUserInfo);
  1249. }
  1250. //
  1251. // Impersonate again
  1252. // We are going to fail. No need to check the return value of SetThreadToken.
  1253. //
  1254. (void) SetThreadToken(NULL, hToken);
  1255. }
  1256. }
  1257. if(hToken)
  1258. {
  1259. CloseHandle(hToken);
  1260. }
  1261. if(RPC_S_OK != RpcStatus)
  1262. {
  1263. dwRetVal = RpcStatus;
  1264. }
  1265. if(h)
  1266. {
  1267. RpcBindingFree(&h);
  1268. }
  1269. if(pszSPN)
  1270. {
  1271. LocalFree(pszSPN);
  1272. }
  1273. D_DebugLog((DEB_TRACE, "BackupKey returned 0x%x\n", dwRetVal));
  1274. return dwRetVal;
  1275. }