Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

811 lines
18 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. krbutils.cxx
  6. Abstract:
  7. utils
  8. Author:
  9. Larry Zhu (LZhu) December 1, 2001 Created
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. --*/
  14. #include "precomp.hxx"
  15. #pragma hdrstop
  16. #include "krbutils.hxx"
  17. #include "kerberr.hxx"
  18. VOID
  19. KerbFreeRealm(
  20. IN PKERB_REALM pRealm
  21. )
  22. {
  23. if (*pRealm != NULL)
  24. {
  25. MIDL_user_free(*pRealm);
  26. *pRealm = NULL;
  27. }
  28. }
  29. VOID
  30. KerbFreePrincipalName(
  31. IN PKERB_PRINCIPAL_NAME pName
  32. )
  33. {
  34. PKERB_PRINCIPAL_NAME_ELEM pElem, pNextElem;
  35. pElem = pName->name_string;
  36. while (pElem != NULL)
  37. {
  38. if (pElem->value != NULL)
  39. {
  40. MIDL_user_free(pElem->value);
  41. }
  42. pNextElem = pElem->next;
  43. MIDL_user_free(pElem);
  44. pElem = pNextElem;
  45. }
  46. pName->name_string = NULL;
  47. }
  48. VOID
  49. KerbFreeData(
  50. IN ULONG PduValue,
  51. IN PVOID pData
  52. )
  53. {
  54. ASN1decoding_t pDec = NULL;
  55. if (pData)
  56. {
  57. TKerbErr KerbErr;
  58. KerbErr DBGCHK = KerbInitAsn(
  59. NULL,
  60. &pDec // this is a decoded structure
  61. );
  62. if (KERB_SUCCESS(KerbErr))
  63. {
  64. ASN1_FreeDecoded(pDec, pData, PduValue);
  65. }
  66. KerbTermAsn(NULL, pDec);
  67. }
  68. }
  69. BOOL fKRB5ModuleStarted = FALSE;
  70. KERBERR
  71. KerbInitAsn(
  72. IN OUT ASN1encoding_t * pEnc,
  73. IN OUT ASN1decoding_t * pDec
  74. )
  75. {
  76. TKerbErr KerbErr = KRB_ERR_GENERIC;
  77. ASN1error_e Asn1Err;
  78. if (!fKRB5ModuleStarted)
  79. {
  80. fKRB5ModuleStarted = TRUE;
  81. KRB5_Module_Startup();
  82. }
  83. if (pEnc != NULL)
  84. {
  85. Asn1Err = ASN1_CreateEncoder(
  86. KRB5_Module,
  87. pEnc,
  88. NULL, // pbBuf
  89. 0, // cbBufSize
  90. NULL // pParent
  91. );
  92. }
  93. else
  94. {
  95. Asn1Err = ASN1_CreateDecoder(
  96. KRB5_Module,
  97. pDec,
  98. NULL, // pbBuf
  99. 0, // cbBufSize
  100. NULL // pParent
  101. );
  102. }
  103. KerbErr DBGCHK = ASN1_SUCCESS == Asn1Err ? KDC_ERR_NONE : KRB_ERR_GENERIC;
  104. return KerbErr;
  105. }
  106. VOID
  107. KerbTermAsn(
  108. IN ASN1encoding_t pEnc,
  109. IN ASN1decoding_t pDec
  110. )
  111. {
  112. if (pEnc != NULL)
  113. {
  114. ASN1_CloseEncoder(pEnc);
  115. }
  116. else if (pDec != NULL)
  117. {
  118. ASN1_CloseDecoder(pDec);
  119. }
  120. }
  121. KERBERR
  122. KerbEncryptDataEx(
  123. OUT PKERB_ENCRYPTED_DATA pEncryptedData,
  124. IN ULONG cbDataSize,
  125. IN PUCHAR Data,
  126. IN ULONG KeyVersion,
  127. IN ULONG UsageFlags,
  128. IN PKERB_ENCRYPTION_KEY pKey
  129. )
  130. {
  131. PCRYPTO_SYSTEM pcsCrypt = NULL;
  132. PCRYPT_STATE_BUFFER psbCryptBuffer = NULL;
  133. NTSTATUS Status = STATUS_SUCCESS;
  134. Status = CDLocateCSystem(pKey->keytype, &pcsCrypt);
  135. if (!NT_SUCCESS(Status))
  136. {
  137. return(KDC_ERR_ETYPE_NOTSUPP);
  138. }
  139. //
  140. // Initialize header
  141. //
  142. pEncryptedData->encryption_type = pKey->keytype;
  143. Status = pcsCrypt->Initialize(
  144. (PUCHAR) pKey->keyvalue.value,
  145. pKey->keyvalue.length,
  146. UsageFlags,
  147. &psbCryptBuffer
  148. );
  149. if (!NT_SUCCESS(Status))
  150. {
  151. return(KRB_ERR_GENERIC);
  152. }
  153. Status = pcsCrypt->Encrypt(
  154. psbCryptBuffer,
  155. Data,
  156. cbDataSize,
  157. pEncryptedData->cipher_text.value,
  158. &pEncryptedData->cipher_text.length
  159. );
  160. (void) pcsCrypt->Discard(&psbCryptBuffer);
  161. if (!NT_SUCCESS(Status))
  162. {
  163. return(KRB_ERR_GENERIC);
  164. }
  165. if (KeyVersion != KERB_NO_KEY_VERSION)
  166. {
  167. pEncryptedData->version = KeyVersion;
  168. pEncryptedData->bit_mask |= version_present;
  169. }
  170. return KDC_ERR_NONE;
  171. }
  172. KERBERR
  173. KerbAllocateEncryptionBuffer(
  174. IN ULONG EncryptionType,
  175. IN ULONG cbBufferSize,
  176. OUT PUINT pcbEncryptionBufferSize,
  177. OUT PBYTE* pEncryptionBuffer
  178. )
  179. {
  180. TKerbErr KerbErr = KDC_ERR_NONE;
  181. ULONG cbEncryptionOverhead = 0;
  182. ULONG cbBlockSize = 0;
  183. KerbErr DBGCHK = KerbGetEncryptionOverhead(
  184. EncryptionType,
  185. &cbEncryptionOverhead,
  186. &cbBlockSize
  187. );
  188. if (KERB_SUCCESS(KerbErr))
  189. {
  190. *pcbEncryptionBufferSize = (UINT) ROUND_UP_COUNT(cbEncryptionOverhead + cbBufferSize, cbBlockSize);
  191. *pEncryptionBuffer = (PBYTE) MIDL_user_allocate(*pcbEncryptionBufferSize);
  192. if (*pEncryptionBuffer == NULL)
  193. {
  194. KerbErr DBGCHK = KRB_ERR_GENERIC;
  195. }
  196. }
  197. return KerbErr;
  198. }
  199. KERBERR
  200. KerbAllocateEncryptionBufferWrapper(
  201. IN ULONG EncryptionType,
  202. IN ULONG cbBufferSize,
  203. OUT ULONG* pcbEncryptionBufferSize,
  204. OUT PBYTE* pEncryptionBuffer
  205. )
  206. {
  207. TKerbErr KerbErr = KDC_ERR_NONE;
  208. UINT tempInt = 0;
  209. KerbErr DBGCHK = KerbAllocateEncryptionBuffer(
  210. EncryptionType,
  211. cbBufferSize,
  212. &tempInt,
  213. pEncryptionBuffer
  214. );
  215. if (KERB_SUCCESS(KerbErr))
  216. {
  217. *pcbEncryptionBufferSize = tempInt;
  218. }
  219. return KerbErr;
  220. }
  221. KERBERR
  222. KerbGetEncryptionOverhead(
  223. IN ULONG Algorithm,
  224. OUT PULONG pcbOverhead,
  225. OUT OPTIONAL PULONG pcbBlockSize
  226. )
  227. {
  228. PCRYPTO_SYSTEM pcsCrypt;
  229. NTSTATUS Status = STATUS_SUCCESS;
  230. Status = CDLocateCSystem(Algorithm, &pcsCrypt);
  231. if (!NT_SUCCESS(Status))
  232. {
  233. return (KDC_ERR_ETYPE_NOTSUPP);
  234. }
  235. *pcbOverhead = pcsCrypt->HeaderSize;
  236. if (pcbBlockSize)
  237. {
  238. *pcbBlockSize = pcsCrypt->BlockSize;
  239. }
  240. return (KDC_ERR_NONE);
  241. }
  242. KERBERR NTAPI
  243. KerbPackData(
  244. IN PVOID Data,
  245. IN ULONG PduValue,
  246. OUT PULONG pcbDataSize,
  247. OUT PUCHAR * MarshalledData
  248. )
  249. {
  250. TKerbErr KerbErr = KDC_ERR_NONE;
  251. ASN1encoding_t pEnc = NULL;
  252. ASN1error_e Asn1Err;
  253. KerbErr DBGCHK = KerbInitAsn(
  254. &pEnc, // we are encoding
  255. NULL
  256. );
  257. if (KERB_SUCCESS(KerbErr))
  258. {
  259. //
  260. // Encode the data type.
  261. //
  262. Asn1Err = ASN1_Encode(
  263. pEnc,
  264. Data,
  265. PduValue,
  266. ASN1ENCODE_ALLOCATEBUFFER,
  267. NULL, // pbBuf
  268. 0 // cbBufSize
  269. );
  270. if (!ASN1_SUCCEEDED(Asn1Err))
  271. {
  272. DebugPrintf(SSPI_ERROR, "KerbPackData failed to encode data: %d\n", Asn1Err);
  273. KerbErr DBGCHK = KRB_ERR_GENERIC;
  274. }
  275. else
  276. {
  277. *MarshalledData = (PUCHAR) MIDL_user_allocate(pEnc->len);
  278. if (*MarshalledData == NULL)
  279. {
  280. KerbErr DBGCHK = KRB_ERR_GENERIC;
  281. *pcbDataSize = 0;
  282. }
  283. else
  284. {
  285. RtlCopyMemory(*MarshalledData, pEnc->buf, pEnc->len);
  286. *pcbDataSize = pEnc->len;
  287. }
  288. ASN1_FreeEncoded(pEnc, pEnc->buf);
  289. }
  290. }
  291. KerbTermAsn(pEnc, NULL);
  292. return KerbErr;
  293. }
  294. KERBERR
  295. KerbConvertUnicodeStringToRealm(
  296. OUT PKERB_REALM pRealm,
  297. IN PUNICODE_STRING pString
  298. )
  299. {
  300. TKerbErr KerbErr;
  301. STRING TempString;
  302. RtlInitString(
  303. &TempString,
  304. NULL
  305. );
  306. *pRealm = NULL;
  307. KerbErr DBGCHK = KerbUnicodeStringToKerbString(
  308. &TempString,
  309. pString
  310. );
  311. if (KERB_SUCCESS(KerbErr))
  312. {
  313. *pRealm = TempString.Buffer;
  314. }
  315. return KerbErr;
  316. }
  317. KERBERR
  318. KerbUnicodeStringToKerbString(
  319. OUT PSTRING pKerbString,
  320. IN PUNICODE_STRING pString
  321. )
  322. {
  323. STRING TempString;
  324. if (!pKerbString)
  325. {
  326. return KRB_ERR_GENERIC;
  327. }
  328. TempString.Buffer = KerbAllocUtf8StrFromUnicodeString(pString);
  329. if (TempString.Buffer == NULL)
  330. {
  331. return KRB_ERR_GENERIC;
  332. }
  333. RtlInitString(
  334. &TempString,
  335. TempString.Buffer
  336. );
  337. *pKerbString = TempString;
  338. return KDC_ERR_NONE;
  339. }
  340. KERBERR
  341. KerbConvertKdcNameToPrincipalName(
  342. OUT PKERB_PRINCIPAL_NAME pPrincipalName,
  343. IN PKERB_INTERNAL_NAME pKdcName
  344. )
  345. {
  346. TKerbErr KerbErr = KDC_ERR_NONE;
  347. PKERB_PRINCIPAL_NAME_ELEM pElem;
  348. PKERB_PRINCIPAL_NAME_ELEM* pLast;
  349. STRING TempKerbString;
  350. ULONG Index;
  351. pPrincipalName->name_type = (int) pKdcName->NameType;
  352. pPrincipalName->name_string = NULL;
  353. pLast = &pPrincipalName->name_string;
  354. //
  355. // Index through the KDC name and add each element to the list
  356. //
  357. for (Index = 0; KERB_SUCCESS(KerbErr) && (Index < pKdcName->NameCount); Index++)
  358. {
  359. KerbErr DBGCHK = KerbUnicodeStringToKerbString(
  360. &TempKerbString,
  361. &pKdcName->Names[Index]
  362. );
  363. if (KERB_SUCCESS(KerbErr))
  364. {
  365. pElem = (PKERB_PRINCIPAL_NAME_ELEM) MIDL_user_allocate(sizeof(KERB_PRINCIPAL_NAME_ELEM));
  366. if (pElem == NULL)
  367. {
  368. KerbErr DBGCHK = KRB_ERR_GENERIC;
  369. }
  370. pElem->value = TempKerbString.Buffer;
  371. pElem->next = NULL;
  372. *pLast = pElem;
  373. pLast = &pElem->next;
  374. }
  375. }
  376. if (!KERB_SUCCESS(KerbErr))
  377. {
  378. KerbFreePrincipalName(pPrincipalName);
  379. }
  380. return KerbErr;
  381. }
  382. ULONG
  383. KerbConvertUlongToFlagUlong(
  384. IN ULONG Flag
  385. )
  386. {
  387. ULONG ReturnFlag;
  388. ((PUCHAR) &ReturnFlag)[0] = ((PUCHAR) &Flag)[3];
  389. ((PUCHAR) &ReturnFlag)[1] = ((PUCHAR) &Flag)[2];
  390. ((PUCHAR) &ReturnFlag)[2] = ((PUCHAR) &Flag)[1];
  391. ((PUCHAR) &ReturnFlag)[3] = ((PUCHAR) &Flag)[0];
  392. return ReturnFlag;
  393. }
  394. VOID
  395. KerbConvertLargeIntToGeneralizedTime(
  396. OUT PKERB_TIME pClientTime,
  397. OUT OPTIONAL INT* pClientUsec,
  398. IN PTimeStamp pTimeStamp
  399. )
  400. {
  401. TIME_FIELDS TimeFields;
  402. //
  403. // Special case zero time
  404. //
  405. #ifndef WIN32_CHICAGO
  406. if (pTimeStamp->QuadPart == 0)
  407. #else // WIN32_CHICAGO
  408. if (*pTimeStamp == 0)
  409. #endif // WIN32_CHICAGO
  410. {
  411. RtlZeroMemory(
  412. pClientTime,
  413. sizeof(KERB_TIME)
  414. );
  415. //
  416. // For MIT compatibility, time zero is 1/1/70
  417. //
  418. pClientTime->year = 1970;
  419. pClientTime->month = 1;
  420. pClientTime->day = 1;
  421. if (pClientUsec)
  422. {
  423. *pClientUsec = 0;
  424. }
  425. pClientTime->universal = TRUE;
  426. }
  427. else
  428. {
  429. #ifndef WIN32_CHICAGO
  430. RtlTimeToTimeFields(
  431. pTimeStamp,
  432. &TimeFields
  433. );
  434. #else // WIN32_CHICAGO
  435. RtlTimeToTimeFields(
  436. (LARGE_INTEGER*) pTimeStamp,
  437. &TimeFields
  438. );
  439. #endif // WIN32_CHICAGO
  440. //
  441. // Generalized times can only contains years up to four digits.
  442. //
  443. if (TimeFields.Year > 2037)
  444. {
  445. pClientTime->year = 2037;
  446. }
  447. else
  448. {
  449. pClientTime->year = TimeFields.Year;
  450. }
  451. pClientTime->month = (ASN1uint8_t) TimeFields.Month;
  452. pClientTime->day = (ASN1uint8_t) TimeFields.Day;
  453. pClientTime->hour = (ASN1uint8_t) TimeFields.Hour;
  454. pClientTime->minute = (ASN1uint8_t) TimeFields.Minute;
  455. pClientTime->second = (ASN1uint8_t) TimeFields.Second;
  456. // MIT kerberos does not support millseconds
  457. //
  458. pClientTime->millisecond = 0;
  459. if (pClientUsec)
  460. {
  461. //
  462. // Since we don't include milliseconds above, use the whole
  463. // thing here.
  464. //
  465. #ifndef WIN32_CHICAGO
  466. *pClientUsec = (pTimeStamp->LowPart / 10) % 1000000;
  467. #else // WIN32_CHICAGO
  468. *pClientUsec = (int) ((*pTimeStamp / 10) % 1000000);
  469. #endif // WIN32_CHICAGO
  470. }
  471. pClientTime->diff = 0;
  472. pClientTime->universal = TRUE;
  473. }
  474. }
  475. NTSTATUS
  476. KerbMapKerbError(
  477. IN KERBERR KerbError
  478. )
  479. {
  480. NTSTATUS Status;
  481. switch(KerbError)
  482. {
  483. case KDC_ERR_NONE:
  484. Status = STATUS_SUCCESS;
  485. break;
  486. case KDC_ERR_CLIENT_REVOKED:
  487. Status = STATUS_ACCOUNT_DISABLED;
  488. break;
  489. case KDC_ERR_KEY_EXPIRED:
  490. Status = STATUS_PASSWORD_EXPIRED;
  491. break;
  492. case KRB_ERR_GENERIC:
  493. Status = STATUS_INSUFFICIENT_RESOURCES;
  494. break;
  495. case KRB_AP_ERR_SKEW:
  496. case KRB_AP_ERR_TKT_NYV:
  497. // Note this was added because of the following scenario:
  498. // Let's say the dc and the client have the correct time. And the
  499. // server's time is off. We aren't going to get rid of the ticket for the
  500. // server on the client because it hasn't expired yet. But, the server
  501. // thinks it has. If event logging was turned on, then admins could look
  502. // at the server's event log and potentially deduce that the server's
  503. // time is off relative to the dc.
  504. case KRB_AP_ERR_TKT_EXPIRED:
  505. Status = STATUS_TIME_DIFFERENCE_AT_DC;
  506. break;
  507. case KDC_ERR_POLICY:
  508. Status = STATUS_ACCOUNT_RESTRICTION;
  509. break;
  510. case KDC_ERR_C_PRINCIPAL_UNKNOWN:
  511. Status = STATUS_NO_SUCH_USER;
  512. break;
  513. case KDC_ERR_S_PRINCIPAL_UNKNOWN:
  514. Status = STATUS_NO_TRUST_SAM_ACCOUNT;
  515. break;
  516. case KRB_AP_ERR_MODIFIED:
  517. case KDC_ERR_PREAUTH_FAILED:
  518. Status = STATUS_WRONG_PASSWORD;
  519. break;
  520. case KRB_ERR_RESPONSE_TOO_BIG:
  521. Status = STATUS_INVALID_BUFFER_SIZE;
  522. break;
  523. case KDC_ERR_PADATA_TYPE_NOSUPP:
  524. Status = STATUS_NOT_SUPPORTED;
  525. break;
  526. case KRB_AP_ERR_NOT_US:
  527. Status = SEC_E_WRONG_PRINCIPAL;
  528. break;
  529. case KDC_ERR_SVC_UNAVAILABLE:
  530. Status = STATUS_NO_LOGON_SERVERS;
  531. break;
  532. case KDC_ERR_WRONG_REALM:
  533. Status = STATUS_NO_LOGON_SERVERS;
  534. break;
  535. case KDC_ERR_CANT_VERIFY_CERTIFICATE:
  536. Status = TRUST_E_SYSTEM_ERROR;
  537. break;
  538. case KDC_ERR_INVALID_CERTIFICATE:
  539. Status = STATUS_INVALID_PARAMETER;
  540. break;
  541. case KDC_ERR_REVOKED_CERTIFICATE:
  542. Status = CRYPT_E_REVOKED;
  543. break;
  544. case KDC_ERR_REVOCATION_STATUS_UNKNOWN:
  545. Status = CRYPT_E_NO_REVOCATION_CHECK;
  546. break;
  547. case KDC_ERR_REVOCATION_STATUS_UNAVAILABLE:
  548. Status = CRYPT_E_REVOCATION_OFFLINE;
  549. break;
  550. case KDC_ERR_CLIENT_NAME_MISMATCH:
  551. case KERB_PKINIT_CLIENT_NAME_MISMATCH:
  552. case KDC_ERR_KDC_NAME_MISMATCH:
  553. Status = STATUS_PKINIT_NAME_MISMATCH;
  554. break;
  555. case KDC_ERR_PATH_NOT_ACCEPTED:
  556. Status = STATUS_TRUST_FAILURE;
  557. break;
  558. case KDC_ERR_ETYPE_NOTSUPP:
  559. Status = STATUS_KDC_UNKNOWN_ETYPE;
  560. break;
  561. case KDC_ERR_MUST_USE_USER2USER:
  562. case KRB_AP_ERR_USER_TO_USER_REQUIRED:
  563. Status = STATUS_USER2USER_REQUIRED;
  564. break;
  565. case KRB_AP_ERR_NOKEY:
  566. Status = STATUS_NO_KERB_KEY;
  567. break;
  568. case KRB_ERR_NAME_TOO_LONG:
  569. Status = STATUS_NAME_TOO_LONG;
  570. break;
  571. default:
  572. Status = STATUS_LOGON_FAILURE;
  573. }
  574. return (Status);
  575. }
  576. KERBERR NTAPI
  577. KerbUnpackData(
  578. IN PUCHAR pData,
  579. IN ULONG cbDataSize,
  580. IN ULONG PduValue,
  581. OUT PVOID * pDecodedData
  582. )
  583. {
  584. TKerbErr KerbErr = KDC_ERR_NONE;
  585. ASN1decoding_t pDec = NULL;
  586. ASN1error_e Asn1Err;
  587. if ((cbDataSize == 0) || (pData == NULL))
  588. {
  589. KerbErr DBGCHK = KRB_ERR_GENERIC;
  590. }
  591. if (KERB_SUCCESS(KerbErr))
  592. {
  593. KerbErr DBGCHK = KerbInitAsn(
  594. NULL,
  595. &pDec // we are decoding
  596. );
  597. }
  598. if (KERB_SUCCESS(KerbErr))
  599. {
  600. *pDecodedData = NULL;
  601. Asn1Err = ASN1_Decode(
  602. pDec,
  603. pDecodedData,
  604. PduValue,
  605. ASN1DECODE_SETBUFFER,
  606. (BYTE *) pData,
  607. cbDataSize
  608. );
  609. if (!ASN1_SUCCEEDED(Asn1Err))
  610. {
  611. if ((ASN1_ERR_BADARGS == Asn1Err) ||
  612. (ASN1_ERR_EOD == Asn1Err))
  613. {
  614. KerbErr DBGCHK = KDC_ERR_MORE_DATA;
  615. }
  616. else
  617. {
  618. KerbErr DBGCHK = KRB_ERR_GENERIC;
  619. }
  620. *pDecodedData = NULL;
  621. }
  622. }
  623. KerbTermAsn(NULL, pDec);
  624. return KerbErr;
  625. }
  626. PSTR
  627. KerbAllocUtf8StrFromUnicodeString(
  628. IN PUNICODE_STRING pUnicodeString
  629. )
  630. {
  631. PSTR pUtf8String = NULL;
  632. UINT cbUtf8StringLen;
  633. //
  634. // If the length is zero, return a null string.
  635. //
  636. if (pUnicodeString->Length == 0)
  637. {
  638. pUtf8String = (PSTR) MIDL_user_allocate(sizeof(CHAR));
  639. if (pUtf8String != NULL)
  640. {
  641. *pUtf8String = '\0';
  642. }
  643. return pUtf8String;
  644. }
  645. //
  646. // Determine the length of the Unicode string.
  647. //
  648. cbUtf8StringLen = WideCharToMultiByte(
  649. #ifndef WIN32_CHICAGO
  650. CP_UTF8,
  651. #else // WIN32_CHICAGO
  652. CP_OEMCP,
  653. #endif // WIN32_CHICAGO
  654. 0, // All characters can be mapped.
  655. pUnicodeString->Buffer,
  656. pUnicodeString->Length / sizeof(WCHAR),
  657. pUtf8String,
  658. 0,
  659. NULL,
  660. NULL
  661. );
  662. if ( cbUtf8StringLen == 0 )
  663. {
  664. return NULL;
  665. }
  666. //
  667. // Allocate a buffer for the Unicode string.
  668. //
  669. pUtf8String = (PSTR) MIDL_user_allocate( cbUtf8StringLen + 1 );
  670. if (pUtf8String == NULL)
  671. {
  672. return NULL;
  673. }
  674. //
  675. // Translate the string to Unicode.
  676. //
  677. cbUtf8StringLen = WideCharToMultiByte(
  678. #ifndef WIN32_CHICAGO
  679. CP_UTF8,
  680. #else // WIN32_CHICAGO
  681. CP_OEMCP,
  682. #endif // WIN32_CHICAGO
  683. 0, // All characters can be mapped.
  684. pUnicodeString->Buffer,
  685. pUnicodeString->Length / sizeof(WCHAR),
  686. pUtf8String,
  687. cbUtf8StringLen,
  688. NULL,
  689. NULL
  690. );
  691. if ( cbUtf8StringLen == 0 )
  692. {
  693. MIDL_user_free( pUtf8String );
  694. return NULL;
  695. }
  696. pUtf8String[cbUtf8StringLen] = '\0';
  697. return pUtf8String;
  698. }