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.

942 lines
19 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: drt.cxx
  7. //
  8. // Contents: Main for OleDs DRT
  9. //
  10. //
  11. // History: 28-Oct-94 KrishnaG, created OleDs DRT
  12. // 28-Oct-94 ChuckC, rewritten.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "precomp.h"
  16. DWORD
  17. LdapOpen(
  18. WCHAR *domainName,
  19. int portno,
  20. HLDAP * phLdapHandle
  21. )
  22. {
  23. int ldaperr = 0;
  24. void *ldapOption;
  25. HLDAP hLdapHandle = NULL;
  26. DWORD dwError = 0;
  27. hLdapHandle = ldap_init(domainName, portno );
  28. if (hLdapHandle == NULL ) {
  29. dwError = ERROR_BAD_NETPATH;
  30. goto error;
  31. }
  32. //
  33. // Now process versioning
  34. //
  35. ldapOption = (void *) LDAP_VERSION3;
  36. ldaperr = ldap_set_option(
  37. hLdapHandle,
  38. LDAP_OPT_VERSION,
  39. &(ldapOption)
  40. );
  41. if (ldaperr) {
  42. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  43. goto error;
  44. }
  45. ldapOption = LDAP_OPT_ON;
  46. ldaperr = ldap_set_option(
  47. hLdapHandle,
  48. LDAP_OPT_ENCRYPT ,
  49. &(ldapOption)
  50. );
  51. if (ldaperr) {
  52. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  53. goto error;
  54. }
  55. ldaperr = ldap_set_option(
  56. hLdapHandle,
  57. LDAP_OPT_SIGN ,
  58. &(ldapOption)
  59. );
  60. if (ldaperr) {
  61. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  62. goto error;
  63. }
  64. ldaperr = ldap_connect(hLdapHandle, NULL);
  65. if (ldaperr) {
  66. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  67. goto error;
  68. }
  69. //
  70. // Disabled Callback function support and chasing external referrals
  71. // KrishnaG - do I need to support this.
  72. *phLdapHandle = hLdapHandle;
  73. return(dwError);
  74. error:
  75. if (hLdapHandle != NULL) {
  76. ldaperr = ldap_unbind( hLdapHandle );
  77. }
  78. return (dwError);
  79. }
  80. DWORD
  81. LdapBind(
  82. HLDAP hLdapHandle
  83. )
  84. {
  85. int ldaperr = 0;
  86. ldaperr = ldap_bind_s(hLdapHandle, NULL, NULL, LDAP_AUTH_SSPI);
  87. return (ldaperr);
  88. }
  89. DWORD
  90. LdapSearchHelper(
  91. HLDAP hLdapHandle,
  92. WCHAR *base,
  93. int scope,
  94. WCHAR *filter,
  95. WCHAR *attrs[],
  96. int attrsonly,
  97. struct l_timeval *timeout,
  98. LDAPMessage **res
  99. )
  100. {
  101. int nCount = 0;
  102. int j = 0;
  103. int ldaperr = 0;
  104. DWORD dwError = 0;
  105. if ( timeout == NULL )
  106. {
  107. ldaperr = ldap_search_s(
  108. hLdapHandle,
  109. base,
  110. scope,
  111. filter,
  112. attrs,
  113. attrsonly,
  114. res
  115. );
  116. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  117. }
  118. else
  119. {
  120. ldaperr = ldap_search_st(
  121. hLdapHandle,
  122. base,
  123. scope,
  124. filter,
  125. attrs,
  126. attrsonly,
  127. timeout,
  128. res
  129. );
  130. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  131. }
  132. //
  133. // Is there an error with checking the no of results
  134. //
  135. return (dwError);
  136. }
  137. DWORD
  138. LdapSearchS(
  139. HLDAP hLdapHandle,
  140. WCHAR *base,
  141. int scope,
  142. WCHAR *filter,
  143. WCHAR *attrs[],
  144. int attrsonly,
  145. LDAPMessage **res
  146. )
  147. {
  148. DWORD dwError = 0;
  149. dwError = LdapSearchHelper(
  150. hLdapHandle,
  151. base,
  152. scope,
  153. filter,
  154. attrs,
  155. attrsonly,
  156. NULL,
  157. res
  158. );
  159. //
  160. // Is there a check needed for connection errors
  161. //
  162. return(dwError);
  163. }
  164. DWORD
  165. LdapSearchST(
  166. HLDAP hLdapHandle,
  167. WCHAR *base,
  168. int scope,
  169. WCHAR *filter,
  170. WCHAR *attrs[],
  171. int attrsonly,
  172. struct l_timeval *timeout,
  173. LDAPMessage **res
  174. )
  175. {
  176. DWORD dwError = 0;
  177. dwError = LdapSearchHelper(
  178. hLdapHandle,
  179. base,
  180. scope,
  181. filter,
  182. attrs,
  183. attrsonly,
  184. timeout,
  185. res
  186. );
  187. return(dwError);
  188. }
  189. //
  190. // Completely new functionality - block ported from YihsinS code in ADSI
  191. //
  192. DWORD
  193. LdapAbandon(
  194. HLDAP hLdapHandle,
  195. int msgid
  196. )
  197. {
  198. // No error code, 0 if success, -1 otherwise
  199. return ldap_abandon( hLdapHandle, msgid );
  200. }
  201. DWORD
  202. LdapResult(
  203. HLDAP hLdapHandle,
  204. int msgid,
  205. int all,
  206. struct l_timeval *timeout,
  207. LDAPMessage **res,
  208. int *restype
  209. )
  210. {
  211. DWORD dwError = 0;
  212. int ldaperr = 0;
  213. *restype = ldap_result( hLdapHandle, msgid, all, timeout, res );
  214. if ( *restype == -1 ) // error
  215. ldaperr = LdapGetLastError();
  216. if (ldaperr) {
  217. if (!ldap_count_entries( hLdapHandle, *res )) {
  218. dwError = CheckAndSetExtendedError( hLdapHandle, ldaperr);
  219. }
  220. }else {
  221. dwError = 0;
  222. }
  223. return(dwError);
  224. }
  225. void
  226. LdapMsgFree(
  227. LDAPMessage *res
  228. )
  229. {
  230. ldap_msgfree( res ); // Returns the type of message freed which
  231. // is not interesting
  232. }
  233. int
  234. LdapResult2Error(
  235. HLDAP hLdapHandle,
  236. LDAPMessage *res,
  237. int freeit
  238. )
  239. {
  240. return ldap_result2error( hLdapHandle, res, freeit );
  241. }
  242. DWORD
  243. LdapFirstEntry(
  244. HLDAP hLdapHandle,
  245. LDAPMessage *res,
  246. LDAPMessage **pfirst
  247. )
  248. {
  249. DWORD dwError = 0;
  250. int ldaperr = 0;
  251. *pfirst = ldap_first_entry( hLdapHandle, res );
  252. if ( *pfirst == NULL )
  253. {
  254. ldaperr = LdapGetLastError();
  255. dwError = CheckAndSetExtendedError( hLdapHandle, ldaperr);
  256. }
  257. return(dwError);
  258. }
  259. DWORD
  260. LdapNextEntry(
  261. HLDAP hLdapHandle,
  262. LDAPMessage *entry,
  263. LDAPMessage **pnext
  264. )
  265. {
  266. DWORD dwError = 0;
  267. int ldaperr = 0;
  268. *pnext = ldap_next_entry( hLdapHandle, entry );
  269. if ( *pnext == NULL )
  270. {
  271. ldaperr = LdapGetLastError();
  272. dwError = CheckAndSetExtendedError( hLdapHandle, ldaperr);
  273. }
  274. return(dwError);
  275. }
  276. int
  277. LdapCountEntries(
  278. HLDAP hLdapHandle,
  279. LDAPMessage *res
  280. )
  281. {
  282. return ldap_count_entries( hLdapHandle, res );
  283. }
  284. DWORD
  285. LdapFirstAttribute(
  286. HLDAP hLdapHandle,
  287. LDAPMessage *entry,
  288. void **ptr,
  289. WCHAR **pattr
  290. )
  291. {
  292. // NOTE: The return value from ldap_first_attribute is static and
  293. // should not be freed
  294. *pattr = ldap_first_attribute( hLdapHandle, entry,
  295. (struct berelement **) ptr ); // static data
  296. if ( *pattr == NULL )
  297. {
  298. DWORD dwError = 0;
  299. int ldaperr = 0;
  300. // Error occurred or end of attributes
  301. ldaperr = LdapGetLastError();
  302. CheckAndSetExtendedError( hLdapHandle, ldaperr);
  303. return(dwError);
  304. }
  305. return NO_ERROR;
  306. }
  307. DWORD
  308. LdapNextAttribute(
  309. HLDAP hLdapHandle,
  310. LDAPMessage *entry,
  311. void *ptr,
  312. WCHAR **pattr
  313. )
  314. {
  315. // NOTE: The return value from ldap_next_attribute is static and
  316. // should not be freed
  317. *pattr = ldap_next_attribute( hLdapHandle, entry,
  318. (struct berelement *) ptr ); // static data
  319. #if 0 // Ignore the error code here since at the end of the enumeration,
  320. // we will probably get an error code here ( both Andy and umich's
  321. // dll will return errors sometimes. No error returned from NTDS,
  322. // but errors are returned from Exchange server )
  323. if ( *pattr == NULL )
  324. {
  325. DWORD hr = NO_ERROR;
  326. int ldaperr = 0;
  327. // Error occurred or end of attributes
  328. ldaperr = LdapGetLastError();
  329. dwError = CheckAndSetExtendedError( hLdapHandle, ldaperr);
  330. return(dwError);
  331. }
  332. #endif
  333. return S_OK;
  334. }
  335. //
  336. // NOTE: LdapGetValues return S_OK if attribute [attr] has no values
  337. // (*[pvalues] =NULL, *[pcount]=0) but all else ok.
  338. //
  339. DWORD
  340. LdapGetValues(
  341. HLDAP hLdapHandle,
  342. LDAPMessage *entry,
  343. WCHAR *attr,
  344. WCHAR ***pvalues,
  345. int *pcount
  346. )
  347. {
  348. DWORD dwError = 0;
  349. int ldaperr = 0;
  350. *pvalues = ldap_get_values( hLdapHandle, entry, attr );
  351. if ( *pvalues == NULL ) {
  352. *pcount=0;
  353. //
  354. // ldap_get_values succeeds if attribute has no values
  355. // but all else ok. (confiremed with anoopa)
  356. //
  357. ldaperr = LdapGetLastError();
  358. if (ldaperr) {
  359. dwError = CheckAndSetExtendedError( hLdapHandle, ldaperr);
  360. }
  361. //
  362. // KrishnaG if *pvalues is NULL which means I don't get back a
  363. // value - return an ERROR
  364. //
  365. return(ERROR_DS_NO_ATTRIBUTE_OR_VALUE);
  366. }
  367. *pcount = ldap_count_values( *pvalues );
  368. return S_OK;
  369. }
  370. //
  371. // NOTE: LdapGetValuesLen return S_OK if attribute [attr] has no values
  372. // (*[pvalues] =NULL, *[pcount]=0) but all else ok.
  373. //
  374. DWORD
  375. LdapGetValuesLen(
  376. HLDAP hLdapHandle,
  377. LDAPMessage *entry,
  378. WCHAR *attr,
  379. struct berval ***pvalues,
  380. int *pcount
  381. )
  382. {
  383. //
  384. // NOTE: this can contain binary data as well as strings,
  385. // strings are ascii, no conversion is done here
  386. //
  387. char *pszAttrA = NULL;
  388. DWORD dwError = 0;
  389. int ldaperr = 0;
  390. *pvalues = ldap_get_values_len( hLdapHandle, entry, attr );
  391. if ( *pvalues == NULL ){
  392. *pcount=0;
  393. //
  394. // ldap_get_values succeeds if attribute has no values
  395. // but all else ok. (confiremed with anoopa)
  396. //
  397. ldaperr = LdapGetLastError();
  398. if (ldaperr) {
  399. dwError = CheckAndSetExtendedError( hLdapHandle,ldaperr);
  400. }
  401. return(ERROR_DS_NO_ATTRIBUTE_OR_VALUE);
  402. }
  403. *pcount = ldap_count_values_len( *pvalues );
  404. return S_OK;
  405. }
  406. void
  407. LdapValueFree(
  408. WCHAR **vals
  409. )
  410. {
  411. ldap_value_free( vals );
  412. }
  413. void
  414. LdapValueFreeLen(
  415. struct berval **vals
  416. )
  417. {
  418. ldap_value_free_len( vals );
  419. }
  420. void
  421. LdapMemFree(
  422. WCHAR *pszString
  423. )
  424. {
  425. ldap_memfree( pszString );
  426. }
  427. void
  428. LdapAttributeFree(
  429. WCHAR *pszString
  430. )
  431. {
  432. // String from ldap_first/next_attribute should not be freed,
  433. // so do nothing here
  434. }
  435. DWORD
  436. LdapGetDn(
  437. HLDAP hLdapHandle,
  438. LDAPMessage *entry,
  439. WCHAR **pdn
  440. )
  441. {
  442. int ldaperr = 0;
  443. DWORD dwError = 0;
  444. *pdn = ldap_get_dn( hLdapHandle, entry );
  445. if ( *pdn == NULL )
  446. {
  447. // Error occurred
  448. ldaperr = LdapGetLastError();
  449. dwError = CheckAndSetExtendedError( hLdapHandle, ldaperr);
  450. return(dwError);
  451. }
  452. return(dwError);
  453. }
  454. DWORD
  455. CheckAndSetExtendedError(
  456. HLDAP hLdapHandle,
  457. int ldaperr
  458. )
  459. {
  460. DWORD dwErr = NO_ERROR;
  461. switch (ldaperr) {
  462. case LDAP_SUCCESS :
  463. dwErr = NO_ERROR;
  464. break;
  465. case LDAP_OPERATIONS_ERROR :
  466. dwErr = ERROR_DS_OPERATIONS_ERROR;
  467. break;
  468. case LDAP_PROTOCOL_ERROR :
  469. dwErr = ERROR_DS_PROTOCOL_ERROR;
  470. break;
  471. case LDAP_TIMELIMIT_EXCEEDED :
  472. dwErr = ERROR_DS_TIMELIMIT_EXCEEDED;
  473. break;
  474. case LDAP_SIZELIMIT_EXCEEDED :
  475. dwErr = ERROR_DS_SIZELIMIT_EXCEEDED;
  476. break;
  477. case LDAP_COMPARE_FALSE :
  478. dwErr = ERROR_DS_COMPARE_FALSE;
  479. break;
  480. case LDAP_COMPARE_TRUE :
  481. dwErr = ERROR_DS_COMPARE_TRUE;
  482. break;
  483. case LDAP_AUTH_METHOD_NOT_SUPPORTED :
  484. dwErr = ERROR_DS_AUTH_METHOD_NOT_SUPPORTED;
  485. break;
  486. case LDAP_STRONG_AUTH_REQUIRED :
  487. dwErr = ERROR_DS_STRONG_AUTH_REQUIRED;
  488. break;
  489. case LDAP_PARTIAL_RESULTS :
  490. //
  491. // Make sure we handle
  492. // partial results.
  493. //
  494. dwErr = ERROR_MORE_DATA;
  495. break;
  496. case LDAP_REFERRAL :
  497. dwErr = ERROR_DS_REFERRAL;
  498. break;
  499. case LDAP_ADMIN_LIMIT_EXCEEDED :
  500. dwErr = ERROR_DS_ADMIN_LIMIT_EXCEEDED;
  501. break;
  502. case LDAP_UNAVAILABLE_CRIT_EXTENSION :
  503. dwErr = ERROR_DS_UNAVAILABLE_CRIT_EXTENSION;
  504. break;
  505. case LDAP_CONFIDENTIALITY_REQUIRED :
  506. dwErr = ERROR_DS_CONFIDENTIALITY_REQUIRED;
  507. break;
  508. case LDAP_NO_SUCH_ATTRIBUTE :
  509. dwErr = ERROR_DS_NO_ATTRIBUTE_OR_VALUE;
  510. break;
  511. case LDAP_UNDEFINED_TYPE :
  512. dwErr = ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED;
  513. break;
  514. case LDAP_INAPPROPRIATE_MATCHING :
  515. dwErr = ERROR_DS_INAPPROPRIATE_MATCHING;
  516. break;
  517. case LDAP_CONSTRAINT_VIOLATION :
  518. dwErr = ERROR_DS_CONSTRAINT_VIOLATION;
  519. break;
  520. case LDAP_ATTRIBUTE_OR_VALUE_EXISTS :
  521. dwErr = ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS;
  522. break;
  523. case LDAP_INVALID_SYNTAX :
  524. dwErr = ERROR_DS_INVALID_ATTRIBUTE_SYNTAX;
  525. break;
  526. case LDAP_NO_SUCH_OBJECT :
  527. dwErr = ERROR_DS_NO_SUCH_OBJECT;
  528. break;
  529. case LDAP_ALIAS_PROBLEM :
  530. dwErr = ERROR_DS_ALIAS_PROBLEM;
  531. break;
  532. case LDAP_INVALID_DN_SYNTAX :
  533. dwErr = ERROR_DS_INVALID_DN_SYNTAX;
  534. break;
  535. case LDAP_IS_LEAF :
  536. dwErr = ERROR_DS_IS_LEAF;
  537. break;
  538. case LDAP_ALIAS_DEREF_PROBLEM :
  539. dwErr = ERROR_DS_ALIAS_DEREF_PROBLEM;
  540. break;
  541. case LDAP_INAPPROPRIATE_AUTH :
  542. dwErr = ERROR_DS_INAPPROPRIATE_AUTH;
  543. break;
  544. case LDAP_INVALID_CREDENTIALS :
  545. dwErr = ERROR_LOGON_FAILURE;
  546. break;
  547. case LDAP_INSUFFICIENT_RIGHTS :
  548. dwErr = ERROR_ACCESS_DENIED;
  549. break;
  550. case LDAP_BUSY :
  551. dwErr = ERROR_DS_BUSY;
  552. break;
  553. case LDAP_UNAVAILABLE :
  554. dwErr = ERROR_DS_UNAVAILABLE;
  555. break;
  556. case LDAP_UNWILLING_TO_PERFORM :
  557. dwErr = ERROR_DS_UNWILLING_TO_PERFORM;
  558. break;
  559. case LDAP_LOOP_DETECT :
  560. dwErr = ERROR_DS_LOOP_DETECT;
  561. break;
  562. case LDAP_NAMING_VIOLATION :
  563. dwErr = ERROR_DS_NAMING_VIOLATION;
  564. break;
  565. case LDAP_OBJECT_CLASS_VIOLATION :
  566. dwErr = ERROR_DS_OBJ_CLASS_VIOLATION;
  567. break;
  568. case LDAP_NOT_ALLOWED_ON_NONLEAF :
  569. dwErr = ERROR_DS_CANT_ON_NON_LEAF;
  570. break;
  571. case LDAP_NOT_ALLOWED_ON_RDN :
  572. dwErr = ERROR_DS_CANT_ON_RDN;
  573. break;
  574. case LDAP_ALREADY_EXISTS :
  575. dwErr = ERROR_OBJECT_ALREADY_EXISTS;
  576. break;
  577. case LDAP_NO_OBJECT_CLASS_MODS :
  578. dwErr = ERROR_DS_CANT_MOD_OBJ_CLASS;
  579. break;
  580. case LDAP_RESULTS_TOO_LARGE :
  581. dwErr = ERROR_DS_OBJECT_RESULTS_TOO_LARGE;
  582. break;
  583. case LDAP_AFFECTS_MULTIPLE_DSAS :
  584. dwErr = ERROR_DS_AFFECTS_MULTIPLE_DSAS;
  585. break;
  586. case LDAP_OTHER :
  587. dwErr = ERROR_GEN_FAILURE;
  588. break;
  589. case LDAP_SERVER_DOWN :
  590. dwErr = ERROR_DS_SERVER_DOWN;
  591. break;
  592. case LDAP_LOCAL_ERROR :
  593. dwErr = ERROR_DS_LOCAL_ERROR;
  594. break;
  595. case LDAP_ENCODING_ERROR :
  596. dwErr = ERROR_DS_ENCODING_ERROR;
  597. break;
  598. case LDAP_DECODING_ERROR :
  599. dwErr = ERROR_DS_DECODING_ERROR;
  600. break;
  601. case LDAP_TIMEOUT :
  602. dwErr = ERROR_TIMEOUT;
  603. break;
  604. case LDAP_AUTH_UNKNOWN :
  605. dwErr = ERROR_DS_AUTH_UNKNOWN;
  606. break;
  607. case LDAP_FILTER_ERROR :
  608. dwErr = ERROR_DS_FILTER_UNKNOWN;
  609. break;
  610. case LDAP_USER_CANCELLED :
  611. dwErr = ERROR_CANCELLED;
  612. break;
  613. case LDAP_PARAM_ERROR :
  614. dwErr = ERROR_DS_PARAM_ERROR;
  615. break;
  616. case LDAP_NO_MEMORY :
  617. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  618. break;
  619. case LDAP_CONNECT_ERROR :
  620. dwErr = ERROR_CONNECTION_REFUSED;
  621. break;
  622. case LDAP_NOT_SUPPORTED :
  623. dwErr = ERROR_DS_NOT_SUPPORTED;
  624. break;
  625. case LDAP_NO_RESULTS_RETURNED :
  626. dwErr = ERROR_DS_NO_RESULTS_RETURNED;
  627. break;
  628. case LDAP_CONTROL_NOT_FOUND :
  629. dwErr = ERROR_DS_CONTROL_NOT_FOUND;
  630. break;
  631. case LDAP_MORE_RESULTS_TO_RETURN :
  632. dwErr = ERROR_MORE_DATA;
  633. break;
  634. case LDAP_CLIENT_LOOP :
  635. dwErr = ERROR_DS_CLIENT_LOOP;
  636. break;
  637. case LDAP_REFERRAL_LIMIT_EXCEEDED :
  638. dwErr = ERROR_DS_REFERRAL_LIMIT_EXCEEDED;
  639. break;
  640. default:
  641. dwErr = ERROR_DS_BUSY;
  642. }
  643. return(dwErr);
  644. }
  645. DWORD
  646. LdapAddS(
  647. HLDAP hLdapHandle,
  648. WCHAR *dn,
  649. LDAPModW *attrs[]
  650. )
  651. {
  652. DWORD dwError = 0;
  653. int ldaperr = 0;
  654. ldaperr = ldap_add_s( hLdapHandle, dn, attrs );
  655. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  656. return(dwError);
  657. }
  658. DWORD
  659. LdapModifyS(
  660. HLDAP hLdapHandle,
  661. WCHAR *dn,
  662. LDAPModW *mods[]
  663. )
  664. {
  665. DWORD dwError = 0;
  666. int ldaperr = 0;
  667. ldaperr = ldap_modify_s( hLdapHandle, dn, mods);
  668. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  669. return(dwError);
  670. }
  671. DWORD
  672. LdapDeleteS(
  673. HLDAP hLdapHandle,
  674. WCHAR *dn
  675. )
  676. {
  677. DWORD dwError = 0;
  678. int ldaperr = 0;
  679. ldaperr = ldap_delete_s( hLdapHandle, dn );
  680. dwError = CheckAndSetExtendedError(hLdapHandle, ldaperr);
  681. return(dwError);
  682. }
  683. DWORD
  684. LdapRename(
  685. HLDAP hLdapHandle,
  686. WCHAR *oldDn,
  687. WCHAR *newDn
  688. )
  689. {
  690. DWORD dwError = 0;
  691. dwError = ldap_modrdn_s (hLdapHandle, oldDn, newDn);
  692. // dwError = ldap_rename_ext_s(hLdapHandle, dn, newName, parentNode, TRUE, NULL, NULL);
  693. return(dwError);
  694. }