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.

4498 lines
108 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1991 - 1992
  6. //
  7. // File: tickets.c
  8. //
  9. // Contents: Ticket bundling code
  10. //
  11. //
  12. // History: 6 Dec 91, RichardW Created
  13. // 04 Jun 92 RichardW NT-ized
  14. // 08-Jun-93 WadeR Converted to C++, rewrote packing code
  15. //
  16. //------------------------------------------------------------------------
  17. #ifdef WIN32_CHICAGO
  18. #include <kerb.hxx>
  19. #include <kerbp.h>
  20. #endif // WIN32_CHICAGO
  21. #ifndef WIN32_CHICAGO
  22. extern "C"
  23. {
  24. #include "krbprgma.h"
  25. #include <nt.h>
  26. #include <ntrtl.h>
  27. #include <nturtl.h>
  28. #include <ntlsa.h>
  29. #include <samrpc.h>
  30. #include <samisrv.h>
  31. #include <dnsapi.h>
  32. #include <wincrypt.h>
  33. #include <certca.h>
  34. }
  35. #include <kerbcomm.h>
  36. #include <kerberr.h>
  37. #include <kerbcon.h>
  38. #include "debug.h"
  39. #include <sddl.h>
  40. #include <malloc.h>
  41. #include <alloca.h>
  42. #endif // WIN32_CHICAGO
  43. #define KERB_NAME_PREFIX L"Kerberos:"
  44. UNICODE_STRING KerbNamePrefix = {sizeof(KERB_NAME_PREFIX) - sizeof(WCHAR), sizeof(KERB_NAME_PREFIX), KERB_NAME_PREFIX };
  45. UNICODE_STRING KerbNameSeparator = {sizeof(WCHAR), 2*sizeof(WCHAR), L"/" };
  46. UNICODE_STRING KerbDomainSeparator = {sizeof(WCHAR), 2*sizeof(WCHAR), L"@" };
  47. #ifndef SHA1DIGESTLEN
  48. #define SHA1DIGESTLEN 20
  49. #endif
  50. // Local Prototype */
  51. BOOL SafeRtlInitString(
  52. OUT PSTRING DestinationString,
  53. IN PCSZ SourceString OPTIONAL
  54. );
  55. BOOL SafeRtlInitUnicodeString(
  56. OUT PUNICODE_STRING DestinationString,
  57. IN PCWSTR SourceString OPTIONAL
  58. );
  59. LPWSTR
  60. KerbAllocWStrFromUtf8Str(
  61. IN PCHAR Utf8String
  62. )
  63. /*++
  64. Routine Description:
  65. Convert a UTF8 (zero terminated) string to the corresponding UNICODE
  66. string.
  67. Arguments:
  68. Utf8String - Specifies the UTF8 zero terminated string to convert.
  69. Return Value:
  70. NULL - There was some error in the conversion.
  71. Otherwise, it returns a pointer to the zero terminated UNICODE string in
  72. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  73. --*/
  74. {
  75. LPWSTR UnicodeString = NULL;
  76. int UnicodeStringLen;
  77. //
  78. // Determine the length of the Unicode string.
  79. //
  80. UnicodeStringLen = MultiByteToWideChar(
  81. #ifndef WIN32_CHICAGO
  82. CP_UTF8,
  83. #else // WIN32_CHICAGO
  84. CP_OEMCP,
  85. #endif // WIN32_CHICAGO
  86. 0, // All characters can be mapped.
  87. Utf8String,
  88. -1, // calculate length
  89. UnicodeString,
  90. 0 );
  91. if ( UnicodeStringLen == 0 ) {
  92. return NULL;
  93. }
  94. //
  95. // Allocate a buffer for the Unicode string.
  96. //
  97. UnicodeString = (LPWSTR) MIDL_user_allocate( (UnicodeStringLen+1)*sizeof(WCHAR) );
  98. if ( UnicodeString == NULL ) {
  99. return NULL;
  100. }
  101. //
  102. // Translate the string to Unicode.
  103. //
  104. UnicodeStringLen = MultiByteToWideChar(
  105. #ifndef WIN32_CHICAGO
  106. CP_UTF8,
  107. #else // WIN32_CHICAGO
  108. CP_OEMCP,
  109. #endif // WIN32_CHICAGO
  110. 0, // All characters can be mapped.
  111. Utf8String,
  112. -1,
  113. UnicodeString,
  114. UnicodeStringLen );
  115. if ( UnicodeStringLen == 0 ) {
  116. MIDL_user_free( UnicodeString );
  117. return NULL;
  118. }
  119. UnicodeString[UnicodeStringLen] = L'\0';
  120. return UnicodeString;
  121. }
  122. NTSTATUS
  123. KerbUnicodeStringFromUtf8Str(
  124. IN PCHAR Utf8String,
  125. OUT PUNICODE_STRING UnicodeString
  126. )
  127. /*++
  128. Routine Description:
  129. Convert a UTF8 (zero terminated) string to the corresponding UNICODE
  130. string.
  131. Arguments:
  132. Utf8String - Specifies the UTF8 zero terminated string to convert.
  133. UnicodeString - Receives the converted unicode string
  134. Return Value:
  135. NULL - There was some error in the conversion.
  136. Otherwise, it returns a pointer to the zero terminated UNICODE string in
  137. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  138. --*/
  139. {
  140. int UnicodeStringLen;
  141. ULONG ulLength = 0;
  142. //
  143. // Determine the length of the Unicode string.
  144. //
  145. UnicodeStringLen = MultiByteToWideChar(
  146. #ifndef WIN32_CHICAGO
  147. CP_UTF8,
  148. #else // WIN32_CHICAGO
  149. CP_OEMCP,
  150. #endif // WIN32_CHICAGO
  151. 0, // All characters can be mapped.
  152. Utf8String,
  153. -1, // calculate length
  154. UnicodeString->Buffer,
  155. 0 );
  156. if ( UnicodeStringLen == 0 ) {
  157. return (STATUS_SUCCESS);
  158. }
  159. //
  160. // The conversion routine returns space for a null terminator, so
  161. // adjust for that.
  162. //
  163. // check to make sure size fits into a USHORT value (with NULL appended)
  164. ulLength = (UnicodeStringLen - 1) * sizeof(WCHAR);
  165. if (ulLength > KERB_MAX_UNICODE_STRING)
  166. {
  167. return(STATUS_NAME_TOO_LONG);
  168. }
  169. UnicodeString->Length = (USHORT)ulLength;
  170. if (UnicodeString->MaximumLength < UnicodeString->Length + sizeof(WCHAR))
  171. {
  172. return(STATUS_BUFFER_TOO_SMALL);
  173. }
  174. //
  175. // Translate the string to Unicode.
  176. //
  177. UnicodeStringLen = MultiByteToWideChar(
  178. #ifndef WIN32_CHICAGO
  179. CP_UTF8,
  180. #else // WIN32_CHICAGO
  181. CP_OEMCP,
  182. #endif // WIN32_CHICAGO
  183. 0, // All characters can be mapped.
  184. Utf8String,
  185. -1,
  186. UnicodeString->Buffer,
  187. UnicodeStringLen );
  188. DsysAssert( UnicodeStringLen != 0 );
  189. UnicodeString->Buffer[UnicodeStringLen-1] = L'\0';
  190. UnicodeString->Length = (USHORT)((UnicodeStringLen-1) * sizeof(WCHAR));
  191. UnicodeString->MaximumLength = (USHORT)(UnicodeStringLen * sizeof(WCHAR));
  192. return STATUS_SUCCESS;
  193. }
  194. PCHAR
  195. KerbAllocUtf8StrFromUnicodeString(
  196. IN PUNICODE_STRING UnicodeString
  197. )
  198. /*++
  199. Routine Description:
  200. Convert a Unicode (zero terminated) string to the corresponding UTF8
  201. string.
  202. Arguments:
  203. UnicodeString - Specifies the Unicode zero terminated string to convert.
  204. Return Value:
  205. NULL - There was some error in the conversion.
  206. Otherwise, it returns a pointer to the zero terminated UTF8 string in
  207. an allocated buffer. The buffer must be freed using NetApiBufferFree.
  208. --*/
  209. {
  210. PCHAR Utf8String = NULL;
  211. int Utf8StringLen;
  212. //
  213. // If the length is zero, return a null string.
  214. //
  215. if (UnicodeString->Length == 0)
  216. {
  217. Utf8String = (PCHAR) MIDL_user_allocate(sizeof(CHAR));
  218. if (Utf8String != NULL)
  219. {
  220. *Utf8String = '\0';
  221. }
  222. return(Utf8String);
  223. }
  224. //
  225. // Determine the length of the Unicode string.
  226. //
  227. Utf8StringLen = WideCharToMultiByte(
  228. #ifndef WIN32_CHICAGO
  229. CP_UTF8,
  230. #else // WIN32_CHICAGO
  231. CP_OEMCP,
  232. #endif // WIN32_CHICAGO
  233. 0, // All characters can be mapped.
  234. UnicodeString->Buffer,
  235. UnicodeString->Length / sizeof(WCHAR),
  236. Utf8String,
  237. 0,
  238. NULL,
  239. NULL );
  240. if ( Utf8StringLen == 0 ) {
  241. return NULL;
  242. }
  243. //
  244. // Allocate a buffer for the Unicode string.
  245. //
  246. Utf8String = (PCHAR) MIDL_user_allocate( Utf8StringLen+1 );
  247. if ( Utf8String == NULL ) {
  248. return NULL;
  249. }
  250. //
  251. // Translate the string to Unicode.
  252. //
  253. Utf8StringLen = WideCharToMultiByte(
  254. #ifndef WIN32_CHICAGO
  255. CP_UTF8,
  256. #else // WIN32_CHICAGO
  257. CP_OEMCP,
  258. #endif // WIN32_CHICAGO
  259. 0, // All characters can be mapped.
  260. UnicodeString->Buffer,
  261. UnicodeString->Length / sizeof(WCHAR),
  262. Utf8String,
  263. Utf8StringLen,
  264. NULL,
  265. NULL );
  266. if ( Utf8StringLen == 0 ) {
  267. MIDL_user_free( Utf8String );
  268. return NULL;
  269. }
  270. Utf8String[Utf8StringLen] = '\0';
  271. return Utf8String;
  272. }
  273. //+-------------------------------------------------------------------------
  274. //
  275. // Function: KerbUnicodeStringToKerbString
  276. //
  277. // Synopsis: Converts a UNICODE_STRING to a kerberos-ansi string
  278. //
  279. // Effects: allocates destination with MIDL_user_allocate
  280. //
  281. // Arguments: KerbString - receives ansi-ized string
  282. // String - containes source unicode string
  283. //
  284. // Requires:
  285. //
  286. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  287. //
  288. // Notes: This routine hides the details of whether we use UTF-8 or
  289. // unicode->ansi conversion
  290. //
  291. //
  292. //--------------------------------------------------------------------------
  293. KERBERR
  294. KerbUnicodeStringToKerbString(
  295. OUT PSTRING KerbString,
  296. IN PUNICODE_STRING String
  297. )
  298. {
  299. STRING TempString;
  300. BOOL fAssigned = FALSE;
  301. if (!ARGUMENT_PRESENT(KerbString))
  302. {
  303. return(KRB_ERR_GENERIC);
  304. }
  305. TempString.Buffer = KerbAllocUtf8StrFromUnicodeString(String);
  306. if (TempString.Buffer == NULL)
  307. {
  308. return(KRB_ERR_GENERIC);
  309. }
  310. fAssigned = SafeRtlInitString(
  311. &TempString,
  312. TempString.Buffer
  313. );
  314. if (fAssigned == FALSE)
  315. {
  316. return(KRB_ERR_GENERIC); // string length would not fit into USHORT
  317. }
  318. *KerbString = TempString;
  319. return(KDC_ERR_NONE);
  320. }
  321. //+-------------------------------------------------------------------------
  322. //
  323. // Function: KerbStringToUnicodeString
  324. //
  325. // Synopsis: Converts a kerberos string to a unicode string
  326. //
  327. // Effects: allocates result string with MIDL_user_allocate
  328. //
  329. // Arguments:
  330. //
  331. // Requires:
  332. //
  333. // Returns:
  334. //
  335. // Notes:
  336. //
  337. //
  338. //--------------------------------------------------------------------------
  339. KERBERR
  340. KerbStringToUnicodeString(
  341. OUT PUNICODE_STRING String,
  342. IN PSTRING KerbString
  343. )
  344. {
  345. PCHAR TerminatedString;
  346. UNICODE_STRING TempString;
  347. BOOL fAssigned = FALSE;
  348. if (!ARGUMENT_PRESENT(KerbString) || !ARGUMENT_PRESENT(String))
  349. {
  350. return(KRB_ERR_GENERIC);
  351. }
  352. //
  353. // Null terminate the string
  354. //
  355. if ((KerbString->MaximumLength > KerbString->Length) &&
  356. (KerbString->Buffer[KerbString->Length] == '\0'))
  357. {
  358. TerminatedString = KerbString->Buffer;
  359. }
  360. else
  361. {
  362. //
  363. // Validate inputs before doing alloc.. This is because the Length can only be USHORT_MAX - 1 - sizeof(CHAR)
  364. // or we'll set max_length == 0.
  365. //
  366. if ( KerbString->Length > KERB_MAX_STRING )
  367. {
  368. return (KRB_ERR_GENERIC);
  369. }
  370. TerminatedString = (PCHAR) MIDL_user_allocate(KerbString->Length + sizeof(CHAR));
  371. if (TerminatedString == NULL)
  372. {
  373. return(KRB_ERR_GENERIC);
  374. }
  375. RtlCopyMemory(
  376. TerminatedString,
  377. KerbString->Buffer,
  378. KerbString->Length
  379. );
  380. TerminatedString[KerbString->Length] = '\0';
  381. }
  382. TempString.Buffer = KerbAllocWStrFromUtf8Str(
  383. TerminatedString
  384. );
  385. if (TerminatedString != KerbString->Buffer)
  386. {
  387. MIDL_user_free(TerminatedString);
  388. }
  389. if (TempString.Buffer == NULL)
  390. {
  391. return(KRB_ERR_GENERIC);
  392. }
  393. fAssigned = SafeRtlInitUnicodeString(
  394. &TempString,
  395. TempString.Buffer
  396. );
  397. if (fAssigned == FALSE)
  398. {
  399. MIDL_user_free(TempString.Buffer);
  400. return(KRB_ERR_GENERIC);
  401. }
  402. *String = TempString;
  403. return(KDC_ERR_NONE);
  404. }
  405. //+-------------------------------------------------------------------------
  406. //
  407. // Function: KerbComparePrincipalNames
  408. //
  409. // Synopsis: Compares two principal names for equality
  410. //
  411. // Effects:
  412. //
  413. // Arguments: Name1 - the first principal name
  414. // Name2 - the second principal name
  415. //
  416. // Requires:
  417. //
  418. // Returns: TRUE for eqaulity, FALSE for non-equality.
  419. //
  420. // Notes:
  421. //
  422. //
  423. //--------------------------------------------------------------------------
  424. BOOLEAN
  425. KerbComparePrincipalNames(
  426. IN PKERB_PRINCIPAL_NAME Name1,
  427. IN PKERB_PRINCIPAL_NAME Name2
  428. )
  429. {
  430. BOOLEAN Result = TRUE;
  431. PKERB_PRINCIPAL_NAME_ELEM NextName1, NextName2;
  432. if ((Name1 == NULL) && (Name2 == NULL))
  433. {
  434. return TRUE;
  435. }
  436. else if ((Name1 == NULL) || (Name2 == NULL))
  437. {
  438. return FALSE;
  439. }
  440. //
  441. // If the name types are known, make sure they match.
  442. //
  443. if ((Name1->name_type != KRB_NT_UNKNOWN) &&
  444. (Name2->name_type != KRB_NT_UNKNOWN) &&
  445. (Name1->name_type != Name2->name_type))
  446. {
  447. Result = FALSE;
  448. goto Cleanup;
  449. }
  450. NextName1 = Name1->name_string;
  451. NextName2 = Name2->name_string;
  452. while ((NextName1 != NULL) && (NextName2 != NULL))
  453. {
  454. if (lstrcmpiA(
  455. NextName1->value,
  456. NextName2->value
  457. ) != 0)
  458. {
  459. Result = FALSE;
  460. goto Cleanup;
  461. }
  462. NextName1 = NextName1->next;
  463. NextName2 = NextName2->next;
  464. }
  465. //
  466. // if one has more names than the other, fail
  467. //
  468. if (!((NextName1 == NULL) && (NextName2 == NULL)))
  469. {
  470. Result = FALSE;
  471. goto Cleanup;
  472. }
  473. return(TRUE);
  474. Cleanup:
  475. //
  476. // BUG 455493: transitional code
  477. //
  478. if (Result == FALSE)
  479. {
  480. KERBERR KerbErr;
  481. ULONG NameType;
  482. UNICODE_STRING UName1;
  483. UNICODE_STRING UName2;
  484. KerbErr = KerbConvertPrincipalNameToString(
  485. &UName1,
  486. &NameType,
  487. Name1
  488. );
  489. if (!KERB_SUCCESS(KerbErr))
  490. {
  491. return(FALSE);
  492. }
  493. KerbErr = KerbConvertPrincipalNameToString(
  494. &UName2,
  495. &NameType,
  496. Name2
  497. );
  498. if (!KERB_SUCCESS(KerbErr))
  499. {
  500. KerbFreeString(&UName1);
  501. return(FALSE);
  502. }
  503. Result = RtlEqualUnicodeString(
  504. &UName1,
  505. &UName2,
  506. TRUE
  507. );
  508. KerbFreeString( &UName1 );
  509. KerbFreeString( &UName2 );
  510. // FESTER
  511. // IF THIS ASSERT GETS FIRED, Contact Todds (0x30864)
  512. // This code *should* be transitional, and I've not seen it called,
  513. // but the only way to be certain is to add Assert and let it rot in
  514. // Whistler... Remove before B2.
  515. //
  516. if (Result)
  517. {
  518. D_DebugLog((DEB_ERROR,"Assert about to fire. Dead code called. Contact Todds\n"));
  519. DsysAssert(FALSE);
  520. }
  521. }
  522. return (Result);
  523. }
  524. //+-------------------------------------------------------------------------
  525. //
  526. // Function: KerbCompareRealmNames
  527. //
  528. // Synopsis: Compares two realm names for equality
  529. //
  530. // Effects:
  531. //
  532. // Arguments: Realm1 - First realm to compare
  533. // Realm2 - Second realm to compare
  534. //
  535. // Requires:
  536. //
  537. // Returns: TRUE if they are equal, FALSE otherwise
  538. //
  539. // Notes:
  540. //
  541. //
  542. //--------------------------------------------------------------------------
  543. BOOLEAN
  544. KerbCompareRealmNames(
  545. IN PKERB_REALM Realm1,
  546. IN PKERB_REALM Realm2
  547. )
  548. {
  549. INT len1;
  550. INT len2;
  551. INT retval;
  552. if ((Realm1 == NULL) && (Realm2 == NULL))
  553. {
  554. return TRUE;
  555. }
  556. else if ((Realm1 == NULL) || (Realm2 == NULL))
  557. {
  558. return FALSE;
  559. }
  560. len1 = (INT) strlen( *Realm1 );
  561. len2 = (INT) strlen( *Realm2 );
  562. //
  563. // Check if any trailing '.' need to be stripped off
  564. //
  565. if ( len2 != len1 )
  566. {
  567. if ( len2 == len1+1 )
  568. {
  569. if ( (*Realm2)[len1] != '.' )
  570. {
  571. return( FALSE );
  572. }
  573. //
  574. // len1 is comparable length
  575. //
  576. }
  577. else if ( len2+1 == len1 )
  578. {
  579. if ( (*Realm1)[len2] != '.' )
  580. {
  581. return( FALSE );
  582. }
  583. //
  584. // len1 is set to comparable length
  585. //
  586. len1 = len2;
  587. }
  588. else
  589. {
  590. return( FALSE );
  591. }
  592. }
  593. retval = CompareStringA( GetSystemDefaultLCID(),
  594. LOCALE_USE_CP_ACP | NORM_IGNORECASE,
  595. (*Realm1),
  596. len1,
  597. (*Realm2),
  598. len1
  599. );
  600. return ( retval == CSTR_EQUAL );
  601. }
  602. //+-------------------------------------------------------------------------
  603. //
  604. // Function: KerbCompareUnicodeRealmNames
  605. //
  606. // Synopsis: Compares two realm names for equality
  607. //
  608. // Effects:
  609. //
  610. // Arguments: Realm1 - First realm to compare
  611. // Realm2 - Second realm to compare
  612. //
  613. // Requires:
  614. //
  615. // Returns: TRUE if they are equal, FALSE otherwise
  616. //
  617. // Notes:
  618. //
  619. //
  620. //--------------------------------------------------------------------------
  621. BOOLEAN
  622. KerbCompareUnicodeRealmNames(
  623. IN PUNICODE_STRING Domain1,
  624. IN PUNICODE_STRING Domain2
  625. )
  626. {
  627. UNICODE_STRING Realm1 = {0};
  628. UNICODE_STRING Realm2 = {0};
  629. if ((Domain1 == NULL) && (Domain2 == NULL))
  630. {
  631. return TRUE;
  632. }
  633. else if ((Domain1 == NULL) || (Domain2 == NULL))
  634. {
  635. return FALSE;
  636. }
  637. else if ((Domain1->Buffer == NULL) && (Domain2->Buffer == NULL))
  638. {
  639. return(TRUE);
  640. }
  641. else if ((Domain1->Buffer == NULL) || (Domain2->Buffer == NULL))
  642. {
  643. return(FALSE);
  644. }
  645. Realm1 = *Domain1;
  646. Realm2 = *Domain2;
  647. //
  648. // Check if any trailing '.' need to be stripped off
  649. //
  650. if ( Realm2.Length != Realm1.Length )
  651. {
  652. if ( Realm2.Length == Realm1.Length+sizeof(WCHAR) )
  653. {
  654. if ( Realm2.Buffer[Realm1.Length / sizeof(WCHAR)] != '.' )
  655. {
  656. return( FALSE );
  657. }
  658. else
  659. {
  660. Realm2.Length = Realm1.Length;
  661. }
  662. }
  663. else if ( Realm2.Length+sizeof(WCHAR) == Realm1.Length )
  664. {
  665. if ( Realm1.Buffer[Realm2.Length / sizeof(WCHAR)] != '.' )
  666. {
  667. return( FALSE );
  668. }
  669. else
  670. {
  671. Realm1.Length = Realm2.Length;
  672. }
  673. }
  674. else
  675. {
  676. return( FALSE );
  677. }
  678. }
  679. //
  680. // compare only comparable length of string
  681. //
  682. return( RtlEqualUnicodeString( &Realm1, &Realm2, TRUE ));
  683. }
  684. //+-------------------------------------------------------------------------
  685. //
  686. // Function: KdcFreeKdcName
  687. //
  688. // Synopsis: Frees all parts of a KDC name structure
  689. //
  690. // Effects:
  691. //
  692. // Arguments:
  693. //
  694. // Requires:
  695. //
  696. // Returns:
  697. //
  698. // Notes:
  699. //
  700. //
  701. //--------------------------------------------------------------------------
  702. VOID
  703. KerbFreeKdcName(
  704. IN PKERB_INTERNAL_NAME * KdcName
  705. )
  706. {
  707. if (*KdcName != NULL)
  708. {
  709. MIDL_user_free(*KdcName);
  710. *KdcName = NULL;
  711. }
  712. }
  713. //+-------------------------------------------------------------------------
  714. //
  715. // Function: KerbConvertPrincipalNameToKdcName
  716. //
  717. // Synopsis:
  718. //
  719. // Effects:
  720. //
  721. // Arguments:
  722. //
  723. // Requires:
  724. //
  725. // Returns:
  726. //
  727. // Notes:
  728. //
  729. //
  730. //--------------------------------------------------------------------------
  731. KERBERR
  732. KerbConvertPrincipalNameToKdcName(
  733. OUT PKERB_INTERNAL_NAME * OutputName,
  734. IN PKERB_PRINCIPAL_NAME PrincipalName
  735. )
  736. {
  737. NTSTATUS Status;
  738. KERBERR KerbErr = KDC_ERR_NONE;
  739. ULONG NameCount = 0;
  740. ULONG Index;
  741. STRING Names[MAX_NAME_ELEMENTS+1];
  742. PKERB_PRINCIPAL_NAME_ELEM NameElement;
  743. PKERB_INTERNAL_NAME KdcName = NULL;
  744. ULONG NameSize = 0;
  745. ULONG NameLength = 0;
  746. PUCHAR Where;
  747. BOOL fAssigned = FALSE;
  748. NameElement = PrincipalName->name_string;
  749. while (NameElement!= NULL)
  750. {
  751. // Verify we do not overrun a USHORT length
  752. fAssigned = SafeRtlInitString(
  753. &Names[NameCount],
  754. NameElement->value
  755. );
  756. if (fAssigned == FALSE)
  757. {
  758. D_DebugLog((DEB_ERROR,"KerbConvertPrincipalNameToKdcName:Name part too long\n"));
  759. return(KRB_ERR_GENERIC);
  760. }
  761. NameLength += (Names[NameCount].Length + 1) * sizeof(WCHAR);
  762. NameCount++;
  763. NameElement = NameElement->next;
  764. if (NameCount > MAX_NAME_ELEMENTS)
  765. {
  766. D_DebugLog((DEB_ERROR,"Too many name parts: %d\n",NameCount));
  767. return(KRB_ERR_GENERIC);
  768. }
  769. }
  770. // check to make sure size fits into a USHORT value (with NULL appended)
  771. // NameLength will be casted to USHORT below.
  772. if (NameLength > KERB_MAX_UNICODE_STRING)
  773. {
  774. D_DebugLog((DEB_ERROR,"KerbConvertPrincipalNameToKdcName: Overall size too large\n"));
  775. return(KRB_ERR_GENERIC);
  776. }
  777. //
  778. // Now we have the count of parts, so allocate the destination structure
  779. //
  780. if (NameCount == 0)
  781. {
  782. D_DebugLog((DEB_ERROR,"Illegal name with zero parts\n"));
  783. return(KRB_ERR_GENERIC);
  784. }
  785. NameSize = KERB_INTERNAL_NAME_SIZE(NameCount) + NameLength;
  786. KdcName = (PKERB_INTERNAL_NAME) MIDL_user_allocate(NameSize);
  787. if (KdcName == NULL)
  788. {
  789. return(KRB_ERR_GENERIC);
  790. }
  791. RtlZeroMemory(
  792. KdcName,
  793. NameSize
  794. );
  795. KdcName->NameCount = (USHORT) NameCount;
  796. KdcName->NameType = (USHORT) PrincipalName->name_type;
  797. Where = (PUCHAR) KdcName + KERB_INTERNAL_NAME_SIZE(NameCount);
  798. //
  799. // Now convert all the strings from the temporary array into
  800. // UNICODE_STRINGs in the final array
  801. //
  802. for (Index = 0; Index < NameCount ; Index++ )
  803. {
  804. KdcName->Names[Index].Length = 0;
  805. KdcName->Names[Index].MaximumLength = (USHORT)NameLength;
  806. KdcName->Names[Index].Buffer = (LPWSTR) Where;
  807. Status = KerbUnicodeStringFromUtf8Str(
  808. Names[Index].Buffer,
  809. &KdcName->Names[Index]
  810. );
  811. if (!NT_SUCCESS(Status))
  812. {
  813. KerbErr = KRB_ERR_GENERIC;
  814. goto Cleanup;
  815. }
  816. Where += KdcName->Names[Index].MaximumLength;
  817. NameLength = NameLength - KdcName->Names[Index].MaximumLength;
  818. }
  819. *OutputName = KdcName;
  820. KdcName = NULL;
  821. Cleanup:
  822. if (KdcName != NULL)
  823. {
  824. KerbFreeKdcName(&KdcName);
  825. }
  826. return(KerbErr);
  827. }
  828. //+-------------------------------------------------------------------------
  829. //
  830. // Function: KerbCovnertKdcNameToPrincipalName
  831. //
  832. // Synopsis: Converts a KDC name to a Principal name & allocates output with
  833. // MIDL_user_allocate
  834. //
  835. // Effects:
  836. //
  837. // Arguments:
  838. //
  839. // Requires:
  840. //
  841. // Returns:
  842. //
  843. // Notes:
  844. //
  845. //
  846. //--------------------------------------------------------------------------
  847. KERBERR
  848. KerbConvertKdcNameToPrincipalName(
  849. OUT PKERB_PRINCIPAL_NAME PrincipalName,
  850. IN PKERB_INTERNAL_NAME KdcName
  851. )
  852. {
  853. PKERB_PRINCIPAL_NAME_ELEM Elem = NULL;
  854. PKERB_PRINCIPAL_NAME_ELEM * Last;
  855. STRING TempKerbString = {0};
  856. KERBERR KerbErr = KDC_ERR_NONE;
  857. ULONG Index;
  858. PrincipalName->name_type = (int) KdcName->NameType;
  859. PrincipalName->name_string = NULL;
  860. Last = &PrincipalName->name_string;
  861. //
  862. // Index through the KDC name and add each element to the list
  863. //
  864. for (Index = 0; Index < KdcName->NameCount ; Index++ )
  865. {
  866. KerbErr = KerbUnicodeStringToKerbString(
  867. &TempKerbString,
  868. &KdcName->Names[Index]
  869. );
  870. if (!KERB_SUCCESS(KerbErr))
  871. {
  872. goto Cleanup;
  873. }
  874. Elem = (PKERB_PRINCIPAL_NAME_ELEM) MIDL_user_allocate(sizeof(KERB_PRINCIPAL_NAME_ELEM));
  875. if (Elem == NULL)
  876. {
  877. KerbErr = KRB_ERR_GENERIC;
  878. goto Cleanup;
  879. }
  880. Elem->value = TempKerbString.Buffer;
  881. Elem->next = NULL;
  882. *Last = Elem;
  883. Last = &Elem->next;
  884. TempKerbString.Buffer = NULL;
  885. }
  886. Cleanup:
  887. if (!KERB_SUCCESS(KerbErr))
  888. {
  889. //
  890. // Cleanup the principal name
  891. //
  892. KerbFreePrincipalName(PrincipalName);
  893. if (TempKerbString.Buffer)
  894. {
  895. MIDL_user_free(TempKerbString.Buffer);
  896. TempKerbString.Buffer = NULL;
  897. }
  898. }
  899. return(KerbErr);
  900. }
  901. //+-------------------------------------------------------------------------
  902. //
  903. // Function: KerbEqualKdcNames
  904. //
  905. // Synopsis: Compares to KDC names for equality
  906. //
  907. // Effects:
  908. //
  909. // Arguments:
  910. //
  911. // Requires:
  912. //
  913. // Returns: TRUE if the names are identical
  914. //
  915. // Notes:
  916. //
  917. //
  918. //--------------------------------------------------------------------------
  919. BOOLEAN
  920. KerbEqualKdcNames(
  921. IN PKERB_INTERNAL_NAME Name1,
  922. IN PKERB_INTERNAL_NAME Name2
  923. )
  924. {
  925. BOOLEAN Equal = TRUE;
  926. ULONG Index;
  927. if ((Name1 == NULL) && (Name2 == NULL))
  928. {
  929. return TRUE;
  930. }
  931. else if ((Name1 == NULL) || (Name2 == NULL))
  932. {
  933. return FALSE;
  934. }
  935. //
  936. // Special case some Microsoft name types
  937. //
  938. if (Name1->NameCount != Name2->NameCount)
  939. {
  940. Equal = FALSE;
  941. }
  942. else
  943. {
  944. for (Index = 0; Index < Name1->NameCount ; Index++ )
  945. {
  946. if (!RtlEqualUnicodeString(
  947. &Name1->Names[Index],
  948. &Name2->Names[Index],
  949. TRUE // case insensitive
  950. ))
  951. {
  952. Equal = FALSE;
  953. break;
  954. }
  955. }
  956. }
  957. return(Equal);
  958. }
  959. //+-------------------------------------------------------------------------
  960. //
  961. // Function: KerbComparePrincipalNameToKdcName
  962. //
  963. // Synopsis: Compares a princial name to a KDC name by first converting
  964. // and then comparing.
  965. //
  966. // Effects:
  967. //
  968. // Arguments:
  969. //
  970. // Requires:
  971. //
  972. // Returns:
  973. //
  974. // Notes:
  975. //
  976. //
  977. //--------------------------------------------------------------------------
  978. KERBERR
  979. KerbCompareKdcNameToPrincipalName(
  980. IN PKERB_PRINCIPAL_NAME PrincipalName,
  981. IN PKERB_INTERNAL_NAME KdcName,
  982. OUT PBOOLEAN Result
  983. )
  984. {
  985. PKERB_INTERNAL_NAME TempName = NULL;
  986. DsysAssert(Result);
  987. if (!KERB_SUCCESS(KerbConvertPrincipalNameToKdcName(
  988. &TempName,
  989. PrincipalName
  990. )))
  991. {
  992. return(KRB_ERR_GENERIC);
  993. }
  994. *Result = KerbEqualKdcNames( TempName, KdcName );
  995. KerbFreeKdcName( &TempName );
  996. return(KDC_ERR_NONE);
  997. }
  998. //+-------------------------------------------------------------------------
  999. //
  1000. // Function: KerbDuplicateKdcName
  1001. //
  1002. // Synopsis: Duplicates an internal name by copying the pointer and
  1003. // referencing the structure.
  1004. //
  1005. // Effects:
  1006. //
  1007. // Arguments:
  1008. //
  1009. // Requires:
  1010. //
  1011. // Returns:
  1012. //
  1013. // Notes:
  1014. //
  1015. //
  1016. //--------------------------------------------------------------------------
  1017. NTSTATUS
  1018. KerbDuplicateKdcName(
  1019. OUT PKERB_INTERNAL_NAME * Destination,
  1020. IN PKERB_INTERNAL_NAME Source
  1021. )
  1022. {
  1023. NTSTATUS Status = STATUS_SUCCESS;
  1024. USHORT Index;
  1025. PKERB_INTERNAL_NAME KdcName = NULL;
  1026. ULONG NameSize = 0;
  1027. ULONG NameLength = 0;
  1028. PUCHAR Where;
  1029. //
  1030. // Now we have the count of parts, so allocate the destination structure
  1031. //
  1032. if (Source->NameCount == 0)
  1033. {
  1034. D_DebugLog((DEB_ERROR,"Illegal name with zero parts\n"));
  1035. return(STATUS_INVALID_PARAMETER);
  1036. }
  1037. for (Index = 0; Index < Source->NameCount ; Index++ )
  1038. {
  1039. NameLength += Source->Names[Index].Length + sizeof(WCHAR);
  1040. }
  1041. NameSize = KERB_INTERNAL_NAME_SIZE(Source->NameCount) + NameLength;
  1042. KdcName = (PKERB_INTERNAL_NAME) MIDL_user_allocate(NameSize);
  1043. if (KdcName == NULL)
  1044. {
  1045. return(STATUS_INSUFFICIENT_RESOURCES);
  1046. }
  1047. RtlZeroMemory(
  1048. KdcName,
  1049. NameSize
  1050. );
  1051. KdcName->NameCount = (USHORT) Source->NameCount;
  1052. Where = (PUCHAR) KdcName + KERB_INTERNAL_NAME_SIZE(Source->NameCount);
  1053. //
  1054. // Now convert all the strings from the temporary array into
  1055. // UNICODE_STRINGs in the final array
  1056. //
  1057. for (Index = 0; Index < Source->NameCount ; Index++ )
  1058. {
  1059. if (Source->Names[Index].Length > KERB_MAX_UNICODE_STRING)
  1060. {
  1061. Status = STATUS_NAME_TOO_LONG;
  1062. goto Cleanup; // length will not fit into USHORT value
  1063. }
  1064. KdcName->Names[Index].Length = Source->Names[Index].Length;
  1065. KdcName->Names[Index].MaximumLength = Source->Names[Index].Length + sizeof(WCHAR);
  1066. KdcName->Names[Index].Buffer = (LPWSTR) Where;
  1067. RtlCopyMemory(
  1068. Where,
  1069. Source->Names[Index].Buffer,
  1070. Source->Names[Index].Length
  1071. );
  1072. KdcName->Names[Index].Buffer[Source->Names[Index].Length / sizeof(WCHAR)] = L'\0';
  1073. Where += KdcName->Names[Index].MaximumLength;
  1074. }
  1075. KdcName->NameType = Source->NameType;
  1076. *Destination = KdcName;
  1077. KdcName = NULL;
  1078. Cleanup:
  1079. if (KdcName != NULL)
  1080. {
  1081. KerbFreeKdcName(&KdcName);
  1082. }
  1083. return(Status);
  1084. }
  1085. #ifdef RETAIL_LOG_SUPPORT
  1086. VOID
  1087. KerbPrintKdcNameEx(
  1088. IN ULONG DebugLevel,
  1089. IN ULONG InfoLevel,
  1090. IN PKERB_INTERNAL_NAME Name
  1091. )
  1092. {
  1093. ULONG Index;
  1094. if ((InfoLevel & DebugLevel) != 0)
  1095. {
  1096. for (Index = 0; Name && (Index < Name->NameCount); Index++)
  1097. {
  1098. DebugLog((DebugLevel | DSYSDBG_CLEAN, " %wZ ", &Name->Names[Index]));
  1099. }
  1100. DebugLog((DebugLevel | DSYSDBG_CLEAN, "\n"));
  1101. }
  1102. }
  1103. VOID
  1104. KerbPrintPrincipalName(
  1105. IN ULONG DebugLevel,
  1106. IN PKERB_PRINCIPAL_NAME Name
  1107. )
  1108. {
  1109. KERBERR KerbErr;
  1110. PKERB_INTERNAL_NAME KdcName = NULL;
  1111. KerbErr = KerbConvertPrincipalNameToKdcName(
  1112. &KdcName,
  1113. Name
  1114. );
  1115. if (KERB_SUCCESS(KerbErr))
  1116. {
  1117. KerbPrintKdcNameEx(DebugLevel, DebugLevel, KdcName);
  1118. KerbFreeKdcName(&KdcName);
  1119. }
  1120. }
  1121. VOID
  1122. KerbPrintKerbRealm(
  1123. IN ULONG DebugLevel,
  1124. IN PKERB_REALM Realm
  1125. )
  1126. {
  1127. KERBERR KerbErr;
  1128. UNICODE_STRING RealmName = {0};
  1129. KerbErr = KerbConvertRealmToUnicodeString(
  1130. &RealmName,
  1131. Realm
  1132. );
  1133. if (KERB_SUCCESS(KerbErr))
  1134. {
  1135. DebugLog((DebugLevel, "%wZ\n", &RealmName));
  1136. KerbFreeString(&RealmName);
  1137. }
  1138. }
  1139. #endif
  1140. //+-------------------------------------------------------------------------
  1141. //
  1142. // Function: KerbConvertStringToKdcName
  1143. //
  1144. // Synopsis: Converts a string to a KRB_NT_MS_PRINCIPAL kdc name
  1145. //
  1146. // Effects:
  1147. //
  1148. // Arguments:
  1149. //
  1150. // Requires:
  1151. //
  1152. // Returns:
  1153. //
  1154. // Notes:
  1155. //
  1156. //
  1157. //--------------------------------------------------------------------------
  1158. KERBERR
  1159. KerbConvertStringToKdcName(
  1160. OUT PKERB_INTERNAL_NAME * PrincipalName,
  1161. IN PUNICODE_STRING String
  1162. )
  1163. {
  1164. PKERB_INTERNAL_NAME LocalName = NULL;
  1165. LocalName = (PKERB_INTERNAL_NAME) MIDL_user_allocate(KERB_INTERNAL_NAME_SIZE(1) + String->Length + sizeof(WCHAR));
  1166. if (LocalName == NULL)
  1167. {
  1168. return(KRB_ERR_GENERIC);
  1169. }
  1170. LocalName->NameCount = 1;
  1171. LocalName->NameType = KRB_NT_MS_PRINCIPAL;
  1172. LocalName->Names[0].Length = String->Length;
  1173. LocalName->Names[0].MaximumLength = String->Length + sizeof(WCHAR);
  1174. LocalName->Names[0].Buffer = (LPWSTR) ((PUCHAR) LocalName + KERB_INTERNAL_NAME_SIZE(1));
  1175. RtlCopyMemory(
  1176. LocalName->Names[0].Buffer,
  1177. String->Buffer,
  1178. String->Length
  1179. );
  1180. LocalName->Names[0].Buffer[String->Length/sizeof(WCHAR)] = L'\0';
  1181. *PrincipalName = LocalName;
  1182. return(KDC_ERR_NONE);
  1183. }
  1184. //+-------------------------------------------------------------------------
  1185. //
  1186. // Function: KerbConvertKdcNameToString
  1187. //
  1188. // Synopsis: Converts a KdcName to a '/' separated unicode string.
  1189. //
  1190. // Effects:
  1191. //
  1192. // Arguments:
  1193. //
  1194. // Requires:
  1195. //
  1196. // Returns:
  1197. //
  1198. // Notes:
  1199. //
  1200. //
  1201. //--------------------------------------------------------------------------
  1202. KERBERR
  1203. KerbConvertKdcNameToString(
  1204. OUT PUNICODE_STRING String,
  1205. IN PKERB_INTERNAL_NAME PrincipalName,
  1206. IN OPTIONAL PUNICODE_STRING RealmName
  1207. )
  1208. {
  1209. ULONG StringLength = 0;
  1210. ULONG Index;
  1211. PBYTE Where;
  1212. if (!ARGUMENT_PRESENT(PrincipalName) || !ARGUMENT_PRESENT(String))
  1213. {
  1214. return(KRB_ERR_GENERIC);
  1215. }
  1216. //
  1217. // Count up the size of the name parts
  1218. //
  1219. for (Index = 0; Index < PrincipalName->NameCount ; Index++ )
  1220. {
  1221. StringLength = StringLength + PrincipalName->Names[Index].Length;
  1222. }
  1223. if (ARGUMENT_PRESENT(RealmName) && (RealmName->Length != 0))
  1224. {
  1225. StringLength = StringLength + (sizeof(WCHAR) + RealmName->Length);
  1226. }
  1227. //
  1228. // Add in '/' separators and a null terminator
  1229. //
  1230. DsysAssert(PrincipalName->NameCount > 0);
  1231. StringLength = StringLength + (PrincipalName->NameCount * sizeof(WCHAR));
  1232. if ((StringLength - sizeof(WCHAR)) > KERB_MAX_UNICODE_STRING)
  1233. {
  1234. return(KRB_ERR_GENERIC); // required size too large for Length
  1235. }
  1236. String->Buffer = (LPWSTR) MIDL_user_allocate(StringLength);
  1237. if (String->Buffer == NULL)
  1238. {
  1239. return(KRB_ERR_GENERIC);
  1240. }
  1241. String->MaximumLength = (USHORT)StringLength;
  1242. String->Length = (USHORT)(StringLength - sizeof(WCHAR));
  1243. Where = (PBYTE) String->Buffer;
  1244. for (Index = 0; Index < PrincipalName->NameCount ; Index++ )
  1245. {
  1246. //
  1247. // Add a '/' before every segment but the first
  1248. //
  1249. if (Index != 0)
  1250. {
  1251. *((LPWSTR)(Where)) = L'/';
  1252. Where += sizeof(WCHAR);
  1253. }
  1254. RtlCopyMemory(
  1255. Where,
  1256. PrincipalName->Names[Index].Buffer,
  1257. PrincipalName->Names[Index].Length
  1258. );
  1259. Where += PrincipalName->Names[Index].Length;
  1260. }
  1261. if (ARGUMENT_PRESENT(RealmName) && (RealmName->Length != 0))
  1262. {
  1263. *((LPWSTR)(Where)) = L'@';
  1264. Where += sizeof(WCHAR);
  1265. RtlCopyMemory(
  1266. Where,
  1267. RealmName->Buffer,
  1268. RealmName->Length
  1269. );
  1270. Where += RealmName->Length;
  1271. }
  1272. *((LPWSTR)(Where)) = L'\0';
  1273. Where += sizeof(WCHAR);
  1274. DsysAssert((Where - (PUCHAR) String->Buffer) == (LONG)StringLength);
  1275. return(KDC_ERR_NONE);
  1276. }
  1277. //+-------------------------------------------------------------------------
  1278. //
  1279. // Function: KerbBuildFullServiceName
  1280. //
  1281. // Synopsis: Combines a service name and domain name to make a full
  1282. // service name.
  1283. //
  1284. // Effects:
  1285. //
  1286. // Arguments: DomainName - Domain name of service
  1287. // Servicename - Name of service
  1288. // FullServiceName - Receives full service name
  1289. //
  1290. // Requires:
  1291. //
  1292. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  1293. //
  1294. // Notes: This is dependent on our DS naming conventions
  1295. //
  1296. //
  1297. //--------------------------------------------------------------------------
  1298. KERBERR
  1299. KerbBuildFullServiceName(
  1300. IN PUNICODE_STRING DomainName,
  1301. IN PUNICODE_STRING ServiceName,
  1302. OUT PUNICODE_STRING FullServiceName
  1303. )
  1304. {
  1305. PUCHAR Where;
  1306. ULONG ulLength = 0;
  1307. FullServiceName->Buffer = NULL;
  1308. ulLength = (ULONG)DomainName->Length +
  1309. (ULONG)ServiceName->Length +
  1310. sizeof(WCHAR);
  1311. if (ulLength > KERB_MAX_UNICODE_STRING)
  1312. {
  1313. return(KRB_ERR_GENERIC); // required size too large for Length
  1314. }
  1315. FullServiceName->Length = (USHORT)ulLength;
  1316. FullServiceName->MaximumLength =
  1317. FullServiceName->Length + sizeof(WCHAR);
  1318. FullServiceName->Buffer = (LPWSTR) MIDL_user_allocate(
  1319. FullServiceName->MaximumLength
  1320. );
  1321. if (FullServiceName->Buffer == NULL)
  1322. {
  1323. return(KRB_ERR_GENERIC);
  1324. }
  1325. Where = (PUCHAR) FullServiceName->Buffer;
  1326. RtlCopyMemory(
  1327. FullServiceName->Buffer,
  1328. DomainName->Buffer,
  1329. DomainName->Length
  1330. );
  1331. Where += DomainName->Length;
  1332. if ((DomainName->Length !=0) && (ServiceName->Length != 0))
  1333. {
  1334. *(LPWSTR) Where = L'\\';
  1335. Where += sizeof(WCHAR);
  1336. }
  1337. RtlCopyMemory(
  1338. Where,
  1339. ServiceName->Buffer,
  1340. ServiceName->Length
  1341. );
  1342. Where += ServiceName->Length;
  1343. FullServiceName->Length = (USHORT)(Where - (PUCHAR) FullServiceName->Buffer);
  1344. *(LPWSTR) Where = L'\0';
  1345. return(KDC_ERR_NONE);
  1346. }
  1347. //+-------------------------------------------------------------------------
  1348. //
  1349. // Function: KerbBuildEmailName
  1350. //
  1351. // Synopsis: Combines a service name and domain name to make an email
  1352. // name = "service@domain".
  1353. //
  1354. //
  1355. // Effects:
  1356. //
  1357. // Arguments: DomainName - Domain name of service
  1358. // Servicename - Name of service
  1359. // FullServiceName - Receives full service name
  1360. //
  1361. // Requires:
  1362. //
  1363. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  1364. //
  1365. // Notes: This is dependent on our DS naming conventions
  1366. //
  1367. //
  1368. //--------------------------------------------------------------------------
  1369. KERBERR
  1370. KerbBuildEmailName(
  1371. IN PUNICODE_STRING DomainName,
  1372. IN PUNICODE_STRING ServiceName,
  1373. OUT PUNICODE_STRING EmailName
  1374. )
  1375. {
  1376. PUCHAR Where;
  1377. ULONG ulLength;
  1378. EmailName->Buffer = NULL;
  1379. ulLength = (ULONG)DomainName->Length +
  1380. (ULONG)ServiceName->Length +
  1381. sizeof(WCHAR);
  1382. if (ulLength > KERB_MAX_UNICODE_STRING)
  1383. {
  1384. return(KRB_ERR_GENERIC); // required size too large for Length
  1385. }
  1386. EmailName->Length = (USHORT)ulLength;
  1387. EmailName->MaximumLength =
  1388. EmailName->Length + sizeof(WCHAR);
  1389. EmailName->Buffer = (LPWSTR) MIDL_user_allocate(
  1390. EmailName->MaximumLength
  1391. );
  1392. if (EmailName->Buffer == NULL)
  1393. {
  1394. return(KRB_ERR_GENERIC);
  1395. }
  1396. Where = (PUCHAR) EmailName->Buffer;
  1397. RtlCopyMemory(
  1398. EmailName->Buffer,
  1399. ServiceName->Buffer,
  1400. ServiceName->Length
  1401. );
  1402. Where += ServiceName->Length;
  1403. *(LPWSTR) Where = L'@';
  1404. Where += sizeof(WCHAR);
  1405. RtlCopyMemory(
  1406. Where,
  1407. DomainName->Buffer,
  1408. DomainName->Length
  1409. );
  1410. Where += DomainName->Length;
  1411. EmailName->Length = (USHORT)(Where - (PUCHAR) EmailName->Buffer);
  1412. *(LPWSTR) Where = L'\0';
  1413. return(KDC_ERR_NONE);
  1414. }
  1415. //+-------------------------------------------------------------------------
  1416. //
  1417. // Function: KerbBuildUnicodeSpn
  1418. //
  1419. // Synopsis: Builds a 2 part SPN
  1420. //
  1421. // Effects:
  1422. //
  1423. // Arguments: DomainName - Domain name of service
  1424. // ServiceName - Name of service
  1425. // Spn - Receives full service name
  1426. //
  1427. // Requires:
  1428. //
  1429. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  1430. //
  1431. // Notes: This is dependent on our DS naming conventions
  1432. //
  1433. //
  1434. //--------------------------------------------------------------------------
  1435. KERBERR
  1436. KerbBuildUnicodeSpn(
  1437. IN PUNICODE_STRING DomainName,
  1438. IN PUNICODE_STRING ServiceName,
  1439. OUT PUNICODE_STRING UnicodeSpn
  1440. )
  1441. {
  1442. PWSTR Spn, tmp;
  1443. ULONG BuffSize;
  1444. BOOL fAssigned = FALSE;
  1445. BuffSize = DomainName->MaximumLength +
  1446. ServiceName->MaximumLength +
  1447. (sizeof(WCHAR) * 2);
  1448. Spn = (PWSTR) MIDL_user_allocate(BuffSize);
  1449. if (NULL == Spn)
  1450. {
  1451. return KRB_ERR_GENERIC;
  1452. }
  1453. tmp = Spn;
  1454. RtlCopyMemory(
  1455. Spn,
  1456. ServiceName->Buffer,
  1457. ServiceName->Length
  1458. );
  1459. tmp += (ServiceName->Length / sizeof(WCHAR));
  1460. *tmp = L'/';
  1461. RtlCopyMemory(
  1462. ++tmp,
  1463. DomainName->Buffer,
  1464. DomainName->Length
  1465. );
  1466. tmp += (DomainName->Length / sizeof(WCHAR));
  1467. *tmp = L'\0';
  1468. fAssigned = SafeRtlInitUnicodeString(
  1469. UnicodeSpn,
  1470. Spn
  1471. );
  1472. if (fAssigned == FALSE)
  1473. {
  1474. return(KRB_ERR_GENERIC); // string length would not fit into USHORT
  1475. }
  1476. return KDC_ERR_NONE;
  1477. }
  1478. //+-------------------------------------------------------------------------
  1479. //
  1480. // Function: KerbBuildFullServiceKdcName
  1481. //
  1482. // Synopsis: Combines a service name and domain name to make a full
  1483. // service name. If the name type is MS_PRINCIPAL they are
  1484. // combined into one portion of the name, otherise left in
  1485. // two portions
  1486. //
  1487. // Effects:
  1488. //
  1489. // Arguments: DomainName - Domain name of service
  1490. // ServiceName - Name of service
  1491. // NameType - Type of name to produce
  1492. // FullServiceName - Receives full service name
  1493. //
  1494. // Requires:
  1495. //
  1496. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  1497. //
  1498. // Notes: This is dependent on our DS naming conventions
  1499. //
  1500. //
  1501. //--------------------------------------------------------------------------
  1502. KERBERR
  1503. KerbBuildFullServiceKdcName(
  1504. IN PUNICODE_STRING DomainName,
  1505. IN PUNICODE_STRING ServiceName,
  1506. IN ULONG NameType,
  1507. OUT PKERB_INTERNAL_NAME * FullServiceName
  1508. )
  1509. {
  1510. return(KerbBuildFullServiceKdcNameWithSid(
  1511. DomainName,
  1512. ServiceName,
  1513. NULL,
  1514. NameType,
  1515. FullServiceName
  1516. ));
  1517. }
  1518. //+-------------------------------------------------------------------------
  1519. //
  1520. // Function: KerbBuildKpasswdName
  1521. //
  1522. // Synopsis: Builds the name of the kpasswd service
  1523. //
  1524. // Effects:
  1525. //
  1526. // Arguments:
  1527. //
  1528. // Requires:
  1529. //
  1530. // Returns:
  1531. //
  1532. // Notes:
  1533. //
  1534. //
  1535. //--------------------------------------------------------------------------
  1536. NTSTATUS
  1537. KerbBuildKpasswdName(
  1538. OUT PKERB_INTERNAL_NAME * KpasswdName
  1539. )
  1540. {
  1541. UNICODE_STRING KpasswdServiceNames[2];
  1542. //
  1543. // Build the service name for the ticket
  1544. //
  1545. (void)RtlInitUnicodeString(
  1546. &KpasswdServiceNames[0],
  1547. KERB_KPASSWD_FIRST_NAME
  1548. );
  1549. (void)RtlInitUnicodeString(
  1550. &KpasswdServiceNames[1],
  1551. KERB_KPASSWD_SECOND_NAME
  1552. );
  1553. if (!KERB_SUCCESS(KerbBuildFullServiceKdcName(
  1554. &KpasswdServiceNames[1],
  1555. &KpasswdServiceNames[0],
  1556. KRB_NT_SRV_INST,
  1557. KpasswdName
  1558. )))
  1559. {
  1560. return(STATUS_INSUFFICIENT_RESOURCES);
  1561. }
  1562. return(STATUS_SUCCESS);
  1563. }
  1564. //+-------------------------------------------------------------------------
  1565. //
  1566. // Function: KerbBuildFullServiceKdcNameWithSid
  1567. //
  1568. // Synopsis: Combines a service name and domain name to make a full
  1569. // service name. If the name type is MS_PRINCIPAL they are
  1570. // combined into one portion of the name, otherise left in
  1571. // two portions. If a sid is presenet, it is tacked on as
  1572. // the last segment of the name
  1573. //
  1574. // Effects:
  1575. //
  1576. // Arguments: DomainName - Domain name of service
  1577. // ServiceName - Name of service
  1578. // Sid - Optionally contains the sid to use
  1579. // NameType - Type of name to produce
  1580. // FullServiceName - Receives full service name
  1581. //
  1582. // Requires:
  1583. //
  1584. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  1585. //
  1586. // Notes: This is dependent on our DS naming conventions
  1587. //
  1588. //
  1589. //--------------------------------------------------------------------------
  1590. KERBERR
  1591. KerbBuildFullServiceKdcNameWithSid(
  1592. IN PUNICODE_STRING DomainName,
  1593. IN PUNICODE_STRING ServiceName,
  1594. IN OPTIONAL PSID Sid,
  1595. IN ULONG NameType,
  1596. OUT PKERB_INTERNAL_NAME * FullServiceName
  1597. )
  1598. {
  1599. PKERB_INTERNAL_NAME FinalName = NULL;
  1600. PUCHAR Where;
  1601. ULONG NameParts;
  1602. ULONG NameLength = 0;
  1603. ULONG ulLength = 0;
  1604. WCHAR SidBuffer[256];
  1605. UNICODE_STRING SidString;
  1606. KERBERR KerbErr = KRB_ERR_GENERIC;
  1607. SidString.Length = 0;
  1608. SidString.MaximumLength = sizeof(SidBuffer);
  1609. SidString.Buffer = SidBuffer;
  1610. if ((NameType == KRB_NT_MS_PRINCIPAL) ||
  1611. (NameType == KRB_NT_MS_PRINCIPAL_AND_ID))
  1612. {
  1613. NameParts = 1;
  1614. NameLength = DomainName->Length + ServiceName->Length + 2*sizeof(WCHAR);
  1615. }
  1616. else if ((NameType == KRB_NT_PRINCIPAL) ||
  1617. (NameType == KRB_NT_PRINCIPAL_AND_ID) ||
  1618. (NameType == KRB_NT_ENTERPRISE_PRINCIPAL) ||
  1619. (NameType == KRB_NT_ENT_PRINCIPAL_AND_ID))
  1620. {
  1621. NameParts = 1;
  1622. NameLength = ServiceName->Length + sizeof(WCHAR);
  1623. }
  1624. else
  1625. {
  1626. NameParts = 2;
  1627. NameLength = DomainName->Length + ServiceName->Length + 2*sizeof(WCHAR);
  1628. }
  1629. //
  1630. // If a SID is present, add another name part
  1631. //
  1632. if (ARGUMENT_PRESENT(Sid))
  1633. {
  1634. NTSTATUS Status;
  1635. Status = KerbConvertSidToString(
  1636. Sid,
  1637. &SidString,
  1638. FALSE // don't allocate
  1639. );
  1640. if (!NT_SUCCESS(Status))
  1641. {
  1642. return(KRB_ERR_GENERIC);
  1643. }
  1644. NameParts++;
  1645. NameLength += SidString.Length + sizeof(WCHAR);
  1646. }
  1647. *FullServiceName = NULL;
  1648. FinalName = (PKERB_INTERNAL_NAME) MIDL_user_allocate(KERB_INTERNAL_NAME_SIZE(NameParts) + NameLength);
  1649. if (FinalName == NULL)
  1650. {
  1651. return(KRB_ERR_GENERIC);
  1652. }
  1653. RtlZeroMemory(
  1654. FinalName,
  1655. KERB_INTERNAL_NAME_SIZE(NameParts) + NameLength
  1656. );
  1657. Where = (PUCHAR) FinalName + KERB_INTERNAL_NAME_SIZE(NameParts);
  1658. FinalName->NameType = (USHORT) NameType;
  1659. FinalName->NameCount = (USHORT) NameParts;
  1660. if ((NameType == KRB_NT_MS_PRINCIPAL) ||
  1661. (NameType == KRB_NT_MS_PRINCIPAL_AND_ID))
  1662. {
  1663. //
  1664. // If the domain name does not have an initial '\', reserve space for one
  1665. //
  1666. FinalName->Names[0].Buffer = (LPWSTR) Where;
  1667. // This is dependent on our naming conventions.
  1668. //
  1669. // The full service name is the '\' domain name ':' service name.
  1670. //
  1671. ulLength = (ULONG)DomainName->Length +
  1672. (ULONG)ServiceName->Length +
  1673. sizeof(WCHAR);
  1674. if (ulLength > KERB_MAX_UNICODE_STRING)
  1675. {
  1676. KerbErr = KRB_ERR_GENERIC; // required size too large for Length
  1677. goto Cleanup;
  1678. }
  1679. FinalName->Names[0].Length = (USHORT)ulLength;
  1680. FinalName->Names[0].MaximumLength =
  1681. FinalName->Names[0].Length + sizeof(WCHAR);
  1682. RtlCopyMemory(
  1683. FinalName->Names[0].Buffer,
  1684. DomainName->Buffer,
  1685. DomainName->Length
  1686. );
  1687. Where += DomainName->Length;
  1688. if ((DomainName->Length !=0) && (ServiceName->Length != 0))
  1689. {
  1690. *(LPWSTR) Where = L'\\';
  1691. Where += sizeof(WCHAR);
  1692. }
  1693. RtlCopyMemory(
  1694. Where,
  1695. ServiceName->Buffer,
  1696. ServiceName->Length
  1697. );
  1698. Where += ServiceName->Length;
  1699. ulLength = (ULONG)(Where - (PUCHAR) FinalName->Names[0].Buffer);
  1700. if (ulLength > KERB_MAX_UNICODE_STRING)
  1701. {
  1702. KerbErr = KRB_ERR_GENERIC; // required size too large for Length
  1703. goto Cleanup;
  1704. }
  1705. FinalName->Names[0].Length = (USHORT)ulLength;
  1706. *(LPWSTR) Where = L'\0';
  1707. }
  1708. else if ((NameType == KRB_NT_PRINCIPAL) ||
  1709. (NameType == KRB_NT_PRINCIPAL_AND_ID) ||
  1710. (NameType == KRB_NT_ENTERPRISE_PRINCIPAL)||
  1711. (NameType == KRB_NT_ENT_PRINCIPAL_AND_ID))
  1712. {
  1713. //
  1714. // Principals have no domain name
  1715. //
  1716. FinalName->Names[0].Length = ServiceName->Length;
  1717. FinalName->Names[0].MaximumLength = ServiceName->Length + sizeof(WCHAR);
  1718. FinalName->Names[0].Buffer = (LPWSTR) Where;
  1719. RtlCopyMemory(
  1720. Where,
  1721. ServiceName->Buffer,
  1722. ServiceName->Length
  1723. );
  1724. Where += ServiceName->Length;
  1725. *((LPWSTR) Where) = L'\0';
  1726. }
  1727. else
  1728. {
  1729. FinalName->Names[0].Length = ServiceName->Length;
  1730. FinalName->Names[0].MaximumLength = ServiceName->Length + sizeof(WCHAR);
  1731. FinalName->Names[0].Buffer = (LPWSTR) Where;
  1732. RtlCopyMemory(
  1733. Where,
  1734. ServiceName->Buffer,
  1735. ServiceName->Length
  1736. );
  1737. Where += ServiceName->Length;
  1738. *((LPWSTR) Where) = L'\0';
  1739. Where += sizeof(WCHAR);
  1740. FinalName->Names[1].Length = DomainName->Length;
  1741. FinalName->Names[1].MaximumLength = DomainName->Length + sizeof(WCHAR);
  1742. FinalName->Names[1].Buffer = (LPWSTR) Where;
  1743. RtlCopyMemory(
  1744. Where,
  1745. DomainName->Buffer,
  1746. DomainName->Length
  1747. );
  1748. Where += DomainName->Length;
  1749. *((LPWSTR) Where) = L'\0';
  1750. Where += sizeof(WCHAR);
  1751. }
  1752. //
  1753. // Append the string, if present
  1754. //
  1755. if (ARGUMENT_PRESENT(Sid))
  1756. {
  1757. FinalName->Names[NameParts-1].Length = SidString.Length;
  1758. FinalName->Names[NameParts-1].MaximumLength = SidString.Length + sizeof(WCHAR);
  1759. FinalName->Names[NameParts-1].Buffer = (LPWSTR) Where;
  1760. RtlCopyMemory(
  1761. Where,
  1762. SidString.Buffer,
  1763. SidString.Length
  1764. );
  1765. Where += SidString.Length;
  1766. *((LPWSTR) Where) = L'\0';
  1767. }
  1768. *FullServiceName = FinalName;
  1769. FinalName = NULL;
  1770. KerbErr = KDC_ERR_NONE;
  1771. Cleanup:
  1772. if (FinalName)
  1773. {
  1774. MIDL_user_free(FinalName);
  1775. }
  1776. return(KerbErr);
  1777. }
  1778. //+-------------------------------------------------------------------------
  1779. //
  1780. // Function: KerbExtractSidFromKdcName
  1781. //
  1782. // Synopsis: Extracts the sid portion from a KDC name with a sid. This
  1783. // routine also decrements the name count so that future
  1784. // users of the name don't see the sid.
  1785. //
  1786. // Effects:
  1787. //
  1788. // Arguments:
  1789. //
  1790. // Requires:
  1791. //
  1792. // Returns:
  1793. //
  1794. // Notes:
  1795. //
  1796. //
  1797. //--------------------------------------------------------------------------
  1798. KERBERR
  1799. KerbExtractSidFromKdcName(
  1800. IN OUT PKERB_INTERNAL_NAME Name,
  1801. OUT PSID * Sid
  1802. )
  1803. {
  1804. NTSTATUS Status;
  1805. DsysAssert(Sid);
  1806. //
  1807. // The sid is in the last portion of the name.
  1808. //
  1809. Status = KerbConvertStringToSid(
  1810. &Name->Names[Name->NameCount-1],
  1811. Sid
  1812. );
  1813. if (NT_SUCCESS(Status))
  1814. {
  1815. Name->NameCount--;
  1816. }
  1817. else
  1818. {
  1819. //
  1820. // If the name wasn't a sid, return success. If it was another
  1821. // problem, return an error
  1822. //
  1823. if (Status != STATUS_INVALID_PARAMETER)
  1824. {
  1825. return(KRB_ERR_GENERIC);
  1826. }
  1827. }
  1828. return(KDC_ERR_NONE);
  1829. }
  1830. //+-------------------------------------------------------------------------
  1831. //
  1832. // Function: KerbDuplicateStringEx
  1833. //
  1834. // Synopsis: Duplicates a UNICODE_STRING. If the source string buffer is
  1835. // NULL the destionation will be too. The EX function doesn't
  1836. // automatically NULL terminate your buffer...
  1837. //
  1838. // Effects: allocates memory with LsaFunctions.AllocateLsaHeap
  1839. //
  1840. // Arguments: DestinationString - Receives a copy of the source string
  1841. // SourceString - String to copy
  1842. //
  1843. // Requires:
  1844. //
  1845. // Returns: STATUS_SUCCESS - the copy succeeded
  1846. // STATUS_INSUFFICIENT_RESOURCES - the call to allocate
  1847. // memory failed.
  1848. //
  1849. // Notes:
  1850. //
  1851. //
  1852. //--------------------------------------------------------------------------
  1853. NTSTATUS
  1854. KerbDuplicateStringEx(
  1855. OUT PUNICODE_STRING DestinationString,
  1856. IN OPTIONAL PUNICODE_STRING SourceString,
  1857. IN BOOLEAN NullTerminate
  1858. )
  1859. {
  1860. ULONG Buffsize = SourceString->Length + (NullTerminate ? sizeof(WCHAR) : 0);
  1861. if ((SourceString == NULL) || (SourceString->Buffer == NULL))
  1862. {
  1863. DestinationString->Buffer = NULL;
  1864. DestinationString->Length = DestinationString->MaximumLength = 0;
  1865. return(STATUS_SUCCESS);
  1866. }
  1867. //
  1868. // Detect potential B.0.s here on USHORT
  1869. //
  1870. if (SourceString->Length > KERB_MAX_UNICODE_STRING )
  1871. {
  1872. // DsysAssert(FALSE);
  1873. return (STATUS_NAME_TOO_LONG);
  1874. }
  1875. DestinationString->Buffer = (LPWSTR) MIDL_user_allocate(Buffsize);
  1876. if (DestinationString->Buffer == NULL)
  1877. {
  1878. return(STATUS_INSUFFICIENT_RESOURCES);
  1879. }
  1880. DestinationString->Length = SourceString->Length;
  1881. DestinationString->MaximumLength = (USHORT) Buffsize;
  1882. RtlCopyMemory(
  1883. DestinationString->Buffer,
  1884. SourceString->Buffer,
  1885. SourceString->Length
  1886. );
  1887. if (NullTerminate)
  1888. {
  1889. DestinationString->Buffer[SourceString->Length/sizeof(WCHAR)] = L'\0';
  1890. }
  1891. return(STATUS_SUCCESS);
  1892. }
  1893. //+-------------------------------------------------------------------------
  1894. //
  1895. // Function: KerbDuplicateString
  1896. //
  1897. // Synopsis: Duplicates a UNICODE_STRING. If the source string buffer is
  1898. // NULL the destionation will be too.
  1899. //
  1900. // Effects: allocates memory with LsaFunctions.AllocateLsaHeap
  1901. //
  1902. // Arguments: DestinationString - Receives a copy of the source string
  1903. // SourceString - String to copy
  1904. //
  1905. // Requires:
  1906. //
  1907. // Returns: STATUS_SUCCESS - the copy succeeded
  1908. // STATUS_INSUFFICIENT_RESOURCES - the call to allocate
  1909. // memory failed.
  1910. //
  1911. // Notes:
  1912. //
  1913. //
  1914. //--------------------------------------------------------------------------
  1915. NTSTATUS
  1916. KerbDuplicateString(
  1917. OUT PUNICODE_STRING DestinationString,
  1918. IN OPTIONAL PUNICODE_STRING SourceString
  1919. )
  1920. {
  1921. return(KerbDuplicateStringEx(
  1922. DestinationString,
  1923. SourceString,
  1924. TRUE
  1925. ));
  1926. }
  1927. //+-------------------------------------------------------------------------
  1928. //
  1929. // Function: KerbBuildNullTerminatedString
  1930. //
  1931. // Synopsis: Converts a UNICODE_STRING to a NULL-termianted string
  1932. //
  1933. // Effects: allocates return with MIDL_user_allocate
  1934. //
  1935. // Arguments: String - string to null terminate.
  1936. //
  1937. // Requires:
  1938. //
  1939. // Returns: NULL on error, a pointer on success
  1940. //
  1941. // Notes: an input string with a NULL buffer pointe results in a
  1942. // return string consisting of just "\0"
  1943. //
  1944. //
  1945. //--------------------------------------------------------------------------
  1946. LPWSTR
  1947. KerbBuildNullTerminatedString(
  1948. IN PUNICODE_STRING String
  1949. )
  1950. {
  1951. LPWSTR ReturnString;
  1952. ReturnString = (LPWSTR) MIDL_user_allocate(String->Length + sizeof(WCHAR));
  1953. if (ReturnString == NULL)
  1954. {
  1955. return(NULL);
  1956. }
  1957. if (String->Buffer != NULL)
  1958. {
  1959. RtlCopyMemory(
  1960. ReturnString,
  1961. String->Buffer,
  1962. String->Length
  1963. );
  1964. }
  1965. ReturnString[String->Length/sizeof(WCHAR)] = L'\0';
  1966. return(ReturnString);
  1967. }
  1968. //+-------------------------------------------------------------------------
  1969. //
  1970. // Function: KerbFreeString
  1971. //
  1972. // Synopsis: Frees a string allocated by KerbDuplicateString
  1973. //
  1974. // Effects:
  1975. //
  1976. // Arguments: String - Optionally points to a UNICODE_STRING
  1977. //
  1978. // Requires:
  1979. //
  1980. // Returns:
  1981. //
  1982. // Notes:
  1983. //
  1984. //
  1985. //--------------------------------------------------------------------------
  1986. VOID
  1987. KerbFreeString(
  1988. IN OPTIONAL PUNICODE_STRING String
  1989. )
  1990. {
  1991. if (ARGUMENT_PRESENT(String) && String->Buffer != NULL)
  1992. {
  1993. MIDL_user_free(String->Buffer);
  1994. ZeroMemory(String, sizeof(UNICODE_STRING));
  1995. }
  1996. }
  1997. //+-------------------------------------------------------------------------
  1998. //
  1999. // Function: KerbFreeRealm
  2000. //
  2001. // Synopsis: Frees a realm allcoated with KerbConvertXXXToRealm
  2002. //
  2003. // Effects: null out the realm.
  2004. //
  2005. // Arguments: Realm - Realm to free
  2006. //
  2007. // Requires:
  2008. //
  2009. // Returns:
  2010. //
  2011. // Notes:
  2012. //
  2013. //
  2014. //--------------------------------------------------------------------------
  2015. VOID
  2016. KerbFreeRealm(
  2017. IN PKERB_REALM Realm
  2018. )
  2019. {
  2020. if (*Realm != NULL)
  2021. {
  2022. MIDL_user_free(*Realm);
  2023. *Realm = NULL;
  2024. }
  2025. }
  2026. //+-------------------------------------------------------------------------
  2027. //
  2028. // Function: KerbCompareUnicodeRealmToKerbRealm
  2029. //
  2030. // Synopsis: Compares a kerb_realm to a unicode kerb realm
  2031. //
  2032. // Effects:
  2033. //
  2034. // Arguments:
  2035. //
  2036. // Requires:
  2037. //
  2038. // Returns:
  2039. //
  2040. // Notes:
  2041. //
  2042. //
  2043. //--------------------------------------------------------------------------
  2044. KERBERR
  2045. KerbCompareUnicodeRealmToKerbRealm(
  2046. IN PKERB_REALM KerbRealm,
  2047. IN PUNICODE_STRING UnicodeRealm,
  2048. OUT PBOOLEAN Result
  2049. )
  2050. {
  2051. KERB_REALM TempName = NULL;
  2052. if (!KERB_SUCCESS(KerbConvertUnicodeStringToRealm(
  2053. &TempName,
  2054. UnicodeRealm
  2055. )))
  2056. {
  2057. return(KRB_ERR_GENERIC);
  2058. }
  2059. *Result = KerbCompareRealmNames(&TempName, KerbRealm);
  2060. KerbFreeRealm( &TempName );
  2061. return(KDC_ERR_NONE);
  2062. }
  2063. //+-------------------------------------------------------------------------
  2064. //
  2065. // Function: KerbFreePrincipalName
  2066. //
  2067. // Synopsis: Frees a principal name allocated with KerbConvertxxxToPrincipalName
  2068. //
  2069. // Effects: zeros out principal name so it won't be freed again
  2070. //
  2071. // Arguments: Name - The name to free
  2072. //
  2073. // Requires:
  2074. //
  2075. // Returns:
  2076. //
  2077. // Notes:
  2078. //
  2079. //
  2080. //--------------------------------------------------------------------------
  2081. VOID
  2082. KerbFreePrincipalName(
  2083. IN PKERB_PRINCIPAL_NAME Name
  2084. )
  2085. {
  2086. PKERB_PRINCIPAL_NAME_ELEM Elem,NextElem;
  2087. Elem = Name->name_string;
  2088. while (Elem != NULL)
  2089. {
  2090. if (Elem->value != NULL)
  2091. {
  2092. MIDL_user_free(Elem->value);
  2093. }
  2094. NextElem = Elem->next;
  2095. MIDL_user_free(Elem);
  2096. Elem = NextElem;
  2097. }
  2098. Name->name_string = NULL;
  2099. }
  2100. //+-------------------------------------------------------------------------
  2101. //
  2102. // Function: KerbConvertUnicodeStringToRealm
  2103. //
  2104. // Synopsis: Converts a unicode-string form of a domain name to a
  2105. // KERB_REALM structure.
  2106. //
  2107. // Effects:
  2108. //
  2109. // Arguments: Realm - the realm
  2110. // String - The string to convert
  2111. //
  2112. // Requires:
  2113. //
  2114. // Returns: none
  2115. //
  2116. // Notes:
  2117. //
  2118. //
  2119. //--------------------------------------------------------------------------
  2120. KERBERR
  2121. KerbConvertUnicodeStringToRealm(
  2122. OUT PKERB_REALM Realm,
  2123. IN PUNICODE_STRING String
  2124. )
  2125. {
  2126. KERBERR KerbErr;
  2127. STRING TempString = {0};
  2128. *Realm = NULL;
  2129. KerbErr = KerbUnicodeStringToKerbString(
  2130. &TempString,
  2131. String
  2132. );
  2133. if (!KERB_SUCCESS(KerbErr))
  2134. {
  2135. return(KerbErr);
  2136. }
  2137. *Realm = TempString.Buffer;
  2138. return(KDC_ERR_NONE);
  2139. }
  2140. //+-------------------------------------------------------------------------
  2141. //
  2142. // Function: KerbConvertRealmToUnicodeString
  2143. //
  2144. // Synopsis: Converts a KERB_REALM structure to a unicode-string form
  2145. // of a domain name.
  2146. //
  2147. // Effects:
  2148. //
  2149. // Arguments: String - the unicode realm name
  2150. // Realm - the realm to convert
  2151. //
  2152. // Requires:
  2153. //
  2154. // Returns: none
  2155. //
  2156. // Notes:
  2157. //
  2158. //
  2159. //--------------------------------------------------------------------------
  2160. KERBERR
  2161. KerbConvertRealmToUnicodeString(
  2162. OUT PUNICODE_STRING String,
  2163. IN PKERB_REALM Realm
  2164. )
  2165. {
  2166. KERBERR Status;
  2167. STRING TempString;
  2168. BOOL fAssigned = FALSE;
  2169. fAssigned = SafeRtlInitString(
  2170. &TempString,
  2171. *Realm
  2172. );
  2173. if (fAssigned == FALSE)
  2174. {
  2175. return(KRB_ERR_GENERIC);
  2176. }
  2177. Status = KerbStringToUnicodeString(
  2178. String,
  2179. &TempString
  2180. );
  2181. return(Status);
  2182. }
  2183. //+-------------------------------------------------------------------------
  2184. //
  2185. // Function: KerbDuplicateRealm
  2186. //
  2187. // Synopsis: Duplciates a realm name
  2188. //
  2189. // Effects:
  2190. //
  2191. // Arguments: Realm - the realm
  2192. // SourceRealm - The realm to duplicate
  2193. //
  2194. // Requires:
  2195. //
  2196. // Returns: none
  2197. //
  2198. // Notes:
  2199. //
  2200. //
  2201. //--------------------------------------------------------------------------
  2202. KERBERR
  2203. KerbDuplicateRealm(
  2204. OUT PKERB_REALM Realm,
  2205. IN KERB_REALM SourceRealm
  2206. )
  2207. {
  2208. ULONG RealmLength;
  2209. if (ARGUMENT_PRESENT(SourceRealm))
  2210. {
  2211. RealmLength = lstrlenA(SourceRealm);
  2212. *Realm = (PCHAR) MIDL_user_allocate(RealmLength + sizeof(CHAR));
  2213. if (*Realm == NULL)
  2214. {
  2215. return(KRB_ERR_GENERIC);
  2216. }
  2217. RtlCopyMemory(
  2218. *Realm,
  2219. SourceRealm,
  2220. RealmLength + sizeof(CHAR)
  2221. );
  2222. }
  2223. else
  2224. {
  2225. *Realm = NULL;
  2226. }
  2227. return(KDC_ERR_NONE);
  2228. }
  2229. //+-------------------------------------------------------------------------
  2230. //
  2231. // Function: KerbCompareStringToPrincipalName
  2232. //
  2233. // Synopsis: Compares a unicode string name to a principal name for
  2234. // equality
  2235. //
  2236. // Effects:
  2237. //
  2238. // Arguments: PrincipalName - kerberos principal name
  2239. // String - String name
  2240. //
  2241. // Requires:
  2242. //
  2243. // Returns: TRUE if one of the principal names matches the string name
  2244. //
  2245. // Notes:
  2246. //
  2247. //
  2248. //--------------------------------------------------------------------------
  2249. BOOLEAN
  2250. KerbCompareStringToPrincipalName(
  2251. IN PKERB_PRINCIPAL_NAME PrincipalName,
  2252. IN PUNICODE_STRING String
  2253. )
  2254. {
  2255. KERBERR Status;
  2256. BOOLEAN FoundMatch = FALSE;
  2257. UNICODE_STRING TempString = {0};
  2258. ULONG NameType;
  2259. Status = KerbConvertPrincipalNameToString(
  2260. &TempString,
  2261. &NameType,
  2262. PrincipalName
  2263. );
  2264. if (!KERB_SUCCESS(Status))
  2265. {
  2266. return(FALSE);
  2267. }
  2268. if (RtlEqualUnicodeString(
  2269. &TempString,
  2270. String,
  2271. TRUE // case insensitive
  2272. ))
  2273. {
  2274. FoundMatch = TRUE;
  2275. }
  2276. KerbFreeString(&TempString);
  2277. return(FoundMatch);
  2278. }
  2279. //+-------------------------------------------------------------------------
  2280. //
  2281. // Function: KerbConvertStringToPrincipalName
  2282. //
  2283. // Synopsis: converts a string to a principal name
  2284. //
  2285. // Effects: allocate memory
  2286. //
  2287. // Arguments: PrincipalName - receives the principal name
  2288. // String - the string name to convert
  2289. //
  2290. // Requires:
  2291. //
  2292. // Returns: KDC_ERR_NONE or STATUS_INSUFFICIENT_MEMORY
  2293. //
  2294. // Notes: principalname->name_value must be freed with MIDL_user_free and
  2295. // principalname->name_value->value must be freed with
  2296. // MIDL_user_Free.
  2297. //
  2298. //
  2299. //--------------------------------------------------------------------------
  2300. KERBERR
  2301. KerbConvertStringToPrincipalName(
  2302. OUT PKERB_PRINCIPAL_NAME PrincipalName,
  2303. IN PUNICODE_STRING String,
  2304. IN ULONG NameType
  2305. )
  2306. {
  2307. PKERB_PRINCIPAL_NAME_ELEM Elem;
  2308. STRING TempKerbString;
  2309. KERBERR Status = KDC_ERR_NONE;
  2310. UNICODE_STRING TempElemString;
  2311. UNICODE_STRING TempString;
  2312. ULONG Index;
  2313. ULONG ulLength;
  2314. RtlZeroMemory(
  2315. PrincipalName,
  2316. sizeof(KERB_PRINCIPAL_NAME)
  2317. );
  2318. PrincipalName->name_type = (int) NameType;
  2319. //
  2320. // MS principals are stuck all in one string
  2321. //
  2322. if (NameType == KRB_NT_MS_PRINCIPAL)
  2323. {
  2324. Status = KerbUnicodeStringToKerbString(
  2325. &TempKerbString,
  2326. String
  2327. );
  2328. if (!KERB_SUCCESS(Status))
  2329. {
  2330. goto Cleanup;
  2331. }
  2332. Elem = (PKERB_PRINCIPAL_NAME_ELEM) MIDL_user_allocate(sizeof(KERB_PRINCIPAL_NAME_ELEM));
  2333. if (Elem == NULL)
  2334. {
  2335. MIDL_user_free(TempKerbString.Buffer);
  2336. Status = KRB_ERR_GENERIC;
  2337. goto Cleanup;
  2338. }
  2339. Elem->value = TempKerbString.Buffer;
  2340. Elem->next = PrincipalName->name_string;
  2341. PrincipalName->name_string = Elem;
  2342. Status = KDC_ERR_NONE;
  2343. goto Cleanup;
  2344. }
  2345. else
  2346. {
  2347. //
  2348. // Go through the string. If we hit a '\\' separator, split
  2349. // the name there into another component.
  2350. //
  2351. TempString = *String;
  2352. Index = 0;
  2353. while (Index <= TempString.Length / sizeof(WCHAR))
  2354. {
  2355. if ((Index == TempString.Length/sizeof(WCHAR)) ||
  2356. (TempString.Buffer[Index] == L'\\') )
  2357. {
  2358. //
  2359. // Build the element string
  2360. //
  2361. ulLength = Index * sizeof(WCHAR);
  2362. if (ulLength > KERB_MAX_UNICODE_STRING)
  2363. {
  2364. Status = KRB_ERR_GENERIC; // length exceed USHORT range
  2365. goto Cleanup;
  2366. }
  2367. TempElemString.Buffer = TempString.Buffer;
  2368. TempElemString.MaximumLength = (USHORT) ulLength;
  2369. TempElemString.Length = TempElemString.MaximumLength;
  2370. Status = KerbUnicodeStringToKerbString(
  2371. &TempKerbString,
  2372. &TempElemString
  2373. );
  2374. if (!KERB_SUCCESS(Status))
  2375. {
  2376. goto Cleanup;
  2377. }
  2378. Elem = (PKERB_PRINCIPAL_NAME_ELEM) MIDL_user_allocate(sizeof(KERB_PRINCIPAL_NAME_ELEM));
  2379. if (Elem == NULL)
  2380. {
  2381. MIDL_user_free(TempKerbString.Buffer);
  2382. Status = KRB_ERR_GENERIC;
  2383. goto Cleanup;
  2384. }
  2385. Elem->value = TempKerbString.Buffer;
  2386. Elem->next = PrincipalName->name_string;
  2387. PrincipalName->name_string = Elem;
  2388. //
  2389. // Reset the string to be the remains of the name
  2390. //
  2391. if (Index != TempString.Length / sizeof(WCHAR))
  2392. {
  2393. ulLength = (Index+1) * sizeof(WCHAR);
  2394. if (ulLength > KERB_MAX_UNICODE_STRING)
  2395. {
  2396. Status = KRB_ERR_GENERIC; // length exceed USHORT range
  2397. goto Cleanup;
  2398. }
  2399. TempString.Buffer = TempString.Buffer + Index + 1;
  2400. TempString.Length = TempString.Length - (USHORT) ulLength;
  2401. TempString.MaximumLength = TempString.MaximumLength - (USHORT) ulLength;
  2402. Index = 0;
  2403. }
  2404. else
  2405. {
  2406. break;
  2407. }
  2408. }
  2409. else
  2410. {
  2411. Index++;
  2412. }
  2413. }
  2414. }
  2415. Cleanup:
  2416. if (!KERB_SUCCESS(Status))
  2417. {
  2418. KerbFreePrincipalName(PrincipalName);
  2419. }
  2420. return(Status);
  2421. }
  2422. //+-------------------------------------------------------------------------
  2423. //
  2424. // Function: KerbDuplicatePrincipalName
  2425. //
  2426. // Synopsis: Duplicates a principal name
  2427. //
  2428. // Effects: allocate memory
  2429. //
  2430. // Arguments: PrincipalName - receives the principal name
  2431. // SourcePrincipalName - the name to copy
  2432. //
  2433. // Requires:
  2434. //
  2435. // Returns: KDC_ERR_NONE or STATUS_INSUFFICIENT_MEMORY
  2436. //
  2437. // Notes: principalname->name_value must be freed with MIDL_user_free and
  2438. // principalname->name_value->value must be freed with
  2439. // MIDL_user_Free.
  2440. //
  2441. //
  2442. //--------------------------------------------------------------------------
  2443. KERBERR
  2444. KerbDuplicatePrincipalName(
  2445. OUT PKERB_PRINCIPAL_NAME PrincipalName,
  2446. IN PKERB_PRINCIPAL_NAME SourcePrincipalName
  2447. )
  2448. {
  2449. KERBERR Status = KDC_ERR_NONE;
  2450. ULONG NameLen;
  2451. PKERB_PRINCIPAL_NAME_ELEM SourceElem;
  2452. PKERB_PRINCIPAL_NAME_ELEM DestElem;
  2453. PKERB_PRINCIPAL_NAME_ELEM * NextElem;
  2454. // DSYSASSERT(PrincipalName);
  2455. // DSYSASSERT(SourcePrincipalName);
  2456. RtlZeroMemory(
  2457. PrincipalName,
  2458. sizeof(KERB_PRINCIPAL_NAME)
  2459. );
  2460. //
  2461. // Fill in correct name type
  2462. //
  2463. PrincipalName->name_type = SourcePrincipalName->name_type;
  2464. SourceElem = SourcePrincipalName->name_string;
  2465. NextElem = &PrincipalName->name_string;
  2466. *NextElem = NULL;
  2467. while (SourceElem != NULL)
  2468. {
  2469. DestElem = (PKERB_PRINCIPAL_NAME_ELEM) MIDL_user_allocate(sizeof(KERB_PRINCIPAL_NAME_ELEM));
  2470. if (DestElem == NULL)
  2471. {
  2472. Status = KRB_ERR_GENERIC;
  2473. goto Cleanup;
  2474. }
  2475. NameLen = lstrlenA(SourceElem->value);
  2476. DestElem->value = (PCHAR) MIDL_user_allocate(NameLen + sizeof(CHAR));
  2477. if (DestElem->value == NULL)
  2478. {
  2479. MIDL_user_free(DestElem);
  2480. Status = KRB_ERR_GENERIC;
  2481. goto Cleanup;
  2482. }
  2483. RtlCopyMemory(
  2484. DestElem->value,
  2485. SourceElem->value,
  2486. NameLen + sizeof(CHAR)
  2487. );
  2488. DestElem->next = NULL;
  2489. *NextElem = DestElem;
  2490. NextElem = &DestElem->next;
  2491. SourceElem = SourceElem->next;
  2492. }
  2493. Cleanup:
  2494. if (!KERB_SUCCESS(Status))
  2495. {
  2496. KerbFreePrincipalName(PrincipalName);
  2497. }
  2498. return(Status);
  2499. }
  2500. //+-------------------------------------------------------------------------
  2501. //
  2502. // Function: KerbConvertPrincipalNameToString
  2503. //
  2504. // Synopsis: Converts a KERB_PRINCIPAL_NAME to a unicode string
  2505. //
  2506. // Effects:
  2507. //
  2508. // Arguments:
  2509. //
  2510. // Requires:
  2511. //
  2512. // Returns:
  2513. //
  2514. // Notes:
  2515. //
  2516. //
  2517. //--------------------------------------------------------------------------
  2518. KERBERR
  2519. KerbConvertPrincipalNameToString(
  2520. OUT PUNICODE_STRING String,
  2521. OUT PULONG NameType,
  2522. IN PKERB_PRINCIPAL_NAME PrincipalName
  2523. )
  2524. {
  2525. KERBERR KerbErr;
  2526. STRING TempAnsiString;
  2527. ULONG StringLength = 0;
  2528. ULONG NameParts = 0;
  2529. ULONG Index;
  2530. PCHAR Where;
  2531. PKERB_PRINCIPAL_NAME_ELEM NameElements[MAX_NAME_ELEMENTS+1];
  2532. *NameType = (ULONG) PrincipalName->name_type;
  2533. NameElements[NameParts] = PrincipalName->name_string;
  2534. while (NameElements[NameParts] != NULL)
  2535. {
  2536. //
  2537. // add in a separator plus the length of the element
  2538. //
  2539. StringLength += lstrlenA(NameElements[NameParts]->value) + 1;
  2540. NameElements[NameParts+1] = NameElements[NameParts]->next;
  2541. NameParts++;
  2542. if (NameParts >= MAX_NAME_ELEMENTS)
  2543. {
  2544. D_DebugLog((DEB_ERROR,"Too many name parts: %d\n",NameParts));
  2545. return(KRB_ERR_GENERIC);
  2546. }
  2547. }
  2548. //
  2549. // Make sure there is at least one name part
  2550. //
  2551. if (NameParts == 0)
  2552. {
  2553. return(KRB_ERR_GENERIC);
  2554. }
  2555. //
  2556. // Test for overflow on USHORT lengths
  2557. //
  2558. if ( (StringLength - sizeof(CHAR)) > KERB_MAX_STRING )
  2559. {
  2560. return (KRB_ERR_GENERIC);
  2561. }
  2562. //
  2563. // Now build the name, backwards to front, with '\\' separators
  2564. //
  2565. TempAnsiString.Length = (USHORT) StringLength - sizeof(CHAR);
  2566. TempAnsiString.MaximumLength = (USHORT) StringLength;
  2567. SafeAllocaAllocate( TempAnsiString.Buffer, StringLength );
  2568. if (TempAnsiString.Buffer == NULL)
  2569. {
  2570. return(KRB_ERR_GENERIC);
  2571. }
  2572. Where = TempAnsiString.Buffer;
  2573. for (Index = 0; Index < NameParts; Index++ )
  2574. {
  2575. ULONG NameLength = lstrlenA(NameElements[Index]->value);
  2576. RtlCopyMemory(
  2577. Where,
  2578. NameElements[Index]->value,
  2579. NameLength
  2580. );
  2581. Where += NameLength;
  2582. //
  2583. // Add either a separating '\' or a trailing '\0'
  2584. //
  2585. if (Index != NameParts - 1)
  2586. {
  2587. *Where = '/';
  2588. }
  2589. else
  2590. {
  2591. *Where = '\0';
  2592. }
  2593. Where++;
  2594. }
  2595. DsysAssert(Where - TempAnsiString.Buffer == TempAnsiString.MaximumLength);
  2596. KerbErr = KerbStringToUnicodeString(
  2597. String,
  2598. &TempAnsiString
  2599. );
  2600. SafeAllocaFree( TempAnsiString.Buffer );
  2601. return(KerbErr);
  2602. }
  2603. //+-------------------------------------------------------------------------
  2604. //
  2605. // Function: KerbConvertPrincipalNameToFullServiceString
  2606. //
  2607. // Synopsis: Converts a KERB_PRINCIPAL_NAME to a unicode string with
  2608. // a realm name
  2609. //
  2610. // Effects:
  2611. //
  2612. // Arguments:
  2613. //
  2614. // Requires:
  2615. //
  2616. // Returns:
  2617. //
  2618. // Notes:
  2619. //
  2620. //
  2621. //--------------------------------------------------------------------------
  2622. KERBERR
  2623. KerbConvertPrincipalNameToFullServiceString(
  2624. OUT PUNICODE_STRING String,
  2625. IN PKERB_PRINCIPAL_NAME PrincipalName,
  2626. IN KERB_REALM RealmName
  2627. )
  2628. {
  2629. KERBERR KerbErr;
  2630. STRING TempAnsiString;
  2631. ULONG StringLength = 0;
  2632. ULONG NameParts = 0;
  2633. ULONG NameLength;
  2634. ULONG Index;
  2635. PCHAR Where;
  2636. PKERB_PRINCIPAL_NAME_ELEM NameElements[MAX_NAME_ELEMENTS+1];
  2637. NameElements[NameParts] = PrincipalName->name_string;
  2638. while (NameElements[NameParts] != NULL)
  2639. {
  2640. //
  2641. // add in a separator plus the length of the element
  2642. //
  2643. StringLength += lstrlenA(NameElements[NameParts]->value) + 1;
  2644. NameElements[NameParts+1] = NameElements[NameParts]->next;
  2645. NameParts++;
  2646. if (NameParts >= MAX_NAME_ELEMENTS)
  2647. {
  2648. D_DebugLog((DEB_ERROR,"Too many name parts: %d\n",NameParts));
  2649. return(KRB_ERR_GENERIC);
  2650. }
  2651. }
  2652. //
  2653. // Make sure there is at least one name part
  2654. //
  2655. if (NameParts == 0)
  2656. {
  2657. return(KRB_ERR_GENERIC);
  2658. }
  2659. //
  2660. // Add in space for the "@" and the realm
  2661. //
  2662. StringLength += lstrlenA(RealmName) + 1;
  2663. //
  2664. // Test for overflow on USHORT lengths
  2665. //
  2666. if ( (StringLength - sizeof(CHAR)) > KERB_MAX_STRING )
  2667. {
  2668. return (KRB_ERR_GENERIC);
  2669. }
  2670. //
  2671. // Now build the name, backwards to front, with '\\' separators
  2672. //
  2673. TempAnsiString.Length = (USHORT) StringLength - sizeof(CHAR);
  2674. TempAnsiString.MaximumLength = (USHORT) StringLength;
  2675. SafeAllocaAllocate( TempAnsiString.Buffer, StringLength );
  2676. if (TempAnsiString.Buffer == NULL)
  2677. {
  2678. return(KRB_ERR_GENERIC);
  2679. }
  2680. Where = TempAnsiString.Buffer;
  2681. for (Index = 0; Index < NameParts; Index++ )
  2682. {
  2683. NameLength = lstrlenA(NameElements[Index]->value);
  2684. RtlCopyMemory(
  2685. Where,
  2686. NameElements[Index]->value,
  2687. NameLength
  2688. );
  2689. Where += NameLength;
  2690. //
  2691. // Add either a separating '\' or a trailing '\0'
  2692. //
  2693. if (Index != NameParts - 1)
  2694. {
  2695. *Where = '/';
  2696. }
  2697. else
  2698. {
  2699. *Where = '@';
  2700. }
  2701. Where++;
  2702. }
  2703. NameLength = lstrlenA(RealmName);
  2704. RtlCopyMemory(
  2705. Where,
  2706. RealmName,
  2707. NameLength
  2708. );
  2709. Where += NameLength;
  2710. //
  2711. // Add either a trailing '\0'
  2712. //
  2713. *Where = '\0';
  2714. Where++;
  2715. DsysAssert(Where - TempAnsiString.Buffer == TempAnsiString.MaximumLength);
  2716. KerbErr = KerbStringToUnicodeString(
  2717. String,
  2718. &TempAnsiString
  2719. );
  2720. SafeAllocaFree( TempAnsiString.Buffer );
  2721. return(KerbErr);
  2722. }
  2723. //+-------------------------------------------------------------------------
  2724. //
  2725. // Function: KerbBuildKeySalt
  2726. //
  2727. // Synopsis: Combines a service name and domain name to make a key salt.
  2728. // For machine account it is DOMAINNAMEhostmachinenamedomainname
  2729. // For users it is DOMAINNAMEusername
  2730. // For trusted domains it is DOMAINNAMEkrbtgtservicename
  2731. //
  2732. // Effects:
  2733. //
  2734. // Arguments: DomainName - Domain name of service
  2735. // Servicename - Name of service
  2736. // AccountType - Type of account, which changes the salt
  2737. // KeySalt - Receives the key salt
  2738. //
  2739. // Requires:
  2740. //
  2741. // Returns: KDC_ERR_NONE or KRB_ERR_GENERIC
  2742. //
  2743. // Notes: This is dependent on our DS naming conventions
  2744. //
  2745. //
  2746. //--------------------------------------------------------------------------
  2747. KERBERR
  2748. KerbBuildKeySalt(
  2749. IN PUNICODE_STRING DomainName,
  2750. IN PUNICODE_STRING ServiceName,
  2751. IN KERB_ACCOUNT_TYPE AccountType,
  2752. OUT PUNICODE_STRING KeySalt
  2753. )
  2754. {
  2755. PUCHAR Where;
  2756. ULONG FinalLength;
  2757. ULONG ulLength = 0;
  2758. USHORT DeadSpace = 0;
  2759. USHORT Index;
  2760. KERBERR KerbErr = KDC_ERR_NONE;
  2761. DsysAssert(KeySalt);
  2762. KeySalt->Buffer = NULL;
  2763. //
  2764. // If there is no domain name, this is a UPN so build a UPN salt.
  2765. //
  2766. if (DomainName->Length == 0)
  2767. {
  2768. return(KerbBuildKeySaltFromUpn(
  2769. ServiceName,
  2770. KeySalt ));
  2771. }
  2772. FinalLength = (ULONG)DomainName->Length +
  2773. (ULONG)ServiceName->Length;
  2774. //
  2775. // Add in any fixed strings, such as "host" for machines or "krbtgt" for
  2776. // interdomain accounts
  2777. //
  2778. if (AccountType == MachineAccount)
  2779. {
  2780. //
  2781. // Check to see if the name is already a "host/..." name. If so,
  2782. // we don't need to do this work.
  2783. //
  2784. if ((ServiceName->Length > sizeof(KERB_HOST_STRING) &&
  2785. (_wcsnicmp(
  2786. ServiceName->Buffer,
  2787. KERB_HOST_STRING,
  2788. (sizeof(KERB_HOST_STRING) - sizeof(WCHAR)) / sizeof(WCHAR)) == 0) &&
  2789. (ServiceName->Buffer[(sizeof(KERB_HOST_STRING) - sizeof(WCHAR)) / sizeof(WCHAR)] == L'/')))
  2790. {
  2791. AccountType = UserAccount;
  2792. }
  2793. else
  2794. {
  2795. FinalLength += sizeof(KERB_HOST_STRING) - sizeof(WCHAR);
  2796. //
  2797. // Add in the rest of the DNS name of the principal
  2798. // as well
  2799. //
  2800. FinalLength += DomainName->Length + sizeof(WCHAR);
  2801. }
  2802. }
  2803. else if (AccountType == DomainTrustAccount)
  2804. {
  2805. FinalLength += sizeof(KDC_PRINCIPAL_NAME) - sizeof(WCHAR);
  2806. }
  2807. else if (AccountType == UnknownAccount)
  2808. {
  2809. for (Index = 0; Index < ServiceName->Length/ sizeof(WCHAR) ; Index++ )
  2810. {
  2811. if (ServiceName->Buffer[Index] == L'/')
  2812. {
  2813. DeadSpace += sizeof(WCHAR);
  2814. }
  2815. }
  2816. FinalLength = FinalLength - DeadSpace;
  2817. }
  2818. //
  2819. // Detect and reject overflows
  2820. //
  2821. if (FinalLength > KERB_MAX_UNICODE_STRING)
  2822. {
  2823. KerbErr = KRB_ERR_GENERIC;
  2824. goto Cleanup;
  2825. }
  2826. KeySalt->Length = 0;
  2827. KeySalt->MaximumLength = (USHORT) FinalLength + sizeof(WCHAR);
  2828. KeySalt->Buffer = (LPWSTR) MIDL_user_allocate(KeySalt->MaximumLength);
  2829. if (KeySalt->Buffer == NULL)
  2830. {
  2831. return KRB_ERR_GENERIC;
  2832. }
  2833. Where = (PUCHAR) KeySalt->Buffer;
  2834. RtlCopyMemory(
  2835. KeySalt->Buffer,
  2836. DomainName->Buffer,
  2837. DomainName->Length
  2838. );
  2839. // KeySalt->Length = KeySalt->Length + DomainName->Length;
  2840. ulLength = (ULONG)KeySalt->Length + (ULONG)DomainName->Length;
  2841. if (ulLength > KERB_MAX_UNICODE_STRING)
  2842. {
  2843. KerbErr = KRB_ERR_GENERIC;
  2844. goto Cleanup;
  2845. }
  2846. KeySalt->Length = (USHORT)ulLength;
  2847. Where += DomainName->Length;
  2848. //
  2849. // Add in any fixed strings, such as "host" for machines or "krbtgt" for
  2850. // interdomain accounts
  2851. //
  2852. if (AccountType == MachineAccount)
  2853. {
  2854. USHORT DontCopyChars = 0;
  2855. UNICODE_STRING LowerCase = {0};
  2856. NTSTATUS Status;
  2857. ulLength = 0;
  2858. RtlCopyMemory(
  2859. Where,
  2860. KERB_HOST_STRING,
  2861. sizeof(KERB_HOST_STRING) - sizeof(WCHAR)
  2862. );
  2863. Where += sizeof(KERB_HOST_STRING) - sizeof(WCHAR);
  2864. //
  2865. // The service name may have a '$' at the end - if so, don't copy
  2866. // it.
  2867. //
  2868. if ((ServiceName->Length >= sizeof(WCHAR)) &&
  2869. (ServiceName->Buffer[-1 + ServiceName->Length / sizeof(WCHAR)] == L'$'))
  2870. {
  2871. DontCopyChars = 1;
  2872. }
  2873. LowerCase.Buffer = (LPWSTR) Where;
  2874. RtlCopyMemory(
  2875. Where,
  2876. ServiceName->Buffer,
  2877. ServiceName->Length - sizeof(WCHAR) * DontCopyChars
  2878. );
  2879. Where += ServiceName->Length - sizeof(WCHAR) * DontCopyChars;
  2880. // LowerCase.Length += ServiceName->Length - sizeof(WCHAR) * DontCopyChars;
  2881. ulLength += ServiceName->Length - sizeof(WCHAR) * DontCopyChars;
  2882. //
  2883. // add in the rest of the DNS name of the server
  2884. //
  2885. *(LPWSTR) Where = L'.';
  2886. Where += sizeof(WCHAR);
  2887. // LowerCase.Length += sizeof(WCHAR);
  2888. ulLength += sizeof(WCHAR);
  2889. RtlCopyMemory(
  2890. Where,
  2891. DomainName->Buffer,
  2892. DomainName->Length
  2893. );
  2894. Where += DomainName->Length;
  2895. // LowerCase.Length = LowerCase.Length + DomainName->Length;
  2896. ulLength = ulLength + DomainName->Length;
  2897. // Test for overflow on USHORT lengths
  2898. if (ulLength > KERB_MAX_UNICODE_STRING )
  2899. {
  2900. KerbErr = KRB_ERR_GENERIC;
  2901. goto Cleanup;
  2902. }
  2903. LowerCase.Length = (USHORT) ulLength;
  2904. LowerCase.MaximumLength = LowerCase.Length;
  2905. Status = RtlDowncaseUnicodeString(
  2906. &LowerCase,
  2907. &LowerCase,
  2908. FALSE
  2909. );
  2910. DsysAssert(NT_SUCCESS(Status));
  2911. }
  2912. else if (AccountType == DomainTrustAccount)
  2913. {
  2914. ULONG DontCopyChars = 0;
  2915. RtlCopyMemory(
  2916. Where,
  2917. KDC_PRINCIPAL_NAME,
  2918. sizeof(KDC_PRINCIPAL_NAME) - sizeof(WCHAR)
  2919. );
  2920. Where += sizeof(KDC_PRINCIPAL_NAME) - sizeof(WCHAR);
  2921. //
  2922. // The service name may have a '$' at the end - if so, don't copy
  2923. // it.
  2924. //
  2925. if ((ServiceName->Length >= sizeof(WCHAR)) &&
  2926. (ServiceName->Buffer[-1 + ServiceName->Length / sizeof(WCHAR)] == L'$'))
  2927. {
  2928. DontCopyChars = 1;
  2929. }
  2930. RtlCopyMemory(
  2931. Where,
  2932. ServiceName->Buffer,
  2933. ServiceName->Length - sizeof(WCHAR) * DontCopyChars
  2934. );
  2935. Where += ServiceName->Length - sizeof(WCHAR) * DontCopyChars;
  2936. }
  2937. else if (AccountType == UnknownAccount)
  2938. {
  2939. //
  2940. // Pull out an '/' from unknown accounts
  2941. //
  2942. for (Index = 0; Index < ServiceName->Length / sizeof(WCHAR) ; Index++)
  2943. {
  2944. if (ServiceName->Buffer[Index] != L'/')
  2945. {
  2946. *((LPWSTR) Where) = ServiceName->Buffer[Index];
  2947. Where += sizeof(WCHAR);
  2948. }
  2949. }
  2950. }
  2951. else
  2952. {
  2953. for (Index = 0; Index < ServiceName->Length / sizeof(WCHAR); Index++ )
  2954. {
  2955. if (ServiceName->Buffer[Index] != L'/')
  2956. {
  2957. *((LPWSTR)Where) = ServiceName->Buffer[Index];
  2958. Where += sizeof(WCHAR);
  2959. }
  2960. }
  2961. }
  2962. // check for USHORT overflow on length
  2963. ulLength = (ULONG)(Where - (PUCHAR) KeySalt->Buffer);
  2964. if (ulLength > KERB_MAX_UNICODE_STRING )
  2965. {
  2966. KerbErr = KRB_ERR_GENERIC;
  2967. goto Cleanup;
  2968. }
  2969. KeySalt->Length = (USHORT) ulLength;
  2970. *(LPWSTR) Where = L'\0';
  2971. KerbErr = KDC_ERR_NONE;
  2972. Cleanup:
  2973. if (!KERB_SUCCESS(KerbErr))
  2974. {
  2975. if (KeySalt->Buffer)
  2976. {
  2977. MIDL_user_free(KeySalt->Buffer);
  2978. KeySalt->Buffer = NULL;
  2979. }
  2980. }
  2981. return(KerbErr);
  2982. }
  2983. //+-------------------------------------------------------------------------
  2984. //
  2985. // Function: KerbBuildKeySaltFromUpn
  2986. //
  2987. // Synopsis: Creaes salt from a UPN
  2988. //
  2989. // Effects:
  2990. // For users it is DOMAINNAMEusername
  2991. //
  2992. // Arguments:
  2993. //
  2994. // Requires:
  2995. //
  2996. // Returns:
  2997. //
  2998. // Notes:
  2999. //
  3000. //
  3001. //--------------------------------------------------------------------------
  3002. KERBERR
  3003. KerbBuildKeySaltFromUpn(
  3004. IN PUNICODE_STRING Upn,
  3005. OUT PUNICODE_STRING Salt
  3006. )
  3007. {
  3008. KERBERR KerbErr = KDC_ERR_NONE;
  3009. UNICODE_STRING RealUpn = {0};
  3010. UNICODE_STRING RealmName = {0};
  3011. UNICODE_STRING LocalSalt = {0};
  3012. ULONG Index;
  3013. ULONG ulLength = 0;
  3014. //
  3015. // If there is an "@" in UPN, strip it out & use the dns domain name
  3016. //
  3017. RealUpn = *Upn;
  3018. for (Index = 0; Index < RealUpn.Length/sizeof(WCHAR) ; Index++ )
  3019. {
  3020. if (RealUpn.Buffer[Index] == L'@')
  3021. {
  3022. RealUpn.Length = (USHORT) (Index * sizeof(WCHAR));
  3023. RealmName.Buffer = &RealUpn.Buffer[Index+1];
  3024. RealmName.Length = Upn->Length - RealUpn.Length - sizeof(WCHAR);
  3025. RealmName.MaximumLength = RealmName.Length;
  3026. break;
  3027. }
  3028. }
  3029. if (RealmName.Length == 0)
  3030. {
  3031. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  3032. goto Cleanup;
  3033. }
  3034. //
  3035. // Create the salt. It starts off with the domain name & then has the
  3036. // UPN without any of the / pieces
  3037. //
  3038. ulLength = (ULONG)RealmName.Length + (ULONG)RealUpn.Length;
  3039. // Test for overflow on USHORT lengths
  3040. if (ulLength > KERB_MAX_UNICODE_STRING )
  3041. {
  3042. KerbErr = KRB_ERR_GENERIC;
  3043. goto Cleanup;
  3044. }
  3045. LocalSalt.MaximumLength = (USHORT)ulLength;
  3046. LocalSalt.Length = 0;
  3047. LocalSalt.Buffer = (LPWSTR) MIDL_user_allocate(LocalSalt.MaximumLength);
  3048. if (LocalSalt.Buffer == NULL)
  3049. {
  3050. KerbErr = KRB_ERR_GENERIC;
  3051. goto Cleanup;
  3052. }
  3053. RtlCopyMemory(
  3054. LocalSalt.Buffer,
  3055. RealmName.Buffer,
  3056. RealmName.Length
  3057. );
  3058. // LocalSalt.Length = LocalSalt.Length + RealmName.Length;
  3059. ulLength = RealmName.Length;
  3060. //
  3061. // Add in the real upn but leave out any "/" marks
  3062. //
  3063. for (Index = 0; Index < RealUpn.Length/sizeof(WCHAR) ; Index++ )
  3064. {
  3065. if (RealUpn.Buffer[Index] != L'/')
  3066. {
  3067. LocalSalt.Buffer[ulLength / sizeof(WCHAR)] = RealUpn.Buffer[Index];
  3068. ulLength += sizeof(WCHAR);
  3069. }
  3070. }
  3071. // Test for overflow on USHORT lengths - no need already done on MAX size possible
  3072. LocalSalt.Length = (USHORT)ulLength;
  3073. //
  3074. // We have to lowercase the username for users
  3075. //
  3076. #ifndef WIN32_CHICAGO
  3077. CharLowerBuff(&(LocalSalt.Buffer[RealmName.Length/sizeof(WCHAR)]), RealUpn.Length/sizeof(WCHAR));
  3078. #endif // WIN32_CHICAGO
  3079. *Salt = LocalSalt; // give memory to caller
  3080. LocalSalt.Buffer = NULL;
  3081. Cleanup:
  3082. return(KerbErr);
  3083. }
  3084. //+-------------------------------------------------------------------------
  3085. //
  3086. // Function: KerbConvertSidToString
  3087. //
  3088. // Synopsis: Converts a sid to a string using RtlConvertSidToUnicodeString
  3089. // but with a different allocator.
  3090. //
  3091. // Effects:
  3092. //
  3093. // Arguments:
  3094. //
  3095. // Requires:
  3096. //
  3097. // Returns:
  3098. //
  3099. // Notes:
  3100. //
  3101. //
  3102. //--------------------------------------------------------------------------
  3103. NTSTATUS
  3104. KerbConvertSidToString(
  3105. IN PSID Sid,
  3106. OUT PUNICODE_STRING String,
  3107. IN BOOLEAN AllocateDestination
  3108. )
  3109. {
  3110. NTSTATUS Status;
  3111. WCHAR Buffer[256];
  3112. UNICODE_STRING TempString;
  3113. if (AllocateDestination)
  3114. {
  3115. TempString.Length = 0;
  3116. TempString.MaximumLength = sizeof(Buffer);
  3117. TempString.Buffer = Buffer;
  3118. }
  3119. else
  3120. {
  3121. TempString = *String;
  3122. }
  3123. Status = RtlConvertSidToUnicodeString(
  3124. &TempString,
  3125. Sid,
  3126. FALSE
  3127. );
  3128. if (NT_SUCCESS(Status))
  3129. {
  3130. if (!AllocateDestination)
  3131. {
  3132. *String = TempString;
  3133. }
  3134. else
  3135. {
  3136. String->Buffer = (LPWSTR) MIDL_user_allocate(TempString.Length+sizeof(WCHAR));
  3137. if (String->Buffer == NULL)
  3138. {
  3139. Status = STATUS_INSUFFICIENT_RESOURCES;
  3140. }
  3141. else
  3142. {
  3143. String->Length = TempString.Length;
  3144. String->MaximumLength = TempString.Length+sizeof(WCHAR);
  3145. RtlCopyMemory(
  3146. String->Buffer,
  3147. TempString.Buffer,
  3148. TempString.Length
  3149. );
  3150. String->Buffer[TempString.Length / sizeof(WCHAR)] = L'\0';
  3151. }
  3152. }
  3153. }
  3154. return(Status);
  3155. }
  3156. //+-------------------------------------------------------------------------
  3157. //
  3158. // Function: KerbConvertStringToSid
  3159. //
  3160. // Synopsis: Converts back a sid from KerbConvertSidToString. If the
  3161. // string is malformed, it will return STATUS_INVALID_PARAMTER
  3162. //
  3163. // Effects:
  3164. //
  3165. // Arguments:
  3166. //
  3167. // Requires:
  3168. //
  3169. // Returns:
  3170. //
  3171. // Notes:
  3172. //
  3173. //
  3174. //--------------------------------------------------------------------------
  3175. NTSTATUS
  3176. KerbConvertStringToSid(
  3177. IN PUNICODE_STRING String,
  3178. OUT PSID * Sid
  3179. )
  3180. {
  3181. NTSTATUS Status;
  3182. WCHAR Buffer[256];
  3183. PSID SidT;
  3184. *Sid = NULL;
  3185. if ( String->Length + sizeof( WCHAR ) <= sizeof( Buffer )) {
  3186. RtlCopyMemory( Buffer, String->Buffer, String->Length );
  3187. } else {
  3188. return STATUS_INVALID_PARAMETER;
  3189. }
  3190. Buffer[String->Length / sizeof( WCHAR )] = L'\0';
  3191. if ( ConvertStringSidToSidW(
  3192. Buffer,
  3193. &SidT )) {
  3194. Status = KerbDuplicateSid(
  3195. Sid,
  3196. SidT
  3197. );
  3198. LocalFree( SidT );
  3199. } else {
  3200. switch( GetLastError()) {
  3201. case ERROR_NOT_ENOUGH_MEMORY:
  3202. Status = STATUS_INSUFFICIENT_RESOURCES;
  3203. break;
  3204. case ERROR_INVALID_SID:
  3205. Status = STATUS_INVALID_PARAMETER;
  3206. break;
  3207. default:
  3208. DsysAssert( FALSE ); // add mapping for the error code
  3209. Status = STATUS_INVALID_PARAMETER;
  3210. break;
  3211. }
  3212. }
  3213. return Status;
  3214. }
  3215. //+-------------------------------------------------------------------------
  3216. //
  3217. // Function: KerbBuildAltSecId
  3218. //
  3219. // Synopsis: Builds the name for the alt-sec-id field lookup
  3220. //
  3221. // Effects: Converts a principal name from name1 name2 name3 to
  3222. // "kerberos:name1/name2/name3@realm"
  3223. //
  3224. // Arguments:
  3225. //
  3226. // Requires:
  3227. //
  3228. // Returns:
  3229. //
  3230. // Notes:
  3231. //
  3232. //
  3233. //--------------------------------------------------------------------------
  3234. KERBERR
  3235. KerbBuildAltSecId(
  3236. OUT PUNICODE_STRING AlternateName,
  3237. IN PKERB_INTERNAL_NAME PrincipalName,
  3238. IN OPTIONAL PKERB_REALM Realm,
  3239. IN OPTIONAL PUNICODE_STRING UnicodeRealm
  3240. )
  3241. {
  3242. ULONG StringLength = sizeof(KERB_NAME_PREFIX) - sizeof(WCHAR);
  3243. ULONG Index;
  3244. UNICODE_STRING TempString = {0};
  3245. UNICODE_STRING LocalRealm = {0};
  3246. KERBERR KerbErr = KDC_ERR_NONE;
  3247. *AlternateName = TempString;
  3248. if (ARGUMENT_PRESENT(UnicodeRealm))
  3249. {
  3250. LocalRealm = *UnicodeRealm;
  3251. }
  3252. else if (ARGUMENT_PRESENT(Realm))
  3253. {
  3254. KerbErr = KerbConvertRealmToUnicodeString(
  3255. &LocalRealm,
  3256. Realm
  3257. );
  3258. if (!KERB_SUCCESS(KerbErr))
  3259. {
  3260. goto Cleanup;
  3261. }
  3262. }
  3263. if (PrincipalName->NameCount == 0)
  3264. {
  3265. KerbErr = KDC_ERR_C_PRINCIPAL_UNKNOWN;
  3266. goto Cleanup;
  3267. }
  3268. //
  3269. // Add in the size of all the components of the name plus a separtor
  3270. // or a null terminator.
  3271. //
  3272. for (Index = 0; Index < PrincipalName->NameCount; Index++ )
  3273. {
  3274. StringLength += PrincipalName->Names[Index].Length + sizeof(WCHAR);
  3275. }
  3276. if (LocalRealm.Length != 0)
  3277. {
  3278. StringLength += sizeof(WCHAR) + // for @
  3279. LocalRealm.Length;
  3280. }
  3281. //
  3282. // Now build the name, front to back (differently from KerbConvertPrincipalNameToString()
  3283. //
  3284. // Test for overflow on USHORT lengths
  3285. if (StringLength > KERB_MAX_UNICODE_STRING ) // actually more accurate to use (StringLength - 1) > MAX
  3286. {
  3287. KerbErr = KRB_ERR_GENERIC;
  3288. goto Cleanup;
  3289. }
  3290. TempString.Buffer = (LPWSTR) MIDL_user_allocate(StringLength);
  3291. if (TempString.Buffer == NULL)
  3292. {
  3293. KerbErr = KRB_ERR_GENERIC;
  3294. goto Cleanup;
  3295. }
  3296. TempString.Length = 0;
  3297. TempString.MaximumLength = (USHORT) StringLength;
  3298. //
  3299. // Now start appending the various portions to the string - max length already tested for overflow
  3300. //
  3301. RtlAppendUnicodeStringToString(
  3302. &TempString,
  3303. &KerbNamePrefix
  3304. );
  3305. for (Index = 0; Index < PrincipalName->NameCount ; Index++ )
  3306. {
  3307. if (Index != 0)
  3308. {
  3309. RtlAppendUnicodeStringToString(
  3310. &TempString,
  3311. &KerbNameSeparator
  3312. );
  3313. }
  3314. RtlAppendUnicodeStringToString(
  3315. &TempString,
  3316. &PrincipalName->Names[Index]
  3317. );
  3318. }
  3319. if (LocalRealm.Length != 0)
  3320. {
  3321. RtlAppendUnicodeStringToString(
  3322. &TempString,
  3323. &KerbDomainSeparator
  3324. );
  3325. RtlAppendUnicodeStringToString(
  3326. &TempString,
  3327. &LocalRealm
  3328. );
  3329. }
  3330. *AlternateName = TempString;
  3331. Cleanup:
  3332. if (!ARGUMENT_PRESENT(UnicodeRealm))
  3333. {
  3334. KerbFreeString(&LocalRealm);
  3335. }
  3336. return(KerbErr);
  3337. }
  3338. #ifndef WIN32_CHICAGO
  3339. //+-------------------------------------------------------------------------
  3340. //
  3341. // Function: KerbGetPrincipalNameFromCertificate
  3342. //
  3343. // Synopsis: Derives the principal name from a certificate
  3344. //
  3345. // Effects:
  3346. //
  3347. // Arguments:
  3348. //
  3349. // Requires:
  3350. //
  3351. // Returns:
  3352. //
  3353. // Notes:
  3354. //
  3355. //
  3356. //--------------------------------------------------------------------------
  3357. NTSTATUS
  3358. KerbGetPrincipalNameFromCertificate(
  3359. IN PCCERT_CONTEXT ClientCert,
  3360. OUT PUNICODE_STRING String
  3361. )
  3362. {
  3363. UNICODE_STRING NameString = {0};
  3364. NTSTATUS Status = STATUS_SUCCESS;
  3365. ULONG ExtensionIndex = 0;
  3366. BOOL fAssigned = FALSE;
  3367. PCERT_ALT_NAME_INFO AltName=NULL;
  3368. PCERT_NAME_VALUE PrincipalNameBlob = NULL;
  3369. LPWSTR CertNameString = NULL;
  3370. CRYPT_DECODE_PARA DecodePara = {sizeof(CRYPT_DECODE_PARA),
  3371. MIDL_user_allocate,
  3372. MIDL_user_free };
  3373. //
  3374. // Get the client name from the cert
  3375. //
  3376. // See if cert has UPN in AltSubjectName->otherName
  3377. for(ExtensionIndex = 0;
  3378. ExtensionIndex < ClientCert->pCertInfo->cExtension;
  3379. ExtensionIndex++)
  3380. {
  3381. if(strcmp(ClientCert->pCertInfo->rgExtension[ExtensionIndex].pszObjId,
  3382. szOID_SUBJECT_ALT_NAME2) == 0)
  3383. {
  3384. DWORD AltNameStructSize = 0;
  3385. ULONG CertAltNameIndex = 0;
  3386. if(CryptDecodeObjectEx(ClientCert->dwCertEncodingType,
  3387. X509_ALTERNATE_NAME,
  3388. ClientCert->pCertInfo->rgExtension[ExtensionIndex].Value.pbData,
  3389. ClientCert->pCertInfo->rgExtension[ExtensionIndex].Value.cbData,
  3390. CRYPT_DECODE_ALLOC_FLAG,
  3391. &DecodePara,
  3392. (PVOID)&AltName,
  3393. &AltNameStructSize))
  3394. {
  3395. for(CertAltNameIndex = 0; CertAltNameIndex < AltName->cAltEntry; CertAltNameIndex++)
  3396. {
  3397. PCERT_ALT_NAME_ENTRY AltNameEntry = &AltName->rgAltEntry[CertAltNameIndex];
  3398. if((CERT_ALT_NAME_OTHER_NAME == AltNameEntry->dwAltNameChoice) &&
  3399. (NULL != AltNameEntry->pOtherName) &&
  3400. (0 == strcmp(szOID_NT_PRINCIPAL_NAME, AltNameEntry->pOtherName->pszObjId)))
  3401. {
  3402. DWORD PrincipalNameBlobSize = 0;
  3403. // We found a UPN!
  3404. if(CryptDecodeObjectEx(ClientCert->dwCertEncodingType,
  3405. X509_UNICODE_ANY_STRING,
  3406. AltNameEntry->pOtherName->Value.pbData,
  3407. AltNameEntry->pOtherName->Value.cbData,
  3408. CRYPT_DECODE_ALLOC_FLAG,
  3409. &DecodePara,
  3410. (PVOID)&PrincipalNameBlob,
  3411. &PrincipalNameBlobSize))
  3412. {
  3413. fAssigned = SafeRtlInitUnicodeString(&NameString,
  3414. (LPCWSTR)PrincipalNameBlob->Value.pbData);
  3415. if (fAssigned == FALSE)
  3416. {
  3417. Status = STATUS_NAME_TOO_LONG;
  3418. goto Cleanup;
  3419. }
  3420. if(NameString.Length)
  3421. {
  3422. break;
  3423. }
  3424. MIDL_user_free(PrincipalNameBlob);
  3425. PrincipalNameBlob = NULL;
  3426. }
  3427. }
  3428. }
  3429. if(NameString.Length)
  3430. {
  3431. break;
  3432. }
  3433. MIDL_user_free(AltName);
  3434. AltName = NULL;
  3435. }
  3436. }
  3437. }
  3438. if(0 != NameString.Length)
  3439. {
  3440. Status = KerbDuplicateString(String, &NameString);
  3441. if (!NT_SUCCESS(Status))
  3442. {
  3443. D_DebugLog((DEB_ERROR,"Failed to normalize name "));
  3444. // KerbPrintKdcName(DEB_ERROR,ClientName);
  3445. goto Cleanup;
  3446. }
  3447. D_DebugLog((DEB_TRACE,"UPN from certificate is %wZ\n",&NameString));
  3448. }
  3449. else
  3450. {
  3451. Status = STATUS_PKINIT_NAME_MISMATCH;
  3452. D_DebugLog((DEB_ERROR,"No valid name in Sclogon certificate\n"));
  3453. goto Cleanup;
  3454. }
  3455. Cleanup:
  3456. if(PrincipalNameBlob)
  3457. {
  3458. MIDL_user_free(PrincipalNameBlob);
  3459. }
  3460. if(AltName)
  3461. {
  3462. MIDL_user_free(AltName);
  3463. }
  3464. if(CertNameString)
  3465. {
  3466. MIDL_user_free(CertNameString);
  3467. }
  3468. return(Status);
  3469. }
  3470. #endif
  3471. BOOL
  3472. SafeRtlInitString(
  3473. OUT PSTRING DestinationString,
  3474. IN PCSZ SourceString OPTIONAL
  3475. )
  3476. /*++
  3477. Routine Description:
  3478. The RtlInitString function initializes an NT counted string.
  3479. The DestinationString is initialized to point to the SourceString
  3480. and the Length and MaximumLength fields of DestinationString are
  3481. initialized to the length of the SourceString, which is zero if
  3482. SourceString is not specified.
  3483. Arguments:
  3484. DestinationString - Pointer to the counted string to initialize
  3485. SourceString - Optional pointer to a null terminated string that
  3486. the counted string is to point to.
  3487. Return Value:
  3488. TRUE if assignment took place, FALSE on error - such as USHORT overflow
  3489. --*/
  3490. {
  3491. ULONG Length;
  3492. DestinationString->Buffer = (PCHAR)SourceString;
  3493. if (ARGUMENT_PRESENT( SourceString )) {
  3494. Length = (ULONG)strlen(SourceString);
  3495. if (Length > KERB_MAX_STRING)
  3496. {
  3497. return FALSE; // length will not fit into USHORT value
  3498. }
  3499. DestinationString->Length = (USHORT)Length;
  3500. DestinationString->MaximumLength = (USHORT)(Length+1);
  3501. }
  3502. else {
  3503. DestinationString->Length = 0;
  3504. DestinationString->MaximumLength = 0;
  3505. }
  3506. return TRUE;
  3507. }
  3508. BOOL
  3509. SafeRtlInitUnicodeString(
  3510. OUT PUNICODE_STRING DestinationString,
  3511. IN PCWSTR SourceString OPTIONAL
  3512. )
  3513. /*++
  3514. Routine Description:
  3515. The RtlInitUnicodeString function initializes an NT counted
  3516. unicode string. The DestinationString is initialized to point to
  3517. the SourceString and the Length and MaximumLength fields of
  3518. DestinationString are initialized to the length of the SourceString,
  3519. which is zero if SourceString is not specified.
  3520. Arguments:
  3521. DestinationString - Pointer to the counted string to initialize
  3522. SourceString - Optional pointer to a null terminated unicode string that
  3523. the counted string is to point to.
  3524. Return Value:
  3525. None.
  3526. --*/
  3527. {
  3528. ULONG Length;
  3529. DestinationString->Buffer = (PWSTR)SourceString;
  3530. if (ARGUMENT_PRESENT( SourceString )) {
  3531. Length = (ULONG)wcslen( SourceString ) * sizeof( WCHAR );
  3532. ASSERT( Length <= KERB_MAX_UNICODE_STRING );
  3533. if (Length > KERB_MAX_UNICODE_STRING)
  3534. {
  3535. return FALSE; // length will not fit into USHORT value
  3536. }
  3537. DestinationString->Length = (USHORT)Length;
  3538. DestinationString->MaximumLength = (USHORT)(Length + sizeof(UNICODE_NULL));
  3539. }
  3540. else {
  3541. DestinationString->MaximumLength = 0;
  3542. DestinationString->Length = 0;
  3543. }
  3544. return TRUE;
  3545. }
  3546. //+-------------------------------------------------------------------------
  3547. //
  3548. // Function: KerbGetCertificateHash
  3549. //
  3550. // Synopsis: Gets the SHA1 hash of a certificate.
  3551. //
  3552. // Effects:
  3553. //
  3554. // Arguments:
  3555. //
  3556. // Requires:
  3557. //
  3558. // Returns:
  3559. //
  3560. // Notes:
  3561. //
  3562. //
  3563. //--------------------------------------------------------------------------
  3564. NTSTATUS
  3565. KerbGetCertificateHash(
  3566. OUT LPBYTE pCertHash,
  3567. IN ULONG cbCertHash,
  3568. IN PCCERT_CONTEXT pCertContext
  3569. )
  3570. {
  3571. ULONG cbHash = cbCertHash;
  3572. if ( CertGetCertificateContextProperty(
  3573. pCertContext,
  3574. CERT_SHA1_HASH_PROP_ID,
  3575. pCertHash,
  3576. &cbHash
  3577. ) == FALSE )
  3578. {
  3579. return( STATUS_PKINIT_FAILURE );
  3580. }
  3581. return( STATUS_SUCCESS );
  3582. }
  3583. //+-------------------------------------------------------------------------
  3584. //
  3585. // Function: KerbCreateUnicodeStringFromHash
  3586. //
  3587. // Synopsis: Creates a hash string from a hash blob
  3588. //
  3589. // Effects:
  3590. //
  3591. // Arguments:
  3592. //
  3593. // Requires:
  3594. //
  3595. // Returns:
  3596. //
  3597. // Notes:
  3598. //
  3599. //
  3600. //
  3601. //--------------------------------------------------------------------------
  3602. NTSTATUS
  3603. KerbCreateUnicodeStringFromBlob(
  3604. IN PBYTE Blob,
  3605. IN ULONG BlobSize,
  3606. IN OUT PUNICODE_STRING String,
  3607. IN BOOLEAN ReverseOrder
  3608. )
  3609. {
  3610. LPWSTR out = NULL;
  3611. WCHAR buff[256];
  3612. PBYTE pb;
  3613. ULONG cb, length;
  3614. //
  3615. // Don't overflow USHORT.
  3616. //
  3617. length = ((2 * BlobSize + 1) * sizeof(WCHAR));
  3618. if ( length > KERB_MAX_UNICODE_STRING )
  3619. {
  3620. return(STATUS_NAME_TOO_LONG);
  3621. }
  3622. out = (LPWSTR) MIDL_user_allocate(length);
  3623. if ( out == NULL )
  3624. {
  3625. return STATUS_NO_MEMORY;
  3626. }
  3627. if ( ReverseOrder )
  3628. {
  3629. pb = Blob;
  3630. for ( cb = BlobSize; cb > 0; cb--, pb++ )
  3631. {
  3632. swprintf(buff, L"%02X", *pb);
  3633. wcscat(out, buff);
  3634. }
  3635. }
  3636. else
  3637. {
  3638. pb = Blob + ( BlobSize - 1 );
  3639. for ( cb = BlobSize; cb > 0; cb--, pb-- )
  3640. {
  3641. swprintf(buff, L"%02X", *pb);
  3642. wcscat(out, buff);
  3643. }
  3644. }
  3645. out[(2*BlobSize)] = L'\0';
  3646. RtlInitUnicodeString(
  3647. String,
  3648. out
  3649. );
  3650. return STATUS_SUCCESS;
  3651. }
  3652. //+-------------------------------------------------------------------------
  3653. //
  3654. // Function: KerbGetCertificateString
  3655. //
  3656. // Synopsis: Gets the specified name type from a cert context
  3657. //
  3658. // Effects:
  3659. //
  3660. // Arguments:
  3661. //
  3662. // Requires:
  3663. //
  3664. // Returns:
  3665. //
  3666. // Notes:
  3667. //
  3668. //
  3669. //
  3670. //--------------------------------------------------------------------------
  3671. NTSTATUS
  3672. KerbGetCertificateString(
  3673. IN PCCERT_CONTEXT Certificate,
  3674. IN DWORD Type,
  3675. IN DWORD Flags,
  3676. IN OUT PUNICODE_STRING CertString
  3677. )
  3678. {
  3679. NTSTATUS Status = STATUS_SUCCESS;
  3680. LPWSTR wszRet = NULL;
  3681. DWORD dwChars = 0;
  3682. ULONG len;
  3683. dwChars = CertGetNameStringW(
  3684. Certificate,
  3685. Type,
  3686. Flags,
  3687. NULL,
  3688. NULL,
  3689. 0
  3690. );
  3691. //
  3692. // If dwChars is 1, then it is an empty string. No reason
  3693. // to do anything more, as Subject wasn't found.
  3694. //
  3695. if (dwChars == 1)
  3696. {
  3697. DebugLog((DEB_ERROR, "Missing %x from cert %p\n", Type, Certificate));
  3698. DsysAssert(FALSE);
  3699. return STATUS_OBJECT_NAME_NOT_FOUND;
  3700. }
  3701. len = (dwChars + 1) * sizeof(WCHAR);
  3702. if (len > KERB_MAX_UNICODE_STRING)
  3703. {
  3704. return(STATUS_NAME_TOO_LONG);
  3705. }
  3706. wszRet = (LPWSTR) MIDL_user_allocate(len);
  3707. if ( NULL == wszRet)
  3708. {
  3709. return STATUS_NO_MEMORY;
  3710. }
  3711. dwChars = CertGetNameStringW(
  3712. Certificate,
  3713. Type,
  3714. Flags,
  3715. NULL,
  3716. wszRet,
  3717. dwChars
  3718. );
  3719. //
  3720. // Huh?
  3721. //
  3722. if (dwChars == 1)
  3723. {
  3724. DebugLog((DEB_ERROR, "Missing %x from cert %p\n", Type, Certificate));
  3725. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3726. goto Cleanup;
  3727. }
  3728. RtlInitUnicodeString(
  3729. CertString,
  3730. wszRet
  3731. );
  3732. Cleanup:
  3733. if (!NT_SUCCESS( Status ))
  3734. {
  3735. if ( wszRet )
  3736. {
  3737. MIDL_user_free( wszRet );
  3738. }
  3739. ZeroMemory(
  3740. CertString,
  3741. sizeof(UNICODE_STRING)
  3742. );
  3743. }
  3744. return Status;
  3745. }
  3746. //+-------------------------------------------------------------------------
  3747. //
  3748. // Function: KerbGetCertificateHashString
  3749. //
  3750. // Synopsis: Creates a string from a hash.
  3751. //
  3752. // Effects:
  3753. //
  3754. // Arguments:
  3755. //
  3756. // Requires:
  3757. //
  3758. // Returns:
  3759. //
  3760. // Notes:
  3761. //
  3762. //
  3763. //----
  3764. NTSTATUS
  3765. KerbGetCertificateHashString(
  3766. IN PCCERT_CONTEXT Certificate,
  3767. IN OUT PUNICODE_STRING HashString
  3768. )
  3769. {
  3770. NTSTATUS Status = STATUS_SUCCESS;
  3771. ULONG HashSize = SHA1DIGESTLEN;
  3772. BYTE Hash[SHA1DIGESTLEN];
  3773. Status = KerbGetCertificateHash(
  3774. Hash,
  3775. HashSize,
  3776. Certificate
  3777. );
  3778. if (!NT_SUCCESS( Status ))
  3779. {
  3780. DebugLog((DEB_ERROR, "KerbGetCertificateHash failed %x\n", Status));
  3781. goto Cleanup;
  3782. }
  3783. Status = KerbCreateUnicodeStringFromBlob(
  3784. Hash,
  3785. HashSize,
  3786. HashString,
  3787. TRUE
  3788. );
  3789. if (!NT_SUCCESS( Status ))
  3790. {
  3791. DebugLog((DEB_ERROR, "KerbCreateUnicodeStringFromHash failed %x\n", Status));
  3792. goto Cleanup;
  3793. }
  3794. Cleanup:
  3795. return Status;
  3796. }
  3797. //+-------------------------------------------------------------------------
  3798. //
  3799. // Function: KerbGetCertificateIssuer
  3800. //
  3801. // Synopsis: Gets the simply display name from a certificate.
  3802. //
  3803. // Effects:
  3804. //
  3805. // Arguments:
  3806. //
  3807. // Requires:
  3808. //
  3809. // Returns:
  3810. //
  3811. // Notes:
  3812. //
  3813. //
  3814. //----
  3815. NTSTATUS
  3816. KerbGetCertificateIssuer(
  3817. IN PCCERT_CONTEXT Certificate,
  3818. IN OUT PUNICODE_STRING Issuer
  3819. )
  3820. {
  3821. NTSTATUS Status = STATUS_SUCCESS;
  3822. Status = KerbGetCertificateString(
  3823. Certificate,
  3824. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  3825. CERT_NAME_ISSUER_FLAG,
  3826. Issuer
  3827. );
  3828. return Status;
  3829. }