Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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