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.

938 lines
25 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1998, Microsoft Corporation
  4. //
  5. // File: dfsacl.c
  6. // Contents: Functions to add/remove entries from ACL list(s).
  7. //
  8. // History: Nov 6, 1998 JHarper created
  9. //
  10. //-----------------------------------------------------------------------------
  11. #include <stdio.h>
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <winldap.h>
  17. #include <ntldap.h>
  18. #include <stdlib.h>
  19. #include <dsgetdc.h>
  20. #include <lm.h>
  21. #include <sddl.h>
  22. #include "dfsacl.h"
  23. DWORD
  24. ReadDSObjSecDesc(
  25. PLDAP pLDAP,
  26. PWSTR pwszObject,
  27. SECURITY_INFORMATION SeInfo,
  28. PSECURITY_DESCRIPTOR *ppSD,
  29. PULONG pcSDSize);
  30. DWORD
  31. DfsGetObjSecurity(
  32. LDAP *pldap,
  33. LPWSTR pwszObjectName,
  34. LPWSTR *pwszStringSD);
  35. DWORD
  36. DfsStampSD(
  37. PWSTR pwszObject,
  38. ULONG cSDSize,
  39. SECURITY_INFORMATION SeInfo,
  40. PSECURITY_DESCRIPTOR pSD,
  41. PLDAP pLDAP);
  42. DWORD
  43. DfsAddAce(
  44. LDAP *pldap,
  45. LPWSTR wszObjectName,
  46. LPWSTR wszStringSD,
  47. LPWSTR wszwszStringSid);
  48. DWORD
  49. DfsRemoveAce(
  50. LDAP *pldap,
  51. LPWSTR wszObjectName,
  52. LPWSTR wszStringSD,
  53. LPWSTR wszwszStringSid);
  54. BOOL
  55. DfsFindSid(
  56. LPWSTR DcName,
  57. LPWSTR Name,
  58. PSID *Sid);
  59. BOOLEAN
  60. DfsSidInAce(
  61. LPWSTR wszAce,
  62. LPWSTR wszStringSid);
  63. #define ACTRL_SD_PROP_NAME L"nTSecurityDescriptor"
  64. //
  65. // Name of the attribute holding the ACL/ACE list
  66. //
  67. #define ACTRL_SD_PROP_NAME L"nTSecurityDescriptor"
  68. //
  69. // The sddl description of the ACE we will be adding
  70. //
  71. LPWSTR wszAce = L"(A;;RPWP;;;";
  72. #if DBG
  73. extern ULONG DfsDebug;
  74. #endif
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Function: DfsAddMachineAce
  78. //
  79. // Synopsis: Adds an ACE representing this machine to the ACL list of the
  80. // object.
  81. //
  82. // Arguments: [pldap] -- The open LDAP connection
  83. // [wszDcName] -- The DC whose DS we are to use.
  84. // [wszObjectName] -- The fully-qualified name of the DS object
  85. // [wszRootName] -- The name of the machine/root we want to add
  86. //
  87. // Returns: ERROR_SUCCESS -- The object is reachable
  88. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  89. //
  90. //----------------------------------------------------------------------------
  91. DWORD
  92. DfsAddMachineAce(
  93. LDAP *pldap,
  94. LPWSTR wszDcName,
  95. LPWSTR wszObjectName,
  96. LPWSTR wszRootName)
  97. {
  98. ULONG dwErr = ERROR_SUCCESS;
  99. PSID Sid = NULL;
  100. BOOL Result;
  101. ULONG i;
  102. ULONG Len = 0;
  103. LPWSTR wszStringSD = NULL;
  104. LPWSTR wszStringSid = NULL;
  105. LPWSTR wszNewRootName = NULL;
  106. UNICODE_STRING DnsName;
  107. UNICODE_STRING NetBiosName;
  108. #if DBG
  109. if (DfsDebug)
  110. DbgPrint("DfsAddMachineAce(%ws,%ws)\n", wszObjectName, wszRootName);
  111. #endif
  112. //
  113. // Get Security Descriptor on the FtDfs object
  114. //
  115. dwErr = DfsGetObjSecurity(pldap, wszObjectName, &wszStringSD);
  116. if (dwErr != ERROR_SUCCESS)
  117. goto Cleanup;
  118. #if DBG
  119. if (DfsDebug)
  120. DbgPrint("ACL=[%ws]\n", wszStringSD);
  121. #endif
  122. Len = wcslen(wszRootName);
  123. wszNewRootName = malloc((Len + 2) * sizeof(WCHAR));
  124. if (wszNewRootName == NULL) {
  125. dwErr = ERROR_OUTOFMEMORY;
  126. goto Cleanup;
  127. }
  128. NetBiosName.Buffer = wszNewRootName;
  129. NetBiosName.MaximumLength = (USHORT)((Len + 2) * sizeof(WCHAR));
  130. NetBiosName.Length = 0;
  131. DnsName.Buffer = wszRootName;
  132. DnsName.Length = (USHORT)(Len * sizeof(WCHAR));
  133. DnsName.MaximumLength = DnsName.Length + sizeof(WCHAR);
  134. dwErr = RtlDnsHostNameToComputerName(
  135. &NetBiosName,
  136. &DnsName,
  137. FALSE);
  138. NetBiosName.Buffer[NetBiosName.Length/sizeof(WCHAR)] = L'\0';
  139. wcscat(wszNewRootName, L"$");
  140. //
  141. // Get SID representing root machine
  142. //
  143. Result = DfsFindSid(wszDcName,wszNewRootName, &Sid);
  144. if (Result != TRUE) {
  145. dwErr = ERROR_OBJECT_NOT_FOUND;
  146. goto Cleanup;
  147. }
  148. #if DBG
  149. if (DfsDebug)
  150. DbgPrint("Got SID for %ws\n", wszRootName);
  151. #endif
  152. //
  153. // Convert the machine SID to a string
  154. //
  155. Result = ConvertSidToStringSid(Sid, &wszStringSid);
  156. if (Result != TRUE) {
  157. dwErr = ERROR_OBJECT_NOT_FOUND;
  158. goto Cleanup;
  159. }
  160. #if DBG
  161. if (DfsDebug)
  162. DbgPrint("Sid=[%ws]\n", wszStringSid);
  163. #endif
  164. //
  165. // Now update the ACL list on the FtDfs object
  166. //
  167. dwErr = DfsAddAce(
  168. pldap,
  169. wszObjectName,
  170. wszStringSD,
  171. wszStringSid);
  172. Cleanup:
  173. if (wszNewRootName != NULL)
  174. free(wszNewRootName);
  175. if (wszStringSD != NULL)
  176. LocalFree(wszStringSD);
  177. if (wszStringSid != NULL)
  178. LocalFree(wszStringSid);
  179. if (Sid != NULL) {
  180. LocalFree(Sid);
  181. }
  182. #if DBG
  183. if (DfsDebug)
  184. DbgPrint("DfsAddMachineAce returning %d\n", dwErr);
  185. #endif
  186. return dwErr;
  187. }
  188. //+---------------------------------------------------------------------------
  189. //
  190. // Function: DfsRemoveMachineAce
  191. //
  192. // Synopsis: Removes an ACE representing this machine from the ACL list of the
  193. // object.
  194. //
  195. // Arguments: [pldap] -- The open LDAP connection
  196. // [wszDcName] -- The DC whose DS we are to use.
  197. // [wszObjectName] -- The fully-qualified name of the DS object
  198. // [wszRootName] -- The name of the machine/root we want to remove
  199. //
  200. // Returns: ERROR_SUCCESS -- The object is reachable
  201. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  202. //
  203. //----------------------------------------------------------------------------
  204. DWORD
  205. DfsRemoveMachineAce(
  206. LDAP *pldap,
  207. LPWSTR wszDcName,
  208. LPWSTR wszObjectName,
  209. LPWSTR wszRootName)
  210. {
  211. ULONG dwErr = ERROR_SUCCESS;
  212. PSID Sid = NULL;
  213. BOOL Result;
  214. LPWSTR wszStringSD = NULL;
  215. LPWSTR wszStringSid = NULL;
  216. LPWSTR wszNewRootName = NULL;
  217. ULONG i;
  218. ULONG Len = 0;
  219. UNICODE_STRING DnsName;
  220. UNICODE_STRING NetBiosName;
  221. #if DBG
  222. if (DfsDebug)
  223. DbgPrint("DfsRemoveMachineAce(%ws,%ws)\n", wszObjectName, wszRootName);
  224. #endif
  225. //
  226. // Get Security Descriptor on the FtDfs object
  227. //
  228. dwErr = DfsGetObjSecurity(pldap, wszObjectName, &wszStringSD);
  229. if (dwErr != ERROR_SUCCESS)
  230. goto Cleanup;
  231. #if DBG
  232. if (DfsDebug)
  233. DbgPrint("ACL=[%ws]\n", wszStringSD);
  234. #endif
  235. Len = wcslen(wszRootName);
  236. wszNewRootName = malloc((Len + 2) * sizeof(WCHAR));
  237. if (wszNewRootName == NULL) {
  238. dwErr = ERROR_OUTOFMEMORY;
  239. goto Cleanup;
  240. }
  241. NetBiosName.Buffer = wszNewRootName;
  242. NetBiosName.MaximumLength = (USHORT)((Len + 2) * sizeof(WCHAR));
  243. NetBiosName.Length = 0;
  244. DnsName.Buffer = wszRootName;
  245. DnsName.Length = (USHORT)(Len * sizeof(WCHAR));
  246. DnsName.MaximumLength = DnsName.Length + sizeof(WCHAR);
  247. dwErr = RtlDnsHostNameToComputerName(
  248. &NetBiosName,
  249. &DnsName,
  250. FALSE);
  251. NetBiosName.Buffer[NetBiosName.Length/sizeof(WCHAR)] = L'\0';
  252. wcscat(wszNewRootName, L"$");
  253. //
  254. // Get SID representing root machine
  255. //
  256. Result = DfsFindSid(wszDcName,wszNewRootName, &Sid);
  257. if (Result != TRUE) {
  258. dwErr = ERROR_OBJECT_NOT_FOUND;
  259. goto Cleanup;
  260. }
  261. #if DBG
  262. if (DfsDebug)
  263. DbgPrint("Got SID for %ws\n", wszRootName);
  264. #endif
  265. //
  266. // Convert the machine SID to a string
  267. //
  268. Result = ConvertSidToStringSid(Sid, &wszStringSid);
  269. if (Result != TRUE) {
  270. dwErr = ERROR_OBJECT_NOT_FOUND;
  271. goto Cleanup;
  272. }
  273. #if DBG
  274. if (DfsDebug)
  275. DbgPrint("Sid=[%ws]\n", wszStringSid);
  276. #endif
  277. //
  278. // Now update the ACL list on the FtDfs object
  279. //
  280. dwErr = DfsRemoveAce(
  281. pldap,
  282. wszObjectName,
  283. wszStringSD,
  284. wszStringSid);
  285. Cleanup:
  286. if (wszNewRootName != NULL)
  287. free(wszNewRootName);
  288. if (wszStringSD != NULL)
  289. LocalFree(wszStringSD);
  290. if (wszStringSid != NULL)
  291. LocalFree(wszStringSid);
  292. if (Sid != NULL) {
  293. LocalFree(Sid);
  294. }
  295. #if DBG
  296. if (DfsDebug)
  297. DbgPrint("DfsRemoveMachineAce exit %d\n", dwErr);
  298. #endif
  299. return dwErr;
  300. }
  301. //+---------------------------------------------------------------------------
  302. //
  303. // Function: ReadDSObjSecDesc
  304. //
  305. // Synopsis: Reads the security descriptor from the specied object via
  306. // the open ldap connection
  307. //
  308. // Arguments: [pLDAP] -- The open LDAP connection
  309. // [pwszDSObj] -- The DSObject to get the security
  310. // descriptor for
  311. // [SeInfo] -- Parts of the security descriptor to
  312. // read.
  313. // [ppSD] -- Where the security descriptor is
  314. // returned
  315. // [pcSDSize -- Size of the security descriptor
  316. //
  317. // Returns: ERROR_SUCCESS -- The object is reachable
  318. // ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
  319. //
  320. // Notes: The returned security descriptor must be freed with LocalFree
  321. //
  322. //----------------------------------------------------------------------------
  323. DWORD
  324. ReadDSObjSecDesc(
  325. PLDAP pLDAP,
  326. PWSTR pwszObject,
  327. SECURITY_INFORMATION SeInfo,
  328. PSECURITY_DESCRIPTOR *ppSD,
  329. PULONG pcSDSize)
  330. {
  331. DWORD dwErr = ERROR_SUCCESS;
  332. PLDAPMessage pMsg = NULL;
  333. PWSTR rgAttribs[2];
  334. BYTE berValue[8];
  335. LDAPControl SeInfoControl =
  336. {
  337. LDAP_SERVER_SD_FLAGS_OID_W,
  338. {
  339. 5, (PCHAR)berValue
  340. },
  341. TRUE
  342. };
  343. PLDAPControl ServerControls[2] =
  344. {
  345. &SeInfoControl,
  346. NULL
  347. };
  348. #if DBG
  349. if (DfsDebug)
  350. DbgPrint("ReadDSObjSecDesc(%ws)\n", pwszObject);
  351. #endif
  352. berValue[0] = 0x30;
  353. berValue[1] = 0x03;
  354. berValue[2] = 0x02;
  355. berValue[3] = 0x01;
  356. berValue[4] = (BYTE)((ULONG)SeInfo & 0xF);
  357. rgAttribs[0] = ACTRL_SD_PROP_NAME;
  358. rgAttribs[1] = NULL;
  359. dwErr = ldap_search_ext_s(
  360. pLDAP,
  361. pwszObject,
  362. LDAP_SCOPE_BASE,
  363. L"(objectClass=*)",
  364. rgAttribs,
  365. 0,
  366. (PLDAPControl *)&ServerControls,
  367. NULL,
  368. NULL,
  369. 10000,
  370. &pMsg);
  371. dwErr = LdapMapErrorToWin32( dwErr );
  372. if(dwErr == ERROR_SUCCESS) {
  373. LDAPMessage *pEntry = NULL;
  374. PWSTR *ppwszValues = NULL;
  375. PLDAP_BERVAL *pSize = NULL;
  376. pEntry = ldap_first_entry(pLDAP, pMsg);
  377. if(pEntry != NULL) {
  378. //
  379. // Now, we'll have to get the values
  380. //
  381. ppwszValues = ldap_get_values(pLDAP, pEntry, rgAttribs[0]);
  382. if(ppwszValues != NULL) {
  383. pSize = ldap_get_values_len(pLDAP, pMsg, rgAttribs[0]);
  384. if(pSize != NULL) {
  385. //
  386. // Allocate the security descriptor to return
  387. //
  388. *ppSD = (PSECURITY_DESCRIPTOR)malloc((*pSize)->bv_len);
  389. if(*ppSD != NULL) {
  390. memcpy(*ppSD, (PBYTE)(*pSize)->bv_val, (*pSize)->bv_len);
  391. *pcSDSize = (*pSize)->bv_len;
  392. } else {
  393. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  394. }
  395. ldap_value_free_len(pSize);
  396. } else {
  397. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  398. }
  399. ldap_value_free(ppwszValues);
  400. } else {
  401. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  402. }
  403. } else {
  404. dwErr = LdapMapErrorToWin32( pLDAP->ld_errno );
  405. }
  406. }
  407. if (pMsg != NULL)
  408. ldap_msgfree(pMsg);
  409. #if DBG
  410. if (DfsDebug)
  411. DbgPrint("ReadDSObjSecDesc returning %d\n", dwErr);
  412. #endif
  413. return(dwErr);
  414. }
  415. //+---------------------------------------------------------------------------
  416. //
  417. // Function: DfsGetObjSecurity
  418. //
  419. // Synopsis: Gets the ACL list of an object in sddl stringized form
  420. //
  421. // Arguments: [pldap] -- The open LDAP connection
  422. // [wszObjectName] -- The fully-qualified name of the DS object
  423. // [pwszStringSD] -- Pointer to pointer to SD in string form (sddl)
  424. //
  425. // Returns: ERROR_SUCCESS -- The object is reachable
  426. //
  427. //----------------------------------------------------------------------------
  428. DWORD
  429. DfsGetObjSecurity(
  430. LDAP *pldap,
  431. LPWSTR pwszObjectName,
  432. LPWSTR *pwszStringSD)
  433. {
  434. DWORD dwErr;
  435. SECURITY_INFORMATION si;
  436. PSECURITY_DESCRIPTOR pSD = NULL;
  437. ULONG cSDSize;
  438. #if DBG
  439. if (DfsDebug)
  440. DbgPrint("DfsGetObjSecurity(%ws)\n", pwszObjectName);
  441. #endif
  442. si = DACL_SECURITY_INFORMATION;
  443. dwErr = ReadDSObjSecDesc(
  444. pldap,
  445. pwszObjectName,
  446. si,
  447. &pSD,
  448. &cSDSize);
  449. if (dwErr == ERROR_SUCCESS) {
  450. if (!ConvertSecurityDescriptorToStringSecurityDescriptor(
  451. pSD,
  452. SDDL_REVISION_1,
  453. DACL_SECURITY_INFORMATION,
  454. pwszStringSD,
  455. NULL)
  456. ) {
  457. dwErr = GetLastError();
  458. #if DBG
  459. if (DfsDebug)
  460. DbgPrint("ConvertSecurityDescriptorToStringSecurityDescriptor FAILED %d:\n", dwErr);
  461. #endif
  462. }
  463. }
  464. #if DBG
  465. if (DfsDebug)
  466. DbgPrint("DfsGetObjSecurity returning %d\n", dwErr);
  467. #endif
  468. return(dwErr);
  469. }
  470. //+---------------------------------------------------------------------------
  471. //
  472. // Function: DfsFindSid
  473. //
  474. // Synopsis: Gets the SID for a name
  475. //
  476. // [DcName] -- The DC to remote to
  477. // [Name] -- The Name of the object
  478. // [Sid] -- Pointer to pointer to returned SID, which must be freed
  479. // using LocalFree
  480. //
  481. // Returns: TRUE or FALSE
  482. //
  483. //----------------------------------------------------------------------------
  484. BOOL
  485. DfsFindSid(
  486. LPWSTR DcName,
  487. LPWSTR Name,
  488. PSID *Sid
  489. )
  490. {
  491. DWORD SidLength = 0;
  492. WCHAR DomainName[256];
  493. DWORD DomainNameLength = 256;
  494. SID_NAME_USE Use;
  495. BOOL Result;
  496. #if DBG
  497. if (DfsDebug)
  498. DbgPrint("DfsFindSid(%ws,%ws)\n", DcName,Name);
  499. #endif
  500. Result = LookupAccountName(
  501. DcName,
  502. Name,
  503. (PSID)NULL,
  504. &SidLength,
  505. DomainName,
  506. &DomainNameLength,
  507. &Use);
  508. if ( !Result && (GetLastError() == ERROR_INSUFFICIENT_BUFFER) ) {
  509. *Sid = LocalAlloc( 0, SidLength );
  510. Result = LookupAccountName(
  511. DcName,
  512. Name,
  513. *Sid,
  514. &SidLength,
  515. DomainName,
  516. &DomainNameLength,
  517. &Use);
  518. }
  519. #if DBG
  520. if (DfsDebug)
  521. DbgPrint("DfsFindSid returning %s\n", Result == TRUE ? "TRUE" : "FALSE");
  522. #endif
  523. return( Result );
  524. }
  525. //+---------------------------------------------------------------------------
  526. //
  527. // Function: DfsAddAce
  528. //
  529. // Synopsis: Adds a string ACE to a string version of an objects SD
  530. // object. This is a string manipulation routine.
  531. //
  532. // Arguments: [pldap] -- The open LDAP connection
  533. // [wszObjectName] -- The fully-qualified name of the DS object
  534. // [wszStringSD] -- String version of SD
  535. // [wszStringSid] -- String version of SID to add
  536. //
  537. // Returns: ERROR_SUCCESS -- ACE was added
  538. //
  539. //----------------------------------------------------------------------------
  540. DWORD
  541. DfsAddAce(
  542. LDAP *pldap,
  543. LPWSTR wszObjectName,
  544. LPWSTR wszStringSD,
  545. LPWSTR wszStringSid)
  546. {
  547. DWORD dwErr = ERROR_SUCCESS;
  548. LPWSTR wszNewStringSD = NULL;
  549. SECURITY_INFORMATION si;
  550. PSECURITY_DESCRIPTOR pSD = NULL;
  551. BOOL Result;
  552. ULONG Size = 0;
  553. ULONG cSDSize = 0;
  554. #if DBG
  555. if (DfsDebug)
  556. DbgPrint("DfsAddAce(%ws)\n", wszObjectName);
  557. #endif
  558. Size = wcslen(wszStringSD) * sizeof(WCHAR) +
  559. wcslen(wszAce) * sizeof(WCHAR) +
  560. wcslen(wszStringSid) * sizeof(WCHAR) +
  561. wcslen(L")") * sizeof(WCHAR) +
  562. sizeof(WCHAR);
  563. wszNewStringSD = malloc(Size);
  564. if (wszNewStringSD != NULL) {
  565. wcscpy(wszNewStringSD,wszStringSD);
  566. wcscat(wszNewStringSD,wszAce);
  567. wcscat(wszNewStringSD,wszStringSid);
  568. wcscat(wszNewStringSD,L")");
  569. #if DBG
  570. if (DfsDebug)
  571. DbgPrint("NewSD=[%ws]\n", wszNewStringSD);
  572. #endif
  573. Result = ConvertStringSecurityDescriptorToSecurityDescriptor(
  574. wszNewStringSD,
  575. SDDL_REVISION_1,
  576. &pSD,
  577. &cSDSize);
  578. if (Result == TRUE) {
  579. si = DACL_SECURITY_INFORMATION;
  580. dwErr = DfsStampSD(
  581. wszObjectName,
  582. cSDSize,
  583. si,
  584. pSD,
  585. pldap);
  586. LocalFree(pSD);
  587. } else {
  588. dwErr = GetLastError();
  589. #if DBG
  590. if (DfsDebug)
  591. DbgPrint("Convert returned %d\n", dwErr);
  592. #endif
  593. }
  594. free(wszNewStringSD);
  595. } else {
  596. dwErr = ERROR_OUTOFMEMORY;
  597. }
  598. #if DBG
  599. if (DfsDebug)
  600. DbgPrint("DfsAddAce returning %d\n", dwErr);
  601. #endif
  602. return(dwErr);
  603. }
  604. //+---------------------------------------------------------------------------
  605. //
  606. // Function: DfsRemoveAce
  607. //
  608. // Synopsis: Finds and removes a string ACE from the string SD of an
  609. // object. This is a string manipulation routine.
  610. //
  611. // Arguments: [pldap] -- The open LDAP connection
  612. // [wszObjectName] -- The fully-qualified name of the DS object
  613. // [wszStringSD] -- String version of SD
  614. // [wszStringSid] -- String version of SID to remove
  615. //
  616. // Returns: ERROR_SUCCESS -- ACE was removed or was not present
  617. //
  618. //----------------------------------------------------------------------------
  619. DWORD
  620. DfsRemoveAce(
  621. LDAP *pldap,
  622. LPWSTR wszObjectName,
  623. LPWSTR wszStringSD,
  624. LPWSTR wszStringSid)
  625. {
  626. DWORD dwErr = ERROR_SUCCESS;
  627. LPWSTR wszNewStringSD = NULL;
  628. SECURITY_INFORMATION si;
  629. PSECURITY_DESCRIPTOR pSD = NULL;
  630. BOOL Result;
  631. ULONG Size = 0;
  632. ULONG cSDSize = 0;
  633. BOOLEAN fCopying;
  634. ULONG s1, s2;
  635. #if DBG
  636. if (DfsDebug)
  637. DbgPrint("DfsRemoveAce(%ws)\n", wszObjectName);
  638. #endif
  639. Size = wcslen(wszStringSD) * sizeof(WCHAR) + sizeof(WCHAR);
  640. wszNewStringSD = malloc(Size);
  641. if (wszNewStringSD != NULL) {
  642. RtlZeroMemory(wszNewStringSD, Size);
  643. //
  644. // We have to find the ACEs containing this SID, and remove them.
  645. //
  646. fCopying = TRUE;
  647. for (s1 = s2 = 0; wszStringSD[s1]; s1++) {
  648. //
  649. // If this is the start of an ACE that has this SID, stop copying
  650. //
  651. if (wszStringSD[s1] == L'(' && DfsSidInAce(&wszStringSD[s1],wszStringSid) == TRUE) {
  652. fCopying = FALSE;
  653. continue;
  654. }
  655. //
  656. // If this is the end of SID we are not copying, start copying again
  657. //
  658. if (wszStringSD[s1] == L')' && fCopying == FALSE) {
  659. fCopying = TRUE;
  660. continue;
  661. }
  662. //
  663. // If we are copying, do so.
  664. //
  665. if (fCopying == TRUE)
  666. wszNewStringSD[s2++] = wszStringSD[s1];
  667. }
  668. #if DBG
  669. if (DfsDebug)
  670. DbgPrint("NewSD=[%ws]\n", wszNewStringSD);
  671. #endif
  672. Result = ConvertStringSecurityDescriptorToSecurityDescriptor(
  673. wszNewStringSD,
  674. SDDL_REVISION_1,
  675. &pSD,
  676. &cSDSize);
  677. if (Result == TRUE) {
  678. si = DACL_SECURITY_INFORMATION;
  679. dwErr = DfsStampSD(
  680. wszObjectName,
  681. cSDSize,
  682. si,
  683. pSD,
  684. pldap);
  685. LocalFree(pSD);
  686. } else {
  687. dwErr = GetLastError();
  688. #if DBG
  689. if (DfsDebug)
  690. DbgPrint("Convert returned %d\n", dwErr);
  691. #endif
  692. }
  693. free(wszNewStringSD);
  694. } else {
  695. dwErr = ERROR_OUTOFMEMORY;
  696. }
  697. #if DBG
  698. if (DfsDebug)
  699. DbgPrint("DfsRemoveAce returning %d\n", dwErr);
  700. #endif
  701. return(dwErr);
  702. }
  703. //+---------------------------------------------------------------------------
  704. //
  705. // Function: DfsSidInAce
  706. //
  707. // Synopsis: Scans an ACE to see if the string SID is in it.
  708. //
  709. // Arguments: [wszAce] -- ACE to scan
  710. // [wszStringSid] -- SID to scan for
  711. //
  712. // Returns: TRUE -- SID is in this ACE
  713. // FALSE -- SID is not in this ACE
  714. //
  715. //----------------------------------------------------------------------------
  716. BOOLEAN
  717. DfsSidInAce(
  718. LPWSTR wszAce,
  719. LPWSTR wszStringSid)
  720. {
  721. ULONG i;
  722. ULONG SidLen = wcslen(wszStringSid);
  723. ULONG AceLen;
  724. WCHAR Oldcp;
  725. for (AceLen = 0; wszAce[AceLen] && wszAce[AceLen] != L')'; AceLen++)
  726. /* NOTHING */;
  727. Oldcp = wszAce[AceLen];
  728. wszAce[AceLen] = L'\0';
  729. #if DBG
  730. if (DfsDebug)
  731. DbgPrint("DfsSidInAce(%ws),%ws)\n", wszAce, wszStringSid);
  732. #endif
  733. wszAce[AceLen] = Oldcp;
  734. if (SidLen > AceLen || wszAce[0] != L'(') {
  735. #if DBG
  736. if (DfsDebug)
  737. DbgPrint("DfsSidInAce returning FALSE(1)\n");
  738. #endif
  739. return FALSE;
  740. }
  741. for (i = 0; i <= (AceLen - SidLen); i++) {
  742. if (wszAce[i] == wszStringSid[0] && wcsncmp(&wszAce[i],wszStringSid,SidLen) == 0) {
  743. #if DBG
  744. if (DfsDebug)
  745. DbgPrint("DfsSidInAce returning TRUE\n");
  746. #endif
  747. return TRUE;
  748. }
  749. }
  750. #if DBG
  751. if (DfsDebug)
  752. DbgPrint("DfsSidInAce returning FALSE(2)\n");
  753. #endif
  754. return FALSE;
  755. }
  756. //+---------------------------------------------------------------------------
  757. //
  758. // Function: DfsStampSD
  759. //
  760. // Synopsis: Actually stamps the security descriptor on the object.
  761. //
  762. // Arguments: [pwszObject] -- The object to stamp the SD on
  763. // [cSDSize] -- The size of the security descriptor
  764. // [SeInfo] -- SecurityInformation about the security
  765. // descriptor
  766. // [pSD] -- The SD to stamp
  767. // [pLDAP] -- The LDAP connection to use
  768. //
  769. // Returns: ERROR_SUCCESS -- Success
  770. //
  771. //----------------------------------------------------------------------------
  772. DWORD
  773. DfsStampSD(
  774. PWSTR pwszObject,
  775. ULONG cSDSize,
  776. SECURITY_INFORMATION SeInfo,
  777. PSECURITY_DESCRIPTOR pSD,
  778. PLDAP pLDAP)
  779. {
  780. DWORD dwErr = ERROR_SUCCESS;
  781. PLDAPMod rgMods[2];
  782. PLDAP_BERVAL pBVals[2];
  783. LDAPMod Mod;
  784. LDAP_BERVAL BVal;
  785. BYTE ControlBuffer[ 5 ];
  786. LDAPControl SeInfoControl =
  787. {
  788. LDAP_SERVER_SD_FLAGS_OID_W,
  789. {
  790. 5, (PCHAR) &ControlBuffer
  791. },
  792. TRUE
  793. };
  794. PLDAPControl ServerControls[2] =
  795. {
  796. &SeInfoControl,
  797. NULL
  798. };
  799. #if DBG
  800. if (DfsDebug)
  801. DbgPrint("DfsStampSD(%ws,%d)\n", pwszObject, cSDSize);
  802. #endif
  803. ASSERT(*(PULONG)pSD > 0xF );
  804. ControlBuffer[0] = 0x30;
  805. ControlBuffer[1] = 0x3;
  806. ControlBuffer[2] = 0x02; // Denotes an integer;
  807. ControlBuffer[3] = 0x01; // Size
  808. ControlBuffer[4] = (BYTE)((ULONG)SeInfo & 0xF);
  809. ASSERT(IsValidSecurityDescriptor( pSD ) );
  810. rgMods[0] = &Mod;
  811. rgMods[1] = NULL;
  812. pBVals[0] = &BVal;
  813. pBVals[1] = NULL;
  814. BVal.bv_len = cSDSize;
  815. BVal.bv_val = (PCHAR)pSD;
  816. Mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
  817. Mod.mod_type = ACTRL_SD_PROP_NAME;
  818. Mod.mod_values = (PWSTR *)pBVals;
  819. //
  820. // Now, we'll do the write...
  821. //
  822. dwErr = ldap_modify_ext_s(pLDAP,
  823. pwszObject,
  824. rgMods,
  825. (PLDAPControl *)&ServerControls,
  826. NULL);
  827. dwErr = LdapMapErrorToWin32(dwErr);
  828. #if DBG
  829. if (DfsDebug)
  830. DbgPrint("DfsStampSD returning %d\n", dwErr);
  831. #endif
  832. return(dwErr);
  833. }