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.

1096 lines
28 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: debug.cxx
  7. //
  8. // Contents: Debug definitions that shouldn't be necessary
  9. // in the retail build.
  10. //
  11. // History: 19-Nov-92 WadeR Created
  12. //
  13. // Notes: If you change or add a debug level, also fix debug.hxx
  14. // This is only compiled if DBG > 0
  15. //
  16. //--------------------------------------------------------------------------
  17. #include "kdcsvr.hxx"
  18. #include <kdcdbg.h>
  19. #include "debug.hxx"
  20. #include <tostring.hxx>
  21. //
  22. // The "#pragma hdrstop" causes the preprocessor to forget any "#if"s
  23. // is is processing. Therefore you can't have it inside an "#if" block.
  24. // So the includes will always compile, and the rest of this code becomes
  25. // conditional.
  26. //
  27. #include <stddef.h>
  28. #ifdef RETAIL_LOG_SUPPORT
  29. //
  30. // Variables for heap checking and used by sectrace.hxx:
  31. //
  32. // Set following to HEAP_CHECK_ON_ENTER | HEAP_CHECK_ON_EXIT for heap checking.
  33. DWORD dwHeapChecking = 0;
  34. // This keeps a registry key handle to the HKLM\System\CCSet\Control\LSA\
  35. // Kerberoskey
  36. HKEY hKeyParams = NULL;
  37. HANDLE hWait = NULL;
  38. // Set following to address of a function which takes 0 arguments and returns
  39. // a void for arbitrary run time checking.
  40. VOID (*debugFuncAddr)() = NULL;
  41. //
  42. // Tons and tons of global data to get debugging params from the ini file.
  43. //
  44. // Note: For every trace bit, there must be a label in this array matching
  45. // that trace bit and only that trace bit. There can be other labels
  46. // matching combinations of trace bits.
  47. //
  48. DEBUG_KEY KdcDebugKeys[] = { {DEB_ERROR, "Error"},
  49. {DEB_WARN, "Warning"},
  50. {DEB_TRACE, "Trace"},
  51. {DEB_T_KDC, "Kdc"},
  52. {DEB_T_TICKETS, "Tickets"},
  53. {DEB_T_DOMAIN, "Domain"},
  54. {DEB_T_SOCK, "Sock"},
  55. {DEB_T_TRANSIT, "Transit"},
  56. {DEB_T_PERF_STATS, "Perf"},
  57. {DEB_T_PKI, "PKI"},
  58. {0, NULL},
  59. };
  60. DEFINE_DEBUG2(KDC);
  61. extern DWORD KSuppInfoLevel; // needed to adjust values for common2 dir
  62. ////////////////////////////////////////////////////////////////////
  63. //
  64. // Name: KerbGetKDCRegParams
  65. //
  66. // Synopsis: Gets the debug paramaters from the registry
  67. //
  68. // Arguments: HKEY to HKLM/System/CCS/LSA/Kerberos
  69. //
  70. // Notes: Sets KDCInfolevel for debug spew
  71. //
  72. void
  73. KerbGetKDCRegParams(HKEY ParamKey)
  74. {
  75. DWORD cbType, tmpInfoLevel = KDCInfoLevel, cbSize = sizeof(DWORD);
  76. DWORD dwErr;
  77. dwErr = RegQueryValueExW(
  78. ParamKey,
  79. WSZ_DEBUGLEVEL,
  80. NULL,
  81. &cbType,
  82. (LPBYTE)&tmpInfoLevel,
  83. &cbSize
  84. );
  85. if (dwErr != ERROR_SUCCESS)
  86. {
  87. if (dwErr == ERROR_FILE_NOT_FOUND)
  88. {
  89. // no registry value is present, don't want info
  90. // so reset to defaults
  91. // NOTE: Since SCLogon sux so badly, we're going to log all PKI events for now.
  92. // FESTER: Pull for server B3.
  93. #if DBG
  94. KSuppInfoLevel = KDCInfoLevel = DEB_ERROR | DEB_T_PKI;
  95. #else // fre
  96. KSuppInfoLevel = KDCInfoLevel = DEB_T_PKI;
  97. #endif
  98. }else{
  99. DebugLog((DEB_WARN, "Failed to query DebugLevel: 0x%x\n", dwErr));
  100. }
  101. }
  102. // TBD: Validate flags?
  103. KSuppInfoLevel = KDCInfoLevel = tmpInfoLevel;
  104. return;
  105. }
  106. //
  107. // Tempo?
  108. //
  109. /*void FillExtError(PKERB_EXT_ERROR p,NTSTATUS s,ULONG f,ULONG l)
  110. {
  111. if (EXT_ERROR_ON(KDCInfoLevel)) \
  112. {
  113. p->status = s;
  114. p->klininfo = KLIN(f,l);
  115. }
  116. sprintf(xx, "XX File-%i, Line-%i", f,l);
  117. OutputDebugStringA(xx);
  118. } */
  119. ////////////////////////////////////////////////////////////////////
  120. //
  121. // Name: KerbWatchParamKey
  122. //
  123. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  124. // debug level, then utilizes thread pool to wait on
  125. // changes to this registry key. Enables dynamic debug
  126. // level changes, as this function will also be callback
  127. // if registry key modified.
  128. //
  129. // Arguments: pCtxt is actually a HANDLE to an event. This event
  130. // will be triggered when key is modified.
  131. //
  132. // Notes: .
  133. //
  134. VOID
  135. KerbWatchParamKey(PVOID pCtxt,
  136. BOOLEAN fWaitStatus)
  137. {
  138. NTSTATUS Status;
  139. LONG lRes = ERROR_SUCCESS;
  140. if (NULL == hKeyParams) // first time we've been called.
  141. {
  142. lRes = RegOpenKeyExW(
  143. HKEY_LOCAL_MACHINE,
  144. KERB_PARAMETER_PATH,
  145. 0,
  146. KEY_READ,
  147. &hKeyParams);
  148. if (ERROR_SUCCESS != lRes)
  149. {
  150. DebugLog((DEB_WARN,"Failed to open kerberos key: 0x%x\n", lRes));
  151. goto Reregister;
  152. }
  153. }
  154. if (NULL != hWait)
  155. {
  156. Status = RtlDeregisterWait(hWait);
  157. if (!NT_SUCCESS(Status))
  158. {
  159. DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  160. goto Reregister;
  161. }
  162. }
  163. lRes = RegNotifyChangeKeyValue(
  164. hKeyParams,
  165. FALSE,
  166. REG_NOTIFY_CHANGE_LAST_SET,
  167. (HANDLE) pCtxt,
  168. TRUE);
  169. if (ERROR_SUCCESS != lRes)
  170. {
  171. DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  172. // we're tanked now. No further notifications, so get this one
  173. }
  174. KerbGetKDCRegParams(hKeyParams);
  175. Reregister:
  176. Status = RtlRegisterWait(&hWait,
  177. (HANDLE) pCtxt,
  178. KerbWatchParamKey,
  179. (HANDLE) pCtxt,
  180. INFINITE,
  181. WT_EXECUTEONLYONCE);
  182. }
  183. ////////////////////////////////////////////////////////////////////
  184. //
  185. // Name: WaitCleanup
  186. //
  187. // Synopsis: Cleans up for KerbWatchParamKey
  188. //
  189. // Arguments: <none>
  190. //
  191. // Notes: .
  192. //
  193. VOID
  194. WaitCleanup(HANDLE hEvent)
  195. {
  196. NTSTATUS Status = STATUS_SUCCESS;
  197. if (NULL != hWait) {
  198. Status = RtlDeregisterWait(hWait);
  199. hWait = NULL;
  200. }
  201. if (NT_SUCCESS(Status) && NULL != hEvent) {
  202. CloseHandle(hEvent);
  203. hEvent = NULL;
  204. }
  205. }
  206. ////////////////////////////////////////////////////////////////////
  207. //
  208. // Name: GetDebugParams
  209. //
  210. // Synopsis: Gets the debug paramaters from the ini file.
  211. //
  212. // Arguments: <none>
  213. //
  214. // Notes: .
  215. //
  216. void
  217. GetDebugParams() {
  218. CHAR chBuf[128];
  219. DWORD cbBuf;
  220. KDCInitDebug(KdcDebugKeys);
  221. }
  222. #if DBG // moved here to utilize debug logging in free builds.
  223. NTSTATUS
  224. KDC_GetState( handle_t hBinding,
  225. DWORD * KDCFlags,
  226. DWORD * MaxLifespan,
  227. DWORD * MaxRenewSpan,
  228. PTimeStamp FudgeFactor)
  229. {
  230. *FudgeFactor = SkewTime;
  231. TimeStamp tsLife, tsRenew;
  232. NTSTATUS hr = SecData.DebugGetState(KDCFlags, &tsLife, &tsRenew );
  233. tsLife.QuadPart = (tsLife.QuadPart / ulTsPerSecond);
  234. *MaxLifespan =tsLife.LowPart;
  235. tsRenew.QuadPart = (tsRenew.QuadPart / ulTsPerSecond);
  236. *MaxRenewSpan = tsRenew.LowPart;
  237. return(hr);
  238. }
  239. NTSTATUS
  240. KDC_SetState( handle_t hBinding,
  241. DWORD KdcFlags,
  242. DWORD MaxLifespan,
  243. DWORD MaxRenewSpan,
  244. TimeStamp FudgeFactor)
  245. {
  246. NTSTATUS hr;
  247. TimeStamp tsLife = {0,0};
  248. TimeStamp tsRenew = {0,0};
  249. UNICODE_STRING ss;
  250. if (FudgeFactor.QuadPart != 0)
  251. {
  252. SkewTime = FudgeFactor;
  253. Authenticators->SetMaxAge( SkewTime );
  254. }
  255. tsLife.QuadPart = (LONGLONG) MaxLifespan * 10000000;
  256. tsRenew.QuadPart = (LONGLONG) MaxRenewSpan * 10000000;
  257. if (KdcFlags == 0)
  258. {
  259. KdcFlags = SecData.KdcFlags();
  260. }
  261. if (MaxLifespan == 0)
  262. {
  263. tsLife = SecData.KdcTgtTicketLifespan();
  264. }
  265. if (MaxRenewSpan == 0)
  266. {
  267. tsLife = SecData.KdcTicketRenewSpan();
  268. }
  269. hr = SecData.DebugSetState(KdcFlags, tsLife, tsRenew);
  270. SecData.DebugShowState();
  271. return(hr);
  272. }
  273. void PrintIntervalTime (
  274. ULONG DebugFlag,
  275. LPSTR Message,
  276. PLARGE_INTEGER Interval )
  277. {
  278. LONGLONG llTime = Interval->QuadPart;
  279. LONG lSeconds = (LONG) ( llTime / 10000000 );
  280. LONG lMinutes = ( lSeconds / 60 ) % 60;
  281. LONG lHours = ( lSeconds / 3600 );
  282. DebugLog(( DebugFlag, "%s %d:%2.2d:%2.2d \n", Message, lHours, lMinutes, lSeconds % 60 ));
  283. }
  284. void PrintTime (
  285. ULONG DebugFlag,
  286. LPSTR Message,
  287. PLARGE_INTEGER Time )
  288. {
  289. SYSTEMTIME st;
  290. FileTimeToSystemTime ( (PFILETIME) Time, & st );
  291. DebugLog((DebugFlag, "%s %d-%d-%d %d:%2.2d:%2.2d\n", Message, st.wMonth, st.wDay, st.wYear,
  292. st.wHour, st.wMinute, st.wSecond ));
  293. }
  294. #else // DBG
  295. NTSTATUS
  296. KDC_GetState( handle_t hBinding,
  297. DWORD * KDCFlags,
  298. DWORD * MaxLifespan,
  299. DWORD * MaxRenewSpan,
  300. PTimeStamp FudgeFactor)
  301. {
  302. return(STATUS_NOT_SUPPORTED);
  303. }
  304. NTSTATUS
  305. KDC_SetState( handle_t hBinding,
  306. DWORD KDCFlags,
  307. DWORD MaxLifespan,
  308. DWORD MaxRenewSpan,
  309. TimeStamp FudgeFactor)
  310. {
  311. return(STATUS_NOT_SUPPORTED);
  312. }
  313. #endif
  314. #endif
  315. BOOLEAN
  316. KdcSetPassSupported(
  317. VOID
  318. )
  319. {
  320. NET_API_STATUS NetStatus;
  321. ULONG SetPassUnsupported = 0;
  322. LPNET_CONFIG_HANDLE ConfigHandle = NULL;
  323. NetStatus = NetpOpenConfigData(
  324. &ConfigHandle,
  325. NULL, // noserer name
  326. L"kdc",
  327. TRUE // read only
  328. );
  329. if (NetStatus != NO_ERROR)
  330. {
  331. return(TRUE);
  332. }
  333. NetStatus = NetpGetConfigDword(
  334. ConfigHandle,
  335. L"SetPassUnsupported",
  336. 0,
  337. &SetPassUnsupported
  338. );
  339. NetpCloseConfigData( ConfigHandle );
  340. if ((NetStatus == NO_ERROR) && (SetPassUnsupported == 1))
  341. {
  342. return(FALSE);
  343. }
  344. else
  345. {
  346. return(TRUE);
  347. }
  348. }
  349. //+-------------------------------------------------------------------------
  350. //
  351. // Function: KDC_SetPassword
  352. //
  353. // Synopsis: Sets password for an account
  354. //
  355. // Effects:
  356. //
  357. // Arguments:
  358. //
  359. // Requires:
  360. //
  361. // Returns:
  362. //
  363. // Notes:
  364. //
  365. //
  366. //--------------------------------------------------------------------------
  367. NTSTATUS
  368. KDC_SetPassword(
  369. IN handle_t hBinding,
  370. IN PUNICODE_STRING UserName,
  371. IN PUNICODE_STRING PrincipalName,
  372. IN PUNICODE_STRING Password,
  373. IN ULONG Flags
  374. )
  375. {
  376. NTSTATUS Status = STATUS_SUCCESS;
  377. KERBERR KerbErr;
  378. SECPKG_SUPPLEMENTAL_CRED Credentials;
  379. KDC_TICKET_INFO TicketInfo;
  380. SAMPR_HANDLE UserHandle = NULL;
  381. UNICODE_STRING NewUserName;
  382. KERB_EXT_ERROR ExtendedError; // dummy var.
  383. Credentials.Credentials = NULL;
  384. if (!KdcSetPassSupported())
  385. {
  386. Status = STATUS_NOT_SUPPORTED;
  387. goto Cleanup;
  388. }
  389. //
  390. // Make sure we can impersonate the caller.
  391. //
  392. if (RpcImpersonateClient(NULL) != ERROR_SUCCESS)
  393. {
  394. Status = STATUS_ACCESS_DENIED;
  395. goto Cleanup;
  396. }
  397. else
  398. {
  399. RpcRevertToSelf();
  400. }
  401. // According to bug 228139, rpc definition of unicode strings allow
  402. // for odd lengths. We will set them to even (1 less) so that we
  403. // don't av in the lsa.
  404. if (ARGUMENT_PRESENT(UserName) && UserName->Buffer)
  405. {
  406. UserName->Length = (UserName->Length/sizeof(WCHAR)) * sizeof(WCHAR);
  407. }
  408. else
  409. {
  410. Status = STATUS_INVALID_PARAMETER;
  411. goto Cleanup;
  412. }
  413. KerbErr = KdcGetTicketInfo(
  414. UserName,
  415. 0, // no flags
  416. NULL,
  417. NULL,
  418. &TicketInfo,
  419. &ExtendedError,
  420. &UserHandle,
  421. 0L, // no fields to fetch
  422. 0L, // no extended fields
  423. NULL, // no user all
  424. NULL
  425. );
  426. if (!KERB_SUCCESS(KerbErr))
  427. {
  428. DebugLog((DEB_ERROR, "Failed to get ticket info for %wZ: 0x%x\n",
  429. UserName, KerbErr ));
  430. Status = STATUS_NO_SUCH_USER;
  431. goto Cleanup;
  432. }
  433. FreeTicketInfo(&TicketInfo);
  434. if (ARGUMENT_PRESENT(Password) && Password->Buffer)
  435. {
  436. Password->Length = (Password->Length/sizeof(WCHAR)) * sizeof(WCHAR);
  437. }
  438. else
  439. {
  440. Status = STATUS_INVALID_PARAMETER;
  441. goto Cleanup;
  442. }
  443. if (ARGUMENT_PRESENT(PrincipalName) && PrincipalName->Buffer)
  444. {
  445. PrincipalName->Length = (PrincipalName->Length/sizeof(WCHAR)) * sizeof(WCHAR);
  446. }
  447. else
  448. {
  449. Status = STATUS_INVALID_PARAMETER;
  450. goto Cleanup;
  451. }
  452. Status = KdcBuildPasswordList(
  453. Password,
  454. PrincipalName,
  455. SecData.KdcDnsRealmName(),
  456. UnknownAccount,
  457. NULL, // no stored creds
  458. 0, // no stored creds
  459. TRUE, // marshall
  460. FALSE, // don't include builtins
  461. Flags,
  462. Unknown,
  463. (PKERB_STORED_CREDENTIAL *) &Credentials.Credentials,
  464. &Credentials.CredentialSize
  465. );
  466. if (!NT_SUCCESS(Status))
  467. {
  468. goto Cleanup;
  469. }
  470. RtlInitUnicodeString(
  471. &Credentials.PackageName,
  472. MICROSOFT_KERBEROS_NAME_W
  473. );
  474. Status = SamIStorePrimaryCredentials(
  475. UserHandle,
  476. &Credentials
  477. );
  478. if (!NT_SUCCESS(Status))
  479. {
  480. DebugLog((DEB_ERROR, "Failed to store primary credentials: 0x%x\n",Status));
  481. goto Cleanup;
  482. }
  483. Cleanup:
  484. if (UserHandle != NULL)
  485. {
  486. SamrCloseHandle(&UserHandle);
  487. }
  488. if (Credentials.Credentials != NULL)
  489. {
  490. MIDL_user_free(Credentials.Credentials);
  491. }
  492. return(Status);
  493. }
  494. NTSTATUS
  495. KDC_GetDomainList(
  496. IN handle_t hBinding,
  497. OUT PKDC_DBG_DOMAIN_LIST * DomainList
  498. )
  499. {
  500. NTSTATUS Status = STATUS_SUCCESS;
  501. PKDC_DBG_DOMAIN_LIST TempList;
  502. PKDC_DBG_DOMAIN_INFO DomainInfo = NULL;
  503. PKDC_DOMAIN_INFO Domain;
  504. ULONG DomainCount = 0;
  505. PLIST_ENTRY ListEntry;
  506. ULONG Index = 0;
  507. *DomainList = NULL;
  508. KdcLockDomainListFn();
  509. TempList = (PKDC_DBG_DOMAIN_LIST) MIDL_user_allocate(sizeof(KDC_DBG_DOMAIN_LIST));
  510. if (TempList == NULL)
  511. {
  512. Status = STATUS_INSUFFICIENT_RESOURCES;
  513. goto Cleanup;
  514. }
  515. for (ListEntry = KdcDomainList.Flink;
  516. ListEntry != &KdcDomainList ;
  517. ListEntry = ListEntry->Flink )
  518. {
  519. DomainCount++;
  520. }
  521. DomainInfo = (PKDC_DBG_DOMAIN_INFO) MIDL_user_allocate(DomainCount * sizeof(KDC_DBG_DOMAIN_INFO));
  522. if (DomainInfo == NULL)
  523. {
  524. Status = STATUS_INSUFFICIENT_RESOURCES;
  525. goto Cleanup;
  526. }
  527. RtlZeroMemory(
  528. DomainInfo,
  529. DomainCount * sizeof(KDC_DBG_DOMAIN_INFO)
  530. );
  531. Index = 0;
  532. for (ListEntry = KdcDomainList.Flink;
  533. ListEntry != &KdcDomainList ;
  534. ListEntry = ListEntry->Flink )
  535. {
  536. Domain = (PKDC_DOMAIN_INFO) CONTAINING_RECORD(ListEntry, KDC_DOMAIN_INFO, Next);
  537. KerbDuplicateString(
  538. &DomainInfo[Index].DnsName,
  539. &Domain->DnsName
  540. );
  541. KerbDuplicateString(
  542. &DomainInfo[Index].NetbiosName,
  543. &Domain->NetbiosName
  544. );
  545. if (Domain->ClosestRoute != NULL)
  546. {
  547. KerbDuplicateString(
  548. &DomainInfo[Index].ClosestRoute,
  549. &Domain->ClosestRoute->DnsName
  550. );
  551. }
  552. DomainInfo->Type = Domain->Type;
  553. DomainInfo->Attributes = Domain->Attributes;
  554. Index++;
  555. }
  556. TempList->Count = DomainCount;
  557. TempList->Domains = DomainInfo;
  558. *DomainList = TempList;
  559. TempList = NULL;
  560. DomainInfo = NULL;
  561. Cleanup:
  562. KdcUnlockDomainListFn();
  563. if (TempList != NULL)
  564. {
  565. MIDL_user_free(TempList);
  566. }
  567. if (DomainInfo != NULL)
  568. {
  569. MIDL_user_free(DomainInfo);
  570. }
  571. return(Status);
  572. }
  573. VOID
  574. KdcCopyKeyData(
  575. OUT PKERB_KEY_DATA NewKey,
  576. IN PKERB_KEY_DATA OldKey,
  577. IN OUT PBYTE * Where,
  578. IN LONG_PTR Offset
  579. )
  580. {
  581. //
  582. // Copy the key
  583. //
  584. NewKey->Key.keytype = OldKey->Key.keytype;
  585. NewKey->Key.keyvalue.length = OldKey->Key.keyvalue.length;
  586. NewKey->Key.keyvalue.value = (*Where) - Offset;
  587. RtlCopyMemory(
  588. (*Where),
  589. OldKey->Key.keyvalue.value,
  590. OldKey->Key.keyvalue.length
  591. );
  592. (*Where) += OldKey->Key.keyvalue.length;
  593. //
  594. // Copy the salt
  595. //
  596. if (OldKey->Salt.Buffer != NULL)
  597. {
  598. NewKey->Salt.Length =
  599. NewKey->Salt.MaximumLength =
  600. OldKey->Salt.Length;
  601. NewKey->Salt.Buffer = (LPWSTR) ((*Where) - Offset);
  602. RtlCopyMemory(
  603. (*Where),
  604. OldKey->Salt.Buffer,
  605. OldKey->Salt.Length
  606. );
  607. (*Where) += OldKey->Salt.Length;
  608. }
  609. }
  610. //+-------------------------------------------------------------------------
  611. //
  612. // Function: KDC_SetAccountKeys
  613. //
  614. // Synopsis: Set the keys for an account
  615. //
  616. // Effects:
  617. //
  618. // Arguments:
  619. //
  620. // Requires:
  621. //
  622. // Returns:
  623. //
  624. // Notes:
  625. //
  626. //
  627. //--------------------------------------------------------------------------
  628. NTSTATUS
  629. KDC_SetAccountKeys(
  630. IN handle_t hBinding,
  631. IN PUNICODE_STRING UserName,
  632. IN ULONG Flags,
  633. IN PKERB_STORED_CREDENTIAL Keys
  634. )
  635. {
  636. NTSTATUS Status = STATUS_SUCCESS;
  637. KERBERR KerbErr;
  638. KERB_EXT_ERROR ExtendedError; // dummy var
  639. SECPKG_SUPPLEMENTAL_CRED Credentials = {0};
  640. KDC_TICKET_INFO TicketInfo= {0};
  641. SAMPR_HANDLE UserHandle = NULL;
  642. PKERB_STORED_CREDENTIAL StoredCreds = NULL;
  643. PKERB_STORED_CREDENTIAL Passwords = NULL;
  644. ULONG StoredCredSize = 0;
  645. ULONG CredentialCount = 0;
  646. ULONG CredentialIndex = 0;
  647. ULONG Index;
  648. PBYTE Where;
  649. UNICODE_STRING DefaultSalt;
  650. LONG_PTR Offset;
  651. if (!KdcSetPassSupported())
  652. {
  653. Status = STATUS_NOT_SUPPORTED;
  654. goto Cleanup;
  655. }
  656. //
  657. // Make sure we can impersonate the caller.
  658. //
  659. if (RpcImpersonateClient(NULL) != ERROR_SUCCESS)
  660. {
  661. Status = STATUS_ACCESS_DENIED;
  662. goto Cleanup;
  663. }
  664. else
  665. {
  666. RpcRevertToSelf();
  667. }
  668. // According to bug 228139, rpc definition of unicode strings allow
  669. // for odd lengths. We will set them to even (1 less) so that we
  670. // don't av in the lsa.
  671. if (ARGUMENT_PRESENT(UserName) && UserName->Buffer)
  672. {
  673. UserName->Length = (UserName->Length/sizeof(WCHAR)) * sizeof(WCHAR);
  674. }
  675. else
  676. {
  677. Status = STATUS_INVALID_PARAMETER;
  678. goto Cleanup;
  679. }
  680. KerbErr = KdcGetTicketInfo(
  681. UserName,
  682. 0, // no flags
  683. NULL,
  684. NULL,
  685. &TicketInfo,
  686. &ExtendedError,
  687. &UserHandle,
  688. 0L, // no fields to fetch
  689. 0L, // no extended fields
  690. NULL, // no user all
  691. NULL
  692. );
  693. if (!KERB_SUCCESS(KerbErr))
  694. {
  695. DebugLog((DEB_ERROR, "Failed to get ticket info for %wZ: 0x%x\n",
  696. UserName, KerbErr ));
  697. Status = STATUS_NO_SUCH_USER;
  698. goto Cleanup;
  699. }
  700. //
  701. // If the caller asks us to replace keys, then clobber all supplemental
  702. // creds with the new ones. Otherwise, just replace the current ones
  703. // with the old ones
  704. //
  705. Passwords = TicketInfo.Passwords;
  706. if ((Flags & KERB_SET_KEYS_REPLACE) ||
  707. (Passwords == NULL))
  708. {
  709. KerbErr = KdcDuplicateCredentials(
  710. &StoredCreds,
  711. &StoredCredSize,
  712. Keys,
  713. TRUE // marshall
  714. );
  715. if (!KERB_SUCCESS(KerbErr))
  716. {
  717. Status = KerbMapKerbError(KerbErr);
  718. goto Cleanup;
  719. }
  720. }
  721. else
  722. {
  723. if (Keys->OldCredentialCount != 0)
  724. {
  725. DebugLog((DEB_ERROR,"OldCredentialCount supplied with merge-in keys - illegal\n"));
  726. Status = STATUS_INVALID_PARAMETER;
  727. goto Cleanup;
  728. }
  729. //
  730. // Calculate the size of the stored creds.
  731. //
  732. StoredCredSize = FIELD_OFFSET(KERB_STORED_CREDENTIAL,Credentials) +
  733. Keys->CredentialCount * sizeof(KERB_KEY_DATA) +
  734. Keys->DefaultSalt.Length;
  735. for (Index = 0; Index < Keys->CredentialCount; Index++ )
  736. {
  737. StoredCredSize += Keys->Credentials[Index].Salt.Length +
  738. Keys->Credentials[Index].Key.keyvalue.length;
  739. CredentialCount++;
  740. }
  741. //
  742. // Add in the keys that aren't in the supplied ones
  743. //
  744. if (Keys->DefaultSalt.Buffer == NULL)
  745. {
  746. StoredCredSize += Passwords->DefaultSalt.Length;
  747. }
  748. //
  749. // Add the size for all the keys in the passwords that weren't
  750. // in the passed in keys
  751. //
  752. for (Index = 0; Index < Passwords->CredentialCount ; Index++ )
  753. {
  754. if (KerbGetKeyFromList(Keys, Passwords->Credentials[Index].Key.keytype) == NULL)
  755. {
  756. //
  757. // Make sure it is not a builtin
  758. //
  759. if ((Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_LM) ||
  760. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_MD4) ||
  761. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_OLD) ||
  762. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_OLD_EXP) ||
  763. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_NT) ||
  764. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_NT_EXP) ||
  765. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_NULL))
  766. {
  767. continue;
  768. }
  769. StoredCredSize += Passwords->Credentials[Index].Salt.Length
  770. + Passwords->Credentials[Index].Key.keyvalue.length
  771. + sizeof(KERB_KEY_DATA);
  772. CredentialCount++;
  773. }
  774. }
  775. //
  776. // Add in the old keys
  777. //
  778. for (Index = 0; Index < Passwords->OldCredentialCount; Index++ )
  779. {
  780. StoredCredSize += sizeof(KERB_KEY_DATA) +
  781. Passwords->Credentials[Index + Passwords->OldCredentialCount].Salt.Length +
  782. Passwords->Credentials[Index + Passwords->OldCredentialCount].Key.keyvalue.length;
  783. }
  784. //
  785. // Allocate a new buffer to contain the marshalled keys
  786. //
  787. StoredCreds = (PKERB_STORED_CREDENTIAL) MIDL_user_allocate(StoredCredSize);
  788. if (StoredCreds == NULL)
  789. {
  790. Status = STATUS_INSUFFICIENT_RESOURCES;
  791. goto Cleanup;
  792. }
  793. RtlZeroMemory(
  794. StoredCreds,
  795. StoredCredSize
  796. );
  797. //
  798. // Set the standard bits
  799. //
  800. StoredCreds->Revision = KERB_PRIMARY_CRED_REVISION;
  801. StoredCreds->Flags = 0;
  802. Offset = (LONG_PTR) StoredCreds;
  803. Where = (PBYTE) &(StoredCreds->Credentials[CredentialCount + Passwords->OldCredentialCount]);
  804. //
  805. // Copy in the default salt.
  806. //
  807. if (Keys->DefaultSalt.Buffer != NULL)
  808. {
  809. DefaultSalt = Keys->DefaultSalt;
  810. }
  811. else
  812. {
  813. DefaultSalt = Passwords->DefaultSalt;
  814. }
  815. if (DefaultSalt.Buffer != NULL)
  816. {
  817. StoredCreds->DefaultSalt.Length =
  818. StoredCreds->DefaultSalt.MaximumLength = DefaultSalt.Length;
  819. StoredCreds->DefaultSalt.Buffer = (LPWSTR) (Where - Offset);
  820. RtlCopyMemory(
  821. Where,
  822. DefaultSalt.Buffer,
  823. DefaultSalt.Length
  824. );
  825. Where += DefaultSalt.Length;
  826. }
  827. //
  828. // Copy in all the new keys
  829. //
  830. for (Index = 0; Index < Keys->CredentialCount ; Index++ )
  831. {
  832. KdcCopyKeyData(
  833. &StoredCreds->Credentials[CredentialIndex],
  834. &Keys->Credentials[Index],
  835. &Where,
  836. Offset
  837. );
  838. CredentialIndex++;
  839. }
  840. //
  841. // Copy in the existing keys
  842. //
  843. for (Index = 0; Index < Passwords->CredentialCount ; Index++ )
  844. {
  845. if (KerbGetKeyFromList(Keys, Passwords->Credentials[Index].Key.keytype) == NULL)
  846. {
  847. if ((Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_LM) ||
  848. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_MD4) ||
  849. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_OLD) ||
  850. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_OLD_EXP) ||
  851. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_NT) ||
  852. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_RC4_HMAC_NT_EXP) ||
  853. (Passwords->Credentials[Index].Key.keytype == KERB_ETYPE_NULL))
  854. {
  855. continue;
  856. }
  857. KdcCopyKeyData(
  858. &StoredCreds->Credentials[CredentialIndex],
  859. &Passwords->Credentials[Index],
  860. &Where,
  861. Offset
  862. );
  863. CredentialIndex++;
  864. }
  865. }
  866. StoredCreds->CredentialCount = (USHORT) CredentialIndex;
  867. //
  868. // Copy in the old keys from the existing keys
  869. //
  870. for (Index = 0; Index < Passwords->OldCredentialCount; Index++ )
  871. {
  872. KdcCopyKeyData(
  873. &StoredCreds->Credentials[CredentialIndex],
  874. &Passwords->Credentials[Index + Passwords->OldCredentialCount],
  875. &Where,
  876. Offset
  877. );
  878. CredentialIndex++;
  879. }
  880. StoredCreds->OldCredentialCount = Passwords->OldCredentialCount;
  881. }
  882. RtlInitUnicodeString(
  883. &Credentials.PackageName,
  884. MICROSOFT_KERBEROS_NAME_W
  885. );
  886. Credentials.Credentials = (PBYTE) StoredCreds;
  887. Credentials.CredentialSize = StoredCredSize;
  888. Status = SamIStorePrimaryCredentials(
  889. UserHandle,
  890. &Credentials
  891. );
  892. if (!NT_SUCCESS(Status))
  893. {
  894. DebugLog((DEB_ERROR, "Failed to store primary credentials: 0x%x\n",Status));
  895. goto Cleanup;
  896. }
  897. Cleanup:
  898. FreeTicketInfo(&TicketInfo);
  899. if (UserHandle != NULL)
  900. {
  901. SamrCloseHandle(&UserHandle);
  902. }
  903. if (StoredCreds != NULL)
  904. {
  905. MIDL_user_free(StoredCreds);
  906. }
  907. return(Status);
  908. }