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.

3405 lines
86 KiB

  1. /*
  2. File adsi.cpp
  3. Com interaction with adsi
  4. Paul Mayfield, 4/14/98
  5. */
  6. #include "dsrights.h"
  7. #include "sddl.h"
  8. #include "mprapip.h"
  9. #include "dsgetdc.h"
  10. // Definition for convenience
  11. //
  12. #define DSR_ADS_RIGHT_GENERIC_READ (ADS_RIGHT_READ_CONTROL | \
  13. ADS_RIGHT_DS_LIST_OBJECT | \
  14. ADS_RIGHT_DS_READ_PROP | \
  15. ADS_RIGHT_ACTRL_DS_LIST )
  16. #define DSR_ADS_ACE_INHERITED (ADS_ACEFLAG_INHERIT_ONLY_ACE | \
  17. ADS_ACEFLAG_INHERIT_ACE)
  18. //
  19. // Describes an Access control entry
  20. //
  21. typedef struct _DSR_ACE_DESCRIPTOR
  22. {
  23. LONG dwAccessMask;
  24. LONG dwAceType;
  25. LONG dwAceFlags;
  26. LONG dwFlags;
  27. BSTR bstrTrustee;
  28. BSTR bstrObjectType;
  29. BSTR bstrInheritedObjectType;
  30. } DSR_ACE_DESCRIPTOR;
  31. //
  32. // Structure maps a domain object to the ACES that should be
  33. // added or removed from it in order to enable/disable NT4
  34. // ras servers in the domain
  35. //
  36. typedef struct _DSR_ACE_APPLICATION
  37. {
  38. IADs* pObject;
  39. DSR_ACE_DESCRIPTOR Ace;
  40. } DSR_ACE_APPLICATION;
  41. //
  42. // Parameters used to generate a DSR_ACE_APPLICATION
  43. //
  44. typedef struct _DSR_ACE_APPLICATION_DESC
  45. {
  46. PWCHAR pszObjectCN; // NULL means domain root
  47. PWCHAR pszObjectClass;
  48. DSR_ACE_DESCRIPTOR Ace;
  49. } DSR_ACE_APPLICATION_DESC;
  50. //
  51. // Structure contains the information needed to have
  52. // ACL's in the AD of a given domain adjusted such that
  53. // the various modes (MPR_DOMAIN_*) of access are granted.
  54. //
  55. typedef struct _DSR_DOMAIN_ACCESS_INFO
  56. {
  57. // The name of a DC in the target domain
  58. //
  59. PWCHAR pszDC;
  60. // Aces derived from the default user SD
  61. // These are added in all modes but never removed.
  62. //
  63. DSR_ACE_APPLICATION* pAcesUser;
  64. DWORD dwAceCountUser;
  65. // Aces for MPRFLAG_DOMAIN_NT4_SERVERS mode
  66. //
  67. DSR_ACE_APPLICATION* pAcesNt4;
  68. DWORD dwAceCountNt4;
  69. // Aces for MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS mode
  70. //
  71. DSR_ACE_APPLICATION* pAcesW2k;
  72. DWORD dwAceCountW2k;
  73. // Stored here for convenience, pointers
  74. // to common ds objects
  75. //
  76. IADs* pDomain;
  77. IADs* pRootDse;
  78. IADs* pUserClass;
  79. } DSR_DOMAIN_ACCESS_INFO;
  80. //
  81. // Strings used in DS queries
  82. //
  83. static const WCHAR pszLdapPrefix[] = L"LDAP://";
  84. static const WCHAR pszLdap[] = L"LDAP:";
  85. static const WCHAR pszCN[] = L"CN=";
  86. static const WCHAR pszGCPrefix[] = L"GC://";
  87. static const WCHAR pszGC[] = L"GC:";
  88. static const WCHAR pszRootDse[] = L"RootDSE";
  89. static const WCHAR pszSecurityDesc[] = L"ntSecurityDescriptor";
  90. static const WCHAR pszDefSecurityDesc[] = L"defaultSecurityDescriptor";
  91. static const WCHAR pszDn[] = L"distinguishedName";
  92. static const WCHAR pszSid[] = L"objectSid";
  93. static const WCHAR pszEveryone[] = L"S-1-1-0";
  94. static const WCHAR pszDefaultNamingContext[] = L"defaultNamingContext";
  95. static const WCHAR pszSchemaNamingCtx[] = L"schemaNamingContext";
  96. static const WCHAR pszBecomeSchemaMaster[] = L"becomeSchemaMaster";
  97. static const WCHAR pszUpdateSchemaCache[] = L"schemaUpdateNow";
  98. static const WCHAR pszRegValSchemaLock[] = L"Schema Update Allowed";
  99. static const WCHAR pszRegKeySchemaLock[]
  100. = L"System\\CurrentControlSet\\Services\\NTDS\\Parameters";
  101. static const WCHAR pszSystemClass[] = L"Container";
  102. static const WCHAR pszSystemCN[] = L"CN=System";
  103. static const WCHAR pszBuiltinClass[] = L"builtinDomain";
  104. static const WCHAR pszBuiltinCN[] = L"CN=Builtin";
  105. static const WCHAR pszSamSvrClass[] = L"samServer";
  106. static const WCHAR pszSamSvrCN[] = L"CN=Server,CN=System";
  107. static const WCHAR pszUserClass[] = L"classSchema";
  108. static const WCHAR pszUserCN[] = L"CN=user";
  109. static const WCHAR pszAccessChkClass[] = L"Container";
  110. static const WCHAR pszAccessChkCN[] =
  111. L"CN=RAS and IAS Servers Access Check,CN=System";
  112. static const WCHAR pszGuidUserParms[] =
  113. L"{BF967A6D-0DE6-11D0-A285-00AA003049E2}";
  114. static const WCHAR pszGuidUserClass[] =
  115. L"{BF967ABA-0DE6-11D0-A285-00aa003049E2}";
  116. //
  117. // This GUID is the property set of the following
  118. // attributes needed for w2k level access.
  119. //
  120. // Token-Groups
  121. // msNPAllowDialin
  122. // msNPCallingStationID
  123. // msRADIUSCallbackNumber
  124. // msRADIUSFramedIPAddress
  125. // msRADIUSFramedRoute
  126. // msRADIUSServiceType
  127. //
  128. static const WCHAR pszGuidRasPropSet1[] =
  129. L"{037088F8-0AE1-11D2-B422-00A0C968F939}";
  130. //
  131. // This GUID is the property set of the following
  132. // attributes needed for w2k level access
  133. //
  134. // User-Account-Control
  135. // Account-Expires
  136. //
  137. static const WCHAR pszGuidRasPropSet2[] =
  138. L"{4C164200-20C0-11D0-A768-00AA006E0529}";
  139. //
  140. // This GUID is the property of the following
  141. // attribute needed for w2k level access
  142. //
  143. // Logon-Hours
  144. //
  145. static const WCHAR pszGuidLogonHours[] =
  146. L"{BF9679AB-0DE6-11D0-A285-00AA003049E2}";
  147. //
  148. // This GUID is the value of the samAccountName
  149. // attribute needed for w2k level access.
  150. //
  151. // samAccountName
  152. //
  153. static const WCHAR pszGuidSamAccountName[] =
  154. L"{3E0ABFD0-126A-11D0-A060-00AA006C33ED}";
  155. // The optimal means for searching for a computer
  156. // in a domain is to lookup its sam account name which
  157. // is indexed. The optimal means for searching for a
  158. // group of a given sid is to lookup its SID which is indexed.
  159. //
  160. const WCHAR pszCompFilterFmt[] = L"(samaccountname=%s$)";
  161. const WCHAR pszGroupFilterFmt[] = L"(objectSid=%s)";
  162. const WCHAR pszUserClassFmt[] =
  163. L"(&(objectClass=user)(!(objectClass=computer)))";
  164. //
  165. // The table of aces to be applied for MPRFLAG_DOMAIN_NT4_SERVERS
  166. //
  167. DSR_ACE_APPLICATION_DESC g_pAcesNt4[] =
  168. {
  169. // Grant list options to everyone for the root domain
  170. // object
  171. //
  172. {
  173. NULL, // Object (NULL = root)
  174. NULL, // Object class
  175. {
  176. ADS_RIGHT_ACTRL_DS_LIST, // dwAccessMask
  177. ADS_ACETYPE_ACCESS_ALLOWED, // dwAceType
  178. 0, // dwAceFlags
  179. 0, // dwFlags
  180. (PWCHAR)pszEveryone, // bstrTrustee
  181. NULL, // bstrObjectType
  182. NULL // bstrInheritedObjectType
  183. }
  184. },
  185. // Grant list contents to everyone for the builtin
  186. // object
  187. //
  188. {
  189. (PWCHAR)pszBuiltinCN, // Object
  190. (PWCHAR)pszBuiltinClass, // Object class
  191. {
  192. ADS_RIGHT_ACTRL_DS_LIST, // dwAccessMask
  193. ADS_ACETYPE_ACCESS_ALLOWED, // dwAceType
  194. 0, // dwAceFlags
  195. 0, // dwFlags
  196. (PWCHAR)pszEveryone, // bstrTrustee
  197. NULL, // bstrObjectType
  198. NULL // bstrInheritedObjectType
  199. }
  200. },
  201. // Grant generic read to everyone on the sam server
  202. // object
  203. //
  204. {
  205. (PWCHAR)pszSamSvrCN, // Object
  206. (PWCHAR)pszSamSvrClass, // Object class
  207. {
  208. DSR_ADS_RIGHT_GENERIC_READ, // dwAccessMask
  209. ADS_ACETYPE_ACCESS_ALLOWED, // dwAceType
  210. 0, // dwAceFlags
  211. 0, // dwFlags
  212. (PWCHAR)pszEveryone, // bstrTrustee
  213. NULL, // bstrObjectType
  214. NULL // bstrInheritedObjectType
  215. }
  216. },
  217. // Allow everyone to read the userparms property of the
  218. // user class by enabling this inheritable ACE to the
  219. // root domain object
  220. {
  221. NULL, // Object (NULL = root)
  222. NULL, // Object class
  223. {
  224. ADS_RIGHT_DS_READ_PROP, // dwAccessMask
  225. ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, // dwAceType
  226. DSR_ADS_ACE_INHERITED, // dwAceFlags
  227. ADS_FLAG_OBJECT_TYPE_PRESENT |
  228. ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT, // dwFlags
  229. (PWCHAR)pszEveryone, // bstrTrustee
  230. (PWCHAR)pszGuidUserParms, // bstrObjectType
  231. (PWCHAR)pszGuidUserClass // bstrInheritedObjectType
  232. }
  233. }
  234. };
  235. //
  236. // The table of aces to be applied for
  237. // MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS
  238. //
  239. DSR_ACE_APPLICATION_DESC g_pAcesW2k[] =
  240. {
  241. // Grant list contents to Everyone for the System
  242. // container
  243. //
  244. {
  245. (PWCHAR)pszSystemCN, // Object
  246. (PWCHAR)pszSystemClass, // Object class
  247. {
  248. ADS_RIGHT_ACTRL_DS_LIST, // dwAccessMask
  249. ADS_ACETYPE_ACCESS_ALLOWED, // dwAceType
  250. 0, // dwAceFlags
  251. 0, // dwFlags
  252. (PWCHAR)pszEveryone, // bstrTrustee
  253. NULL, // bstrObjectType
  254. NULL // bstrInheritedObjectType
  255. }
  256. },
  257. // Grant generic read to Everyone for the 'RAS and IAS Servers
  258. // Access Check' container
  259. //
  260. {
  261. (PWCHAR)pszAccessChkCN, // Object
  262. (PWCHAR)pszAccessChkClass, // Object class
  263. {
  264. DSR_ADS_RIGHT_GENERIC_READ, // dwAccessMask
  265. ADS_ACETYPE_ACCESS_ALLOWED, // dwAceType
  266. 0, // dwAceFlags
  267. 0, // dwFlags
  268. (PWCHAR)pszEveryone, // bstrTrustee
  269. NULL, // bstrObjectType
  270. NULL // bstrInheritedObjectType
  271. }
  272. },
  273. // Users should expose their RAS properties
  274. //
  275. {
  276. NULL, // Object (NULL = root)
  277. NULL, // Object class
  278. {
  279. ADS_RIGHT_DS_READ_PROP, // dwAccessMask
  280. ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, // dwAceType
  281. DSR_ADS_ACE_INHERITED, // dwAceFlags
  282. ADS_FLAG_OBJECT_TYPE_PRESENT |
  283. ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT, // dwFlags
  284. (PWCHAR)pszEveryone, // bstrTrustee
  285. (PWCHAR)pszGuidRasPropSet1, // bstrObjectType
  286. (PWCHAR)pszGuidUserClass // bstrInheritedObjectType
  287. }
  288. },
  289. // Users should expose their RAS properties
  290. //
  291. {
  292. NULL, // Object (NULL = root)
  293. NULL, // Object class
  294. {
  295. ADS_RIGHT_DS_READ_PROP, // dwAccessMask
  296. ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, // dwAceType
  297. DSR_ADS_ACE_INHERITED, // dwAceFlags
  298. ADS_FLAG_OBJECT_TYPE_PRESENT |
  299. ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT, // dwFlags
  300. (PWCHAR)pszEveryone, // bstrTrustee
  301. (PWCHAR)pszGuidRasPropSet2, // bstrObjectType
  302. (PWCHAR)pszGuidUserClass // bstrInheritedObjectType
  303. }
  304. },
  305. // Users should expose their logon hours property
  306. //
  307. {
  308. NULL, // Object (NULL = root)
  309. NULL, // Object class
  310. {
  311. ADS_RIGHT_DS_READ_PROP, // dwAccessMask
  312. ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, // dwAceType
  313. DSR_ADS_ACE_INHERITED, // dwAceFlags
  314. ADS_FLAG_OBJECT_TYPE_PRESENT |
  315. ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT, // dwFlags
  316. (PWCHAR)pszEveryone, // bstrTrustee
  317. (PWCHAR)pszGuidLogonHours, // bstrObjectType
  318. (PWCHAR)pszGuidUserClass // bstrInheritedObjectType
  319. }
  320. },
  321. // Grant list contents to everything in the domain.
  322. //
  323. //{
  324. // NULL, // Object
  325. // NULL, // Object class
  326. // {
  327. // ADS_RIGHT_ACTRL_DS_LIST, // dwAccessMask
  328. // ADS_ACETYPE_ACCESS_ALLOWED, // dwAceType
  329. // DSR_ADS_ACE_INHERITED, // dwAceFlags
  330. // 0, // dwFlags
  331. // (PWCHAR)pszEveryone, // bstrTrustee
  332. // NULL, // bstrObjectType
  333. // NULL // bstrInheritedObjectType
  334. // }
  335. //},
  336. // Users should expose their samAccountName
  337. //
  338. {
  339. NULL, // Object (NULL = root)
  340. NULL, // Object class
  341. {
  342. ADS_RIGHT_DS_READ_PROP, // dwAccessMask
  343. ADS_ACETYPE_ACCESS_ALLOWED_OBJECT, // dwAceType
  344. DSR_ADS_ACE_INHERITED, // dwAceFlags
  345. ADS_FLAG_OBJECT_TYPE_PRESENT |
  346. ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT, // dwFlags
  347. (PWCHAR)pszEveryone, // bstrTrustee
  348. (PWCHAR)pszGuidSamAccountName, // bstrObjectType
  349. (PWCHAR)pszGuidUserClass // bstrInheritedObjectType
  350. }
  351. }
  352. };
  353. DWORD
  354. DsrAccessInfoCleanup(
  355. IN DSR_DOMAIN_ACCESS_INFO* pSecurityInfo);
  356. DWORD
  357. DsrAceDescClear(
  358. IN DSR_ACE_DESCRIPTOR* pParams);
  359. HRESULT
  360. DsrAceDescCopy(
  361. OUT DSR_ACE_DESCRIPTOR* pDst,
  362. IN DSR_ACE_DESCRIPTOR* pSrc);
  363. VOID
  364. DsrAceDescTrace(
  365. IN IADs* pIads,
  366. IN DSR_ACE_DESCRIPTOR* pA);
  367. HRESULT
  368. DsrAceAdd(
  369. IN PWCHAR pszDC,
  370. IN IADs* pIads,
  371. IN DSR_ACE_DESCRIPTOR * pAceParams);
  372. HRESULT
  373. DsrAceCreate(
  374. IN DSR_ACE_DESCRIPTOR * pAceParams,
  375. OUT IDispatch** ppAce);
  376. HRESULT
  377. DsrAceFind(
  378. IN PWCHAR pszDC,
  379. IN IADs* pObject,
  380. IN DSR_ACE_DESCRIPTOR* pAceParams,
  381. OUT VARIANT* pVarSD,
  382. OUT IADsSecurityDescriptor** ppSD,
  383. OUT IADsAccessControlList** ppAcl,
  384. OUT IDispatch** ppAce);
  385. HRESULT
  386. DsrAceFindInAcl(
  387. IN PWCHAR pszDC,
  388. IN IADsAccessControlList* pAcl,
  389. IN DSR_ACE_DESCRIPTOR* pAceDesc,
  390. OUT IDispatch** ppAce);
  391. HRESULT
  392. DsrAceRemove(
  393. IN PWCHAR pszDC,
  394. IN IADs* pIads,
  395. IN DSR_ACE_DESCRIPTOR * pAceParams);
  396. HRESULT
  397. DsrDomainQueryAccessEx(
  398. IN PWCHAR pszDomain,
  399. OUT LPDWORD lpdwAccessFlags,
  400. OUT DSR_DOMAIN_ACCESS_INFO** ppInfo);
  401. //
  402. // Allocates memory for use with dsr functions
  403. //
  404. PVOID DsrAlloc(DWORD dwSize, BOOL bZero) {
  405. return GlobalAlloc (bZero ? GPTR : GMEM_FIXED, dwSize);
  406. }
  407. //
  408. // Free memory used by dsr functions
  409. //
  410. DWORD DsrFree(PVOID pvBuf) {
  411. GlobalFree(pvBuf);
  412. return NO_ERROR;
  413. }
  414. //
  415. // Compares to optional strings
  416. //
  417. INT
  418. DsrStrCompare(
  419. IN BSTR bstrS1,
  420. IN BSTR bstrS2)
  421. {
  422. if ((!!bstrS1) != (!!bstrS2))
  423. {
  424. return -1;
  425. }
  426. if (bstrS1 == NULL)
  427. {
  428. return 0;
  429. }
  430. return lstrcmpi(bstrS1, bstrS2);
  431. }
  432. //
  433. // Adds or removes a substring from the given string
  434. //
  435. HRESULT
  436. DsrStrAddRemoveSubstring(
  437. IN BSTR bstrSrc,
  438. IN PWCHAR pszSubString,
  439. IN BOOL bAdd,
  440. OUT BSTR* pbstrResult)
  441. {
  442. HRESULT hr = S_OK;
  443. PWCHAR pszBuffer = NULL, pszStart = NULL, pszEnd = NULL;
  444. PWCHAR pszSrc, pszDst;
  445. DWORD dwSize = 0, dwLen = 0;
  446. // Find out if the sub string is already in the
  447. // string
  448. pszStart = wcsstr(bstrSrc, pszSubString);
  449. // The substring already exists in the string
  450. //
  451. if (pszStart)
  452. {
  453. // No need to add it since it's already there.
  454. if (bAdd)
  455. {
  456. *pbstrResult = SysAllocString(bstrSrc);
  457. }
  458. // Remove the substring
  459. else
  460. {
  461. dwLen = wcslen(pszSubString);
  462. pszEnd = pszStart + dwLen;
  463. dwSize = (DWORD)(pszStart - bstrSrc) + wcslen(pszEnd) + 1;
  464. dwSize *= sizeof(WCHAR);
  465. pszBuffer = (PWCHAR) DsrAlloc(dwSize, FALSE);
  466. if (pszBuffer == NULL)
  467. {
  468. return E_OUTOFMEMORY;
  469. }
  470. // Copy everything up to the substring
  471. //
  472. for (pszSrc = bstrSrc, pszDst = pszBuffer;
  473. pszSrc != pszStart;
  474. pszSrc++, pszDst++)
  475. {
  476. *pszDst = *pszSrc;
  477. }
  478. // Copy everything after the substring
  479. for (pszSrc = pszEnd; *pszSrc; pszSrc++, pszDst++)
  480. {
  481. *pszDst = *pszSrc;
  482. }
  483. // Null terminate
  484. *pszDst = L'\0';
  485. *pbstrResult = SysAllocString(pszBuffer);
  486. DsrFree(pszBuffer);
  487. }
  488. }
  489. // The substring does not already exist in the
  490. // string
  491. else
  492. {
  493. // Append the string
  494. //
  495. if (bAdd)
  496. {
  497. dwSize = wcslen(bstrSrc) + wcslen(pszSubString) + 1;
  498. dwSize *= sizeof(WCHAR);
  499. pszBuffer = (PWCHAR) DsrAlloc(dwSize, FALSE);
  500. if (pszBuffer == NULL)
  501. {
  502. return E_OUTOFMEMORY;
  503. }
  504. wcscpy(pszBuffer, bstrSrc);
  505. wcscat(pszBuffer, pszSubString);
  506. *pbstrResult = SysAllocString(pszBuffer);
  507. DsrFree(pszBuffer);
  508. }
  509. // Or nothing to do since the substring was
  510. // already removed
  511. else
  512. {
  513. *pbstrResult = SysAllocString(bstrSrc);
  514. }
  515. }
  516. return (*pbstrResult) ? S_OK : E_OUTOFMEMORY;
  517. }
  518. //
  519. // Converts a SID into a buffer
  520. //
  521. DWORD
  522. DsrStrFromSID(
  523. IN PSID pSid,
  524. OUT PWCHAR pszString,
  525. IN DWORD dwSize)
  526. {
  527. NTSTATUS nStatus = STATUS_SUCCESS;
  528. UNICODE_STRING UnicodeString;
  529. // Initialize the unicode string
  530. //
  531. RtlInitUnicodeString(&UnicodeString, NULL);
  532. do
  533. {
  534. // Convert the string
  535. //
  536. nStatus = RtlConvertSidToUnicodeString(
  537. &UnicodeString,
  538. pSid,
  539. TRUE);
  540. if (! NT_SUCCESS(nStatus))
  541. {
  542. break;
  543. }
  544. // Validate the result
  545. //
  546. if (UnicodeString.Buffer == NULL)
  547. {
  548. nStatus = ERROR_CAN_NOT_COMPLETE;
  549. break;
  550. }
  551. if (UnicodeString.Length > dwSize)
  552. {
  553. nStatus = STATUS_BUFFER_OVERFLOW;
  554. break;
  555. }
  556. // Copy the result
  557. //
  558. wcscpy(pszString, UnicodeString.Buffer);
  559. nStatus = STATUS_SUCCESS;
  560. } while (FALSE);
  561. // Cleanup
  562. {
  563. if (UnicodeString.Buffer != NULL)
  564. {
  565. RtlFreeUnicodeString(&UnicodeString);
  566. }
  567. }
  568. return RtlNtStatusToDosError(nStatus);
  569. }
  570. //
  571. // Generates an LDAP path based on a domain and a
  572. // distinguished name
  573. //
  574. // Form of value returned: LDAP://<domain or dc>/dn
  575. HRESULT
  576. DsrDomainGenLdapPath(
  577. IN PWCHAR pszDomain,
  578. IN PWCHAR pszDN,
  579. OUT PWCHAR* ppszObject)
  580. {
  581. DWORD dwSize;
  582. // Calculate the size needed
  583. //
  584. dwSize = (wcslen(pszLdapPrefix) + wcslen(pszDN) + 1) * sizeof(WCHAR);
  585. if (pszDomain)
  586. {
  587. dwSize += (wcslen(pszDomain) + 1) * sizeof(WCHAR); // +1 for '/'
  588. }
  589. // Allocate the return value
  590. //
  591. *ppszObject = (PWCHAR) DsrAlloc(dwSize, FALSE);
  592. if (*ppszObject == NULL)
  593. {
  594. return E_OUTOFMEMORY;
  595. }
  596. // Format the return value
  597. if (pszDomain == NULL)
  598. {
  599. wsprintfW(*ppszObject, L"%s%s", pszLdapPrefix, pszDN);
  600. }
  601. else
  602. {
  603. wsprintfW(*ppszObject, L"%s%s/%s", pszLdapPrefix, pszDomain, pszDN);
  604. }
  605. return S_OK;
  606. }
  607. //
  608. // Returns a reference to rootDse of the given
  609. // domain
  610. //
  611. HRESULT
  612. DsrDomainGetRootDse(
  613. IN PWCHAR pszDomain,
  614. OUT IADs** ppRootDse)
  615. {
  616. HRESULT hr = S_OK;
  617. PWCHAR pszPath = NULL;
  618. DWORD dwSize = 0;
  619. do
  620. {
  621. // Get the object path
  622. //
  623. hr = DsrDomainGenLdapPath(pszDomain, (PWCHAR)pszRootDse, &pszPath);
  624. DSR_BREAK_ON_FAILED_HR(hr);
  625. // Get RootDSE
  626. //
  627. hr = ADsGetObject(pszPath, IID_IADs, (VOID**)ppRootDse);
  628. DSR_BREAK_ON_FAILED_HR( hr );
  629. } while (FALSE);
  630. // Cleanup
  631. {
  632. DSR_FREE(pszPath);
  633. if (FAILED (hr))
  634. {
  635. DSR_RELEASE(*ppRootDse);
  636. }
  637. }
  638. return hr;
  639. }
  640. //
  641. // Returns a reference to the root domain object
  642. //
  643. HRESULT
  644. DsrDomainGetContainers(
  645. IN PWCHAR pszDomain,
  646. OUT IADs** ppRootDse,
  647. OUT IADsContainer** ppDomain,
  648. OUT IADsContainer** ppSchema)
  649. {
  650. PWCHAR pszDomainObj = NULL, pszSchemaObj = NULL;
  651. HRESULT hr = S_OK;
  652. DWORD dwSize = 0;
  653. VARIANT var;
  654. // Iniatialize
  655. //
  656. {
  657. *ppRootDse = NULL;
  658. *ppDomain = NULL;
  659. *ppSchema = NULL;
  660. VariantInit(&var);
  661. }
  662. do
  663. {
  664. // Get RootDSE
  665. //
  666. hr = DsrDomainGetRootDse(pszDomain, ppRootDse);
  667. DSR_BREAK_ON_FAILED_HR(hr);
  668. // Use RootDSE to figure out the name of the domain object
  669. // to query
  670. hr = (*ppRootDse)->Get((PWCHAR)pszDefaultNamingContext, &var);
  671. DSR_BREAK_ON_FAILED_HR( hr );
  672. // Compute the distinguished name of the root domain object
  673. //
  674. hr = DsrDomainGenLdapPath(pszDomain, V_BSTR(&var), &pszDomainObj);
  675. DSR_BREAK_ON_FAILED_HR(hr);
  676. // Use RootDSE to figure out the name of the schema context
  677. //
  678. VariantClear(&var);
  679. hr = (*ppRootDse)->Get((PWCHAR)pszSchemaNamingCtx, &var);
  680. DSR_BREAK_ON_FAILED_HR( hr );
  681. // Compute the distinguished name of the root schema object
  682. //
  683. hr = DsrDomainGenLdapPath(pszDomain, V_BSTR(&var), &pszSchemaObj);
  684. DSR_BREAK_ON_FAILED_HR(hr);
  685. // Get the objects
  686. //
  687. hr = ADsGetObject(pszDomainObj, IID_IADsContainer, (VOID**)ppDomain);
  688. DSR_BREAK_ON_FAILED_HR( hr );
  689. hr = ADsGetObject(pszSchemaObj, IID_IADsContainer, (VOID**)ppSchema);
  690. DSR_BREAK_ON_FAILED_HR( hr );
  691. } while (FALSE);
  692. // Cleanup
  693. //
  694. {
  695. if (FAILED( hr ))
  696. {
  697. DSR_RELEASE(*ppRootDse);
  698. DSR_RELEASE(*ppDomain);
  699. DSR_RELEASE(*ppSchema);
  700. *ppRootDse = NULL;
  701. *ppDomain = NULL;
  702. *ppSchema = NULL;
  703. }
  704. DSR_FREE(pszDomainObj);
  705. DSR_FREE(pszSchemaObj);
  706. VariantClear(&var);
  707. }
  708. return hr;
  709. }
  710. //
  711. // Initializes COM
  712. //
  713. HRESULT
  714. DsrComIntialize()
  715. {
  716. HRESULT hr;
  717. hr = CoInitializeEx (NULL, COINIT_APARTMENTTHREADED);
  718. if (hr == RPC_E_CHANGED_MODE)
  719. {
  720. hr = CoInitializeEx (NULL, COINIT_MULTITHREADED);
  721. }
  722. if ((hr != S_FALSE) && (FAILED(hr)))
  723. {
  724. return hr;
  725. }
  726. return NO_ERROR;
  727. }
  728. //
  729. // Unitializes COM
  730. //
  731. VOID
  732. DsrComUninitialize()
  733. {
  734. CoUninitialize();
  735. }
  736. //
  737. // Creates a SID based on the array of bytes
  738. // stored in a variant.
  739. //
  740. DWORD
  741. DsrSidInit (
  742. IN VARIANT * pVar,
  743. OUT PBYTE* ppbSid)
  744. {
  745. SAFEARRAY * pArray = V_ARRAY(pVar);
  746. DWORD dwSize, dwLow, dwHigh, i;
  747. HRESULT hr;
  748. BYTE* pbRet = NULL;
  749. VARIANT var;
  750. DsrTraceEx (0, "DsrSidInit: entered.");
  751. // Get the array of bytes
  752. i = 0;
  753. hr = SafeArrayGetElement(pArray, (LONG*)&i, (VOID*)&var);
  754. if (FAILED (hr))
  755. return hr;
  756. // Initialize the return buffer accordingly
  757. pArray = V_ARRAY(&var);
  758. dwSize = SafeArrayGetDim(pArray);
  759. hr = SafeArrayGetLBound(pArray, 1, (LONG*)&dwLow);
  760. if (FAILED (hr))
  761. return DsrTraceEx(hr, "DsrSidInit: %x unable to get lbound", hr);
  762. hr = SafeArrayGetUBound(pArray, 1, (LONG*)&dwHigh);
  763. if (FAILED (hr))
  764. return DsrTraceEx(hr, "DsrSidInit: %x unable to get ubound", hr);
  765. DsrTraceEx (
  766. 0,
  767. "DsrSidInit: Dim=%d, Low=%d, High=%d",
  768. dwSize,
  769. dwLow,
  770. dwHigh);
  771. // Allocate the sid
  772. if ((pbRet = (BYTE*)DsrAlloc((dwHigh - dwLow) + 2, TRUE)) == NULL) {
  773. return DsrTraceEx (
  774. ERROR_NOT_ENOUGH_MEMORY,
  775. "DsrSidInit: Unable to alloc");
  776. }
  777. // Copy in the bytes of the SID
  778. i = dwLow;
  779. while (TRUE) {
  780. hr = SafeArrayGetElement(pArray, (LONG*)&i, (VOID*)(&(pbRet[i])));
  781. if (FAILED (hr))
  782. break;
  783. i++;
  784. }
  785. DsrTraceEx(0, "DsrSidInit: copied %d bytes", i);
  786. *ppbSid = pbRet;
  787. {
  788. PUCHAR puSA;
  789. DsrTraceEx (0, "DsrSidInit: Sid Length: %d", GetLengthSid(pbRet));
  790. puSA = GetSidSubAuthorityCount(pbRet);
  791. if (puSA)
  792. DsrTraceEx (0, "DsrSidInit: Sid SA Count: %d", *puSA);
  793. }
  794. return NO_ERROR;
  795. }
  796. //
  797. // Generates the ascii equivalent (suitable for submission as part of
  798. // a query against the DS) of a SID based on a base SID and a sub authority
  799. // to be appeneded.
  800. //
  801. HRESULT
  802. DsrSidInitAscii(
  803. IN LPBYTE pBaseSid,
  804. IN DWORD dwSubAuthority,
  805. OUT PWCHAR* ppszSid)
  806. {
  807. DWORD dwLen, dwSidLen, i;
  808. WCHAR* pszRet = NULL;
  809. PUCHAR puCount;
  810. LPBYTE pByte;
  811. // Calculate the length of the returned buffer
  812. dwSidLen = GetLengthSid(pBaseSid);
  813. dwLen = (dwSidLen * 2) + sizeof(DWORD) + 1;
  814. dwLen *= sizeof (WCHAR);
  815. // we put '\' before each byte, so double the size
  816. dwLen *= 2;
  817. // Allocate the return buffer
  818. pszRet = (PWCHAR) DsrAlloc(dwLen, TRUE);
  819. if (pszRet == NULL)
  820. return E_OUTOFMEMORY;
  821. // Increment the sub authority count
  822. puCount = GetSidSubAuthorityCount(pBaseSid);
  823. *puCount = *puCount + 1;
  824. // Copy the bytes
  825. for (i = 0; i < dwSidLen; i++) {
  826. pszRet[i*3] = L'\\';
  827. wsprintfW(&(pszRet[i*3+1]), L"%02x", (DWORD)pBaseSid[i]);
  828. }
  829. // Append the bytes for the new sub authority
  830. pByte = (LPBYTE)&(dwSubAuthority);
  831. for (; i < dwSidLen + sizeof(DWORD); i++) {
  832. pszRet[i*3] = L'\\';
  833. wsprintfW(&(pszRet[i*3+1]), L"%02x", (DWORD)pByte[i-dwSidLen]);
  834. }
  835. // Decrement the sub authority count -- restoring the
  836. // base sid.
  837. *puCount = *puCount - 1;
  838. *ppszSid = pszRet;
  839. return NO_ERROR;
  840. }
  841. //
  842. // Searches given domain for a computer account
  843. // with the given name and returns its ADsPath
  844. // if found.
  845. //
  846. DWORD
  847. DsrFindDomainComputer (
  848. IN PWCHAR pszDomain,
  849. IN PWCHAR pszComputer,
  850. OUT PWCHAR* ppszADsPath)
  851. {
  852. HRESULT hr = S_OK;
  853. DWORD dwLen, dwSrchAttribCount;
  854. IDirectorySearch * pSearch = NULL;
  855. PWCHAR pszDomainPath = NULL, pszFilter = NULL;
  856. PWCHAR pszBase, pszPrefix;
  857. ADS_SEARCH_HANDLE hSearch = NULL;
  858. ADS_SEARCH_COLUMN adsColumn;
  859. PWCHAR ppszSrchAttribs[] =
  860. {
  861. (PWCHAR)pszDn,
  862. NULL
  863. };
  864. BOOL bSearchGC = FALSE;
  865. do {
  866. // Validate parameters
  867. if (!pszDomain || !pszComputer || !ppszADsPath) {
  868. hr = ERROR_INVALID_PARAMETER;
  869. break;
  870. }
  871. // Decide whether to search the GC or the domain
  872. // object
  873. if (bSearchGC) {
  874. pszBase = (PWCHAR)pszGC;
  875. pszPrefix = (PWCHAR)pszGCPrefix;
  876. }
  877. else {
  878. pszBase = (PWCHAR)pszLdap;
  879. pszPrefix = (PWCHAR)pszLdapPrefix;
  880. }
  881. // Allocate the domain path
  882. dwLen = (pszDomain) ? wcslen(pszDomain) : 0;
  883. dwLen += wcslen(pszPrefix) + 1;
  884. dwLen *= sizeof(WCHAR);
  885. pszDomainPath = (PWCHAR) DsrAlloc(dwLen, FALSE);
  886. if (pszDomainPath == NULL) {
  887. hr = ERROR_NOT_ENOUGH_MEMORY;
  888. break;
  889. }
  890. // Format the domain path
  891. if (pszDomain) {
  892. wcscpy(pszDomainPath, pszPrefix);
  893. wcscat(pszDomainPath, pszDomain);
  894. }
  895. else
  896. wcscpy(pszDomainPath, pszBase);
  897. // Get a reference to the object to search
  898. // (either domain object or GC)
  899. hr = ADsGetObject (
  900. pszDomainPath,
  901. IID_IDirectorySearch,
  902. (VOID**)&pSearch);
  903. if (FAILED (hr))
  904. break;
  905. // Prepare the search filter
  906. //
  907. dwLen = wcslen(pszCompFilterFmt) + wcslen(pszComputer) + 1;
  908. dwLen *= sizeof(WCHAR);
  909. pszFilter = (PWCHAR) DsrAlloc(dwLen, FALSE);
  910. if (pszFilter == NULL) {
  911. hr = ERROR_NOT_ENOUGH_MEMORY;
  912. break;
  913. }
  914. wsprintfW(pszFilter, pszCompFilterFmt, pszComputer);
  915. // Count the number of attributes we're searching
  916. // for
  917. if (ppszSrchAttribs == NULL)
  918. dwSrchAttribCount = (DWORD)-1;
  919. else {
  920. for (dwSrchAttribCount = 0;
  921. ppszSrchAttribs[dwSrchAttribCount];
  922. dwSrchAttribCount++);
  923. }
  924. // Search the DS
  925. hr = pSearch->ExecuteSearch(
  926. pszFilter,
  927. ppszSrchAttribs,
  928. dwSrchAttribCount,
  929. &hSearch);
  930. if (FAILED (hr))
  931. break;
  932. // Get the first result
  933. hr = pSearch->GetNextRow(hSearch);
  934. if (hr == S_ADS_NOMORE_ROWS) {
  935. hr = ERROR_NOT_FOUND;
  936. break;
  937. }
  938. // Get the attribute we're interested in
  939. hr = pSearch->GetColumn(hSearch, (PWCHAR)pszDn, &adsColumn);
  940. if (SUCCEEDED (hr)) {
  941. dwLen = wcslen(adsColumn.pADsValues[0].PrintableString) +
  942. wcslen(pszLdapPrefix) +
  943. 1;
  944. dwLen *= 2;
  945. *ppszADsPath = (PWCHAR) DsrAlloc(dwLen, FALSE);
  946. if (*ppszADsPath == NULL)
  947. {
  948. pSearch->FreeColumn(&adsColumn);
  949. hr = ERROR_NOT_ENOUGH_MEMORY;
  950. break;
  951. }
  952. wcscpy(*ppszADsPath, pszLdapPrefix);
  953. wcscat(*ppszADsPath, adsColumn.pADsValues[0].PrintableString);
  954. pSearch->FreeColumn (&adsColumn);
  955. hr = NO_ERROR;
  956. }
  957. } while (FALSE);
  958. // Cleanup
  959. {
  960. if (hSearch)
  961. pSearch->CloseSearchHandle(hSearch);
  962. DSR_FREE (pszDomainPath);
  963. DSR_FREE (pszFilter);
  964. DSR_RELEASE (pSearch);
  965. }
  966. return DSR_ERROR(hr);
  967. }
  968. //
  969. // Searches given domain for the well known
  970. // "RAS and IAS Servers" group and returns
  971. // its ADsPath if found.
  972. //
  973. DWORD
  974. DsrFindRasServersGroup (
  975. IN PWCHAR pszDomain,
  976. OUT PWCHAR* ppszADsPath)
  977. {
  978. HRESULT hr = S_OK;
  979. DWORD dwLen, dwSrchAttribCount, dwErr;
  980. IDirectorySearch * pSearch = NULL;
  981. IADs * pIads = NULL;
  982. PWCHAR pszDomainPath = NULL, pszFilter = NULL;
  983. PWCHAR pszBase, pszPrefix, pszGroupSid = NULL;
  984. ADS_SEARCH_HANDLE hSearch = NULL;
  985. ADS_SEARCH_COLUMN adsColumn;
  986. PWCHAR ppszSrchAttribs[] =
  987. {
  988. (PWCHAR)pszDn,
  989. NULL
  990. };
  991. BOOL bSearchGC = FALSE;
  992. VARIANT var;
  993. LPBYTE pDomainSid = NULL;
  994. BSTR bstrSid = NULL;
  995. do {
  996. // Validate parameters
  997. if (!pszDomain || !ppszADsPath) {
  998. hr = ERROR_INVALID_PARAMETER;
  999. break;
  1000. }
  1001. // Decide whether to search the GC or the domain
  1002. // object
  1003. if (bSearchGC) {
  1004. pszBase = (PWCHAR)pszGC;
  1005. pszPrefix = (PWCHAR)pszGCPrefix;
  1006. }
  1007. else {
  1008. pszBase = (PWCHAR)pszLdap;
  1009. pszPrefix = (PWCHAR)pszLdapPrefix;
  1010. }
  1011. // Allocate the domain path
  1012. dwLen = wcslen(pszDomain) + wcslen(pszPrefix) + 1;
  1013. dwLen *= sizeof(WCHAR);
  1014. pszDomainPath = (PWCHAR) DsrAlloc(dwLen, FALSE);
  1015. if (pszDomainPath == NULL) {
  1016. hr = ERROR_NOT_ENOUGH_MEMORY;
  1017. break;
  1018. }
  1019. // Format the domain path
  1020. wcscpy(pszDomainPath, pszPrefix);
  1021. wcscat(pszDomainPath, pszDomain);
  1022. // Get a reference to the object to search
  1023. // (either domain object or GC)
  1024. hr = ADsGetObject (
  1025. pszDomainPath,
  1026. IID_IDirectorySearch,
  1027. (VOID**)&pSearch);
  1028. if (FAILED (hr))
  1029. break;
  1030. // Get IADs reference to domain object
  1031. hr = pSearch->QueryInterface(IID_IADs, (VOID**)&pIads);
  1032. if (FAILED (hr))
  1033. break;
  1034. // Get the SID of the domain object
  1035. VariantInit(&var);
  1036. bstrSid = SysAllocString(pszSid);
  1037. if (bstrSid == NULL)
  1038. {
  1039. hr = ERROR_NOT_ENOUGH_MEMORY;
  1040. break;
  1041. }
  1042. hr = pIads->GetEx(bstrSid, &var);
  1043. if (FAILED (hr))
  1044. {
  1045. break;
  1046. }
  1047. dwErr = DsrSidInit(&var, &pDomainSid);
  1048. if (dwErr != NO_ERROR) {
  1049. hr = dwErr;
  1050. break;
  1051. }
  1052. VariantClear(&var);
  1053. // Prepare the ascii version of the "RAS and IAS Servers" SID
  1054. // for use in querying the DC
  1055. hr = DsrSidInitAscii(
  1056. pDomainSid,
  1057. DOMAIN_ALIAS_RID_RAS_SERVERS,
  1058. &pszGroupSid);
  1059. if (FAILED (hr))
  1060. break;
  1061. DsrTraceEx(0, "GroupSid = %ls", pszGroupSid);
  1062. // Prepare the search filter
  1063. //
  1064. dwLen = (wcslen(pszGroupFilterFmt) + wcslen(pszGroupSid) + 1);
  1065. dwLen *= sizeof(WCHAR);
  1066. pszFilter = (PWCHAR) DsrAlloc(dwLen, FALSE);
  1067. if (pszFilter == NULL) {
  1068. hr = ERROR_NOT_ENOUGH_MEMORY;
  1069. break;
  1070. }
  1071. wsprintfW(pszFilter, pszGroupFilterFmt, pszGroupSid);
  1072. // Count the number of attributes we're searching
  1073. // for
  1074. if (ppszSrchAttribs == NULL)
  1075. dwSrchAttribCount = (DWORD)-1;
  1076. else
  1077. {
  1078. for (dwSrchAttribCount = 0;
  1079. ppszSrchAttribs[dwSrchAttribCount];
  1080. dwSrchAttribCount++);
  1081. }
  1082. // Search the DS
  1083. hr = pSearch->ExecuteSearch(
  1084. pszFilter,
  1085. ppszSrchAttribs,
  1086. dwSrchAttribCount,
  1087. &hSearch);
  1088. if (FAILED (hr))
  1089. break;
  1090. // Get the first result
  1091. hr = pSearch->GetNextRow(hSearch);
  1092. if (hr == S_ADS_NOMORE_ROWS) {
  1093. hr = ERROR_NOT_FOUND;
  1094. break;
  1095. }
  1096. // Get the attribute we're interested in
  1097. hr = pSearch->GetColumn(hSearch, (PWCHAR)pszDn, &adsColumn);
  1098. if (SUCCEEDED (hr))
  1099. {
  1100. dwLen = wcslen(adsColumn.pADsValues[0].PrintableString) +
  1101. wcslen(pszLdapPrefix) +
  1102. 1;
  1103. dwLen *= sizeof(WCHAR);
  1104. *ppszADsPath = (PWCHAR) DsrAlloc(dwLen, FALSE);
  1105. if (*ppszADsPath == NULL)
  1106. {
  1107. pSearch->FreeColumn(&adsColumn);
  1108. hr = ERROR_NOT_ENOUGH_MEMORY;
  1109. break;
  1110. }
  1111. wsprintfW(
  1112. *ppszADsPath,
  1113. L"%s%s",
  1114. pszLdapPrefix,
  1115. adsColumn.pADsValues[0].PrintableString);
  1116. pSearch->FreeColumn(&adsColumn);
  1117. hr = NO_ERROR;
  1118. }
  1119. } while (FALSE);
  1120. // Cleanup
  1121. {
  1122. if (hSearch)
  1123. pSearch->CloseSearchHandle(hSearch);
  1124. DSR_FREE (pszDomainPath);
  1125. DSR_FREE (pszFilter);
  1126. DSR_FREE (pDomainSid);
  1127. DSR_FREE (pszGroupSid);
  1128. DSR_RELEASE (pSearch);
  1129. DSR_RELEASE (pIads);
  1130. if (bstrSid)
  1131. SysFreeString(bstrSid);
  1132. }
  1133. return DSR_ERROR(hr);
  1134. }
  1135. //
  1136. // Adds or removes a given object from a given group.
  1137. //
  1138. DWORD
  1139. DsrGroupAddRemoveMember(
  1140. IN PWCHAR pszGroupDN,
  1141. IN PWCHAR pszNewMemberDN,
  1142. IN BOOL bAdd)
  1143. {
  1144. VARIANT_BOOL vbIsMember = VARIANT_FALSE;
  1145. IADsGroup* pGroup = NULL;
  1146. HRESULT hr = S_OK;
  1147. DsrTraceEx (
  1148. 0,
  1149. "DsrGroupAddRemoveMember entered for [%S] [%S]",
  1150. pszGroupDN,
  1151. pszNewMemberDN);
  1152. do
  1153. {
  1154. // Get a reference to the group
  1155. hr = ADsGetObject (pszGroupDN, IID_IADsGroup, (VOID**)&pGroup);
  1156. if (FAILED (hr))
  1157. {
  1158. DsrTraceEx(
  1159. hr,
  1160. "DsrGroupAddRemoveMember: %x from ADsGetObject(%S)",
  1161. hr,
  1162. pszGroupDN);
  1163. break;
  1164. }
  1165. // Find out if the given new member is in the group
  1166. hr = pGroup->IsMember (pszNewMemberDN, &vbIsMember);
  1167. if (FAILED (hr))
  1168. {
  1169. DsrTraceEx (
  1170. hr,
  1171. "DsrGroupAddRemoveMember: %x from IsMember\n",
  1172. hr);
  1173. break;
  1174. }
  1175. // Add the object to the group and flush the cache
  1176. if (bAdd)
  1177. {
  1178. if (vbIsMember == VARIANT_FALSE)
  1179. {
  1180. hr = pGroup->Add (pszNewMemberDN);
  1181. }
  1182. }
  1183. else
  1184. {
  1185. if (vbIsMember == VARIANT_TRUE)
  1186. {
  1187. hr = pGroup->Remove (pszNewMemberDN);
  1188. }
  1189. }
  1190. // If the new member is already in the group, the error code
  1191. // is ERROR_DS_CONSTRAINT_VIOLATION. I suspect this may change.
  1192. //
  1193. if (hr == ERROR_DS_CONSTRAINT_VIOLATION)
  1194. {
  1195. hr = ERROR_ALREADY_EXISTS;
  1196. break;
  1197. }
  1198. if (FAILED (hr))
  1199. {
  1200. DsrTraceEx(
  1201. hr,
  1202. "DsrGroupAddRemoveMember: %x from Add/Remove",
  1203. hr);
  1204. break;
  1205. }
  1206. } while (FALSE);
  1207. // Cleanup
  1208. {
  1209. DSR_RELEASE(pGroup);
  1210. }
  1211. return DSR_ERROR(hr);
  1212. }
  1213. //
  1214. // Returns whether the given object is a member of
  1215. // the given group.
  1216. //
  1217. DWORD
  1218. DsrGroupIsMember(
  1219. IN PWCHAR pszGroupDN,
  1220. IN PWCHAR pszObjectDN,
  1221. OUT PBOOL pbIsMember)
  1222. {
  1223. IADsGroup * pGroup = NULL;
  1224. HRESULT hr = S_OK;
  1225. VARIANT_BOOL vbIsMember = VARIANT_FALSE;
  1226. DsrTraceEx (
  1227. 0,
  1228. "DsrGroupIsMember: entered [%S] [%S].",
  1229. pszGroupDN,
  1230. pszObjectDN);
  1231. do
  1232. {
  1233. // Get a reference to the group
  1234. hr = ADsGetObject (pszGroupDN, IID_IADsGroup, (VOID**)&pGroup);
  1235. if (FAILED (hr))
  1236. {
  1237. DsrTraceEx (
  1238. hr,
  1239. "DsrGroupIsMember: %x returned when opening %S",
  1240. hr,
  1241. pszGroupDN);
  1242. *pbIsMember = FALSE;
  1243. hr = NO_ERROR;
  1244. break;
  1245. }
  1246. // Find out if the object is a member
  1247. hr = pGroup->IsMember (pszObjectDN, &vbIsMember);
  1248. if (FAILED (hr))
  1249. {
  1250. DsrTraceEx (hr, "DsrGroupIsMember: %x from IsMember\n", hr);
  1251. break;
  1252. }
  1253. *pbIsMember = (vbIsMember == VARIANT_TRUE) ? TRUE : FALSE;
  1254. } while (FALSE);
  1255. // Cleanup
  1256. {
  1257. DSR_RELEASE(pGroup);
  1258. }
  1259. return DSR_ERROR(hr);
  1260. }
  1261. //
  1262. // Applies the aces in the given access settings to the
  1263. // appropriate domain.
  1264. //
  1265. HRESULT
  1266. DsrAceAppAdd(
  1267. IN PWCHAR pszDC,
  1268. IN DSR_ACE_APPLICATION* pAces,
  1269. IN DWORD dwCount)
  1270. {
  1271. HRESULT hr = S_OK;
  1272. DSR_ACE_APPLICATION* pAceApp = NULL;
  1273. DWORD i;
  1274. // Output the aces that we'll set
  1275. //
  1276. DsrTraceEx(0, "Adding %d aces...", dwCount);
  1277. do
  1278. {
  1279. // Add the ACES to the domain objects
  1280. //
  1281. for (i = 0, pAceApp = pAces; i < dwCount; i++, pAceApp++)
  1282. {
  1283. hr = DsrAceAdd(
  1284. pszDC,
  1285. pAceApp->pObject,
  1286. &(pAceApp->Ace));
  1287. DSR_BREAK_ON_FAILED_HR( hr );
  1288. }
  1289. DSR_BREAK_ON_FAILED_HR( hr );
  1290. // Commit the ACE's to the domain objects.
  1291. //
  1292. for (i = 0, pAceApp = pAces; i < dwCount; i++, pAceApp++)
  1293. {
  1294. hr = pAceApp->pObject->SetInfo();
  1295. DSR_BREAK_ON_FAILED_HR( hr );
  1296. }
  1297. DSR_BREAK_ON_FAILED_HR( hr );
  1298. } while (FALSE);
  1299. // Cleanup
  1300. {
  1301. }
  1302. return hr;
  1303. }
  1304. //
  1305. // Releases the resources held by an ace application
  1306. //
  1307. HRESULT
  1308. DsrAceAppCleanup(
  1309. IN DSR_ACE_APPLICATION* pAces,
  1310. IN DWORD dwCount)
  1311. {
  1312. DSR_ACE_APPLICATION* pAceApp = NULL;
  1313. DWORD i;
  1314. if (pAces)
  1315. {
  1316. for (i = 0, pAceApp = pAces; i < dwCount; i++, pAceApp++)
  1317. {
  1318. DSR_RELEASE(pAceApp->pObject);
  1319. DsrAceDescClear(&(pAceApp->Ace));
  1320. }
  1321. DSR_FREE(pAces);
  1322. }
  1323. return NO_ERROR;
  1324. }
  1325. //
  1326. // Generates a list of ace applications based on a list
  1327. // of ace application descriptions
  1328. //
  1329. HRESULT
  1330. DsrAceAppFromAppDesc(
  1331. IN DSR_ACE_APPLICATION_DESC* pDesc,
  1332. IN DWORD dwCount,
  1333. IN IADsContainer* pContainer,
  1334. IN IADs* pDefault,
  1335. OUT DSR_ACE_APPLICATION** ppAceApp,
  1336. OUT LPDWORD lpdwCount)
  1337. {
  1338. DSR_ACE_APPLICATION* pAceApp = NULL, *pCurApp = NULL;
  1339. DSR_ACE_APPLICATION_DESC* pAceAppDesc = NULL;
  1340. IDispatch* pDispatch = NULL;
  1341. HRESULT hr = S_OK;
  1342. DWORD i;
  1343. do
  1344. {
  1345. // Allocate and zero the ACE list
  1346. //
  1347. pAceApp = (DSR_ACE_APPLICATION*)
  1348. DsrAlloc(sizeof(DSR_ACE_APPLICATION) * dwCount, TRUE);
  1349. if (pAceApp == NULL)
  1350. {
  1351. DSR_BREAK_ON_FAILED_HR(hr = E_OUTOFMEMORY);
  1352. }
  1353. // Set up the ACE applications
  1354. //
  1355. for (i = 0, pAceAppDesc = pDesc, pCurApp = pAceApp;
  1356. i < dwCount;
  1357. i++, pAceAppDesc++, pCurApp++)
  1358. {
  1359. // Get the desired object in the DS
  1360. //
  1361. if (pAceAppDesc->pszObjectCN)
  1362. {
  1363. hr = pContainer->GetObject(
  1364. pAceAppDesc->pszObjectClass,
  1365. pAceAppDesc->pszObjectCN,
  1366. &pDispatch);
  1367. DSR_BREAK_ON_FAILED_HR( hr );
  1368. hr = pDispatch->QueryInterface(
  1369. IID_IADs,
  1370. (VOID**)&(pCurApp->pObject));
  1371. DSR_BREAK_ON_FAILED_HR( hr );
  1372. pDispatch->Release();
  1373. pDispatch = NULL;
  1374. }
  1375. else
  1376. {
  1377. pCurApp->pObject = pDefault;
  1378. pCurApp->pObject->AddRef();
  1379. }
  1380. // Copy over the ACE information
  1381. hr = DsrAceDescCopy(
  1382. &(pCurApp->Ace),
  1383. &(pAceAppDesc->Ace));
  1384. DSR_BREAK_ON_FAILED_HR( hr );
  1385. }
  1386. DSR_BREAK_ON_FAILED_HR( hr );
  1387. // Assign the return values
  1388. *ppAceApp = pAceApp;
  1389. *lpdwCount = dwCount;
  1390. } while (FALSE);
  1391. // Cleanup
  1392. {
  1393. if (FAILED(hr))
  1394. {
  1395. DsrAceAppCleanup(pAceApp, i);
  1396. }
  1397. }
  1398. return hr;
  1399. }
  1400. //
  1401. // Discovers whether a set of aces is present in the given
  1402. // domain.
  1403. //
  1404. HRESULT
  1405. DsrAceAppQueryPresence(
  1406. IN PWCHAR pszDC,
  1407. IN DSR_ACE_APPLICATION* pAces,
  1408. IN DWORD dwCount,
  1409. OUT PBOOL pbPresent)
  1410. {
  1411. DSR_ACE_APPLICATION* pAceApp = NULL;
  1412. IADsSecurityDescriptor* pSD = NULL;
  1413. IADsAccessControlList* pAcl = NULL;
  1414. IDispatch* pAce = NULL;
  1415. VARIANT varSD;
  1416. HRESULT hr = S_OK;
  1417. BOOL bEnabled = FALSE, bOk = TRUE;
  1418. DWORD i;
  1419. do
  1420. {
  1421. // Initialize
  1422. *pbPresent = FALSE;
  1423. VariantInit(&varSD);
  1424. // Find out if the ACES are set
  1425. //
  1426. for (i = 0, pAceApp = pAces; i < dwCount; i++, pAceApp++)
  1427. {
  1428. hr = DsrAceFind(
  1429. pszDC,
  1430. pAceApp->pObject,
  1431. &(pAceApp->Ace),
  1432. &varSD,
  1433. &pSD,
  1434. &pAcl,
  1435. &pAce);
  1436. DSR_BREAK_ON_FAILED_HR( hr );
  1437. // We're enabled so long as we don't find
  1438. // a missing ACE
  1439. //
  1440. bOk = (pAce != NULL);
  1441. // Cleanup
  1442. //
  1443. DSR_RELEASE( pAce );
  1444. DSR_RELEASE( pAcl );
  1445. DSR_RELEASE( pSD );
  1446. VariantClear(&varSD);
  1447. pAce = NULL;
  1448. pAcl = NULL;
  1449. pSD = NULL;
  1450. // Break if we find out we're not enabled
  1451. //
  1452. if (bOk == FALSE)
  1453. {
  1454. break;
  1455. }
  1456. }
  1457. DSR_BREAK_ON_FAILED_HR( hr );
  1458. *pbPresent = bOk;
  1459. } while (FALSE);
  1460. // Cleanup
  1461. {
  1462. }
  1463. return hr;
  1464. }
  1465. //
  1466. // Applies the aces in the given access settings to the
  1467. // appropriate domain.
  1468. //
  1469. HRESULT
  1470. DsrAceAppRemove(
  1471. IN PWCHAR pszDC,
  1472. IN DSR_ACE_APPLICATION* pAces,
  1473. IN DWORD dwCount)
  1474. {
  1475. HRESULT hr = S_OK;
  1476. DSR_ACE_APPLICATION* pAceApp = NULL;
  1477. DWORD i;
  1478. // Output the aces that we'll set
  1479. //
  1480. DsrTraceEx(0, "Removing %d aces...", dwCount);
  1481. do
  1482. {
  1483. // Add/Del the ACES to the domain objects
  1484. //
  1485. for (i = 0, pAceApp = pAces; i < dwCount; i++, pAceApp++)
  1486. {
  1487. hr = DsrAceRemove(
  1488. pszDC,
  1489. pAceApp->pObject,
  1490. &(pAceApp->Ace));
  1491. DSR_BREAK_ON_FAILED_HR( hr );
  1492. }
  1493. DSR_BREAK_ON_FAILED_HR( hr );
  1494. // Commit the ACE's to the domain objects.
  1495. //
  1496. for (i = 0, pAceApp = pAces; i < dwCount; i++, pAceApp++)
  1497. {
  1498. hr = pAceApp->pObject->SetInfo();
  1499. DSR_BREAK_ON_FAILED_HR( hr );
  1500. }
  1501. DSR_BREAK_ON_FAILED_HR( hr );
  1502. } while (FALSE);
  1503. // Cleanup
  1504. {
  1505. }
  1506. return hr;
  1507. }
  1508. //
  1509. // Clear the dsr ace parameters
  1510. //
  1511. DWORD
  1512. DsrAceDescClear(
  1513. IN DSR_ACE_DESCRIPTOR* pParams)
  1514. {
  1515. if (pParams)
  1516. {
  1517. if (pParams->bstrTrustee)
  1518. {
  1519. SysFreeString(pParams->bstrTrustee);
  1520. }
  1521. if (pParams->bstrObjectType)
  1522. {
  1523. SysFreeString(pParams->bstrObjectType);
  1524. }
  1525. if (pParams->bstrInheritedObjectType)
  1526. {
  1527. SysFreeString(pParams->bstrInheritedObjectType);
  1528. }
  1529. ZeroMemory(pParams, sizeof(DSR_ACE_DESCRIPTOR));
  1530. }
  1531. return NO_ERROR;
  1532. }
  1533. //
  1534. // Returns 0 if ACE descriptors are describing the same ACE.
  1535. // FALSE, otherwise.
  1536. //
  1537. HRESULT
  1538. DsrAceDescCompare(
  1539. IN DSR_ACE_DESCRIPTOR* pAce1,
  1540. IN DSR_ACE_DESCRIPTOR* pAce2)
  1541. {
  1542. DWORD dw1, dw2;
  1543. // Compare the non-string fields so that we can rule things
  1544. // out w/o string compares if possible
  1545. //
  1546. if (
  1547. (pAce1->dwAccessMask != pAce2->dwAccessMask) ||
  1548. (pAce1->dwAceFlags != pAce2->dwAceFlags) ||
  1549. (pAce1->dwAceType != pAce2->dwAceType) ||
  1550. (pAce1->dwFlags != pAce2->dwFlags)
  1551. )
  1552. {
  1553. return 1;
  1554. }
  1555. // Compare the strings
  1556. //
  1557. if ((DsrStrCompare(pAce1->bstrTrustee, pAce2->bstrTrustee)) ||
  1558. (DsrStrCompare(pAce1->bstrObjectType, pAce2->bstrObjectType)) ||
  1559. (DsrStrCompare(pAce1->bstrInheritedObjectType,
  1560. pAce2->bstrInheritedObjectType))
  1561. )
  1562. {
  1563. return 1;
  1564. }
  1565. // Return success
  1566. //
  1567. return 0;
  1568. }
  1569. //
  1570. // Copy over the ACE information
  1571. //
  1572. HRESULT
  1573. DsrAceDescCopy(
  1574. OUT DSR_ACE_DESCRIPTOR* pDst,
  1575. IN DSR_ACE_DESCRIPTOR* pSrc)
  1576. {
  1577. HRESULT hr = S_OK;
  1578. do
  1579. {
  1580. // Initialize the ACE parameters
  1581. *pDst = *pSrc;
  1582. if (pSrc->bstrTrustee)
  1583. {
  1584. pDst->bstrTrustee =
  1585. SysAllocString(pSrc->bstrTrustee);
  1586. if (pDst->bstrTrustee == NULL)
  1587. {
  1588. DSR_BREAK_ON_FAILED_HR(hr = E_OUTOFMEMORY);
  1589. }
  1590. }
  1591. if (pSrc->bstrObjectType)
  1592. {
  1593. pDst->bstrObjectType =
  1594. SysAllocString(pSrc->bstrObjectType);
  1595. if (pDst->bstrObjectType == NULL)
  1596. {
  1597. DSR_BREAK_ON_FAILED_HR(hr = E_OUTOFMEMORY);
  1598. }
  1599. }
  1600. if (pSrc->bstrInheritedObjectType)
  1601. {
  1602. pDst->bstrInheritedObjectType =
  1603. SysAllocString(pSrc->bstrInheritedObjectType);
  1604. if (pDst->bstrInheritedObjectType == NULL)
  1605. {
  1606. DSR_BREAK_ON_FAILED_HR(hr = E_OUTOFMEMORY);
  1607. }
  1608. }
  1609. } while (FALSE);
  1610. // Cleanup
  1611. {
  1612. if (FAILED( hr ))
  1613. {
  1614. if (pDst->bstrTrustee)
  1615. {
  1616. SysFreeString(pDst->bstrTrustee);
  1617. }
  1618. if (pDst->bstrObjectType)
  1619. {
  1620. SysFreeString(pDst->bstrObjectType);
  1621. }
  1622. if (pDst->bstrInheritedObjectType)
  1623. {
  1624. SysFreeString(pDst->bstrInheritedObjectType);
  1625. }
  1626. }
  1627. }
  1628. return hr;
  1629. }
  1630. //
  1631. // Populates the given ACE descriptor with the values from
  1632. // the given ACE.
  1633. //
  1634. HRESULT
  1635. DsrAceDescFromIadsAce(
  1636. IN PWCHAR pszDC,
  1637. IN IADsAccessControlEntry* pAce,
  1638. IN DSR_ACE_DESCRIPTOR* pAceParams)
  1639. {
  1640. HRESULT hr = S_OK;
  1641. BSTR bstrTrustee = NULL;
  1642. WCHAR pszSid[1024], pszDomain[1024];
  1643. BYTE pbSid[1024];
  1644. DWORD dwSidSize, dwDomainSize;
  1645. BOOL bOk;
  1646. SID_NAME_USE SidNameUse;
  1647. do
  1648. {
  1649. hr = pAce->get_AccessMask(&(pAceParams->dwAccessMask));
  1650. DSR_BREAK_ON_FAILED_HR( hr );
  1651. hr = pAce->get_AceType(&(pAceParams->dwAceType));
  1652. DSR_BREAK_ON_FAILED_HR( hr );
  1653. hr = pAce->get_AceFlags(&(pAceParams->dwAceFlags));
  1654. DSR_BREAK_ON_FAILED_HR( hr );
  1655. hr = pAce->get_Flags(&(pAceParams->dwFlags));
  1656. DSR_BREAK_ON_FAILED_HR( hr );
  1657. hr = pAce->get_ObjectType(&(pAceParams->bstrObjectType));
  1658. DSR_BREAK_ON_FAILED_HR( hr );
  1659. hr = pAce->get_InheritedObjectType(
  1660. &(pAceParams->bstrInheritedObjectType));
  1661. DSR_BREAK_ON_FAILED_HR( hr );
  1662. hr = pAce->get_Trustee(&bstrTrustee);
  1663. DSR_BREAK_ON_FAILED_HR( hr );
  1664. // Get the SID of the trustee
  1665. //
  1666. dwSidSize = sizeof(pbSid);
  1667. dwDomainSize = sizeof(pszDomain) / sizeof(WCHAR);
  1668. bOk = LookupAccountName(
  1669. pszDC,
  1670. bstrTrustee,
  1671. (PSID)pbSid,
  1672. &dwSidSize,
  1673. pszDomain,
  1674. &dwDomainSize,
  1675. &SidNameUse);
  1676. if (bOk == FALSE)
  1677. {
  1678. hr = GetLastError();
  1679. break;
  1680. }
  1681. // Convert the sid to a string
  1682. //
  1683. hr = DsrStrFromSID((PSID)pbSid, pszSid, sizeof(pszSid));
  1684. if (hr != NO_ERROR)
  1685. {
  1686. break;
  1687. }
  1688. // Create the trustee accordingly
  1689. //
  1690. pAceParams->bstrTrustee = SysAllocString(pszSid);
  1691. if (pAceParams->bstrTrustee == NULL)
  1692. {
  1693. hr = E_OUTOFMEMORY;
  1694. break;
  1695. }
  1696. } while (FALSE);
  1697. // Cleanup
  1698. {
  1699. if (bstrTrustee)
  1700. {
  1701. SysFreeString(bstrTrustee);
  1702. }
  1703. if (FAILED(hr))
  1704. {
  1705. DsrAceDescClear(pAceParams);
  1706. }
  1707. }
  1708. return hr;
  1709. }
  1710. //
  1711. // Initialize an ace descriptor from a W2K Ace
  1712. //
  1713. HRESULT
  1714. DsrAceDescFromW2KAce(
  1715. IN PWCHAR pszDC,
  1716. IN PVOID pvAce,
  1717. OUT DSR_ACE_DESCRIPTOR* pAceDesc)
  1718. {
  1719. PACCESS_ALLOWED_ACE pAaAce = NULL;
  1720. PACCESS_DENIED_ACE pAdAce = NULL;
  1721. PACCESS_ALLOWED_OBJECT_ACE pAaoAce = NULL;
  1722. PACCESS_DENIED_OBJECT_ACE pAdoAce = NULL;
  1723. PSID pSID = NULL;
  1724. DWORD dwFlags = 0, dwNameSize, dwDomainSize, dwAccessMask;
  1725. BYTE bAceType, bAceFlags;
  1726. SID_NAME_USE SidNameUse;
  1727. WCHAR pszGuid[64], pszName[512], pszDomain[512], pszTrustee[1024];
  1728. HRESULT hr = S_OK;
  1729. GUID* pgObj = NULL, *pgInhObj = NULL;
  1730. BOOL bOk = TRUE;
  1731. // Read in the ace values
  1732. //
  1733. bAceType = ((ACE_HEADER *)pvAce)->AceType;
  1734. bAceFlags = ((ACE_HEADER *)pvAce)->AceFlags;
  1735. switch (bAceType)
  1736. {
  1737. case ACCESS_ALLOWED_ACE_TYPE:
  1738. pAaAce = (PACCESS_ALLOWED_ACE)pvAce;
  1739. dwAccessMask = pAaAce->Mask;
  1740. pSID = (PSID)&(pAaAce->SidStart);
  1741. break;
  1742. case ACCESS_DENIED_ACE_TYPE:
  1743. pAdAce = (PACCESS_DENIED_ACE)pvAce;
  1744. dwAccessMask = pAdAce->Mask;
  1745. pSID = (PSID)&(pAdAce->SidStart);
  1746. break;
  1747. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  1748. pAaoAce = (PACCESS_ALLOWED_OBJECT_ACE)pvAce;
  1749. dwAccessMask = pAaoAce->Mask;
  1750. dwFlags = pAaoAce->Flags;
  1751. // Determine the location of the guids
  1752. // and SIDs. They are arranged such that they
  1753. // take up as little memory as possible
  1754. //
  1755. if (dwFlags & ACE_OBJECT_TYPE_PRESENT)
  1756. {
  1757. pgObj = (GUID*)&(pAaoAce->ObjectType);
  1758. pSID = (PSID)&(pAaoAce->InheritedObjectType);
  1759. if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
  1760. {
  1761. pgInhObj = (GUID*)&(pAaoAce->InheritedObjectType);
  1762. pSID = (PSID)&(pAaoAce->SidStart);
  1763. }
  1764. }
  1765. else
  1766. {
  1767. pSID = (PSID)&(pAaoAce->ObjectType);
  1768. if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
  1769. {
  1770. pgInhObj = (GUID*)&(pAaoAce->ObjectType);
  1771. pSID = (PSID)&(pAaoAce->InheritedObjectType);
  1772. }
  1773. }
  1774. break;
  1775. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  1776. pAdoAce = (PACCESS_DENIED_OBJECT_ACE)pvAce;
  1777. dwAccessMask = pAdoAce->Mask;
  1778. dwFlags = pAdoAce->Flags;
  1779. // Determine the location of the guids
  1780. // and SIDs. They are arranged such that they
  1781. // take up as little memory as possible
  1782. //
  1783. if (dwFlags & ACE_OBJECT_TYPE_PRESENT)
  1784. {
  1785. pgObj = (GUID*)&(pAdoAce->ObjectType);
  1786. pSID = (PSID)&(pAdoAce->InheritedObjectType);
  1787. if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
  1788. {
  1789. pgInhObj = (GUID*)&(pAdoAce->InheritedObjectType);
  1790. pSID = (PSID)&(pAdoAce->SidStart);
  1791. }
  1792. }
  1793. else
  1794. {
  1795. pSID = (PSID)&(pAdoAce->ObjectType);
  1796. if (dwFlags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
  1797. {
  1798. pgInhObj = (GUID*)&(pAdoAce->ObjectType);
  1799. pSID = (PSID)&(pAdoAce->InheritedObjectType);
  1800. }
  1801. }
  1802. break;
  1803. default:
  1804. DsrTraceEx(0, "Unknown ACE TYPE %x", bAceType);
  1805. bOk = FALSE;
  1806. break;
  1807. }
  1808. if (bOk == FALSE)
  1809. {
  1810. return E_FAIL;
  1811. }
  1812. // Lookup the account name of the sid
  1813. //
  1814. hr = DsrStrFromSID(pSID, pszTrustee, sizeof(pszTrustee));
  1815. if (hr != NO_ERROR)
  1816. {
  1817. return HRESULT_FROM_WIN32(hr);
  1818. }
  1819. // Fill in the ACE fields
  1820. pAceDesc->dwAceType = (LONG)bAceType;
  1821. pAceDesc->dwAceFlags = (LONG)bAceFlags;
  1822. pAceDesc->dwAccessMask = (LONG)dwAccessMask;
  1823. pAceDesc->dwFlags = (LONG)dwFlags;
  1824. pAceDesc->bstrTrustee = SysAllocString(pszTrustee);
  1825. if (pgObj)
  1826. {
  1827. StringFromGUID2(
  1828. *pgObj,
  1829. pszGuid,
  1830. sizeof(pszGuid)/sizeof(WCHAR));
  1831. pAceDesc->bstrObjectType = SysAllocString(pszGuid);
  1832. }
  1833. if (pgInhObj)
  1834. {
  1835. StringFromGUID2(
  1836. *pgInhObj,
  1837. pszGuid,
  1838. sizeof(pszGuid)/sizeof(WCHAR));
  1839. pAceDesc->bstrInheritedObjectType = SysAllocString(pszGuid);
  1840. }
  1841. return hr;
  1842. }
  1843. //
  1844. // Generates a list of ace descriptors based on a stringized
  1845. // SD
  1846. //
  1847. HRESULT
  1848. DsrAceDescListFromString(
  1849. IN PWCHAR pszDC,
  1850. IN PWCHAR pszSD,
  1851. OUT DSR_ACE_DESCRIPTOR** ppAceList,
  1852. OUT LPDWORD lpdwAceCount)
  1853. {
  1854. BOOL bOk = TRUE, bPresent = FALSE, bDefaulted = FALSE;
  1855. DSR_ACE_DESCRIPTOR* pAceList = NULL, *pCurAce = NULL;
  1856. PSECURITY_DESCRIPTOR pSD = NULL;
  1857. PVOID pvAce = NULL;
  1858. ULONG ulSize = 0;
  1859. PACL pDacl = NULL;
  1860. HRESULT hr = S_OK;
  1861. DWORD i;
  1862. do
  1863. {
  1864. // First, convert the stringized security descriptor to a
  1865. // plain old vanilla security descriptor. ADSI doesn't
  1866. // support this for W2K, so we have to do it with SDDL
  1867. // api's
  1868. //
  1869. bOk = ConvertStringSecurityDescriptorToSecurityDescriptorW(
  1870. pszSD,
  1871. SDDL_REVISION_1,
  1872. &pSD,
  1873. &ulSize);
  1874. if (bOk == FALSE)
  1875. {
  1876. hr = E_FAIL;
  1877. break;
  1878. }
  1879. // Get the DACL from the SD.
  1880. //
  1881. bOk = GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted);
  1882. if (bOk == FALSE)
  1883. {
  1884. hr = E_FAIL;
  1885. break;
  1886. }
  1887. // If there are no aces, then there's nothing to do
  1888. //
  1889. if (pDacl->AceCount == 0)
  1890. {
  1891. break;
  1892. }
  1893. // Allocate the list that we'll return if everything goes well.
  1894. //
  1895. pAceList = (DSR_ACE_DESCRIPTOR*)
  1896. DsrAlloc(pDacl->AceCount * sizeof(DSR_ACE_DESCRIPTOR), TRUE);
  1897. if (pAceList == NULL)
  1898. {
  1899. hr = E_OUTOFMEMORY;
  1900. break;
  1901. }
  1902. // Initialize the list of aces
  1903. //
  1904. for (i = 0, pCurAce = pAceList; i < pDacl->AceCount; i++, pCurAce++)
  1905. {
  1906. // Get a reference to the current
  1907. // ACE
  1908. //
  1909. if (! GetAce(pDacl, i, &pvAce))
  1910. {
  1911. continue;
  1912. }
  1913. // Initialize the ACE descriptor accordingly
  1914. //
  1915. hr = DsrAceDescFromW2KAce(pszDC, pvAce, pCurAce);
  1916. DSR_BREAK_ON_FAILED_HR(hr);
  1917. //DsrAceDescTrace(pCurAce);
  1918. }
  1919. DSR_BREAK_ON_FAILED_HR(hr);
  1920. // Set the return values. Clear pAceList so it doesn't
  1921. // get cleaned up.
  1922. //
  1923. *ppAceList = pAceList;
  1924. *lpdwAceCount = pDacl->AceCount;
  1925. pAceList = NULL;
  1926. } while (FALSE);
  1927. // Cleanup
  1928. {
  1929. if (pSD)
  1930. {
  1931. LocalFree(pSD);
  1932. }
  1933. if (pAceList)
  1934. {
  1935. for (i = 0; i < pDacl->AceCount; i++)
  1936. {
  1937. DsrAceDescClear(&(pAceList[i]));
  1938. }
  1939. DsrFree(pAceList);
  1940. }
  1941. }
  1942. return hr;
  1943. }
  1944. PWCHAR
  1945. DsrAceAttrToString(
  1946. IN PWCHAR pszObjectType)
  1947. {
  1948. if (pszObjectType == NULL)
  1949. {
  1950. return L"All";
  1951. }
  1952. else if (lstrcmpi(pszObjectType, pszGuidUserParms) == 0)
  1953. {
  1954. return L"UserParms (BF967A6D-0DE6-11D0-A285-00AA003049E2)";
  1955. }
  1956. else if (lstrcmpi(pszObjectType, pszGuidRasPropSet1) == 0)
  1957. {
  1958. return L"Ras user properties (037088F8-0AE1-11D2-B422-00A0C968F939)";
  1959. }
  1960. else if (lstrcmpi(pszObjectType, pszGuidRasPropSet2) == 0)
  1961. {
  1962. return L"Misc user properties (4C164200-20C0-11D0-A768-00AA006E0529)";
  1963. }
  1964. else if (lstrcmpi(pszObjectType, pszGuidLogonHours) == 0)
  1965. {
  1966. return L"Logon-Hours (BF9679AB-0DE6-11D0-A285-00AA003049E2)";
  1967. }
  1968. else if (lstrcmpi(pszObjectType, pszGuidSamAccountName) == 0)
  1969. {
  1970. return L"Sam account name (3E0ABFD0-126A-11D0-A060-00AA006C33ED)";
  1971. }
  1972. return pszObjectType;
  1973. }
  1974. PWCHAR
  1975. DsrAceApplyToString(
  1976. IN PWCHAR pszApply)
  1977. {
  1978. if (pszApply == NULL)
  1979. {
  1980. return L"This object";
  1981. }
  1982. else if (lstrcmpi(pszApply, pszGuidUserClass) == 0)
  1983. {
  1984. return L"User objects (BF967ABA-0DE6-11D0-A285-00aa003049E2)";
  1985. }
  1986. return pszApply;
  1987. }
  1988. PWCHAR
  1989. DsrAceMaskToString(
  1990. IN DWORD dwType,
  1991. IN DWORD dwMask,
  1992. IN PWCHAR pszBuf)
  1993. {
  1994. WCHAR pszTemp[64];
  1995. *pszBuf = L'\0';
  1996. switch (dwType)
  1997. {
  1998. case ADS_ACETYPE_ACCESS_ALLOWED:
  1999. wcscpy(pszBuf, L"Allow: ");
  2000. break;
  2001. case ADS_ACETYPE_ACCESS_DENIED:
  2002. wcscpy(pszBuf, L"Deny: ");
  2003. break;
  2004. case ADS_ACETYPE_SYSTEM_AUDIT:
  2005. wcscpy(pszBuf, L"Audit: ");
  2006. break;
  2007. case ADS_ACETYPE_ACCESS_ALLOWED_OBJECT:
  2008. wcscpy(pszBuf, L"Allow obj: ");
  2009. break;
  2010. case ADS_ACETYPE_ACCESS_DENIED_OBJECT:
  2011. wcscpy(pszBuf, L"Deny obj: ");
  2012. break;
  2013. case ADS_ACETYPE_SYSTEM_AUDIT_OBJECT:
  2014. wcscpy(pszBuf, L"Audit obj: ");
  2015. break;
  2016. }
  2017. wsprintfW(pszTemp, L"(%x): ", dwMask);
  2018. wcscat(pszBuf, pszTemp);
  2019. if (dwMask == DSR_ADS_RIGHT_GENERIC_READ)
  2020. {
  2021. wcscat(pszBuf, L"Generic read");
  2022. }
  2023. else if (dwMask == 0xffffffff)
  2024. {
  2025. wcscat(pszBuf, L"Full control");
  2026. }
  2027. else
  2028. {
  2029. if (dwMask & ADS_RIGHT_READ_CONTROL)
  2030. wcscat(pszBuf, L"R ctrl, ");
  2031. if (dwMask & ADS_RIGHT_WRITE_DAC)
  2032. wcscat(pszBuf, L"R/W dac, ");
  2033. if (dwMask & ADS_RIGHT_WRITE_OWNER)
  2034. wcscat(pszBuf, L"W own, ");
  2035. if (dwMask & ADS_RIGHT_SYNCHRONIZE)
  2036. wcscat(pszBuf, L"Sync, ");
  2037. if (dwMask & ADS_RIGHT_ACCESS_SYSTEM_SECURITY)
  2038. wcscat(pszBuf, L"Sys, ");
  2039. if (dwMask & ADS_RIGHT_GENERIC_READ)
  2040. wcscat(pszBuf, L"R (gen), ");
  2041. if (dwMask & ADS_RIGHT_GENERIC_WRITE)
  2042. wcscat(pszBuf, L"W (gen), ");
  2043. if (dwMask & ADS_RIGHT_GENERIC_EXECUTE)
  2044. wcscat(pszBuf, L"Ex, ");
  2045. if (dwMask & ADS_RIGHT_GENERIC_ALL)
  2046. wcscat(pszBuf, L"All, ");
  2047. if (dwMask & ADS_RIGHT_DS_CREATE_CHILD)
  2048. wcscat(pszBuf, L"Cr cld, ");
  2049. if (dwMask & ADS_RIGHT_DS_DELETE_CHILD)
  2050. wcscat(pszBuf, L"Del cld, ");
  2051. if (dwMask & ADS_RIGHT_ACTRL_DS_LIST)
  2052. wcscat(pszBuf, L"List, ");
  2053. if (dwMask & ADS_RIGHT_DS_SELF)
  2054. wcscat(pszBuf, L"Self, ");
  2055. if (dwMask & ADS_RIGHT_DS_READ_PROP)
  2056. wcscat(pszBuf, L"R prop, ");
  2057. if (dwMask & ADS_RIGHT_DS_WRITE_PROP)
  2058. wcscat(pszBuf, L"W prop, ");
  2059. if (dwMask & ADS_RIGHT_DS_DELETE_TREE)
  2060. wcscat(pszBuf, L"Del tree, ");
  2061. if (dwMask & ADS_RIGHT_DS_LIST_OBJECT)
  2062. wcscat(pszBuf, L"List obj, ");
  2063. if (dwMask & ADS_RIGHT_DS_CONTROL_ACCESS)
  2064. wcscat(pszBuf, L"Ctrl acc, ");
  2065. }
  2066. return pszBuf;
  2067. }
  2068. PWCHAR
  2069. DsrAceFlagsToString(
  2070. IN DWORD dwAceFlags,
  2071. IN PWCHAR pszBuf)
  2072. {
  2073. WCHAR pszTemp[64];
  2074. *pszBuf = L'\0';
  2075. switch (dwAceFlags)
  2076. {
  2077. case 0:
  2078. wcscpy(pszBuf, L"This object only");
  2079. break;
  2080. case ADS_ACEFLAG_INHERIT_ACE:
  2081. wcscpy(pszBuf, L"This object and children");
  2082. break;
  2083. case ADS_ACEFLAG_NO_PROPAGATE_INHERIT_ACE:
  2084. wcscpy(pszBuf, L"No-prop inherit");
  2085. break;
  2086. case ADS_ACEFLAG_INHERIT_ONLY_ACE:
  2087. wcscpy(pszBuf, L"Inherit-only");
  2088. break;
  2089. case ADS_ACEFLAG_INHERITED_ACE:
  2090. wcscpy(pszBuf, L"Inherited");
  2091. break;
  2092. case ADS_ACEFLAG_VALID_INHERIT_FLAGS:
  2093. wcscpy(pszBuf, L"Valid inherit flags");
  2094. break;
  2095. case ADS_ACEFLAG_SUCCESSFUL_ACCESS:
  2096. wcscpy(pszBuf, L"Successful access");
  2097. break;
  2098. case ADS_ACEFLAG_FAILED_ACCESS:
  2099. wcscpy(pszBuf, L"Failed access");
  2100. break;
  2101. }
  2102. wsprintfW(pszTemp, L" (%x)", dwAceFlags);
  2103. wcscat(pszBuf, pszTemp);
  2104. return pszBuf;
  2105. }
  2106. //
  2107. // Traces out the contents of an ACE
  2108. //
  2109. VOID
  2110. DsrAceDescTrace(
  2111. IN IADs* pIads,
  2112. IN DSR_ACE_DESCRIPTOR* pA)
  2113. {
  2114. VARIANT var;
  2115. BSTR bstrProp = SysAllocString(pszDn);
  2116. HRESULT hr = S_OK;
  2117. WCHAR pszBuf[1024];
  2118. do
  2119. {
  2120. VariantInit(&var);
  2121. if (bstrProp == NULL)
  2122. {
  2123. hr = E_FAIL;
  2124. break;
  2125. }
  2126. hr = pIads->Get(bstrProp, &var);
  2127. DSR_BREAK_ON_FAILED_HR( hr );
  2128. DsrTraceEx(0, "%ls", V_BSTR(&var));
  2129. DsrTraceEx(0, "%ls",
  2130. DsrAceMaskToString(pA->dwAceType, pA->dwAccessMask, pszBuf));
  2131. DsrTraceEx(0, "To: %ls", pA->bstrTrustee);
  2132. DsrTraceEx(0, "Attribute: %ls",
  2133. DsrAceAttrToString(pA->bstrObjectType));
  2134. DsrTraceEx(0, "ApplyTo: %ls",
  2135. DsrAceApplyToString(pA->bstrInheritedObjectType));
  2136. DsrTraceEx(0, "Inheritance: %ls",
  2137. DsrAceFlagsToString(pA->dwAceFlags, pszBuf));
  2138. DsrTraceEx(0, "Flags: %x", pA->dwFlags);
  2139. DsrTraceEx(0, " ");
  2140. } while (FALSE);
  2141. // Cleanup
  2142. //
  2143. {
  2144. SysFreeString(bstrProp);
  2145. VariantClear(&var);
  2146. }
  2147. if (FAILED(hr))
  2148. {
  2149. DsrTraceEx(
  2150. 0,
  2151. "{ %-8x %-2x %-2x %-2x %-40ls %ls %ls }",
  2152. pA->dwAccessMask,
  2153. pA->dwAceType,
  2154. pA->dwAceFlags,
  2155. pA->dwFlags,
  2156. pA->bstrTrustee,
  2157. pA->bstrObjectType,
  2158. pA->bstrInheritedObjectType);
  2159. }
  2160. }
  2161. //
  2162. // Adds the given ace to the given ds object
  2163. //
  2164. HRESULT
  2165. DsrAceAdd(
  2166. IN PWCHAR pszDC,
  2167. IN IADs* pIads,
  2168. IN DSR_ACE_DESCRIPTOR * pAceParams)
  2169. {
  2170. IADsSecurityDescriptor* pSD = NULL;
  2171. IADsAccessControlList* pAcl = NULL;
  2172. IDispatch* pAce = NULL;
  2173. IDispatch* pDispatch = NULL;
  2174. HRESULT hr = S_OK;
  2175. VARIANT var;
  2176. // Initialize
  2177. VariantInit(&var);
  2178. do
  2179. {
  2180. // Get the security descriptor
  2181. //
  2182. pIads->Get((PWCHAR)pszSecurityDesc, &var);
  2183. DSR_BREAK_ON_FAILED_HR( hr );
  2184. // Get the appropriate interface to the sd
  2185. //
  2186. V_DISPATCH(&var)->QueryInterface(
  2187. IID_IADsSecurityDescriptor,
  2188. (VOID**)&pSD);
  2189. DSR_BREAK_ON_FAILED_HR( hr );
  2190. // Get a reference to the discretionary acl
  2191. //
  2192. hr = pSD->get_DiscretionaryAcl(&pDispatch);
  2193. DSR_BREAK_ON_FAILED_HR( hr );
  2194. hr = pDispatch->QueryInterface(
  2195. IID_IADsAccessControlList,
  2196. (VOID**)&pAcl);
  2197. DSR_BREAK_ON_FAILED_HR( hr );
  2198. // Don't add the ACE if it's already there.
  2199. //
  2200. hr = DsrAceFindInAcl(
  2201. pszDC,
  2202. pAcl,
  2203. pAceParams,
  2204. &pAce);
  2205. if (SUCCEEDED(hr) && pAce)
  2206. {
  2207. hr = S_OK;
  2208. break;
  2209. }
  2210. // Trace out the ACE
  2211. DsrAceDescTrace(pIads, pAceParams);
  2212. // Create the ACE
  2213. hr = DsrAceCreate(pAceParams, &pAce);
  2214. DSR_BREAK_ON_FAILED_HR( hr );
  2215. // Add the newly created ACE to the ACL
  2216. //
  2217. hr = pAcl->AddAce(pAce);
  2218. DSR_BREAK_ON_FAILED_HR( hr );
  2219. // Now commit the result in the ACL
  2220. //
  2221. hr = pSD->put_DiscretionaryAcl(pDispatch);
  2222. DSR_BREAK_ON_FAILED_HR( hr );
  2223. // Finally, commit the result in the ds object
  2224. //
  2225. hr = pIads->Put((PWCHAR)pszSecurityDesc, var);
  2226. DSR_BREAK_ON_FAILED_HR( hr );
  2227. } while (FALSE);
  2228. // Cleanup
  2229. {
  2230. DSR_RELEASE( pAce );
  2231. DSR_RELEASE( pAcl );
  2232. DSR_RELEASE( pDispatch );
  2233. DSR_RELEASE( pSD );
  2234. VariantClear(&var);
  2235. }
  2236. return DSR_ERROR(hr);
  2237. }
  2238. //
  2239. // Creates a new ACE object from the given parameters
  2240. //
  2241. HRESULT
  2242. DsrAceCreate(
  2243. IN DSR_ACE_DESCRIPTOR * pAceParams,
  2244. OUT IDispatch** ppAce)
  2245. {
  2246. IADsAccessControlEntry* pAce = NULL;
  2247. IDispatch* pRet = NULL;
  2248. HRESULT hr = S_OK;
  2249. do
  2250. {
  2251. // Create the new ACE
  2252. //
  2253. hr = CoCreateInstance(
  2254. CLSID_AccessControlEntry,
  2255. NULL,
  2256. CLSCTX_INPROC_SERVER,
  2257. IID_IADsAccessControlEntry,
  2258. (VOID**) &pAce);
  2259. DSR_BREAK_ON_FAILED_HR( hr );
  2260. // Initialize the values
  2261. //
  2262. hr = pAce->put_Trustee(pAceParams->bstrTrustee);
  2263. DSR_BREAK_ON_FAILED_HR( hr );
  2264. hr = pAce->put_AceFlags(pAceParams->dwAceFlags);
  2265. DSR_BREAK_ON_FAILED_HR( hr );
  2266. hr = pAce->put_Flags(pAceParams->dwFlags);
  2267. DSR_BREAK_ON_FAILED_HR( hr );
  2268. hr = pAce->put_AceType(pAceParams->dwAceType);
  2269. DSR_BREAK_ON_FAILED_HR( hr );
  2270. hr = pAce->put_AccessMask(pAceParams->dwAccessMask);
  2271. DSR_BREAK_ON_FAILED_HR( hr );
  2272. hr = pAce->put_ObjectType(pAceParams->bstrObjectType);
  2273. DSR_BREAK_ON_FAILED_HR( hr );
  2274. hr = pAce->put_InheritedObjectType(
  2275. pAceParams->bstrInheritedObjectType);
  2276. DSR_BREAK_ON_FAILED_HR( hr );
  2277. // Query the return value
  2278. //
  2279. hr = pAce->QueryInterface(IID_IDispatch, (VOID**)&pRet);
  2280. DSR_BREAK_ON_FAILED_HR( hr );
  2281. // Assign the return value
  2282. *ppAce = pRet;
  2283. } while (FALSE);
  2284. // Cleanup
  2285. {
  2286. if (FAILED (hr))
  2287. {
  2288. DSR_RELEASE(pRet);
  2289. }
  2290. DSR_RELEASE(pAce);
  2291. }
  2292. return hr;
  2293. }
  2294. //
  2295. // Finds the given ace in the given acl
  2296. //
  2297. HRESULT
  2298. DsrAceFind(
  2299. IN PWCHAR pszDC,
  2300. IN IADs* pObject,
  2301. IN DSR_ACE_DESCRIPTOR* pAceParams,
  2302. OUT VARIANT* pVarSD,
  2303. OUT IADsSecurityDescriptor** ppSD,
  2304. OUT IADsAccessControlList** ppAcl,
  2305. OUT IDispatch** ppAce)
  2306. {
  2307. IDispatch* pAcl = NULL;
  2308. HRESULT hr = S_OK;
  2309. do
  2310. {
  2311. // Get the security descriptor
  2312. //
  2313. pObject->Get((PWCHAR)pszSecurityDesc, pVarSD);
  2314. DSR_BREAK_ON_FAILED_HR( hr );
  2315. // Get the appropriate interface to the sd
  2316. //
  2317. V_DISPATCH(pVarSD)->QueryInterface(
  2318. IID_IADsSecurityDescriptor,
  2319. (VOID**)ppSD);
  2320. DSR_BREAK_ON_FAILED_HR( hr );
  2321. // Get a reference to the discretionary acl
  2322. //
  2323. hr = (*ppSD)->get_DiscretionaryAcl(&pAcl);
  2324. DSR_BREAK_ON_FAILED_HR( hr );
  2325. hr = pAcl->QueryInterface(
  2326. IID_IADsAccessControlList,
  2327. (VOID**)ppAcl);
  2328. DSR_BREAK_ON_FAILED_HR( hr );
  2329. hr = DsrAceFindInAcl(
  2330. pszDC,
  2331. *ppAcl,
  2332. pAceParams,
  2333. ppAce);
  2334. DSR_BREAK_ON_FAILED_HR(hr);
  2335. } while (FALSE);
  2336. // Cleanup
  2337. {
  2338. DSR_RELEASE( pAcl );
  2339. if (*ppAce == NULL)
  2340. {
  2341. VariantClear(pVarSD);
  2342. DSR_RELEASE(*ppAcl);
  2343. DSR_RELEASE(*ppSD);
  2344. *ppAcl = NULL;
  2345. *ppSD = NULL;
  2346. }
  2347. }
  2348. return hr;
  2349. }
  2350. //
  2351. // Finds the given ACE in the given ACL
  2352. //
  2353. HRESULT
  2354. DsrAceFindInAcl(
  2355. IN PWCHAR pszDC,
  2356. IN IADsAccessControlList* pAcl,
  2357. IN DSR_ACE_DESCRIPTOR* pAceDesc,
  2358. OUT IDispatch** ppAce)
  2359. {
  2360. DSR_ACE_DESCRIPTOR CurAceParams, *pCurAceDesc = &CurAceParams;
  2361. IADsAccessControlEntry* pCurAce = NULL;
  2362. HRESULT hr = S_OK;
  2363. IUnknown* pUnknown = NULL;
  2364. IEnumVARIANT* pEnumVar = NULL;
  2365. IDispatch* pRet = NULL;
  2366. DWORD dwRetrieved;
  2367. VARIANT var;
  2368. do
  2369. {
  2370. // Get an enumerator of the aces
  2371. //
  2372. hr = pAcl->get__NewEnum(&pUnknown);
  2373. DSR_BREAK_ON_FAILED_HR( hr );
  2374. // Get the right interface to enumerate the aces
  2375. //
  2376. hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (VOID**)&pEnumVar);
  2377. DSR_BREAK_ON_FAILED_HR( hr );
  2378. // Enumerate
  2379. //
  2380. pEnumVar->Reset();
  2381. VariantInit(&var);
  2382. ZeroMemory(pCurAceDesc, sizeof(DSR_ACE_DESCRIPTOR));
  2383. while ((pEnumVar->Next(1, &var, &dwRetrieved) == S_OK) &&
  2384. (dwRetrieved == 1)
  2385. )
  2386. {
  2387. // Get the reference to the ace
  2388. //
  2389. hr = V_DISPATCH(&var)->QueryInterface(
  2390. IID_IADsAccessControlEntry,
  2391. (VOID**)&pCurAce);
  2392. if (SUCCEEDED (hr))
  2393. {
  2394. // Read the ACE parameters
  2395. //
  2396. hr = DsrAceDescFromIadsAce(pszDC, pCurAce, pCurAceDesc);
  2397. if (SUCCEEDED (hr))
  2398. {
  2399. // Assign the ace if we have a match
  2400. //
  2401. if (DsrAceDescCompare(pCurAceDesc, pAceDesc) == 0)
  2402. {
  2403. pRet = V_DISPATCH(&var);
  2404. }
  2405. DsrAceDescClear(pCurAceDesc);
  2406. }
  2407. pCurAce->Release();
  2408. }
  2409. if (pRet == NULL)
  2410. {
  2411. VariantClear(&var);
  2412. }
  2413. else
  2414. {
  2415. break;
  2416. }
  2417. }
  2418. // Assign the return value
  2419. //
  2420. *ppAce = pRet;
  2421. } while (FALSE);
  2422. // Cleanup
  2423. {
  2424. DSR_RELEASE( pEnumVar );
  2425. DSR_RELEASE( pUnknown );
  2426. }
  2427. return hr;
  2428. }
  2429. //
  2430. // Removes the given ace from the given ds object
  2431. //
  2432. HRESULT
  2433. DsrAceRemove(
  2434. IN PWCHAR pszDC,
  2435. IN IADs* pIads,
  2436. IN DSR_ACE_DESCRIPTOR * pAceParams)
  2437. {
  2438. IADsSecurityDescriptor* pSD = NULL;
  2439. IADsAccessControlList* pAcl = NULL;
  2440. IADsAccessControlEntry* pIadsAce = NULL;
  2441. IDispatch* pAce = NULL;
  2442. DSR_ACE_DESCRIPTOR CurAceParams;
  2443. HRESULT hr = S_OK;
  2444. VARIANT varSD;
  2445. do
  2446. {
  2447. VariantInit(&varSD);
  2448. hr = DsrAceFind(pszDC, pIads, pAceParams, &varSD, &pSD, &pAcl, &pAce);
  2449. DSR_BREAK_ON_FAILED_HR( hr );
  2450. if (pAce)
  2451. {
  2452. // Make sure the ace is the same as we think
  2453. //
  2454. hr = pAce->QueryInterface(
  2455. IID_IADsAccessControlEntry,
  2456. (VOID**)&pIadsAce);
  2457. if (SUCCEEDED(hr))
  2458. {
  2459. DsrTraceEx(0, "ACE to be removed!");
  2460. DsrAceDescFromIadsAce(pszDC, pIadsAce, &CurAceParams);
  2461. DsrAceDescTrace(pIads, &CurAceParams);
  2462. DsrAceDescClear(&CurAceParams);
  2463. }
  2464. else
  2465. {
  2466. DsrTraceEx(0, "Unable to trace ACE that will be removed!\n");
  2467. }
  2468. // Remove the ace found if any.
  2469. //
  2470. // Trace out the ACE
  2471. hr = pAcl->RemoveAce(pAce);
  2472. DSR_BREAK_ON_FAILED_HR( hr );
  2473. // Now commit the result in the ACL
  2474. //
  2475. hr = pSD->put_DiscretionaryAcl(pAcl);
  2476. DSR_BREAK_ON_FAILED_HR( hr );
  2477. // Finally, commit the result in the ds object
  2478. //
  2479. hr = pIads->Put((PWCHAR)pszSecurityDesc, varSD);
  2480. DSR_BREAK_ON_FAILED_HR( hr );
  2481. }
  2482. else
  2483. {
  2484. DsrTraceEx(0, "DsrAceRemove: unable to match ACE for removal:");
  2485. DsrAceDescTrace(pIads, pAceParams);
  2486. }
  2487. } while (FALSE);
  2488. // Cleanup
  2489. {
  2490. DSR_RELEASE( pAce );
  2491. DSR_RELEASE( pIadsAce );
  2492. DSR_RELEASE( pAcl );
  2493. DSR_RELEASE( pSD );
  2494. VariantClear(&varSD);
  2495. }
  2496. return DSR_ERROR(hr);
  2497. }
  2498. //
  2499. // Cleans up after DsrAccessInfoInit
  2500. //
  2501. DWORD
  2502. DsrAccessInfoCleanup(
  2503. IN DSR_DOMAIN_ACCESS_INFO* pInfo)
  2504. {
  2505. if (pInfo)
  2506. {
  2507. // Cleanup the name of the DC
  2508. //
  2509. if (pInfo->pszDC)
  2510. {
  2511. DsrFree(pInfo->pszDC);
  2512. }
  2513. // Cleanup the ace applications
  2514. //
  2515. DsrAceAppCleanup(pInfo->pAcesUser, pInfo->dwAceCountUser);
  2516. DsrAceAppCleanup(pInfo->pAcesNt4, pInfo->dwAceCountNt4);
  2517. DsrAceAppCleanup(pInfo->pAcesW2k, pInfo->dwAceCountW2k);
  2518. // Release the hold on domain objects
  2519. //
  2520. DSR_RELEASE(pInfo->pUserClass);
  2521. DSR_RELEASE(pInfo->pRootDse);
  2522. DSR_RELEASE(pInfo->pDomain);
  2523. DsrFree(pInfo);
  2524. }
  2525. return NO_ERROR;
  2526. }
  2527. //
  2528. // Generates aces from the default user SD
  2529. //
  2530. HRESULT
  2531. DsrAccessInfoGenerateUserAces(
  2532. IN OUT DSR_DOMAIN_ACCESS_INFO* pInfo)
  2533. {
  2534. DSR_ACE_DESCRIPTOR* pAceSrc = NULL, *pAceList = NULL;
  2535. DSR_ACE_APPLICATION* pAceApp = NULL;
  2536. DWORD i, dwAceCount = 0;
  2537. HRESULT hr = S_OK;
  2538. VARIANT var;
  2539. VariantInit(&var);
  2540. do
  2541. {
  2542. // Read in the default user SD
  2543. //
  2544. hr = pInfo->pUserClass->Get((PWCHAR)pszDefSecurityDesc, &var);
  2545. DSR_BREAK_ON_FAILED_HR(hr);
  2546. // Generate a list of ACE descriptors based on the
  2547. // default user SD.
  2548. //
  2549. hr = DsrAceDescListFromString(
  2550. pInfo->pszDC,
  2551. V_BSTR(&var),
  2552. &pAceList,
  2553. &dwAceCount);
  2554. DSR_BREAK_ON_FAILED_HR(hr);
  2555. // Initialize a new array of ace applications big enough
  2556. // to hold the hard coded ones plus the ones we just read
  2557. // from the default SD of the user class.
  2558. //
  2559. pInfo->pAcesUser = (DSR_ACE_APPLICATION*)
  2560. DsrAlloc((sizeof(DSR_ACE_APPLICATION) * dwAceCount), TRUE);
  2561. if (pInfo->pAcesUser == NULL)
  2562. {
  2563. hr = E_OUTOFMEMORY;
  2564. break;
  2565. }
  2566. // Add the ACEs we read from the default user SD
  2567. //
  2568. pAceApp = pInfo->pAcesUser;
  2569. for (i = 0, pAceSrc = pAceList;
  2570. i < dwAceCount;
  2571. i++, pAceSrc++, pAceApp++)
  2572. {
  2573. pAceApp->pObject = pInfo->pDomain;
  2574. pAceApp->pObject->AddRef();
  2575. CopyMemory(
  2576. &(pAceApp->Ace),
  2577. pAceSrc,
  2578. sizeof(DSR_ACE_DESCRIPTOR));
  2579. pInfo->dwAceCountUser++;
  2580. // As we append the aces, we need to modify them
  2581. // so that they apply only to user objects in the
  2582. // domain.
  2583. pAceApp->Ace.bstrInheritedObjectType =
  2584. SysAllocString(pszGuidUserClass);
  2585. pAceApp->Ace.dwAceFlags = DSR_ADS_ACE_INHERITED;
  2586. pAceApp->Ace.dwFlags |= ADS_FLAG_INHERITED_OBJECT_TYPE_PRESENT;
  2587. if (pAceApp->Ace.dwAceType == ADS_ACETYPE_ACCESS_ALLOWED)
  2588. {
  2589. pAceApp->Ace.dwAceType =
  2590. ADS_ACETYPE_ACCESS_ALLOWED_OBJECT;
  2591. }
  2592. else if (pAceApp->Ace.dwAceType == ADS_ACETYPE_ACCESS_DENIED)
  2593. {
  2594. pAceApp->Ace.dwAceType =
  2595. ADS_ACETYPE_ACCESS_DENIED_OBJECT;
  2596. }
  2597. }
  2598. } while (FALSE);
  2599. // Cleanup
  2600. {
  2601. DSR_FREE(pAceList);
  2602. VariantClear(&var);
  2603. }
  2604. return hr;
  2605. }
  2606. //
  2607. // Generates the information needed to enable nt4 ras
  2608. // servers in a domain
  2609. //
  2610. HRESULT
  2611. DsrAccessInfoInit(
  2612. IN PWCHAR pszDomain,
  2613. OUT DSR_DOMAIN_ACCESS_INFO** ppInfo)
  2614. {
  2615. DSR_DOMAIN_ACCESS_INFO* pInfo = NULL;
  2616. IADsContainer* pDomContainer = NULL, *pSchemaContainer = NULL;
  2617. IADs* pDomain = NULL;
  2618. IDispatch* pDispatch = NULL;
  2619. PDOMAIN_CONTROLLER_INFO pDomainInfo = NULL;
  2620. HRESULT hr = S_OK;
  2621. do
  2622. {
  2623. // Allocate and zero the return value
  2624. //
  2625. pInfo = (DSR_DOMAIN_ACCESS_INFO*)
  2626. DsrAlloc(sizeof(DSR_DOMAIN_ACCESS_INFO), TRUE);
  2627. if (pInfo == NULL)
  2628. {
  2629. DSR_BREAK_ON_FAILED_HR(hr = E_OUTOFMEMORY);
  2630. }
  2631. // Get the name of a DC to query when needed
  2632. //
  2633. hr = DsGetDcNameW(
  2634. NULL,
  2635. pszDomain,
  2636. NULL,
  2637. NULL,
  2638. DS_DIRECTORY_SERVICE_REQUIRED,
  2639. &pDomainInfo);
  2640. if (hr != NO_ERROR)
  2641. {
  2642. hr = HRESULT_FROM_WIN32(hr);
  2643. break;
  2644. }
  2645. // Copy the string
  2646. //
  2647. pInfo->pszDC = (PWCHAR)
  2648. DsrAlloc(
  2649. (wcslen(pDomainInfo->DomainControllerName) + 1) *
  2650. sizeof(WCHAR),
  2651. FALSE);
  2652. if (pInfo->pszDC == NULL)
  2653. {
  2654. hr = E_OUTOFMEMORY;
  2655. break;
  2656. }
  2657. wcscpy(pInfo->pszDC, pDomainInfo->DomainControllerName);
  2658. // Get the well known domain containers
  2659. //
  2660. hr = DsrDomainGetContainers(
  2661. pszDomain,
  2662. &(pInfo->pRootDse),
  2663. &pDomContainer,
  2664. &pSchemaContainer);
  2665. DSR_BREAK_ON_FAILED_HR( hr );
  2666. // Get the interface to the domain object
  2667. //
  2668. hr = pDomContainer->QueryInterface(
  2669. IID_IADs,
  2670. (VOID**)&pDomain);
  2671. DSR_BREAK_ON_FAILED_HR( hr );
  2672. pInfo->pDomain = pDomain;
  2673. pInfo->pDomain->AddRef();
  2674. // Get the reference to the user class in the
  2675. // schema
  2676. hr = pSchemaContainer->GetObject(
  2677. (PWCHAR)pszUserClass,
  2678. (PWCHAR)pszUserCN,
  2679. &pDispatch);
  2680. DSR_BREAK_ON_FAILED_HR( hr );
  2681. hr = pDispatch->QueryInterface(
  2682. IID_IADs,
  2683. (VOID**)&(pInfo->pUserClass));
  2684. DSR_BREAK_ON_FAILED_HR( hr );
  2685. // Generate the ACEs from the default user SD
  2686. //
  2687. hr = DsrAccessInfoGenerateUserAces(pInfo);
  2688. DSR_BREAK_ON_FAILED_HR( hr );
  2689. // Create ace applications for all of the nt4
  2690. // aces
  2691. hr = DsrAceAppFromAppDesc(
  2692. g_pAcesNt4,
  2693. sizeof(g_pAcesNt4) / sizeof(*g_pAcesNt4),
  2694. pDomContainer,
  2695. pDomain,
  2696. &(pInfo->pAcesNt4),
  2697. &(pInfo->dwAceCountNt4));
  2698. DSR_BREAK_ON_FAILED_HR( hr );
  2699. // Create ace applications for all of the w2k
  2700. // aces
  2701. hr = DsrAceAppFromAppDesc(
  2702. g_pAcesW2k,
  2703. sizeof(g_pAcesW2k) / sizeof(*g_pAcesW2k),
  2704. pDomContainer,
  2705. pDomain,
  2706. &(pInfo->pAcesW2k),
  2707. &(pInfo->dwAceCountW2k));
  2708. DSR_BREAK_ON_FAILED_HR( hr );
  2709. // Assign the return value
  2710. *ppInfo = pInfo;
  2711. } while (FALSE);
  2712. // Cleanup
  2713. //
  2714. {
  2715. DSR_RELEASE(pDomain);
  2716. DSR_RELEASE(pDomContainer);
  2717. DSR_RELEASE(pSchemaContainer);
  2718. DSR_RELEASE(pDispatch);
  2719. if (FAILED (hr))
  2720. {
  2721. DsrAccessInfoCleanup(pInfo);
  2722. }
  2723. if (pDomainInfo)
  2724. {
  2725. NetApiBufferFree(pDomainInfo);
  2726. }
  2727. }
  2728. return hr;
  2729. }
  2730. //
  2731. // Discovers the access mode of the domain currently.
  2732. //
  2733. // Assumes COM is initialized
  2734. //
  2735. HRESULT
  2736. DsrDomainQueryAccessEx(
  2737. IN PWCHAR pszDomain,
  2738. OUT LPDWORD lpdwAccessFlags,
  2739. OUT DSR_DOMAIN_ACCESS_INFO** ppInfo)
  2740. {
  2741. DSR_DOMAIN_ACCESS_INFO* pInfo = NULL;
  2742. HRESULT hr = S_OK;
  2743. BOOL bOk = FALSE;
  2744. if (lpdwAccessFlags == NULL)
  2745. {
  2746. return ERROR_INVALID_PARAMETER;
  2747. }
  2748. do
  2749. {
  2750. // Initialize
  2751. //
  2752. *lpdwAccessFlags = 0;
  2753. // Read in the info that tells us what ACE's
  2754. // need to be set.
  2755. //
  2756. hr = DsrAccessInfoInit(
  2757. pszDomain,
  2758. &pInfo);
  2759. DSR_BREAK_ON_FAILED_HR( hr );
  2760. // Check for nt4 level access
  2761. //
  2762. bOk = FALSE;
  2763. hr = DsrAceAppQueryPresence(
  2764. pInfo->pszDC,
  2765. pInfo->pAcesNt4,
  2766. pInfo->dwAceCountNt4,
  2767. &bOk);
  2768. DSR_BREAK_ON_FAILED_HR(hr);
  2769. // If we don't have nt4 access, we have no access
  2770. //
  2771. if (bOk == FALSE)
  2772. {
  2773. *lpdwAccessFlags = 0;
  2774. break;
  2775. }
  2776. *lpdwAccessFlags |= MPRFLAG_DOMAIN_NT4_SERVERS;
  2777. // Check for w2k level access
  2778. //
  2779. bOk = FALSE;
  2780. hr = DsrAceAppQueryPresence(
  2781. pInfo->pszDC,
  2782. pInfo->pAcesW2k,
  2783. pInfo->dwAceCountW2k,
  2784. &bOk);
  2785. DSR_BREAK_ON_FAILED_HR(hr);
  2786. // If we don't have w2k access, no need to proceed
  2787. //
  2788. if (bOk == FALSE)
  2789. {
  2790. break;
  2791. }
  2792. *lpdwAccessFlags |= MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS;
  2793. } while (FALSE);
  2794. // Cleanup
  2795. {
  2796. if (FAILED(hr))
  2797. {
  2798. if (pInfo)
  2799. {
  2800. DsrAccessInfoCleanup(pInfo);
  2801. }
  2802. }
  2803. else
  2804. {
  2805. *ppInfo = pInfo;
  2806. }
  2807. }
  2808. return hr;
  2809. }
  2810. //
  2811. // Returns the access level of the given domain
  2812. //
  2813. DWORD
  2814. DsrDomainQueryAccess(
  2815. IN PWCHAR pszDomain,
  2816. OUT LPDWORD lpdwAccessFlags)
  2817. {
  2818. DSR_DOMAIN_ACCESS_INFO* pInfo = NULL;
  2819. HRESULT hr = S_OK;
  2820. do
  2821. {
  2822. // Initialize
  2823. hr = DsrComIntialize();
  2824. DSR_BREAK_ON_FAILED_HR( hr );
  2825. // Query the access
  2826. hr = DsrDomainQueryAccessEx(
  2827. pszDomain,
  2828. lpdwAccessFlags,
  2829. &pInfo);
  2830. DSR_BREAK_ON_FAILED_HR(hr);
  2831. } while (FALSE);
  2832. // Cleanup
  2833. {
  2834. if (pInfo)
  2835. {
  2836. DsrAccessInfoCleanup(pInfo);
  2837. }
  2838. DsrComUninitialize();
  2839. }
  2840. return DSR_ERROR(hr);
  2841. }
  2842. //
  2843. // Sets the ACES in the given domain to enable nt4 servers
  2844. //
  2845. DWORD
  2846. DsrDomainSetAccess(
  2847. IN PWCHAR pszDomain,
  2848. IN DWORD dwAccessFlags)
  2849. {
  2850. DSR_DOMAIN_ACCESS_INFO* pInfo = NULL;
  2851. HRESULT hr = S_OK;
  2852. BOOL bClean = TRUE;
  2853. DWORD dwCurAccess = 0;
  2854. do
  2855. {
  2856. // Initialize
  2857. hr = DsrComIntialize();
  2858. DSR_BREAK_ON_FAILED_HR( hr );
  2859. DsrTraceEx(
  2860. 0,
  2861. "DsrDomainSetAccess: Req: %x",
  2862. dwAccessFlags);
  2863. // W2k mode always implies nt4 mode as well
  2864. //
  2865. if (dwAccessFlags & MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS)
  2866. {
  2867. dwAccessFlags |= MPRFLAG_DOMAIN_NT4_SERVERS;
  2868. }
  2869. // Discover the current access on the domain and
  2870. // initialize the info we need
  2871. //
  2872. hr = DsrDomainQueryAccessEx(
  2873. pszDomain,
  2874. &dwCurAccess,
  2875. &pInfo);
  2876. DSR_BREAK_ON_FAILED_HR(hr);
  2877. DsrTraceEx(
  2878. 0,
  2879. "DsrDomainSetAccess: Cur: %x",
  2880. dwCurAccess);
  2881. // Remove all appropriate aces if the requested access
  2882. // is none.
  2883. if (dwAccessFlags == 0)
  2884. {
  2885. // Remove the nt4 mode aces if needed
  2886. //
  2887. if (dwCurAccess & MPRFLAG_DOMAIN_NT4_SERVERS)
  2888. {
  2889. hr = DsrAceAppRemove(
  2890. pInfo->pszDC,
  2891. pInfo->pAcesUser,
  2892. pInfo->dwAceCountUser);
  2893. DSR_BREAK_ON_FAILED_HR(hr);
  2894. hr = DsrAceAppRemove(
  2895. pInfo->pszDC,
  2896. pInfo->pAcesNt4,
  2897. pInfo->dwAceCountNt4);
  2898. DSR_BREAK_ON_FAILED_HR(hr);
  2899. }
  2900. // Remove the w2k mode aces if needed
  2901. //
  2902. if (dwCurAccess & MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS)
  2903. {
  2904. hr = DsrAceAppRemove(
  2905. pInfo->pszDC,
  2906. pInfo->pAcesW2k,
  2907. pInfo->dwAceCountW2k);
  2908. DSR_BREAK_ON_FAILED_HR(hr);
  2909. }
  2910. }
  2911. // Set nt4 mode if needed
  2912. //
  2913. if (dwAccessFlags & MPRFLAG_DOMAIN_NT4_SERVERS)
  2914. {
  2915. // Remove w2k level access if needed
  2916. //
  2917. if ((!(dwAccessFlags & MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS)) &&
  2918. (dwCurAccess & MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS))
  2919. {
  2920. hr = DsrAceAppRemove(
  2921. pInfo->pszDC,
  2922. pInfo->pAcesW2k,
  2923. pInfo->dwAceCountW2k);
  2924. DSR_BREAK_ON_FAILED_HR(hr);
  2925. }
  2926. // Add nt4 level access if needed
  2927. //
  2928. if (! (dwCurAccess & MPRFLAG_DOMAIN_NT4_SERVERS))
  2929. {
  2930. hr = DsrAceAppAdd(
  2931. pInfo->pszDC,
  2932. pInfo->pAcesUser,
  2933. pInfo->dwAceCountUser);
  2934. DSR_BREAK_ON_FAILED_HR(hr);
  2935. hr = DsrAceAppAdd(
  2936. pInfo->pszDC,
  2937. pInfo->pAcesNt4,
  2938. pInfo->dwAceCountNt4);
  2939. DSR_BREAK_ON_FAILED_HR(hr);
  2940. }
  2941. }
  2942. // Set w2k mode if needed
  2943. //
  2944. if (dwAccessFlags & MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS)
  2945. {
  2946. if (!(dwCurAccess & MPRFLAG_DOMAIN_W2K_IN_NT4_DOMAINS))
  2947. {
  2948. hr = DsrAceAppAdd(
  2949. pInfo->pszDC,
  2950. pInfo->pAcesW2k,
  2951. pInfo->dwAceCountW2k);
  2952. DSR_BREAK_ON_FAILED_HR(hr);
  2953. }
  2954. }
  2955. } while (FALSE);
  2956. // Cleanup
  2957. {
  2958. if (pInfo)
  2959. {
  2960. DsrAccessInfoCleanup(pInfo);
  2961. }
  2962. DsrComUninitialize();
  2963. }
  2964. return DSR_ERROR(hr);
  2965. }