Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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