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.

1382 lines
37 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1996
  5. //
  6. // File: globals.cxx
  7. //
  8. // Contents:
  9. //
  10. // History:
  11. //----------------------------------------------------------------------------
  12. #include "ldap.hxx"
  13. #pragma hdrstop
  14. TCHAR *szProviderName = TEXT("LDAP");
  15. TCHAR *szLDAPNamespaceName = TEXT("LDAP");
  16. TCHAR *szGCNamespaceName = TEXT("GC");
  17. //
  18. // List of interface properties for Generic Objects
  19. //
  20. INTF_PROP_DATA IntfPropsGeneric[] =
  21. {
  22. // 9999 implies BSTR value got using pIADs ptr.
  23. { TEXT("__Class"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  24. { TEXT("__GUID"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  25. { TEXT("__Path"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  26. { TEXT("__Parent"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  27. { TEXT("__Schema"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  28. { TEXT("__URL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  29. // end of list from IADs::get_ methods.
  30. { TEXT("__Genus"), OPERATION_CODE_READABLE,
  31. UMI_TYPE_I4, FALSE, {UMI_GENUS_INSTANCE}},
  32. { TEXT("__Name"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  33. { TEXT("__KEY"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  34. { TEXT("__RELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  35. { TEXT("__RELPATH"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  36. { TEXT("__FULLRELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  37. { TEXT("__PADS_SCHEMA_CONTAINER_PATH"), OPERATION_CODE_READABLE,
  38. 9999, FALSE, {NULL}},
  39. { TEXT("__SECURITY_DESCRIPTOR"), OPERATION_CODE_READWRITE,
  40. 9999, FALSE, {NULL}},
  41. { NULL, 0, 0, FALSE, {0}} // end of data marker
  42. };
  43. //
  44. // Same as generic save that genus is set to schema value.
  45. //
  46. INTF_PROP_DATA IntfPropsSchema[] =
  47. {
  48. // 9999 implies BSTR value got using pIADs ptr.
  49. { TEXT("__Class"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  50. { TEXT("__Path"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  51. { TEXT("__Parent"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  52. { TEXT("__URL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  53. // end of list from IADs::get_ methods.
  54. { TEXT("__Genus"), OPERATION_CODE_READABLE,
  55. UMI_TYPE_I4, FALSE, {UMI_GENUS_CLASS}},
  56. { TEXT("__Name"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  57. { TEXT("__RELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  58. { TEXT("__RELPATH"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  59. { TEXT("__FULLRELURL"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  60. { TEXT("__SUPERCLASS"), OPERATION_CODE_READABLE, 9999, FALSE, {NULL}},
  61. { NULL, 0, 0, FALSE, {0}} // end of data marker
  62. };
  63. //
  64. // Interface property data for connection objects.
  65. //
  66. INTF_PROP_DATA IntfPropsConnection[] =
  67. {
  68. { TEXT("Class"), OPERATION_CODE_READABLE,
  69. UMI_TYPE_LPWSTR, FALSE, {NULL} },
  70. { TEXT("__UserId"), OPERATION_CODE_READWRITE,
  71. UMI_TYPE_LPWSTR, FALSE, {NULL}},
  72. { TEXT("__Password"), OPERATION_CODE_WRITEABLE,
  73. UMI_TYPE_LPWSTR, FALSE, {NULL}},
  74. { TEXT("__SECURE_AUTHENTICATION"), OPERATION_CODE_READWRITE,
  75. UMI_TYPE_BOOL, FALSE, {TRUE}},
  76. { TEXT("__NO_AUTHENTICATION"), OPERATION_CODE_READWRITE,
  77. UMI_TYPE_BOOL, FALSE, {FALSE}},
  78. { TEXT("__PADS_READONLY_SERVER"), OPERATION_CODE_READWRITE,
  79. UMI_TYPE_BOOL, FALSE, {FALSE}},
  80. { TEXT("__PADS_PROMPT_CREDENTIALS"), OPERATION_CODE_READWRITE,
  81. UMI_TYPE_BOOL, FALSE, {FALSE}},
  82. { TEXT("__PADS_SERVER_BIND"), OPERATION_CODE_READWRITE,
  83. UMI_TYPE_BOOL, FALSE, {FALSE}},
  84. { TEXT("__PADS_FAST_BIND"), OPERATION_CODE_READWRITE,
  85. UMI_TYPE_BOOL, FALSE, {FALSE}},
  86. { TEXT("__PADS_USE_SIGNING"), OPERATION_CODE_READWRITE,
  87. UMI_TYPE_BOOL, FALSE, {FALSE}},
  88. { TEXT("__PADS_USE_SEALING"), OPERATION_CODE_READWRITE,
  89. UMI_TYPE_BOOL, FALSE, {FALSE}},
  90. // { TEXT("SecurityFlags"), OPERATION_CODE_READWRITE,
  91. // UMI_TYPE_I4, FALSE, {1}},
  92. { NULL, 0, 0, FALSE, {0}} // end of data marker
  93. };
  94. //
  95. // Interface property data for cursor objects.
  96. //
  97. INTF_PROP_DATA IntfPropsCursor[] =
  98. {
  99. { TEXT("__Filter"), OPERATION_CODE_READWRITE,
  100. UMI_TYPE_LPWSTR, TRUE, {NULL}},
  101. { NULL, 0, 0, FALSE, {0}} // end of data marker
  102. };
  103. //
  104. // Interface properties for query object.
  105. //
  106. INTF_PROP_DATA IntfPropsQuery[]=
  107. {
  108. { TEXT("__SEARCH_SCOPE"), OPERATION_CODE_READWRITE, UMI_TYPE_I4,
  109. FALSE, {LDAP_SCOPE_SUBTREE} },
  110. { TEXT("__PADS_SEARCHPREF_ASYNCHRONOUS"), OPERATION_CODE_READWRITE,
  111. UMI_TYPE_BOOL, FALSE, {FALSE}},
  112. { TEXT("__PADS_SEARCHPREF_DEREF_ALIASES"), OPERATION_CODE_READWRITE,
  113. UMI_TYPE_BOOL, FALSE, {FALSE}},
  114. { TEXT("__PADS_SEARCHPREF_SIZE_LIMIT"), OPERATION_CODE_READWRITE,
  115. UMI_TYPE_I4, FALSE, {0}},
  116. { TEXT("__PADS_SEARCHPREF_TIME_LIMIT"), OPERATION_CODE_READWRITE,
  117. UMI_TYPE_I4, FALSE, {0}},
  118. { TEXT("__PADS_SEARCHPREF_ATTRIBTYPES_ONLY"), OPERATION_CODE_READWRITE,
  119. UMI_TYPE_BOOL, FALSE, {FALSE}},
  120. { TEXT("__PADS_SEARCHPREF_TIMEOUT"), OPERATION_CODE_READWRITE,
  121. UMI_TYPE_I4, FALSE, {0}},
  122. { TEXT("__PADS_SEARCHPREF_PAGESIZE"), OPERATION_CODE_READWRITE,
  123. UMI_TYPE_I4, FALSE, {0}},
  124. { TEXT("__PADS_SEARCHPREF_PAGED_TIME_LIMIT"), OPERATION_CODE_READWRITE,
  125. UMI_TYPE_I4, FALSE, {0}},
  126. { TEXT("__PADS_SEARCHPREF_CHASE_REFERRALS"), OPERATION_CODE_READWRITE,
  127. UMI_TYPE_I4, FALSE, {ADS_CHASE_REFERRALS_EXTERNAL}},
  128. //
  129. // BugBug do we keep this similar to IDirectorySearch or do we not cache.
  130. //
  131. { TEXT("__PADS_SEARCHPREF_CACHE_RESULTS"), OPERATION_CODE_READWRITE,
  132. UMI_TYPE_BOOL, FALSE, {TRUE}},
  133. { TEXT("__PADS_SEARCHPREF_TOMBSTONE"), OPERATION_CODE_READWRITE,
  134. UMI_TYPE_BOOL, FALSE, {FALSE}},
  135. { TEXT("__PADS_SEARCHPREF_FILTER"), OPERATION_CODE_READWRITE,
  136. UMI_TYPE_LPWSTR, FALSE, {0}},
  137. { TEXT("__PADS_SEARCHPREF_ATTRIBUTES"), OPERATION_CODE_READWRITE,
  138. UMI_TYPE_LPWSTR, TRUE, {0}},
  139. { NULL, 0, 0, FALSE, {0}} // end of data marker
  140. };
  141. BOOL g_fDllsLoaded = FALSE;
  142. HANDLE g_hDllNtdsapi = NULL;
  143. HANDLE g_hDllSecur32 = NULL;
  144. CRITICAL_SECTION g_csLoadLibsCritSect;
  145. // load library helper
  146. HMODULE LoadLibraryHelper(
  147. LPTSTR pszFileName
  148. )
  149. {
  150. const DWORD iSize = GetSystemDirectory(NULL, 0);
  151. TCHAR* buffer = NULL;
  152. DWORD dwTemp = 0;
  153. HMODULE handle = NULL;
  154. if(iSize == 0)
  155. {
  156. goto error;
  157. }
  158. buffer = new TCHAR[iSize + _tcslen(__TEXT("\\")) + _tcslen(pszFileName)]; // iSize includes the NULL terminiator
  159. if(!buffer)
  160. {
  161. goto error;
  162. }
  163. dwTemp = GetSystemDirectory(buffer, iSize);
  164. if(dwTemp == 0)
  165. {
  166. goto error;
  167. }
  168. _tcscat(buffer, __TEXT("\\"));
  169. _tcscat(buffer, pszFileName);
  170. handle = LoadLibrary(buffer);
  171. error:
  172. if(buffer)
  173. {
  174. delete [] buffer;
  175. buffer = NULL;
  176. }
  177. return handle;
  178. }
  179. //
  180. // Loads all the dynamic libs we need.
  181. //
  182. void BindToDlls()
  183. {
  184. DWORD dwErr = 0;
  185. if (g_fDllsLoaded) {
  186. return;
  187. }
  188. ENTER_LOADLIBS_CRITSECT();
  189. if (g_fDllsLoaded) {
  190. LEAVE_LOADLIBS_CRITSECT();
  191. return;
  192. }
  193. if (!(g_hDllNtdsapi = LoadLibraryHelper(L"NTDSAPI.DLL"))) {
  194. dwErr = GetLastError();
  195. }
  196. if (g_hDllSecur32 = LoadLibraryHelper(L"SECUR32.DLL")) {
  197. if (dwErr) {
  198. //
  199. // Set the last error for whatever it is worth.
  200. // This does not really matter cause any dll we
  201. // cannot load, we will not get functions on that
  202. // dll. If secur32 load failed, then that call
  203. // would have set a relevant last error.
  204. //
  205. SetLastError(dwErr);
  206. }
  207. }
  208. g_fDllsLoaded = TRUE;
  209. LEAVE_LOADLIBS_CRITSECT();
  210. return;
  211. }
  212. //
  213. // Loads the appropriate ntdsapi fn.
  214. //
  215. PVOID LoadNtDsApiFunction(CHAR *function)
  216. {
  217. if (!g_fDllsLoaded) {
  218. BindToDlls();
  219. }
  220. if (g_hDllNtdsapi) {
  221. return((PVOID*) GetProcAddress((HMODULE) g_hDllNtdsapi, function));
  222. }
  223. return NULL;
  224. }
  225. //
  226. // Loads the appropriate secur32 fn.
  227. //
  228. PVOID LoadSecur32Function(CHAR *function)
  229. {
  230. if (!g_fDllsLoaded) {
  231. BindToDlls();
  232. }
  233. if (g_hDllSecur32) {
  234. return((PVOID*) GetProcAddress((HMODULE) g_hDllSecur32, function));
  235. }
  236. return NULL;
  237. }
  238. //
  239. // DsUnquoteRdnValueWrapper
  240. //
  241. DWORD DsUnquoteRdnValueWrapper(
  242. IN DWORD cQuotedRdnValueLength,
  243. IN LPCWSTR psQuotedRdnValue,
  244. IN OUT DWORD *pcUnquotedRdnValueLength,
  245. OUT LPWSTR psUnquotedRdnValue
  246. )
  247. {
  248. static PF_DsUnquoteRdnValueW pfDsUnquoteRdnVal = NULL;
  249. static BOOL f_LoadAttempted = FALSE;
  250. //
  251. // Load the fn and set the variables accordingly.
  252. //
  253. if (!f_LoadAttempted && pfDsUnquoteRdnVal == NULL) {
  254. pfDsUnquoteRdnVal =
  255. (PF_DsUnquoteRdnValueW) LoadNtDsApiFunction(DSUNQUOTERDN_API);
  256. f_LoadAttempted = TRUE;
  257. }
  258. if (pfDsUnquoteRdnVal != NULL) {
  259. return ((*pfDsUnquoteRdnVal)(
  260. cQuotedRdnValueLength,
  261. psQuotedRdnValue,
  262. pcUnquotedRdnValueLength,
  263. psUnquotedRdnValue
  264. )
  265. );
  266. }
  267. else {
  268. return (ERROR_GEN_FAILURE);
  269. }
  270. }
  271. //
  272. // DsMakePasswordCredentialsWrapper
  273. //
  274. DWORD DsMakePasswordCredentialsWrapper(
  275. LPCWSTR User,
  276. LPCWSTR Domain,
  277. LPCWSTR Password,
  278. RPC_AUTH_IDENTITY_HANDLE *pAuthIdentity
  279. )
  280. {
  281. static PF_DsMakePasswordCredentialsW pfMakePwdCreds = NULL;
  282. static BOOL f_LoadAttempted = FALSE;
  283. //
  284. // Load the fn and set the variables accordingly.
  285. //
  286. if (!f_LoadAttempted && pfMakePwdCreds == NULL) {
  287. pfMakePwdCreds = (PF_DsMakePasswordCredentialsW)
  288. LoadNtDsApiFunction(DSMAKEPASSWD_CRED_API);
  289. f_LoadAttempted = TRUE;
  290. }
  291. if (pfMakePwdCreds != NULL) {
  292. return ((*pfMakePwdCreds)(
  293. User,
  294. Domain,
  295. Password,
  296. pAuthIdentity
  297. )
  298. );
  299. }
  300. else {
  301. return (ERROR_GEN_FAILURE);
  302. }
  303. }
  304. //
  305. // DsFreePasswordCredentialsWrapper
  306. //
  307. DWORD DsFreePasswordCredentialsWrapper(
  308. RPC_AUTH_IDENTITY_HANDLE AuthIdentity
  309. )
  310. {
  311. static PF_DsFreePasswordCredentials pfFreeCreds = NULL;
  312. static BOOL f_LoadAttempted = FALSE;
  313. //
  314. // Load the fn and set the variables accordingly.
  315. //
  316. if (!f_LoadAttempted && pfFreeCreds == NULL) {
  317. pfFreeCreds = (PF_DsFreePasswordCredentials)
  318. LoadNtDsApiFunction(DSFREEPASSWD_CRED_API);
  319. f_LoadAttempted = TRUE;
  320. }
  321. if (pfFreeCreds != NULL) {
  322. return ((*pfFreeCreds)(
  323. AuthIdentity
  324. )
  325. );
  326. }
  327. else {
  328. return (ERROR_GEN_FAILURE);
  329. }
  330. }
  331. //
  332. // DsBindWrapper.
  333. //
  334. DWORD DsBindWrapper(
  335. LPCWSTR DomainControllerName,
  336. LPCWSTR DnsDomainName,
  337. HANDLE *phDS
  338. )
  339. {
  340. static PF_DsBindW pfDsBind = NULL;
  341. static BOOL f_LoadAttempted = FALSE;
  342. //
  343. // Load the fn and set the variables accordingly.
  344. //
  345. if (!f_LoadAttempted && pfDsBind == NULL) {
  346. pfDsBind = (PF_DsBindW) LoadNtDsApiFunction(DSBIND_API);
  347. f_LoadAttempted = TRUE;
  348. }
  349. if (pfDsBind != NULL) {
  350. return ((*pfDsBind)(
  351. DomainControllerName,
  352. DnsDomainName,
  353. phDS
  354. )
  355. );
  356. }
  357. else {
  358. return (ERROR_GEN_FAILURE);
  359. }
  360. }
  361. //
  362. // DsUnBindWrapper.
  363. //
  364. DWORD DsUnBindWrapper(
  365. HANDLE *phDS
  366. )
  367. {
  368. static PF_DsUnbindW pfDsUnbind = NULL;
  369. static BOOL f_LoadAttempted = FALSE;
  370. //
  371. // Load the fn and set the variables accordingly.
  372. //
  373. if (!f_LoadAttempted && pfDsUnbind == NULL) {
  374. pfDsUnbind = (PF_DsUnbindW) LoadNtDsApiFunction(DSUNBIND_API);
  375. f_LoadAttempted = TRUE;
  376. }
  377. if (pfDsUnbind != NULL) {
  378. return ((*pfDsUnbind)(
  379. phDS
  380. )
  381. );
  382. }
  383. else {
  384. return (ERROR_GEN_FAILURE);
  385. }
  386. }
  387. //
  388. // DsCrackNamesWrapper.
  389. //
  390. DWORD DsCrackNamesWrapper(
  391. HANDLE hDS,
  392. DS_NAME_FLAGS flags,
  393. DS_NAME_FORMAT formatOffered,
  394. DS_NAME_FORMAT formatDesired,
  395. DWORD cNames,
  396. const LPCWSTR *rpNames,
  397. PDS_NAME_RESULTW *ppResult
  398. )
  399. {
  400. static PF_DsCrackNamesW pfDsCrackNames = NULL;
  401. static BOOL f_LoadAttempted = FALSE;
  402. //
  403. // Load the fn and set the variables accordingly.
  404. //
  405. if (!f_LoadAttempted && pfDsCrackNames == NULL) {
  406. pfDsCrackNames = (PF_DsCrackNamesW)
  407. LoadNtDsApiFunction(DSCRACK_NAMES_API);
  408. f_LoadAttempted = TRUE;
  409. }
  410. if (pfDsCrackNames != NULL) {
  411. return ((*pfDsCrackNames)(
  412. hDS,
  413. flags,
  414. formatOffered,
  415. formatDesired,
  416. cNames,
  417. rpNames,
  418. ppResult
  419. )
  420. );
  421. }
  422. else {
  423. return (ERROR_GEN_FAILURE);
  424. }
  425. }
  426. //
  427. // DsBindWithCredWrapper.
  428. //
  429. DWORD DsBindWithCredWrapper(
  430. LPCWSTR DomainControllerName,
  431. LPCWSTR DnsDomainName,
  432. RPC_AUTH_IDENTITY_HANDLE AuthIdentity,
  433. HANDLE *phDS
  434. )
  435. {
  436. static PF_DsBindWithCredW pfDsBindWithCred = NULL;
  437. static BOOL f_LoadAttempted = FALSE;
  438. //
  439. // Load the fn and set the variables accordingly.
  440. //
  441. if (!f_LoadAttempted && pfDsBindWithCred == NULL) {
  442. pfDsBindWithCred = (PF_DsBindWithCredW)
  443. LoadNtDsApiFunction(DSBINDWITHCRED_API);
  444. f_LoadAttempted = TRUE;
  445. }
  446. if (pfDsBindWithCred != NULL) {
  447. return ((*pfDsBindWithCred)(
  448. DomainControllerName,
  449. DnsDomainName,
  450. AuthIdentity,
  451. phDS
  452. )
  453. );
  454. }
  455. else {
  456. return (ERROR_GEN_FAILURE);
  457. }
  458. }
  459. //
  460. // DsFreeNameResultWrapper.
  461. //
  462. DWORD DsFreeNameResultWrapper(
  463. DS_NAME_RESULTW *pResult
  464. )
  465. {
  466. static PF_DsFreeNameResultW pfDsFreeNameResult = NULL;
  467. static BOOL f_LoadAttempted = FALSE;
  468. //
  469. // Load the fn and set the variables accordingly.
  470. //
  471. if (!f_LoadAttempted && pfDsFreeNameResult == NULL) {
  472. pfDsFreeNameResult = (PF_DsFreeNameResultW)
  473. LoadNtDsApiFunction(DSFREENAME_RESULT_API);
  474. f_LoadAttempted = TRUE;
  475. }
  476. if (pfDsFreeNameResult != NULL) {
  477. return ((*pfDsFreeNameResult)(
  478. pResult
  479. )
  480. );
  481. }
  482. else {
  483. return (ERROR_GEN_FAILURE);
  484. }
  485. }
  486. //
  487. // QueryContextAttributesWrapper.
  488. //
  489. DWORD QueryContextAttributesWrapper(
  490. PCtxtHandle phContext,
  491. unsigned long ulAttribute,
  492. void SEC_FAR * pBuffer
  493. )
  494. {
  495. static PF_QueryContextAttributes pfQueryCtxtAttr = NULL;
  496. static BOOL f_LoadAttempted = FALSE;
  497. //
  498. // Load the fn and set the variables accordingly.
  499. //
  500. if (!f_LoadAttempted && pfQueryCtxtAttr == NULL) {
  501. pfQueryCtxtAttr = (PF_QueryContextAttributes)
  502. LoadSecur32Function(QUERYCONTEXT_ATTR_API);
  503. f_LoadAttempted = TRUE;
  504. }
  505. if (pfQueryCtxtAttr != NULL) {
  506. return ((*pfQueryCtxtAttr)(
  507. phContext,
  508. ulAttribute,
  509. pBuffer
  510. )
  511. );
  512. }
  513. else {
  514. return (ERROR_GEN_FAILURE);
  515. }
  516. }
  517. //+---------------------------------------------------------------------------
  518. // Function: UrlToClassAndDn - global scope, helper function.
  519. //
  520. // Synopsis: This function takes strings of the following formats and
  521. // returns the class name and dn part in the appropriate return
  522. // values :
  523. // 1) Fully qualified = user.cn=MyTestUser,
  524. // 2) Full Name (umi) = .cn=MyTestUser,
  525. // 3) ADSI style RDN = cn=MyTestUser.
  526. //
  527. // Arguments: pUrl - IUmiURL pointer.
  528. // ppszDN - Contains returned DN (callee must free
  529. // using FreeADsStr.
  530. // ppszClass - Contains returned class name string. It
  531. // is the callees responsiblity to free using
  532. // FreeADsStrResult.
  533. //
  534. // Returns: HRESULT - S_OK or any failure ecode.
  535. //
  536. // Modifies: *ppszDN && *ppszClass.
  537. //
  538. //----------------------------------------------------------------------------
  539. HRESULT
  540. UrlToClassAndDn(
  541. IN IUmiURL *pUrl,
  542. OUT LPWSTR *ppszClass,
  543. OUT LPWSTR *ppszDN
  544. )
  545. {
  546. HRESULT hr;
  547. WCHAR pszTxt[1024];
  548. ULONG ulLen = 1023;
  549. WCHAR *pszUrlTxt = pszTxt;
  550. LPCWSTR pszUrlTxtCopy = NULL;
  551. LPWSTR pszDN = NULL, pszClass = NULL;
  552. DWORD dwClassCount = 0;
  553. *ppszDN = *ppszClass = NULL;
  554. ADsAssert(pUrl);
  555. //
  556. // Something on the url object telling us what is wrong will help.
  557. //
  558. //
  559. // We need to get hold of the string from the url.
  560. //
  561. hr = pUrl->Get(0, &ulLen, pszUrlTxt);
  562. // replace the correct error code below WBEM_E_BUFFER_TOO_SMALL
  563. if (hr == 0x8004103c) {
  564. //
  565. // not enough space in our buffer, lets try again.
  566. //
  567. pszUrlTxt = (WCHAR*) AllocADsMem(ulLen * sizeof(WCHAR));
  568. if (!pszUrlTxt) {
  569. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  570. }
  571. hr = pUrl->Get(0, &ulLen, pszUrlTxt);
  572. }
  573. BAIL_ON_FAILURE(hr);
  574. pszUrlTxtCopy = pszUrlTxt;
  575. //
  576. // Look for the . if there is one that is.
  577. //
  578. while (*pszUrlTxtCopy
  579. && (*pszUrlTxtCopy != L'.')
  580. && (*pszUrlTxtCopy != L'=')
  581. ) {
  582. dwClassCount++;
  583. pszUrlTxtCopy++;
  584. }
  585. if (!*pszUrlTxtCopy) {
  586. //
  587. // There was no = in the url has to be a bad RDN.
  588. //
  589. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  590. }
  591. //
  592. // Urls without a . or not valid.
  593. //
  594. if (*pszUrlTxtCopy != L'.') {
  595. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  596. }
  597. if (*pszUrlTxtCopy == L'=') {
  598. //
  599. // We do not have any class name
  600. //
  601. pszDN = AllocADsStr(pszUrlTxt);
  602. if (!pszDN) {
  603. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  604. }
  605. }
  606. else {
  607. //
  608. // If the count is zero then we have .cn=something
  609. //
  610. if (dwClassCount == 0) {
  611. pszDN = AllocADsStr(++pszUrlTxtCopy);
  612. if (!pszDN) {
  613. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  614. }
  615. }
  616. else {
  617. //
  618. // A valid class name is present.
  619. //
  620. pszClass = (LPWSTR) AllocADsMem(sizeof(WCHAR) * (dwClassCount+1));
  621. if (!pszClass) {
  622. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  623. }
  624. wcsncpy(pszClass, pszUrlTxt, dwClassCount);
  625. //
  626. // Advance beyond the . in the url and copy the rdn.
  627. //
  628. pszUrlTxtCopy++;
  629. if (!*pszUrlTxtCopy) {
  630. //
  631. // Only class name, no RDN.
  632. //
  633. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  634. }
  635. pszDN = AllocADsStr(pszUrlTxtCopy);
  636. if (!pszDN) {
  637. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  638. }
  639. } // end of else that is dwClassCount != 0
  640. } // end of else corresponding to class name or . present
  641. //
  642. // Alloc class name into new str so we can free using FreeADsStr.
  643. //
  644. if (pszClass) {
  645. *ppszClass = AllocADsStr(pszClass);
  646. if (!*ppszClass) {
  647. BAIL_ON_FAILURE(hr);
  648. }
  649. FreeADsMem(pszClass);
  650. }
  651. *ppszDN = pszDN;
  652. error:
  653. if (pszUrlTxt && (pszUrlTxt != pszTxt)) {
  654. FreeADsMem(pszUrlTxt);
  655. }
  656. //
  657. // Free the DN and Class only if applicable.
  658. //
  659. if (FAILED(hr)) {
  660. if (pszDN) {
  661. FreeADsStr(pszDN);
  662. }
  663. if (pszClass) {
  664. FreeADsMem(pszClass);
  665. }
  666. }
  667. RRETURN(hr);
  668. }
  669. HRESULT
  670. GetRDn(
  671. IUmiURL *pURL,
  672. DWORD dwComponent,
  673. LPWSTR pszRDn,
  674. DWORD dwRDnLen
  675. )
  676. {
  677. HRESULT hr = S_OK;
  678. IUmiURLKeyList * pKeyList = NULL;
  679. DWORD dwLen = dwRDnLen;
  680. DWORD dwKeyNameLen = 64;
  681. WCHAR szKeyName[64];
  682. LPWSTR pszTmpStr = NULL;
  683. BOOL fSchema = FALSE;
  684. pszTmpStr = (WCHAR*)AllocADsMem(dwRDnLen);
  685. if (!pszTmpStr) {
  686. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  687. }
  688. //
  689. // Get the component we need, num is passed in.
  690. //
  691. hr = pURL->GetComponent(
  692. dwComponent,
  693. &dwLen,
  694. pszRDn,
  695. &pKeyList
  696. );
  697. BAIL_ON_FAILURE(hr);
  698. if (!pKeyList) {
  699. BAIL_ON_FAILURE(hr = UMI_E_NOT_FOUND);
  700. }
  701. //
  702. // Make sure that the key count is only one, anything
  703. //else cannot be an LDAP path component.
  704. //
  705. hr = pKeyList->GetCount(&dwLen);
  706. BAIL_ON_FAILURE(hr);
  707. if (dwLen != 1) {
  708. //
  709. // Need to see if we have the pszRDN set, if so that is the
  710. // RDN itself - for example Schema or RootDSE.
  711. //
  712. if (pszRDn) {
  713. goto error;
  714. }
  715. BAIL_ON_FAILURE(hr = UMI_E_NOT_FOUND);
  716. }
  717. dwLen = dwRDnLen;
  718. //
  719. // Get the RDN from the key !.
  720. //
  721. hr = pKeyList->GetKey(
  722. 0,
  723. 0,
  724. &dwKeyNameLen,
  725. szKeyName,
  726. &dwLen,
  727. pszTmpStr
  728. );
  729. BAIL_ON_FAILURE(hr);
  730. //
  731. // We need to special case class.Name=User. This means
  732. // we are looking for a class called user not an instance
  733. // of class with RDN Name=User.
  734. //
  735. fSchema = !_wcsicmp(pszRDn, L"Class")
  736. || !_wcsicmp(pszRDn, L"Schema")
  737. || !_wcsicmp(pszRDn, L"Property")
  738. || !_wcsicmp(pszRDn, L"Syntax");
  739. if (fSchema
  740. && szKeyName
  741. && !_wcsicmp(szKeyName, L"Name")
  742. ) {
  743. //
  744. // We have class.Name=User.
  745. //
  746. wsprintf(pszRDn, L"%s", pszTmpStr);
  747. }
  748. else {
  749. //
  750. // We have right values and this is the normal code path.
  751. //
  752. wsprintf(pszRDn, L"%s=",szKeyName);
  753. wcscat(pszRDn, pszTmpStr);
  754. }
  755. error:
  756. if (pKeyList) {
  757. pKeyList->Release();
  758. }
  759. if (pszTmpStr) {
  760. FreeADsMem(pszTmpStr);
  761. }
  762. RRETURN(hr);
  763. }
  764. HRESULT
  765. GetDNFromURL(
  766. IUmiURL *pURL,
  767. LPWSTR *pszDnStr,
  768. DWORD dwTotalLen
  769. )
  770. {
  771. HRESULT hr = S_OK;
  772. DWORD dwNumComponents = 0, dwCtr = 0;
  773. LPWSTR pszLocalDn = NULL;
  774. LPWSTR pszRDn = NULL;
  775. *pszDnStr = NULL;
  776. hr = pURL->GetComponentCount(&dwNumComponents);
  777. BAIL_ON_FAILURE(hr);
  778. if (dwNumComponents == 0) {
  779. //
  780. // DnStr is NULL in this case.
  781. //
  782. RRETURN(hr);
  783. }
  784. //
  785. // This is for the retval.
  786. //
  787. pszLocalDn = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR));
  788. if (!pszLocalDn) {
  789. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  790. }
  791. //
  792. // This is for the rdn's, this buffer should be more than enough
  793. //
  794. pszRDn = (LPWSTR) AllocADsMem(dwTotalLen * sizeof(WCHAR));
  795. if (!pszRDn) {
  796. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  797. }
  798. //
  799. // We need to get each of the individuals dn's and keep adding
  800. // them to the dn we return.
  801. //
  802. for (dwCtr = 0; dwCtr < dwNumComponents; dwCtr++) {
  803. *pszRDn = NULL;
  804. hr = GetRDn(pURL, (dwNumComponents-1) - dwCtr, pszRDn, dwTotalLen);
  805. BAIL_ON_FAILURE(hr);
  806. if (*pszRDn) {
  807. wcscat(pszLocalDn, pszRDn);
  808. if (dwCtr != (dwNumComponents - 1)) {
  809. wcscat(pszLocalDn, L",");
  810. }
  811. }
  812. else {
  813. BAIL_ON_FAILURE(hr = E_FAIL);
  814. }
  815. }
  816. //
  817. // We must have the correct DN !
  818. //
  819. *pszDnStr = pszLocalDn;
  820. error:
  821. if (FAILED(hr)) {
  822. if (pszLocalDn) {
  823. FreeADsMem(pszLocalDn);
  824. }
  825. }
  826. if (pszRDn) {
  827. FreeADsMem(pszRDn);
  828. }
  829. RRETURN(hr);
  830. }
  831. //+---------------------------------------------------------------------------
  832. // Function: UrlToLDAPPath - global scope, helper function.
  833. //
  834. // Synopsis: This routine converts the URL to the
  835. //
  836. // Arguments: pURL - URL to be converted to path. Note
  837. // that this can be native or Umi.
  838. // pszLDAPPath - Path is allocated into this var.
  839. // ppszDn -
  840. // ppszClass - Contains returned class name string. It
  841. // is the callees responsiblity to free using
  842. // FreeADsStrResult.
  843. //
  844. // Returns: HRESULT - S_OK or any failure ecode.
  845. //
  846. // Modifies: *ppszDN && *ppszClass.
  847. //
  848. //----------------------------------------------------------------------------
  849. HRESULT
  850. UrlToLDAPPath(
  851. IN IUmiURL *pURL,
  852. OUT LPWSTR *ppszLDAPPath,
  853. OPTIONAL OUT LPWSTR *ppszDn,
  854. OPTIONAL OUT LPWSTR *ppszServer
  855. )
  856. {
  857. HRESULT hr = S_OK;
  858. DWORD dwURLType = 0;
  859. DWORD dwLen = 1023;
  860. DWORD dwTxtLen = 1023;
  861. WCHAR pszTxt[1024];
  862. LPWSTR pszDn = NULL;
  863. LPWSTR pszLdapPath = NULL;
  864. BOOL fAddSlash = FALSE;
  865. ULONGLONG ululPathType = UMIPATH_INFO_INSTANCE_PATH;
  866. //
  867. // We need the type of the url, if it is an ldap native path.
  868. // For now though this support is not available. We assume that
  869. // this is a umi path for now.
  870. //
  871. //
  872. // Get the total length needed for the path.
  873. //
  874. hr = pURL->Get(0, &dwLen, pszTxt);
  875. // replace the correct error code below WBEM_E_BUFFER_TOO_SMALL
  876. if ((FAILED(hr) && (hr != 0x8004103c))
  877. || (dwLen == 0)) {
  878. //
  879. // Failure was either length was zero or error was someting
  880. // other than buffer too small.
  881. //
  882. BAIL_ON_FAILURE(hr);
  883. }
  884. dwLen++; // for the terminating \0.
  885. pszLdapPath = (LPWSTR) AllocADsMem(dwLen * sizeof(WCHAR));
  886. if (!pszLdapPath) {
  887. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  888. }
  889. hr = pURL->GetPathInfo(0, &ululPathType);
  890. BAIL_ON_FAILURE(hr);
  891. if (ululPathType == UMIPATH_INFO_NATIVE_STRING) {
  892. //
  893. // Just get the path in pszLdapPath and return.
  894. //
  895. hr = pURL->Get(0, &dwLen, pszLdapPath);
  896. BAIL_ON_FAILURE(hr);
  897. }
  898. else {
  899. //
  900. // Make sure that the namespace is either LDAP or GC.
  901. // We bail on failure cause we cannot possibly have a locator
  902. // that is more than our buffer size !
  903. //
  904. hr = pURL->GetRootNamespace(&dwTxtLen, pszTxt);
  905. BAIL_ON_FAILURE(hr);
  906. if (!_wcsicmp(L"LDAP", pszTxt)) {
  907. wsprintf(pszLdapPath, L"%s", L"LDAP:");
  908. }
  909. else if (!_wcsicmp(L"GC", pszTxt)) {
  910. wsprintf(pszLdapPath, L"%s", L"GC:");
  911. }
  912. else {
  913. BAIL_ON_FAILURE(hr = UMI_E_NOT_FOUND);
  914. }
  915. //
  916. // We now need to add the server and the // if applicable.
  917. //
  918. dwTxtLen = 1023;
  919. hr = pURL->GetLocator(&dwTxtLen, pszTxt);
  920. if (hr == 0x8004103c) {
  921. //
  922. // Unexpected cause locator is too big !.
  923. //
  924. hr = E_FAIL;
  925. }
  926. BAIL_ON_FAILURE(hr);
  927. if (!wcscmp(pszTxt, L".")) {
  928. //
  929. // This would mean we are going serverless.
  930. //
  931. wcscat(pszLdapPath, L"/");
  932. }
  933. else if (!*pszTxt) {
  934. //
  935. // Means that we have the LDAP namespace or no server.
  936. //
  937. fAddSlash = TRUE;
  938. }
  939. else {
  940. //
  941. // Add the // and the servername given.
  942. //
  943. wcscat(pszLdapPath, L"//");
  944. wcscat(pszLdapPath, pszTxt);
  945. }
  946. //
  947. // Now we need to get the DN and tag it along.
  948. //
  949. hr = GetDNFromURL(pURL, &pszDn, dwLen);
  950. BAIL_ON_FAILURE(hr);
  951. if (pszDn && *pszDn) {
  952. if (fAddSlash) {
  953. //
  954. // Serverless path.
  955. //
  956. wcscat(pszLdapPath, L"/");
  957. }
  958. //
  959. // Tag on the DN now, it will do the right thing for
  960. // both server and serverless paths.
  961. //
  962. wcscat(pszLdapPath,L"/");
  963. wcscat(pszLdapPath,pszDn);
  964. }
  965. } // this was not a native path.
  966. *ppszLDAPPath = pszLdapPath;
  967. error:
  968. if (FAILED(hr)) {
  969. if (pszLdapPath) {
  970. FreeADsMem(pszLdapPath);
  971. }
  972. }
  973. if (pszDn) {
  974. FreeADsMem(pszDn);
  975. }
  976. RRETURN(hr);
  977. }
  978. //+---------------------------------------------------------------------------
  979. // Function: ADsPathToUmiUrl - global scope, helper function.
  980. //
  981. // Synopsis: This routine converts the ADsPath to UMI URL txt.
  982. //
  983. // Arguments: ADsPath - Input string.
  984. // ppszUrlTxt - Output converted url txt.
  985. //
  986. // Returns: HRESULT - S_OK or any failure ecode.
  987. //
  988. // Modifies: *ppszUrlTxt - to point to the correct
  989. //
  990. //----------------------------------------------------------------------------
  991. HRESULT
  992. ADsPathToUmiURL(
  993. IN LPWSTR ADsPath,
  994. OUT LPWSTR *ppszUrlTxt
  995. )
  996. {
  997. HRESULT hr = S_OK;
  998. OBJECTINFO ObjectInfo;
  999. POBJECTINFO pObjectInfo = &ObjectInfo;
  1000. DWORD dwNumComponents = 0, dwCtr;
  1001. LPWSTR pszUrl = NULL;
  1002. BOOL fReverseOrder = TRUE;
  1003. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1004. ADsAssert(ADsPath && ppszUrlTxt);
  1005. *ppszUrlTxt = NULL;
  1006. //
  1007. // We build our ObjectInfo struct and then build the url
  1008. // from the objectInfo struct.
  1009. //
  1010. pObjectInfo->ObjectType = TOKEN_LDAPOBJECT;
  1011. hr = ADsObject(ADsPath, pObjectInfo);
  1012. BAIL_ON_FAILURE(hr);
  1013. dwNumComponents = pObjectInfo->NumComponents;
  1014. //
  1015. // We can make a guess as to the size we need for the string.
  1016. //
  1017. pszUrl = (WCHAR *) AllocADsMem(
  1018. ( sizeof(WCHAR) * wcslen(ADsPath) )
  1019. // for the actual name
  1020. + (sizeof(WCHAR) * dwNumComponents)
  1021. // for all the .'s we need as in .DC=test
  1022. + (sizeof(WCHAR) * 15)
  1023. );
  1024. //
  1025. // sizeof(WCHAR) * 15 has been added so that we can handle
  1026. // the umi:// (6) which is extra + if we have a GC path, then
  1027. // we would need to add LDAP/ (5) just in case a small buffer
  1028. // of 4 giving the 15
  1029. //
  1030. if (!pszUrl) {
  1031. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1032. }
  1033. //
  1034. // Get the umi:// in the output, then add the server if applicable,
  1035. // then the LDAP/GC or LDAP alone as applicable.
  1036. //
  1037. wsprintf(pszUrl, L"%s", L"umi://");
  1038. if (pObjectInfo->dwServerPresent) {
  1039. if (pObjectInfo->TreeName) {
  1040. wcscat(pszUrl, pObjectInfo->TreeName);
  1041. }
  1042. }
  1043. wcscat(pszUrl, L"/"); // need if there is a server or not.
  1044. wcscat(pszUrl, L"LDAP"); // needed if LDAP or GC.
  1045. if (!_wcsicmp(pObjectInfo->ProviderName, szGCNamespaceName)) {
  1046. wcscat(pszUrl, L"/GC");
  1047. }
  1048. //
  1049. // This is to check if we were given an LDAP windows style path,
  1050. // with reverse order rather than LDAP dn style path.
  1051. //
  1052. if (pObjectInfo->dwPathType == ADS_PATHTYPE_ROOTFIRST) {
  1053. //
  1054. // Already reversed so just use the order directly.
  1055. //
  1056. for (dwCtr = 0; dwCtr < dwNumComponents; dwCtr++) {
  1057. //
  1058. // When you have a path like LDAP://RootDSE, then the szComponent
  1059. // alone is set and not the value in these cases we need to
  1060. // build the path in a different manner.
  1061. //
  1062. if (pObjectInfo->ComponentArray[dwCtr].szValue) {
  1063. wcscat(pszUrl, L"/.");
  1064. wcscat(
  1065. pszUrl,
  1066. pObjectInfo->ComponentArray[dwCtr].szComponent
  1067. );
  1068. wcscat(pszUrl, L"=");
  1069. wcscat(pszUrl, pObjectInfo->ComponentArray[dwCtr].szValue);
  1070. }
  1071. else {
  1072. //
  1073. // We just have a component as in RootDSE or Schema so.
  1074. //
  1075. wcscat(pszUrl, L"/");
  1076. wcscat(
  1077. pszUrl,
  1078. pObjectInfo->ComponentArray[dwCtr].szComponent
  1079. );
  1080. }
  1081. }
  1082. }
  1083. else {
  1084. //
  1085. // Need to do this reverse order.
  1086. //
  1087. for (dwCtr = dwNumComponents; dwCtr > 0; dwCtr--) {
  1088. //
  1089. // When you have a path like LDAP://RootDSE, then the szComponent
  1090. // alone is set and not the value in these cases we need to
  1091. // build the path in a different manner.
  1092. //
  1093. if (pObjectInfo->ComponentArray[dwCtr-1].szValue) {
  1094. wcscat(pszUrl, L"/.");
  1095. wcscat(
  1096. pszUrl,
  1097. pObjectInfo->ComponentArray[dwCtr-1].szComponent
  1098. );
  1099. wcscat(pszUrl, L"=");
  1100. wcscat(pszUrl, pObjectInfo->ComponentArray[dwCtr-1].szValue);
  1101. }
  1102. else {
  1103. //
  1104. // We just have a component as in RootDSE or Schema so.
  1105. //
  1106. wcscat(pszUrl, L"/");
  1107. wcscat(
  1108. pszUrl,
  1109. pObjectInfo->ComponentArray[dwCtr-1].szComponent
  1110. );
  1111. }
  1112. }
  1113. }
  1114. *ppszUrlTxt = pszUrl;
  1115. error:
  1116. if (FAILED(hr)) {
  1117. if (pszUrl) {
  1118. FreeADsMem(pszUrl);
  1119. }
  1120. }
  1121. if (pObjectInfo) {
  1122. FreeObjectInfo(pObjectInfo);
  1123. }
  1124. RRETURN(hr);
  1125. }
  1126. BOOL
  1127. IsPreDefinedErrorCode(HRESULT hr)
  1128. {
  1129. switch (hr) {
  1130. case E_UNEXPECTED :
  1131. case E_NOTIMPL :
  1132. case E_OUTOFMEMORY :
  1133. case E_INVALIDARG :
  1134. case E_NOINTERFACE :
  1135. case E_HANDLE :
  1136. case E_ABORT :
  1137. case E_FAIL :
  1138. case E_ACCESSDENIED :
  1139. case E_PENDING :
  1140. case E_POINTER :
  1141. case UMI_E_CONNECTION_FAILURE :
  1142. case UMI_E_TIMED_OUT :
  1143. case UMI_E_TYPE_MISMATCH :
  1144. case UMI_E_NOT_FOUND :
  1145. case UMI_E_INVALID_FLAGS :
  1146. case UMI_E_UNSUPPORTED_FLAGS :
  1147. case UMI_E_SYNCHRONIZATION_REQUIRED :
  1148. case UMI_E_UNSUPPORTED_OPERATION :
  1149. case UMI_E_TRANSACTION_FAILURE :
  1150. RRETURN(TRUE);
  1151. break;
  1152. default:
  1153. RRETURN(FALSE);
  1154. break;
  1155. }
  1156. }
  1157. //+---------------------------------------------------------------------------
  1158. // Function: MapHrToUmiError - global scope, helper function.
  1159. //
  1160. // Synopsis: This routine converts the given hr to an equivalent umi err.
  1161. //
  1162. // Arguments: hr - hr to convert to umi error.
  1163. //
  1164. // Returns: HRESULT - umi error code corresponing to hr passed in.
  1165. //
  1166. // Modifies: N/A.
  1167. //
  1168. //----------------------------------------------------------------------------
  1169. HRESULT
  1170. MapHrToUmiError(HRESULT hr)
  1171. {
  1172. HRESULT retHr = hr;
  1173. if (IsPreDefinedErrorCode(hr)) {
  1174. RRETURN(hr);
  1175. }
  1176. switch (hr) {
  1177. case E_ADS_INVALID_DOMAIN_OBJECT:
  1178. case E_ADS_INVALID_USER_OBJECT:
  1179. case E_ADS_INVALID_COMPUTER_OBJECT:
  1180. case E_ADS_UNKNOWN_OBJECT:
  1181. retHr = UMI_E_NOT_FOUND;
  1182. break;
  1183. case E_ADS_PROPERTY_NOT_FOUND:
  1184. retHr = UMI_E_NOT_FOUND;
  1185. break;
  1186. case E_ADS_BAD_PARAMETER:
  1187. retHr = E_INVALIDARG;
  1188. break;
  1189. case E_ADS_CANT_CONVERT_DATATYPE:
  1190. retHr = UMI_E_TYPE_MISMATCH;
  1191. break;
  1192. case E_ADS_BAD_PATHNAME:
  1193. retHr = E_INVALIDARG;
  1194. break;
  1195. case HRESULT_FROM_WIN32(ERROR_DS_NO_ATTRIBUTE_OR_VALUE) :
  1196. // LDAP_NO_SUCH_ATTRIBUTE
  1197. retHr = UMI_E_NOT_FOUND;
  1198. break;
  1199. case HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) :
  1200. // LDAP_NO_SUCH_OBJECT
  1201. retHr = UMI_E_NOT_FOUND;
  1202. break;
  1203. default:
  1204. retHr = E_FAIL;
  1205. break;
  1206. } // end of case
  1207. RRETURN(retHr);
  1208. }