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.

3438 lines
84 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. EEInfo.cxx
  5. Abstract:
  6. Extended Error Info public & private functions
  7. Author:
  8. Kamen Moutafov [KamenM]
  9. Revision History:
  10. KamenM Mar 2000 Initial version
  11. KamenM Oct 2000 Add caching of EEInfo blocks to
  12. solve Exchange perf problems
  13. --*/
  14. #include <precomp.hxx>
  15. #include <EEInfo.h>
  16. #include <EEInfo.hxx>
  17. const int MaxBinaryBlobSize = 4096; // 4K limit
  18. ExtendedErrorInfo *
  19. AllocateExtendedErrorInfoRecord (
  20. IN int NumberOfParams
  21. )
  22. /*++
  23. Routine Description:
  24. Allocates a memory block large enough to hold an
  25. extended error record with the specified number of
  26. parameters. It is allocated with MIDL_user_allocate.
  27. Arguments:
  28. NumberOfParams - number of paramaters to provide space
  29. for
  30. Return Value:
  31. The address of the block or NULL if out of memory
  32. --*/
  33. {
  34. ExtendedErrorInfo *EEInfo;
  35. THREAD *ThisThread;
  36. ThisThread = ThreadSelf();
  37. if (ThisThread)
  38. {
  39. EEInfo = ThisThread->GetCachedEEInfoBlock(NumberOfParams);
  40. }
  41. else
  42. EEInfo = NULL;
  43. if (EEInfo == NULL)
  44. {
  45. EEInfo = (ExtendedErrorInfo *) MIDL_user_allocate(sizeof(ExtendedErrorInfo) +
  46. (NumberOfParams - 1) * sizeof(ExtendedErrorParam));
  47. }
  48. if (EEInfo)
  49. EEInfo->nLen = (short)NumberOfParams;
  50. return EEInfo;
  51. }
  52. inline void
  53. FreeEEInfoRecordShallow (
  54. IN ExtendedErrorInfo *InfoToFree
  55. )
  56. /*++
  57. Routine Description:
  58. Frees only the eeinfo record - not any of
  59. the pointers contained in it.
  60. Arguments:
  61. InfoToFree - the eeinfo record
  62. Return Value:
  63. void
  64. --*/
  65. {
  66. MIDL_user_free(InfoToFree);
  67. }
  68. RPC_STATUS
  69. DuplicatePrivateString (
  70. IN EEUString *SourceString,
  71. OUT EEUString *DestString
  72. )
  73. /*++
  74. Routine Description:
  75. Takes a EEUString structure and makes a copy
  76. of it.
  77. Arguments:
  78. SourceString - the string to copy
  79. DestString - a placeholder allocated by caller to copy to
  80. Return Value:
  81. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  82. --*/
  83. {
  84. DestString->nLength = SourceString->nLength;
  85. DestString->pString = (LPWSTR)MIDL_user_allocate(DestString->nLength * sizeof(unsigned short));
  86. if (DestString->pString != NULL)
  87. {
  88. RpcpMemoryCopy(DestString->pString, SourceString->pString, DestString->nLength * sizeof(unsigned short));
  89. return RPC_S_OK;
  90. }
  91. else
  92. {
  93. return RPC_S_OUT_OF_MEMORY;
  94. }
  95. }
  96. RPC_STATUS
  97. DuplicatePrivateString (
  98. IN EEAString *SourceString,
  99. OUT EEAString *DestString
  100. )
  101. /*++
  102. Routine Description:
  103. Takes a EEAString structure and makes a copy
  104. of it.
  105. Arguments:
  106. SourceString - the string to copy
  107. DestString - a placeholder allocated by caller to copy to
  108. Return Value:
  109. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  110. --*/
  111. {
  112. DestString->nLength = SourceString->nLength;
  113. DestString->pString = (unsigned char *)MIDL_user_allocate(DestString->nLength);
  114. if (DestString->pString != NULL)
  115. {
  116. RpcpMemoryCopy(DestString->pString, SourceString->pString, DestString->nLength);
  117. return RPC_S_OK;
  118. }
  119. else
  120. {
  121. return RPC_S_OUT_OF_MEMORY;
  122. }
  123. }
  124. RPC_STATUS
  125. DuplicateBlob (
  126. IN void *SourceBlob,
  127. IN short Size,
  128. OUT void **DestBlob)
  129. /*++
  130. Routine Description:
  131. Takes a blob and makes a copy of it.
  132. Arguments:
  133. SourceBlob - the blob to copy
  134. Size - the size of the blob
  135. DestBlob - a placeholder where a pointer to the copied
  136. buffer will be put
  137. Return Value:
  138. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  139. --*/
  140. {
  141. void *CopiedBlob;
  142. CopiedBlob = MIDL_user_allocate(Size);
  143. if (CopiedBlob)
  144. {
  145. RpcpMemoryCopy(CopiedBlob, SourceBlob, Size);
  146. *DestBlob = CopiedBlob;
  147. return RPC_S_OK;
  148. }
  149. else
  150. {
  151. return RPC_S_OUT_OF_MEMORY;
  152. }
  153. }
  154. RPC_STATUS
  155. DuplicatePrivateBlob (
  156. IN BinaryEEInfo *SourceBlob,
  157. OUT BinaryEEInfo *DestBlob)
  158. /*++
  159. Routine Description:
  160. Takes a binary param and makes a copy of it.
  161. Arguments:
  162. SourceBlob - the blob to copy
  163. DestBlob - a placeholder allocated by caller to copy to
  164. Return Value:
  165. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  166. --*/
  167. {
  168. RPC_STATUS Status;
  169. Status = DuplicateBlob(SourceBlob->pBlob, SourceBlob->nSize, (PVOID *)&DestBlob->pBlob);
  170. if (Status == RPC_S_OK)
  171. {
  172. DestBlob->nSize = SourceBlob->nSize;
  173. }
  174. return Status;
  175. }
  176. RPC_STATUS
  177. ConvertPublicStringToPrivateString (
  178. IN LPWSTR PublicString,
  179. OUT EEUString *PrivateString)
  180. /*++
  181. Routine Description:
  182. Takes a LPWSTR string and makes a copy
  183. of it into a EEUString structure
  184. Arguments:
  185. PublicString - the string to copy - cannot be NULL
  186. PrivateString - a placeholder allocated by caller to copy to
  187. Return Value:
  188. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  189. --*/
  190. {
  191. // the StringLength is in bytes
  192. int StringLength = (wcslen(PublicString) + 1) * 2;
  193. LPWSTR CopiedString;
  194. CopiedString = (LPWSTR)MIDL_user_allocate(StringLength);
  195. if (CopiedString)
  196. {
  197. RpcpMemoryCopy(CopiedString, PublicString, StringLength);
  198. PrivateString->pString = CopiedString;
  199. PrivateString->nLength = (short)StringLength / 2;
  200. return RPC_S_OK;
  201. }
  202. else
  203. {
  204. return RPC_S_OUT_OF_MEMORY;
  205. }
  206. }
  207. RPC_STATUS
  208. ConvertPublicStringToPrivateString (
  209. IN LPSTR PublicString,
  210. OUT EEAString *PrivateString)
  211. /*++
  212. Routine Description:
  213. Takes a LPSTR string and makes a copy
  214. of it into a EEAString structure
  215. Arguments:
  216. PublicString - the string to copy - cannot be NULL
  217. PrivateString - a placeholder allocated by caller to copy to
  218. Return Value:
  219. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  220. --*/
  221. {
  222. int StringLength = strlen(PublicString) + 1;
  223. LPSTR CopiedString;
  224. CopiedString = (LPSTR)MIDL_user_allocate(StringLength);
  225. if (CopiedString)
  226. {
  227. RpcpMemoryCopy(CopiedString, PublicString, StringLength);
  228. PrivateString->pString = (unsigned char *)CopiedString;
  229. PrivateString->nLength = (short)StringLength;
  230. return RPC_S_OK;
  231. }
  232. else
  233. {
  234. return RPC_S_OUT_OF_MEMORY;
  235. }
  236. }
  237. RPC_STATUS
  238. ConvertPublicBlobToPrivateBlob (
  239. IN BinaryParam *PublicBlob,
  240. OUT BinaryEEInfo *PrivateBlob)
  241. /*++
  242. Routine Description:
  243. Takes a binary param and converts it to private format.
  244. Arguments:
  245. PublicBlob - the blob to copy - cannot be NULL
  246. PrivateBlob - a placeholder allocated by caller to copy to
  247. Return Value:
  248. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  249. --*/
  250. {
  251. unsigned char *CopiedBlob;
  252. if (PublicBlob->Size > MaxBinaryBlobSize)
  253. {
  254. return ERROR_INVALID_PARAMETER;
  255. }
  256. RPC_STATUS Status;
  257. Status = DuplicateBlob(PublicBlob->Buffer, PublicBlob->Size, (PVOID *)&PrivateBlob->pBlob);
  258. if (Status == RPC_S_OK)
  259. {
  260. PrivateBlob->nSize = PublicBlob->Size;
  261. }
  262. return Status;
  263. }
  264. RPC_STATUS
  265. ConvertPrivateStringToPublicString (
  266. IN EEUString *PrivateString,
  267. IN BOOL CopyStrings,
  268. OUT LPWSTR *PublicString
  269. )
  270. /*++
  271. Routine Description:
  272. Takes a EEUString and makes a copy
  273. of it into a LPWSTR
  274. Arguments:
  275. PrivateString - the string to copy
  276. CopyStrings - if non-zero this routine will allocate
  277. space on the process heap and will copy the string.
  278. If zero, it will alias the PublicString to the
  279. pString member of PrivateString
  280. PublicString - the string to copy to
  281. Return Value:
  282. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  283. --*/
  284. {
  285. LPWSTR ReturnString;
  286. int StringLength; // in bytes
  287. if (CopyStrings)
  288. {
  289. StringLength = PrivateString->nLength * 2;
  290. ReturnString = (LPWSTR)RtlAllocateHeap(RtlProcessHeap(), 0, StringLength);
  291. if (ReturnString == NULL)
  292. return RPC_S_OUT_OF_MEMORY;
  293. RpcpMemoryCopy(ReturnString, PrivateString->pString, StringLength);
  294. }
  295. else
  296. {
  297. ReturnString = PrivateString->pString;
  298. }
  299. *PublicString = ReturnString;
  300. return RPC_S_OK;
  301. }
  302. RPC_STATUS
  303. ConvertPrivateStringToPublicString (
  304. IN EEAString *PrivateString,
  305. IN BOOL CopyStrings,
  306. OUT LPSTR *PublicString
  307. )
  308. /*++
  309. Routine Description:
  310. Takes a EEAString and makes a copy
  311. of it into a LPSTR
  312. Arguments:
  313. PrivateString - the string to copy
  314. CopyStrings - if non-zero this routine will allocate
  315. space on the process heap and will copy the string.
  316. If zero, it will alias the PublicString to the
  317. pString member of PrivateString
  318. PublicString - the string to copy to
  319. Return Value:
  320. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  321. --*/
  322. {
  323. LPSTR ReturnString;
  324. if (CopyStrings)
  325. {
  326. ReturnString = (LPSTR)RtlAllocateHeap(RtlProcessHeap(), 0, PrivateString->nLength);
  327. if (ReturnString == NULL)
  328. return RPC_S_OUT_OF_MEMORY;
  329. RpcpMemoryCopy(ReturnString, PrivateString->pString, PrivateString->nLength);
  330. }
  331. else
  332. {
  333. ReturnString = (char *)PrivateString->pString;
  334. }
  335. *PublicString = ReturnString;
  336. return RPC_S_OK;
  337. }
  338. RPC_STATUS
  339. ConvertPrivateBlobToPublicBlob (
  340. IN BinaryEEInfo *PrivateBlob,
  341. IN BOOL CopyStrings,
  342. OUT BinaryParam *PublicBlob
  343. )
  344. /*++
  345. Routine Description:
  346. Takes a private blob and makes a copy
  347. of it into a public blob format
  348. Arguments:
  349. PrivateBlob - the blob to copy
  350. CopyStrings - if non-zero this routine will allocate
  351. space on the process heap and will copy the blob.
  352. If zero, it will alias the PublicBlob to the
  353. Blob.pBlob member of PrivateBlob
  354. PublicBlob - the blob to copy to
  355. Return Value:
  356. RPC_S_OK or RPC_S_OUT_OF_MEMORY
  357. --*/
  358. {
  359. void *ReturnBuffer;
  360. if (CopyStrings)
  361. {
  362. ReturnBuffer = RtlAllocateHeap(RtlProcessHeap(), 0, PrivateBlob->nSize);
  363. if (ReturnBuffer == NULL)
  364. return RPC_S_OUT_OF_MEMORY;
  365. RpcpMemoryCopy(ReturnBuffer, PrivateBlob->pBlob, PrivateBlob->nSize);
  366. }
  367. else
  368. {
  369. ReturnBuffer = PrivateBlob->pBlob;
  370. }
  371. PublicBlob->Buffer = ReturnBuffer;
  372. PublicBlob->Size = PrivateBlob->nSize;
  373. return RPC_S_OK;
  374. }
  375. inline void
  376. FreePublicStringIfNecessary (
  377. OUT LPWSTR PublicString,
  378. IN BOOL CopyStrings
  379. )
  380. /*++
  381. Routine Description:
  382. Deletes the string if necessary
  383. Arguments:
  384. PublicString - the string to delete. Must be on the
  385. process heap
  386. CopyStrings - the value of the CopyStrings parameter
  387. when RpcErrorGetNextRecord was called. If non-zero
  388. the string will be freed. Otherwise, the function
  389. is a no-op
  390. Return Value:
  391. void
  392. --*/
  393. {
  394. if (CopyStrings)
  395. {
  396. if (PublicString)
  397. {
  398. RtlFreeHeap(RtlProcessHeap(), 0, PublicString);
  399. }
  400. }
  401. }
  402. RPC_STATUS
  403. ConvertPublicParamToPrivateParam (
  404. IN RPC_EE_INFO_PARAM *PublicParam,
  405. OUT ExtendedErrorParam *PrivateParam
  406. )
  407. /*++
  408. Routine Description:
  409. Takes a parameter in format RPC_EE_INFO_PARAM and
  410. converts it to ExtendedErrorParam.
  411. Arguments:
  412. PublicParam - the parameter to copy.
  413. PrivateParam - the parameter to copy to
  414. Return Value:
  415. RPC_S_OK, RPC_S_INTERNAL_ERROR, RPC_S_OUT_OF_MEMORY
  416. --*/
  417. {
  418. RPC_STATUS RpcStatus = RPC_S_OK;
  419. PrivateParam->Type = (ExtendedErrorParamTypesInternal)PublicParam->ParameterType;
  420. switch (PrivateParam->Type)
  421. {
  422. case eeptiAnsiString:
  423. RpcStatus = ConvertPublicStringToPrivateString(PublicParam->u.AnsiString,
  424. &PrivateParam->AnsiString);
  425. break;
  426. case eeptiUnicodeString:
  427. RpcStatus = ConvertPublicStringToPrivateString(PublicParam->u.UnicodeString,
  428. &PrivateParam->UnicodeString);
  429. break;
  430. case eeptiLongVal:
  431. PrivateParam->LVal = PublicParam->u.LVal;
  432. break;
  433. case eeptiShortVal:
  434. PrivateParam->IVal = PublicParam->u.SVal;
  435. break;
  436. case eeptiPointerVal:
  437. PrivateParam->PVal = (ULONGLONG)PublicParam->u.PVal;
  438. break;
  439. case eeptiNone:
  440. break;
  441. case eeptiBinary:
  442. RpcStatus = ConvertPublicBlobToPrivateBlob(&PublicParam->u.BVal,
  443. &PrivateParam->Blob);
  444. break;
  445. default:
  446. ASSERT(FALSE);
  447. RpcStatus = ERROR_INVALID_PARAMETER;
  448. }
  449. return RpcStatus;
  450. }
  451. RPC_STATUS
  452. ConvertPrivateParamToPublicParam (
  453. IN ExtendedErrorParam *PrivateParam,
  454. IN BOOL CopyStrings,
  455. OUT RPC_EE_INFO_PARAM *PublicParam
  456. )
  457. /*++
  458. Routine Description:
  459. Takes a parameter in format ExtendedErrorParam and
  460. converts it to RPC_EE_INFO_PARAM.
  461. Arguments:
  462. PrivateParam - the parameter to copy
  463. CopyStrings - if non-zero, this function will allocate
  464. space for any strings to be copied on the process
  465. heap and will copy the strings. If FALSE, it
  466. will alias the output pointers to RPC internal
  467. data structures
  468. PublicParam - the parameter to copy to
  469. Return Value:
  470. RPC_S_OK, RPC_S_INTERNAL_ERROR, RPC_S_OUT_OF_MEMORY
  471. --*/
  472. {
  473. RPC_STATUS RpcStatus = RPC_S_OK;
  474. PublicParam->ParameterType = (ExtendedErrorParamTypes)PrivateParam->Type;
  475. switch (PublicParam->ParameterType)
  476. {
  477. case eeptAnsiString:
  478. RpcStatus = ConvertPrivateStringToPublicString(&PrivateParam->AnsiString,
  479. CopyStrings,
  480. &PublicParam->u.AnsiString);
  481. break;
  482. case eeptUnicodeString:
  483. RpcStatus = ConvertPrivateStringToPublicString(&PrivateParam->UnicodeString,
  484. CopyStrings,
  485. &PublicParam->u.UnicodeString);
  486. break;
  487. case eeptLongVal:
  488. PublicParam->u.LVal = PrivateParam->LVal;
  489. break;
  490. case eeptShortVal:
  491. PublicParam->u.SVal = PrivateParam->IVal;
  492. break;
  493. case eeptPointerVal:
  494. PublicParam->u.PVal = PrivateParam->PVal;
  495. break;
  496. case eeptNone:
  497. break;
  498. case eeptBinary:
  499. RpcStatus = ConvertPrivateBlobToPublicBlob(&PrivateParam->Blob,
  500. CopyStrings,
  501. &PublicParam->u.BVal);
  502. break;
  503. default:
  504. ASSERT(FALSE);
  505. RpcStatus = RPC_S_INTERNAL_ERROR;
  506. }
  507. return RpcStatus;
  508. }
  509. void
  510. InitializePrivateEEInfo (
  511. IN ExtendedErrorInfo *ErrorInfo
  512. )
  513. /*++
  514. Routine Description:
  515. Initializes the common data members of the ExtendedErrorInfo
  516. structure.
  517. Arguments:
  518. ErrorInfo - the structure to initialize
  519. Return Value:
  520. void
  521. --*/
  522. {
  523. ErrorInfo->Next = NULL;
  524. ErrorInfo->ComputerName.Type = eecnpNotPresent;
  525. ErrorInfo->ProcessID = GetCurrentProcessId();
  526. GetSystemTimeAsFileTime((FILETIME *)&ErrorInfo->TimeStamp);
  527. ErrorInfo->Flags = 0;
  528. }
  529. RPC_STATUS
  530. ConvertPublicEEInfoToPrivateEEInfo (
  531. IN RPC_EXTENDED_ERROR_INFO *PublicEEInfo,
  532. IN short DetectionLocation,
  533. OUT ExtendedErrorInfo *PrivateEEInfo
  534. )
  535. /*++
  536. Routine Description:
  537. Takes a RPC_EXTENDED_ERROR_INFO record and converts
  538. it to an ExtendedErrorInfo record.
  539. Arguments:
  540. PublicEEInfo - the public record to convert
  541. DetectionLocation - the detection location to use in the
  542. private record.
  543. PrivateEEInfo - the private record to copy to
  544. Return Value:
  545. RPC_S_OK or RPC_S_* error
  546. --*/
  547. {
  548. int NumberOfParams;
  549. int i;
  550. RPC_STATUS RpcStatus = RPC_S_OK;
  551. ASSERT(PrivateEEInfo != NULL);
  552. ASSERT(PrivateEEInfo->nLen == PublicEEInfo->NumberOfParameters);
  553. if (PublicEEInfo->Version != RPC_EEINFO_VERSION)
  554. return RPC_S_INVALID_LEVEL;
  555. InitializePrivateEEInfo(PrivateEEInfo);
  556. // EEInfoGCCOM can come externally. If it's not, set it to
  557. // EEInfoGCApplication
  558. if (PublicEEInfo->GeneratingComponent != EEInfoGCCOM)
  559. {
  560. PrivateEEInfo->GeneratingComponent = EEInfoGCApplication;
  561. }
  562. else
  563. {
  564. PrivateEEInfo->GeneratingComponent = EEInfoGCCOM;
  565. }
  566. PrivateEEInfo->Status = PublicEEInfo->Status;
  567. PrivateEEInfo->DetectionLocation = DetectionLocation;
  568. // the next line should have been executed by the allocating code
  569. //PrivateEEInfo->nLen = PublicEEInfo->NumberOfParameters;
  570. NumberOfParams = PrivateEEInfo->nLen;
  571. for (i = 0; i < NumberOfParams; i ++)
  572. {
  573. if ((PublicEEInfo->Parameters[i].ParameterType < eeptAnsiString)
  574. || (PublicEEInfo->Parameters[i].ParameterType > eeptBinary))
  575. RpcStatus = ERROR_INVALID_PARAMETER;
  576. if (RpcStatus == RPC_S_OK)
  577. {
  578. RpcStatus = ConvertPublicParamToPrivateParam(&PublicEEInfo->Parameters[i],
  579. &PrivateEEInfo->Params[i]);
  580. }
  581. if (RpcStatus != RPC_S_OK)
  582. {
  583. // go backward and free all memory
  584. i --;
  585. for (; i >= 0; i --)
  586. {
  587. FreeEEInfoPrivateParam(&PrivateEEInfo->Params[i]);
  588. }
  589. break;
  590. }
  591. }
  592. return RpcStatus;
  593. }
  594. RPC_STATUS
  595. ConvertPrivateEEInfoToPublicEEInfo (
  596. IN ExtendedErrorInfo *PrivateEEInfo,
  597. IN BOOL CopyStrings,
  598. OUT RPC_EXTENDED_ERROR_INFO *PublicEEInfo
  599. )
  600. /*++
  601. Routine Description:
  602. Takes an ExtendedErrorInfo record and converts
  603. it to a RPC_EXTENDED_ERROR_INFO record.
  604. Arguments:
  605. PrivateEEInfo - the private record to convert
  606. CopyStrings - If non-zero, all strings will be allocated
  607. space on the process heap and will be copied. Otherwise
  608. they will be aliased to the privated data structure
  609. strings
  610. PublicEEInfo - the public record to copy to
  611. Return Value:
  612. RPC_S_OK or RPC_S_* error
  613. --*/
  614. {
  615. BOOL Result;
  616. int NumberOfParams;
  617. int i;
  618. RPC_STATUS RpcStatus;
  619. ASSERT (PublicEEInfo != NULL);
  620. if (PublicEEInfo->Version != RPC_EEINFO_VERSION)
  621. return RPC_S_INVALID_LEVEL;
  622. if (PublicEEInfo->NumberOfParameters < PrivateEEInfo->nLen)
  623. return RPC_S_BUFFER_TOO_SMALL;
  624. if (PublicEEInfo->Flags & (~EEInfoValidInputFlags))
  625. return RPC_S_INVALID_LEVEL;
  626. if (PrivateEEInfo->ComputerName.Type == eecnpNotPresent)
  627. {
  628. PublicEEInfo->ComputerName = NULL;
  629. }
  630. else
  631. {
  632. RpcStatus = ConvertPrivateStringToPublicString(&PrivateEEInfo->ComputerName.Name,
  633. CopyStrings, &PublicEEInfo->ComputerName);
  634. if (RpcStatus != RPC_S_OK)
  635. return RpcStatus;
  636. }
  637. PublicEEInfo->ProcessID = PrivateEEInfo->ProcessID;
  638. if (PublicEEInfo->Flags & EEInfoUseFileTime)
  639. {
  640. RpcpMemoryCopy(&PublicEEInfo->u.FileTime, &PrivateEEInfo->TimeStamp, sizeof(FILETIME));
  641. }
  642. else
  643. {
  644. Result = FileTimeToSystemTime((FILETIME *)&PrivateEEInfo->TimeStamp,
  645. &PublicEEInfo->u.SystemTime);
  646. if (Result == 0)
  647. return GetLastError();
  648. }
  649. PublicEEInfo->GeneratingComponent = PrivateEEInfo->GeneratingComponent;
  650. PublicEEInfo->Status = PrivateEEInfo->Status;
  651. PublicEEInfo->DetectionLocation = PrivateEEInfo->DetectionLocation;
  652. PublicEEInfo->Flags = PrivateEEInfo->Flags;
  653. // restore the consistency of the flags, if necessary
  654. if (PrivateEEInfo->Next)
  655. {
  656. // if there is next record, and its flags indicate that
  657. // a previous record is missing
  658. if (PrivateEEInfo->Next->Flags & EEInfoPreviousRecordsMissing)
  659. PublicEEInfo->Flags |= EEInfoNextRecordsMissing;
  660. }
  661. NumberOfParams = PrivateEEInfo->nLen;
  662. PublicEEInfo->NumberOfParameters = NumberOfParams;
  663. for (i = 0; i < NumberOfParams; i ++)
  664. {
  665. // convert the params
  666. RpcStatus = ConvertPrivateParamToPublicParam(&PrivateEEInfo->Params[i],
  667. CopyStrings, &PublicEEInfo->Parameters[i]);
  668. if (RpcStatus != RPC_S_OK)
  669. {
  670. // go back, and free eveyrthing
  671. FreePublicStringIfNecessary(PublicEEInfo->ComputerName, CopyStrings);
  672. i --;
  673. for ( ; i >= 0; i --)
  674. {
  675. FreeEEInfoPublicParam(&PublicEEInfo->Parameters[i], CopyStrings);
  676. }
  677. return RpcStatus;
  678. }
  679. }
  680. return RPC_S_OK;
  681. }
  682. RPC_STATUS
  683. CloneEEInfoParam (
  684. IN ExtendedErrorParam *SourceParam,
  685. OUT ExtendedErrorParam *DestParam
  686. )
  687. /*++
  688. Routine Description:
  689. Makes an exact deep copy of an ExtendedErrorParam structure
  690. Arguments:
  691. SourceParam - the parameter to copy from
  692. DestParam - the parameter to copy to
  693. Return Value:
  694. RPC_S_OK or RPC_S_* error
  695. --*/
  696. {
  697. RPC_STATUS RpcStatus = RPC_S_OK;
  698. ASSERT (DestParam != NULL);
  699. switch (SourceParam->Type)
  700. {
  701. case eeptiAnsiString:
  702. RpcStatus = DuplicatePrivateString(&SourceParam->AnsiString,
  703. &DestParam->AnsiString);
  704. break;
  705. case eeptiUnicodeString:
  706. RpcStatus = DuplicatePrivateString(&SourceParam->UnicodeString,
  707. &DestParam->UnicodeString);
  708. break;
  709. case eeptiLongVal:
  710. DestParam->LVal = SourceParam->LVal;
  711. break;
  712. case eeptiShortVal:
  713. DestParam->IVal = SourceParam->IVal;
  714. break;
  715. case eeptiPointerVal:
  716. DestParam->PVal = SourceParam->PVal;
  717. break;
  718. case eeptiNone:
  719. break;
  720. case eeptiBinary:
  721. RpcStatus = DuplicatePrivateBlob(&SourceParam->Blob,
  722. &DestParam->Blob);
  723. break;
  724. default:
  725. ASSERT(0);
  726. RpcStatus = RPC_S_INTERNAL_ERROR;
  727. }
  728. DestParam->Type = SourceParam->Type;
  729. return RpcStatus;
  730. }
  731. RPC_STATUS
  732. CloneEEInfoRecord (
  733. IN ExtendedErrorInfo *SourceInfo,
  734. OUT ExtendedErrorInfo **DestInfo
  735. )
  736. /*++
  737. Routine Description:
  738. Makes an exact deep copy of a single ExtendedErrorInfo record
  739. Arguments:
  740. SourceInfo - the record to copy from
  741. DestInfo - the record to copy to
  742. Return Value:
  743. RPC_S_OK or RPC_S_* error
  744. --*/
  745. {
  746. ExtendedErrorInfo *NewInfo;
  747. int NumberOfParams;
  748. int i;
  749. RPC_STATUS RpcStatus;
  750. EEUString *ComputerNameToFree = NULL;
  751. *DestInfo = NULL;
  752. NumberOfParams = SourceInfo->nLen;
  753. NewInfo = AllocateExtendedErrorInfoRecord(NumberOfParams);
  754. if (NewInfo == NULL)
  755. return RPC_S_OUT_OF_MEMORY;
  756. // shallow copy all the fields. This is good for most fields
  757. // we will process the ones that need deep copy further down.
  758. // we copy everything, but the first param, which may require
  759. // deep copying
  760. RpcpMemoryCopy(NewInfo, SourceInfo, sizeof(ExtendedErrorInfo) - sizeof(ExtendedErrorParam));
  761. // N.B. Zero out the next field before any failure paths
  762. NewInfo->Next = NULL;
  763. if (SourceInfo->ComputerName.Type == eecnpPresent)
  764. {
  765. RpcStatus = DuplicatePrivateString(&SourceInfo->ComputerName.Name,
  766. &NewInfo->ComputerName.Name);
  767. if (RpcStatus != RPC_S_OK)
  768. {
  769. FreeEEInfoRecordShallow(NewInfo);
  770. return RpcStatus;
  771. }
  772. ComputerNameToFree = &NewInfo->ComputerName.Name;
  773. }
  774. for (i = 0; i < NumberOfParams; i ++)
  775. {
  776. RpcStatus = CloneEEInfoParam(&SourceInfo->Params[i],
  777. &NewInfo->Params[i]);
  778. if (RpcStatus != RPC_S_OK)
  779. {
  780. if (ComputerNameToFree)
  781. MIDL_user_free(ComputerNameToFree->pString);
  782. i --;
  783. for ( ; i >= 0; i --)
  784. {
  785. FreeEEInfoPrivateParam(&NewInfo->Params[i]);
  786. }
  787. FreeEEInfoRecordShallow(NewInfo);
  788. return RpcStatus;
  789. }
  790. }
  791. *DestInfo = NewInfo;
  792. return RPC_S_OK;
  793. }
  794. RPC_STATUS
  795. CloneEEInfoChain (
  796. IN ExtendedErrorInfo *SourceEEInfo,
  797. OUT ExtendedErrorInfo **DestEEInfo
  798. )
  799. /*++
  800. Routine Description:
  801. Makes an exact deep copy of an ExtendedErrorInfo chain
  802. Arguments:
  803. SourceEEInfo - the head of the chain to copy from
  804. DestEEInfo - a pointer to the head of the cloned chain.
  805. The memory for the head of the cloned chain will be
  806. allocated by this function and the given pointer
  807. will be set to point to it.
  808. Return Value:
  809. RPC_S_OK or RPC_S_* error
  810. --*/
  811. {
  812. ExtendedErrorInfo *CurrentInfo, *NewInfo, *NewInfoHead = NULL;
  813. ExtendedErrorInfo *LastNewInfo = NULL;
  814. RPC_STATUS RpcStatus;
  815. CurrentInfo = SourceEEInfo;
  816. while (CurrentInfo != NULL)
  817. {
  818. RpcStatus = CloneEEInfoRecord(CurrentInfo, &NewInfo);
  819. if (RpcStatus != RPC_S_OK)
  820. {
  821. if (NewInfoHead != NULL)
  822. FreeEEInfoChain(NewInfoHead);
  823. return RpcStatus;
  824. }
  825. if (NewInfoHead == NULL)
  826. NewInfoHead = NewInfo;
  827. if (LastNewInfo != NULL)
  828. LastNewInfo->Next = NewInfo;
  829. // advance both chains
  830. LastNewInfo = NewInfo;
  831. CurrentInfo = CurrentInfo->Next;
  832. }
  833. *DestEEInfo = NewInfoHead;
  834. return RPC_S_OK;
  835. }
  836. const ULONG EnumSignatureLive = 0xfcfcfcfc;
  837. const ULONG EnumSignatureDead = 0xfdfdfdfd;
  838. void
  839. InitializeEnumHandleWithEEInfo (
  840. IN ExtendedErrorInfo *EEInfo,
  841. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  842. )
  843. /*++
  844. Routine Description:
  845. Initializes the common fields of a RPC_ERROR_ENUM_HANDLE
  846. structure
  847. Arguments:
  848. EEInfo - the chain we're enumerating from
  849. EnumHandle - the structure to initialize
  850. Return Value:
  851. void
  852. --*/
  853. {
  854. ASSERT(EEInfo != NULL);
  855. EnumHandle->Signature = EnumSignatureLive;
  856. EnumHandle->Head = EEInfo;
  857. EnumHandle->CurrentPos = EEInfo;
  858. }
  859. RPC_STATUS
  860. RpcpErrorStartEnumerationFromEEInfo (
  861. IN ExtendedErrorInfo *EEInfo,
  862. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  863. )
  864. /*++
  865. Routine Description:
  866. Starts an eeinfo enumeration using the passed
  867. EEInfo structure to start the enumeration
  868. Arguments:
  869. EEInfo - the chain we will enumerate
  870. EnumHandle - the enumeration handle
  871. Return Value:
  872. RPC_S_OK or RPC_S_* error
  873. --*/
  874. {
  875. ExtendedErrorInfo *ClonedEEInfo;
  876. RPC_STATUS RpcStatus;
  877. RpcStatus = CloneEEInfoChain(EEInfo, &ClonedEEInfo);
  878. if (RpcStatus != RPC_S_OK)
  879. return RpcStatus;
  880. InitializeEnumHandleWithEEInfo(ClonedEEInfo, EnumHandle);
  881. return RPC_S_OK;
  882. }
  883. RPCRTAPI
  884. RPC_STATUS
  885. RPC_ENTRY
  886. RpcErrorStartEnumeration (
  887. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  888. )
  889. /*++
  890. Routine Description:
  891. Starts an eeinfo enumeration using the eeinfo on
  892. the thread
  893. Arguments:
  894. EnumHandle - the enumeration handle. Allocated by caller
  895. Return Value:
  896. RPC_S_OK or RPC_S_* error
  897. --*/
  898. {
  899. ExtendedErrorInfo *ClonedEEInfo, *EEInfo;
  900. RPC_STATUS RpcStatus;
  901. THREAD *Thread;
  902. // get the EEInfo from the Teb
  903. Thread = RpcpGetThreadPointer();
  904. if (Thread == NULL)
  905. return RPC_S_ENTRY_NOT_FOUND;
  906. EEInfo = Thread->GetEEInfo();
  907. if (EEInfo == NULL)
  908. return RPC_S_ENTRY_NOT_FOUND;
  909. return RpcpErrorStartEnumerationFromEEInfo(EEInfo, EnumHandle);
  910. }
  911. RPCRTAPI
  912. RPC_STATUS
  913. RPC_ENTRY
  914. RpcErrorGetNextRecord (
  915. IN RPC_ERROR_ENUM_HANDLE *EnumHandle,
  916. IN BOOL CopyStrings,
  917. OUT RPC_EXTENDED_ERROR_INFO *ErrorInfo
  918. )
  919. /*++
  920. Routine Description:
  921. Retrieves the next private record from the enumeration
  922. and converts it to public format
  923. Arguments:
  924. EnumHandle - the enumeration handle
  925. CopyStrings - if non-zero, all strings converted to public
  926. format will be allocated space for on the process heap
  927. and will be copied there. If FALSE, the strings in the
  928. public structures will be aliases to the private structure
  929. ErrorInfo - the public record that will be filled on output
  930. Return Value:
  931. RPC_S_OK or RPC_S_* error
  932. --*/
  933. {
  934. RPC_STATUS RpcStatus;
  935. ExtendedErrorInfo *CurrentRecord;
  936. ASSERT(EnumHandle != NULL);
  937. ASSERT(EnumHandle->Head != NULL);
  938. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  939. if (EnumHandle->Signature != EnumSignatureLive)
  940. return ERROR_INVALID_PARAMETER;
  941. if (EnumHandle->CurrentPos == NULL)
  942. return RPC_S_ENTRY_NOT_FOUND;
  943. CurrentRecord = (ExtendedErrorInfo *) EnumHandle->CurrentPos;
  944. RpcStatus = ConvertPrivateEEInfoToPublicEEInfo(CurrentRecord,
  945. CopyStrings, ErrorInfo);
  946. if (RpcStatus == RPC_S_OK)
  947. {
  948. EnumHandle->CurrentPos = CurrentRecord->Next;
  949. }
  950. return RpcStatus;
  951. }
  952. RPCRTAPI
  953. RPC_STATUS
  954. RPC_ENTRY
  955. RpcErrorEndEnumeration (
  956. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  957. )
  958. /*++
  959. Routine Description:
  960. Finished the enumeration and frees all resources associated with
  961. the enumeration
  962. Arguments:
  963. EnumHandle - the enumeration handle
  964. Return Value:
  965. RPC_S_OK or RPC_S_* error - can fail only if given invalid parameters
  966. --*/
  967. {
  968. ExtendedErrorInfo *EEInfoChain;
  969. ASSERT(EnumHandle != NULL);
  970. ASSERT(EnumHandle->Head != NULL);
  971. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  972. if (EnumHandle->Signature != EnumSignatureLive)
  973. return ERROR_INVALID_PARAMETER;
  974. EEInfoChain = (ExtendedErrorInfo *)EnumHandle->Head;
  975. FreeEEInfoChain(EEInfoChain);
  976. EnumHandle->Head = NULL;
  977. EnumHandle->Signature = EnumSignatureDead;
  978. return RPC_S_OK;
  979. }
  980. RPCRTAPI
  981. RPC_STATUS
  982. RPC_ENTRY
  983. RpcErrorResetEnumeration (
  984. IN OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  985. )
  986. /*++
  987. Routine Description:
  988. Reset the enumeration so that the next call to
  989. RpcErrorGetNextRecord returns the first record
  990. again.
  991. Arguments:
  992. EnumHandle - the enumeration handle
  993. Return Value:
  994. RPC_S_OK or RPC_S_* error - can fail only if given invalid
  995. parameters
  996. --*/
  997. {
  998. ASSERT(EnumHandle != NULL);
  999. ASSERT(EnumHandle->Head != NULL);
  1000. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1001. if (EnumHandle->Signature != EnumSignatureLive)
  1002. return ERROR_INVALID_PARAMETER;
  1003. EnumHandle->CurrentPos = EnumHandle->Head;
  1004. return RPC_S_OK;
  1005. }
  1006. RPCRTAPI
  1007. RPC_STATUS
  1008. RPC_ENTRY
  1009. RpcErrorGetNumberOfRecords (
  1010. IN RPC_ERROR_ENUM_HANDLE *EnumHandle,
  1011. OUT int *Records
  1012. )
  1013. /*++
  1014. Routine Description:
  1015. Gets the number of records in the chain that it currently
  1016. enumerated
  1017. Arguments:
  1018. EnumHandle - the enumeration handle
  1019. Records - on output will contain the number of records
  1020. Return Value:
  1021. RPC_S_OK or RPC_S_* error - the function cannot fail unless
  1022. given invalid parameters
  1023. --*/
  1024. {
  1025. ExtendedErrorInfo *CurrentRecord;
  1026. int Count;
  1027. ASSERT(EnumHandle != NULL);
  1028. ASSERT(EnumHandle->Head != NULL);
  1029. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1030. if (EnumHandle->Signature != EnumSignatureLive)
  1031. return ERROR_INVALID_PARAMETER;
  1032. CurrentRecord = (ExtendedErrorInfo *) EnumHandle->Head;
  1033. Count = 0;
  1034. while (CurrentRecord != NULL)
  1035. {
  1036. Count ++;
  1037. CurrentRecord = CurrentRecord->Next;
  1038. }
  1039. *Records = Count;
  1040. return RPC_S_OK;
  1041. }
  1042. RPCRTAPI
  1043. RPC_STATUS
  1044. RPC_ENTRY
  1045. RpcErrorSaveErrorInfo (
  1046. IN RPC_ERROR_ENUM_HANDLE *EnumHandle,
  1047. OUT PVOID *ErrorBlob,
  1048. OUT size_t *BlobSize
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Saves the eeinfo in the enumeration to a memory block
  1053. Arguments:
  1054. EnumHandle - the enumeration handle
  1055. ErrorBlob - on output the allocated and filled in blob
  1056. containing the eeinfo in binary format
  1057. BlobSize - on output the size of the blob
  1058. Return Value:
  1059. RPC_S_OK or RPC_S_* error
  1060. --*/
  1061. {
  1062. ULONG EncodedSize;
  1063. ExtendedErrorInfo *EEInfo;
  1064. handle_t PickleHandle;
  1065. char *TempBuffer;
  1066. RPC_STATUS RpcStatus;
  1067. ExtendedErrorInfoPtr *EEInfoPtr;
  1068. size_t MarshallSize;
  1069. HANDLE ProcessHeap;
  1070. PVOID Buffer;
  1071. ASSERT(EnumHandle != NULL);
  1072. ASSERT(EnumHandle->Head != NULL);
  1073. ASSERT(EnumHandle->Signature != EnumSignatureDead);
  1074. if (EnumHandle->Signature != EnumSignatureLive)
  1075. return ERROR_INVALID_PARAMETER;
  1076. // pickle the eeinfo into a buffer
  1077. RpcStatus = MesEncodeDynBufferHandleCreate(&TempBuffer, &EncodedSize, &PickleHandle);
  1078. if (RpcStatus != RPC_S_OK)
  1079. {
  1080. return RpcStatus;
  1081. }
  1082. EEInfo = (ExtendedErrorInfo *) EnumHandle->Head;
  1083. EEInfoPtr = &EEInfo;
  1084. // get the estimated size
  1085. MarshallSize = ExtendedErrorInfoPtr_AlignSize(PickleHandle, EEInfoPtr);
  1086. ProcessHeap = RtlProcessHeap();
  1087. Buffer = RtlAllocateHeap(ProcessHeap, 0, MarshallSize);
  1088. if (Buffer == NULL)
  1089. {
  1090. MesHandleFree(PickleHandle);
  1091. return RPC_S_OUT_OF_MEMORY;
  1092. }
  1093. TempBuffer = (char *)Buffer;
  1094. // re-initialize the handle to fixed buffer
  1095. RpcStatus = MesBufferHandleReset(PickleHandle,
  1096. MES_FIXED_BUFFER_HANDLE,
  1097. MES_ENCODE,
  1098. &TempBuffer,
  1099. MarshallSize,
  1100. &EncodedSize);
  1101. if (RpcStatus != RPC_S_OK)
  1102. {
  1103. MesHandleFree(PickleHandle);
  1104. RtlFreeHeap(ProcessHeap, 0, Buffer);
  1105. return RpcStatus;
  1106. }
  1107. // do the pickling itself
  1108. RpcTryExcept
  1109. {
  1110. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  1111. }
  1112. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  1113. {
  1114. RpcStatus = RpcExceptionCode();
  1115. }
  1116. RpcEndExcept
  1117. if (RpcStatus != RPC_S_OK)
  1118. {
  1119. MesHandleFree(PickleHandle);
  1120. RtlFreeHeap(ProcessHeap, 0, Buffer);
  1121. return RpcStatus;
  1122. }
  1123. // whack out the rest, to prevent random process data going out on the wire/disk
  1124. RpcpMemorySet((unsigned char *)Buffer + EncodedSize, 0, MarshallSize - EncodedSize);
  1125. MesHandleFree(PickleHandle);
  1126. *ErrorBlob = Buffer;
  1127. *BlobSize = EncodedSize;
  1128. return RPC_S_OK;
  1129. }
  1130. RPCRTAPI
  1131. RPC_STATUS
  1132. RPC_ENTRY
  1133. RpcErrorLoadErrorInfo (
  1134. IN PVOID ErrorBlob,
  1135. IN size_t BlobSize,
  1136. OUT RPC_ERROR_ENUM_HANDLE *EnumHandle
  1137. )
  1138. /*++
  1139. Routine Description:
  1140. Creates an enumeration from a blob
  1141. Arguments:
  1142. ErrorBlob - the blob as obtained by RpcErrorSaveErrorInfo
  1143. BlobSize - the size of the blob as obtained by RpcErrorSaveErrorInfo
  1144. EnumHandle - the enumeration handle allocated by the caller
  1145. and filled on output
  1146. Return Value:
  1147. RPC_S_OK or RPC_S_* error
  1148. --*/
  1149. {
  1150. RPC_STATUS RpcStatus;
  1151. ExtendedErrorInfo *EEInfo;
  1152. RpcStatus = UnpickleEEInfo((unsigned char *)ErrorBlob, BlobSize, &EEInfo);
  1153. if (RpcStatus != RPC_S_OK)
  1154. return RpcStatus;
  1155. InitializeEnumHandleWithEEInfo(EEInfo, EnumHandle);
  1156. return RPC_S_OK;
  1157. }
  1158. RPC_STATUS
  1159. AddPrivateRecord (
  1160. IN ExtendedErrorInfo *ErrorInfo
  1161. )
  1162. /*++
  1163. Routine Description:
  1164. Adds the supplied record to the top of the chain in the teb
  1165. N.B. There can be no additional failure paths in the callers
  1166. after this function. This is because it will chain this
  1167. record to the teb, and if we bail out later, the teb will
  1168. point to invalid record.
  1169. Arguments:
  1170. ErrorInfo - the eeinfo record to add to the chain
  1171. Return Value:
  1172. RPC_S_OK or RPC_S_* error - the function cannot fail if the
  1173. RPC per-thread object has already been allocated for this
  1174. thread
  1175. --*/
  1176. {
  1177. THREAD *Thread;
  1178. Thread = ThreadSelf();
  1179. if (Thread == NULL)
  1180. return RPC_S_OUT_OF_MEMORY;
  1181. ErrorInfo->Next = Thread->GetEEInfo();
  1182. Thread->SetEEInfo(ErrorInfo);
  1183. return RPC_S_OK;
  1184. }
  1185. inline LPWSTR
  1186. ReplaceWithEmptyStringIfNull (
  1187. IN LPWSTR String
  1188. )
  1189. {
  1190. return (String ? String : L"");
  1191. }
  1192. inline LPSTR
  1193. ReplaceWithEmptyStringIfNull (
  1194. IN LPSTR String
  1195. )
  1196. {
  1197. return (String ? String : "");
  1198. }
  1199. void
  1200. RpcpErrorAddRecord (
  1201. ULONG GeneratingComponent,
  1202. ULONG Status,
  1203. USHORT DetectionLocation,
  1204. int NumberOfParameters,
  1205. ExtendedErrorParam *Params
  1206. )
  1207. /*++
  1208. Routine Description:
  1209. Adds an extended error info to the thread. The
  1210. following is a description of how fields are set:
  1211. Next - will be set to the next record.
  1212. ComputerName - will be set to not-present (eecnpNotPresent)
  1213. ProcessID - will be set to the process ID
  1214. TimeStamp - will be set to the current time
  1215. GeneratingComponent - set to GeneratingComponent
  1216. Status - set to Status
  1217. DetectionLocation - set to DetectionLocation
  1218. Flags - set to 0.
  1219. nLen - set to NumberOfParameters
  1220. Params will be copied to the parameters array. The caller can
  1221. allocate them off the stack if it wants.
  1222. N.B. The runtime should never directly call this function. If it
  1223. needs to add records, it should call one of the overloaded
  1224. RpcpErrorAddRecord functions below. If there isn't one suitable,
  1225. add one. All the RpcpErrorAddRecord functions below are just
  1226. syntactic sugar for this function.
  1227. Arguments:
  1228. GeneratingComponent - will be set in the record
  1229. Status - will be set in the record
  1230. DetectionLocation - will be set in the record
  1231. NumberOfParameters - the number of parameters in the Params array
  1232. Params - the parameters to add
  1233. Return Value:
  1234. void - this is a best effort - no guarantees. Even if we
  1235. return failure, there's little the caller can do about it.
  1236. --*/
  1237. {
  1238. ExtendedErrorInfo *NewRecord;
  1239. RPC_STATUS RpcStatus;
  1240. int i;
  1241. LogEvent(SU_EEINFO,
  1242. (char)GeneratingComponent,
  1243. ULongToPtr(Status),
  1244. ULongToPtr(DetectionLocation),
  1245. (NumberOfParameters > 0) ? Params[0].LVal : 0);
  1246. NewRecord = AllocateExtendedErrorInfoRecord(NumberOfParameters);
  1247. if (NewRecord == NULL)
  1248. {
  1249. // If allocation of extended error information has failed
  1250. // we need to free the parameters passed in since there is
  1251. // no way to communicate the failure to the upper layers.
  1252. if (Params != NULL)
  1253. {
  1254. for (i = NumberOfParameters - 1; i >= 0; i--)
  1255. {
  1256. FreeEEInfoPrivateParam(&Params[i]);
  1257. }
  1258. }
  1259. return;
  1260. }
  1261. InitializePrivateEEInfo(NewRecord);
  1262. NewRecord->DetectionLocation = DetectionLocation;
  1263. NewRecord->GeneratingComponent = GeneratingComponent;
  1264. NewRecord->Status = Status;
  1265. for (i = 0; i < NumberOfParameters; i ++)
  1266. {
  1267. // all parameter types requiring an allocation have already
  1268. // been copied by our caller - no need to clone - we can just
  1269. // do shallow copy
  1270. RpcpMemoryCopy(&NewRecord->Params[i], &Params[i], sizeof(ExtendedErrorParam));
  1271. }
  1272. RpcStatus = AddPrivateRecord(NewRecord);
  1273. if (RpcStatus != RPC_S_OK)
  1274. {
  1275. FreeEEInfoRecord(NewRecord);
  1276. }
  1277. }
  1278. void
  1279. RpcpErrorAddRecord (
  1280. IN ULONG GeneratingComponent,
  1281. IN ULONG Status,
  1282. IN USHORT DetectionLocation,
  1283. IN ULONG Long,
  1284. IN short Short,
  1285. IN ULONG Long2
  1286. )
  1287. /*++
  1288. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1289. USHORT, int, ExtendedErrorParam*) above
  1290. --*/
  1291. {
  1292. ExtendedErrorParam Params[3];
  1293. Params[0].Type = eeptiLongVal;
  1294. Params[0].LVal = (long)Long;
  1295. Params[1].Type = eeptiShortVal;
  1296. Params[1].IVal = Short;
  1297. Params[2].Type = eeptiLongVal;
  1298. Params[2].LVal = (long)Long2;
  1299. RpcpErrorAddRecord (GeneratingComponent,
  1300. Status,
  1301. DetectionLocation,
  1302. 3,
  1303. Params);
  1304. }
  1305. void
  1306. RpcpErrorAddRecord (
  1307. IN ULONG GeneratingComponent,
  1308. IN ULONG Status,
  1309. IN USHORT DetectionLocation,
  1310. IN ULONG Long,
  1311. IN short Short,
  1312. IN ULONG Long2,
  1313. IN ULONG Long3
  1314. )
  1315. /*++
  1316. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1317. USHORT, int, ExtendedErrorParam*) above
  1318. --*/
  1319. {
  1320. ExtendedErrorParam Params[4];
  1321. Params[0].Type = eeptiLongVal;
  1322. Params[0].LVal = (long)Long;
  1323. Params[1].Type = eeptiShortVal;
  1324. Params[1].IVal = Short;
  1325. Params[2].Type = eeptiLongVal;
  1326. Params[2].LVal = (long)Long2;
  1327. Params[3].Type = eeptiLongVal;
  1328. Params[3].LVal = (long)Long3;
  1329. RpcpErrorAddRecord (GeneratingComponent,
  1330. Status,
  1331. DetectionLocation,
  1332. 4,
  1333. Params);
  1334. }
  1335. void
  1336. RpcpErrorAddRecord (
  1337. IN ULONG GeneratingComponent,
  1338. IN ULONG Status,
  1339. IN USHORT DetectionLocation,
  1340. IN ULONG Long,
  1341. IN ULONG Long2
  1342. )
  1343. /*++
  1344. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1345. USHORT, int, ExtendedErrorParam*) above
  1346. --*/
  1347. {
  1348. ExtendedErrorParam Params[2];
  1349. Params[0].Type = eeptiLongVal;
  1350. Params[0].LVal = (long)Long;
  1351. Params[1].Type = eeptiLongVal;
  1352. Params[1].LVal = (long)Long2;
  1353. RpcpErrorAddRecord (GeneratingComponent,
  1354. Status,
  1355. DetectionLocation,
  1356. 2,
  1357. Params);
  1358. }
  1359. void
  1360. RpcpErrorAddRecord (
  1361. IN ULONG GeneratingComponent,
  1362. IN ULONG Status,
  1363. IN USHORT DetectionLocation,
  1364. IN LPWSTR String1,
  1365. IN LPWSTR String2
  1366. )
  1367. /*++
  1368. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1369. USHORT, int, ExtendedErrorParam*) above
  1370. --*/
  1371. {
  1372. ExtendedErrorParam Params[2];
  1373. RPC_STATUS RpcStatus;
  1374. int i;
  1375. LPWSTR Strings[2];
  1376. Strings[0] = ReplaceWithEmptyStringIfNull(String1);
  1377. Strings[1] = ReplaceWithEmptyStringIfNull(String2);
  1378. for (i = 0; i < 2; i ++)
  1379. {
  1380. RpcStatus = ConvertPublicStringToPrivateString(Strings[i],
  1381. &Params[i].UnicodeString);
  1382. if (RpcStatus == RPC_S_OK)
  1383. {
  1384. Params[i].Type = eeptiUnicodeString;
  1385. }
  1386. else
  1387. {
  1388. Params[i].Type = eeptiNone;
  1389. }
  1390. }
  1391. RpcpErrorAddRecord (GeneratingComponent,
  1392. Status,
  1393. DetectionLocation,
  1394. 2,
  1395. Params);
  1396. }
  1397. void
  1398. RpcpErrorAddRecord (
  1399. IN ULONG GeneratingComponent,
  1400. IN ULONG Status,
  1401. IN USHORT DetectionLocation,
  1402. IN LPWSTR String1,
  1403. IN LPWSTR String2,
  1404. IN ULONG Long1,
  1405. IN ULONG Long2
  1406. )
  1407. /*++
  1408. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1409. USHORT, int, ExtendedErrorParam*) above
  1410. --*/
  1411. {
  1412. ExtendedErrorParam Params[4];
  1413. RPC_STATUS RpcStatus;
  1414. int i;
  1415. LPWSTR Strings[2];
  1416. Strings[0] = ReplaceWithEmptyStringIfNull(String1);
  1417. Strings[1] = ReplaceWithEmptyStringIfNull(String2);
  1418. for (i = 0; i < 2; i ++)
  1419. {
  1420. RpcStatus = ConvertPublicStringToPrivateString(Strings[i],
  1421. &Params[i].UnicodeString);
  1422. if (RpcStatus == RPC_S_OK)
  1423. {
  1424. Params[i].Type = eeptiUnicodeString;
  1425. }
  1426. else
  1427. {
  1428. Params[i].Type = eeptiNone;
  1429. }
  1430. }
  1431. Params[2].Type = eeptiLongVal;
  1432. Params[2].LVal = (long)Long1;
  1433. Params[3].Type = eeptiLongVal;
  1434. Params[3].LVal = (long)Long2;
  1435. RpcpErrorAddRecord (GeneratingComponent,
  1436. Status,
  1437. DetectionLocation,
  1438. 4,
  1439. Params);
  1440. }
  1441. void
  1442. RpcpErrorAddRecord (
  1443. IN ULONG GeneratingComponent,
  1444. IN ULONG Status,
  1445. IN USHORT DetectionLocation,
  1446. IN LPWSTR String1,
  1447. IN LPWSTR String2,
  1448. IN ULONG Long1,
  1449. IN ULONGLONG PVal1
  1450. )
  1451. /*++
  1452. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1453. USHORT, int, ExtendedErrorParam*) above
  1454. --*/
  1455. {
  1456. ExtendedErrorParam Params[4];
  1457. RPC_STATUS RpcStatus;
  1458. int i;
  1459. LPWSTR Strings[2];
  1460. Strings[0] = ReplaceWithEmptyStringIfNull(String1);
  1461. Strings[1] = ReplaceWithEmptyStringIfNull(String2);
  1462. for (i = 0; i < 2; i ++)
  1463. {
  1464. RpcStatus = ConvertPublicStringToPrivateString(Strings[i],
  1465. &Params[i].UnicodeString);
  1466. if (RpcStatus == RPC_S_OK)
  1467. {
  1468. Params[i].Type = eeptiUnicodeString;
  1469. }
  1470. else
  1471. {
  1472. Params[i].Type = eeptiNone;
  1473. }
  1474. }
  1475. Params[2].Type = eeptiLongVal;
  1476. Params[2].LVal = (long)Long1;
  1477. Params[3].Type = eeptiPointerVal;
  1478. Params[3].PVal = (long)PVal1;
  1479. RpcpErrorAddRecord (GeneratingComponent,
  1480. Status,
  1481. DetectionLocation,
  1482. 4,
  1483. Params);
  1484. }
  1485. void
  1486. RpcpErrorAddRecord (
  1487. IN ULONG GeneratingComponent,
  1488. IN ULONG Status,
  1489. IN USHORT DetectionLocation,
  1490. IN ULONG Long1,
  1491. IN ULONG Long2,
  1492. IN LPWSTR String,
  1493. IN ULONG Long3
  1494. )
  1495. /*++
  1496. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1497. USHORT, int, ExtendedErrorParam*) above
  1498. --*/
  1499. {
  1500. ExtendedErrorParam Params[4];
  1501. RPC_STATUS RpcStatus;
  1502. Params[0].Type = eeptiLongVal;
  1503. Params[0].LVal = (long)Long1;
  1504. Params[1].Type = eeptiLongVal;
  1505. Params[1].LVal = (long)Long2;
  1506. Params[3].Type = eeptiLongVal;
  1507. Params[3].LVal = (long)Long3;
  1508. RpcStatus = ConvertPublicStringToPrivateString(
  1509. ReplaceWithEmptyStringIfNull(String),
  1510. &Params[2].UnicodeString);
  1511. if (RpcStatus == RPC_S_OK)
  1512. {
  1513. Params[2].Type = eeptiUnicodeString;
  1514. }
  1515. else
  1516. {
  1517. Params[2].Type = eeptiNone;
  1518. }
  1519. RpcpErrorAddRecord (GeneratingComponent,
  1520. Status,
  1521. DetectionLocation,
  1522. 4,
  1523. Params);
  1524. }
  1525. void
  1526. RpcpErrorAddRecord (
  1527. IN ULONG GeneratingComponent,
  1528. IN ULONG Status,
  1529. IN USHORT DetectionLocation,
  1530. IN LPWSTR String,
  1531. IN ULONG Long
  1532. )
  1533. /*++
  1534. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1535. USHORT, int, ExtendedErrorParam*) above
  1536. --*/
  1537. {
  1538. ExtendedErrorParam Params[2];
  1539. RPC_STATUS RpcStatus;
  1540. Params[0].Type = eeptiLongVal;
  1541. Params[0].LVal = (long)Long;
  1542. RpcStatus = ConvertPublicStringToPrivateString(
  1543. ReplaceWithEmptyStringIfNull(String),
  1544. &Params[1].UnicodeString);
  1545. if (RpcStatus == RPC_S_OK)
  1546. {
  1547. Params[1].Type = eeptiUnicodeString;
  1548. }
  1549. else
  1550. {
  1551. Params[1].Type = eeptiNone;
  1552. }
  1553. RpcpErrorAddRecord (GeneratingComponent,
  1554. Status,
  1555. DetectionLocation,
  1556. 2,
  1557. Params);
  1558. }
  1559. void
  1560. RpcpErrorAddRecord (
  1561. IN ULONG GeneratingComponent,
  1562. IN ULONG Status,
  1563. IN USHORT DetectionLocation,
  1564. IN LPWSTR String,
  1565. IN ULONG Long1,
  1566. IN ULONG Long2
  1567. )
  1568. /*++
  1569. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1570. USHORT, int, ExtendedErrorParam*) above
  1571. --*/
  1572. {
  1573. ExtendedErrorParam Params[3];
  1574. RPC_STATUS RpcStatus;
  1575. Params[1].Type = eeptiLongVal;
  1576. Params[1].LVal = (long)Long1;
  1577. Params[2].Type = eeptiLongVal;
  1578. Params[2].LVal = (long)Long2;
  1579. RpcStatus = ConvertPublicStringToPrivateString(
  1580. ReplaceWithEmptyStringIfNull(String),
  1581. &Params[0].UnicodeString);
  1582. if (RpcStatus == RPC_S_OK)
  1583. {
  1584. Params[0].Type = eeptiUnicodeString;
  1585. }
  1586. else
  1587. {
  1588. Params[0].Type = eeptiNone;
  1589. }
  1590. RpcpErrorAddRecord (GeneratingComponent,
  1591. Status,
  1592. DetectionLocation,
  1593. 3,
  1594. Params);
  1595. }
  1596. void
  1597. RpcpErrorAddRecord (
  1598. IN ULONG GeneratingComponent,
  1599. IN ULONG Status,
  1600. IN USHORT DetectionLocation,
  1601. IN LPWSTR String
  1602. )
  1603. /*++
  1604. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1605. USHORT, int, ExtendedErrorParam*) above
  1606. --*/
  1607. {
  1608. ExtendedErrorParam Params[1];
  1609. RPC_STATUS RpcStatus;
  1610. RpcStatus = ConvertPublicStringToPrivateString(
  1611. ReplaceWithEmptyStringIfNull(String),
  1612. &Params[0].UnicodeString);
  1613. if (RpcStatus == RPC_S_OK)
  1614. {
  1615. Params[0].Type = eeptiUnicodeString;
  1616. }
  1617. else
  1618. {
  1619. Params[0].Type = eeptiNone;
  1620. }
  1621. RpcpErrorAddRecord (GeneratingComponent,
  1622. Status,
  1623. DetectionLocation,
  1624. 1,
  1625. Params);
  1626. }
  1627. void
  1628. RpcpErrorAddRecord (
  1629. IN ULONG GeneratingComponent,
  1630. IN ULONG Status,
  1631. IN USHORT DetectionLocation,
  1632. IN LPSTR String
  1633. )
  1634. /*++
  1635. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1636. USHORT, int, ExtendedErrorParam*) above
  1637. --*/
  1638. {
  1639. ExtendedErrorParam Params[1];
  1640. RPC_STATUS RpcStatus;
  1641. RpcStatus = ConvertPublicStringToPrivateString(
  1642. ReplaceWithEmptyStringIfNull(String),
  1643. &Params[0].AnsiString);
  1644. if (RpcStatus == RPC_S_OK)
  1645. {
  1646. Params[0].Type = eeptiAnsiString;
  1647. }
  1648. else
  1649. {
  1650. Params[0].Type = eeptiNone;
  1651. }
  1652. RpcpErrorAddRecord (GeneratingComponent,
  1653. Status,
  1654. DetectionLocation,
  1655. 1,
  1656. Params);
  1657. }
  1658. void
  1659. RpcpErrorAddRecord (
  1660. IN ULONG GeneratingComponent,
  1661. IN ULONG Status,
  1662. IN USHORT DetectionLocation,
  1663. IN ULONG Long,
  1664. IN ULONG Long2,
  1665. IN ULONG Long3
  1666. )
  1667. /*++
  1668. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1669. USHORT, int, ExtendedErrorParam*) above
  1670. --*/
  1671. {
  1672. ExtendedErrorParam Params[3];
  1673. Params[0].Type = eeptiLongVal;
  1674. Params[0].LVal = (long)Long;
  1675. Params[1].Type = eeptiLongVal;
  1676. Params[1].LVal = (long)Long2;
  1677. Params[2].Type = eeptiLongVal;
  1678. Params[2].LVal = (long)Long3;
  1679. RpcpErrorAddRecord (GeneratingComponent,
  1680. Status,
  1681. DetectionLocation,
  1682. 3,
  1683. Params);
  1684. }
  1685. void
  1686. RpcpErrorAddRecord (
  1687. IN ULONG GeneratingComponent,
  1688. IN ULONG Status,
  1689. IN USHORT DetectionLocation,
  1690. IN ULONGLONG PVal1,
  1691. IN ULONGLONG PVal2,
  1692. IN ULONG Long
  1693. )
  1694. /*++
  1695. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1696. USHORT, int, ExtendedErrorParam*) above
  1697. --*/
  1698. {
  1699. ExtendedErrorParam Params[3];
  1700. Params[0].Type = eeptiPointerVal;
  1701. Params[0].PVal = PVal1;
  1702. Params[1].Type = eeptiPointerVal;
  1703. Params[1].PVal = PVal2;
  1704. Params[2].Type = eeptiLongVal;
  1705. Params[2].LVal = (long)Long;
  1706. RpcpErrorAddRecord (GeneratingComponent,
  1707. Status,
  1708. DetectionLocation,
  1709. 3,
  1710. Params);
  1711. }
  1712. void
  1713. RpcpErrorAddRecord (
  1714. IN ULONG GeneratingComponent,
  1715. IN ULONG Status,
  1716. IN USHORT DetectionLocation,
  1717. IN ULONGLONG PVal1,
  1718. IN ULONGLONG PVal2,
  1719. IN ULONG Long1,
  1720. IN ULONG Long2
  1721. )
  1722. /*++
  1723. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1724. USHORT, int, ExtendedErrorParam*) above
  1725. --*/
  1726. {
  1727. ExtendedErrorParam Params[4];
  1728. Params[0].Type = eeptiPointerVal;
  1729. Params[0].PVal = PVal1;
  1730. Params[1].Type = eeptiPointerVal;
  1731. Params[1].PVal = PVal2;
  1732. Params[2].Type = eeptiLongVal;
  1733. Params[2].LVal = (long)Long1;
  1734. Params[3].Type = eeptiLongVal;
  1735. Params[3].LVal = (long)Long2;
  1736. RpcpErrorAddRecord (GeneratingComponent,
  1737. Status,
  1738. DetectionLocation,
  1739. 4,
  1740. Params);
  1741. }
  1742. void
  1743. RpcpErrorAddRecord (
  1744. IN ULONG GeneratingComponent,
  1745. IN ULONG Status,
  1746. IN USHORT DetectionLocation,
  1747. IN ULONGLONG PVal1,
  1748. IN ULONGLONG PVal2
  1749. )
  1750. /*++
  1751. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1752. USHORT, int, ExtendedErrorParam*) above
  1753. --*/
  1754. {
  1755. ExtendedErrorParam Params[2];
  1756. Params[0].Type = eeptiPointerVal;
  1757. Params[0].PVal = PVal1;
  1758. Params[1].Type = eeptiPointerVal;
  1759. Params[1].PVal = PVal2;
  1760. RpcpErrorAddRecord (GeneratingComponent,
  1761. Status,
  1762. DetectionLocation,
  1763. 2,
  1764. Params);
  1765. }
  1766. void
  1767. RpcpErrorAddRecord (
  1768. IN ULONG GeneratingComponent,
  1769. IN ULONG Status,
  1770. IN USHORT DetectionLocation,
  1771. IN ULONGLONG PVal1,
  1772. IN ULONG LVal1
  1773. )
  1774. /*++
  1775. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1776. USHORT, int, ExtendedErrorParam*) above
  1777. --*/
  1778. {
  1779. ExtendedErrorParam Params[2];
  1780. Params[0].Type = eeptiPointerVal;
  1781. Params[0].PVal = PVal1;
  1782. Params[1].Type = eeptiLongVal;
  1783. Params[1].PVal = LVal1;
  1784. RpcpErrorAddRecord (GeneratingComponent,
  1785. Status,
  1786. DetectionLocation,
  1787. 2,
  1788. Params);
  1789. }
  1790. void
  1791. RpcpErrorAddRecord (
  1792. IN ULONG GeneratingComponent,
  1793. IN ULONG Status,
  1794. IN USHORT DetectionLocation,
  1795. IN ULONG Long,
  1796. IN ULONGLONG PVal1
  1797. )
  1798. /*++
  1799. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1800. USHORT, int, ExtendedErrorParam*) above
  1801. --*/
  1802. {
  1803. ExtendedErrorParam Params[2];
  1804. Params[0].Type = eeptiLongVal;
  1805. Params[0].LVal = Long;
  1806. Params[1].Type = eeptiPointerVal;
  1807. Params[1].PVal = PVal1;
  1808. RpcpErrorAddRecord (GeneratingComponent,
  1809. Status,
  1810. DetectionLocation,
  1811. 2,
  1812. Params);
  1813. }
  1814. void
  1815. RpcpErrorAddRecord (
  1816. IN ULONG GeneratingComponent,
  1817. IN ULONG Status,
  1818. IN USHORT DetectionLocation,
  1819. IN ULONG Long,
  1820. IN ULONGLONG PVal1,
  1821. IN ULONGLONG PVal2
  1822. )
  1823. /*++
  1824. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1825. USHORT, int, ExtendedErrorParam*) above
  1826. --*/
  1827. {
  1828. ExtendedErrorParam Params[3];
  1829. Params[0].Type = eeptiLongVal;
  1830. Params[0].LVal = (long)Long;
  1831. Params[1].Type = eeptiPointerVal;
  1832. Params[1].PVal = PVal1;
  1833. Params[2].Type = eeptiPointerVal;
  1834. Params[2].PVal = PVal2;
  1835. RpcpErrorAddRecord (GeneratingComponent,
  1836. Status,
  1837. DetectionLocation,
  1838. 3,
  1839. Params);
  1840. }
  1841. void
  1842. RpcpErrorAddRecord (
  1843. IN ULONG GeneratingComponent,
  1844. IN ULONG Status,
  1845. IN USHORT DetectionLocation,
  1846. IN ULONG Long
  1847. )
  1848. /*++
  1849. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1850. USHORT, int, ExtendedErrorParam*) above
  1851. --*/
  1852. {
  1853. ExtendedErrorParam Params[1];
  1854. Params[0].Type = eeptiLongVal;
  1855. Params[0].LVal = (long)Long;
  1856. RpcpErrorAddRecord (GeneratingComponent,
  1857. Status,
  1858. DetectionLocation,
  1859. 1,
  1860. Params);
  1861. }
  1862. void
  1863. RpcpErrorAddRecord (
  1864. IN ULONG GeneratingComponent,
  1865. IN ULONG Status,
  1866. IN USHORT DetectionLocation,
  1867. IN ULONG LVal1,
  1868. IN ULONGLONG PVal1,
  1869. IN ULONG LVal2
  1870. )
  1871. /*++
  1872. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1873. USHORT, int, ExtendedErrorParam*) above
  1874. --*/
  1875. {
  1876. ExtendedErrorParam Params[3];
  1877. Params[0].Type = eeptiLongVal;
  1878. Params[0].LVal = (long)LVal1;
  1879. Params[1].Type = eeptiPointerVal;
  1880. Params[1].PVal = PVal1;
  1881. Params[2].Type = eeptiLongVal;
  1882. Params[2].LVal = (long)LVal2;
  1883. RpcpErrorAddRecord (GeneratingComponent,
  1884. Status,
  1885. DetectionLocation,
  1886. 3,
  1887. Params);
  1888. }
  1889. void
  1890. RpcpErrorAddRecord (
  1891. IN ULONG GeneratingComponent,
  1892. IN ULONG Status,
  1893. IN USHORT DetectionLocation,
  1894. IN ULONG LVal1,
  1895. IN ULONG LVal2,
  1896. IN ULONG LVal3,
  1897. IN ULONGLONG PVal1
  1898. )
  1899. /*++
  1900. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1901. USHORT, int, ExtendedErrorParam*) above
  1902. --*/
  1903. {
  1904. ExtendedErrorParam Params[4];
  1905. Params[0].Type = eeptiLongVal;
  1906. Params[0].LVal = (long)LVal1;
  1907. Params[1].Type = eeptiLongVal;
  1908. Params[1].LVal = (long)LVal2;
  1909. Params[2].Type = eeptiLongVal;
  1910. Params[2].LVal = (long)LVal3;
  1911. Params[3].Type = eeptiPointerVal;
  1912. Params[3].PVal = PVal1;
  1913. RpcpErrorAddRecord (GeneratingComponent,
  1914. Status,
  1915. DetectionLocation,
  1916. 3,
  1917. Params);
  1918. }
  1919. void
  1920. RpcpErrorAddRecord (
  1921. IN ULONG GeneratingComponent,
  1922. IN ULONG Status,
  1923. IN USHORT DetectionLocation,
  1924. IN ULONG LVal1,
  1925. IN ULONG LVal2,
  1926. IN ULONG LVal3,
  1927. IN ULONG LVal4
  1928. )
  1929. /*++
  1930. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1931. USHORT, int, ExtendedErrorParam*) above
  1932. --*/
  1933. {
  1934. ExtendedErrorParam Params[4];
  1935. Params[0].Type = eeptiLongVal;
  1936. Params[0].LVal = (long)LVal1;
  1937. Params[1].Type = eeptiLongVal;
  1938. Params[1].LVal = (long)LVal2;
  1939. Params[2].Type = eeptiLongVal;
  1940. Params[2].LVal = (long)LVal3;
  1941. Params[3].Type = eeptiLongVal;
  1942. Params[3].PVal = LVal4;
  1943. RpcpErrorAddRecord (GeneratingComponent,
  1944. Status,
  1945. DetectionLocation,
  1946. 4,
  1947. Params);
  1948. }
  1949. void
  1950. RpcpErrorAddRecord (
  1951. IN ULONG GeneratingComponent,
  1952. IN ULONG Status,
  1953. IN USHORT DetectionLocation,
  1954. IN ULONGLONG PVal1,
  1955. IN ULONGLONG PVal2,
  1956. IN ULONGLONG PVal3,
  1957. IN ULONGLONG PVal4
  1958. )
  1959. /*++
  1960. See description of RpcpErrorAddRecord(ULONG, ULONG,
  1961. USHORT, int, ExtendedErrorParam*) above
  1962. --*/
  1963. {
  1964. ExtendedErrorParam Params[4];
  1965. Params[0].Type = eeptiPointerVal;
  1966. Params[0].PVal = PVal1;
  1967. Params[1].Type = eeptiPointerVal;
  1968. Params[1].PVal = PVal2;
  1969. Params[2].Type = eeptiPointerVal;
  1970. Params[2].PVal = PVal3;
  1971. Params[3].Type = eeptiPointerVal;
  1972. Params[3].PVal = PVal4;
  1973. RpcpErrorAddRecord (GeneratingComponent,
  1974. Status,
  1975. DetectionLocation,
  1976. 4,
  1977. Params);
  1978. }
  1979. RPCRTAPI
  1980. RPC_STATUS
  1981. RPC_ENTRY
  1982. RpcErrorAddRecord (
  1983. IN RPC_EXTENDED_ERROR_INFO *ErrorInfo
  1984. )
  1985. /*++
  1986. Routine Description:
  1987. Adds the supplied record to the top of the chain in the teb
  1988. Arguments:
  1989. ErrorInfo - the eeinfo record to add to the chain
  1990. Return Value:
  1991. RPC_S_OK or RPC_S_* error
  1992. --*/
  1993. {
  1994. ExtendedErrorInfo *NewRecord;
  1995. RPC_STATUS RpcStatus;
  1996. if (ErrorInfo->Version != RPC_EEINFO_VERSION)
  1997. return ERROR_INVALID_PARAMETER;
  1998. if (ErrorInfo->ComputerName != NULL)
  1999. return ERROR_INVALID_PARAMETER;
  2000. if (ErrorInfo->Flags != 0)
  2001. return ERROR_INVALID_PARAMETER;
  2002. if (ErrorInfo->NumberOfParameters < 0)
  2003. return ERROR_INVALID_PARAMETER;
  2004. if (ErrorInfo->NumberOfParameters > MaxNumberOfEEInfoParams)
  2005. return ERROR_INVALID_PARAMETER;
  2006. if (ErrorInfo->DetectionLocation != 0)
  2007. return ERROR_INVALID_PARAMETER;
  2008. // make sure only valid constants come through. This can be the microsoft outside of RPC range
  2009. // (currently bounded by EEInfoGCCOM to EEInfoGCFRS) or outside the microsoft range). If not, it
  2010. // can be 0
  2011. if ((ErrorInfo->GeneratingComponent != 0)
  2012. &&
  2013. (
  2014. (ErrorInfo->GeneratingComponent < EEInfoGCCOM)
  2015. ||
  2016. (
  2017. (ErrorInfo->GeneratingComponent > EEInfoGCFRS)
  2018. &&
  2019. (ErrorInfo->GeneratingComponent < 0x80000000)
  2020. )
  2021. )
  2022. )
  2023. {
  2024. return ERROR_INVALID_PARAMETER;
  2025. }
  2026. if (ErrorInfo->ProcessID != 0)
  2027. return ERROR_INVALID_PARAMETER;
  2028. NewRecord = AllocateExtendedErrorInfoRecord(ErrorInfo->NumberOfParameters);
  2029. if (NewRecord == NULL)
  2030. return RPC_S_OUT_OF_MEMORY;
  2031. RpcStatus = ConvertPublicEEInfoToPrivateEEInfo(ErrorInfo, EEInfoDLApi, NewRecord);
  2032. if (RpcStatus != RPC_S_OK)
  2033. {
  2034. FreeEEInfoRecordShallow(NewRecord);
  2035. return RpcStatus;
  2036. }
  2037. RpcStatus = AddPrivateRecord(NewRecord);
  2038. if (RpcStatus != RPC_S_OK)
  2039. {
  2040. FreeEEInfoRecord(NewRecord);
  2041. }
  2042. return RpcStatus;
  2043. }
  2044. RPCRTAPI
  2045. void
  2046. RPC_ENTRY
  2047. RpcErrorClearInformation (
  2048. void
  2049. )
  2050. /*++
  2051. Routine Description:
  2052. Clears the existing eeinfo on the teb (if any)
  2053. Arguments:
  2054. void
  2055. Return Value:
  2056. void
  2057. --*/
  2058. {
  2059. ExtendedErrorInfo *EEInfo;
  2060. THREAD *Thread;
  2061. Thread = RpcpGetThreadPointer();
  2062. if (Thread == NULL)
  2063. return;
  2064. EEInfo = Thread->GetEEInfo();
  2065. Thread->SetEEInfo(NULL);
  2066. FreeEEInfoChain(EEInfo);
  2067. }
  2068. BOOL
  2069. KnockOffLastButOneEEInfoRecord (
  2070. IN ExtendedErrorInfo *EEInfo
  2071. )
  2072. /*++
  2073. Routine Description:
  2074. Will delete the last-but-one record from the chain. If there
  2075. are two or less record, nothing is deleted, and FALSE gets
  2076. returned.
  2077. Arguments:
  2078. EEInfo - the extended error info chain
  2079. Return Value:
  2080. TRUE - a record was deleted
  2081. FALSE - there were two or less records, and nothing was deleted.
  2082. --*/
  2083. {
  2084. ExtendedErrorInfo *NextRecord, *LastButOneRecord;
  2085. ExtendedErrorInfo *PreviousRecord;
  2086. LastButOneRecord = NextRecord = EEInfo;
  2087. while ((NextRecord != NULL) && (NextRecord->Next != NULL))
  2088. {
  2089. PreviousRecord = LastButOneRecord;
  2090. LastButOneRecord = NextRecord;
  2091. NextRecord = NextRecord->Next;
  2092. }
  2093. if ((NextRecord == EEInfo) || (LastButOneRecord == EEInfo))
  2094. {
  2095. return FALSE;
  2096. }
  2097. PreviousRecord->Next = NextRecord;
  2098. // indicate that the chain has been broken
  2099. PreviousRecord->Flags |= EEInfoNextRecordsMissing;
  2100. NextRecord->Flags |= EEInfoPreviousRecordsMissing;
  2101. // move the computer name up if necessary
  2102. if ((LastButOneRecord->ComputerName.Type == eecnpPresent)
  2103. && (NextRecord->ComputerName.Type == eecnpNotPresent))
  2104. {
  2105. // N.B. Not covered by unit tests
  2106. LastButOneRecord->ComputerName.Type = eecnpNotPresent;
  2107. NextRecord->ComputerName.Type = eecnpPresent;
  2108. NextRecord->ComputerName.Name.nLength = LastButOneRecord->ComputerName.Name.nLength;
  2109. NextRecord->ComputerName.Name.pString = LastButOneRecord->ComputerName.Name.pString;
  2110. }
  2111. FreeEEInfoRecord(LastButOneRecord);
  2112. return TRUE;
  2113. }
  2114. RPC_STATUS
  2115. TrimEEInfoToLengthByRemovingRecords (
  2116. IN ExtendedErrorInfo *EEInfo,
  2117. IN size_t MaxLength,
  2118. OUT BOOL *fTrimmedEnough,
  2119. OUT size_t *NeededLength
  2120. )
  2121. /*++
  2122. Routine Description:
  2123. This function removes records, until either two records are
  2124. left, or the pickled length drops below MaxLength. If the
  2125. pickled length is below the MaxLength to start with, no
  2126. records should be dropped. The records are dropped starting
  2127. from the last-but-one, and going backwards (towards the
  2128. current record). The previous and next records should
  2129. have their chain broken flags set, and the computer name
  2130. should be moved up the chain, if the last record has
  2131. no computer name.
  2132. Arguments:
  2133. EEInfo - the EE chain
  2134. MaxLength - the length that we need to trim to.
  2135. fTrimmedEnough - will be set to TRUE if the pickled length
  2136. on return from this function fits in MaxLength. Undefined
  2137. if the return value is not RPC_S_OK
  2138. NeededLength - if fTrimmedEnough was set to TRUE, and the
  2139. return value is RPC_S_OK, the current pickled length.
  2140. Otherwise, this value must not be touched (i.e. use
  2141. a local variable until you're sure that both conditions
  2142. are true).
  2143. Return Value:
  2144. RPC_S_OK on success.
  2145. != RPC_S_OK on error. On error, fTrimmedEnough is undefined, and
  2146. NeededLength is not touched.
  2147. --*/
  2148. {
  2149. ULONG EncodedSize;
  2150. handle_t PickleHandle = NULL;
  2151. char *TempBuffer;
  2152. RPC_STATUS RpcStatus;
  2153. ExtendedErrorInfoPtr *EEInfoPtr;
  2154. PVOID Buffer = NULL;
  2155. size_t CurrentlyNeededLength;
  2156. size_t PickleLength;
  2157. size_t BufferLength;
  2158. BOOL Result;
  2159. RpcStatus = MesEncodeDynBufferHandleCreate(&TempBuffer, &EncodedSize, &PickleHandle);
  2160. if (RpcStatus != RPC_S_OK)
  2161. {
  2162. return RpcStatus;
  2163. }
  2164. // our first goal is to drive the pickled length to less than 2 times
  2165. // the MaxLength. Since the actual pickling often takes less than the
  2166. // estimated, we will do the fine tuning by actually pickling and measuring
  2167. // the resulting size. For the rough tuning, we will use the estimate, and
  2168. // knock off it, if we are over the estimate
  2169. CurrentlyNeededLength = MaxLength * 2;
  2170. while (TRUE)
  2171. {
  2172. EEInfoPtr = &EEInfo;
  2173. // get the estimated size
  2174. PickleLength = ExtendedErrorInfoPtr_AlignSize(PickleHandle, EEInfoPtr);
  2175. if (PickleLength <= CurrentlyNeededLength)
  2176. {
  2177. break;
  2178. }
  2179. // knock off the last-but-one element
  2180. Result = KnockOffLastButOneEEInfoRecord(EEInfo);
  2181. if (Result == FALSE)
  2182. {
  2183. *fTrimmedEnough = FALSE;
  2184. goto SuccessCleanupAndExit;
  2185. }
  2186. }
  2187. // here, the PickleHandle should be valid, and ready for actual pickling
  2188. // do the fine-tuned trimming - actually pickle, and see whether it fits
  2189. Buffer = MIDL_user_allocate(PickleLength);
  2190. if (Buffer == NULL)
  2191. {
  2192. RpcStatus = RPC_S_OUT_OF_MEMORY;
  2193. goto CleanupAndExit;
  2194. }
  2195. BufferLength = PickleLength;
  2196. TempBuffer = (char *)Buffer;
  2197. CurrentlyNeededLength = MaxLength;
  2198. while (TRUE)
  2199. {
  2200. // re-initialize the handle to fixed buffer
  2201. RpcStatus = MesBufferHandleReset(PickleHandle,
  2202. MES_FIXED_BUFFER_HANDLE,
  2203. MES_ENCODE,
  2204. &TempBuffer,
  2205. BufferLength,
  2206. &EncodedSize);
  2207. if (RpcStatus != RPC_S_OK)
  2208. {
  2209. goto CleanupAndExit;
  2210. }
  2211. RpcTryExcept
  2212. {
  2213. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  2214. }
  2215. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2216. {
  2217. RpcStatus = RpcExceptionCode();
  2218. }
  2219. RpcEndExcept
  2220. if (RpcStatus != RPC_S_OK)
  2221. {
  2222. goto CleanupAndExit;
  2223. }
  2224. if (EncodedSize <= CurrentlyNeededLength)
  2225. {
  2226. *fTrimmedEnough = TRUE;
  2227. *NeededLength = EncodedSize;
  2228. goto SuccessCleanupAndExit;
  2229. }
  2230. Result = KnockOffLastButOneEEInfoRecord(EEInfo);
  2231. if (Result == FALSE)
  2232. {
  2233. *fTrimmedEnough = FALSE;
  2234. goto SuccessCleanupAndExit;
  2235. }
  2236. }
  2237. SuccessCleanupAndExit:
  2238. RpcStatus = RPC_S_OK;
  2239. CleanupAndExit:
  2240. if (Buffer != NULL)
  2241. {
  2242. MIDL_user_free(Buffer);
  2243. }
  2244. if (PickleHandle != NULL)
  2245. {
  2246. MesHandleFree(PickleHandle);
  2247. }
  2248. return RpcStatus;
  2249. }
  2250. RPC_STATUS
  2251. GetLengthOfPickledEEInfo (
  2252. IN ExtendedErrorInfo *EEInfo,
  2253. OUT size_t *NeededLength
  2254. )
  2255. /*++
  2256. Routine Description:
  2257. Calculate the length of the given eeinfo when pickled. It
  2258. does that by pickling it in a temporary buffer and
  2259. checking the resulting length.
  2260. Arguments:
  2261. ErrorInfo - the eeinfo chain whose length we need to calculate
  2262. NeededLength - the length in bytes
  2263. Return Value:
  2264. RPC_S_OK or RPC_S_* error
  2265. --*/
  2266. {
  2267. ULONG EncodedSize;
  2268. handle_t PickleHandle = NULL;
  2269. char *TempBuffer;
  2270. RPC_STATUS RpcStatus;
  2271. ExtendedErrorInfoPtr *EEInfoPtr;
  2272. PVOID Buffer = NULL;
  2273. size_t MarshallSize;
  2274. RpcStatus = MesEncodeDynBufferHandleCreate(&TempBuffer, &EncodedSize, &PickleHandle);
  2275. if (RpcStatus != RPC_S_OK)
  2276. {
  2277. return RpcStatus;
  2278. }
  2279. EEInfoPtr = &EEInfo;
  2280. // get the estimated size
  2281. MarshallSize = ExtendedErrorInfoPtr_AlignSize(PickleHandle, EEInfoPtr);
  2282. Buffer = MIDL_user_allocate(MarshallSize);
  2283. if (Buffer == NULL)
  2284. {
  2285. RpcStatus = RPC_S_OUT_OF_MEMORY;
  2286. goto CleanupAndExit;
  2287. }
  2288. TempBuffer = (char *)Buffer;
  2289. // re-initialize the handle to fixed buffer
  2290. RpcStatus = MesBufferHandleReset(PickleHandle,
  2291. MES_FIXED_BUFFER_HANDLE,
  2292. MES_ENCODE,
  2293. &TempBuffer,
  2294. MarshallSize,
  2295. &EncodedSize);
  2296. if (RpcStatus != RPC_S_OK)
  2297. {
  2298. goto CleanupAndExit;
  2299. }
  2300. RpcTryExcept
  2301. {
  2302. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  2303. }
  2304. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2305. {
  2306. RpcStatus = RpcExceptionCode();
  2307. }
  2308. RpcEndExcept
  2309. if (RpcStatus != RPC_S_OK)
  2310. {
  2311. goto CleanupAndExit;
  2312. }
  2313. *NeededLength = EncodedSize;
  2314. CleanupAndExit:
  2315. if (Buffer != NULL)
  2316. {
  2317. MIDL_user_free(Buffer);
  2318. }
  2319. if (PickleHandle != NULL)
  2320. {
  2321. MesHandleFree(PickleHandle);
  2322. }
  2323. return RpcStatus;
  2324. }
  2325. RPC_STATUS
  2326. TrimEEInfoToLengthByRemovingStrings (
  2327. IN ExtendedErrorInfo *EEInfo,
  2328. IN size_t MaxLength,
  2329. OUT BOOL *fTrimmedEnough,
  2330. OUT size_t *NeededLength
  2331. )
  2332. /*++
  2333. Routine Description:
  2334. Try to trim the eeinfo to the given length by whacking any
  2335. strings in the eeinfo chain. After each string is whacked
  2336. a re-measurement is made
  2337. Arguments:
  2338. ErrorInfo - the eeinfo chain that we need to fit in MaxLength
  2339. bytes.
  2340. MaxLength - the length we need to trim to
  2341. fTrimmedEnough - non-zero if we were able to trim the length below
  2342. MaxLength.
  2343. NeededLength - the length in bytes of the trimmed eeinfo. Not
  2344. touched if fTrimmedEnough is FALSE.
  2345. N.B. This function should only be called after
  2346. TrimEEInfoToLengthByRemovingRecords
  2347. Return Value:
  2348. RPC_S_OK or RPC_S_* error
  2349. --*/
  2350. {
  2351. ExtendedErrorInfo *CurrentRecord;
  2352. size_t CurrentLength;
  2353. int i;
  2354. RPC_STATUS RpcStatus;
  2355. BOOL TrimLongParam;
  2356. void *ParameterToTrim;
  2357. // we shouldn't be here if there are more than two records
  2358. if (EEInfo->Next && EEInfo->Next->Next)
  2359. {
  2360. ASSERT(0);
  2361. }
  2362. CurrentRecord = EEInfo;
  2363. while (CurrentRecord != NULL)
  2364. {
  2365. // trim the parameters and remeasure. If still nothing, move on to
  2366. // the computer name.
  2367. for (i = 0; i < EEInfo->nLen; i ++)
  2368. {
  2369. TrimLongParam = FALSE;
  2370. if ((CurrentRecord->Params[i].Type == eeptiAnsiString)
  2371. || (CurrentRecord->Params[i].Type == eeptiUnicodeString))
  2372. {
  2373. TrimLongParam = TRUE;
  2374. // both string pointers occupy the same memory location,
  2375. // so it is ok to free either
  2376. ParameterToTrim = CurrentRecord->Params[i].AnsiString.pString;
  2377. }
  2378. else if (CurrentRecord->Params[i].Type == eeptiBinary)
  2379. {
  2380. TrimLongParam = TRUE;
  2381. ParameterToTrim = CurrentRecord->Params[i].Blob.pBlob;
  2382. }
  2383. if (TrimLongParam)
  2384. {
  2385. MIDL_user_free(CurrentRecord->Params[i].AnsiString.pString);
  2386. CurrentRecord->Params[i].Type = eeptiNone;
  2387. // remeasure
  2388. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, &CurrentLength);
  2389. if (RpcStatus != RPC_S_OK)
  2390. return RpcStatus;
  2391. if (CurrentLength <= MaxLength)
  2392. {
  2393. *NeededLength = CurrentLength;
  2394. *fTrimmedEnough = TRUE;
  2395. return RPC_S_OK;
  2396. }
  2397. }
  2398. }
  2399. // if the computer name is there, try to trim it. If nothing,
  2400. // move on to the next record
  2401. if (CurrentRecord->ComputerName.Type == eecnpPresent)
  2402. {
  2403. // N.B. Not covered by unit tests
  2404. MIDL_user_free(CurrentRecord->ComputerName.Name.pString);
  2405. CurrentRecord->ComputerName.Type = eecnpNotPresent;
  2406. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, &CurrentLength);
  2407. if (RpcStatus != RPC_S_OK)
  2408. return RpcStatus;
  2409. if (CurrentLength <= MaxLength)
  2410. {
  2411. // N.B. Not covered by unit tests
  2412. *NeededLength = CurrentLength;
  2413. *fTrimmedEnough = TRUE;
  2414. return RPC_S_OK;
  2415. }
  2416. // N.B. Not covered by unit tests
  2417. }
  2418. CurrentRecord = CurrentRecord->Next;
  2419. }
  2420. // N.B. In the current implementation, the minimum fragment length
  2421. // belongs to LRPC, and is 0xb8. At this length, two records
  2422. // with strings stripped always fit. Therefore, we can never be
  2423. // here. The code below is untested, and is left only for future
  2424. // work where we have a transport supporting fragment length
  2425. // which doesn't hold two records with strings stripped
  2426. ASSERT(0);
  2427. // if we are here, obviously we couldn't trim enough
  2428. *fTrimmedEnough = FALSE;
  2429. return RPC_S_OK;
  2430. }
  2431. void
  2432. TrimEEInfoToLength (
  2433. IN size_t MaxLength,
  2434. OUT size_t *NeededLength
  2435. )
  2436. /*++
  2437. Routine Description:
  2438. Some protocols don't allow transmitting arbitrary lengths
  2439. of information. This function will attempt to trim the pickled
  2440. length of the existing error information so as to fit MaxLength.
  2441. First, it will try to knock off records, starting from the
  2442. last-but-one, and going back. If this is not sufficient, it will
  2443. whack any string arguments/computer names in the record. If this
  2444. is also, not sufficient, it should drop the top record. This should
  2445. leave the total length to be about 128 bytes. All protocols must
  2446. be able to transmit that, as this routine cannot trim it any
  2447. further.
  2448. If MaxLength is larger than the current pickled length, no trimming
  2449. is done, and the actual pickled length will be returned in
  2450. NeededLength
  2451. Arguments:
  2452. MaxLength - the maximum length for this chain.
  2453. NeededLength - on success, how much we actually need to transfer
  2454. the existing extended error info. This must be less than
  2455. MaxLength. If the function cannot get estimation for some
  2456. reason (probably out-of-memory), or there is no extended
  2457. error information, it will return 0 in this parameter.
  2458. Return Value:
  2459. void
  2460. --*/
  2461. {
  2462. RPC_STATUS RpcStatus;
  2463. BOOL fTrimmedEnough;
  2464. ExtendedErrorInfo *EEInfo;
  2465. THREAD *Thread;
  2466. ExtendedErrorInfo *LastRecord;
  2467. ASSERT(MaxLength >= MinimumTransportEEInfoLength);
  2468. *NeededLength = 0;
  2469. Thread = RpcpGetThreadPointer();
  2470. if (Thread == NULL)
  2471. return;
  2472. EEInfo = Thread->GetEEInfo();
  2473. if (EEInfo == NULL)
  2474. return;
  2475. RpcStatus = TrimEEInfoToLengthByRemovingRecords(EEInfo, MaxLength, &fTrimmedEnough, NeededLength);
  2476. if (RpcStatus != RPC_S_OK)
  2477. return;
  2478. // if fTrimmedEnough is set, NeededLength should have been set
  2479. if (fTrimmedEnough == TRUE)
  2480. {
  2481. ASSERT(*NeededLength <= MaxLength);
  2482. return;
  2483. }
  2484. ASSERT(*NeededLength == 0);
  2485. RpcStatus = TrimEEInfoToLengthByRemovingStrings(EEInfo, MaxLength, &fTrimmedEnough, NeededLength);
  2486. if (RpcStatus != RPC_S_OK)
  2487. return;
  2488. // if fTrimmedEnough is set, NeededLength should have been set
  2489. if (fTrimmedEnough == TRUE)
  2490. {
  2491. ASSERT(*NeededLength <= MaxLength);
  2492. return;
  2493. }
  2494. // N.B. In the current implementation, the minimum fragment length
  2495. // belongs to LRPC, and is 0xb8. At this length, two records
  2496. // with strings stripped always fit. Therefore, we can never be
  2497. // here. The code below is untested, and is left only for future
  2498. // work where we have a transport supporting fragment length
  2499. // which doesn't hold two records with strings stripped
  2500. ASSERT(0);
  2501. // again, we couldn't trim it enough
  2502. // drop the first record
  2503. // make sure there are exactly two records
  2504. // this is so, because if we have only one record,
  2505. // it should have fit by now. If we had more than two
  2506. // records, there is a bug in the trimming records code
  2507. ASSERT(EEInfo->Next);
  2508. ASSERT(EEInfo->Next->Next == NULL);
  2509. LastRecord = EEInfo->Next;
  2510. FreeEEInfoRecord(EEInfo);
  2511. EEInfo = LastRecord;
  2512. Thread->SetEEInfo(LastRecord);
  2513. #if DBG
  2514. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, NeededLength);
  2515. if (RpcStatus != RPC_S_OK)
  2516. return;
  2517. ASSERT(*NeededLength <= MaxLength);
  2518. #endif
  2519. }
  2520. size_t
  2521. EstimateSizeOfEEInfo (
  2522. void
  2523. )
  2524. /*++
  2525. Routine Description:
  2526. Takes the EEInfo from the teb (if any) and calculates the size
  2527. of the pickled eeinfo
  2528. Arguments:
  2529. void
  2530. Return Value:
  2531. the size or 0 if it fails
  2532. --*/
  2533. {
  2534. ExtendedErrorInfo *EEInfo;
  2535. THREAD *Thread;
  2536. RPC_STATUS RpcStatus;
  2537. size_t NeededLength;
  2538. Thread = RpcpGetThreadPointer();
  2539. if (Thread == NULL)
  2540. return 0;
  2541. EEInfo = Thread->GetEEInfo();
  2542. if (EEInfo == NULL)
  2543. return 0;
  2544. RpcStatus = GetLengthOfPickledEEInfo(EEInfo, &NeededLength);
  2545. if (RpcStatus != RPC_S_OK)
  2546. return 0;
  2547. return NeededLength;
  2548. }
  2549. RPC_STATUS
  2550. PickleEEInfo (
  2551. IN ExtendedErrorInfo *EEInfo,
  2552. IN OUT unsigned char *Buffer,
  2553. IN size_t BufferSize
  2554. )
  2555. /*++
  2556. Routine Description:
  2557. This routine does the actual pickling in a user supplied buffer.
  2558. The buffer must have been allocated large enough to hold all
  2559. pickled data. Some of the other functions should have been
  2560. used to get the size of the pickled data and the buffer
  2561. should have been allocated appropriately
  2562. Arguments:
  2563. Buffer - the actual Buffer to pickle into
  2564. BufferSize - the size of the Buffer.
  2565. Return Value:
  2566. RPC_S_OK if the pickling was successful.
  2567. other RPC_S_* codes if it failed.
  2568. --*/
  2569. {
  2570. ULONG EncodedSize;
  2571. handle_t PickleHandle = NULL;
  2572. RPC_STATUS RpcStatus;
  2573. ExtendedErrorInfoPtr *EEInfoPtr;
  2574. ASSERT(((ULONG_PTR)Buffer & 0x7) == 0);
  2575. RpcStatus = MesEncodeFixedBufferHandleCreate((char *)Buffer, BufferSize, &EncodedSize, &PickleHandle);
  2576. if (RpcStatus != RPC_S_OK)
  2577. {
  2578. return RpcStatus;
  2579. }
  2580. EEInfoPtr = &EEInfo;
  2581. RpcTryExcept
  2582. {
  2583. ExtendedErrorInfoPtr_Encode(PickleHandle, EEInfoPtr);
  2584. }
  2585. RpcExcept(I_RpcExceptionFilter(RpcExceptionCode()))
  2586. {
  2587. RpcStatus = RpcExceptionCode();
  2588. }
  2589. RpcEndExcept
  2590. ASSERT(EncodedSize <= BufferSize);
  2591. MesHandleFree(PickleHandle);
  2592. return RpcStatus;
  2593. }
  2594. void
  2595. NukeStaleEEInfoIfNecessary (
  2596. IN RPC_STATUS exception
  2597. )
  2598. /*++
  2599. Routine Description:
  2600. Matches the given error code to the error code in the
  2601. first record of the eeinfo chain in the teb. If they match
  2602. or if there is *no* Win32<->NT_STATUS correspondence b/n them
  2603. the eeinfo in the teb is nuked
  2604. Arguments:
  2605. exception - the error code to match against
  2606. Return Value:
  2607. void
  2608. --*/
  2609. {
  2610. THREAD *Thread;
  2611. ExtendedErrorInfo *EEInfo;
  2612. long ExceptionNtStatus;
  2613. long EEInfoNtStatus;
  2614. Thread = RpcpGetThreadPointer();
  2615. if (Thread)
  2616. {
  2617. EEInfo = Thread->GetEEInfo();
  2618. if (EEInfo && Thread->Context)
  2619. {
  2620. // there is extended info - try to match it to what we have
  2621. ExceptionNtStatus = I_RpcMapWin32Status(exception);
  2622. EEInfoNtStatus = I_RpcMapWin32Status(EEInfo->Status);
  2623. if (EEInfoNtStatus != ExceptionNtStatus)
  2624. {
  2625. // they are not the same - nuke the stale info
  2626. // to prevent confusion
  2627. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  2628. }
  2629. }
  2630. }
  2631. }
  2632. LPWSTR
  2633. AllocateAndGetComputerName (
  2634. IN ComputerNameAllocators AllocatorToUse,
  2635. IN COMPUTER_NAME_FORMAT NameToRetrieve,
  2636. IN size_t ExtraBytes,
  2637. IN int StartingOffset,
  2638. OUT DWORD *Size
  2639. )
  2640. /*++
  2641. Routine Description:
  2642. Allocates space for the computer name and gets it
  2643. Arguments:
  2644. AllocatorToUse - cnaMidl or cnaNew. If cnaMidl is used, MIDL_user_allocate
  2645. will be used to allocate the computer name, If cnaNew is used, new will
  2646. be used for allocating.
  2647. NameToRetreive - standard COMPUTER_NAME_FORMAT enumerator - see MSDN.
  2648. ExtraBytes - extra bytes to allocate in the buffer (in bytes, not in characters!)
  2649. StartingOffset - will put the computer name in the buffer starting at
  2650. the given offset. In bytes, not in characters!
  2651. Size - on output the size of the string in characters, including
  2652. the terminating NULL, but not including the StartingOffset.
  2653. Return Value:
  2654. The computer name or NULL of out-of-memory
  2655. --*/
  2656. {
  2657. DWORD LocalSize = 0;
  2658. BOOL Result;
  2659. LPWSTR Buffer = NULL;
  2660. DWORD LastError;
  2661. Result = GetComputerNameEx(NameToRetrieve,
  2662. Buffer,
  2663. &LocalSize);
  2664. ASSERT(Result == 0);
  2665. LastError = GetLastError();
  2666. if (LastError == ERROR_MORE_DATA)
  2667. {
  2668. if (AllocatorToUse == cnaMidl)
  2669. {
  2670. Buffer = (LPWSTR)MIDL_user_allocate(LocalSize * sizeof(RPC_CHAR) + ExtraBytes);
  2671. }
  2672. else
  2673. {
  2674. ASSERT(AllocatorToUse == cnaNew);
  2675. Buffer = (RPC_CHAR *)new char[LocalSize * sizeof(RPC_CHAR) + ExtraBytes];
  2676. }
  2677. if (Buffer)
  2678. {
  2679. Result = GetComputerNameEx(NameToRetrieve,
  2680. (RPC_CHAR *)((char *)Buffer + StartingOffset),
  2681. &LocalSize);
  2682. if (Result == 0)
  2683. {
  2684. if (AllocatorToUse == cnaMidl)
  2685. {
  2686. MIDL_user_free(Buffer);
  2687. }
  2688. else
  2689. {
  2690. delete Buffer;
  2691. }
  2692. Buffer = NULL;
  2693. }
  2694. else
  2695. {
  2696. // sometimes GetComputerNameEx returns the size
  2697. // without the terminating NULL regardless of what
  2698. // the MSDN says. The base group (Earhart, NeillC)
  2699. // know about it but won't change it for now.
  2700. // Code it in such a way that it works regardless
  2701. // of when and if they change it.
  2702. *Size = wcslen((RPC_CHAR *)((char *)Buffer + StartingOffset)) + 1;
  2703. }
  2704. }
  2705. }
  2706. return Buffer;
  2707. }
  2708. void
  2709. AddComputerNameToChain (
  2710. ExtendedErrorInfo *EEInfo
  2711. )
  2712. /*++
  2713. Routine Description:
  2714. Checks the first record in eeinfo, and if it doesn't have
  2715. a computer name to it, adds it.
  2716. Arguments:
  2717. EEInfo - the eeinfo chain to add the computer name to
  2718. Return Value:
  2719. void - best effort - no guarantees.
  2720. --*/
  2721. {
  2722. LPWSTR Buffer;
  2723. DWORD Size;
  2724. if (EEInfo->ComputerName.Type == eecnpNotPresent)
  2725. {
  2726. Buffer = AllocateAndGetComputerName(cnaMidl,
  2727. ComputerNamePhysicalDnsHostname,
  2728. 0, // extra bytes
  2729. 0, // starting offset
  2730. &Size);
  2731. if (Buffer)
  2732. {
  2733. EEInfo->ComputerName.Type = eecnpPresent;
  2734. EEInfo->ComputerName.Name.nLength = (CSHORT)Size;
  2735. EEInfo->ComputerName.Name.pString = Buffer;
  2736. }
  2737. }
  2738. }
  2739. void
  2740. StripComputerNameIfRedundant (
  2741. ExtendedErrorInfo *EEInfo
  2742. )
  2743. /*++
  2744. Routine Description:
  2745. Checks the first record in eeinfo, and if it does have
  2746. a computer name to it and it is the same as the computer
  2747. name of this machine, remove it. This is done to keep
  2748. the length of the chain short during local calls using
  2749. remote protocols
  2750. Arguments:
  2751. EEInfo - the eeinfo chain to remove the computer name from
  2752. Return Value:
  2753. void
  2754. --*/
  2755. {
  2756. LPWSTR Buffer = NULL;
  2757. DWORD Size;
  2758. if (EEInfo->ComputerName.Type == eecnpPresent)
  2759. {
  2760. Buffer = AllocateAndGetComputerName(cnaMidl,
  2761. ComputerNamePhysicalDnsHostname,
  2762. 0, // extra bytes
  2763. 0, // starting offset
  2764. &Size);
  2765. if (Buffer)
  2766. {
  2767. if (Size != (DWORD)EEInfo->ComputerName.Name.nLength)
  2768. goto CleanupAndExit;
  2769. // The strings are Unicode - need to multiply by two
  2770. if (RpcpMemoryCompare(Buffer, EEInfo->ComputerName.Name.pString, Size * 2) == 0)
  2771. {
  2772. MIDL_user_free(EEInfo->ComputerName.Name.pString);
  2773. EEInfo->ComputerName.Type = eecnpNotPresent;
  2774. }
  2775. }
  2776. }
  2777. CleanupAndExit:
  2778. if (Buffer)
  2779. {
  2780. MIDL_user_free(Buffer);
  2781. }
  2782. }