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

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