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.

2146 lines
66 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1996.
  5. //
  6. // File: DSOBJECT.CXX
  7. //
  8. // Contents: DSObject support functions
  9. //
  10. // History: 01-Jul-96 MacM Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <aclpch.hxx>
  14. #pragma hdrstop
  15. #define NO_PROPAGATE
  16. #define ACTRL_SD_PROP_NAME L"nTSecurityDescriptor"
  17. #define ACTRL_EXT_RIGHTS_CONTAINER L"CN=Extended-Rights,"
  18. #include <dsgetdc.h>
  19. #include <lmapibuf.h>
  20. #include <mapicode.h>
  21. extern "C"
  22. {
  23. #include <permit.h>
  24. #include <seopaque.h>
  25. #include <sertlp.h>
  26. #include <ntdsguid.h>
  27. #include <ntldap.h>
  28. }
  29. #define PSD_FROM_DS_PSD(psd) (PSECURITY_DESCRIPTOR)((PBYTE)psd + sizeof(ULONG))
  30. #define BYTE_0_MASK 0xFF
  31. #define BYTE_3(Value) (UCHAR)( (Value) & BYTE_0_MASK)
  32. #define BYTE_2(Value) (UCHAR)( ((Value) >> 8) & BYTE_0_MASK)
  33. #define BYTE_1(Value) (UCHAR)( ((Value) >> 16) & BYTE_0_MASK)
  34. #define BYTE_0(Value) (UCHAR)( ((Value) >> 24) & BYTE_0_MASK)
  35. #define MartaPutUlong(Buffer, Value) { \
  36. ((PBYTE)Buffer)[0] = BYTE_0(Value), \
  37. ((PBYTE)Buffer)[1] = BYTE_1(Value), \
  38. ((PBYTE)Buffer)[2] = BYTE_2(Value), \
  39. ((PBYTE)Buffer)[3] = BYTE_3(Value); \
  40. }
  41. DWORD
  42. ConvertStringAToStringW (
  43. IN PSTR pszString,
  44. OUT PWSTR *ppwszString
  45. )
  46. /*++
  47. Routine Description:
  48. This routine will convert an ASCII string to a UNICODE string.
  49. The returned string buffer must be freed via a call to LocalFree
  50. Arguments:
  51. pszString - The string to convert
  52. ppwszString - Where the converted string is returned
  53. Return Value:
  54. ERROR_SUCCESS - Success
  55. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  56. --*/
  57. {
  58. if(pszString == NULL)
  59. {
  60. *ppwszString = NULL;
  61. }
  62. else
  63. {
  64. ULONG cLen = strlen(pszString);
  65. *ppwszString = (PWSTR)AccAlloc(sizeof(WCHAR) *
  66. (mbstowcs(NULL, pszString, cLen + 1) + 1));
  67. if(*ppwszString != NULL)
  68. {
  69. mbstowcs(*ppwszString,
  70. pszString,
  71. cLen + 1);
  72. }
  73. else
  74. {
  75. return(ERROR_NOT_ENOUGH_MEMORY);
  76. }
  77. }
  78. return(ERROR_SUCCESS);
  79. }
  80. DWORD
  81. ConvertStringWToStringA (
  82. IN PWSTR pwszString,
  83. OUT PSTR *ppszString
  84. )
  85. /*++
  86. Routine Description:
  87. This routine will convert a UNICODE string to an ANSI string.
  88. The returned string buffer must be freed via a call to LocalFree
  89. Arguments:
  90. pwszString - The string to convert
  91. ppszString - Where the converted string is returned
  92. Return Value:
  93. ERROR_SUCCESS - Success
  94. ERROR_NOT_ENOUGH_MEMORY - A memory allocation failed
  95. --*/
  96. {
  97. if(pwszString == NULL)
  98. {
  99. *ppszString = NULL;
  100. }
  101. else
  102. {
  103. ULONG cLen = wcslen(pwszString);
  104. *ppszString = (PSTR)AccAlloc(sizeof(CHAR) *
  105. (wcstombs(NULL, pwszString, cLen + 1) + 1));
  106. if(*ppszString != NULL)
  107. {
  108. wcstombs(*ppszString,
  109. pwszString,
  110. cLen + 1);
  111. }
  112. else
  113. {
  114. return(ERROR_NOT_ENOUGH_MEMORY);
  115. }
  116. }
  117. return(ERROR_SUCCESS);
  118. }
  119. //+---------------------------------------------------------------------------
  120. //
  121. // Function: DspSplitPath
  122. //
  123. // Synopsis: This function splits a path into the server portion and the
  124. // path portion. If the server portion doesn't exist, a NULL is
  125. // returned
  126. //
  127. // Arguments: [IN pwszObjectPath]-- The name of the object to be split
  128. // [OUT ppwszAllocatedServer] -- Where the server name is returned.
  129. // Must be freed via AccFree
  130. // [OUT ppwszReferencePath] -- Ptr within the input path that
  131. // contains the path portion.
  132. //
  133. // Returns: ERROR_SUCCESS -- The object is reachable
  134. // ERROR_PATH_NOT_FOUND-- The object was not reachable
  135. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  136. //
  137. // Notes:
  138. //
  139. //----------------------------------------------------------------------------
  140. DWORD DspSplitPath(IN PWSTR pwszObjectPath,
  141. OUT PWSTR *ppwszAllocatedServer,
  142. OUT PWSTR *ppwszReferencePath)
  143. {
  144. DWORD dwErr = ERROR_SUCCESS;
  145. PWSTR Temp = NULL;
  146. ULONG Len = 0;
  147. if(IS_UNC_PATH(pwszObjectPath, wcslen(pwszObjectPath)))
  148. {
  149. Temp = wcschr(pwszObjectPath + 2, L'\\');
  150. if (Temp == NULL) {
  151. Len = wcslen(pwszObjectPath);
  152. }
  153. else
  154. {
  155. Len = (ULONG)(Temp - pwszObjectPath);
  156. }
  157. *ppwszAllocatedServer = ( PWSTR )AccAlloc( ( Len + 1 ) * sizeof( WCHAR ) );
  158. if(*ppwszAllocatedServer == NULL)
  159. {
  160. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  161. }
  162. else
  163. {
  164. wcsncpy( *ppwszAllocatedServer, pwszObjectPath, Len );
  165. *( *ppwszAllocatedServer + Len ) = UNICODE_NULL;
  166. }
  167. if(Temp != NULL)
  168. {
  169. *ppwszReferencePath = Temp + 1;
  170. }
  171. else
  172. {
  173. *ppwszReferencePath = NULL;
  174. }
  175. }
  176. else
  177. {
  178. *ppwszReferencePath = pwszObjectPath;
  179. *ppwszAllocatedServer = NULL;
  180. }
  181. return(dwErr);
  182. }
  183. //+---------------------------------------------------------------------------
  184. //
  185. // Function: PingDSObjByNameRes
  186. //
  187. // Synopsis: "Pings" the specified DS object, to determine if it is
  188. // reachable or not
  189. //
  190. // REMOVE POST BETA - 1. Raid 107329
  191. //
  192. // Arguments: [IN pObjectName] -- The name of the object
  193. //
  194. // Returns: ERROR_SUCCESS -- The object is reachable
  195. // ERROR_PATH_NOT_FOUND-- The object was not reachable
  196. //
  197. // Notes:
  198. //
  199. //----------------------------------------------------------------------------
  200. DWORD
  201. PingDSObjByNameRes(IN PWSTR pwszDSObj,
  202. IN PDS_NAME_RESULTW pNameRes)
  203. {
  204. acDebugOut((DEB_TRACE, "in PingDSObjByNameRes\n"));
  205. DWORD dwErr;
  206. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0)
  207. {
  208. dwErr = ERROR_PATH_NOT_FOUND;
  209. }
  210. else
  211. {
  212. //
  213. // Now, we'll bind to the object, and then do the read
  214. //
  215. PLDAP pLDAP;
  216. dwErr = BindToDSObject(NULL,
  217. pNameRes->rItems[0].pDomain,
  218. &pLDAP);
  219. if(dwErr == ERROR_SUCCESS)
  220. {
  221. PLDAPMessage pMessage = NULL;
  222. PWSTR rgAttribs[2];
  223. rgAttribs[0] = L"distinguishedName";
  224. rgAttribs[1] = NULL;
  225. if(dwErr == ERROR_SUCCESS)
  226. {
  227. dwErr = ldap_search_s(pLDAP,
  228. (PWSTR)pwszDSObj,
  229. LDAP_SCOPE_BASE,
  230. L"(objectClass=*)",
  231. rgAttribs,
  232. 0,
  233. &pMessage);
  234. dwErr = LdapMapErrorToWin32( dwErr );
  235. }
  236. if(dwErr == ERROR_SUCCESS)
  237. {
  238. LDAPMessage *pEntry = NULL;
  239. pEntry = ldap_first_entry(pLDAP,
  240. pMessage);
  241. if(pEntry == NULL)
  242. {
  243. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  244. }
  245. else
  246. {
  247. //
  248. // Now, we'll have to get the values
  249. //
  250. PWSTR *ppwszValues = ldap_get_values(pLDAP,
  251. pEntry,
  252. rgAttribs[0]);
  253. if(ppwszValues == NULL)
  254. {
  255. if(pLDAP->ld_errno == LDAP_NO_SUCH_ATTRIBUTE )
  256. {
  257. dwErr = ERROR_SUCCESS;
  258. }
  259. else
  260. {
  261. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  262. }
  263. }
  264. else
  265. {
  266. ldap_value_free(ppwszValues);
  267. }
  268. }
  269. ldap_msgfree(pMessage);
  270. }
  271. }
  272. }
  273. acDebugOut((DEB_TRACE, "out PingDSObjByNameRes: %lu\n", dwErr));
  274. return(dwErr);
  275. }
  276. //+---------------------------------------------------------------------------
  277. //
  278. // Function: DspBindAndCrack
  279. //
  280. // Synopsis: Does a DsCrackName on the object
  281. //
  282. // Arguments: [IN pwszServer] -- Optional server name to bind to
  283. // [IN pwszDSObj] -- The DS object to bind to
  284. // [OUT pResults] -- The returned cracked name
  285. //
  286. // Returns: ERROR_SUCCESS -- The object is reachable
  287. //
  288. // Notes:
  289. //
  290. //----------------------------------------------------------------------------
  291. DWORD DspBindAndCrack( IN PWSTR pwszServer, OPTIONAL
  292. IN PWSTR pwszDSObj,
  293. IN DWORD OptionalDsGetDcFlags,
  294. OUT PDS_NAME_RESULTW *pResults )
  295. {
  296. return DspBindAndCrackEx( pwszServer,
  297. pwszDSObj,
  298. OptionalDsGetDcFlags,
  299. DS_FQDN_1779_NAME,
  300. pResults );
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Function: DspBindAndCrackEx
  305. //
  306. // Synopsis: Does a DsCrackName on the object
  307. //
  308. // Arguments: [IN pwszServer] -- Optional server name to bind to
  309. // [IN pwszDSObj] -- The DS object to bind to
  310. // [IN formatDesired] -- indicates the format of the returned name
  311. // [OUT pResults] -- The returned cracked name
  312. //
  313. // Returns: ERROR_SUCCESS -- The object is reachable
  314. //
  315. // Notes:
  316. //
  317. //----------------------------------------------------------------------------
  318. DWORD DspBindAndCrackEx( IN PWSTR pwszServer,
  319. IN PWSTR pwszDSObj,
  320. IN DWORD OptionalDsGetDcFlags,
  321. IN DS_NAME_FORMAT formatDesired,
  322. OUT PDS_NAME_RESULTW *pResults )
  323. {
  324. DWORD dwErr = ERROR_SUCCESS;
  325. HANDLE hDS = NULL;
  326. PDS_NAME_RESULTW pNameRes;
  327. PDOMAIN_CONTROLLER_INFOW pDCI = NULL;
  328. BOOL NamedServer = FALSE;
  329. //
  330. // The path we are given could be of the form \\\\servername\\path. If it is, it
  331. // is not necessary to do the DsGetDcName call. We'll just use the server name
  332. // we are given
  333. //
  334. if(pwszServer != NULL)
  335. {
  336. NamedServer = TRUE;
  337. }
  338. else
  339. {
  340. dwErr = DsGetDcNameW(NULL,
  341. NULL,
  342. NULL,
  343. NULL,
  344. DS_DIRECTORY_SERVICE_REQUIRED | OptionalDsGetDcFlags, // DS_IP_REQUIRED
  345. &pDCI);
  346. if(dwErr == ERROR_SUCCESS)
  347. {
  348. pwszServer = pDCI[0].DomainControllerName; // pDCI[0].DomainControllerAddress;
  349. }
  350. }
  351. //
  352. // Do the bind and crack
  353. //
  354. if(dwErr == ERROR_SUCCESS)
  355. {
  356. dwErr = DsBindW(pwszServer,
  357. NULL,
  358. &hDS);
  359. if(dwErr == ERROR_SUCCESS)
  360. {
  361. dwErr = DsCrackNamesW(hDS,
  362. DS_NAME_NO_FLAGS,
  363. DS_UNKNOWN_NAME,
  364. formatDesired,
  365. 1,
  366. &pwszDSObj,
  367. &pNameRes);
  368. if (dwErr == ERROR_SUCCESS)
  369. {
  370. if(pNameRes->cItems != 0 &&
  371. pNameRes->rItems[0].status == DS_NAME_ERROR_DOMAIN_ONLY &&
  372. NamedServer == FALSE )
  373. {
  374. NetApiBufferFree(pDCI);
  375. pDCI = NULL;
  376. dwErr = DsGetDcNameW(NULL,
  377. pNameRes->rItems[0].pDomain,
  378. NULL,
  379. NULL,
  380. DS_DIRECTORY_SERVICE_REQUIRED | OptionalDsGetDcFlags, // DS_IP_REQUIRED |
  381. &pDCI);
  382. if(dwErr == ERROR_SUCCESS)
  383. {
  384. DsUnBindW(&hDS);
  385. hDS = NULL;
  386. dwErr = DsBindW(pDCI[0].DomainControllerName, // DomainControllerAddress,
  387. NULL,
  388. &hDS);
  389. if(dwErr == ERROR_SUCCESS)
  390. {
  391. dwErr = DsCrackNamesW(hDS,
  392. DS_NAME_NO_FLAGS,
  393. DS_UNKNOWN_NAME,
  394. formatDesired,
  395. 1,
  396. &pwszDSObj,
  397. &pNameRes);
  398. }
  399. }
  400. }
  401. //
  402. // If this is a case where we don't have a named server, handle
  403. // the case where an object was created on one Dc, but we've just
  404. // bound to a second one
  405. //
  406. //
  407. if (dwErr == ERROR_SUCCESS && formatDesired == DS_FQDN_1779_NAME &&
  408. NamedServer == FALSE )
  409. {
  410. dwErr = PingDSObjByNameRes( pwszDSObj,pNameRes );
  411. if(dwErr != ERROR_SUCCESS)
  412. {
  413. DsFreeNameResultW(pNameRes);
  414. }
  415. if(dwErr == ERROR_PATH_NOT_FOUND && OptionalDsGetDcFlags == 0)
  416. {
  417. dwErr = DspBindAndCrackEx( pDCI[0].DomainControllerName, //DomainControllerAddress,
  418. pwszDSObj,
  419. DS_WRITABLE_REQUIRED,
  420. formatDesired,
  421. &pNameRes );
  422. }
  423. }
  424. *pResults = pNameRes;
  425. }
  426. if(hDS != NULL)
  427. {
  428. DsUnBindW(&hDS);
  429. }
  430. }
  431. }
  432. if(pDCI != NULL)
  433. {
  434. NetApiBufferFree(pDCI);
  435. }
  436. return( dwErr );
  437. }
  438. //+---------------------------------------------------------------------------
  439. //
  440. // Function: BindToDSObject
  441. //
  442. // Synopsis: Binds to a DS object
  443. //
  444. // Arguments: [IN pwszServer] -- OPTIONAL. If specified, this is the name
  445. // of the server to bind to
  446. // [IN pwszDSObj] -- The DS object to bind to
  447. // [OUT ppLDAP] -- The returned LDAP handle
  448. //
  449. // Returns: ERROR_SUCCESS -- The object is reachable
  450. // ERROR_PATH_NOT_FOUND-- The object was not reachable
  451. //
  452. // Notes: The returned LDAP handle must be closed via UnbindFromDSObject
  453. //
  454. //----------------------------------------------------------------------------
  455. DWORD BindToDSObject(IN PWSTR pwszServer, OPTIONAL
  456. IN LPWSTR pwszDSObj,
  457. OUT PLDAP *ppLDAP)
  458. {
  459. acDebugOut((DEB_TRACE, "in BindToDSObject\n"));
  460. PDOMAIN_CONTROLLER_INFOW pDCI = NULL;
  461. DWORD dwErr = ERROR_SUCCESS;
  462. //
  463. // The path we are given could be of the form \\\\servername\\path. If it is, it
  464. // is not necessary to do the DsGetDcName call. We'll just use the server name
  465. // we are given
  466. //
  467. // Change: in order to use mutual authentication, A DNS format domain name must
  468. // be passed into ldap_open/ldap_init. So even a servername is passed in, it's
  469. // necessary to call DsGetDcNameW to get the DNS format domain name.
  470. // Since we asked for DIRECTORY_SERVICE_REQUIRED, this call won't talk to any
  471. // NT4 domain and the DNS name should always be returned. If it fails to get the
  472. // DNS name, we will fail this function - by design.
  473. //
  474. dwErr = DsGetDcNameW(pwszServer,
  475. NULL,
  476. NULL,
  477. NULL,
  478. DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME,
  479. &pDCI);
  480. if(dwErr == ERROR_SUCCESS)
  481. {
  482. *ppLDAP = ldap_open(pDCI->DomainName, LDAP_PORT);
  483. if(*ppLDAP == NULL)
  484. {
  485. dwErr = ERROR_PATH_NOT_FOUND;
  486. }
  487. else
  488. {
  489. //
  490. // Do a bind...
  491. //
  492. dwErr = ldap_bind_s(*ppLDAP,
  493. NULL,
  494. NULL,
  495. LDAP_AUTH_SSPI);
  496. }
  497. }
  498. if(pDCI != NULL)
  499. {
  500. NetApiBufferFree(pDCI);
  501. }
  502. acDebugOut((DEB_TRACE, "out BindToDSObject: %lu\n", dwErr));
  503. return(dwErr);
  504. }
  505. //+---------------------------------------------------------------------------
  506. //
  507. // Function: UnBindFromDSObject
  508. //
  509. // Synopsis: Closes a binding to a DS object
  510. //
  511. // Arguments: [IN ppLDAP] -- The LDAP connection to close
  512. //
  513. // Returns: ERROR_SUCCESS -- The object is reachable
  514. //
  515. // Notes:
  516. //
  517. //----------------------------------------------------------------------------
  518. DWORD UnBindFromDSObject(OUT PLDAP *ppLDAP)
  519. {
  520. acDebugOut((DEB_TRACE, "in UnBindFromDSObject\n"));
  521. DWORD dwErr = ERROR_SUCCESS;
  522. if(*ppLDAP != NULL)
  523. {
  524. ldap_unbind(*ppLDAP);
  525. *ppLDAP = NULL;
  526. }
  527. acDebugOut((DEB_TRACE, "out UnBindFromDSObject: %lu\n", dwErr));
  528. return(dwErr);
  529. }
  530. //+---------------------------------------------------------------------------
  531. //
  532. // Function: ReadDSObjSecDesc
  533. //
  534. // Synopsis: Reads the security descriptor from the specied object via
  535. // the open ldap connection
  536. //
  537. // Arguments: [IN pLDAP] -- The open LDAP connection
  538. // [IN SeInfo] -- Parts of the security descriptor to
  539. // read.
  540. // [IN pwszDSObj] -- The DSObject to get the security
  541. // descriptor for
  542. // [OUT ppSD] -- Where the security descriptor is
  543. // returned
  544. //
  545. // Returns: ERROR_SUCCESS -- The object is reachable
  546. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  547. //
  548. // Notes: The returned security descriptor must be freed with LocalFree
  549. //
  550. //----------------------------------------------------------------------------
  551. DWORD
  552. ReadDSObjSecDesc(IN PLDAP pLDAP,
  553. IN PWSTR pwszObject,
  554. IN SECURITY_INFORMATION SeInfo,
  555. OUT PSECURITY_DESCRIPTOR *ppSD)
  556. {
  557. DWORD dwErr = ERROR_SUCCESS;
  558. PLDAPMessage pMessage = NULL;
  559. PWSTR rgAttribs[2];
  560. BYTE berValue[8];
  561. //
  562. // JohnsonA The BER encoding is current hardcoded. Change this to use
  563. // AndyHe's BER_printf package once it's done.
  564. //
  565. berValue[0] = 0x30;
  566. berValue[1] = 0x03;
  567. berValue[2] = 0x02;
  568. berValue[3] = 0x01;
  569. berValue[4] = (BYTE)((ULONG)SeInfo & 0xF);
  570. LDAPControl SeInfoControl =
  571. {
  572. LDAP_SERVER_SD_FLAGS_OID_W,
  573. {
  574. 5, (PCHAR)berValue
  575. },
  576. TRUE
  577. };
  578. PLDAPControl ServerControls[2] =
  579. {
  580. &SeInfoControl,
  581. NULL
  582. };
  583. rgAttribs[0] = ACTRL_SD_PROP_NAME;
  584. rgAttribs[1] = NULL;
  585. if(dwErr == ERROR_SUCCESS)
  586. {
  587. dwErr = ldap_search_ext_s(pLDAP,
  588. pwszObject,
  589. LDAP_SCOPE_BASE,
  590. L"(objectClass=*)",
  591. rgAttribs,
  592. 0,
  593. (PLDAPControl *)&ServerControls,
  594. NULL,
  595. NULL,
  596. 10000,
  597. &pMessage);
  598. dwErr = LdapMapErrorToWin32( dwErr );
  599. }
  600. if(dwErr == ERROR_SUCCESS)
  601. {
  602. LDAPMessage *pEntry = NULL;
  603. pEntry = ldap_first_entry(pLDAP,
  604. pMessage);
  605. if(pEntry == NULL)
  606. {
  607. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  608. }
  609. else
  610. {
  611. //
  612. // Now, we'll have to get the values
  613. //
  614. PWSTR *ppwszValues = ldap_get_values(pLDAP,
  615. pEntry,
  616. rgAttribs[0]);
  617. if(ppwszValues == NULL)
  618. {
  619. if(pLDAP->ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
  620. {
  621. dwErr = ERROR_ACCESS_DENIED;
  622. }
  623. else
  624. {
  625. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  626. }
  627. }
  628. else
  629. {
  630. PLDAP_BERVAL *pSize = ldap_get_values_len(pLDAP,
  631. pMessage,
  632. rgAttribs[0]);
  633. if(pSize == NULL)
  634. {
  635. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  636. }
  637. else
  638. {
  639. //
  640. // Allocate the security descriptor to return
  641. //
  642. *ppSD = (PSECURITY_DESCRIPTOR)AccAlloc((*pSize)->bv_len);
  643. if(*ppSD == NULL)
  644. {
  645. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  646. }
  647. else
  648. {
  649. memcpy(*ppSD,
  650. (PBYTE)(*pSize)->bv_val,
  651. (*pSize)->bv_len);
  652. }
  653. ldap_value_free_len(pSize);
  654. }
  655. ldap_value_free(ppwszValues);
  656. }
  657. }
  658. ldap_msgfree(pMessage);
  659. }
  660. return(dwErr);
  661. }
  662. //+---------------------------------------------------------------------------
  663. //
  664. // Function: GetSDForDSObj
  665. //
  666. // Synopsis: Gets a security descriptor from a DS object
  667. //
  668. // Arguments: [IN pwszDSObj] -- The DSObject to get the security
  669. // descriptor for
  670. // [OUT ppSD] -- Where the security descriptor is
  671. // returned
  672. //
  673. // Returns: ERROR_SUCCESS -- The object is reachable
  674. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  675. // ERROR_INVALID_PARAMETER The object name that was given was in
  676. // a bad format (not \\x\y)
  677. //
  678. // Notes: The returned security descriptor must be freed with LocalFree
  679. //
  680. //----------------------------------------------------------------------------
  681. DWORD
  682. GetSDForDSObj(IN LPWSTR pwszDSObj,
  683. IN SECURITY_INFORMATION SeInfo,
  684. OUT PSECURITY_DESCRIPTOR *ppSD)
  685. {
  686. acDebugOut((DEB_TRACE, "in GetSDForDSObj\n"));
  687. DWORD dwErr = ERROR_SUCCESS;
  688. PWSTR pwszServer = NULL, pwszPath = NULL;
  689. dwErr = DspSplitPath(pwszDSObj,
  690. &pwszServer,
  691. &pwszPath);
  692. if(dwErr == ERROR_SUCCESS)
  693. {
  694. //
  695. // Convert the name into attributed format
  696. //
  697. PDS_NAME_RESULTW pNameRes;
  698. dwErr = DspBindAndCrack( pwszServer, pwszPath, 0, &pNameRes );
  699. if(dwErr == ERROR_SUCCESS)
  700. {
  701. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0)
  702. {
  703. dwErr = ERROR_PATH_NOT_FOUND;
  704. }
  705. else
  706. {
  707. //
  708. // Now, we'll bind to the object, and then do the read
  709. //
  710. PLDAP pLDAP;
  711. dwErr = BindToDSObject(pwszServer,
  712. pNameRes->rItems[0].pDomain,
  713. &pLDAP);
  714. if(dwErr == ERROR_SUCCESS)
  715. {
  716. //
  717. // Now, we'll do the read...
  718. //
  719. dwErr = ReadDSObjSecDesc(pLDAP,
  720. pNameRes->rItems[0].pName,
  721. SeInfo,
  722. ppSD);
  723. UnBindFromDSObject(&pLDAP);
  724. }
  725. }
  726. DsFreeNameResultW(pNameRes);
  727. }
  728. AccFree(pwszServer);
  729. }
  730. acDebugOut((DEB_TRACE, "Out GetSDForDSObj: %lu\n", dwErr));
  731. return(dwErr);
  732. }
  733. //+---------------------------------------------------------------------------
  734. //
  735. // Function: ReadDSObjPropertyRights
  736. //
  737. // Synopsis: Reads the specified property rights from the named DS object
  738. //
  739. // Arguments: [IN pwszDSObj] -- The DSObject to get the security
  740. // descriptor for
  741. // [IN pRightsList] -- The rights information to get
  742. // [IN cRights] -- Number of items in the rights list
  743. // [IN AccessList] -- The access list to initialize
  744. //
  745. // Returns: ERROR_SUCCESS -- The object is reachable
  746. // ERROR_INVALID_PARAMETER A NULL parameter was given
  747. //
  748. // Notes:
  749. //
  750. //----------------------------------------------------------------------------
  751. DWORD
  752. ReadDSObjPropertyRights(IN LPWSTR pwszDSObj,
  753. IN PACTRL_RIGHTS_INFO pRightsList,
  754. IN ULONG cRights,
  755. IN CAccessList& AccessList)
  756. {
  757. acDebugOut((DEB_TRACE, "in ReadDSObjPropertyRights\n"));
  758. DWORD dwErr = ERROR_SUCCESS;
  759. if(pwszDSObj == NULL || pRightsList == NULL)
  760. {
  761. return(ERROR_INVALID_PARAMETER);
  762. }
  763. else
  764. {
  765. //
  766. // Build the security info structure we will need
  767. //
  768. SECURITY_INFORMATION SeInfo = 0;
  769. for(ULONG i = 0; i < cRights; i++)
  770. {
  771. SeInfo |= pRightsList[i].SeInfo;
  772. }
  773. PSECURITY_DESCRIPTOR pSD;
  774. dwErr = GetSDForDSObj(pwszDSObj,
  775. SeInfo,
  776. &pSD);
  777. if(dwErr == ERROR_SUCCESS)
  778. {
  779. //
  780. // Now, we'll simply add the appropriate property based entries
  781. // to our access list.
  782. //
  783. for(ULONG iIndex = 0;
  784. iIndex < cRights && dwErr == ERROR_SUCCESS;
  785. iIndex++)
  786. {
  787. dwErr = AccessList.AddSD(pSD,
  788. pRightsList[iIndex].SeInfo,
  789. pRightsList[iIndex].pwszProperty,
  790. FALSE);
  791. }
  792. AccFree(pSD);
  793. }
  794. }
  795. acDebugOut((DEB_TRACE, "out ReadDSObjPropertyRights: %lu\n", dwErr));
  796. return(dwErr);
  797. }
  798. //+---------------------------------------------------------------------------
  799. //
  800. // Function: ReadAllDSObjPropertyRights
  801. //
  802. // Synopsis: Reads the all the property rights from the named DS object
  803. //
  804. // Arguments: [IN pwszDSObj] -- The DSObject to get the security
  805. // descriptor for
  806. // [IN pRightsList] -- The rights information to get
  807. // [IN cRights] -- Number of items in the rights list
  808. // [IN AccessList] -- The access list to initialize
  809. //
  810. // Returns: ERROR_SUCCESS -- The object is reachable
  811. // ERROR_INVALID_PARAMETER A NULL parameter was given
  812. //
  813. // Notes:
  814. //
  815. //----------------------------------------------------------------------------
  816. DWORD
  817. ReadAllDSObjPropertyRights(IN LPWSTR pwszDSObj,
  818. IN PACTRL_RIGHTS_INFO pRightsList,
  819. IN ULONG cRights,
  820. IN CAccessList& AccessList)
  821. {
  822. DWORD dwErr = ERROR_SUCCESS;
  823. if(pwszDSObj == NULL || pRightsList == NULL)
  824. {
  825. return(ERROR_INVALID_PARAMETER);
  826. }
  827. else
  828. {
  829. //
  830. // Build the security info structure we will need
  831. //
  832. SECURITY_INFORMATION SeInfo = 0;
  833. for(ULONG i = 0; i < cRights; i++)
  834. {
  835. SeInfo |= pRightsList[i].SeInfo;
  836. }
  837. PSECURITY_DESCRIPTOR pSD;
  838. dwErr = GetSDForDSObj(pwszDSObj,
  839. SeInfo,
  840. &pSD);
  841. if(dwErr == ERROR_SUCCESS)
  842. {
  843. //
  844. // Now, we'll simply add it to our access list. We'll ignore
  845. // any rights info after the first one.
  846. //
  847. dwErr = AccessList.AddSD(pSD,
  848. pRightsList[0].SeInfo,
  849. NULL,
  850. TRUE);
  851. AccFree(pSD);
  852. }
  853. }
  854. return(dwErr);
  855. }
  856. //+---------------------------------------------------------------------------
  857. //
  858. // Function: SetDSObjSecurityInfo
  859. //
  860. // Synopsis: Sets the security descriptor on the DS object
  861. //
  862. // Arguments: [IN pwszDSObj] -- The DSObject to get the security
  863. // descriptor for
  864. // [IN SeInfo] -- Security Infofor the security
  865. // descriptor
  866. // [IN pwszProperty] -- Object property to set the access on
  867. // [IN pSD] -- Security descriptor to set
  868. // [IN cSDSize] -- Size of the security descriptor
  869. // [IN pfStopFlag] -- The stop flag to monitor
  870. // [IN pcProcessed] -- Where to increment the count of
  871. // processsed items
  872. //
  873. // Returns: ERROR_SUCCESS -- The object is reachable
  874. // ERROR_INVALID_PARAMETER A NULL parameter was given
  875. //
  876. // Notes:
  877. //
  878. //----------------------------------------------------------------------------
  879. DWORD
  880. SetDSObjSecurityInfo(IN LPWSTR pwszDSObj,
  881. IN SECURITY_INFORMATION SeInfo,
  882. IN PWSTR pwszProperty,
  883. IN PSECURITY_DESCRIPTOR pSD,
  884. IN ULONG cSDSize,
  885. IN PULONG pfStopFlag,
  886. IN PULONG pcProcessed)
  887. {
  888. DWORD dwErr = ERROR_SUCCESS;
  889. PWSTR pwszServer = NULL, pwszPath = NULL;
  890. dwErr = DspSplitPath(pwszDSObj,
  891. &pwszServer,
  892. &pwszPath);
  893. if(dwErr == ERROR_SUCCESS)
  894. {
  895. //
  896. // Convert the name into attributed format
  897. //
  898. PDS_NAME_RESULTW pNameRes;
  899. dwErr = DspBindAndCrack( pwszServer, pwszPath, 0, &pNameRes );
  900. if(dwErr == ERROR_SUCCESS)
  901. {
  902. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0)
  903. {
  904. dwErr = ERROR_PATH_NOT_FOUND;
  905. }
  906. else
  907. {
  908. //
  909. // Convert our name to ascii
  910. //
  911. PLDAP pLDAP;
  912. dwErr = BindToDSObject(pwszServer,
  913. pNameRes->rItems[0].pDomain,
  914. &pLDAP);
  915. if(dwErr == ERROR_SUCCESS)
  916. {
  917. #ifdef NO_PROPAGATE
  918. dwErr = StampSD(pNameRes->rItems[0].pName,
  919. cSDSize,
  920. SeInfo,
  921. pSD,
  922. pLDAP);
  923. #else
  924. dwErr = PropagateDSRightsDeep(NULL,
  925. pSD,
  926. SeInfo,
  927. pNameRes->rItems[0].pName,
  928. pLDAP,
  929. pcProcessed,
  930. pfStopFlag);
  931. #endif
  932. UnBindFromDSObject(&pLDAP);
  933. }
  934. }
  935. DsFreeNameResultW(pNameRes);
  936. }
  937. AccFree(pwszServer);
  938. }
  939. return(dwErr);
  940. }
  941. //+---------------------------------------------------------------------------
  942. //
  943. // Function: PingDSObj
  944. //
  945. // Synopsis: "Pings" the specified DS object, to determine if it is
  946. // reachable or not
  947. //
  948. // Arguments: [IN pObjectName] -- The name of the object
  949. //
  950. // Returns: ERROR_SUCCESS -- The object is reachable
  951. // ERROR_PATH_NOT_FOUND-- The object was not reachable
  952. //
  953. // Notes:
  954. //
  955. //----------------------------------------------------------------------------
  956. DWORD
  957. PingDSObj(IN LPCWSTR pwszDSObj)
  958. {
  959. acDebugOut((DEB_TRACE, "in PingDSObj\n"));
  960. DWORD dwErr;
  961. PWSTR pwszServer = NULL, pwszPath = NULL;
  962. dwErr = DspSplitPath((PWSTR)pwszDSObj,
  963. &pwszServer,
  964. &pwszPath);
  965. if(dwErr == ERROR_SUCCESS)
  966. {
  967. //
  968. // Convert the name into attributed format
  969. //
  970. PDS_NAME_RESULTW pNameRes;
  971. dwErr = DspBindAndCrack(pwszServer, pwszPath, 0, &pNameRes);
  972. if(dwErr == ERROR_SUCCESS)
  973. {
  974. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0)
  975. {
  976. dwErr = ERROR_PATH_NOT_FOUND;
  977. }
  978. else
  979. {
  980. //
  981. // Now, we'll bind to the object, and then do the read
  982. //
  983. PLDAP pLDAP;
  984. dwErr = BindToDSObject(pwszServer,
  985. pNameRes->rItems[0].pDomain,
  986. &pLDAP);
  987. if(dwErr == ERROR_SUCCESS)
  988. {
  989. PLDAPMessage pMessage = NULL;
  990. PWSTR rgAttribs[2];
  991. rgAttribs[0] = L"distinguishedName";
  992. rgAttribs[1] = NULL;
  993. if(dwErr == ERROR_SUCCESS)
  994. {
  995. dwErr = ldap_search_s(pLDAP,
  996. pwszPath,
  997. LDAP_SCOPE_BASE,
  998. L"(objectClass=*)",
  999. rgAttribs,
  1000. 0,
  1001. &pMessage);
  1002. dwErr = LdapMapErrorToWin32( dwErr );
  1003. }
  1004. if(dwErr == ERROR_SUCCESS)
  1005. {
  1006. LDAPMessage *pEntry = NULL;
  1007. pEntry = ldap_first_entry(pLDAP,
  1008. pMessage);
  1009. if(pEntry == NULL)
  1010. {
  1011. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1012. }
  1013. else
  1014. {
  1015. //
  1016. // Now, we'll have to get the values
  1017. //
  1018. PWSTR *ppwszValues = ldap_get_values(pLDAP,
  1019. pEntry,
  1020. rgAttribs[0]);
  1021. if(ppwszValues == NULL)
  1022. {
  1023. if(pLDAP->ld_errno == LDAP_NO_SUCH_ATTRIBUTE )
  1024. {
  1025. dwErr = ERROR_SUCCESS;
  1026. }
  1027. else
  1028. {
  1029. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1030. }
  1031. }
  1032. else
  1033. {
  1034. ldap_value_free(ppwszValues);
  1035. }
  1036. }
  1037. ldap_msgfree(pMessage);
  1038. }
  1039. }
  1040. }
  1041. DsFreeNameResultW(pNameRes);
  1042. }
  1043. AccFree(pwszServer);
  1044. }
  1045. acDebugOut((DEB_TRACE, "out PingDSObj: %lu\n", dwErr));
  1046. return(dwErr);
  1047. }
  1048. DWORD
  1049. Nt4NameToNt5Name(IN PWSTR pwszName,
  1050. IN PWSTR pwszDomain,
  1051. OUT PWSTR *ppwszNt5Name)
  1052. {
  1053. DWORD dwErr = ERROR_SUCCESS;
  1054. WCHAR wszFullName[MAX_PATH + 1];
  1055. LPWSTR pwszFullName;
  1056. ULONG cLen = wcslen(pwszName) + 1;
  1057. if(pwszDomain != NULL)
  1058. {
  1059. cLen += wcslen(pwszDomain) + 1;
  1060. }
  1061. if(cLen < MAX_PATH + 1)
  1062. {
  1063. pwszFullName = wszFullName;
  1064. }
  1065. else
  1066. {
  1067. pwszFullName = (PWSTR)AccAlloc(cLen * sizeof(WCHAR));
  1068. if(pwszFullName == NULL)
  1069. {
  1070. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1071. }
  1072. }
  1073. if(dwErr == ERROR_SUCCESS)
  1074. {
  1075. if(pwszDomain != NULL)
  1076. {
  1077. wcscpy(pwszFullName, pwszDomain);
  1078. wcscat(pwszFullName, L"\\");
  1079. }
  1080. else
  1081. {
  1082. *pwszFullName = L'\0';
  1083. }
  1084. wcscat(pwszFullName, pwszName);
  1085. }
  1086. //
  1087. // Now, for the crack name...
  1088. //
  1089. if(dwErr == ERROR_SUCCESS)
  1090. {
  1091. PDS_NAME_RESULTW pNameRes;
  1092. dwErr = DspBindAndCrack(NULL, wszFullName, 0, &pNameRes );
  1093. if(dwErr == ERROR_SUCCESS)
  1094. {
  1095. if(pNameRes->cItems == 0 || pNameRes->rItems[0].status != 0)
  1096. {
  1097. dwErr = ERROR_PATH_NOT_FOUND;
  1098. }
  1099. else
  1100. {
  1101. ACC_ALLOC_AND_COPY_STRINGW(pNameRes->rItems[0].pName,
  1102. *ppwszNt5Name,
  1103. dwErr);
  1104. }
  1105. }
  1106. else
  1107. {
  1108. if(dwErr == MAPI_E_LOGON_FAILED)
  1109. {
  1110. dwErr = ERROR_LOGON_FAILURE;
  1111. }
  1112. }
  1113. DsFreeNameResultW(pNameRes);
  1114. }
  1115. //
  1116. // See if we need to free our buffer
  1117. //
  1118. if(pwszFullName != wszFullName)
  1119. {
  1120. AccFree(pwszFullName);
  1121. }
  1122. return(dwErr);
  1123. }
  1124. #define CLEANUP_ON_INTERRUPT(pstopflag) \
  1125. if(*pstopflag != 0) \
  1126. { \
  1127. goto DSCleanup; \
  1128. }
  1129. //+---------------------------------------------------------------------------
  1130. //
  1131. // Function: PropagateDSRightsDeep, recursive
  1132. //
  1133. // Synopsis: Does a deep propagation of the access.
  1134. //
  1135. // Arguments: [IN pParentSD] -- The current parent sd
  1136. // [IN SeInfo] -- What is being written
  1137. // [IN pwszFile] -- Parent file path
  1138. // [IN pcProcessed] -- Where the number processed is
  1139. // returned.
  1140. // [IN pfStopFlag] -- Stop flag to monitor
  1141. //
  1142. // Returns: ERROR_SUCCESS -- Success
  1143. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1144. //
  1145. //----------------------------------------------------------------------------
  1146. DWORD
  1147. PropagateDSRightsDeep(IN PSECURITY_DESCRIPTOR pParentSD,
  1148. IN PSECURITY_DESCRIPTOR pChildSD,
  1149. IN SECURITY_INFORMATION SeInfo,
  1150. IN PWSTR pwszDSObject,
  1151. IN PLDAP pLDAP,
  1152. IN PULONG pcProcessed,
  1153. IN PULONG pfStopFlag)
  1154. {
  1155. acDebugOut((DEB_TRACE, "in PropagateDSRightsDeep\n"));
  1156. DWORD dwErr = ERROR_SUCCESS;
  1157. BOOL fFreeChildSD = FALSE;
  1158. acDebugOut((DEB_TRACE_PROP, "Processing %ws\n", pwszDSObject));
  1159. //
  1160. // If our security descriptor is already in DS form, then we'll have
  1161. // to adjust for that
  1162. //
  1163. if(pChildSD != NULL)
  1164. {
  1165. PULONG pSE = (PULONG)(pChildSD);
  1166. if(*pSE == SeInfo)
  1167. {
  1168. pChildSD = (PSECURITY_DESCRIPTOR)((PBYTE)pChildSD + sizeof(ULONG));
  1169. }
  1170. }
  1171. else
  1172. {
  1173. dwErr = ReadDSObjSecDesc(pLDAP,
  1174. pwszDSObject,
  1175. SeInfo,
  1176. &pChildSD);
  1177. if(dwErr == ERROR_SUCCESS)
  1178. {
  1179. fFreeChildSD = TRUE;
  1180. }
  1181. else
  1182. {
  1183. return(dwErr);
  1184. }
  1185. }
  1186. //
  1187. // Ok, we'll convert our path to a narrow string, and then we'll enumerate
  1188. // all of the children
  1189. //
  1190. PSECURITY_DESCRIPTOR pNewSD = NULL;
  1191. PLDAPMessage pMessage = NULL;
  1192. //
  1193. // First, we'll create the new SD...
  1194. //
  1195. HANDLE hProcessToken = NULL;
  1196. GENERIC_MAPPING GenMap;
  1197. GenMap.GenericRead = GENERIC_READ_MAPPING;
  1198. GenMap.GenericWrite = GENERIC_WRITE_MAPPING;
  1199. GenMap.GenericExecute = GENERIC_EXECUTE_MAPPING;
  1200. GenMap.GenericAll = GENERIC_ALL_MAPPING;
  1201. dwErr = GetCurrentToken( &hProcessToken );
  1202. if(dwErr == ERROR_SUCCESS)
  1203. {
  1204. #ifdef DBG
  1205. DebugDumpSD("CPOSE ParentSD", pParentSD);
  1206. DebugDumpSD("CPOSE ChildSD", pChildSD);
  1207. #endif
  1208. if(CreatePrivateObjectSecurityEx(pParentSD,
  1209. pChildSD,
  1210. &pNewSD,
  1211. NULL,
  1212. TRUE,
  1213. SEF_DACL_AUTO_INHERIT |
  1214. SEF_SACL_AUTO_INHERIT,
  1215. hProcessToken,
  1216. &GenMap) == FALSE)
  1217. {
  1218. dwErr = GetLastError();
  1219. }
  1220. else
  1221. {
  1222. #ifdef DBG
  1223. DebugDumpSD("CPOSE NewSD", pNewSD);
  1224. #endif
  1225. //
  1226. // Stamp the SD on the object... This means that we'll have
  1227. // to allocate a new security descriptor that is 4 bytes
  1228. // bigger than what we need, and set our SeInfo
  1229. //
  1230. PSECURITY_DESCRIPTOR pSetSD = NULL;
  1231. ULONG cNewSDSize = 0;
  1232. if(RtlpAreControlBitsSet((PISECURITY_DESCRIPTOR)pChildSD,
  1233. SE_SELF_RELATIVE))
  1234. {
  1235. cNewSDSize = RtlLengthSecurityDescriptor(pNewSD);
  1236. ASSERT(cNewSDSize != 0);
  1237. }
  1238. else
  1239. {
  1240. MakeSelfRelativeSD(pNewSD,
  1241. NULL,
  1242. &cNewSDSize);
  1243. ASSERT(GetLastError() == ERROR_INSUFFICIENT_BUFFER);
  1244. }
  1245. cNewSDSize += sizeof(ULONG);
  1246. pSetSD = (PSECURITY_DESCRIPTOR)AccAlloc(cNewSDSize);
  1247. if(pSetSD == NULL)
  1248. {
  1249. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1250. }
  1251. else
  1252. {
  1253. pSetSD = (PSECURITY_DESCRIPTOR)
  1254. ((PBYTE)pSetSD + sizeof(ULONG));
  1255. if(RtlpAreControlBitsSet((PISECURITY_DESCRIPTOR)pChildSD,
  1256. SE_SELF_RELATIVE))
  1257. {
  1258. memcpy(pSetSD, pNewSD, cNewSDSize - sizeof(ULONG));
  1259. }
  1260. else
  1261. {
  1262. if(MakeSelfRelativeSD(pNewSD,
  1263. pSetSD,
  1264. &cNewSDSize) == FALSE)
  1265. {
  1266. dwErr = GetLastError();
  1267. }
  1268. }
  1269. PULONG pSE = (PULONG)((PBYTE)pSetSD - sizeof(ULONG));
  1270. *pSE = SeInfo;
  1271. //
  1272. // We need to pass in the security_information
  1273. //
  1274. pSetSD = (PSECURITY_DESCRIPTOR)pSE;
  1275. //
  1276. // Now, do the write
  1277. //
  1278. dwErr = StampSD(pwszDSObject,
  1279. cNewSDSize,
  1280. SeInfo,
  1281. pSetSD,
  1282. pLDAP);
  1283. AccFree(pSetSD);
  1284. }
  1285. }
  1286. }
  1287. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1288. if(dwErr == ERROR_SUCCESS)
  1289. {
  1290. PWSTR rgAttribs[2];
  1291. WCHAR wszAttrib[]=L"distinguishedName";
  1292. //
  1293. // Do the search...
  1294. //
  1295. rgAttribs[0] = wszAttrib;
  1296. rgAttribs[1] = NULL;
  1297. if(dwErr == ERROR_SUCCESS)
  1298. {
  1299. dwErr = ldap_search_s(pLDAP,
  1300. pwszDSObject,
  1301. LDAP_SCOPE_ONELEVEL,
  1302. L"(objectClass=*)",
  1303. rgAttribs,
  1304. 0,
  1305. &pMessage);
  1306. dwErr = LdapMapErrorToWin32( dwErr );
  1307. }
  1308. if(dwErr == ERROR_SUCCESS)
  1309. {
  1310. ULONG cChildren = ldap_count_entries(pLDAP,
  1311. pMessage);
  1312. acDebugOut((DEB_TRACE_PROP,
  1313. "%ws has %lu children\n",
  1314. pwszDSObject, cChildren));
  1315. LDAPMessage *pEntry = ldap_first_entry(pLDAP,
  1316. pMessage);
  1317. for(ULONG i = 0; i < cChildren; i++)
  1318. {
  1319. if(pEntry == NULL)
  1320. {
  1321. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1322. break;
  1323. }
  1324. //
  1325. // Now, we'll have to get the values
  1326. //
  1327. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1328. PWSTR *ppwszValues = ldap_get_values(pLDAP,
  1329. pEntry,
  1330. rgAttribs[0]);
  1331. if(ppwszValues == NULL)
  1332. {
  1333. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1334. }
  1335. else
  1336. {
  1337. //
  1338. // Go ahead and propagate to the child
  1339. //
  1340. acDebugOut((DEB_TRACE_PROP,
  1341. "Child %ws of %ws [%lu]\n",
  1342. ppwszValues[0], pwszDSObject, i));
  1343. dwErr = PropagateDSRightsDeep(pNewSD,
  1344. NULL,
  1345. SeInfo,
  1346. ppwszValues[0],
  1347. pLDAP,
  1348. pcProcessed,
  1349. pfStopFlag);
  1350. ldap_value_free(ppwszValues);
  1351. CLEANUP_ON_INTERRUPT(pfStopFlag);
  1352. }
  1353. pEntry = ldap_next_entry(pLDAP,
  1354. pEntry);
  1355. }
  1356. }
  1357. }
  1358. DSCleanup:
  1359. ldap_msgfree(pMessage);
  1360. DestroyPrivateObjectSecurity(&pNewSD);
  1361. if(fFreeChildSD == TRUE)
  1362. {
  1363. AccFree(pChildSD);
  1364. }
  1365. acDebugOut((DEB_TRACE, "Out PropagateDSRightsDeep: %ld\n", dwErr));
  1366. return(dwErr);
  1367. }
  1368. //+---------------------------------------------------------------------------
  1369. //
  1370. // Function: StampSD
  1371. //
  1372. // Synopsis: Actually stamps the security descriptor on the object.
  1373. //
  1374. // Arguments: [IN pwszObject] -- The object to stamp the SD on
  1375. // [IN cSDSize] -- The size of the security descriptor
  1376. // [IN SeInfo] -- SecurityInformation about the security
  1377. // descriptor
  1378. // [IN pSD] -- The SD to stamp
  1379. // [IN pLDAP] -- The LDAP connection to use
  1380. //
  1381. // Returns: ERROR_SUCCESS -- Success
  1382. // ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed
  1383. //
  1384. //----------------------------------------------------------------------------
  1385. DWORD
  1386. StampSD(IN PWSTR pwszObject,
  1387. IN ULONG cSDSize,
  1388. IN SECURITY_INFORMATION SeInfo,
  1389. IN PSECURITY_DESCRIPTOR pSD,
  1390. IN PLDAP pLDAP)
  1391. {
  1392. DWORD dwErr = ERROR_SUCCESS;
  1393. acDebugOut((DEB_TRACE_PROP, "Stamping %ws\n", pwszObject));
  1394. //
  1395. // Now, we'll do the write. The security descriptor
  1396. // we got passed in better not be in the old Ds format,
  1397. // where the leading 4 bytes are the SECURITY_INFORMATION, which we'll skip
  1398. // and replace with control information
  1399. //
  1400. ASSERT(*(PULONG)pSD > 0xF );
  1401. PLDAPMod rgMods[2];
  1402. PLDAP_BERVAL pBVals[2];
  1403. LDAPMod Mod;
  1404. LDAP_BERVAL BVal;
  1405. BYTE ControlBuffer[ 5 ];
  1406. LDAPControl SeInfoControl =
  1407. {
  1408. LDAP_SERVER_SD_FLAGS_OID_W,
  1409. {
  1410. 5, (PCHAR) &ControlBuffer
  1411. },
  1412. TRUE
  1413. };
  1414. //
  1415. // !!! Hardcoded for now. Use Andyhe's BER_printf once it's done.
  1416. //
  1417. ControlBuffer[0] = 0x30;
  1418. ControlBuffer[1] = 0x3;
  1419. ControlBuffer[2] = 0x02; // Denotes an integer;
  1420. ControlBuffer[3] = 0x01; // Size
  1421. ControlBuffer[4] = (BYTE)((ULONG)SeInfo & 0xF);
  1422. PLDAPControl ServerControls[2] =
  1423. {
  1424. &SeInfoControl,
  1425. NULL
  1426. };
  1427. ASSERT(IsValidSecurityDescriptor( pSD ) );
  1428. rgMods[0] = &Mod;
  1429. rgMods[1] = NULL;
  1430. pBVals[0] = &BVal;
  1431. pBVals[1] = NULL;
  1432. BVal.bv_len = cSDSize;
  1433. BVal.bv_val = (PCHAR)pSD;
  1434. Mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  1435. Mod.mod_type = ACTRL_SD_PROP_NAME;
  1436. Mod.mod_values = (PWSTR *)pBVals;
  1437. //
  1438. // Now, we'll do the write...
  1439. //
  1440. dwErr = ldap_modify_ext_s(pLDAP,
  1441. pwszObject,
  1442. rgMods,
  1443. (PLDAPControl *)&ServerControls,
  1444. NULL);
  1445. dwErr = LdapMapErrorToWin32(dwErr);
  1446. #if DBG
  1447. PACL pAcl = RtlpDaclAddrSecurityDescriptor((PISECURITY_DESCRIPTOR)pSD);
  1448. ACL_SIZE_INFORMATION AclSize;
  1449. ACL_REVISION_INFORMATION AclRev;
  1450. PKNOWN_ACE pAce;
  1451. PSID pSid;
  1452. DWORD iIndex;
  1453. DWORD GuidPart;
  1454. DWORD OldInfoLevel;
  1455. //
  1456. // Now, dump all of the aces
  1457. //
  1458. if(pAcl)
  1459. {
  1460. pAce = (PKNOWN_ACE)FirstAce(pAcl);
  1461. for(iIndex = 0; iIndex < pAcl->AceCount; iIndex++)
  1462. {
  1463. //
  1464. // If it's an object ace, dump the guids
  1465. //
  1466. if(IsObjectAceType(pAce))
  1467. {
  1468. OldInfoLevel = acInfoLevel;
  1469. // acInfoLevel |= DEB_TRACE_SD;
  1470. DebugDumpGuid("\t\t\tObjectId", RtlObjectAceObjectType(pAce));
  1471. GuidPart = (ULONG)((ULONG_PTR)RtlObjectAceObjectType(pAce));
  1472. ASSERT(GuidPart != 0x2bfff20);
  1473. acInfoLevel = OldInfoLevel;
  1474. }
  1475. pAce = (PKNOWN_ACE)NextAce(pAce);
  1476. }
  1477. }
  1478. #endif
  1479. return(dwErr);
  1480. }
  1481. //+---------------------------------------------------------------------------
  1482. //
  1483. // Function: AccDsReadSchemaInfo
  1484. //
  1485. // Synopsis: Reads the schema object/property info.
  1486. //
  1487. // Arguments: [IN pLDAP] -- LDAP connection to use
  1488. // [OUT pcClasses] -- Where the count of class info
  1489. // is returned
  1490. // [OUT pppwszClasses] -- Where the list of classes info
  1491. // is returned. Freed with
  1492. // ldap_value_free
  1493. // [OUT pcAttributes] -- Where the count of property infos
  1494. // is returned
  1495. // [OUT pppwszAttributes] -- Where the list of property infos
  1496. // is returned. Freed with
  1497. // ldap_value_free
  1498. //
  1499. // Returns: ERROR_SUCCESS -- Success
  1500. //
  1501. //----------------------------------------------------------------------------
  1502. DWORD
  1503. AccDsReadSchemaInfo (IN PLDAP pLDAP,
  1504. OUT PULONG pcClasses,
  1505. OUT PWSTR **pppwszClasses,
  1506. OUT PULONG pcAttributes,
  1507. OUT PWSTR **pppwszAttributes)
  1508. {
  1509. DWORD dwErr = ERROR_SUCCESS;
  1510. PWSTR *ppwszValues = NULL;
  1511. PWSTR rgwszAttribs[3];
  1512. PDS_NAME_RESULTW pNameRes = NULL;
  1513. LDAPMessage *pMessage, *pEntry;
  1514. *pcClasses = 0;
  1515. *pcAttributes = 0;
  1516. *pppwszAttributes = NULL;
  1517. *pppwszClasses = NULL;
  1518. //
  1519. // Get the subschema path
  1520. //
  1521. if(dwErr == ERROR_SUCCESS)
  1522. {
  1523. rgwszAttribs[0] = L"subschemaSubentry";
  1524. rgwszAttribs[1] = NULL;
  1525. dwErr = ldap_search_s(pLDAP,
  1526. NULL,
  1527. LDAP_SCOPE_BASE,
  1528. L"(objectClass=*)",
  1529. rgwszAttribs,
  1530. 0,
  1531. &pMessage);
  1532. if(dwErr == ERROR_SUCCESS)
  1533. {
  1534. pEntry = ldap_first_entry(pLDAP,
  1535. pMessage);
  1536. if(pEntry == NULL)
  1537. {
  1538. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1539. }
  1540. else
  1541. {
  1542. //
  1543. // Now, we'll have to get the values
  1544. //
  1545. ppwszValues = ldap_get_values(pLDAP,
  1546. pEntry,
  1547. rgwszAttribs[0]);
  1548. ldap_msgfree(pMessage);
  1549. if(ppwszValues == NULL)
  1550. {
  1551. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1552. }
  1553. else
  1554. {
  1555. rgwszAttribs[0] = L"extendedClassInfo";
  1556. rgwszAttribs[1] = L"extendedAttributeInfo";
  1557. rgwszAttribs[2] = NULL;
  1558. dwErr = ldap_search_s(pLDAP,
  1559. ppwszValues[0],
  1560. LDAP_SCOPE_BASE,
  1561. L"(objectClass=*)",
  1562. rgwszAttribs,
  1563. 0,
  1564. &pMessage);
  1565. ldap_value_free(ppwszValues);
  1566. if(dwErr == ERROR_SUCCESS)
  1567. {
  1568. ldap_count_entries( pLDAP, pMessage );
  1569. pEntry = ldap_first_entry(pLDAP,
  1570. pMessage);
  1571. if(pEntry == NULL)
  1572. {
  1573. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1574. }
  1575. else
  1576. {
  1577. //
  1578. // Now, we'll have to get the values
  1579. //
  1580. *pppwszClasses = ldap_get_values(pLDAP,
  1581. pEntry,
  1582. rgwszAttribs[0]);
  1583. if(*pppwszClasses == NULL)
  1584. {
  1585. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1586. }
  1587. else
  1588. {
  1589. *pcClasses = ldap_count_values(*pppwszClasses);
  1590. *pppwszAttributes = ldap_get_values(pLDAP,
  1591. pEntry,
  1592. rgwszAttribs[1]);
  1593. if(*pppwszAttributes == NULL)
  1594. {
  1595. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1596. ldap_value_free(*pppwszClasses);
  1597. }
  1598. else
  1599. {
  1600. *pcAttributes =
  1601. ldap_count_values(*pppwszAttributes);
  1602. }
  1603. }
  1604. }
  1605. }
  1606. else
  1607. {
  1608. dwErr = LdapMapErrorToWin32( dwErr );
  1609. }
  1610. ldap_msgfree(pMessage);
  1611. }
  1612. }
  1613. }
  1614. else
  1615. {
  1616. dwErr = LdapMapErrorToWin32( dwErr );
  1617. }
  1618. }
  1619. return(dwErr);
  1620. }
  1621. //+---------------------------------------------------------------------------
  1622. //
  1623. // Function: AccDsReadExtendedRights
  1624. //
  1625. // Synopsis: Reads the list of extended rights from the schema
  1626. //
  1627. // Arguments: [IN pLDAP] -- LDAP connection to use
  1628. // [OUT pcItems] -- Where the count of items
  1629. // is returned
  1630. // [OUT ppwszNames] -- Where the list of Names is
  1631. // returned.
  1632. // [OUT ppwszGuids] -- Where the list of guids is
  1633. // returned.
  1634. //
  1635. // Notes: Freed via AccDsFreeExtendedRights
  1636. //
  1637. // Returns: ERROR_SUCCESS -- Success
  1638. //
  1639. //----------------------------------------------------------------------------
  1640. DWORD
  1641. AccDsReadExtendedRights(IN PLDAP pLDAP,
  1642. OUT PULONG pcItems,
  1643. OUT PWSTR **pppwszNames,
  1644. OUT PWSTR **pppwszGuids)
  1645. {
  1646. DWORD dwErr = ERROR_SUCCESS;
  1647. PWSTR *ppwszValues = NULL;
  1648. PWSTR rgwszAttribs[3];
  1649. PWSTR pwszERContainer = NULL;
  1650. PDS_NAME_RESULTW pNameRes = NULL;
  1651. LDAPMessage *pMessage, *pEntry;
  1652. ULONG cEntries = 0, i;
  1653. *pcItems = 0;
  1654. *pppwszNames = NULL;
  1655. *pppwszGuids = NULL;
  1656. //
  1657. // Get the subschema path
  1658. //
  1659. if(dwErr == ERROR_SUCCESS)
  1660. {
  1661. rgwszAttribs[0] = L"configurationNamingContext";
  1662. rgwszAttribs[1] = NULL;
  1663. dwErr = ldap_search_s(pLDAP,
  1664. NULL,
  1665. LDAP_SCOPE_BASE,
  1666. L"(objectClass=*)",
  1667. rgwszAttribs,
  1668. 0,
  1669. &pMessage);
  1670. if(dwErr == ERROR_SUCCESS)
  1671. {
  1672. pEntry = ldap_first_entry(pLDAP,
  1673. pMessage);
  1674. if(pEntry == NULL)
  1675. {
  1676. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1677. }
  1678. else
  1679. {
  1680. //
  1681. // Now, we'll have to get the values
  1682. //
  1683. ppwszValues = ldap_get_values(pLDAP,
  1684. pEntry,
  1685. rgwszAttribs[0]);
  1686. ldap_msgfree(pMessage);
  1687. if(ppwszValues == NULL)
  1688. {
  1689. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1690. }
  1691. else
  1692. {
  1693. pwszERContainer = (PWSTR)AccAlloc((wcslen(ppwszValues[0]) * sizeof(WCHAR)) +
  1694. sizeof(ACTRL_EXT_RIGHTS_CONTAINER));
  1695. if(pwszERContainer == NULL)
  1696. {
  1697. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1698. }
  1699. else
  1700. {
  1701. wcscpy(pwszERContainer,
  1702. ACTRL_EXT_RIGHTS_CONTAINER);
  1703. wcscat(pwszERContainer,
  1704. ppwszValues[0]);
  1705. rgwszAttribs[0] = L"displayName";
  1706. rgwszAttribs[1] = L"rightsGuid";
  1707. rgwszAttribs[2] = NULL;
  1708. //
  1709. // Read the control access rights
  1710. //
  1711. dwErr = ldap_search_s(pLDAP,
  1712. pwszERContainer,
  1713. LDAP_SCOPE_ONELEVEL,
  1714. L"(objectClass=controlAccessRight)",
  1715. rgwszAttribs,
  1716. 0,
  1717. &pMessage);
  1718. dwErr = LdapMapErrorToWin32( dwErr );
  1719. AccFree(pwszERContainer);
  1720. }
  1721. ldap_value_free(ppwszValues);
  1722. if(dwErr == ERROR_SUCCESS)
  1723. {
  1724. cEntries = ldap_count_entries( pLDAP, pMessage );
  1725. *pppwszNames = (PWSTR *)AccAlloc( sizeof( PWSTR ) * cEntries );
  1726. if(*pppwszNames == NULL)
  1727. {
  1728. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1729. }
  1730. else
  1731. {
  1732. *pppwszGuids = (PWSTR *)AccAlloc( sizeof( PWSTR ) * cEntries );
  1733. if(*pppwszGuids == NULL)
  1734. {
  1735. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  1736. AccFree(*pppwszNames);
  1737. *pppwszNames = NULL;
  1738. }
  1739. }
  1740. if(dwErr == ERROR_SUCCESS)
  1741. {
  1742. pEntry = ldap_first_entry(pLDAP,
  1743. pMessage);
  1744. if(pEntry == NULL)
  1745. {
  1746. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1747. }
  1748. else
  1749. {
  1750. for(i = 0; i < cEntries && dwErr == ERROR_SUCCESS; i++) {
  1751. ppwszValues = ldap_get_values(pLDAP,
  1752. pEntry,
  1753. rgwszAttribs[0]);
  1754. if(ppwszValues == NULL)
  1755. {
  1756. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1757. }
  1758. else
  1759. {
  1760. //
  1761. // Now, we'll have to get the values
  1762. //
  1763. ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0],
  1764. (*pppwszNames)[i],
  1765. dwErr);
  1766. ldap_value_free(ppwszValues);
  1767. if(dwErr == ERROR_SUCCESS)
  1768. {
  1769. ppwszValues = ldap_get_values(pLDAP,
  1770. pEntry,
  1771. rgwszAttribs[1]);
  1772. if(ppwszValues == NULL)
  1773. {
  1774. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  1775. }
  1776. else
  1777. {
  1778. ACC_ALLOC_AND_COPY_STRINGW(ppwszValues[0],
  1779. (*pppwszGuids)[i],
  1780. dwErr);
  1781. ldap_value_free(ppwszValues);
  1782. }
  1783. }
  1784. }
  1785. pEntry = ldap_next_entry( pLDAP, pEntry );
  1786. }
  1787. if(dwErr != ERROR_SUCCESS)
  1788. {
  1789. AccDsFreeExtendedRights(i,
  1790. *pppwszNames,
  1791. *pppwszGuids);
  1792. }
  1793. }
  1794. }
  1795. }
  1796. if(dwErr == ERROR_SUCCESS)
  1797. {
  1798. *pcItems = cEntries;
  1799. }
  1800. ldap_msgfree(pMessage);
  1801. }
  1802. }
  1803. }
  1804. else
  1805. {
  1806. dwErr = LdapMapErrorToWin32( dwErr );
  1807. }
  1808. }
  1809. return(dwErr) ;
  1810. }
  1811. VOID
  1812. AccDsFreeExtendedRights(IN ULONG cItems,
  1813. IN PWSTR *ppwszNames,
  1814. IN PWSTR *ppwszGuids)
  1815. {
  1816. ULONG i;
  1817. for(i = 0;i < cItems;i++ )
  1818. {
  1819. AccFree( ppwszNames[ i ]);
  1820. AccFree( ppwszGuids[ i ]);
  1821. }
  1822. AccFree(ppwszNames);
  1823. AccFree(ppwszGuids);
  1824. }